Forum Discussion
Catch specific SSL errors/failures???
One of the requirements that I've been given is to try and catch certain SSL errors and return a more friendly error page, rather than the browser default...
A couple of the examples that have come up so far are:
* A User attempting to connect to a VIP that is enforcing client SSL certficiates but doesn't have a valid Client SSL certificate installed...
* A user attempting to connect to a VIP with an expired Client SSL certificate
* A user connecting with a very old SSL Version or Cipher...
Now the last one is nice and easy as there's plenty of reference code on the Wiki...
However I'm struggling with 1 & 2 above...
Any pointers or ideas???
Cheers
Gav
23 Replies
- nitass
Employee
not sure whether SSL::verify_result is usable.
SSL::verify_result wiki
http://devcentral.f5.com/wiki/iRules.SSL__verify_result.ashx
[root@ve1023:Active] ca2012 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@ve1023:Active] ca2012 b pool foo list pool foo { members 200.200.200.101:80 {} } [root@ve1023:Active] ca2012 b profile myclientssl list profile clientssl myclientssl { defaults from clientssl ca file "chain.crt" peer cert mode request } [root@ve1023:Active] ca2012 b rule myrule list rule myrule { when HTTP_REQUEST { if {[SSL::verify_result]} { HTTP::respond 403 content [X509::verify_cert_error_string [SSL::verify_result]] } } } [root@ve1023:Active] ca2012 curl -ik https://172.28.19.79 HTTP/1.0 403 Forbidden Server: BigIP Connection: Keep-Alive Content-Length: 32 application verification failure [root@ve1023:Active] ca2012 curl -ik https://172.28.19.79 --cert certs/client.crt --key certs/client.key HTTP/1.1 200 OK Date: Mon, 16 Jan 2012 17:32:45 GMT Server: Apache/2.2.3 (CentOS) Last-Modified: Fri, 11 Nov 2011 14:48:14 GMT ETag: "4183e4-3e-9c564780" Accept-Ranges: bytes Content-Length: 62 Set-Cookie: BROWSER=MOZILLA%20INTERNET_EXPLORER%20CHROME; path=/ Content-Type: text/html; charset=UTF-8 ...
- hoolio
Cirrostratus
One of the keys to this working is that you need to change the client cert mode from require to request. This allows LTM to complete the SSL handshake without a valid client cert. - GavinW_29074
Nimbostratus
Aaron/Nitass - nitass
Employee
You should probable also add a check that [SSL::cert 0] ne "" before checking SSL::verify_result doesn't return 0 for an invalid cert. since it does not return 0, bigip should respond with 403, shouldn't it?
[root@ve1023:Active] ssl curl -ik https://172.28.19.79 --cert ssl.crt/default.crt --key ssl.key/default.key HTTP/1.0 403 Forbidden Server: BigIP Connection: Keep-Alive Content-Length: 23 self signed certificate
- GavinW_29074
Nimbostratus
Sorry for the weird formatting on the above 2 posts... I've tried several edit's to get it correct, but it's having none of it... - hoolio
Cirrostratus
That looks like a good start Gavin. Can you try moving the ifile command to RULE_INIT and use subst to force evaluation of the variable? - GavinW_29074
Nimbostratus
Double post... - GavinW_29074
Nimbostratus
Aaron
Did try putting code tags in, but just kept breaking... I guess could be due to the HTML tags in the include page...
I tried adding your line to the RULE_INIT block, but got the following error:
Jan 18 13:57:24 tmm err tmm[9144]: 01220001:3: TCL error: /Common/Catch_SSL_Errors - can't read "failure_result": no such variable while executing "subst [ifile get error_page_html]"
Jan 18 13:57:24 tmm err tmm[9144]: 01220006:3: RULE_INIT for rule /Common/Catch_SSL_Errors failed
However that did send me in the right direction... I've kept the error_page variable in the HTTP_REQUEST block, and have wrapped it inside a 'subst' tag on the HTTP::respond lines... E.g:
HTTP::respond 403 content [subst $error_page] "Content-Type" "text/html" "Connection" "Close"
I did try the code without the SSL::cert count, and it returns a result code of 50 - 'X509_V_ERR_APPLICATION_VERIFICATION: application verification failure'. I chose to wrap it in a count as it gives me an easy way of picking out where they don't have a client cert, as that's our typical failure method. Plus it saves some processing time I guess...
Latest copy of the rule is below...
Going back to your suggestion of putting the 'ifile get' in the RULE_INIT section, are there any advantages/disadvantages of this?
Cheers
Gav
when RULE_INIT {
Debug Loggingset static::CatchSSLErrorsDebug 1Get the Error Page HTMLset static::error_page [ifile get error_page_html]}
v10.1 or higher
Redirect any client HTTP request with no client certificate or with a cert which is not correctly
validated against the trusted root certificate specified in the client SSL profile.
when HTTP_REQUEST priority 10 {
if {$static::CatchSSLErrorsDebug == 1} { log local0. "CatchSSLErrors HTTP Request:" }Return the Logo if requested.if { [HTTP::uri] ends_with "logo-act.png" } {if {$static::CatchSSLErrorsDebug > 0} { log local0.info "Returning Logo..." }HTTP::respond 200 content [ifile get act_logo_png] "Content-Type" "image/png" "Connection" "Close"event disablereturn}Hide the SSL:: command's from the iRule parserso the iRule can be used on a non-client SSL VSset cipher_cmd "SSL::cipher version"set count_cmd "SSL::cert 0"set verify_cmd "SSL::verify_result"set failure_cmd "X509::verify_cert_error_string"Get the error pageset error_page [ifile get error_page_html]Check if the client used an SSL cipher and it's not "none"if {not ([catch {eval $cipher_cmd} result]) && $result ne "none"}{Client did use a cipherif {$static::CatchSSLErrorsDebug == 1} { log local0.info "SSL Connection initiated... Verifying client certificate." }catch {eval $count_cmd} count_resultif {$static::CatchSSLErrorsDebug == 1} { log local0.info "SSL::cert returned the following output... '$count_result'" }if {$count_result ne ""} {if {$static::CatchSSLErrorsDebug == 1} { log local0.info "Client cert presented. Verifying..." }catch {eval $verify_cmd} verify_resultif { $verify_result == 0 } {Client Cert present and verified successfully.if {$static::CatchSSLErrorsDebug == 1} { log local0.info "SSL::Verify_result was OK... '$verify_result' Continuing..." }return} else {Client cert verification error.if {$static::CatchSSLErrorsDebug == 1} { log local0.info "SSL::Verify_result was NOT OK... '$verify_result'" }Get failure reasoncatch {eval $failure_cmd $verify_result } failure_resultif {$static::CatchSSLErrorsDebug == 1} { log local0.info "X509::verify_cert_error_string value is... '$failure_result'" }HTTP::respond 403 content [subst $error_page] "Content-Type" "text/html" "Connection" "Close"event disablereturn}} else {if {$static::CatchSSLErrorsDebug == 1} { log local0.info "No Client cert presented. Returning error page..." }Return failure page. No Client cert presented...set failure_result "No client certificate present"HTTP::respond 403 content [subst $error_page] "Content-Type" "text/html" "Connection" "Close"event disablereturn}} else {Client did not use a cipherif {$static::CatchSSLErrorsDebug == 1} { log local0.info "Non-SSL Connection initiated... Continuing..." }return}}
- hoolio
Cirrostratus
Sorry, $failure_result is calculated at runtime, so your solution of calling subst at runtime is perfect. You should be able to get the ifile contents in RULE_INIT using 'set static::error_page [ifile get error_page_html]' and then call subt against that with HTTP::respond: - GavinW_29074
Nimbostratus
Aaron
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