Forum Discussion

Ted_51200's avatar
Ted_51200
Icon for Nimbostratus rankNimbostratus
Apr 14, 2008

Client SSL Cert Irule

I am looking to request a client ssl cert to happen only if a a spacific url is requested but ignore if not.

 

 

My Irule

 

 

when CLIENTSSL_CLIENTCERT {

 

set the_cert [SSL::cert 0]

 

set subject_dn [X509::subject $the_cert]

 

if { $subject_dn != "" }{

 

if { $debug }{ log "Client Certificate received: $subject_dn"}

 

}

 

}

 

 

when HTTP_REQUEST {

 

if { [HTTP::uri] starts_with "/secure/" } {

 

log "Certificate required for: [HTTP::uri]"

 

if { [SSL::cert count] == 0} {

 

log "Certificate not present. Passing to Login .....: [HTTP::uri]"

 

SSL::cert mode require

 

SSL::renegotiate

 

pool pool_xx

 

}

 

 

set pkiSubject [X509::subject $the_cert]

 

set pkiIssuer [X509::issuer $the_cert]

 

HTTP::header insert CLIENTSSL_Status [SSL::verify_result]

 

HTTP::header insert CLIENTSSL_StatusString [X509::verify_cert_error_string [SSL::verify_result]]

 

HTTP::header insert CLIENTSSL_CN $pkiSubject

 

HTTP::header insert CLIENTSSL_SSLIssuer $pkiIssuer

 

HTTP::header insert CLIENTSSL_SSLClientCertSN [X509::serial_number $the_cert]

 

}

 

}

