For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

Marcin_01_16191's avatar
Marcin_01_16191
Icon for Nimbostratus rankNimbostratus
Sep 11, 2014

Client Certificate Authentication/Certificate in header PROBLEM

Hi everyone,

I have big problem with f5. In my application I authentication users by their cert. Authentication is required in specified URL. Bellow my iRule. I have configured Client SSL Profile and connected to VIP: every options default excluding:


Client Certificate: ignore 
Frequency: once 
Certificate Chain Traversal Depth 9 
Trusted Certificate Authorities: My_CA 
Advertised Certificate Authorities: None 
Certificate Revocation List (CRL): My_CRL

When I open url: "/url/no_"1 I get prompt about client certificate. This is OK. But when I choose certificate and click "OK" f5 should add and send my client cert to the application in header. F5 don't send this certificate. Header is blank. F5 add and send certificate in header after 2 redirection or when user two time refresh website. Cert should by always send in header. If header is blank application returns 401 (unauthorized).

Please help me, thank you

My irule in the order:

iRule1:


when HTTP_REQUEST { 
set host [string tolower [HTTP::host]]
if { $host eq "" }
{
set host [IP::local_addr]
}
STREAM::disable
}
when HTTP_RESPONSE {
 if { [HTTP::header value Content-Type] contains "text" and $host ne "" }
  {
    STREAM::expression "@http://$host @https://$host@"
    STREAM::enable
  }
 if {  [string tolower [HTTP::header Location]] starts_with "http://$host" }
  {
    HTTP::header replace Location [string map -nocase "http://$host https://$host" 
[HTTP::header Location]]
  }
}
iRule2:


when CLIENTSSL_HANDSHAKE { 
   set cur [SSL::sessionid] 
   set ask [session lookup ssl $cur] 
   if { $ask eq "" } { 
     session add ssl [SSL::sessionid] [SSL::cert 0]
   }
 }
 when HTTP_REQUEST  {
   set id [SSL::sessionid]
   set the_cert [session lookup ssl $id]
   if { $the_cert != ""} {
     HTTP::header insert SSL_CLIENT_CERT [X509::whole $the_cert]
   }
 }
iRule3:


when CLIENTSSL_HANDSHAKE {
  if { [SSL::cert count] ==0 } {
  }
  else {
    HTTP::release 
  }
}

when HTTP_REQUEST {
 if { [HTTP::uri] starts_with "/url/no_1" or [HTTP::uri] starts_with "/url/no_2"  } {
    if {[SSL::cert count] == 0} {
    HTTP::collect
        SSL::authenticate always
        SSL::authenticate depth 9
        SSL::cert mode require
        SSL::renegotiate
    }
  }
  else {
  }
}

2 Replies

  • Give this a shot. It's also a combination of all of your rules, so you can replace all of them for this one:

    when CLIENTSSL_CLIENTCERT {
        if { [SSL::cert count] < 1 } {
             if the client did not present a certificate - fail
            reject
        } else {
             set a temporary cert variable here
            set clientcertdata [X509::whole [SSL::cert 0]]
        }
        HTTP::release
    }
    when HTTP_REQUEST {
         get host header and disable STREAM
        set host [string tolower [HTTP::host]]
        if { $host eq "" } {
            set host [IP::local_addr]
        }
        STREAM::disable
    
         private URI space requested and F5AUTH cookie does not exist - prompt for client certificate
        if { not ( [HTTP::uri] equals "/favicon.ico" ) and ( [HTTP::uri] starts_with "/private" ) and not ( [HTTP::cookie exists F5AUTH] ) } { 
             invalidate SSL and renegotiate
            HTTP::collect
            SSL::session invalidate
            SSL::authenticate always
            SSL::authenticate depth 9
            SSL::cert mode require
            SSL::renegotiate
        } elseif { [HTTP::cookie exists F5AUTH] } {
             F5AUTH cookie exists - send HTTP header data
            if { [table lookup -subtable CERTDATA [HTTP::cookie value F5AUTH]] ne "" } {
                 insert cert subject          
                HTTP::header replace SSL-CLIENT-CERT [table lookup -subtable CERTDATA [HTTP::cookie value F5AUTH]]
            }
        }
    }
    when HTTP_REQUEST_SEND {    
        clientside {
            if { ( [info exists clientcertdata] ) and not ( [HTTP::cookie exists F5AUTH] ) } {
                 send first header            
                HTTP::header replace SSL-CLIENT-CERT $clientcertdata
            }
        }
    }
    when HTTP_RESPONSE {
         process response payload with STREAM
        if { [HTTP::header value Content-Type] contains "text" and $host ne "" } {
            STREAM::expression "@http://$host @https://$host@"
            STREAM::enable
        }
         rewrite the redirect Location header if it exists
        if { [string tolower [HTTP::header Location]] starts_with "http://$host" } {
            HTTP::header replace Location [string map -nocase "http://$host https://$host" [HTTP::header Location]]
        }
    
         if the uniqueid variable is set - send the F5AUTH cookie to client
        if { [info exists clientcertdata] } {
             generate a GUID
            set uniqueid "_[string range [AES::key 256] 34 end]"
    
             insert the table entry
            table add -subtable CERTDATA $uniqueid $clientcertdata 3600
    
             send the cookie
            HTTP::header insert "Set-Cookie" "F5AUTH=$uniqueid; path=/; secure; HTTPOnly"
    
             unset the clientcertdata variable
            unset clientcertdata
        }
    }
    

    The iRule sets a cookie and stores the cookie data in a session table entry to guarantee that a) it always exists, and b) the user doesn't have to renegotiate SSL every time they attempt to access a private URI. You'll need to modify the URI condition above for your private URI patterns.