BUG/MINOR: ssl: fix cipherlist captures with sustainable SSL calls

Use SSL_set_ex_data/SSL_get_ex_data standard API call to store capture.
We need to avoid internal structures/undocumented calls usage to try to
control the beast and limit painful compatibilities.
This commit is contained in:
Emmanuel Hocdet 2017-03-07 18:34:58 +01:00 committed by Willy Tarreau
parent f6b37c67be
commit aaee75088a
2 changed files with 19 additions and 56 deletions

View File

@ -13880,14 +13880,12 @@ ssl_fc_cipher : string
ssl_fc_cipherlist_bin : binary ssl_fc_cipherlist_bin : binary
Returns the binary form of the client hello cipher list. The maximum returned Returns the binary form of the client hello cipher list. The maximum returned
value length is according with the value of value length is according with the value of
"tune.ssl.capture-cipherlist-size". Note that this sample-fetch is available "tune.ssl.capture-cipherlist-size".
only with OpenSSL > 0.9.7
ssl_fc_cipherlist_hex : string ssl_fc_cipherlist_hex : string
Returns the binary form of the client hello cipher list encoded as Returns the binary form of the client hello cipher list encoded as
hexadecimal. The maximum returned value length is according with the value of hexadecimal. The maximum returned value length is according with the value of
"tune.ssl.capture-cipherlist-size". Note that this sample-fetch is available "tune.ssl.capture-cipherlist-size".
only with OpenSSL > 0.9.7
ssl_fc_cipherlist_str : string ssl_fc_cipherlist_str : string
Returns the decoded text form of the client hello cipher list. The maximum Returns the decoded text form of the client hello cipher list. The maximum
@ -13900,8 +13898,7 @@ ssl_fc_cipherlist_str : string
ssl_fc_cipherlist_xxh : integer ssl_fc_cipherlist_xxh : integer
Returns a xxh64 of the cipher list. This hash can be return only is the value Returns a xxh64 of the cipher list. This hash can be return only is the value
"tune.ssl.capture-cipherlist-size" is set greater than 0, however the hash "tune.ssl.capture-cipherlist-size" is set greater than 0, however the hash
take in account all the data of the cipher list. Note that this sample-fetch is take in account all the data of the cipher list.
avalaible only with OpenSSL > 0.9.7
ssl_fc_has_crt : boolean ssl_fc_has_crt : boolean
Returns true if a client certificate is present in an incoming connection over Returns true if a client certificate is present in an incoming connection over

View File

