mirror of
https://github.com/openssl/openssl.git
synced 2024-11-21 01:15:20 +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",
|
||||
"static-engine",
|
||||
"stdio",
|
||||
"sslkeylog",
|
||||
"tests",
|
||||
"tfo",
|
||||
"thread-pool",
|
||||
@ -598,6 +599,7 @@ our %disabled = ( # "what" => "comment"
|
||||
"sctp" => "default",
|
||||
"ssl3" => "default",
|
||||
"ssl3-method" => "default",
|
||||
"sslkeylog" => "default",
|
||||
"tfo" => "default",
|
||||
"trace" => "default",
|
||||
"ubsan" => "default",
|
||||
|
116
ssl/ssl_lib.c
116
ssl/ssl_lib.c
@ -27,6 +27,7 @@
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/nelem.h"
|
||||
#include "internal/refcount.h"
|
||||
#include "internal/thread_once.h"
|
||||
#include "internal/ktls.h"
|
||||
#include "internal/to_hex.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);
|
||||
}
|
||||
|
||||
#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
|
||||
* 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)
|
||||
{
|
||||
SSL_CTX *ret = NULL;
|
||||
#ifndef OPENSSL_NO_SSLKEYLOG
|
||||
const char *keylogfile = ossl_safe_getenv("SSLKEYLOGFILE");
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_COMP_ALG
|
||||
int i;
|
||||
#endif
|
||||
@ -4120,6 +4173,43 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
|
||||
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;
|
||||
err:
|
||||
SSL_CTX_free(ret);
|
||||
@ -4157,6 +4247,20 @@ void SSL_CTX_free(SSL_CTX *a)
|
||||
return;
|
||||
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);
|
||||
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;
|
||||
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)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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 = '\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);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1099,6 +1099,16 @@ struct ssl_ctx_st {
|
||||
*/
|
||||
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
|
||||
* sent as early data.
|
||||
|
Loading…
Reference in New Issue
Block a user