Forum Discussion

Mike_Maher's avatar
Mike_Maher
Icon for Nimbostratus rankNimbostratus
Mar 02, 2012

TCL with iRule in v11.1

I have the following iRule that went through an upgrade from 10.2.0 to 11.1, and I now seeing some TCL errors. I am pretty sure it has to do with the way I am referencing the Data Group, but I am not sure how to resolve the issue. Any help is appreciated.

 

 

All logs are sent to /var/log/ltm

 

 

If the CN on the certificate or the Issuer changes, you can

 

add the new data under Data Group to either ExtQuotes_CN_List

 

or ExtQuotes_Issuer_List

 

 

when CLIENTSSL_CLIENTCERT {

 

Example Subject DN: /C=AU/ST=NSW/L=Syd/O=Your Organisation/OU=Your OU/CN=John Smith

 

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

 

log "Client Certificate Received: $subject_dn"

 

 

set inter_cert [X509::issuer [SSL::cert 0]]

 

log "Client Certificate Received: $inter_cert"

 

 

 

 

Check if the client certificate contains the correct CN and Issuer from Data Groups

 

if { ([matchclass $subject_dn contains $::ExtQuotes_CN_List])

 

and ([matchclass $inter_cert contains $::ExtQuotes_Issuer_List])} {

 

Accept the client cert

 

log "Client Certificate Accepted: $subject_dn"

 

} else {

 

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

 

reject

 

}

 

}

 

 

 

 

Here is the error

 

 

TCL Error: /Common/ExtQuotes_Client_Cert_Auth - Can't Read "::ExtQuotes_CN_List" : no such variable while executing "matchclass $subject_dn contains $::ExtQuotes_CN_List"

 

  • Hi Mike,

     

     

    In 9.4.4 and higher you shouldn't use the $:: prefix for referencing data groups in an iRule. In 10.x it would load but just return the class name. In 11.x you get a runtime error.

     

     

    Out of curiosity, do you have client cert mode set to require with a frequency of every request? If so, you might be able to save some CPU by changing the cert frequency to once (per session) and parsing the cert subject on each HTTP request. Or do it once in CLIENTSSL_CLIENTCERT, save the result to the session table and then check the session table entry on each HTTP request. If you're open to changes let me know and I'll give more details.

     

     

    Aaron
  • Aaron,

     

    Thanks for the reply, so if I don't use $:: to reference data groups what is the proper way to reference them, I know I have been doing this wrong for a while but just have not found the correct syntax.

     

     

    Yes I am open to changes to make things more efficient so any tips would be appreciated. I will probably just correct the syntax error to get through my upgrade, but would like to test what you are referring to in my lab for a change to the iRule after the upgrade is complete.

     

     

    Mike
  • I'm bumping this because I have the same question. In my case I'm going from 9.4.4 to 11.1 and I'm thinking this iRule is going to give me issues. I see a lot of examples going to version 10 not too many for 11, I don't know if its different.

     

     

    How should this look in version 11?

     

     

    when CLIENT_ACCEPTED {

     

    if { [IP::addr [IP::remote_addr] equals 10.10.10.10 ] or [matchclass [IP::remote_addr] equals $::ext_net ] } {

     

    pool ssh

     

    } else {

     

    discard

     

    }

     

    }

     

     

    Thanks in advance,

     

     

    Misty
  • Hi Mike,

    In 10.1, TMM stores the client's cert details in the SSL session cache:

    https://devcentral.f5.com/wiki/iRules.ssl__cert.ashx

    Note: As of 10.1.0, as described in CR116806, the following iRule commands now apply to the lifetime of the SSL session, and not only for the connection in which the system receives the client certificate:

    * SSL::cert

    * SSL::cert issuer

    * SSL::cert count

    Here's an untested example of what I'm thinking you could try:

    
    All logs are sent to /var/log/ltm
    
    If the CN on the certificate or the Issuer changes, you can
    add the new data under Data Group to either ExtQuotes_CN_List
    or ExtQuotes_Issuer_List
    
    when HTTP_REQUEST {
    
     Log debug to /var/log/ltm? 1=yes, 0=no
    set cc_debug 1
    
     Track whether we found a valid client cert
    set redirect 0
    
     Check if the client presented a cert for this session
    if {[SSL::cert count] == 0}{
    set redirect 1
    set reason "No client certificate found"
    } else {
    
     Verify the cert properties (dates, etc) are valid
     https://devcentral.f5.com/wiki/iRules.SSL__verify_result.ashx
    if {[SSL::verify_result] != 0}{
    
    set redirect 1
    set reason "[X509::verify_cert_error_string [SSL::verify_result]]"
    
    } else {
    
    Example Subject DN:  /C=AU/ST=NSW/L=Syd/O=Your Organisation/OU=Your OU/CN=John Smith
    set cert_subject_dn [X509::subject [SSL::cert 0]]
    if {$cc_debug}{log "Parsed subject: $cert_subject_dn"}
    
    set cert_issuer_dn [X509::issuer [SSL::cert 0]]
    if {$cc_debug}{log "Parsed issuer: $cert_issuer_dn"}
    
    Check if the client certificate contains the correct CN the data group
    if { [class match $cert_subject_dn contains ExtQuotes_CN_List] }{
    
     Client cert subject is valid
    if {$cc_debug}{log "Client certificate subject: $cert_subject_dn"}
    
     Check if the client certificate contains the correct Issuer from the data group
    if { [class match $cert_issuer_dn contains ExtQuotes_Issuer_List] } {
    
     Client cert subject is valid
    if {$cc_debug}{log "Client certificate subject is valid: $cert_subject_dn"}
    
    } else {
     Client cert issuer is not valid
    if {$cc_debug}{log "Client certificate issuer not valid: $cert_issuer_dn"}
    set reason "Invalid issuer: $cert_issuer_dn"
    }
    } else {
     Client cert subject is not valid
    if {$cc_debug}{log "Client certificate subject not valid: $cert_subject_dn"}
    set reason "Invalid subject: $cert_subject_dn"
    }
    }
    }
    if {$redirect}{
    if {$cc_debug}{log "No matching Client Certificate or Issuer Was Found Using: $cert_subject_dn or $cert_issuer_dn"}
     Reject the connection
    reject
    
     Or send a redirect to a remediation URL
    HTTP::redirect "https://fixyourcert.example.com/reason=[URI::encode $reason]"
    TCP::close
    }
    }
    

    If you use the HTTP::redirect to send the client to a separate page which explains why their request was rejected, make sure that you HTML encode any data you display back to the client to avoid any XSS vulnerabilities. You could also send a response with content directly from the iRule using HTTP::respond instead of a redirect.

    If you test this could you let me know how it goes? If it works, I'll add it to the codeshare.

    Thanks, Aaron
  • Hi Misty,

    It would be better to create a new post for a new question. Regardless, you can remove the $:: prefix from the data group and replace matchclass with class match:

    when CLIENT_ACCEPTED {
       if { [IP::addr [IP::client_addr] equals 10.10.10.10 ] or [class match [IP::client_addr] equals ext_net ] } {
          pool ssh
       } else {
          discard
       }
    }
    

    You could also move the single IP address into the ext_net address data group and remove the IP::addr command.

    Aaron