Forum Discussion

Ron_Kim_110696's avatar
Ron_Kim_110696
Icon for Nimbostratus rankNimbostratus
Jan 11, 2007

iRule example to extract specific X509 information: SOL5171

I can't get this iRule to work.

 

The variable $sn in the HTTP_REQUEST section does not have a value.

 

It is working in the CLIENTSSL_CLIENTCERT section.

 

 

Variables do not seem to pass from the CLIENTSSL_CLIENTCERT to the HTTP_REQUEST sections.

 

================

 

iRule example to extract specific X509 information: SOL5171

 

In the following example, a variable value is set using an SSL command to identify the X509 certificate. Once the X509 certificate is identified, another variable value is set using an X509 command to extract the certificate serial number. The client certificate's serial number is then inserted into an HTTP header with the name Serial.

 

 

when CLIENTSSL_CLIENTCERT {

 

set cert [SSL::cert 0]

 

set sn [X509::serial_number $cert]

 

}

 

when HTTP_REQUEST {

 

if { [info exists sn] } {

 

HTTP::header insert Serial $sn

 

}

 

}
  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    When you say that the $sn variable doesn't have a value, are you saying that because the "Serial" header being inserted is blank? Is the Serial header even being inserted?

    I'd add a few logging statements to the rule to be sure things are functioning, or in this case malfunctioning, the way you think they are, and to give us a bit more insight if things are still failing as to what the problem might be.

    Something like:

    
    when CLIENTSSL_CLIENTCERT {
      set cert [SSL::cert 0]
      set sn [X509::serial_number $cert]
      log local0. "cert is $cert"
      log local0. "sn is $sn"
    }
    when HTTP_REQUEST {
      if { [info exists $sn] } {
        HTTP::header insert Serial $sn
        log local0. "sn is $sn"
      }
    }

    HTH,

    Colin
  • Thank you.

     

     

    We tried this.

     

     

    when CLIENTSSL_CLIENTCERT {

     

    set cert [SSL::cert 0]

     

    set sn [X509::serial_number $cert]

     

    log local0. "cert is $cert" ; This works

     

    log local0. "sn is $sn" ; This works

     

    }

     

    when HTTP_REQUEST {

     

    if { [info exists $sn] } {

     

    HTTP::header insert Serial $sn

     

    log local0. "sn is $sn" ; This DOES NOT work. Blank Value

     

    }

     

    }

     

     

    Any variable that is set in the CLIENTSSL_CLIENTCERT section, does not pass to the HTTP_REQUEST section.

     

    We tried this with multiple different X509 variables.

     

     

    We are running version 9.1.2, could this be a bug?

     

     

  • Deb_Allen_18's avatar
    Deb_Allen_18
    Historic F5 Account
    I talked to one of my co-workers who encountered this difficulty, and he worked around it by saving the value in the session table in CLIENTSSL_CLIENTCERT with a key of ssl-id, then pulled it out of the session table in HTTP_REQUEST as in this codeshare example:

     

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/InsertCertInServerHeaders.html (Click here)

     

     

    HTH

     

    /deb
  • Thanks.

     

     

    We now have an iRule that works.

     

    Now how do we use the "SSL:cert mode request" command to toggle ON and OFF depending on the URI?

     

    And how do we handle the case when the client does not have an Client SSL cert.

     

     

    What would be the best way to achieve the following?

     

     

    * Create a Class that has a list of URI's.

     

    * If the URI is listed in the Class, then do not Request the Client SSL cert.

     

     

    * If the URI is NOT in the Class, then ask for the Client SSL cert.

     

    - Client does NOT have or does NOT have the proper Client SSL cert, then sent them to an error page. (I guess a good filter for the Proper SSL cert would be based on the Issuer.)

     

    - The Client DOES have a valid SSL cert, then insert information into an HTTP header.

     

     

  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    If it were me, I would create a class of URIs (assuming you have more than 10-15 or so, otherwise an if/else chain or switch is more efficient), and check to see if the incoming URI is in that class. On success, I'd force the cert mode to require.

    It would look something like this (assuming you created a class of desired URIs as "certURIs"):

    
    when HTTP_REQUEST {
      if { [matchclass [HTTP::uri] starts_with $::certURIs] } {
        SSL::authenticate always
        SSL::authenticate depth 9
        SSL::cert mode require
        SSL::renegotiate
      }
    }

    Which is distilled from this earlier post where a community member got a slightly more involved version of the above working: Click here

    HTH,

    Colin
  • Thanks Colin.

     

     

    Questions:

     

    Will the below work?

     

    Do we need to initialize the variables in the beginning of the rule?

     

    What happens if a hacker inserted his own HTTP header insterts?

     

    Where and how would I add the ability to check for "[X509::verify_cert_error_string" and do a redirect if there is an error?

     

     

    ===================================

     

    class certURIs {

     

    "/uri1/"

     

    "/uri2/"

     

    "/uri3/"

     

    "/uri4/"

     

    }

     

    ===================================

     

     

    when HTTP_REQUEST {

     

    if { [matchclass [HTTP::uri] starts_with $::certURIs] } {

     

    SSL::authenticate always

     

    why not 'SSL::autenticate once' ??

     

    SSL::authenticate depth 9

     

    SSL::cert mode request

     

    SSL::renegotiate

     

    }

     

    }

     

     

    when CLIENTSSL_CLIENTCERT {

     

    set cert [SSL::cert 0]

     

    set sn [X509::serial_number $cert]

     

    set subject [X509::subject $cert]

     

    set issuer [X509::issuer $cert]

     

    set version [X509::version $cert]

     

     

    session add uie [SSL::sessionid] [list $sn $issuer $subject $version] 1800

     

    log local0. "in SSLid_F5 [SSL::sessionid]"

     

    }

     

     

    when HTTP_REQUEST {

     

    set values [session lookup uie [SSL::sessionid] ]

     

     

    if { [lindex $values 0] != "" } {

     

    HTTP::header insert ClientSSL_Serial_F5 [lindex $values 0]

     

    log local0. "in inserting Serial_F5 [lindex $values 0]"

     

     

    HTTP::header insert ClientSSL_Issuer_F5 [lindex $values 1]

     

    log local0. "in inserting Issuer_F5 [lindex $values 1]"

     

     

    HTTP::header insert ClientSSL_Subject_F5 [lindex $values 2]

     

    log local0. "in inserting Subject_F5 [lindex $values 2]"

     

     

    HTTP::header insert Version_F5 [lindex $values 3]

     

    log local0. "in inserting Version_F5 [lindex $values 3]"

     

    }

     

    }

     

  • High Level Goals of the iRule for a virtual server with HTTPS are:

     

    - Examine URI

     

    - Request Client SSL Cert

     

    - Insert Client SSL Cert info into the HTTP Headers sent to the web server.

     

     

    Attached is a image of a flow chart of what we are trying to achieve.

     

     

    If we want to parse the client requested URI, would it be better to use "CLIENTSSL_HANDSHAKE" in addition to "CLIENTSSL_CLIENTCERT"?

     

    Or do we need two iRules?
  • There is a sample irule from F5 support:

    
    when CLIENTSSL_CLIENTCERT {
    HTTP::release
    if { [SSL::cert count] < 1 } {
    reject
    }
    }
    when HTTP_REQUEST {
    if { [matchclass [HTTP::uri] starts_with $::requires_client_cert] } {
    if { [SSL::cert count] <= 0 } {
    HTTP::collect
    SSL::authenticate always
    SSL::authenticate depth 9
    SSL::cert mode require
    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 "X-SSL-Client-Cert-Subject" [X509::subject [SSL::cert 0]]
    HTTP::header insert "X-SSL-Client-Cert-Issuer"  [X509::issuer [SSL::cert 0]]
    }
    }
    }