Forum Discussion
Generate SHA1 thumbprint of incoming SSL cert
Greetings! I have a request from a developer (below). I was hoping one of you could please help me come up with a solution?
---------------
The F5 needs to generate an SHA1 thumbprint of the incoming SSL certificate and add the output hexadecimal encoded string as a new HTTP header to be passed along to the application. The generated thumbprint is a standard SHA1 thumbprint for identification purposes.
Example HTTP Header:
ClientCert-Thumbprint: a448327eff9283928b9d9993049f0386
---------------
Below is the existing iRule that is in place currently:
when CLIENTSSL_CLIENTCERT {
set cert_subject [X509::subject [SSL::cert 0]]
if { $cert_subject == "" }
{ log "[IP::client_addr]:[TCP::client_port]: No client cert found!"}
}
when HTTP_REQUEST {
if { [info exist cert_subject] } {
HTTP::header insert SSLClientCertSubject $cert_subject
return
}
}
Thanks!
20 Replies
- RiverFish
Altostratus
So this:
binary scan [sha1 [SSL::cert 0]] H* cert_hex
HTTP::header insert ClientCert-Thumbprint $cert_hex
is the same as this:
when CLIENTSSL_CLIENTCERT {
set client_cert [SSL::cert 0]
log local0 "Cert Thumbprint - [X509::subject $client_Hash]"
set cert_hash [X509::hash $client_cert]
}
when HTTP_REQUEST {
if { [info exist cert_hash] } {
HTTP::header insert ClientCertThumbprint $cert_hash
return
}
}
? - hoolio
Cirrostratus
X509::hash will return the md5 hash of the binary cert. sha1 will return the sha1 hash.
Also, a client can resume an existing SSL session and not present the client cert in a new handshake for every TCP connection or HTTP request. TMM automatically stores the cert for the life of the SSL session and makes it accessible using [SSL::cert 0]. So it's better to get the value on each HTTP request instead of storing it in a local variable which is specific to that one TCP connection.
Long story short...the last example I posted should work for your scenario.
Aaron - RiverFish
Altostratus
oops. disregard this post. delete if possible.
- RiverFish
Altostratus
Hoolio, I ran your iRule accross the dev guys one last time to confirm they were good with it. They came back with the following question:
So long as “binary scan [sha1 [SSL::cert 0]] H* cert_hex” gives us the thumbprint out of the certificate and not a SHA1 hash generated across the bytes of the presented certificate…then yes.
Could you please confirm? - hoolio
Cirrostratus
Here's a quick test to show the results:when CLIENTSSL_CLIENTCERT { log local0. "Got [SSL::cert count] certs" if {[SSL::cert 0] eq ""}{ log local0. "cert 0 empty" } else { binary scan [SSL::cert 0] H* whole_cert_hex log local0. "\$whole_cert_hex: $whole_cert_hex" binary scan [sha1 [SSL::cert 0]] H* fingerprint log local0. "sha1: $fingerprint" binary scan [md5 [SSL::cert 0]] H* fingerprint log local0. "md5 manual: $fingerprint" log local0. "md5 from X509::hash: [X509::hash [SSL::cert 0]]" } } And the log results: : sha1: 591fb5e98f012218dbe946780197e061206ab35f : md5 manual: 39b06fdf22022ff0c25672cbee2263f1 : md5 from X509::hash: 39:b0:6f:df:22:02:2f:f0:c2:56:72:cb:ee:22:63:f1 And the openssl results for the same client cert: openssl x509 -in client1.example.com.crt -sha1 -noout -fingerprint SHA1 Fingerprint=59:1F:B5:E9:8F:01:22:18:DB:E9:46:78:01:97:E0:61:20:6A:B3:5F openssl x509 -in client1.example.com.crt -md5 -noout -fingerprint MD5 Fingerprint=39:B0:6F:DF:22:02:2F:F0:C2:56:72:CB:EE:22:63:F1
Aaron - hoolio
Cirrostratus
There's also an enhancement request to update X509::hash to allow you to specify the hash type instead of it being hardcoded to md5:
Bug 380676 - RFE: Enhance X509::hash to use a specified hash, and default to hash used in cert
You could open a case with F5 Support to request this feature be built.
Aaron - RiverFish
Altostratus
Just wanted to post an update. Hoolio's iRule made it through test, QA, and is now in production. It takes the SHA1 thumbprint of the incoming SSL cert, converts it to hex, and inserts it into the header. It also takes the cert subject of the incoming SSL cert and inserts it into the header. Lastly, it scrubs any pre-existing headers before inserting the new ones as an extra measure of security. Thanks again Hoolio, and thanks to everyone else who pitched in. Here is the iRule again in final form:
when HTTP_REQUEST {
if { [SSL::cert count] > 0 } {
HTTP::header remove SSLClientCertSubject
HTTP::header insert SSLClientCertSubject [X509::subject [SSL::cert 0]]
binary scan [sha1 [SSL::cert 0]] H* cert_hex
HTTP::header remove ClientCertThumbprint
HTTP::header insert ClientCertThumbprint $cert_hex
}
} - hoolio
Cirrostratus
That's good to hear. Thanks for posting the final iRule.
Aaron - hoolio
Cirrostratus
Actually, you might want to remove the cert headers regardless of whether the client presented a cert for the SSL session to prevent a client from injecting their own headers.when HTTP_REQUEST { HTTP::header remove SSLClientCertSubject HTTP::header remove ClientCertThumbprint if { [SSL::cert count] > 0 } { HTTP::header insert SSLClientCertSubject [X509::subject [SSL::cert 0]] binary scan [sha1 [SSL::cert 0]] H* cert_hex HTTP::header insert ClientCertThumbprint $cert_hex } }
Aaron - RiverFish
Altostratus
Good catch, will do. Thank you.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
