mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 05:21:51 +08:00
Add sslkeylog config option and implementation
Add a config option for sslkeylog (disabled by default) When enabled, SSL_CTX_new[_ex] becomes sensitive to the SSLKEYLOGFILE environment variable. It records keylog callback messages to the file specified in the environment variable according to the format specified in https://www.ietf.org/archive/id/draft-thomson-tls-keylogfile-00.html Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Saša Nedvědický <sashan@openssl.org> Reviewed-by: Hugo Landau <hlandau@devever.net> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/25297)
This commit is contained in:
parent
256f580dcd
commit
4a69a6d171
@ -526,6 +526,7 @@ my @disablables = (
|
|||||||
"ssl-trace",
|
"ssl-trace",
|
||||||
"static-engine",
|
"static-engine",
|
||||||
"stdio",
|
"stdio",
|
||||||
|
"sslkeylog",
|
||||||
"tests",
|
"tests",
|
||||||
"tfo",
|
"tfo",
|
||||||
"thread-pool",
|
"thread-pool",
|
||||||
@ -598,6 +599,7 @@ our %disabled = ( # "what" => "comment"
|
|||||||
"sctp" => "default",
|
"sctp" => "default",
|
||||||
"ssl3" => "default",
|
"ssl3" => "default",
|
||||||
"ssl3-method" => "default",
|
"ssl3-method" => "default",
|
||||||
|
"sslkeylog" => "default",
|
||||||
"tfo" => "default",
|
"tfo" => "default",
|
||||||
"trace" => "default",
|
"trace" => "default",
|
||||||
"ubsan" => "default",
|
"ubsan" => "default",
|
||||||
|
116
ssl/ssl_lib.c
116
ssl/ssl_lib.c
@ -27,6 +27,7 @@
|
|||||||
#include "internal/cryptlib.h"
|
#include "internal/cryptlib.h"
|
||||||
#include "internal/nelem.h"
|
#include "internal/nelem.h"
|
||||||
#include "internal/refcount.h"
|
#include "internal/refcount.h"
|
||||||
|
#include "internal/thread_once.h"
|
||||||
#include "internal/ktls.h"
|
#include "internal/ktls.h"
|
||||||
#include "internal/to_hex.h"
|
#include "internal/to_hex.h"
|
||||||
#include "quic/quic_local.h"
|
#include "quic/quic_local.h"
|
||||||
@ -3849,6 +3850,55 @@ static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
|
|||||||
return memcmp(a->session_id, b->session_id, a->session_id_length);
|
return memcmp(a->session_id, b->session_id, a->session_id_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_SSLKEYLOG
|
||||||
|
/**
|
||||||
|
* @brief Static initialization for a one-time action to initialize the SSL key log.
|
||||||
|
*/
|
||||||
|
static CRYPTO_ONCE ssl_keylog_once = CRYPTO_ONCE_STATIC_INIT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pointer to a read-write lock used to protect access to the key log.
|
||||||
|
*/
|
||||||
|
static CRYPTO_RWLOCK *keylog_lock = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pointer to a BIO structure used for writing the key log information.
|
||||||
|
*/
|
||||||
|
static BIO *keylog_bio = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ref counter tracking the number of keylog_bio users.
|
||||||
|
*/
|
||||||
|
static unsigned int keylog_count = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the SSLKEYLOGFILE lock.
|
||||||
|
*
|
||||||
|
* @return 1 on success, 0 on failure.
|
||||||
|
*/
|
||||||
|
DEFINE_RUN_ONCE_STATIC(ssl_keylog_init)
|
||||||
|
{
|
||||||
|
keylog_lock = CRYPTO_THREAD_lock_new();
|
||||||
|
if (keylog_lock == NULL)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sslkeylogfile_cb(const SSL *ssl, const char *line)
|
||||||
|
{
|
||||||
|
if (keylog_lock == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!CRYPTO_THREAD_write_lock(keylog_lock))
|
||||||
|
return;
|
||||||
|
if (keylog_bio != NULL) {
|
||||||
|
BIO_printf(keylog_bio, "%s\n", line);
|
||||||
|
(void)BIO_flush(keylog_bio);
|
||||||
|
}
|
||||||
|
CRYPTO_THREAD_unlock(keylog_lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These wrapper functions should remain rather than redeclaring
|
* These wrapper functions should remain rather than redeclaring
|
||||||
* SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
|
* SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each
|
||||||
@ -3860,6 +3910,9 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
|
|||||||
const SSL_METHOD *meth)
|
const SSL_METHOD *meth)
|
||||||
{
|
{
|
||||||
SSL_CTX *ret = NULL;
|
SSL_CTX *ret = NULL;
|
||||||
|
#ifndef OPENSSL_NO_SSLKEYLOG
|
||||||
|
const char *keylogfile = ossl_safe_getenv("SSLKEYLOGFILE");
|
||||||
|
#endif
|
||||||
#ifndef OPENSSL_NO_COMP_ALG
|
#ifndef OPENSSL_NO_COMP_ALG
|
||||||
int i;
|
int i;
|
||||||
#endif
|
#endif
|
||||||
@ -4120,6 +4173,43 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_SSLKEYLOG
|
||||||
|
if (keylogfile != NULL && strlen(keylogfile) != 0) {
|
||||||
|
/* Make sure we have a global lock allocated */
|
||||||
|
if (!RUN_ONCE(&ssl_keylog_once, ssl_keylog_init)) {
|
||||||
|
/* log an error, but don't fail here */
|
||||||
|
ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab out global lock */
|
||||||
|
if (!CRYPTO_THREAD_write_lock(keylog_lock)) {
|
||||||
|
ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If the bio for the requested keylog file hasn't been
|
||||||
|
* created yet, go ahead and create it, and set it to append
|
||||||
|
* if its already there.
|
||||||
|
*/
|
||||||
|
if (keylog_bio == NULL) {
|
||||||
|
keylog_bio = BIO_new_file(keylogfile, "a");
|
||||||
|
if (keylog_bio == NULL)
|
||||||
|
ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
|
||||||
|
else
|
||||||
|
/* up our ref count for the newly created case */
|
||||||
|
keylog_count++;
|
||||||
|
} else {
|
||||||
|
/* up our refcount for the already-created case */
|
||||||
|
keylog_count++;
|
||||||
|
}
|
||||||
|
/* If we have a bio now, assign the callback handler */
|
||||||
|
if (keylog_bio != NULL)
|
||||||
|
ret->sslkeylog_callback = sslkeylogfile_cb;
|
||||||
|
/* unlock, and we're done */
|
||||||
|
CRYPTO_THREAD_unlock(keylog_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
err:
|
err:
|
||||||
SSL_CTX_free(ret);
|
SSL_CTX_free(ret);
|
||||||
@ -4157,6 +4247,20 @@ void SSL_CTX_free(SSL_CTX *a)
|
|||||||
return;
|
return;
|
||||||
REF_ASSERT_ISNT(i < 0);
|
REF_ASSERT_ISNT(i < 0);
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_SSLKEYLOG
|
||||||
|
if (keylog_lock != NULL && CRYPTO_THREAD_write_lock(keylog_lock)) {
|
||||||
|
if (a->sslkeylog_callback != NULL)
|
||||||
|
keylog_count--;
|
||||||
|
a->sslkeylog_callback = NULL;
|
||||||
|
/* If we're the last user, close the bio */
|
||||||
|
if (keylog_count == 0) {
|
||||||
|
BIO_free(keylog_bio);
|
||||||
|
keylog_bio = NULL;
|
||||||
|
}
|
||||||
|
CRYPTO_THREAD_unlock(keylog_lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
X509_VERIFY_PARAM_free(a->param);
|
X509_VERIFY_PARAM_free(a->param);
|
||||||
dane_ctx_final(&a->dane);
|
dane_ctx_final(&a->dane);
|
||||||
|
|
||||||
@ -6750,8 +6854,13 @@ static int nss_keylog_int(const char *prefix,
|
|||||||
size_t out_len = 0, i, prefix_len;
|
size_t out_len = 0, i, prefix_len;
|
||||||
SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(sc);
|
SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(sc);
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_SSLKEYLOG
|
||||||
|
if (sctx->keylog_callback == NULL && sctx->sslkeylog_callback == NULL)
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (sctx->keylog_callback == NULL)
|
if (sctx->keylog_callback == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our output buffer will contain the following strings, rendered with
|
* Our output buffer will contain the following strings, rendered with
|
||||||
@ -6778,7 +6887,12 @@ static int nss_keylog_int(const char *prefix,
|
|||||||
cursor += ossl_to_lowerhex(cursor, parameter_2[i]);
|
cursor += ossl_to_lowerhex(cursor, parameter_2[i]);
|
||||||
*cursor = '\0';
|
*cursor = '\0';
|
||||||
|
|
||||||
sctx->keylog_callback(SSL_CONNECTION_GET_SSL(sc), (const char *)out);
|
#ifndef OPENSSL_NO_SSLKEYLOG
|
||||||
|
if (sctx->sslkeylog_callback != NULL)
|
||||||
|
sctx->sslkeylog_callback(SSL_CONNECTION_GET_SSL(sc), (const char *)out);
|
||||||
|
#endif
|
||||||
|
if (sctx->keylog_callback != NULL)
|
||||||
|
sctx->keylog_callback(SSL_CONNECTION_GET_SSL(sc), (const char *)out);
|
||||||
OPENSSL_clear_free(out, out_len);
|
OPENSSL_clear_free(out, out_len);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1099,6 +1099,16 @@ struct ssl_ctx_st {
|
|||||||
*/
|
*/
|
||||||
SSL_CTX_keylog_cb_func keylog_callback;
|
SSL_CTX_keylog_cb_func keylog_callback;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private callback for internal key logging based on SSLKEYLOG env
|
||||||
|
* We don't want to create a chaining mechanism as we're never sure
|
||||||
|
* if the application wants to set an additional callback or override
|
||||||
|
* the one set via SSLKEYLOGFILE, so we just keep them separate
|
||||||
|
*/
|
||||||
|
# ifndef OPENSSL_NO_SSLKEYLOG
|
||||||
|
SSL_CTX_keylog_cb_func sslkeylog_callback;
|
||||||
|
# endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The maximum number of bytes advertised in session tickets that can be
|
* The maximum number of bytes advertised in session tickets that can be
|
||||||
* sent as early data.
|
* sent as early data.
|
||||||
|
Loading…
Reference in New Issue
Block a user