@ -165,10 +165,7 @@ static struct {
.capture_cipherlist = 0, .capture_cipherlist = 0,
}; };
/* This memory pool is used for capturing clienthello parameters. /* This memory pool is used for capturing clienthello parameters. */
* The message callback is only available after openssl 0.9.7,
* so the memory pool is useless before this version.
*/
struct ssl_capture { struct ssl_capture {
struct connection *conn; struct connection *conn;
unsigned long long int xxh64; unsigned long long int xxh64;
@ -176,17 +173,7 @@ struct ssl_capture {
char ciphersuite[0]; char ciphersuite[0];
}; };
struct pool_head *pool2_ssl_capture = NULL; struct pool_head *pool2_ssl_capture = NULL;
static int ssl_capture_ptr_index = -1;
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
/* This fu**ing funtion is announced in some OpenSSL manual pages,
* but doesn't exists in the OpenSSL library !
* eg. https://www.openssl.org/docs/man1.0.1/ssl/SSL_get_msg_callback_arg.html
*/
static void *SSL_get_msg_callback_arg(SSL *ssl)
{
return ssl->msg_callback_arg;
}
#endif
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0) #if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference); struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference);
@ -1258,11 +1245,11 @@ void ssl_sock_parse_clienthello(int write_p, int version, int content_type,
/* Callback is called for ssl protocol analyse */ /* 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) void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
{ {
/* If the SSL connection doesn't had sufficient memory while if (global_ssl.capture_cipherlist) {
* the structure was initialized, arg is NULL. struct ssl_capture *capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
*/ if (capture)
if (global_ssl.capture_cipherlist && arg) ssl_sock_parse_clienthello(write_p, version, content_type, buf, len, capture);
ssl_sock_parse_clienthello(write_p, version, content_type, buf, len, arg); }
#ifdef TLS1_RT_HEARTBEAT #ifdef TLS1_RT_HEARTBEAT
/* test heartbeat received (write_p is set to 0 /* test heartbeat received (write_p is set to 0
@ -3971,8 +3958,6 @@ ssl_sock_free_ca(struct bind_conf *bind_conf)
*/ */
static int ssl_sock_init(struct connection *conn) static int ssl_sock_init(struct connection *conn)
{ {
struct ssl_capture *capture;
/* already initialized */ /* already initialized */
if (conn->xprt_ctx) if (conn->xprt_ctx)
return 0; return 0;
@ -4080,19 +4065,15 @@ static int ssl_sock_init(struct connection *conn)
return -1; return -1;
} }
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
/* Set capture struct as opaque argument for the msg callback. */ /* Set capture struct as opaque argument for the msg callback. */
if (global_ssl.capture_cipherlist > 0) { if (global_ssl.capture_cipherlist > 0) {
capture = pool_alloc_dirty(pool2_ssl_capture); struct ssl_capture *capture = pool_alloc_dirty(pool2_ssl_capture);
if (capture) { if (capture) {
capture->conn = conn; capture->conn = conn;
capture->ciphersuite_len = 0; capture->ciphersuite_len = 0;
SSL_set_msg_callback_arg(conn->xprt_ctx, capture); SSL_set_ex_data(conn->xprt_ctx, ssl_capture_ptr_index, capture);
} }
} else {
SSL_set_msg_callback_arg(conn->xprt_ctx, NULL);
} }
#endif
SSL_set_accept_state(conn->xprt_ctx); SSL_set_accept_state(conn->xprt_ctx);
@ -4541,13 +4522,8 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
} }
static void ssl_sock_close(struct connection *conn) { static void ssl_sock_close(struct connection *conn) {
struct ssl_capture *capture;
if (conn->xprt_ctx) { if (conn->xprt_ctx) {
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
capture = SSL_get_msg_callback_arg(conn->xprt_ctx);
pool_free2(pool2_ssl_capture, capture);
#endif
SSL_free(conn->xprt_ctx); SSL_free(conn->xprt_ctx);
conn->xprt_ctx = NULL; conn->xprt_ctx = NULL;
sslconns--; sslconns--;
@ -5661,7 +5637,6 @@ smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw,
static int static int
smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private) smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
{ {
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
struct connection *conn; struct connection *conn;
struct ssl_capture *capture; struct ssl_capture *capture;
@ -5669,7 +5644,7 @@ smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock) if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0; return 0;
capture = SSL_get_msg_callback_arg(conn->xprt_ctx); capture = SSL_get_ex_data(conn->xprt_ctx, ssl_capture_ptr_index);
if (!capture) if (!capture)
return 0; return 0;
@ -5678,10 +5653,6 @@ smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *
smp->data.u.str.str = capture->ciphersuite; smp->data.u.str.str = capture->ciphersuite;
smp->data.u.str.len = capture->ciphersuite_len; smp->data.u.str.len = capture->ciphersuite_len;
return 1; return 1;
#else
return 0;
#endif
} }
static int static int
@ -5702,7 +5673,6 @@ smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *
static int static int
smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private) smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
{ {
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
struct connection *conn; struct connection *conn;
struct ssl_capture *capture; struct ssl_capture *capture;
@ -5710,17 +5680,13 @@ smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock) if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0; return 0;
capture = SSL_get_msg_callback_arg(conn->xprt_ctx); capture = SSL_get_ex_data(conn->xprt_ctx, ssl_capture_ptr_index);
if (!capture) if (!capture)
return 0; return 0;
smp->data.type = SMP_T_SINT; smp->data.type = SMP_T_SINT;
smp->data.u.sint = capture->xxh64; smp->data.u.sint = capture->xxh64;
return 1; return 1;
#else
return 0;
#endif
} }
static int static int
@ -6910,7 +6876,6 @@ static int ssl_parse_global_capture_cipherlist(char **args, int section_type, st
struct proxy *defpx, const char *file, int line, struct proxy *defpx, const char *file, int line,
char **err) char **err)
{ {
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
int ret; int ret;
ret = ssl_parse_global_int(args, section_type, curpx, defpx, file, line, err); ret = ssl_parse_global_int(args, section_type, curpx, defpx, file, line, err);
@ -6928,10 +6893,6 @@ static int ssl_parse_global_capture_cipherlist(char **args, int section_type, st
return -1; return -1;
} }
return 0; return 0;
#else
memprintf(err, "'%s' requires OpenSSL 0.9.7 or above.", args[0]);
return -1;
#endif
} }
/* parse "ssl.force-private-cache". /* parse "ssl.force-private-cache".
@ -7482,6 +7443,10 @@ static void ssl_sock_sctl_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
} }
#endif #endif
static void ssl_sock_capture_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
{
pool_free2(pool2_ssl_capture, ptr);
}
__attribute__((constructor)) __attribute__((constructor))
static void __ssl_sock_init(void) static void __ssl_sock_init(void)
@ -7502,6 +7467,7 @@ static void __ssl_sock_init(void)
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER) #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
sctl_ex_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_sctl_free_func); sctl_ex_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_sctl_free_func);
#endif #endif
ssl_capture_ptr_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_capture_free_func);
sample_register_fetches(&sample_fetch_keywords); sample_register_fetches(&sample_fetch_keywords);
acl_register_keywords(&acl_kws); acl_register_keywords(&acl_kws);
bind_register_keywords(&bind_kws); bind_register_keywords(&bind_kws);