MEDIUM: ssl: split ssl_sock_msgcbk() and use a new callback mechanism
Make use of ssl_sock_register_msg_callback(). Function ssl_sock_msgcbk()
is now split into two dedicated functions for heartbeat and clienthello.
They are both registered by using a new callback mechanism for SSL/TLS
protocol messages.
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 4a4ca9b..232b10b 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -629,6 +629,17 @@
#define sh_ssl_sess_tree_lookup(k) (struct sh_ssl_sess_hdr *)ebmb_lookup(sh_ssl_sess_tree, \
(k), SSL_MAX_SSL_SESSION_ID_LENGTH);
+/* Dedicated callback functions for heartbeat and clienthello.
+ */
+#ifdef TLS1_RT_HEARTBEAT
+static void ssl_sock_parse_heartbeat(struct connection *conn, int write_p, int version,
+ int content_type, const void *buf, size_t len,
+ SSL *ssl);
+#endif
+static void ssl_sock_parse_clienthello(struct connection *conn, int write_p, int version,
+ int content_type, const void *buf, size_t len,
+ SSL *ssl);
+
/* List head of all registered SSL/TLS protocol message callbacks. */
struct list ssl_sock_msg_callbacks = LIST_HEAD_INIT(ssl_sock_msg_callbacks);
@@ -656,6 +667,21 @@
return 1;
}
+/* Used to register dedicated SSL/TLS protocol message callbacks.
+ */
+static int ssl_sock_register_msg_callbacks(void)
+{
+#ifdef TLS1_RT_HEARTBEAT
+ if (!ssl_sock_register_msg_callback(ssl_sock_parse_heartbeat))
+ return ERR_ABORT;
+#endif
+ if (global_ssl.capture_cipherlist > 0) {
+ if (!ssl_sock_register_msg_callback(ssl_sock_parse_clienthello))
+ return ERR_ABORT;
+ }
+ return 0;
+}
+
/* Used to free all SSL/TLS protocol message callbacks that were
* registered by using ssl_sock_register_msg_callback().
*/
@@ -1815,9 +1841,52 @@
return 0;
}
-static inline
-void ssl_sock_parse_clienthello(int write_p, int version, int content_type,
- const void *buf, size_t len, SSL *ssl)
+#ifdef TLS1_RT_HEARTBEAT
+static void ssl_sock_parse_heartbeat(struct connection *conn, int write_p, int version,
+ int content_type, const void *buf, size_t len,
+ SSL *ssl)
+{
+ /* test heartbeat received (write_p is set to 0
+ for a received record) */
+ if ((content_type == TLS1_RT_HEARTBEAT) && (write_p == 0)) {
+ struct ssl_sock_ctx *ctx = conn->xprt_ctx;
+ const unsigned char *p = buf;
+ unsigned int payload;
+
+ ctx->xprt_st |= SSL_SOCK_RECV_HEARTBEAT;
+
+ /* Check if this is a CVE-2014-0160 exploitation attempt. */
+ if (*p != TLS1_HB_REQUEST)
+ return;
+
+ if (len < 1 + 2 + 16) /* 1 type + 2 size + 0 payload + 16 padding */
+ goto kill_it;
+
+ payload = (p[1] * 256) + p[2];
+ if (3 + payload + 16 <= len)
+ return; /* OK no problem */
+ kill_it:
+ /* We have a clear heartbleed attack (CVE-2014-0160), the
+ * advertised payload is larger than the advertised packet
+ * length, so we have garbage in the buffer between the
+ * payload and the end of the buffer (p+len). We can't know
+ * if the SSL stack is patched, and we don't know if we can
+ * safely wipe out the area between p+3+len and payload.
+ * So instead, we prevent the response from being sent by
+ * setting the max_send_fragment to 0 and we report an SSL
+ * error, which will kill this connection. It will be reported
+ * above as SSL_ERROR_SSL while an other handshake failure with
+ * a heartbeat message will be reported as SSL_ERROR_SYSCALL.
+ */
+ ssl->max_send_fragment = 0;
+ SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_SSL_HANDSHAKE_FAILURE);
+ }
+}
+#endif
+
+static void ssl_sock_parse_clienthello(struct connection *conn, int write_p, int version,
+ int content_type, const void *buf, size_t len,
+ SSL *ssl)
{
struct ssl_capture *capture;
unsigned char *msg;
@@ -1930,47 +1999,6 @@
struct connection *conn = SSL_get_ex_data(ssl, ssl_app_data_index);
struct ssl_sock_msg_callback *cbk;
-#ifdef TLS1_RT_HEARTBEAT
- /* test heartbeat received (write_p is set to 0
- for a received record) */
- if ((content_type == TLS1_RT_HEARTBEAT) && (write_p == 0)) {
- struct ssl_sock_ctx *ctx = conn->xprt_ctx;
- const unsigned char *p = buf;
- unsigned int payload;
-
- ctx->xprt_st |= SSL_SOCK_RECV_HEARTBEAT;
-
- /* Check if this is a CVE-2014-0160 exploitation attempt. */
- if (*p != TLS1_HB_REQUEST)
- return;
-
- if (len < 1 + 2 + 16) /* 1 type + 2 size + 0 payload + 16 padding */
- goto kill_it;
-
- payload = (p[1] * 256) + p[2];
- if (3 + payload + 16 <= len)
- return; /* OK no problem */
- kill_it:
- /* We have a clear heartbleed attack (CVE-2014-0160), the
- * advertised payload is larger than the advertised packet
- * length, so we have garbage in the buffer between the
- * payload and the end of the buffer (p+len). We can't know
- * if the SSL stack is patched, and we don't know if we can
- * safely wipe out the area between p+3+len and payload.
- * So instead, we prevent the response from being sent by
- * setting the max_send_fragment to 0 and we report an SSL
- * error, which will kill this connection. It will be reported
- * above as SSL_ERROR_SSL while an other handshake failure with
- * a heartbeat message will be reported as SSL_ERROR_SYSCALL.
- */
- ssl->max_send_fragment = 0;
- SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_SSL_HANDSHAKE_FAILURE);
- return;
- }
-#endif
- if (global_ssl.capture_cipherlist > 0)
- ssl_sock_parse_clienthello(write_p, version, content_type, buf, len, ssl);
-
/* Try to call all callback functions that were registered by using
* ssl_sock_register_msg_callback().
*/
@@ -13150,6 +13178,11 @@
HA_SPIN_INIT(&ckch_lock);
+ /* Try to register dedicated SSL/TLS protocol message callbacks for
+ * heartbleed attack (CVE-2014-0160) and clienthello.
+ */
+ hap_register_post_check(ssl_sock_register_msg_callbacks);
+
/* Try to free all callbacks that were registered by using
* ssl_sock_register_msg_callback().
*/