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
- What_Lies_Bene1
Cirrostratus
You should be able to use the sha1 command to generate the message digest of the $cert_subject and then insert that as a header. - Kevin_Stewart
Employee
The sha1 command produces a binary value. To convert it to hexadecimal, use the binary scan command:binary scan [sha1 [SSL::cert 0]] H* output log local0. $output - hui_37443
Nimbostratus
Here is what I did a while ago. I leave the hexdecimal handling to the backend web app.
set ssl_cert [SSL::cert 0]
...
set hash [b64encode [sha1 $ssl_cert]]
...
HTTP::header insert "thumbprintheader" $hash - nitass
Employee
e.g.[root@ve10:Active] config b version|grep -iA 1 version BIG-IP Version 10.2.4 655.0 Hotfix HF4 Edition [root@ve10:Active] config b virtual bar list virtual bar { snat automap pool foo destination 172.28.19.79:443 ip protocol 6 rules myrule profiles { http {} myclientssl { clientside } tcp {} } } [root@ve10:Active] config b pool foo list pool foo { members 200.200.200.101:80 {} } [root@ve10:Active] config b profile myclientssl list profile clientssl myclientssl { defaults from clientssl ca file "ca.crt" client cert ca "ca.crt" peer cert mode require } [root@ve10:Active] config b rule myrule list rule myrule { when HTTP_REQUEST { 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 ClientCert-Thumbprint $cert_hex } } } client1 certificate [root@ve10:Active] config ssldump -Aed -nni 0.0 port 80 or port 443 -k /config/ssl/ssl.key/default.key New TCP connection 1: 172.28.19.251(35670) <-> 172.28.19.79(443) 1 1 1354080555.1567 (0.0241) C>S SSLv2 compatible client hello 1 2 1354080555.1568 (0.0000) S>CV3.1(81) Handshake 1 3 1354080555.1568 (0.0000) S>CV3.1(953) Handshake 1 4 1354080555.1568 (0.0000) S>CV3.1(114) Handshake 1 5 1354080555.1568 (0.0000) S>CV3.1(4) Handshake 1 6 1354080555.2336 (0.0768) C>SV3.1(1489) Handshake 1 7 1354080555.2336 (0.0000) C>SV3.1(262) Handshake 1 8 1354080555.2336 (0.0000) C>SV3.1(518) Handshake 1 9 1354080555.2336 (0.0000) C>SV3.1(1) ChangeCipherSpec 1 10 1354080555.2336 (0.0000) C>SV3.1(36) Handshake 1 11 1354080555.2556 (0.0219) S>CV3.1(1) ChangeCipherSpec 1 12 1354080555.2556 (0.0000) S>CV3.1(36) Handshake 1 13 1354080555.2567 (0.0011) C>SV3.1(175) application_data --------------------------------------------------------------- HEAD / HTTP/1.1 User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 Host: 172.28.19.79 Accept: */* --------------------------------------------------------------- New TCP connection 2: 200.200.200.10(35670) <-> 200.200.200.101(80) 1354080555.2599 (0.0013) C>S --------------------------------------------------------------- HEAD / HTTP/1.1 User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 Host: 172.28.19.79 Accept: */* SSLClientCertSubject: CN=client1.acme.com,OU=IT,O=Acme Ltd,L=Seattle,ST=WA,C=US ClientCert-Thumbprint: 9240c3ccc820c3506c271517c6d5f35d2337c57e --------------------------------------------------------------- client2 certificate [root@ve10:Active] config ssldump -Aed -nni 0.0 port 80 or port 443 -k /config/ssl/ssl.key/default.key New TCP connection 1: 172.28.19.251(35671) <-> 172.28.19.79(443) 1 1 1354080624.7908 (0.0210) C>S SSLv2 compatible client hello 1 2 1354080624.7909 (0.0000) S>CV3.1(81) Handshake 1 3 1354080624.7909 (0.0000) S>CV3.1(953) Handshake 1 4 1354080624.7909 (0.0000) S>CV3.1(114) Handshake 1 5 1354080624.7909 (0.0000) S>CV3.1(4) Handshake 1 6 1354080624.9088 (0.1179) C>SV3.1(1489) Handshake 1 7 1354080624.9088 (0.0000) C>SV3.1(262) Handshake 1 8 1354080624.9088 (0.0000) C>SV3.1(518) Handshake 1 9 1354080624.9088 (0.0000) C>SV3.1(1) ChangeCipherSpec 1 10 1354080624.9088 (0.0000) C>SV3.1(36) Handshake 1 11 1354080624.9294 (0.0206) S>CV3.1(1) ChangeCipherSpec 1 12 1354080624.9294 (0.0000) S>CV3.1(36) Handshake 1 13 1354080624.9308 (0.0013) C>SV3.1(175) application_data --------------------------------------------------------------- HEAD / HTTP/1.1 User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 Host: 172.28.19.79 Accept: */* --------------------------------------------------------------- New TCP connection 2: 200.200.200.10(35671) <-> 200.200.200.101(80) 1354080624.9328 (0.0017) C>S --------------------------------------------------------------- HEAD / HTTP/1.1 User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 Host: 172.28.19.79 Accept: */* SSLClientCertSubject: CN=client2.acme.com,OU=IT,O=Acme Ltd,L=Seattle,ST=WA,C=US ClientCert-Thumbprint: 96d093f76eb7634b377374253762b00aef036a7f --------------------------------------------------------------- - RiverFish
Altostratus
You guys are the best! Nitass, you always knock it out of the park. I'll get this implemented and see how it goes. Thanks again. - hoolio
Cirrostratus
Nice work as always Nitass. You might want to also remove any pre-existing SSLClientCertSubject and ClientCert-Thumbprint headers before inserting the new values to prevent a malicious user from injecting their own headers.
Aaron - RiverFish
Altostratus
So the devs said that Nitass's iRule didn't look familiar to them. Familiar? I asked what they were expecting and they said there might be an existing iRule on one of the F5's. So I dug around and found the one below. They said that this is the one they needed. So what exactly is the difference?
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
}
} - RiverFish
Altostratus
Hoolio, the devs just asked about your concern about "preventing a malicious user from injecting their own headers". Could someone please post the complete iRule that will 1) insert the cert subject 2) insert the thumbprint and 3) remove pre-existing headers? I'm starting to understand iRules now but not sure the order in which to plug things in. Thanks! - Kevin_Stewart
Employee
Just change "HTTP::header insert" with "HTTP::header replace":when HTTP_REQUEST { if { [SSL::cert count] > 0 } { HTTP::header replace SSLClientCertSubject [X509::subject [SSL::cert 0]] binary scan [sha1 [SSL::cert 0]] H* cert_hex HTTP::header replace ClientCertThumbprint $cert_hex } } - hoolio
Cirrostratus
HTTP::header replace will only affect the last header instance so an attacker could still inject a header by setting more than one. I put in a feature request to create an 'HTTP::header replace-all $name $value' command which would replace all existing $name headers with one new value.
For now, if you want to guarantee that no client set headers are included in the proxied request to the server, you can do this: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 } }
Aaron
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
