alanjohnson7467
Jul 10, 2019Cirrus
Extract SAN from Client SSL Certificate & Insert into HTTP Header
Hi folks,
I'm working with some co-workers to setup some Slack.com forwarding in our environment. Mutual TLS and the insertion of the SAN from the client certificate into a HTTP header is a requirement. Can anyone help me come up with an iRule or LTM Policy to extract the SAN/CN from the client SSl cert and insert it as a HTTP header? Here's some additional info from Slack:
Configure your TLS-terminating server to request client certificates. Your server should accept client certificates issued by DigiCert SHA2 Secure Server CA, an intermediate CA under DigiCert Global Root CA. These CAs are included in many standard CA certificate bundles.
1- Extract either of the following fields in the certificate.
Subject Alternative Name: DNS:platform-tls-client.slack.com. By RFC 6125, this is the recommended field to extract.
or Subject Common Name: platform-tls-client.slack.com.
2- Inject the extracted domain into a header, and forward the request to your application server. Here's an example header you might add to the request: X-Client-Certificate-SAN: platform-tls-client.slack.com. Whatever you choose to call your header, check to make sure this header hasn't already been added to the request. Your upstream application server must know that the header was added by your TLS-terminating server as part of the Mutual TLS process.
When I apply that iRule my test cert works. Not sure why your environment is different. Here's an alternate iRule you could try.
when HTTP_REQUEST { if {[SSL::cert 0] ne ""}{ set tmpcn [X509::subject [SSL::cert 0]] set cn [findstr $tmpcn "CN=" 3] HTTP::header replace X-Client-Certificate-SAN $cn } else { HTTP::header remove X-Client-Certificate-SAN } }
My test results.
curl -k --cert ./platform-tls-client.slack.com.crt --key ./platform-tls-client.slack.com.key https://192.168.1.200:8443/headers.json {"User-Agent":"curl/7.29.0","Host":"192.168.1.200:8443","Accept":"*/*","X-Client-Certificate-SAN":"platform-tls-client.slack.com"}
Here's what my config looks like.
ltm virtual test_vs { creation-time 2019-08-27:10:03:53 destination 192.168.1.200:pcsync-https ip-protocol tcp last-modified-time 2019-08-27:10:20:58 mask 255.255.255.255 pool slack_pool profiles { http { } mtls_clientssl { context clientside } tcp { } } rules { slack2 } source 0.0.0.0/0 source-address-translation { type automap } translate-address enabled translate-port enabled vs-index 3 } ltm profile client-ssl mtls_clientssl { app-service none authenticate-depth 0 ca-file f5ca cert-key-chain { default { cert default.crt key default.key } } defaults-from clientssl inherit-ca-certkeychain true inherit-certkeychain true peer-cert-mode require } ltm rule slack2 { when HTTP_REQUEST { if {[SSL::cert 0] ne ""}{ # extract SAN set santemp [findstr [X509::extensions [SSL::cert 0]] "Subject Alternative Name" 32 ","] # remove DNS: prefix set san [findstr $santemp "DNS" 4] # insert X-Client-Certificate-SAN header HTTP::header replace X-Client-Certificate-SAN $san } else { HTTP::header remove X-Client-Certificate-SAN } } }