Forum Discussion
Scot_86001
Nimbostratus
Feb 21, 2010iRule Optimization w/ Certificates?
The iRule below functions and performs as it should. I have been told that what I have below may not be efficient or optimized. I am looking to see if anyone can make some suggestions on how to better optimize. I would also like to know if session persistence and timeout are being maintained as they should. This iRule performs client side cert authentication only when a certain URI is sent. Upon successfull login, header information from the cert is passed to the receiving application. The code below was pieced together from other iRules on DevCentral.
when CLIENTSSL_CLIENTCERT {
set cert [SSL::cert 0]
HTTP::release
if { [SSL::cert count] < 1 } {
reject
}
}
when HTTP_REQUEST {
set v1 [URI::query [HTTP::uri] "p"]
if { ($v1 contains "ESAT") || ($v1 contains "311") } then {
if { [SSL::cert count] <= 0 } {
HTTP::collect
SSL::session invalidate
SSL::authenticate always
SSL::authenticate depth 9
SSL::cert mode request
SSL::renegotiate
}
}
}
when HTTP_REQUEST_SEND {
clientside {
if { [SSL::cert count] > 0 } {
HTTP::header insert "X-SSL-Session-ID"[SSL::sessionid]
HTTP::header insert "X-SSL-Client-Cert-Status"[X509::verify_cert_error_string [SSL::verify_result]]
HTTP::header insert "SSL_CLIENT_S_DN"[X509::subject [SSL::cert 0]]
HTTP::header insert "SSL_CLIENT_I_DN"[X509::issuer [SSL::cert 0]]
}
}
}
21 Replies
- hoolio
Cirrostratus
Hi Scot,
That iRule would request a client cert any time the URI checks are true, even if the client has already presented a cert on the same TCP connection or on another TCP connection trying to re-use the same SSL session ID. Also note that you're checking the cert validity against the client SSL trusted cert bundle using SSL::verify_result, but you're not doing anything if the cert is invalid. I assume the application is checking the headers and handling invalid certs?
You could make this more efficient by storing the cert details in the session table and then checking when a restricted URI is requested to see if the SSL session ID has a corresponding session table entry. If so, you could insert the cert details in the headers without invalidating the session and requesting a client cert again.
You can add/retrieve key-value pairs to the session table using the session command:
http://devcentral.f5.com/wiki/default.aspx/iRules/session
If you're inserting the verification string, subject and issuer into the HTTP headers, it would make sense to parse these values once per SSL session and then insert them into the session table using the SSL session ID as the key. You'd also want to check that the SSL session isn't 64 zeroes (Click here as this is what SSL::sessionid will return if the client's SSL session ID isn't in LTM's SSL cache.
I'll try to give an example later this week if I have time to test one. Can you confirm which LTM version you're running? You could also try updating your rule to use the session table and reply here if you get stuck.
Also, your iRule isn't doing anything with pool selection or persistence. So it would be up to the VIP's persistence profile to handle persistence and the persistence timeout.
Aaron - Scot_86001
Nimbostratus
Aaron,
Thank you for all the great information. I will be adding in the OCSP checking of the cert once we get that process working (AUTH_ERROR, AUTH_FAIL, etc). As for the session table, I understand what you are saying, but am pretty clueless on how to implement. I have noticed the issues you are speaking about. I have seen a lot of code out on DevCentral about this, but have been unable to weave it in to my scenario. Lets just say, I am extremely junior with the F5 (LTM1500 - 9.4.6). Any help would be greatly appreciated.
-Scot - hoolio
Cirrostratus
If you're going to do OCSP checking of the client cert, I'll add a rule I've been working on which does this to the iRule Codeshare. I'll try to do this by Friday. You'll need to upgrade to 9.4.8HF3 in order to use it.
Aaron - hoolio
Cirrostratus
I've done a quick job of anonymizing the iRule and added it to the Codeshare. I didn't do any testing of the iRule or sample config after removing the customer-specific options. If you're able to upgrade to v9.4.8 and install hotfix 3, can you test this and let me know if you have any problems. Please do make sure to do thorough testing before using in a production environment.
http://devcentral.f5.com/wiki/default.aspx/iRules/client_cert_request_by_uri_with_ocsp_checking.html
Thanks,
Aaron - Scot_86001
Nimbostratus
Aaron,
Thank you.
I have taken my orginal iRule I posted and think I have added in session gathering/persistence correctly. Currently, I am working w/ F5 to get my OCSP responders to work. Once that happens, i will move on to checking those results. I hope what I have done closes some of my previous mistakes/holes.
when CLIENTSSL_CLIENTCERT {
set time to maintain session data (in seconds)
set session_timeout 1800
set ssl_cert [SSL::cert 0]
set ssl_errstr [X509::verify_cert_error_string [SSL::verify_result]]
set ssl_subject [X509::subject [SSL::cert 0]]
set ssl_issuer [X509::issuer [SSL::cert 0]]
set ssl_stuff [list $ssl_cert $ssl_errstr $ssl_subject $ssl_issuer]
session add ssl [SSL::sessionid] $ssl_stuff $session_timeout
HTTP::release
if { [SSL::cert count] < 1 } {
reject
}
}
when HTTP_REQUEST {
set v1 [URI::query [HTTP::uri] "p"]
if { ($v1 contains "ESAT") || ($v1 contains "311") } then {
if { [SSL::cert count] <= 0 } {
HTTP::collect
SSL::session invalidate
SSL::authenticate always
SSL::authenticate depth 9
SSL::cert mode request
SSL::renegotiate
}
}
}
when HTTP_REQUEST_SEND {
clientside {
if { [SSL::cert count] > 0 } {
set ssl_stuff2 [session lookup ssl [SSL::sessionid]]
set ssl_cert2 [lindex $ssl_stuff2 0]
set ssl_errstr2 [lindex $ssl_stuff2 1]
set ssl_subject2 [lindex $ssl_stuff2 2]
set ssl_issuer2 [lindex $ssl_stuff2 3]
if { $ssl_errstr2 eq "ok" } {
HTTP::header insert SSLClientCertStatus $ssl_errstr2
HTTP::header insert SSLClientCertSN [X509::serial_number $ssl_cert2]
HTTP::header insert "SSL_CLIENT_S_DN" $ssl_subject2
HTTP::header insert "SSL_CLIENT_I_DN" $ssl_issuer2
} else {
send HTTP 302 redirect to an error page
HTTP::redirect "http://images.mhf.dod.mil/error.html"
}
}
}
} - hoolio
Cirrostratus
The issue with that approach is that you cannot send an HTTP response from the HTTP_REQUEST_SEND event. When I ran into that issue, F5 development created a hotfix to allow sending an HTTP response from the CLIENTSSL_HANDSHAKE event:
CR125264 - HTTP::respond should be allowed in CLIENTSSL_HANDSHAKE (fix ncluded in 9.4.8HF3)
Also, you're resetting the connection in CLIENTSSL_CLIENTCERT if the client doesn't present a cert. To handle this more gracefully and send an HTTP response in that case, you need another fix included in 9.4.8HF3:
CR111646: Connections are no longer rejected when clients fail to send a certificate to a virtual server with a clientssl profile configured to "request" one.
Aaron - Scot_86001
Nimbostratus
Aaron, Due to a slew of issues/conflicts with my iRULE and the default ocsp iRULE provided by F5, I have started working w/ the iRULE you provided. In my case, I have multiple responders. Is there a way for me to check the status of each responders results? - hoolio
Cirrostratus
Hi Scot,
I think it's more reasonable to replace the default OCSP auth rule on the auth profile with a custom rule versus trying to use a separate custom rule on the VIP along with the default auth rule on the auth profile.
Do you want to load balance the OCSP servers? If so, you can follow the sample configuration in the Codeshare example which shows how to configure an "internal" virtual server pointing to a pool of OCSP servers. If that's not what you're trying to do, can you rephrase the question?
Also, I wouldn't bother trying to test the Codeshare iRule unless you've been able to upgrade to 9.4.8HF3. I think you'll get iRule validation errors in previous versions of 9.4.x.
Thanks,
Aaron - Scot_86001
Nimbostratus
Aaron,
I upgraded both of my F5's to the reccommended levels last night. It seems that the OCSP Responder settings produce different results. I set up my DoD responder with the same options as you provided and IT WORKS. My Verisign ECA responder is not working at all. I wonder if there are specific settings for it?
My question was, is there a way for the iRULE to tell me the success or failer of each responder as I have 2. I am having trouble with the Verisign responder. But I am now batting .500. Not bad for being clueless. - hoolio
Cirrostratus
500 is not a bad start! Can you explain why you're trying to check the client cert against a DOD and Verisign OCSP server? Are there two different sets of CA's issuing the client certs?
The idea with the VIP for the OCSP servers is that you can eventually configure an external monitor which replicates a client OCSP request. If the OCSP server fails to respond to the monitor requests, it would be marked down in the pool and not used.
To troubleshoot the responder failure, I'd start with a command line request from LTM direct to the server to see if the TCP connection works and if so whether you get an HTTP response. If that works, then try making the same request to the OCSP VIP with only the Verisign server enabled in the pool. If you get an HTTP response from the VIP, then try the client cert VIP again with only the Verisign server enabled in the pool. If the OCSP auth fails, I'd try loosening the validation of the OCSP server(s) in the OCSP responder config.
Aaron
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* 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
Discover DevCentral Connects