From 71d058c288b4d108ce9352da712fd33fa5a434c7 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 26 Jul 2017 20:09:56 +0200 Subject: [PATCH] MINOR: ssl: add a new error codes for wrong server certificates 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 | 2 ++ include/types/connection.h | 2 ++ src/ssl_sock.c | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/include/proto/connection.h b/include/proto/connection.h index 09467ba50..9b025941c 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -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)"; diff --git a/include/types/connection.h b/include/types/connection.h index 1e3fb7389..7da0a7a9b 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -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) */ diff --git a/src/ssl_sock.c b/src/ssl_sock.c index c53cc063e..207f4275a 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -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; }