Forum Discussion

DecDawkins_3864's avatar
DecDawkins_3864
Icon for Nimbostratus rankNimbostratus
Apr 02, 2019

Base64 decode certificate in header help

Hi!

Looking for some help on using the b64decode option within my irule, to decode an incoming client certificate which has been base64 encoded in a custom HTTP header.

I currently have the client certificate validation working (line 6 down), however due to changes in the application now require to decode said incoming certificate. I've written a first pass configuration, which I believe should see an HTTP requests, if the header equals a certain string, it should find and decode said string, then pass onto the cert validation.

when HTTP_REQUEST {
    if { [HTTP::header exists X-Client-Cert-Example]}
    b64decode [findstr [HTTP::header X-Client-Cert-Example]]
}
 
when CLIENTSSL_CLIENTCERT {
    Set up variables
    set ::org "O=Example Org"
    set ::cust "CN=Example Cust"
    set ::debug 1
    set ::to_reject 0
    
  Check if the client provided a certificate
    if {[SSL::cert 0] eq ""}{
         Reject if the client provided no certificate
        if { $::debug }{ log "NO Client Certificate Received from client [IP::client_addr]:[TCP::local_port]" }
        set ::to_reject 1
        return
    } else {
         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]]
        if { $::debug }{ log "Client Certificate Received: $subject_dn" }
        return
        Check if the client certificate contains the correct O and a CN
        if { ($subject_dn contains $::cust) and ($subject_dn contains $::org) } {
             Accept the client cert and drop through to the HTTP_REQUEST
            if { $::debug }{ log "Client Certificate Accepted: $subject_dn" }
        } else {
            if { $::debug }{ log "No Matching Client Certificate Was Found Using: $subject_dn" }
            set ::to_reject 1
            return
        }
    }
}

Cheers,

Dec

7 Replies

  • Hi,

     

    Could you please explain the connection flow ? the issue here is that the "CLIENTSSL_CLIENTCERT" event is triggered only when the client sends a certificate during an SSL handshanke, not when sending the certificate inside an HTTP header with a GET/POST request.

     

    is the client trying to set up an ssl connection with the VS ? or is he simply sending a certificate inside a http request ?

     

    many thanks,

     

    karim

     

    • DecDawkins_3864's avatar
      DecDawkins_3864
      Icon for Nimbostratus rankNimbostratus

      Hi Karim,

       

      We have a cloud proxy sending a two way client cert request to exampleurl.com. Exampleurl.com is protected by F5 Silverline, with it's backend being a BigIP. Silverline cannot provide the client cert auth, so the SOC team have written an irule to encode the cert and pass it to the backend in the header leaving it to our BigIP backend to validate the cert.

       

      Cheers,

       

      Dec

       

    • Karim_Benyello1's avatar
      Karim_Benyello1
      Icon for Cirrus rankCirrus

      Ok, if I understand well: your bigip receives a certificate inside an HTTP header and you want to validate it. Your BIGIP doesn't request the client certificate as part of the SSL handshake.

      If the above is correct then the event "CLIENTSSL_CLIENTCERT" is never triggered on your bigip. You have to validate the certificate inside the HTTP_REQUEST event. Try the following:

      when HTTP_REQUEST {
      if { [HTTP::header exists "X-Client-Cert-Example"] } {
          set cert_header [b64decode [HTTP::header "X-Client-Cert-Example"]]
          set subject_dn [X509::subject $cert_header]
          log local0. $subject_dn
           you can add below all the tests you want about the certificate; 
      }
      }
      

      Many thanks,

      Karim

  • Hi,

     

    Could you please explain the connection flow ? the issue here is that the "CLIENTSSL_CLIENTCERT" event is triggered only when the client sends a certificate during an SSL handshanke, not when sending the certificate inside an HTTP header with a GET/POST request.

     

    is the client trying to set up an ssl connection with the VS ? or is he simply sending a certificate inside a http request ?

     

    many thanks,

     

    karim

     

    • DecDawkins_3864's avatar
      DecDawkins_3864
      Icon for Nimbostratus rankNimbostratus

      Hi Karim,

       

      We have a cloud proxy sending a two way client cert request to exampleurl.com. Exampleurl.com is protected by F5 Silverline, with it's backend being a BigIP. Silverline cannot provide the client cert auth, so the SOC team have written an irule to encode the cert and pass it to the backend in the header leaving it to our BigIP backend to validate the cert.

       

      Cheers,

       

      Dec

       

    • Karim's avatar
      Karim
      Icon for Cirrus rankCirrus

      Ok, if I understand well: your bigip receives a certificate inside an HTTP header and you want to validate it. Your BIGIP doesn't request the client certificate as part of the SSL handshake.

      If the above is correct then the event "CLIENTSSL_CLIENTCERT" is never triggered on your bigip. You have to validate the certificate inside the HTTP_REQUEST event. Try the following:

      when HTTP_REQUEST {
      if { [HTTP::header exists "X-Client-Cert-Example"] } {
          set cert_header [b64decode [HTTP::header "X-Client-Cert-Example"]]
          set subject_dn [X509::subject $cert_header]
          log local0. $subject_dn
           you can add below all the tests you want about the certificate; 
      }
      }
      

      Many thanks,

      Karim

  • Hi DecDawkins,

    you can not perform a full certificate validation based on such HTTP-Header. All you can do is to extract some certificate fields.

    when HTTP_REQUEST {
        if { [HTTP::header value "X-Client-Cert-Example"] ne "" } then {
    
            log local0.debug "Certificate HTTP header detected. X-Client-Cert-Example = [HTTP::header value "X-Client-Cert-Example"]"
    
            if { [catch {
    
                log local0.debug "Trying to b64decode the certificate HTTP header..."
                set header_certificate [b64decode [HTTP::header value "X-Client-Cert-Example"]]
                log local0.debug "... successfully b64decoded the certificate HTTP header."
    
            }] } then {
    
                log local0.debug "... failed to b64decode the certificate HTTP header."
                return
    
            }
            if { [catch {
    
                log local0.debug "Trying to extract X509 certificate information..."
                set subject_name [X509::subject $header_certificate]
                set issuer_name [X509::issuer $header_certificate]
                log local0.debug "... successfully extracted Subject = \"$subject_name\" from CA = \"$issuer_name\"."
    
            }] } then {
    
                log local0.debug "... failed to extract Subject and CA values from the certificate."
    
            }
        }
    }
    

    Note: Unless you are using a very old TMOS version, you should not continue to use those

    $::variables
    . They are not CMP-compliant and forcing your Virtual Server to run just on a single CPU-core. Check out support article K13033 for further information.

    K13033: Constructing CMP-compatible iRules

    https://support.f5.com/csp/article/K13033

    Cheers, Kai