]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: allow to register callbacks for SSL/TLS protocol messages
authorDragan Dosen <ddosen@haproxy.com>
Fri, 8 May 2020 16:30:00 +0000 (18:30 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Thu, 14 May 2020 11:13:14 +0000 (13:13 +0200)
This patch adds the ability to register callbacks for SSL/TLS protocol
messages by using the function ssl_sock_register_msg_callback().

All registered callback functions will be called when observing received
or sent SSL/TLS protocol messages.

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

index 5e3f6036a28ac13d25581ebb89221dec1d2cfb6c..d0293948620c4d36f4ec1f53f5e93722df2d0aa0 100644 (file)
@@ -103,6 +103,12 @@ void ssl_async_fd_free(int fd);
 
 #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);
+
+/* Registers the function <func> in order to be called on SSL/TLS protocol
+ * message processing.
+ */
+int ssl_sock_register_msg_callback(ssl_sock_msg_callback_func func);
+
 #endif /* USE_OPENSSL */
 #endif /* _PROTO_SSL_SOCK_H */
 
index dbfa3d72616b61d70000cb390af0723913aacd9f..d71924f0721eedde458298bee2c5a018e70068a2 100644 (file)
@@ -31,6 +31,8 @@
 #include <common/mini-clist.h>
 #include <common/openssl-compat.h>
 
+struct connection;
+
 struct pkey_info {
        uint8_t sig;          /* TLSEXT_signature_[rsa,ecdsa,...] */
        uint16_t bits;        /* key size in bits */
@@ -202,6 +204,18 @@ struct issuer_chain {
        char *path;
 };
 
+typedef void (*ssl_sock_msg_callback_func)(struct connection *conn,
+       int write_p, int version, int content_type,
+       const void *buf, size_t len, SSL *ssl);
+
+/* This structure contains a function pointer <func> that is called
+ * when observing received or sent SSL/TLS protocol messages, such as
+ * handshake messages or other events that can occur during processing.
+ */
+struct ssl_sock_msg_callback {
+       ssl_sock_msg_callback_func func;
+       struct list list;    /* list of registered callbacks */
+};
 
 #endif /* USE_OPENSSL */
 #endif /* _TYPES_SSL_SOCK_H */
index 16c7227a18f2bdf755ef1109236f46632bba2bde..4a4ca9b3a54c8d744aaf060ae2f300e9cb93d336 100644 (file)
@@ -629,6 +629,46 @@ static struct eb_root *sh_ssl_sess_tree; /* ssl shared session tree */
 #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);
 
+/* List head of all registered SSL/TLS protocol message callbacks. */
+struct list ssl_sock_msg_callbacks = LIST_HEAD_INIT(ssl_sock_msg_callbacks);
+
+/* Registers the function <func> in order to be called on SSL/TLS protocol
+ * message processing. It will return 0 if the function <func> is not set
+ * or if it fails to allocate memory.
+ */
+int ssl_sock_register_msg_callback(ssl_sock_msg_callback_func func)
+{
+       struct ssl_sock_msg_callback *cbk;
+
+       if (!func)
+               return 0;
+
+       cbk = calloc(1, sizeof(*cbk));
+       if (!cbk) {
+               ha_alert("out of memory in ssl_sock_register_msg_callback().\n");
+               return 0;
+       }
+
+       cbk->func = func;
+
+       LIST_ADDQ(&ssl_sock_msg_callbacks, &cbk->list);
+
+       return 1;
+}
+
+/* Used to free all SSL/TLS protocol message callbacks that were
+ * registered by using ssl_sock_register_msg_callback().
+ */
+static void ssl_sock_unregister_msg_callbacks(void)
+{
+       struct ssl_sock_msg_callback *cbk, *cbkback;
+
+       list_for_each_entry_safe(cbk, cbkback, &ssl_sock_msg_callbacks, list) {
+               LIST_DEL(&cbk->list);
+               free(cbk);
+       }
+}
+
 /*
  * This function gives the detail of the SSL error. It is used only
  * if the debug mode and the verbose mode are activated. It dump all
@@ -1887,11 +1927,13 @@ void ssl_sock_parse_clienthello(int write_p, int version, int content_type,
 /* Callback is called for ssl protocol analyse */
 void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
 {
+       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 connection *conn = SSL_get_ex_data(ssl, ssl_app_data_index);
                struct ssl_sock_ctx *ctx = conn->xprt_ctx;
                const unsigned char *p = buf;
                unsigned int payload;
@@ -1928,6 +1970,13 @@ void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf
 #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().
+        */
+       list_for_each_entry(cbk, &ssl_sock_msg_callbacks, list) {
+               cbk->func(conn, write_p, version, content_type, buf, len, ssl);
+       }
 }
 
 #if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
@@ -13100,6 +13149,11 @@ static void __ssl_sock_init(void)
        BIO_meth_set_gets(ha_meth, ha_ssl_gets);
 
        HA_SPIN_INIT(&ckch_lock);
+
+       /* Try to free all callbacks that were registered by using
+        * ssl_sock_register_msg_callback().
+        */
+       hap_register_post_deinit(ssl_sock_unregister_msg_callbacks);
 }
 
 /* Compute and register the version string */