]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: protect against client-initiated renegociation
authorEmeric Brun <ebrun@exceliance.fr>
Mon, 3 Sep 2012 18:36:47 +0000 (20:36 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 3 Sep 2012 20:03:17 +0000 (22:03 +0200)
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.

include/proto/ssl_sock.h
src/cfgparse.c
src/ssl_sock.c

index c37bcdcc1b5c0b7b7c788e6deb943e0082c24d2b..c630f08d8bf20dffe29e7177e004d4025940b618 100644 (file)
@@ -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 */
 
index 06559e6b62596b49cc904a83d275e2d882e2bd08..82c741ae5bfc9977838b678839d1ebe517abaf68 100644 (file)
@@ -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",
index 2aa11b8bc705f4a5dcf1cc60fa2e82dbf1f581f4..f5d054e74b473675694d982d35bbf7cbfc947c3c 100644 (file)
 #include <types/global.h>
 
 
+
+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;