From: Emeric Brun Date: Mon, 3 Sep 2012 18:36:47 +0000 (+0200) Subject: MEDIUM: ssl: protect against client-initiated renegociation X-Git-Tag: v1.5-dev12~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1f38dbb44ed7947a1036f7b267e9c2ca8aa9116;p=thirdparty%2Fhaproxy.git MEDIUM: ssl: protect against client-initiated renegociation CVE-2009-3555 suggests that client-initiated renegociation should be prevented in the middle of data. The workaround here consists in having the SSL layer notify our callback about a handshake occurring, which in turn causes the connection to be marked in the error state if it was already considered established (which means if a previous handshake was completed). The result is that the connection with the client is immediately aborted and any pending data are dropped. --- diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h index c37bcdcc1b..c630f08d8b 100644 --- a/include/proto/ssl_sock.h +++ b/include/proto/ssl_sock.h @@ -26,6 +26,7 @@ extern struct data_ops ssl_sock; int ssl_sock_handshake(struct connection *conn, unsigned int flag); +void ssl_sock_infocbk(const SSL *ssl, int where, int ret); #endif /* _PROTO_SSL_SOCK_H */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 06559e6b62..82c741ae5b 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -6704,6 +6704,7 @@ out_uri_auth_compat: SSL_CTX_set_mode(listener->ssl_ctx.ctx, sslmode); SSL_CTX_set_verify(listener->ssl_ctx.ctx, SSL_VERIFY_NONE, NULL); SSL_CTX_set_session_cache_mode(listener->ssl_ctx.ctx, SSL_SESS_CACHE_SERVER); + SSL_CTX_set_info_callback(listener->ssl_ctx.ctx, ssl_sock_infocbk); if (SSL_CTX_use_PrivateKey_file(listener->ssl_ctx.ctx, listener->ssl_cert, SSL_FILETYPE_PEM) <= 0) { Alert("Proxy '%s': unable to load SSL private key from file '%s' in listener %d (%s:%d).\n", diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 2aa11b8bc7..f5d054e74b 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -44,6 +44,19 @@ #include + +void ssl_sock_infocbk(const SSL *ssl, int where, int ret) +{ + struct connection *conn = (struct connection *)SSL_get_app_data(ssl); + (void)ret; /* shut gcc stupid warning */ + + if (where & SSL_CB_HANDSHAKE_START) { + /* Disable renegotiation (CVE-2009-3555) */ + if (conn->flags & CO_FL_CONNECTED) + conn->flags |= CO_FL_ERROR; + } +} + /* * This function is called if SSL * context is not yet allocated. The function * is designed to be called before any other data-layer operation and sets the @@ -88,6 +101,9 @@ static int ssl_sock_init(struct connection *conn) /* set fd on SSL session context */ SSL_set_fd(conn->data_ctx, conn->t.sock.fd); + /* set connection pointer */ + SSL_set_app_data(conn->data_ctx, conn); + /* leave init state and start handshake */ conn->flags |= CO_FL_SSL_WAIT_HS; return 0; @@ -197,7 +213,10 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun */ while (try) { ret = SSL_read(conn->data_ctx, bi_end(buf), try); - + if (conn->flags & CO_FL_ERROR) { + /* CO_FL_ERROR may be set by ssl_sock_infocbk */ + break; + } if (ret > 0) { buf->i += ret; done += ret; @@ -271,6 +290,10 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl try = buf->data + try - buf->p; ret = SSL_write(conn->data_ctx, bo_ptr(buf), try); + if (conn->flags & CO_FL_ERROR) { + /* CO_FL_ERROR may be set by ssl_sock_infocbk */ + break; + } if (ret > 0) { buf->o -= ret; done += ret;