Forum Discussion

Vasil_Genov's avatar
Vasil_Genov
Icon for Altostratus rankAltostratus
Jan 17, 2022

iRule to Insert Client Cert into HTTP Header only when Certificate is from certain Root CA

Hello Group,

 

My curent setup is as follows:

I have a HTTPS VS with Clinet SSL profile that has Client Authentication set to Request with Trusted CA and Advertised CA set to appropriate CA.

What I need to achieve is to insert the client Cert into the HTTP Header with the following conditions:

1) If there is no client Cert in the request, LTM should simply establish the connection.

2) If there is a client cert and it is signed by the Trunster CA, I should inser the ssl cert in X-Client-Cert and establish the connection.

3) If there is a client cert and it is not signed by the Trunster CA, I should reject the connetion.

4) if the reqest alredy has a X-Client-Cert header, I should drop the connection.

 

I do not have much experience in creating iRules but thied something like this:

when RULE_INIT {

    set static::debug 1

}

 

when CLIENTSSL_CLIENTCERT {

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

    if { $subject_dn != "" }{

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

    }

}

when HTTP_REQUEST {

    if { ($subject_dn contains "CN=blah-blah") } {

HTTP::header insert X-Client-Cert [b64encode [SSL::cert 0]]

    }

    else {

    continue

    }

}

 

Needless to say, it did not work :D

Scenarios 1) and 4) returned „SSL_connect: Connection reset by peer in connection to test-site:443“

Scenarios 2) adn 3) returned „SSL_read: Connection reset by peer, errno 54“

 

Any suggestions would be great.

Thanks in advance!

  • I modified the rule and also added a check for existing x-client-cert. Now it seem to work.

    when RULE_INIT {

      set static::org "O=MON"

    }

     

    when CLIENTSSL_CLIENTCERT {

    if {[SSL::cert 0] eq ""}{

      return

      }

    else {

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

    log "Client Certificate Received: $issuer_dn"

    if { ($issuer_dn contains $static::org) } {

    log "Client Certificate Accepted: $issuer_dn"

    }

    else {

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

    reject

    }

    }

    }

     

    when HTTP_REQUEST {

    foreach header_name [HTTP::header names] {

    if {[string match -nocase x-client-cert $header_name]}{

    HTTP::header remove $header_name

      }

      }

       HTTP::header insert X-Client-Cert [b64encode [SSL::cert 0]]  

    }

     

    I am leaving the full rule here, so if anyone need something similar, it can be used.

  • I updated the iRule as follows:

    when RULE_INIT {

      set static::org "OU=<neededOU>"

    }

     

    when CLIENTSSL_CLIENTCERT {

    if {[SSL::cert 0] eq ""}{

      return

      }

    else {

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

    log "Client Certificate Received: $subject_dn"

    if { ($subject_dn contains $static::org) } {

    log "Client Certificate Accepted: $subject_dn"

    }

    else {

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

    reject

    }

    }

    }

     

    when HTTP_REQUEST {

      HTTP::header insert X-Client-Cert [b64encode [SSL::cert 0]]

    }

     

    Now I get somehow mixed results -

    1 is OK

    2 is OK

    3 is Kinda OK - connection is reset

    4 is not OK (which at time point is obvious as I am not actually trying to correct it - I want to get first 3 working first)

     

    So what Is left is how to check if there is already and inserted spoofed X-Client-Cert in the header.

    Any suggestions?

     

  • I modified the rule and also added a check for existing x-client-cert. Now it seem to work.

    when RULE_INIT {

      set static::org "O=MON"

    }

     

    when CLIENTSSL_CLIENTCERT {

    if {[SSL::cert 0] eq ""}{

      return

      }

    else {

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

    log "Client Certificate Received: $issuer_dn"

    if { ($issuer_dn contains $static::org) } {

    log "Client Certificate Accepted: $issuer_dn"

    }

    else {

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

    reject

    }

    }

    }

     

    when HTTP_REQUEST {

    foreach header_name [HTTP::header names] {

    if {[string match -nocase x-client-cert $header_name]}{

    HTTP::header remove $header_name

      }

      }

       HTTP::header insert X-Client-Cert [b64encode [SSL::cert 0]]  

    }

     

    I am leaving the full rule here, so if anyone need something similar, it can be used.