After some serious devcentral digging I was finally able to piece together a working iRule. The key was to set the cert mode to request (not require) within the client ssl profile, and then use the [SSL::verify_result] command in the iRule. Below is the iRule so far, please let me know if you see any potential flaws or security holes or maybe some tweaks to make it more efficient.
when CLIENTSSL_CLIENTCERT {
if {[SSL::cert count] < 1}{set cert_count 0}
if {[SSL::cert count] > 0}{set cert_count 1}
set ssl_status_code [SSL::verify_result]
set ssl_status_desc [X509::verify_cert_error_string [SSL::verify_result]]
log local0. "$ssl_status_code $ssl_status_desc"
}
when HTTP_REQUEST {
Reject requests to the service if a cert was not presented
if {[HTTP::uri] contains "/service"}{
if {$cert_count == 0}{reject}
Permit requests to the service if a cert was presented and the cert was verified against the CA assigned to the clientssl profile
A status code of "0" (0 X509_V_OK) means the cert was verified successfully as defined here: http://www.openssl.org/docs/apps/verify.htmlDIAGNOSTICS
if {($cert_count == 1) and ($ssl_status_code == 0)}{
scrub existing headers
HTTP::header remove chain
HTTP::header remove client
HTTP::header remove testCert
HTTP::header remove ClientCert-Subject
HTTP::header remove SSLClientCertSubject
HTTP::header remove SSLClientCertThumbprint
insert cert subject
HTTP::header insert SSLClientCertSubject [X509::subject [SSL::cert 0]]
}
Forward registration requests to the registration pool
Reject all other scenarios
} elseif {[HTTP::uri] contains "/register"}{pool register-pl}
else {reject}
}