From 4faa8d064c24cfa5f5850d22a9f40fbfbe712df4 Mon Sep 17 00:00:00 2001 From: Anthony Rossi <41394064+anrossi@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:29:15 -0700 Subject: [PATCH] Log QUIC_TLS_SECRETS on all TestConnections and write to disk on cleanup (#4349) * Log QUIC_TLS_SECRETS on all TestConnections and have option to write to disk on cleanup. * Implement kernel mode routine to write sslkeylogfile * Add sslkeylogfile generation to handshake tests. --- scripts/run-gtest.ps1 | 1 + src/inc/msquichelper.h | 360 ++++++++++++++++++++++++++++- src/test/MsQuicTests.h | 6 + src/test/bin/quic_gtest.cpp | 12 + src/test/bin/winkernel/control.cpp | 9 + src/test/lib/HandshakeTest.cpp | 57 ++++- src/test/lib/TestConnection.cpp | 41 +++- src/test/lib/TestConnection.h | 9 + src/test/lib/precomp.h | 1 + 9 files changed, 491 insertions(+), 5 deletions(-) diff --git a/scripts/run-gtest.ps1 b/scripts/run-gtest.ps1 index 9fa2c9c4d7..fd7a0247fb 100644 --- a/scripts/run-gtest.ps1 +++ b/scripts/run-gtest.ps1 @@ -345,6 +345,7 @@ function Start-TestExecutable([String]$Arguments, [String]$OutputDir) { } else { $pinfo.FileName = $Path $pinfo.Arguments = $Arguments + $pinfo.WorkingDirectory = $OutputDir if (Test-Administrator) { # Enable WER dump collection. New-ItemProperty -Path $WerDumpRegPath -Name DumpType -PropertyType DWord -Value 2 -Force | Out-Null diff --git a/src/inc/msquichelper.h b/src/inc/msquichelper.h index a3837bec4a..4572ddbd3e 100644 --- a/src/inc/msquichelper.h +++ b/src/inc/msquichelper.h @@ -568,9 +568,352 @@ FreeServerConfiguration( MsQuicTable->ConfigurationClose(Configuration); } +#ifdef _KERNEL_MODE inline void -WriteSslKeyLogFile( +WriteSslKeyLogFileKernelMode( + _In_z_ const char* FileName, + _In_ QUIC_TLS_SECRETS& TlsSecrets + ) +{ + WCHAR ConvertedFileName[MAX_PATH + 1] = {0}; + char ClientRandomBuffer[(2 * sizeof(QUIC_TLS_SECRETS::ClientRandom)) + 1] = {0}; + char TempHexBuffer[(2 * QUIC_TLS_SECRETS_MAX_SECRET_LEN) + 1] = {0}; + char TempLogBuffer[sizeof(ClientRandomBuffer) + sizeof(TempHexBuffer) + 32 + 3 + 1] = {0}; + UNICODE_STRING FileNameString = {0}; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE Handle; + size_t RemainingLengthBytes = 0; + NTSTATUS Status; + ULONG StringLengthBytes = 0; + + size_t FileNameLength = strnlen_s(FileName, MAX_PATH + 1); + if (FileNameLength == MAX_PATH + 1) { + goto Error; + } + FileNameLength++; + + Status = + RtlUTF8ToUnicodeN( + ConvertedFileName, + sizeof(ConvertedFileName), + &StringLengthBytes, + FileName, + (ULONG) FileNameLength); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Convert string to unicode"); + goto Error; + } + + FileNameString.Buffer = ConvertedFileName; + FileNameString.Length = (USHORT)StringLengthBytes - sizeof(WCHAR); + FileNameString.MaximumLength = (USHORT)sizeof(ConvertedFileName); + + InitializeObjectAttributes( + &ObjectAttributes, + &FileNameString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = + ZwCreateFile( + &Handle, + FILE_APPEND_DATA | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OPEN_IF, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, + NULL, + 0); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Open sslkeylogfile for append"); + goto Error; + } + + if (IoStatusBlock.Information == FILE_CREATED) { + CHAR Header[] = "# TLS 1.3 secrets log file, generated by quicinterop\n"; + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Header, + sizeof(Header) - 1, + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write header to sslkeylogfile"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ClientRandom) { + EncodeHexBuffer( + TlsSecrets.ClientRandom, + (uint8_t)sizeof(TlsSecrets.ClientRandom), + ClientRandomBuffer); + } + + if (TlsSecrets.IsSet.ClientEarlyTrafficSecret) { + EncodeHexBuffer( + TlsSecrets.ClientEarlyTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "CLIENT_EARLY_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format CLIENT_EARLY_TRAFFIC_SECRET"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write CLIENT_EARLY_TRAFFIC_SECRET"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ClientHandshakeTrafficSecret) { + EncodeHexBuffer( + TlsSecrets.ClientHandshakeTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "CLIENT_HANDSHAKE_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format CLIENT_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write CLIENT_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ServerHandshakeTrafficSecret) { + EncodeHexBuffer( + TlsSecrets.ServerHandshakeTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "SERVER_HANDSHAKE_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format SERVER_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write SERVER_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ClientTrafficSecret0) { + EncodeHexBuffer( + TlsSecrets.ClientTrafficSecret0, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "CLIENT_TRAFFIC_SECRET_0 %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format CLIENT_TRAFFIC_SECRET_0"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write CLIENT_TRAFFIC_SECRET_0"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ServerTrafficSecret0) { + EncodeHexBuffer( + TlsSecrets.ServerTrafficSecret0, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "SERVER_TRAFFIC_SECRET_0 %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format SERVER_TRAFFIC_SECRET_0"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write SERVER_TRAFFIC_SECRET_0"); + goto WriteError; + } + } + +WriteError: + ZwClose(Handle); + +Error: + return; +} +#endif + +inline +void +WriteSslKeyLogFileUserMode( _In_z_ const char* FileName, _In_ QUIC_TLS_SECRETS& TlsSecrets ) @@ -662,4 +1005,19 @@ WriteSslKeyLogFile( fclose(File); } + +inline +void +WriteSslKeyLogFile( + _In_z_ const char* FileName, + _In_ QUIC_TLS_SECRETS& TlsSecrets + ) +{ +#ifdef _KERNEL_MODE + WriteSslKeyLogFileKernelMode(FileName, TlsSecrets); +#else + WriteSslKeyLogFileUserMode(FileName, TlsSecrets); +#endif +} + #endif // defined(__cplusplus) diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index 83943df6fa..5634c17952 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -21,6 +21,11 @@ extern QUIC_CREDENTIAL_CONFIG ServerSelfSignedCredConfig; extern QUIC_CREDENTIAL_CONFIG ServerSelfSignedCredConfigClientAuth; extern QUIC_CREDENTIAL_CONFIG ClientCertCredConfig; +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif +extern char CurrentWorkingDirectory[MAX_PATH + 1]; + #ifdef __cplusplus extern "C" { #endif @@ -706,6 +711,7 @@ static const GUID QUIC_TEST_DEVICE_INSTANCE = typedef struct { BOOLEAN UseDuoNic; + char CurrentDirectory[MAX_PATH]; } QUIC_TEST_CONFIGURATION_PARAMS; #define IOCTL_QUIC_TEST_CONFIGURATION \ diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index ffb97c9f50..93eb10341c 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -89,6 +89,12 @@ class QuicTestEnvironment : public ::testing::Environment { QUIC_TEST_CONFIGURATION_PARAMS Params { UseDuoNic, }; + +#ifdef _WIN32 + ASSERT_NE(GetCurrentDirectoryA(sizeof(Params.CurrentDirectory), Params.CurrentDirectory), 0); + strcat_s(Params.CurrentDirectory, "\\"); +#endif + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_TEST_CONFIGURATION, Params)); } else { @@ -120,6 +126,12 @@ class QuicTestEnvironment : public ::testing::Environment { memcpy(&ClientCertCredConfig, ClientCertParams, sizeof(QUIC_CREDENTIAL_CONFIG)); ClientCertCredConfig.Flags |= QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION; QuicTestInitialize(); + +#ifdef _WIN32 + ASSERT_NE(GetCurrentDirectoryA(sizeof(CurrentWorkingDirectory), CurrentWorkingDirectory), 0); +#else + ASSERT_NE(getcwd(CurrentWorkingDirectory, sizeof(CurrentWorkingDirectory)), nullptr); +#endif } } void TearDown() override { diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index b4f9c7c50d..68dccdb29b 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -679,6 +679,15 @@ QuicTestCtlEvtIoDeviceControl( case IOCTL_QUIC_TEST_CONFIGURATION: CXPLAT_FRE_ASSERT(Params != nullptr); UseDuoNic = Params->TestConfigurationParams.UseDuoNic; + RtlCopyMemory(CurrentWorkingDirectory, "\\DosDevices\\", sizeof("\\DosDevices\\")); + Status = + RtlStringCbCatExA( + CurrentWorkingDirectory, + sizeof(CurrentWorkingDirectory), + Params->TestConfigurationParams.CurrentDirectory, + nullptr, + nullptr, + STRSAFE_NULL_ON_FAILURE); break; case IOCTL_QUIC_SET_CERT_PARAMS: diff --git a/src/test/lib/HandshakeTest.cpp b/src/test/lib/HandshakeTest.cpp index aec150c9e3..71cddd74c5 100644 --- a/src/test/lib/HandshakeTest.cpp +++ b/src/test/lib/HandshakeTest.cpp @@ -14,6 +14,8 @@ #include "HandshakeTest.cpp.clog.h" #endif +char CurrentWorkingDirectory[MAX_PATH + 1]; + QUIC_TEST_DATAPATH_HOOKS DatapathHooks::FuncTable = { DatapathHooks::CreateCallback, DatapathHooks::GetLocalAddressCallback, @@ -251,15 +253,14 @@ QuicTestConnect( ServerAcceptCtx.ExpectedCustomTicketValidationResult = QUIC_STATUS_INTERNAL_ERROR; } } - ServerAcceptCtx.TlsSecrets = &ServerSecrets; Listener.Context = &ServerAcceptCtx; { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetHasRandomLoss(RandomLossPercentage != 0); - TEST_QUIC_SUCCEEDED(Client.SetTlsSecrets(&ClientSecrets)); if (ClientUsesOldVersion) { TEST_QUIC_SUCCEEDED( @@ -317,11 +318,15 @@ QuicTestConnect( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } TEST_TRUE(Server->GetIsConnected()); + ClientSecrets = Client.GetTlsSecrets(); + ServerSecrets = Server->GetTlsSecrets(); + TEST_EQUAL( ServerSecrets.IsSet.ClientRandom, ClientSecrets.IsSet.ClientRandom); @@ -861,6 +866,7 @@ QuicTestCustomServerCertificateValidation( TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedCustomValidationResult(AcceptCert); Client.SetAsyncCustomValidationResult(AsyncValidation); if (!AcceptCert) { @@ -886,6 +892,7 @@ QuicTestCustomServerCertificateValidation( TEST_EQUAL(AcceptCert, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -963,6 +970,7 @@ QuicTestCustomClientCertificateValidation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); if (!AcceptCert) { Client.SetExpectedTransportCloseStatus(QUIC_STATUS_BAD_CERTIFICATE); @@ -1000,6 +1008,7 @@ QuicTestCustomClientCertificateValidation( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1048,6 +1057,7 @@ QuicTestShutdownDuringHandshake( TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedCustomValidationResult(TRUE); Client.SetAsyncCustomValidationResult(TRUE); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_USER_CANCELED); @@ -1062,6 +1072,9 @@ QuicTestShutdownDuringHandshake( CxPlatSleep(1000); + TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); + // // By now, the handshake is waiting for custom certificate validation. // @@ -1256,6 +1269,7 @@ QuicTestVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1270,6 +1284,9 @@ QuicTestVersionNegotiation( TEST_TRUE(Client.GetIsConnected()); TEST_TRUE(Client.GetStatistics().VersionNegotiation); TEST_EQUAL(Client.GetQuicVersion(), LATEST_SUPPORTED_VERSION); + + TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); } } } @@ -1353,6 +1370,7 @@ QuicTestVersionNegotiationRetry( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1368,6 +1386,9 @@ QuicTestVersionNegotiationRetry( TEST_TRUE(Client.GetStatistics().VersionNegotiation); TEST_TRUE(Client.GetStatistics().StatelessRetry); TEST_EQUAL(Client.GetQuicVersion(), LATEST_SUPPORTED_VERSION); + + TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); } } } @@ -1444,6 +1465,7 @@ QuicTestCompatibleVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1458,6 +1480,7 @@ QuicTestCompatibleVersionNegotiation( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1550,6 +1573,7 @@ QuicTestCompatibleVersionNegotiationRetry( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1564,6 +1588,7 @@ QuicTestCompatibleVersionNegotiationRetry( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1640,6 +1665,7 @@ QuicTestCompatibleVersionNegotiationDefaultServer( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1654,6 +1680,7 @@ QuicTestCompatibleVersionNegotiationDefaultServer( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1737,6 +1764,7 @@ QuicTestCompatibleVersionNegotiationDefaultClient( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1751,6 +1779,7 @@ QuicTestCompatibleVersionNegotiationDefaultClient( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1827,6 +1856,7 @@ QuicTestIncompatibleVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1841,6 +1871,7 @@ QuicTestIncompatibleVersionNegotiation( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1930,6 +1961,7 @@ RunFailedVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(ExpectedClientError); TEST_QUIC_SUCCEEDED( @@ -1944,6 +1976,7 @@ RunFailedVersionNegotiation( if (QUIC_FAILED(ExpectedServerError)) { TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); } else { TEST_EQUAL(nullptr, Server); } @@ -2169,6 +2202,7 @@ QuicTestConnectBadAlpn( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_ALPN_NEG_FAILURE); TEST_QUIC_SUCCEEDED( @@ -2226,6 +2260,7 @@ QuicTestConnectBadSni( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); QuicAddr RemoteAddr(Family == 4 ? QUIC_ADDRESS_FAMILY_INET : QUIC_ADDRESS_FAMILY_INET6, true); if (UseDuoNic) { @@ -2744,6 +2779,7 @@ QuicTestConnectClientCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); if (!UseClientCertificate) { Client.SetExpectedTransportCloseStatus(QUIC_STATUS_REQUIRED_CERTIFICATE); } @@ -2761,6 +2797,7 @@ QuicTestConnectClientCertificate( } TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (UseClientCertificate) { if (!Server->WaitForConnectionComplete()) { return; @@ -2844,6 +2881,7 @@ QuicTestValidAlpnLengths( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -2859,6 +2897,7 @@ QuicTestValidAlpnLengths( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -2909,6 +2948,7 @@ QuicTestConnectExpiredServerCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_EXPIRED_CERTIFICATE); TEST_QUIC_SUCCEEDED( @@ -2925,6 +2965,7 @@ QuicTestConnectExpiredServerCertificate( TEST_EQUAL(false, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -2973,6 +3014,7 @@ QuicTestConnectValidServerCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -2988,6 +3030,7 @@ QuicTestConnectValidServerCertificate( TEST_EQUAL(true, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3036,6 +3079,7 @@ QuicTestConnectValidClientCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -3051,6 +3095,7 @@ QuicTestConnectValidClientCertificate( TEST_EQUAL(true, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3099,6 +3144,7 @@ QuicTestConnectExpiredClientCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -3118,6 +3164,7 @@ QuicTestConnectExpiredClientCertificate( TEST_EQUAL(true, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3480,6 +3527,7 @@ QuicTestResumptionAcrossVersions() { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); VersionSettings.SetAllVersionLists(SecondClientVersions, ARRAYSIZE(SecondClientVersions)); TEST_QUIC_SUCCEEDED(ClientConfiguration.SetVersionSettings(VersionSettings)); @@ -3506,6 +3554,7 @@ QuicTestResumptionAcrossVersions() TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3601,6 +3650,7 @@ QuicTestChangeAlpn( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -3616,6 +3666,7 @@ QuicTestChangeAlpn( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3791,6 +3842,7 @@ QuicTestCustomVNTP( &Disable)); } TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_INTERNAL_ERROR); TEST_QUIC_SUCCEEDED( @@ -3807,6 +3859,7 @@ QuicTestCustomVNTP( if (TestServer) { TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } diff --git a/src/test/lib/TestConnection.cpp b/src/test/lib/TestConnection.cpp index 058c01dbb7..60476d463e 100644 --- a/src/test/lib/TestConnection.cpp +++ b/src/test/lib/TestConnection.cpp @@ -30,7 +30,7 @@ TestConnection::TestConnection( NewStreamCallback(NewStreamCallbackHandler), ShutdownCompleteCallback(nullptr), DatagramsSent(0), DatagramsCanceled(0), DatagramsSuspectLost(0), DatagramsLost(0), DatagramsAcknowledged(0), NegotiatedAlpn(nullptr), - NegotiatedAlpnLength(0), Context(nullptr) + NegotiatedAlpnLength(0), SslKeyLogFileName(nullptr), Context(nullptr) { CxPlatEventInitialize(&EventConnectionComplete, TRUE, FALSE); CxPlatEventInitialize(&EventPeerClosed, TRUE, FALSE); @@ -42,6 +42,10 @@ TestConnection::TestConnection( } else { MsQuic->SetCallbackHandler(QuicConnection, (void*)QuicConnectionHandler, this); } + QUIC_STATUS Status = SetTlsSecrets(&TlsSecrets); + if (QUIC_FAILED(Status)) { + TEST_FAILURE("SetTlsSecrets failed, 0x%x", Status); + } } TestConnection::TestConnection( @@ -60,7 +64,7 @@ TestConnection::TestConnection( NewStreamCallback(NewStreamCallbackHandler), ShutdownCompleteCallback(nullptr), DatagramsSent(0), DatagramsCanceled(0), DatagramsSuspectLost(0), DatagramsLost(0), DatagramsAcknowledged(0), NegotiatedAlpn(nullptr), - NegotiatedAlpnLength(0), Context(nullptr) + NegotiatedAlpnLength(0), SslKeyLogFileName(nullptr), Context(nullptr) { CxPlatEventInitialize(&EventConnectionComplete, TRUE, FALSE); CxPlatEventInitialize(&EventPeerClosed, TRUE, FALSE); @@ -77,6 +81,10 @@ TestConnection::TestConnection( TEST_FAILURE("MsQuic->ConnectionOpen failed, 0x%x.", Status); QuicConnection = nullptr; } + Status = SetTlsSecrets(&TlsSecrets); + if (QUIC_FAILED(Status)) { + TEST_FAILURE("SetTlsSecrets failed, 0x%x", Status); + } } TestConnection::~TestConnection() @@ -92,6 +100,35 @@ TestConnection::~TestConnection() if (EventDeleted) { CxPlatEventSet(*EventDeleted); } + if (SslKeyLogFileName != nullptr) { +#ifdef _KERNEL_MODE + char SslKeyLogFileFullPathName[MAX_PATH + 1]; + NTSTATUS Status = + RtlStringCbCopyA( + SslKeyLogFileFullPathName, + sizeof(SslKeyLogFileFullPathName), + CurrentWorkingDirectory); + if (!NT_SUCCESS(Status)) { + TEST_FAILURE("RtlStringCbCopyA failed"); + return; + } + Status = + RtlStringCbCatExA( + SslKeyLogFileFullPathName, + sizeof(SslKeyLogFileFullPathName), + SslKeyLogFileName, + nullptr, + nullptr, + STRSAFE_NULL_ON_FAILURE); + if (!NT_SUCCESS(Status)) { + TEST_FAILURE("RtlStringCbCatExA failed"); + return; + } + WriteSslKeyLogFile(SslKeyLogFileFullPathName, TlsSecrets); +#else + WriteSslKeyLogFile(SslKeyLogFileName, TlsSecrets); +#endif + } } QUIC_STATUS diff --git a/src/test/lib/TestConnection.h b/src/test/lib/TestConnection.h index 1beeb9c3d3..8338aee758 100644 --- a/src/test/lib/TestConnection.h +++ b/src/test/lib/TestConnection.h @@ -17,6 +17,8 @@ enum NEW_STREAM_START_TYPE { NEW_STREAM_START_ASYNC // Start asynchronously }; +#define DEFAULT_SSLKEYLOGFILE_NAME "sslkeylogfile.txt" + // // Callback for processing peer created streams. // @@ -96,6 +98,9 @@ class TestConnection const uint8_t* NegotiatedAlpn; uint8_t NegotiatedAlpnLength; + QUIC_TLS_SECRETS TlsSecrets; + const char* SslKeyLogFileName; + QUIC_STATUS HandleConnectionEvent( _Inout_ QUIC_CONNECTION_EVENT* Event @@ -309,4 +314,8 @@ class TestConnection uint8_t GetNegotiatedAlpnLength() const; QUIC_STATUS SetTlsSecrets(QUIC_TLS_SECRETS* Secrets); + + QUIC_TLS_SECRETS GetTlsSecrets() const { return TlsSecrets; } + + void SetSslKeyLogFilePath(const char* Path = DEFAULT_SSLKEYLOGFILE_NAME) { SslKeyLogFileName = Path; } }; diff --git a/src/test/lib/precomp.h b/src/test/lib/precomp.h index b0590e8853..fe3a649316 100644 --- a/src/test/lib/precomp.h +++ b/src/test/lib/precomp.h @@ -24,6 +24,7 @@ #include "msquicp.h" #include "quic_versions.h" #include "quic_trace.h" +#include "msquichelper.h" #include "quic_var_int.h" #include "../core/quicdef.h"