MEDIUM: ssl: allow to register callbacks for SSL/TLS protocol messages
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.
diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h
index 5e3f603..d029394 100644
--- a/include/proto/ssl_sock.h
+++ b/include/proto/ssl_sock.h
@@ -103,6 +103,12 @@
#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 */
diff --git a/include/types/ssl_sock.h b/include/types/ssl_sock.h
index dbfa3d7..d71924f 100644
--- a/include/types/ssl_sock.h
+++ b/include/types/ssl_sock.h
@@ -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 @@
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 */
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 16c7227..4a4ca9b 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -629,6 +629,46 @@
#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 @@
/* 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 @@
#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 @@
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 */