Skip to content

Commit

Permalink
support SslStream SSLKEYLOGFILE in debug builds (#90429)
Browse files Browse the repository at this point in the history
* support SslStream SSLKEYLOGFILE in debug builds

* compat

* feedback
  • Loading branch information
wfurt authored Aug 14, 2023
1 parent 2470610 commit 58e0349
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ internal static partial class Interop
{
internal static partial class OpenSsl
{
#if DEBUG
private static readonly string? s_keyLogFile = Environment.GetEnvironmentVariable("SSLKEYLOGFILE");
private static readonly FileStream? s_fileStream = s_keyLogFile != null ? File.Open(s_keyLogFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite) : null;
#endif
private const string DisableTlsResumeCtxSwitch = "System.Net.Security.DisableTlsResume";
private const string DisableTlsResumeEnvironmentVariable = "DOTNET_SYSTEM_NET_SECURITY_DISABLETLSRESUME";
private const string TlsCacheSizeCtxName = "System.Net.Security.TlsCacheSize";
Expand Down Expand Up @@ -236,6 +240,12 @@ internal static unsafe SafeSslContextHandle AllocateSslContext(SslAuthentication
Ssl.SslCtxSetDefaultOcspCallback(sslCtx);
}
}
#if DEBUG
if (s_fileStream != null)
{
Ssl.SslCtxSetKeylogCallback(sslCtx, &KeyLogCallback);
}
#endif
}
catch
{
Expand Down Expand Up @@ -783,6 +793,23 @@ private static unsafe void RemoveSessionCallback(IntPtr ctx, IntPtr session)
ctxHandle.RemoveSession(name);
}

#if DEBUG
[UnmanagedCallersOnly]
private static unsafe void KeyLogCallback(IntPtr ssl, char* line)
{
Debug.Assert(s_fileStream != null);
ReadOnlySpan<byte> data = MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)line);
if (data.Length > 0)
{
lock (s_fileStream)
{
s_fileStream.Write(data);
s_fileStream.WriteByte((byte)'\n');
}
}
}
#endif

private static int BioRead(SafeBioHandle bio, byte[] buffer, int count)
{
Debug.Assert(buffer != null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ internal static partial class Ssl
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetAlpnSelectCb")]
internal static unsafe partial void SslCtxSetAlpnSelectCb(SafeSslContextHandle ctx, delegate* unmanaged<IntPtr, byte**, byte*, byte*, uint, IntPtr, int> callback, IntPtr arg);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetKeylogCallback")]
internal static unsafe partial void SslCtxSetKeylogCallback(SafeSslContextHandle ctx, delegate* unmanaged<IntPtr, char*, void> callback);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetCaching")]
internal static unsafe partial int SslCtxSetCaching(SafeSslContextHandle ctx, int mode, int cacheSize, int contextIdLength, Span<byte> contextId, delegate* unmanaged<IntPtr, IntPtr, int> neewSessionCallback, delegate* unmanaged<IntPtr, IntPtr, void> removeSessionCallback);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace System.Net.Quic;
internal sealed class MsQuicTlsSecret : IDisposable
{
private static readonly string? s_keyLogFile = Environment.GetEnvironmentVariable("SSLKEYLOGFILE");
private static readonly FileStream? s_fileStream = s_keyLogFile != null ? File.Open(s_keyLogFile, FileMode.Append, FileAccess.Write) : null;
private static readonly FileStream? s_fileStream = s_keyLogFile != null ? File.Open(s_keyLogFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite) : null;

private unsafe QUIC_TLS_SECRETS* _tlsSecrets;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,12 @@ void local_SSL_set_security_level(SSL* ssl, int32_t level)
(void)level;
}

void local_SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb)
{
(void)ctx;
(void)cb;
}

int local_BIO_up_ref(BIO *bio)
{
if (!bio)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,5 @@ const X509_ALGOR* local_X509_get0_tbs_sigalg(const X509* x509);
X509_PUBKEY* local_X509_get_X509_PUBKEY(const X509* x509);
int32_t local_X509_get_version(const X509* x509);
int32_t local_X509_up_ref(X509* x509);
typedef void (*SSL_CTX_keylog_cb_func)(const SSL *ssl, const char *line);
void local_SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb);
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_SslCtxSetCiphers)
DllImportEntry(CryptoNative_SslCtxSetDefaultOcspCallback)
DllImportEntry(CryptoNative_SslCtxSetEncryptionPolicy)
DllImportEntry(CryptoNative_SslCtxSetKeylogCallback)
DllImportEntry(CryptoNative_SetCiphers)
DllImportEntry(CryptoNative_SslCreate)
DllImportEntry(CryptoNative_SslCtxCheckPrivateKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t len);
LIGHTUP_FUNCTION(SSL_CTX_set_ciphersuites) \
REQUIRED_FUNCTION(SSL_CTX_set_client_cert_cb) \
REQUIRED_FUNCTION(SSL_CTX_set_ex_data) \
FALLBACK_FUNCTION(SSL_CTX_set_keylog_callback) \
REQUIRED_FUNCTION(SSL_CTX_set_quiet_shutdown) \
FALLBACK_FUNCTION(SSL_CTX_set_options) \
FALLBACK_FUNCTION(SSL_CTX_set_security_level) \
Expand Down Expand Up @@ -1005,6 +1006,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define SSL_CTX_set_client_cert_cb SSL_CTX_set_client_cert_cb_ptr
#define SSL_CTX_set_ex_data SSL_CTX_set_ex_data_ptr
#define SSL_CTX_set_options SSL_CTX_set_options_ptr
#define SSL_CTX_set_keylog_callback SSL_CTX_set_keylog_callback_ptr
#define SSL_CTX_set_quiet_shutdown SSL_CTX_set_quiet_shutdown_ptr
#define SSL_CTX_set_security_level SSL_CTX_set_security_level_ptr
#define SSL_CTX_set_session_id_context SSL_CTX_set_session_id_context_ptr
Expand Down Expand Up @@ -1268,6 +1270,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define X509_get_X509_PUBKEY local_X509_get_X509_PUBKEY
#define X509_get_version local_X509_get_version
#define X509_up_ref local_X509_up_ref
#define SSL_CTX_set_keylog_callback local_SSL_CTX_set_keylog_callback

