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.
diff --git a/include/proto/connection.h b/include/proto/connection.h
index 09467ba..9b02594 100644
--- a/include/proto/connection.h
+++ b/include/proto/connection.h
@@ -605,6 +605,8 @@
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 1e3fb73..7da0a7a 100644
--- a/include/types/connection.h
+++ b/include/types/connection.h
@@ -179,6 +179,8 @@
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 c53cc06..207f427 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -3931,6 +3931,7 @@
SSL *ssl;
struct connection *conn;
const char *servername;
+ const char *sni;
int depth;
X509 *cert;
@@ -3952,6 +3953,7 @@
* 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 @@
}
}
+ /* 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;
}