]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: ssl: wrong priority whem limiting ECDSA ciphers in ECDSA+RSA configuration
authorWilliam Lallemand <wlallemand@haproxy.com>
Wed, 5 Jun 2024 09:37:14 +0000 (11:37 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Wed, 5 Jun 2024 13:33:36 +0000 (15:33 +0200)
The ClientHello Callback which is used for certificate selection uses
both the signature algorithms and the ciphers sent by the client.

However, when a client is announcing both ECDSA and RSA capabilities
with ECSDA ciphers that are not available on haproxy side and RSA
ciphers that are compatibles, the ECDSA certificate will still be used
but this will result in a "no shared cipher" error, instead of a
fallback on the RSA certificate.

For example, a client could send
'ECDHE-ECDSA-AES128-CCM:ECDHE-RSA-AES256-SHA and HAProxy could be
configured with only 'ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA'.

This patch fixes the issue by validating that at least one ECDSA cipher
is available on both side before chosing the ECDSA certificate.

This must be backported on all stable versions.

src/ssl_sock.c

index e6bf3ff179ade3a3ca27edfbc96bf7f441fc9e1b..94f950e489d0464ce33b32ea8561658dd456fadd 100644 (file)
@@ -2268,10 +2268,14 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
        }
        if (has_ecdsa_sig) {  /* in very rare case: has ecdsa sign but not a ECDSA cipher */
                const SSL_CIPHER *cipher;
+               STACK_OF(SSL_CIPHER) *ha_ciphers; /* haproxy side ciphers */
                uint32_t cipher_id;
                size_t len;
                const uint8_t *cipher_suites;
+
+               ha_ciphers = SSL_get_ciphers(ssl);
                has_ecdsa_sig = 0;
+
 #ifdef OPENSSL_IS_BORINGSSL
                len = ctx->cipher_suites_len;
                cipher_suites = ctx->cipher_suites;
@@ -2290,6 +2294,10 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
                        if (!cipher)
                                continue;
 
+                       /* check if this cipher is available in haproxy configuration */
+                       if (sk_SSL_CIPHER_find(ha_ciphers, cipher) == -1)
+                               continue;
+
                        cipher_id = SSL_CIPHER_get_id(cipher);
                        /* skip the SCSV "fake" signaling ciphersuites because they are NID_auth_any (RFC 7507) */
                        if (cipher_id == SSL3_CK_SCSV || cipher_id == SSL3_CK_FALLBACK_SCSV)