Forum Discussion

David_Haupt_130's avatar
David_Haupt_130
Icon for Nimbostratus rankNimbostratus
Oct 05, 2013

SNI and Client certificate authentication

Hi

 

LTM 11.4.0 VE

 

I want a VS that listens to 443 and terminates TLS 1.0+ https traffic. It should have two Client SSL profiles (with different certificates and hostnames in the certificates for SNI to work of course), one default and the other should use SNI. They should afterwards be proxied to different pools.

 

So far so good.

 

The problem is that I want to have Client Certificate Authentication as well. Unfortunetaly the Client SSL profiles above should not accept certificates issued from the same CA-chain. (The client certificates do share the same rootCA though).

 

The only way I can get F5 to swallow my two Client SSL profiles at the same time in my VS is to put a CA bundle containing both my CA-chains in "Trusted Certificate Authorities" on both Client SSL profiles. Unless I do this I get: 0107157c:3: Selected client SSL profiles do not match security policies for Virtual Server /Common/vs_https_external. Putting the bundle in Trusted Certificate Authorities gives the unwanted effect that clients from one CA-chain can is authenticated sucessfully agains the other Client SSL profile and the opposite. As a side note, both type of client certificates will be checked against a common OCSP server.

 

This all comes from a shortage of IP adresses.

 

Do any of you F5 professors have any idea? Do I have to code/copy-paste a custom iRule to solve this?

 

  • A bit more investigation. Without any authentication profile enabled and just a default SNI ssl client profile and another ssl client profile that uses SNI and a simple irule:

     

    when CLIENTSSL_HANDSHAKE { log local0.debug "My selected sslprofile [PROFILE::clientssl name]" }

     

    I always get the sslprofile name of the profile that is on top in the list in my VS->SSL Profile (Client) even though I send in SNI in my handskake and I get the correct server certificate back.

     

    I would have expected to get the profile name in the log that is corresponding to my SNI clientssl profile...

     

  • I've no doubt where the iRule is concerned it's simply a matter (as used to be the case with HTTP::uri and others) that what's logged doesn't actually reflect changes that have occurred during LTM (and iRule) processing. Perhaps change the event to a serverside one (but specify clientside operation) to get the real picture. Of course, logically, this may just be how things work for now.

     

    Regarding the ClientSSL issue, I assume you've specified different CA's in each profile?

     

  • This one is definitely unusual. For all intents and purposes, if the SNI-based profile selection is based on the CLIENTHELLO message, I would think the parts of the individual profiles shouldn't matter and certainly shouldn't have to match. I would also comment that trying to do anything in an iRule under the CLIENTSSL_ commands is too late in the process. For that reason I put together a potential workaround that relies on capturing the CLIENTHELLO server_name data in the (still unencrypted) TCP payload. Here's what it looks like:

     

    when CLIENT_ACCEPTED {
        TCP::collect
    }
    when CLIENT_DATA {
        if { [info exists selected_profile] } { 
             use specified client SSL profile if set
            catch { eval "SSL::profile $selected_profile" } 
        } else {
             look for CLIENTHELLO message in the TLS handshake (SSL bypassed)
            binary scan [TCP::payload] cSSc tls_xacttype tls_version tls_recordlen tls_handshake_type
            switch -- $tls_version {
                "769" -
                "770" -
                "771" { 
                    if { $tls_handshake_type equals 1 } {
                         CLIENTHELLO message
                        binary scan [TCP::payload] H* hexdump
                        if { [class match $hexdump contains my_ssl_profile_dg] } {
                             use client SSL profile from data group
                            set selected_profile [class match -value $hexdump contains my_ssl_profile_dg]
                            catch { eval "SSL::profile $selected_profile" }
                        }
                    } 
                }
            }
        }
        TCP::release
        TCP::collect
    }

    Essentially what's happening is that I'm capturing the TCP payload and looking for a CLIENTHELLO message inside a TLS (1.0, 1.1, or 1.2) handshake. I toyed with a few different approaches, but for the sake of simplicity I hex-encoded the server names and added them to a data group with the corresponding client SSL profile name. Example:

     

    6d79736572766572312e646f6d61696e2e636f6d := myserver1.domain.com_clientssl
    6d79736572766572322e646f6d61696e2e636f6d := myserver2.domain.com_clientssl

    You can get these values with the following code:

     

    when RULE_INIT {
        binary scan "myserver1.mydomain.com" H* tmp
        log local0. $tmp
    }

    Another option would have been to loop through the literal server name strings in the data group and hex encode them on the fly. Ultimately, instead of trying to binary parse the CLIENTHELLO payload to find the exact server_name value, I'm simply looking for this particular hex string in the hex-encoded payload. Once I find and match the payload value to a data group entry, I extract and use the defined client SSL profile. The SSL::profile command isn't technically supported in the CLIENT_DATA event, so I wrapped in an eval command, and again in a catch command. I also set the profile name to a local variable so that subsequent requests in the same TCP session will use the same profile. You need at least one client SSL profile applied to the VIP, and all non-TLS-capable clients should simply fall through to this default profile.

     

    The one thing it doesn't seem to support is flipping back and forth between the SSL VIPs in a single browser session. I don't imagine that'll happen often and I haven't figured out how to fix that yet. This workaround does seem to work well though. It also supports client SSL profiles with different client cert auth settings.

     

  • Thanks for the excellent reply Kevin!

     

    In my case I ended up with two SSL profiles and one OCSP authentication profile and an iRule that send traffic to the correct pool for the type of client as determined by the iRule looking at the certificate in CLIENTSSL_CLIENTCERT.

     

    It seems to work reasonably well. I think we can live with not being able to set different cipher suites on the two SSL profiles.

     

  • Hi all,

    it seems I'm running into the same issue, but I'm not sure if I really understand the above answers correctly.

    We also have a VS with currently seven different clientSSL-profiles (and might be more in the future). One of it should be configured with Client Authentication, but if I try to enable it I get the following error message.

    0107157c:3: Selected client SSL profiles do not match security policies for Virtual Server /Common/.
    

    The default SSL profile contains a self-signed wildcard certificate and all other six profiles just have its cert-key-chain configured and the appropriate "Server Name". The chain is equal for all six "real" certificates and I also tried to include it for the default wildcard profile, but the error message is still the same.

    Right now I don't see the reason for this error message and therefor don't know where to search for. And I also don't really understand if the answer from Kevin is the solution/workaround for my setup as well.

    We have another VS with just one clientSSL-profile active and there Client Authentication can be enable without any issues.

    By the way we are using 11.5.3

    Thank you for your help or further ideas!

    Ciao Stefan 🙂