From 20879a0233c252e06a5703d7c43cc0fa4a611b5a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 3 Dec 2012 16:32:10 +0100 Subject: [PATCH] MEDIUM: connection: add error reporting for the SSL Get a bit more info in the logs when client-side SSL handshakes fail. --- include/proto/connection.h | 9 ++++++++ include/types/connection.h | 9 ++++++++ src/session.c | 3 ++- src/ssl_sock.c | 42 ++++++++++++++++++++++++++++++++++---- 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/include/proto/connection.h b/include/proto/connection.h index 8a40575a7f..ddfb89e4ef 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -476,7 +476,16 @@ static inline const char *conn_err_code_str(struct connection *c) case CO_ER_PRX_NOT_HDR: return "Received something which does not look like a PROXY protocol header"; case CO_ER_PRX_BAD_HDR: return "Received an invalid PROXY protocol header"; case CO_ER_PRX_BAD_PROTO: return "Received an unhandled protocol in the PROXY protocol header"; + case CO_ER_SSL_EMPTY: return "Connection closed during SSL handshake"; + case CO_ER_SSL_ABORT: return "Connection error during SSL handshake"; case CO_ER_SSL_TIMEOUT: return "Timeout during SSL handshake"; + case CO_ER_SSL_TOO_MANY: return "Too many SSL connections"; + case CO_ER_SSL_NO_MEM: return "Out of memory when initializing an SSL connection"; + 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_HANDSHAKE: return "SSL handshake failure"; + case CO_ER_SSL_NO_TARGET: return "Attempt to use SSL on an unknownn target (internal error)"; } return NULL; } diff --git a/include/types/connection.h b/include/types/connection.h index f9bedcdcc2..85ea48c306 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -154,7 +154,16 @@ enum { CO_ER_PRX_BAD_HDR, /* bad PROXY protocol header */ CO_ER_PRX_BAD_PROTO, /* unsupported protocol in PROXY header */ + CO_ER_SSL_EMPTY, /* client closed during SSL handshake */ + CO_ER_SSL_ABORT, /* client abort during SSL handshake */ CO_ER_SSL_TIMEOUT, /* timeout during SSL handshake */ + CO_ER_SSL_TOO_MANY, /* too many SSL connections */ + CO_ER_SSL_NO_MEM, /* no more memory to allocate an SSL connection */ + 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_HANDSHAKE, /* SSL error during handshake */ + CO_ER_SSL_NO_TARGET, /* unkonwn target (not client nor server) */ }; /* xprt_ops describes transport-layer operations for a connection. They diff --git a/src/session.c b/src/session.c index c22459ba71..e5350350a0 100644 --- a/src/session.c +++ b/src/session.c @@ -286,7 +286,8 @@ static void kill_mini_session(struct session *s) if (log && (s->fe->options & PR_O_NULLNOLOG)) { /* with "option dontlognull", we don't log connections with no transfer */ if (!conn->err_code || - conn->err_code == CO_ER_PRX_EMPTY || conn->err_code == CO_ER_PRX_ABORT) + conn->err_code == CO_ER_PRX_EMPTY || conn->err_code == CO_ER_PRX_ABORT || + conn->err_code == CO_ER_SSL_EMPTY || conn->err_code == CO_ER_SSL_ABORT) log = 0; } diff --git a/src/ssl_sock.c b/src/ssl_sock.c index be324c0ee8..35c7bd91d5 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -93,8 +93,10 @@ void ssl_sock_infocbk(const SSL *ssl, int where, int ret) if (where & SSL_CB_HANDSHAKE_START) { /* Disable renegotiation (CVE-2009-3555) */ - if (conn->flags & CO_FL_CONNECTED) + if (conn->flags & CO_FL_CONNECTED) { conn->flags |= CO_FL_ERROR; + conn->err_code = CO_ER_SSL_RENEG; + } } } @@ -128,6 +130,7 @@ int ssl_sock_verifycbk(int ok, X509_STORE_CTX *x_store) if (objt_listener(conn->target)->bind_conf->ca_ignerr & (1ULL << err)) return 1; + conn->err_code = CO_ER_SSL_CA_FAIL; return 0; } @@ -138,6 +141,7 @@ int ssl_sock_verifycbk(int ok, X509_STORE_CTX *x_store) if (objt_listener(conn->target)->bind_conf->crt_ignerr & (1ULL << err)) return 1; + conn->err_code = CO_ER_SSL_CRT_FAIL; return 0; } @@ -800,16 +804,20 @@ static int ssl_sock_init(struct connection *conn) if (conn->xprt_ctx) return 0; - if (global.maxsslconn && sslconns >= global.maxsslconn) + if (global.maxsslconn && sslconns >= global.maxsslconn) { + conn->err_code = CO_ER_SSL_TOO_MANY; return -1; + } /* If it is in client mode initiate SSL session in connect state otherwise accept state */ if (objt_server(conn->target)) { /* Alloc a new SSL session ctx */ conn->xprt_ctx = SSL_new(objt_server(conn->target)->ssl_ctx.ctx); - if (!conn->xprt_ctx) + if (!conn->xprt_ctx) { + conn->err_code = CO_ER_SSL_NO_MEM; return -1; + } SSL_set_connect_state(conn->xprt_ctx); if (objt_server(conn->target)->ssl_ctx.reused_sess) @@ -827,8 +835,10 @@ static int ssl_sock_init(struct connection *conn) else if (objt_listener(conn->target)) { /* Alloc a new SSL session ctx */ conn->xprt_ctx = SSL_new(objt_listener(conn->target)->bind_conf->default_ctx); - if (!conn->xprt_ctx) + if (!conn->xprt_ctx) { + conn->err_code = CO_ER_SSL_NO_MEM; return -1; + } SSL_set_accept_state(conn->xprt_ctx); @@ -845,6 +855,7 @@ static int ssl_sock_init(struct connection *conn) return 0; } /* don't know how to handle such a target */ + conn->err_code = CO_ER_SSL_NO_TARGET; return -1; } @@ -900,6 +911,15 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag) /* if errno is null, then connection was successfully established */ if (!errno && conn->flags & CO_FL_WAIT_L4_CONN) conn->flags &= ~CO_FL_WAIT_L4_CONN; + if (!conn->err_code) { + if (!((SSL *)conn->xprt_ctx)->packet_length) + if (!errno) + conn->err_code = CO_ER_SSL_EMPTY; + else + conn->err_code = CO_ER_SSL_ABORT; + else + conn->err_code = CO_ER_SSL_HANDSHAKE; + } goto out_error; } else { @@ -910,6 +930,8 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag) * data to avoid this as much as possible. */ ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT); + if (!conn->err_code) + conn->err_code = CO_ER_SSL_HANDSHAKE; goto out_error; } } @@ -940,6 +962,14 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag) /* if errno is null, then connection was successfully established */ if (!errno && conn->flags & CO_FL_WAIT_L4_CONN) conn->flags &= ~CO_FL_WAIT_L4_CONN; + + if (!((SSL *)conn->xprt_ctx)->packet_length) + if (!errno) + conn->err_code = CO_ER_SSL_EMPTY; + else + conn->err_code = CO_ER_SSL_ABORT; + else + conn->err_code = CO_ER_SSL_HANDSHAKE; goto out_error; } else { @@ -950,6 +980,8 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag) * data to avoid this as much as possible. */ ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT); + if (!conn->err_code) + conn->err_code = CO_ER_SSL_HANDSHAKE; goto out_error; } } @@ -980,6 +1012,8 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag) /* Fail on all other handshake errors */ conn->flags |= CO_FL_ERROR; + if (!conn->err_code) + conn->err_code = CO_ER_SSL_HANDSHAKE; return 0; }