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
Oct 03, 2014

Redirect when Client doesn't send certificate.

Hello

I have webpages and I authorize user by they certificate when they are in specific URL. (iRule below), this work perfectly.

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
    }
}

I need redirect Clients when they don't send certificate to server.

Example:

Client go to url "https://www.mysite.com/private", system ask him for a certificate. Client click "Cancel". Now client sees message "This webpage is not available". Client instead message "This webpage is not available" should redirect to "https://www.mysite.com/public/401.html" or he should see static pages from ifile.

I try in section CLIENTSSL_CLIENTCERT assign variable "SSL::verify_result" and then in HTTP_REQUEST redirect client if "SSL::verify_result != 0", but this doesn't work.

I try use this script:
https://devcentral.f5.com/wiki/iRules.Catch-SSL-Errors-and-return-a-friendly-page.ashx

but no effects

Please help and thank you very much

1 Reply

  • Here's a minor modification to the above:

    when CLIENTSSL_CLIENTCERT {
        if { [SSL::cert count] < 1 } {
             if the client did not present a certificate - fail
            set nocert 1
        } 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
             set to "request" to allow user to bypass cert prompt
            SSL::cert mode request
            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 nocert] } {
                 send redirect or static content if no cert selected
                HTTP::respond 200 content "No Cert" "Connection" "close"
            } elseif { ( [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
        }
    }
    

    Three things had to change:

    1. In the CLIENTSSL_CLIENTCERT event, the [SSL::cert count] < 1 evaluation simply sets a variable instead of rejecting the connection.

    2. In the HTTP_REQUEST event, set the SSL::cert mode to "request" instead of "require".

    3. In the HTTP_REQUEST_SEND event, add an evaluation to look for the "nocert" variable with [info exists nocert]. If it exists, redirect the user or respond with static HTML.