]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: connection: add error reporting for the SSL
authorWilly Tarreau <w@1wt.eu>
Mon, 3 Dec 2012 15:32:10 +0000 (16:32 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 3 Dec 2012 16:21:52 +0000 (17:21 +0100)
Get a bit more info in the logs when client-side SSL handshakes fail.

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

index 8a40575a7f57474408d33f9613f5eaae68104eaa..ddfb89e4eff04b92d6d33235bed8d42cc2e1c3f2 100644 (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_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;
 }
index f9bedcdcc232bb52b961d93d6d1a53b1c79c931e..85ea48c306d1253617d32c4e15691ce09b49a6e9 100644 (file)
@@ -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
index c22459ba719446ce0d78f98e3bf84f87d61a03a7..e5350350a02702c7058bfd242ae00bbc38d92150 100644 (file)
@@ -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;
        }
 
index be324c0ee8d0d93f6a4a898be0edf15cbec1b62a..35c7bd91d5147b164ea0ed00d87109412dddd351 100644 (file)
@@ -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 @@ reneg_ok:
 
        /* Fail on all other handshake errors */
        conn->flags |= CO_FL_ERROR;
+       if (!conn->err_code)
+               conn->err_code = CO_ER_SSL_HANDSHAKE;
        return 0;
 }