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;
}
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
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;
+ }
}
}
if (objt_listener(conn->target)->bind_conf->ca_ignerr & (1ULL << err))
return 1;
+ conn->err_code = CO_ER_SSL_CA_FAIL;
return 0;
}
if (objt_listener(conn->target)->bind_conf->crt_ignerr & (1ULL << err))
return 1;
+ conn->err_code = CO_ER_SSL_CRT_FAIL;
return 0;
}
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)
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);
return 0;
}
/* don't know how to handle such a target */
+ conn->err_code = CO_ER_SSL_NO_TARGET;
return -1;
}
/* 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 {
* 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;
}
}
/* 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 {
* 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;
}
}
/* Fail on all other handshake errors */
conn->flags |= CO_FL_ERROR;
+ if (!conn->err_code)
+ conn->err_code = CO_ER_SSL_HANDSHAKE;
return 0;
}