]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: ssl: suboptimal certificate selection with TLSv1.3 and dual ECDSA/RSA
authorWilliam Lallemand <wlallemand@haproxy.com>
Tue, 24 Oct 2023 21:58:02 +0000 (23:58 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Thu, 26 Oct 2023 17:17:13 +0000 (19:17 +0200)
When using TLSv1.3, the signature algorithms extension is used to chose
the right ECDSA or RSA certificate.

However there was an old test for previous version of TLS (< 1.3) which
was testing if the cipher is compatible with ECDSA when an ECDSA
signature algorithm is used. This test was relying on
SSL_CIPHER_get_auth_nid(cipher) == NID_auth_ecdsa to verify if the
cipher is still good.

Problem is, with TLSv1.3, all ciphersuites are compatible with any
authentication algorithm, but SSL_CIPHER_get_auth_nid(cipher) does not
return NID_auth_ecdsa, but NID_auth_any.

Because of this, with TLSv1.3 when both ECDSA and RSA certificates are
available for a domain, the ECDSA one is not chosen in priority.

This patch also introduces a test on the cipher IDs for the signaling
ciphersuites, because they would always return NID_auth_any, and are not
relevent for this selection.

This patch fixes issue #2300.

Must be backported in all stable versions.

src/ssl_sock.c

index 8a3a1b04f13de081efeecde6d776decf7b4b5ec0..0e83253464d170b53c8bb9158a788ac317c33d69 100644 (file)
@@ -2487,6 +2487,7 @@ 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;
+               uint32_t cipher_id;
                size_t len;
                const uint8_t *cipher_suites;
                has_ecdsa_sig = 0;
@@ -2505,7 +2506,13 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
 #else
                        cipher = SSL_CIPHER_find(ssl, cipher_suites);
 #endif
-                       if (cipher && SSL_CIPHER_get_auth_nid(cipher) == NID_auth_ecdsa) {
+                       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)
+                               continue;
+
+                       if (cipher && (   SSL_CIPHER_get_auth_nid(cipher) == NID_auth_ecdsa
+                                      || SSL_CIPHER_get_auth_nid(cipher) == NID_auth_any)) {
                                has_ecdsa_sig = 1;
                                break;
                        }