Forum Discussion

rnavarro's avatar
rnavarro
Icon for Nimbostratus rankNimbostratus
Jun 18, 2025

irule that presents certificate doesn´ t run in TLSv1.3

 

Hi, since last update google chrome and MD edge (chromium based), clients start tunel https with TLSv1.3, and I have a irule that presents and accepts a certificate, with TLSv1.2 runs Ok, but with TLSv1.3 appears a handshake SSL fail. Another SSL profiles without irule, with only TLSv1.3, is Ok (BIGIP version 15.1.x and 16.1.x LTM) 

A known issue related to ML-KEM post-quantum TLS key exchange, which has recently become supported in the following browser versions:

  • Google Chrome 131.
  • Microsoft Edge 131.0.2903.48 (Stable).
  • Mozilla Firefox 132.0.

  Technical Tip: ERR_SSL_PROTOCOL_ERROR 

a known issue related to ML-KEM post-quantum TLS key exchange, which has recently become supported in the following browser versions: Google Chrome 13...

IRULE is same like this (when user puts in browser https://www.something/web/ in browser appears a choice with many certificates to choose one and then connect with the virtual server) :

 

when CLIENT_ACCEPTED {
  set needcert 0
  set gotcert 0
  set serror 0
}
when HTTP_REQUEST {
  #log local0. "HTTP_REQUEST"
  if { $gotcert == 0 and [HTTP::uri] contains "/web/" } {
                
    HTTP::collect
    SSL::cert mode request
    SSL::renegotiate
    set needcert 1
    #log local0. " ($needcert)"
  }
  else {
    SSL::cert mode ignore
    #log local0. ""
  }
}
when CLIENTSSL_HANDSHAKE {
  #log local0. ""
  #log local0. " count is ([SSL::cert count]) and result is =([SSL::verify_result])"
  if { [SSL::cert count] == 0 or [SSL::verify_result] != 0 } {
    #log local0. "Bad cert! "
    #log local0. "needcert  es $needcert"
    if { $needcert == 1 } {
      #reject
      set serror 1
      HTTP::release        
    }
  }
  else {
    #log local0. "Good cert!($needcert)"
    set gotcert 1
    if { $needcert == 1 } {
      HTTP::release
      #set c_cert [SSL::cert 0]
      set c_cert [X509::whole [SSL::cert 0]]
    }
  }
}
when HTTP_REQUEST_SEND {
  #log local0. "HTTP_REQUEST_SEND..."
  clientside {
    if { [info exists c_cert] } {
      #log local0. "Certificado es $c_cert"
      #HTTP::header insert X-Client-Cert [b64encode $c_cert]
      HTTP::header insert SSL_CLIENT_CERT $c_cert
      #log local0. ""     
    } else {
      if { $serror == 1 } { 
      }
    }
  }
}

 

I need help! thanks a lot.

1 Reply

  • f51's avatar
    f51
    Icon for Cumulonimbus rankCumulonimbus

    Hi rnavarro​ 

    TLS 1.3 has removed support for renegotiation. The SSL::renegotiate iRule command, which is used to request a client certificate after the initial handshake (for example, based on a specific URI), is not supported in TLS 1.3. When a client connects using TLS 1.3 and your iRule tries to invoke SSL::renegotiate, the connection will fail—typically with a handshake error or silent failure. This is exactly what you are seeing with recent versions of Chrome and Edge, which now default to TLS 1.3 and support post-quantum key exchange (ML-KEM/Kyber) ciphers.

    References:

    If you require on-demand client certificate authentication (i.e., requesting a certificate after the handshake based on URI or other conditions), you must disable TLS 1.3 in your Client SSL profile. This will force clients to use TLS 1.2, where renegotiation is still supported.

    Rewrite the iRule to Avoid Renegotiation for TLS 1.3 Connections

    when HTTP_REQUEST {

      if { [SSL::cipher version] == "TLSv1.2" } {

        # Safe to use SSL::renegotiate

        SSL::cert mode request

        SSL::renegotiate

      } else {

        # TLS 1.3 or higher: do not attempt renegotiation

        # Optionally, log or handle differently

      }

    }