6 Replies

  • when i go into the Local Traffic / Client SSL Profiles / EXTCLIENTSSL Profile

     

    and set Client Authentication / Client Certificateit to ignore i lose the client cert field.. and as per my request above i want it to ignore until that /secure/~ is hit then request...

     

     

    Please help devcental... your my only hope =)
  • Stephen_Archer_'s avatar
    Stephen_Archer_
    Historic F5 Account
    I've been trying to do a similar thing... and am also having problems. All I'm trying to do is to check a URI, and if it contains '/SecureURI', then perform client authentication, and if authorised (using the SOA_Trusted_Certs , forward to the secure pool using a serverSSL profile. If unauthorised, reject the connection.

     

     

    If the URI does not contain '/SecureURI', then forward to the regular HTTP pool, and disable the serverSSL profile. When I test the iRule below, by trying to access the insecure site, it works, however when I try the secure URI, I get this error: "HTTP_REQUEST - cant read subject_dn: no such variable while executing matchclass $subject_dn contains $::SOA_Trusted_Certs"

     

     

    Here is the iRule:

     

     

    when RULE_INIT {

     

    set ::org "O=MyCompany"

     

    }

     

    when CLIENTSSL_CLIENTCERT {

     

    set subject_dn [X509::subject [SSL::cert 0]]

     

    log "Client Certificate Received: $subject_dn"

     

    }

     

    when HTTP_REQUEST {

     

    if {[HTTP::uri] contains "/SecureURI"} {

     

    pool secure_pool_443

     

    if { ([matchclass $subject_dn contains $::SOA_Trusted_Certs]) and ($subject_dn contains $::org) } {

     

    log "Client Certificate Accepted: $subject_dn"

     

    } else {

     

    log "No Matching Client Certificate Was Found Using: $subject_dn"

     

    reject

     

    }

     

    }

     

    else {

     

    pool unsecure_pool_80

     

    SSL::disable serverside

     

    }

     

    }

     

     

    Kircos, what error do you see when the iRule is hit?
  • I now have a working Irule, but only sends the SSL headers/Info on refresh... anyone have any idea why ? or how to correct it?

     

     

    Irule:

     

     

    when CLIENTSSL_CLIENTCERT {

     

    log local0. "start CLIENTSSL_CLIENTCERT"

     

    set the_cert [SSL::cert 0]

     

    set pkiSubject [X509::subject $the_cert]

     

    set pkiIssuer [X509::issuer $the_cert]

     

    HTTP::release

     

    log local0. "end CLIENTSSL_CLIENTCERT"

     

    }

     

     

    when HTTP_REQUEST_SEND {

     

    clientside {

     

    log local0. "start HTTP_REQUEST_SEND"

     

    if { [SSL::cert count] > 0} {

     

    set the_cert [SSL::cert 0]

     

    set pkiSubject [X509::subject $the_cert]

     

    set pkiIssuer [X509::issuer $the_cert]

     

    HTTP::header replace CLIENTSSL_Status [SSL::verify_result]

     

    HTTP::header replace CLIENTSSL_StatusString [X509::verify_cert_error_string [SSL::verify_result]]

     

    HTTP::header replace CLIENTSSL_CN $pkiSubject

     

    HTTP::header replace CLIENTSSL_SSLIssuer $pkiIssuer

     

    HTTP::header replace CLIENTSSL_SSLClientCertSN [X509::serial_number $the_cert]

     

    HTTP::header replace CLIENTSSL_Cert [b64encode $the_cert]

     

    log local0. "end HTTP_REQUEST_SEND"

     

    }

     

     

    }

     

    }

     

     

    when HTTP_REQUEST {

     

    log local0. "start HTTP_REQUEST"

     

    if { [HTTP::uri] starts_with "/SLFCSSOCollector/ssl/" } {

     

    if { [SSL::cert count] == 0} {

     

    SSL::cert mode require

     

    SSL::renegotiate

     

    log local0. "end HTTP_REQUEST"

     

    }

     

    }

     

    }
  • Hi,

     

     

    I don't understand why you use HTTP::release in your CLIENT_SSL event.

     

     

    can't you do this with this code? :

     

     

    
    when CLIENTSSL_CLIENTCERT {
    log local0. "start CLIENTSSL_CLIENTCERT"
    set the_cert [SSL::cert 0]
    set pkiSubject [X509::subject $the_cert]
    set pkiIssuer [X509::issuer $the_cert]
    log local0. "end CLIENTSSL_CLIENTCERT"
    }
    when HTTP_REQUEST {
      log local0. "start HTTP_REQUEST, uri is [HTTP::uri]"
      if { [HTTP::uri] starts_with "/SLFCSSOCollector/ssl/" } {
         log local0. "URI /SLFCSSOCollector/ssl/ detected!"
         if { [SSL::cert count] == 0} {
            log local0. "no certificate found... force SSL"
            SSL::cert mode require
            SSL::renegotiate
            log local0. "end HTTP_REQUEST"
          }
       } else {
        log local0. "certificate found!"
        set the_cert [SSL::cert 0]
        set pkiSubject [X509::subject $the_cert]
        set pkiIssuer [X509::issuer $the_cert]
        HTTP::header insert CLIENTSSL_Status [SSL::verify_result]
        HTTP::header insert CLIENTSSL_StatusString [X509::verify_cert_error_string [SSL::verify_result]]
        HTTP::header insert CLIENTSSL_CN $pkiSubject
        HTTP::header insert CLIENTSSL_SSLIssuer $pkiIssuer
        HTTP::header insert CLIENTSSL_SSLClientCertSN [X509::serial_number $the_cert]
        HTTP::header insert CLIENTSSL_Cert [b64encode $the_cert]
       }
    }

     

     

    If you test this code, please show us the output of /var/log/ltm so that we can trace what is happening
  • im now using the following irule

     

     

    when CLIENTSSL_CLIENTCERT {

     

    log local0. "start CLIENTSSL_CLIENTCERT"

     

    set the_cert [SSL::cert 0]

     

    set pkiSubject [X509::subject $the_cert]

     

    set pkiIssuer [X509::issuer $the_cert]

     

    log local0. "end CLIENTSSL_CLIENTCERT"

     

    }

     

     

     

     

    when HTTP_REQUEST {

     

     

    log local0. "start HTTP_REQUEST, uri is [HTTP::uri]"

     

     

    if { [HTTP::uri] starts_with "/SLFCSSOCollector/ssl/" } {

     

    log local0. "URI /SLFCSSOCollector/ssl/ detected!"

     

    if { [SSL::cert count] == 0} {

     

    log local0. "no certificate found... force SSL"

     

    SSL::cert mode require

     

    SSL::renegotiate

     

    log local0. "end HTTP_REQUEST"

     

    } else {

     

    log local0. "certificate found!"

     

    set the_cert [SSL::cert 0]

     

    set pkiSubject [X509::subject $the_cert]

     

    set pkiIssuer [X509::issuer $the_cert]

     

    HTTP::header insert CLIENTSSL_Status [SSL::verify_result]

     

    HTTP::header insert CLIENTSSL_StatusString [X509::verify_cert_error_string [SSL::verify_result]]

     

    HTTP::header insert CLIENTSSL_CN $pkiSubject

     

    HTTP::header insert CLIENTSSL_SSLIssuer $pkiIssuer

     

    HTTP::header insert CLIENTSSL_SSLClientCertSN [X509::serial_number $the_cert]

     

    HTTP::header insert CLIENTSSL_Cert [b64encode $the_cert]

     

    }

     

    }

     

    }

     

     

     

    I am still having the info not come accross in the first header have to hit F5(refresh) then after headers show up... Here is my logs

     

     

    12:28:31 EDT 2008Rule sslheader : start HTTP_REQUEST, uri is /SLFCSSOCollector/ssl/headers.asp

     

    12:28:31 EDT 2008Rule sslheader : URI /SLFCSSOCollector/ssl/ detected!

     

    12:28:31 EDT 2008Rule sslheader : no certificate found... force SSL

     

    12:28:31 EDT 2008Rule sslheader : end HTTP_REQUEST

     

    12:28:33 EDT 2008Rule sslheader : start HTTP_REQUEST, uri is /SLFCSSOCollector/ssl/headers.asp

     

    12:28:33 EDT 2008Rule sslheader : URI /SLFCSSOCollector/ssl/ detected!

     

    12:28:33 EDT 2008Rule sslheader : no certificate found... force SSL

     

    12:28:33 EDT 2008Rule sslheader : end HTTP_REQUEST

     

    12:28:33 EDT 2008Rule sslheader : start CLIENTSSL_CLIENTCERT

     

    12:28:33 EDT 2008Rule sslheader : end CLIENTSSL_CLIENTCERT

     

    12:28:35 EDT 2008Rule sslheader : start HTTP_REQUEST, uri is /SLFCSSOCollector/ssl/headers.asp

     

    12:28:35 EDT 2008Rule sslheader : URI /SLFCSSOCollector/ssl/ detected!

     

    12:28:35 EDT 2008Rule sslheader : certificate found!

     

    12:28:37 EDT 2008Rule sslheader : start HTTP_REQUEST, uri is /SLFCSSOCollector/ssl/headers.asp

     

    12:28:37 EDT 2008Rule sslheader : URI /SLFCSSOCollector/ssl/ detected!

     

    12:28:37 EDT 2008Rule sslheader : no certificate found... force SSL

     

    12:28:37 EDT 2008Rule sslheader : end HTTP_REQUEST

     

    12:28:52 EDT 2008Rule sslheader : start HTTP_REQUEST, uri is /SLFCSSOCollector/ssl/headers.asp

     

    12:28:52 EDT 2008Rule sslheader : URI /SLFCSSOCollector/ssl/ detected!

     

    12:28:52 EDT 2008Rule sslheader : no certificate found... force SSL

     

    12:28:52 EDT 2008Rule sslheader : end HTTP_REQUEST

     

     

     

  • Ok Thanks for your logging details !!

    I checked the wiki and it seems you need to do an HTTP::collect ... i'm unsure why but rules1: Devcentral's wiki should be trusted 😄

    
    when CLIENTSSL_HANDSHAKE {
      log local0. "client SSL Handshake"
      if { [SSL::cert count] > 0 } {
        log local0. "client SSL Handshake...HTTP released"
        HTTP::release
      }
    }
    when CLIENTSSL_CLIENTCERT {
    log local0. "start CLIENTSSL_CLIENTCERT"
    set the_cert [SSL::cert 0]
    set pkiSubject [X509::subject $the_cert]
    set pkiIssuer [X509::issuer $the_cert]
    log local0. "end CLIENTSSL_CLIENTCERT"
    }
    when HTTP_REQUEST {
      log local0. "start HTTP_REQUEST, uri is [HTTP::uri]"
      if { [HTTP::uri] starts_with "/SLFCSSOCollector/ssl/" } {
         log local0. "URI /SLFCSSOCollector/ssl/ detected!"
         if { [SSL::cert count] == 0} {
            HTTP::collect
            SSL::authenticate always
            SSL::authenticate depth 9
            log local0. "no certificate found... force SSL"
            SSL::cert mode require
            SSL::renegotiate
            log local0. "end HTTP_REQUEST"
          }
       } else {
        log local0. "certificate found!"
        set the_cert [SSL::cert 0]
        set pkiSubject [X509::subject $the_cert]
        set pkiIssuer [X509::issuer $the_cert]
        HTTP::header insert CLIENTSSL_Status [SSL::verify_result]
        HTTP::header insert CLIENTSSL_StatusString [SSL::verify_result]]
        HTTP::header insert CLIENTSSL_CN $pkiSubject
        HTTP::header insert CLIENTSSL_SSLIssuer $pkiIssuer
        HTTP::header insert CLIENTSSL_SSLClientCertSN [X509::serial_number $the_cert]
        HTTP::header insert CLIENTSSL_Cert [b64encode $the_cert]
       }
    }

    This way it applies the recommandation from the wiki: Click here