Here's the iRule I'm using:
# client_cert_header_insert_rule
when CLIENTSSL_CLIENTCERT {
# Check if client presented at least one cert
if {[SSL::cert count] > 0}{
# Insert the following fields in the session table with a timeout of 7200 seconds:
# Do the processing now as opposed to in HTTP_REQUEST as there
# can be many HTTP requests using the same SSL session ID
#
# Index - item
# 0 - base64 encoding of the client SSL cert
# 1 - serial number of the cert
# 2 - the verification status text for the client cert against the client SSL profile's root CA cert
session add ssl [SSL::sessionid] [list \
[SSL::verify_result] \
[b64encode [SSL::cert 0]] \
[X509::serial_number [SSL::cert 0]] \
] 7200
log local0. "[IP::client_addr]:[TCP::client_port]: Added session data for cert. Status:\
[X509::verify_cert_error_string [lindex [session lookup ssl [SSL::sessionid]] 0]] with key [SSL::sessionid]"
}
}
when HTTP_REQUEST {
if {[string tolower [HTTP::host]] equals "URL goes here" and [string tolower [HTTP::uri]] equals "URI goes here" } {
HTTP::header replace Host "Back end service goes here"
# Check if SSL session ID is in the cache (SSL::sessionid returns 64 zeroes if it's not in v9 and a null string in v10)
if {[SSL::sessionid] ne "0000000000000000000000000000000000000000000000000000000000000000" && [SSL::sessionid] ne ""}{
# Get the session table entry (a TCL list) for this session ID
set session_data [session lookup ssl [SSL::sessionid]]
# Check if the first element of the session table entry for this session ID is 0 (status for successful cert validation)
if {[lindex $session_data 0] == 0}{
log local0. "[IP::client_addr]:[TCP::client_port]: Valid cert per session table entry. Inserting cert details in HTTP headers."
# Insert cert details in the HTTP headers
HTTP::header insert SSLClientCertStatus "ok"
HTTP::header insert SSLClientCertb64 [lindex $session_data 1]
HTTP::header insert SSLClientCertSN [lindex $session_data 2]
# Exit this event in this rule
return
}
}
# If we're still in this rule, cert wasn't valid
# so send HTTP 302 redirect to an error page
HTTP::respond 302 Location "http://[HTTP::host]/cert_error.html"
log local0. "[IP::client_addr]:[TCP::client_port]: No or invalid cert from client."
}
}