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 c37bcdc..c630f08 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 06559e6..82c741a 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -6704,6 +6704,7 @@
 				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 2aa11b8..f5d054e 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -44,6 +44,19 @@
 #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 @@
 		/* 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 @@
 	 */
 	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 @@
 			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;