MEDIUM: connection: add error reporting for the SSL

Get a bit more info in the logs when client-side SSL handshakes fail.
This commit is contained in:
Willy Tarreau 2012-12-03 16:32:10 +01:00
parent 8e3bf699db
commit 20879a0233
4 changed files with 58 additions and 5 deletions

View File

@ -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_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_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_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_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; return NULL;
} }

View File

@ -154,7 +154,16 @@ enum {
CO_ER_PRX_BAD_HDR, /* bad PROXY protocol header */ CO_ER_PRX_BAD_HDR, /* bad PROXY protocol header */
CO_ER_PRX_BAD_PROTO, /* unsupported protocol in PROXY 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_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 /* xprt_ops describes transport-layer operations for a connection. They

View File

@ -286,7 +286,8 @@ static void kill_mini_session(struct session *s)
if (log && (s->fe->options & PR_O_NULLNOLOG)) { if (log && (s->fe->options & PR_O_NULLNOLOG)) {
/* with "option dontlognull", we don't log connections with no transfer */ /* with "option dontlognull", we don't log connections with no transfer */
if (!conn->err_code || 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; log = 0;
} }

View File

@ -93,8 +93,10 @@ void ssl_sock_infocbk(const SSL *ssl, int where, int ret)
if (where & SSL_CB_HANDSHAKE_START) { if (where & SSL_CB_HANDSHAKE_START) {
/* Disable renegotiation (CVE-2009-3555) */ /* Disable renegotiation (CVE-2009-3555) */
if (conn->flags & CO_FL_CONNECTED) if (conn->flags & CO_FL_CONNECTED) {
conn->flags |= CO_FL_ERROR; 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)) if (objt_listener(conn->target)->bind_conf->ca_ignerr & (1ULL << err))
return 1; return 1;
conn->err_code = CO_ER_SSL_CA_FAIL;
return 0; 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)) if (objt_listener(conn->target)->bind_conf->crt_ignerr & (1ULL << err))
return 1; return 1;
conn->err_code = CO_ER_SSL_CRT_FAIL;
return 0; return 0;
} }
@ -800,16 +804,20 @@ static int ssl_sock_init(struct connection *conn)
if (conn->xprt_ctx) if (conn->xprt_ctx)
return 0; return 0;
if (global.maxsslconn && sslconns >= global.maxsslconn) if (global.maxsslconn && sslconns >= global.maxsslconn) {
conn->err_code = CO_ER_SSL_TOO_MANY;
return -1; return -1;
}
/* If it is in client mode initiate SSL session /* If it is in client mode initiate SSL session
in connect state otherwise accept state */ in connect state otherwise accept state */
if (objt_server(conn->target)) { if (objt_server(conn->target)) {
/* Alloc a new SSL session ctx */ /* Alloc a new SSL session ctx */
conn->xprt_ctx = SSL_new(objt_server(conn->target)->ssl_ctx.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; return -1;
}
SSL_set_connect_state(conn->xprt_ctx); SSL_set_connect_state(conn->xprt_ctx);
if (objt_server(conn->target)->ssl_ctx.reused_sess) 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)) { else if (objt_listener(conn->target)) {
/* Alloc a new SSL session ctx */ /* Alloc a new SSL session ctx */
conn->xprt_ctx = SSL_new(objt_listener(conn->target)->bind_conf->default_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; return -1;
}
SSL_set_accept_state(conn->xprt_ctx); SSL_set_accept_state(conn->xprt_ctx);
@ -845,6 +855,7 @@ static int ssl_sock_init(struct connection *conn)
return 0; return 0;
} }
/* don't know how to handle such a target */ /* don't know how to handle such a target */
conn->err_code = CO_ER_SSL_NO_TARGET;
return -1; 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 is null, then connection was successfully established */
if (!errno && conn->flags & CO_FL_WAIT_L4_CONN) if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
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; goto out_error;
} }
else { else {
@ -910,6 +930,8 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
* data to avoid this as much as possible. * data to avoid this as much as possible.
*/ */
ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT); 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; 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 is null, then connection was successfully established */
if (!errno && conn->flags & CO_FL_WAIT_L4_CONN) if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
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; goto out_error;
} }
else { else {
@ -950,6 +980,8 @@ int ssl_sock_handshake(struct connection *conn, unsigned int flag)
* data to avoid this as much as possible. * data to avoid this as much as possible.
*/ */
ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT); 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; goto out_error;
} }
} }
@ -980,6 +1012,8 @@ reneg_ok:
/* Fail on all other handshake errors */ /* Fail on all other handshake errors */
conn->flags |= CO_FL_ERROR; conn->flags |= CO_FL_ERROR;
if (!conn->err_code)
conn->err_code = CO_ER_SSL_HANDSHAKE;
return 0; return 0;
} }