#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ int X509_set1_notBefore(X509* x509, const ASN1_TIME*);
int32_t X509_up_ref(X509* x509);
const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s);
int SSL_SESSION_set1_hostname(SSL_SESSION *s, const char *hostname);
void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb);

#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM
int32_t X509_check_host(X509* x509, const char* name, size_t namelen, unsigned int flags, char** peername);
Expand Down
7 changes: 7 additions & 0 deletions src/native/libs/System.Security.Cryptography.Native/pal_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,13 @@ void CryptoNative_SslSetClientCertCallback(SSL* ssl, int set)
SSL_set_cert_cb(ssl, set ? client_certificate_cb : NULL, NULL);
}

void CryptoNative_SslCtxSetKeylogCallback(SSL_CTX* ctx, SslCtxSetKeylogCallback cb)
{
// void shim functions don't lead to exceptions, so skip the unconditional error clearing.

SSL_CTX_set_keylog_callback(ctx, cb);
}

void CryptoNative_SslSetPostHandshakeAuth(SSL* ssl, int32_t val)
{
#if defined NEED_OPENSSL_1_1 || defined NEED_OPENSSL_3_0
Expand Down
8 changes: 8 additions & 0 deletions src/native/libs/System.Security.Cryptography.Native/pal_ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ typedef int32_t (*SslCtxNewSessionCallback)(SSL* ssl, SSL_SESSION* session);
// the function pointer used for new session
typedef void (*SslCtxRemoveSessionCallback)(SSL_CTX* ctx, SSL_SESSION* session);

// the function pointer for keylog
typedef void (*SslCtxSetKeylogCallback)(const SSL* ssl, const char *line);

/*
Ensures that libssl is correctly initialized and ready to use.
*/
Expand Down Expand Up @@ -164,6 +167,11 @@ Sets session caching. 0 is disabled.
*/
PALEXPORT int CryptoNative_SslCtxSetCaching(SSL_CTX* ctx, int mode, int cacheSize, int contextIdLength, uint8_t* contextId, SslCtxNewSessionCallback newSessionCb, SslCtxRemoveSessionCallback removeSessionCb);

/*
Sets callback to log TLS session keys
*/
PALEXPORT void CryptoNative_SslCtxSetKeylogCallback(SSL_CTX* ctx, SslCtxSetKeylogCallback callback);

/*
Returns name associated with given ssl session.
OpenSSL holds reference to it and it must not be freed.
Expand Down

0 comments on commit 58e0349

Please sign in to comment.