Forum Discussion

Brad_Baker's avatar
Apr 18, 2024

Chrome V 124+ on MacOS - Virtual Server Access Issue

(editors note: this is not just MacOS - appears to be all Chrome browsers regardless of OS)

It appears that the latest version of Google Chrome (version 124) on MacOS (ed. any OS) has broken the above code. With debugging turned on, we get this when a MacOS client accesses a virtual server with this rule:

No SSL/TLS protocol detected ; connection is rejected (0x0000)

Can anyone else confirm this? Any idea how to fix it? Stanislas_Piro2 

----

(Editors Note: This forum post was created via a comment on the OG Article written by Eric_Chen here:
How to use SNI Routing with BIG-IP.
That article contains 'the above code' and 'the rule' referenced here)

  • Brad_Baker  / LiefZimmerman  / Eric_Chen  / Stan_PIRON_F5 / Stanislas_Piro2 

    I have patched my copy of the original iRule with what I think is a working fix, but I would love if someone in the community could validate it, because my knowledge of the intricacies of the TLS packet is not strong.

    Essentially, I have replaced this if check in the original...

    # If valid TLS 1.X CLIENT_HELLO handshake packet
    if { [binary scan $payload cH4Scx3H4x32c tls_record_content_type tls_version tls_recordlen tls_handshake_action tls_handshake_version tls_handshake_sessidlen] == 6 && \
        ($tls_record_content_type == 22) && \
        ([string match {030[1-3]} $tls_version]) && \
        ($tls_handshake_action == 1) && \
        ($payloadlen == $tls_recordlen+5)} {

    ...with this block, which is intended to determine whether the reported TLS record length is longer than the payload we have and, if so, collect more packets until we have enough:

    # Keep collecting if CLIENT_HELLO messages that span more than one packet...
    if {![info exists payloadscan]} {
        set payloadscan [binary scan $payload cH4Scx3H4x32c tls_record_content_type tls_version tls_recordlen tls_handshake_action \
                                                            tls_handshake_version tls_handshake_sessidlen]
    }
    if {($payloadscan == 6)} {
        if {($tls_recordlen < 0 || $tls_recordlen > 16389)} {  # if we are asked to collect more than we will handle, bail...
            log local0.warn "[IP::remote_addr] : parsed TLS record length ${tls_recordlen} outside of handled length (0..16389)"
            reject
            return
        } elseif {($payloadlen < $tls_recordlen+5)} {          # if we have not collected enough yet, collect some more
            TCP::collect [expr {$tls_recordlen+5 - $payloadlen}]
            return
        }
    }
    
    # If valid TLS 1.X CLIENT_HELLO handshake packet
    if {($payloadscan == 6) && \
        ($tls_record_content_type == 22) && \
        ([string match {030[1-3]} $tls_version]) && \
        ($tls_handshake_action == 1) && \
        ($payloadlen == $tls_recordlen+5)} {

    This has allowed the rest of the original logic to capture the SNI server name and my services to resume operation.

    However, one new thing of note, is that the resulting values in $tls_handshake_preferred_version now include an extra value.  If I log this value, I can see...

    • Firefox returns 0304 0303 0302 0301
    • Chrome/Edge with --ssl-version-max=tls1.2 return 0303 only
    • Chrome/Edge v124 return xAxA 0304 0303

     

    The xAxA value changes every time -- so far, I have seen 1A1A, 7A7A, 8A8A, DADA and FAFA.  (I do not see a 7Fxy, as indicated in the switch statement).

    I am now wondering if this is just an implementation detail of the new Chrome TLS packet, or if I/we are now reading the preferred values from the wrong position in the payload.

    Is anyone able to verify the above?

  • Brad_Baker 

    I can't speak to the issue technically but I am interested in whether you get a resolution here?
    If Eric_Chen or Stan_PIRON_F5 can't help right away (or at all?) perhaps a new post in the Technical Forum is in order. 

    I may even be able to move it automagically for you if you like

     

    • Brad_Baker's avatar
      Brad_Baker
      Icon for Cirrus rankCirrus

      I have not heard from anyone so far. It seems this issue may be greater in scope than I realized. Its not just chrome 124 on Mac apparently its impacting Google Chrome 124, Google Chrome 125 and Google Chrome 126 on Windows, Linux, and Mac, Google Chrome 125/126 are pre-release though. 

      • Brad_Baker's avatar
        Brad_Baker
        Icon for Cirrus rankCirrus

        LiefZimmermanMoving this to a new thread would be great - I would love to get some eyes on this as its impacting us greatly - more and more complaints are pouring in and we've had to turn off SNI on some of our more popular VIPs.

        I know SNI can be implemented using F5 LTM policies but frankly we found that kludgy - its slow to work with you have to create drafts and then publish them, and set a lot of drop downs that end up being identical for all our sites. 

        Maybe its just our LTMs but it took 3-5 minutes to publish each policy it was SO incredibly painful to work with that we abandoned it for this irule approach which up until now has worked great. It takes second to add a new site to the datagroup. But if we can't find a solution to this fast we may have to go back to policies 😰

        Unfortunately this rule is quite complex - if it was simpler I might be able to edit it but I'm not sure I'll be able to figure out what's going on without some help. 

  • I do not read the thread completely, but why all this TCP::collect stuff? I personally use a SSL Persistence Profile with a simple iRule:

    when CLIENTSSL_CLIENTHELLO priority 100 {
        set sni_name ""
        if { [SSL::extensions exists -type 0] } {
            binary scan [SSL::extensions -type 0] {@9A*} sni_name
            log local0. "SNI: $sni_name"
        }
        switch -- [string tolower $sni_name] {
        ...
        }
    }

     

    • Brad_Baker's avatar
      Brad_Baker
      Icon for Cirrus rankCirrus

      Here's the original article about this (with now broken code): https://community.f5.com/kb/technicalarticles/multiple-certs-one-vip-tls-server-name-indication-via-irules/275951

      Per https://clouddocs.f5.com/cli/tmsh-reference/v16/modules/ltm/ltm_rule_command_SSL_extensions.html SSL::Extensions is only valid during:
      CLIENTSSL_CLIENTCERT CLIENTSSL_HANDSHAKE CLIENTSSL_CLIENTHELLO SERVERSSL_HANDSHAKE SERVERSSL_SERVERHELLO SERVERSSL_CLIENTHELLO_SEND

      My impression/understanding is that you need a client SSL profile associated with the VIP for SSL::Extensions to be valid in an iRule. I could have that wrong though. 

      In this case we have a single VIP acting as a SNI router. It looks at the SNI domain and then re-routes traffic to hundreds of destination VIPs based on a datagroup mapping.

      If we used the SSL::Extensions we'd have to have all our Client SSL profiles (hundreds of them) associated with the SNI router VIP. 

      And at least my experience has been if you have multiple Client SSL profiles associated with a VIP F5 doesn't always pick the correct ssl profile to use. 

      • candc's avatar
        candc
        Icon for Cirrus rankCirrus

        Juergen_Mang 

        It's not just Brad's article which espouses this approach.  https://devcentral.f5.com/s/articles/sni-based-pool-selection-without-clientssl-profile-1119 also describes using raw TCP data in the CLIENT_DATA event to grab SNI like this.

        My workaround/patch is specific to the iRule described in the URL above, from which our own SNI handing was heavily derived.

        Reworking this to use CLIENTSSL_CLIENTHELLO and SSL::extensions may well be a reasonable next-step but, for the time being, I just needed to get the original iRule in working state again...

  • My impression/understanding is that you need a client SSL profile associated with the VIP for SSL::Extensions to be valid in an iRule. I could have that wrong though.

    No, a SSL Persistence Profile is sufficient enough for SNI based routing functionality. Give it a try, it works in my setups like a charm and it is ridiculous easy.