]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: add a new error codes for wrong server certificates
authorWilly Tarreau <w@1wt.eu>
Wed, 26 Jul 2017 18:09:56 +0000 (20:09 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 28 Jul 2017 09:50:16 +0000 (11:50 +0200)
If a server presents an unexpected certificate to haproxy, that is, a
certificate that doesn't match the expected name as configured in
verifyhost or as requested using SNI, we want to store that precious
information. Fortunately we have access to the connection in the
verification callback so it's possible to store an error code there.

For this purpose we use CO_ER_SSL_MISMATCH_SNI (for when the cert name
didn't match the one requested using SNI) and CO_ER_SSL_MISMATCH for
when it doesn't match verifyhost.

include/proto/connection.h
include/types/connection.h
src/ssl_sock.c

index 09467ba504f239cf7aec56acfea6fce791b19505..9b025941c6bc667852bc2b84f3afdc9129e2fefb 100644 (file)
@@ -605,6 +605,8 @@ static inline const char *conn_err_code_str(struct connection *c)
        case CO_ER_SSL_RENEG:     return "Rejected a client-initiated SSL renegociation attempt";
        case CO_ER_SSL_CA_FAIL:   return "SSL client CA chain cannot be verified";
        case CO_ER_SSL_CRT_FAIL:  return "SSL client certificate not trusted";
+       case CO_ER_SSL_MISMATCH:  return "Server presented an SSL certificate different from the configured one";
+       case CO_ER_SSL_MISMATCH_SNI: return "Server presented an SSL certificate different from the expected one";
        case CO_ER_SSL_HANDSHAKE: return "SSL handshake failure";
        case CO_ER_SSL_HANDSHAKE_HB: return "SSL handshake failure after heartbeat";
        case CO_ER_SSL_KILLED_HB: return "Stopped a TLSv1 heartbeat attack (CVE-2014-0160)";
index 1e3fb738995d7578e5a76bf00cb05c4988d64873..7da0a7a9b8a369780a77ffee33fb31ef0c62d77d 100644 (file)
@@ -179,6 +179,8 @@ enum {
        CO_ER_SSL_RENEG,        /* forbidden client renegociation */
        CO_ER_SSL_CA_FAIL,      /* client cert verification failed in the CA chain */
        CO_ER_SSL_CRT_FAIL,     /* client cert verification failed on the certificate */
+       CO_ER_SSL_MISMATCH,     /* Server presented an SSL certificate different from the configured one */
+       CO_ER_SSL_MISMATCH_SNI, /* Server presented an SSL certificate different from the expected one */
        CO_ER_SSL_HANDSHAKE,    /* SSL error during handshake */
        CO_ER_SSL_HANDSHAKE_HB, /* SSL error during handshake with heartbeat present */
        CO_ER_SSL_KILLED_HB,    /* Stopped a TLSv1 heartbeat attack (CVE-2014-0160) */
index c53cc063e7dc61e89684b51051942198a6e0f3a9..207f4275a376b384470ed10960362a3c999627bd 100644 (file)
@@ -3931,6 +3931,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
        SSL *ssl;
        struct connection *conn;
        const char *servername;
+       const char *sni;
 
        int depth;
        X509 *cert;
@@ -3952,6 +3953,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
         * verification is OK.
         */
        servername = SSL_get_servername(conn->xprt_ctx, TLSEXT_NAMETYPE_host_name);
+       sni = servername;
        if (!servername) {
                servername = objt_server(conn->target)->ssl_ctx.verify_host;
                if (!servername)
@@ -4003,6 +4005,9 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
                }
        }
 
+       /* report the mismatch and indicate if SNI was used or not */
+       if (!ok && !conn->err_code)
+               conn->err_code = sni ? CO_ER_SSL_MISMATCH_SNI : CO_ER_SSL_MISMATCH;
        return ok;
 }