Add SSLKEYLOGFILE support to quicinterop client (#1020)

This commit is contained in:
Anthony Rossi 2020-11-12 13:28:14 -08:00 коммит произвёл GitHub
Родитель b75c881f25
Коммит 077a4e9c14
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 512 добавлений и 10 удалений

Просмотреть файл

@ -126,6 +126,7 @@ option(QUIC_CODE_CHECK "Run static code checkers" OFF)
option(QUIC_OPTIMIZE_LOCAL "Optimize code for local machine architecture" OFF)
option(QUIC_CI "CI Specific build optimizations" OFF)
option(QUIC_RANDOM_ALLOC_FAIL "Randomly fails allocation calls" OFF)
option(QUIC_TLS_SECRETS_SUPPORT "Enable export of TLS secrets" OFF)
# FindLTTngUST does not exist before CMake 3.6, so disable logging for older cmake versions
if (${CMAKE_VERSION} VERSION_LESS "3.6.0")
@ -226,6 +227,10 @@ if(QUIC_RANDOM_ALLOC_FAIL)
list(APPEND QUIC_COMMON_DEFINES QUIC_RANDOM_ALLOC_FAIL=1 QUIC_DISABLE_MEM_POOL=1)
endif()
if(QUIC_TLS_SECRETS_SUPPORT)
list(APPEND QUIC_COMMON_DEFINES QUIC_TLS_SECRETS_SUPPORT=1)
endif()
if(WIN32)
# Generate the MsQuicEtw header file.
file(MAKE_DIRECTORY ${QUIC_BUILD_DIR}/inc)

Просмотреть файл

@ -14,7 +14,7 @@ RUN chmod +x /src/scripts/install-powershell-docker.sh
RUN /src/scripts/install-powershell-docker.sh
ENV PATH="/root/.dotnet/tools:${PATH}"
RUN cmake -DQUIC_BUILD_TEST=OFF -DQUIC_BUILD_PERF=OFF \
-DQUIC_ENABLE_LOGGING=on ..
-DQUIC_ENABLE_LOGGING=on -DQUIC_TLS_SECRETS_SUPPORT=on ..
RUN cmake --build .
FROM martenseemann/quic-network-simulator-endpoint

Просмотреть файл

@ -72,6 +72,9 @@ This script provides helpers for building msquic.
.PARAMETER RandomAllocFail
Enables random allocation failures.
.PARAMETER TlsSecretsSupport
Enables export of traffic secrets.
.EXAMPLE
build.ps1
@ -149,7 +152,10 @@ param (
[switch]$CI = $false,
[Parameter(Mandatory = $false)]
[switch]$RandomAllocFail = $false
[switch]$RandomAllocFail = $false,
[Parameter(Mandatory = $false)]
[switch]$TlsSecretsSupport = $false
)
Set-StrictMode -Version 'Latest'
@ -296,6 +302,9 @@ function CMake-Generate {
if ($RandomAllocFail) {
$Arguments += " -DQUIC_RANDOM_ALLOC_FAIL=on"
}
if ($TlsSecretsSupport) {
$Arguments += " -DQUIC_TLS_SECRETS_SUPPORT=on"
}
$Arguments += " ../../.."
CMake-Execute $Arguments

Просмотреть файл

@ -34,6 +34,8 @@ if [ "$ROLE" == "client" ]; then
/wait-for-it.sh sim:57832 -s -t 30
cd /downloads || exit
CLIENT_PARAMS = "-sslkeylogfile:$SSLKEYLOGFILE"
case "$TESTCASE" in
"resumption")
CLIENT_PARAMS="-test:R $CLIENT_PARAMS"

Просмотреть файл

@ -5626,6 +5626,27 @@ QuicConnParamSet(
Status = QUIC_STATUS_SUCCESS;
break;
case QUIC_PARAM_CONN_TLS_SECRETS:
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (BufferLength != sizeof(QUIC_TLS_SECRETS) || Buffer == NULL) {
Status = QUIC_STATUS_INVALID_PARAMETER;
break;
}
if (Connection->State.Started) {
Status = QUIC_STATUS_INVALID_STATE;
break;
}
Connection->TlsSecrets = (QUIC_TLS_SECRETS*)Buffer;
QuicZeroMemory(Connection->TlsSecrets, sizeof(*Connection->TlsSecrets));
Status = QUIC_STATUS_SUCCESS;
#else
Status = QUIC_STATUS_NOT_SUPPORTED;
#endif
break;
default:
Status = QUIC_STATUS_INVALID_PARAMETER;
break;

Просмотреть файл

@ -531,6 +531,14 @@ typedef struct QUIC_CONNECTION {
//
QUIC_PRIVATE_TRANSPORT_PARAMETER TestTransportParameter;
#ifdef QUIC_TLS_SECRETS_SUPPORT
//
// Struct to log TLS traffic secrets. The app will have to read and
// format the struct once the connection is connected.
//
QUIC_TLS_SECRETS* TlsSecrets;
#endif
} QUIC_CONNECTION;
typedef struct QUIC_SERIALIZED_RESUMPTION_STATE {

Просмотреть файл

@ -288,6 +288,9 @@ QuicCryptoInitializeTls(
if (!QuicConnIsServer(Connection)) {
TlsConfig.ServerName = Connection->RemoteServerName;
}
#ifdef QUIC_TLS_SECRETS_SUPPORT
TlsConfig.TlsSecrets = Connection->TlsSecrets;
#endif
TlsConfig.LocalTPBuffer =
QuicCryptoTlsEncodeTransportParameters(
@ -1343,6 +1346,28 @@ QuicCryptoProcessTlsCompletion(
}
if (ResultFlags & QUIC_TLS_RESULT_DATA) {
#ifdef QUIC_TLS_SECRETS_SUPPORT
//
// Parse the client initial to populate the TlsSecrets with the
// ClientRandom
//
if (Connection->TlsSecrets != NULL &&
!QuicConnIsServer(Connection) &&
Crypto->TlsState.WriteKey == QUIC_PACKET_KEY_INITIAL &&
Crypto->TlsState.BufferLength > 0) {
QUIC_NEW_CONNECTION_INFO Info = { 0 };
QuicCryptoTlsReadInitial(
Connection,
Crypto->TlsState.Buffer,
Crypto->TlsState.BufferLength,
&Info,
Connection->TlsSecrets);
//
// Connection is done with TlsSecrets, clean up.
//
Connection->TlsSecrets = NULL;
}
#endif
QuicSendSetSendFlag(
&QuicCryptoGetConnection(Crypto)->Send,
QUIC_CONN_SEND_FLAG_CRYPTO);
@ -1546,7 +1571,16 @@ QuicCryptoProcessData(
Connection,
Buffer.Buffer,
Buffer.Length,
&Info);
&Info
#ifdef QUIC_TLS_SECRETS_SUPPORT
//
// On server, TLS is initialized before the listener
// is told about the connection, so TlsSecrets is still
// NULL.
//
, NULL
#endif
);
if (QUIC_FAILED(Status)) {
QuicConnTransportError(
Connection,

Просмотреть файл

@ -275,6 +275,9 @@ QuicCryptoTlsReadInitial(
const uint8_t* Buffer,
_In_ uint32_t BufferLength,
_Inout_ QUIC_NEW_CONNECTION_INFO* Info
#ifdef QUIC_TLS_SECRETS_SUPPORT
, _Inout_opt_ QUIC_TLS_SECRETS* TlsSecrets
#endif
);
//

Просмотреть файл

@ -422,6 +422,9 @@ QuicCryptoTlsReadClientHello(
const uint8_t* Buffer,
_In_ uint32_t BufferLength,
_Inout_ QUIC_NEW_CONNECTION_INFO* Info
#ifdef QUIC_TLS_SECRETS_SUPPORT
, _Inout_opt_ QUIC_TLS_SECRETS* TlsSecrets
#endif
)
{
/*
@ -466,6 +469,12 @@ QuicCryptoTlsReadClientHello(
"Parse error. ReadTlsClientHello #2");
return QUIC_STATUS_INVALID_PARAMETER;
}
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (TlsSecrets != NULL) {
memcpy(TlsSecrets->ClientRandom, Buffer, TLS_RANDOM_LENGTH);
TlsSecrets->IsSet.ClientRandom = TRUE;
}
#endif
BufferLength -= TLS_RANDOM_LENGTH;
Buffer += TLS_RANDOM_LENGTH;
@ -582,6 +591,9 @@ QuicCryptoTlsReadInitial(
const uint8_t* Buffer,
_In_ uint32_t BufferLength,
_Inout_ QUIC_NEW_CONNECTION_INFO* Info
#ifdef QUIC_TLS_SECRETS_SUPPORT
, _Inout_opt_ QUIC_TLS_SECRETS* TlsSecrets
#endif
)
{
do {
@ -608,7 +620,11 @@ QuicCryptoTlsReadInitial(
Connection,
Buffer + TLS_MESSAGE_HEADER_LENGTH,
MessageLength,
Info);
Info
#ifdef QUIC_TLS_SECRETS_SUPPORT
, TlsSecrets
#endif
);
if (QUIC_FAILED(Status)) {
return Status;
}

Просмотреть файл

@ -248,6 +248,21 @@ DecodeHexBuffer(
return HexBufferLen;
}
inline
void
EncodeHexBuffer(
_In_reads_(BufferLen) uint8_t* Buffer,
_In_ uint8_t BufferLen,
_Out_writes_bytes_(2*BufferLen) char* HexString
)
{
#define HEX_TO_CHAR(x) ((x) > 9 ? ('a' + ((x) - 10)) : '0' + (x))
for (uint8_t i = 0; i < BufferLen; i++) {
HexString[i*2] = HEX_TO_CHAR(Buffer[i] >> 4);
HexString[i*2 + 1] = HEX_TO_CHAR(Buffer[i] & 0xf);
}
}
#if defined(__cplusplus)
//
@ -494,4 +509,101 @@ FreeServerConfiguration(
MsQuic->ConfigurationClose(Configuration);
}
inline
void
WriteSslKeyLogFile(
_In_z_ const char* FileName,
_In_ QUIC_TLS_SECRETS& TlsSecrets
)
{
FILE* File = nullptr;
#ifdef _WIN32
if (fopen_s(&File, FileName, "ab")) {
printf("Failed to open sslkeylogfile %s\n", FileName);
return;
}
#else
File = fopen(FileName, "ab");
#endif
if (File == nullptr) {
printf("Failed to open sslkeylogfile %s\n", FileName);
return;
}
if (fseek(File, 0, SEEK_END) == 0 && ftell(File) == 0) {
fprintf(File, "# TLS 1.3 secrets log file, generated by quicinterop\n");
}
char ClientRandomBuffer[(2 * sizeof(QUIC_TLS_SECRETS::ClientRandom)) + 1] = {0};
char TempHexBuffer[(2 * QUIC_TLS_SECRETS_MAX_SECRET_LEN) + 1] = {0};
if (TlsSecrets.IsSet.ClientRandom) {
EncodeHexBuffer(
TlsSecrets.ClientRandom,
(uint8_t)sizeof(TlsSecrets.ClientRandom),
ClientRandomBuffer);
}
if (TlsSecrets.IsSet.ClientEarlyTrafficSecret) {
EncodeHexBuffer(
TlsSecrets.ClientEarlyTrafficSecret,
TlsSecrets.SecretLength,
TempHexBuffer);
fprintf(
File,
"CLIENT_EARLY_TRAFFIC_SECRET %s %s\n",
ClientRandomBuffer,
TempHexBuffer);
}
if (TlsSecrets.IsSet.ClientHandshakeTrafficSecret) {
EncodeHexBuffer(
TlsSecrets.ClientHandshakeTrafficSecret,
TlsSecrets.SecretLength,
TempHexBuffer);
fprintf(
File,
"CLIENT_HANDSHAKE_TRAFFIC_SECRET %s %s\n",
ClientRandomBuffer,
TempHexBuffer);
}
if (TlsSecrets.IsSet.ServerHandshakeTrafficSecret) {
EncodeHexBuffer(
TlsSecrets.ServerHandshakeTrafficSecret,
TlsSecrets.SecretLength,
TempHexBuffer);
fprintf(
File,
"SERVER_HANDSHAKE_TRAFFIC_SECRET %s %s\n",
ClientRandomBuffer,
TempHexBuffer);
}
if (TlsSecrets.IsSet.ClientTrafficSecret0) {
EncodeHexBuffer(
TlsSecrets.ClientTrafficSecret0,
TlsSecrets.SecretLength,
TempHexBuffer);
fprintf(
File,
"CLIENT_TRAFFIC_SECRET_0 %s %s\n",
ClientRandomBuffer,
TempHexBuffer);
}
if (TlsSecrets.IsSet.ServerTrafficSecret0) {
EncodeHexBuffer(
TlsSecrets.ServerTrafficSecret0,
TlsSecrets.SecretLength,
TempHexBuffer);
fprintf(
File,
"SERVER_TRAFFIC_SECRET_0 %s %s\n",
ClientRandomBuffer,
TempHexBuffer);
}
fflush(File);
fclose(File);
}
#endif // defined(__cplusplus)

Просмотреть файл

@ -65,6 +65,30 @@ typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER {
const uint8_t* Buffer;
} QUIC_PRIVATE_TRANSPORT_PARAMETER;
//
// This struct enables QUIC applications to support SSLKEYLOGFILE
// for debugging packet captures with e.g. Wireshark.
//
#define QUIC_TLS_SECRETS_MAX_SECRET_LEN 64
typedef struct QUIC_TLS_SECRETS {
uint8_t SecretLength;
struct {
uint8_t ClientRandom : 1;
uint8_t ClientEarlyTrafficSecret : 1;
uint8_t ClientHandshakeTrafficSecret : 1;
uint8_t ServerHandshakeTrafficSecret : 1;
uint8_t ClientTrafficSecret0 : 1;
uint8_t ServerTrafficSecret0 : 1;
} IsSet;
uint8_t ClientRandom[32];
uint8_t ClientEarlyTrafficSecret[QUIC_TLS_SECRETS_MAX_SECRET_LEN];
uint8_t ClientHandshakeTrafficSecret[QUIC_TLS_SECRETS_MAX_SECRET_LEN];
uint8_t ServerHandshakeTrafficSecret[QUIC_TLS_SECRETS_MAX_SECRET_LEN];
uint8_t ClientTrafficSecret0[QUIC_TLS_SECRETS_MAX_SECRET_LEN];
uint8_t ServerTrafficSecret0[QUIC_TLS_SECRETS_MAX_SECRET_LEN];
} QUIC_TLS_SECRETS;
//
// The different private parameters for QUIC_PARAM_LEVEL_GLOBAL.
//
@ -78,6 +102,7 @@ typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER {
#define QUIC_PARAM_CONN_FORCE_KEY_UPDATE 0x80000001 // No payload
#define QUIC_PARAM_CONN_FORCE_CID_UPDATE 0x80000002 // No payload
#define QUIC_PARAM_CONN_TEST_TRANSPORT_PARAMETER 0x80000003 // QUIC_PRIVATE_TRANSPORT_PARAMETER
#define QUIC_PARAM_CONN_TLS_SECRETS 0x80000004 // QUIC_TLS_SECRETS (SSLKEYLOGFILE compatible)
#if defined(__cplusplus)
}

Просмотреть файл

@ -24,6 +24,7 @@ extern "C" {
typedef struct QUIC_SEC_CONFIG QUIC_SEC_CONFIG;
typedef struct QUIC_CONNECTION QUIC_CONNECTION;
typedef struct QUIC_TLS QUIC_TLS;
typedef struct QUIC_TLS_SECRETS QUIC_TLS_SECRETS;
#define TLS_EXTENSION_TYPE_APPLICATION_LAYER_PROTOCOL_NEGOTIATION 0x0010 // Host Byte Order
#define TLS_EXTENSION_TYPE_QUIC_TRANSPORT_PARAMETERS 0xffa5 // Host Byte Order
@ -134,6 +135,14 @@ typedef struct QUIC_TLS_CONFIG {
//
QUIC_TLS_RECEIVE_TICKET_CALLBACK_HANDLER ReceiveResumptionCallback;
#ifdef QUIC_TLS_SECRETS_SUPPORT
//
// Storage for TLS traffic secrets when QUIC_TLS_SECRETS_SUPPORT is enabled,
// and the connection has the parameter set to enable logging.
//
QUIC_TLS_SECRETS* TlsSecrets;
#endif
} QUIC_TLS_CONFIG;
//

Просмотреть файл

@ -285,6 +285,13 @@ typedef struct QUIC_TLS {
//
mitls_extension Extensions[2];
#ifdef QUIC_TLS_SECRETS_SUPPORT
//
// Optional pointer to struct to store TLS secrets.
//
QUIC_TLS_SECRETS* TlsSecrets;
#endif
} QUIC_TLS;
DWORD miTlsCurrentConnectionIndex = TLS_OUT_OF_INDEXES; // Thread-local storage index
@ -561,6 +568,10 @@ QuicTlsInitialize(
TlsContext->miTlsConfig.nego_callback = QuicTlsOnNegotiate;
TlsContext->miTlsConfig.cert_callbacks = &TlsContext->miTlsCertCallbacks;
#ifdef QUIC_TLS_SECRETS_SUPPORT
TlsContext->TlsSecrets = Config->TlsSecrets;
#endif
if (Config->IsServer) {
QUIC_DBG_ASSERT(Config->ResumptionTicketBuffer == NULL);
@ -2180,7 +2191,6 @@ QuicPacketKeyCreate(
}
memcpy(Key->Iv, RecordKey.aead_iv, QUIC_IV_LENGTH);
if (KeyType == QUIC_PACKET_KEY_1_RTT) {
quic_secret ClientReadSecret, ServerReadSecret;
Result =
@ -2226,6 +2236,43 @@ QuicPacketKeyCreate(
QuicCopyMemory(Key->TrafficSecret->Secret, CopySecret->secret, QUIC_HASH_MAX_SIZE);
}
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (TlsContext->TlsSecrets != NULL) {
switch (KeyType) {
case QUIC_PACKET_KEY_1_RTT: {
quic_secret ClientReadSecret, ServerReadSecret;
if (FFI_mitls_quic_get_record_secrets(
TlsContext->miTlsState,
&ClientReadSecret,
&ServerReadSecret)) {
TlsContext->TlsSecrets->SecretLength = (uint8_t)QuicHashLength(ServerReadSecret.hash - 3);
memcpy(
TlsContext->TlsSecrets->ServerTrafficSecret0,
ServerReadSecret.secret,
TlsContext->TlsSecrets->SecretLength);
TlsContext->TlsSecrets->IsSet.ServerTrafficSecret0 = TRUE;
memcpy(
TlsContext->TlsSecrets->ClientTrafficSecret0,
ClientReadSecret.secret,
TlsContext->TlsSecrets->SecretLength);
TlsContext->TlsSecrets->IsSet.ClientTrafficSecret0 = TRUE;
}
//
// We're done with the TlsSecrets.
//
TlsContext->TlsSecrets = NULL;
break;
}
default:
//
// miTls doesn't provide an interface to get the intermediate
// traffic secrets, so only 1-RTT keys can be decrypted.
//
break;
}
}
#endif
*NewKey = Key;
Key = NULL;

Просмотреть файл

@ -87,6 +87,14 @@ typedef struct QUIC_TLS {
QUIC_CONNECTION* Connection;
QUIC_TLS_RECEIVE_TP_CALLBACK_HANDLER ReceiveTPCallback;
#ifdef QUIC_TLS_SECRETS_SUPPORT
//
// Optional struct to log TLS traffic secrets.
// Only non-null when the connection is configured to log these.
//
QUIC_TLS_SECRETS* TlsSecrets;
#endif
} QUIC_TLS;
typedef struct QUIC_HP_KEY {
@ -270,6 +278,47 @@ QuicTlsSetEncryptionSecretsCallback(
TlsState->ReadKey = KeyType;
TlsContext->ResultFlags |= QUIC_TLS_RESULT_READ_KEY_UPDATED;
}
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (TlsContext->TlsSecrets != NULL) {
TlsContext->TlsSecrets->SecretLength = (uint8_t)SecretLen;
switch (KeyType) {
case QUIC_PACKET_KEY_HANDSHAKE:
if (TlsContext->IsServer) {
memcpy(TlsContext->TlsSecrets->ClientHandshakeTrafficSecret, ReadSecret, SecretLen);
memcpy(TlsContext->TlsSecrets->ServerHandshakeTrafficSecret, WriteSecret, SecretLen);
} else {
memcpy(TlsContext->TlsSecrets->ClientHandshakeTrafficSecret, WriteSecret, SecretLen);
memcpy(TlsContext->TlsSecrets->ServerHandshakeTrafficSecret, ReadSecret, SecretLen);
}
TlsContext->TlsSecrets->IsSet.ClientHandshakeTrafficSecret = TRUE;
TlsContext->TlsSecrets->IsSet.ServerHandshakeTrafficSecret = TRUE;
break;
case QUIC_PACKET_KEY_1_RTT:
if (TlsContext->IsServer) {
memcpy(TlsContext->TlsSecrets->ClientTrafficSecret0, ReadSecret, SecretLen);
memcpy(TlsContext->TlsSecrets->ServerTrafficSecret0, WriteSecret, SecretLen);
} else {
memcpy(TlsContext->TlsSecrets->ClientTrafficSecret0, WriteSecret, SecretLen);
memcpy(TlsContext->TlsSecrets->ServerTrafficSecret0, ReadSecret, SecretLen);
}
TlsContext->TlsSecrets->IsSet.ClientTrafficSecret0 = TRUE;
TlsContext->TlsSecrets->IsSet.ServerTrafficSecret0 = TRUE;
//
// We're done with the TlsSecrets.
//
TlsContext->TlsSecrets = NULL;
break;
case QUIC_PACKET_KEY_0_RTT:
if (!TlsContext->IsServer) {
memcpy(TlsContext->TlsSecrets->ClientEarlyTrafficSecret, WriteSecret, SecretLen);
TlsContext->TlsSecrets->IsSet.ClientEarlyTrafficSecret = TRUE;
}
break;
default:
break;
}
}
#endif
return 1;
}
@ -741,6 +790,9 @@ QuicTlsInitialize(
TlsContext->AlpnBufferLength = Config->AlpnBufferLength;
TlsContext->AlpnBuffer = Config->AlpnBuffer;
TlsContext->ReceiveTPCallback = Config->ReceiveTPCallback;
#ifdef QUIC_TLS_SECRETS_SUPPORT
TlsContext->TlsSecrets = Config->TlsSecrets;
#endif
QuicTraceLogConnVerbose(
OpenSslContextCreated,

Просмотреть файл

@ -388,6 +388,14 @@ typedef struct QUIC_TLS {
//
SEC_BUFFER_WORKSPACE Workspace;
#ifdef QUIC_TLS_SECRETS_SUPPORT
//
// Optional struct to log TLS traffic secrets.
// Only non-null when the connection is configured to log these.
//
QUIC_TLS_SECRETS* TlsSecrets;
#endif
} QUIC_TLS;
typedef struct QUIC_HP_KEY {
@ -1469,6 +1477,9 @@ QuicTlsInitialize(
TlsContext->ReceiveTicketCallback = Config->ReceiveResumptionCallback;
TlsContext->SNI = Config->ServerName;
TlsContext->SecConfig = Config->SecConfig;
#ifdef QUIC_TLS_SECRETS_SUPPORT
TlsContext->TlsSecrets = Config->TlsSecrets;
#endif
QuicTraceLogConnVerbose(
SchannelContextCreated,
@ -2035,6 +2046,24 @@ QuicTlsWriteDataToSchannel(
SchannelReadHandshakeStart,
TlsContext->Connection,
"Reading Handshake data starts now");
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (TlsContext->TlsSecrets != NULL) {
TlsContext->TlsSecrets->SecretLength = (uint8_t)NewPeerTrafficSecrets[i]->TrafficSecretSize;
if (TlsContext->IsServer) {
memcpy(
TlsContext->TlsSecrets->ClientHandshakeTrafficSecret,
NewPeerTrafficSecrets[i]->TrafficSecret,
NewPeerTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ClientHandshakeTrafficSecret = TRUE;
} else {
memcpy(
TlsContext->TlsSecrets->ServerHandshakeTrafficSecret,
NewPeerTrafficSecrets[i]->TrafficSecret,
NewPeerTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ServerHandshakeTrafficSecret = TRUE;
}
}
#endif
} else if (State->ReadKey == QUIC_PACKET_KEY_HANDSHAKE) {
if (!QuicPacketKeyCreate(
TlsContext,
@ -2050,6 +2079,24 @@ QuicTlsWriteDataToSchannel(
SchannelRead1RttStart,
TlsContext->Connection,
"Reading 1-RTT data starts now");
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (TlsContext->TlsSecrets != NULL) {
TlsContext->TlsSecrets->SecretLength = (uint8_t)NewPeerTrafficSecrets[i]->TrafficSecretSize;
if (TlsContext->IsServer) {
memcpy(
TlsContext->TlsSecrets->ClientTrafficSecret0,
NewPeerTrafficSecrets[i]->TrafficSecret,
NewPeerTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ClientTrafficSecret0 = TRUE;
} else {
memcpy(
TlsContext->TlsSecrets->ServerTrafficSecret0,
NewPeerTrafficSecrets[i]->TrafficSecret,
NewPeerTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ServerTrafficSecret0 = TRUE;
}
}
#endif
}
}
}
@ -2061,6 +2108,17 @@ QuicTlsWriteDataToSchannel(
Result |= QUIC_TLS_RESULT_WRITE_KEY_UPDATED;
if (NewOwnTrafficSecrets[i]->TrafficSecretType == SecTrafficSecret_ClientEarlyData) {
QUIC_FRE_ASSERT(FALSE); // TODO - Finish the 0-RTT logic.
#ifdef QUIC_TLS_SECRETS_SUPPORT
QUIC_FRE_ASSERT(!TlsContext->IsServer);
if (TlsContext->TlsSecrets != NULL) {
TlsContext->TlsSecrets->SecretLength = (uint8_t)NewOwnTrafficSecrets[i]->TrafficSecretSize;
memcpy(
TlsContext->TlsSecrets->ClientEarlyTrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ClientEarlyTrafficSecret = TRUE;
}
#endif
} else {
if (State->WriteKey == QUIC_PACKET_KEY_INITIAL) {
if (!QuicPacketKeyCreate(
@ -2082,6 +2140,24 @@ QuicTlsWriteDataToSchannel(
TlsContext->Connection,
"Writing Handshake data starts at %u",
State->BufferOffsetHandshake);
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (TlsContext->TlsSecrets != NULL) {
TlsContext->TlsSecrets->SecretLength = (uint8_t)NewOwnTrafficSecrets[i]->TrafficSecretSize;
if (TlsContext->IsServer) {
memcpy(
TlsContext->TlsSecrets->ServerHandshakeTrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ServerHandshakeTrafficSecret = TRUE;
} else {
memcpy(
TlsContext->TlsSecrets->ClientHandshakeTrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ClientHandshakeTrafficSecret = TRUE;
}
}
#endif
} else if (State->WriteKey == QUIC_PACKET_KEY_HANDSHAKE) {
if (!TlsContext->IsServer && State->BufferOffsetHandshake == State->BufferOffset1Rtt) {
State->BufferOffset1Rtt = // HACK - Currently Schannel has weird output for 1-RTT start
@ -2104,11 +2180,38 @@ QuicTlsWriteDataToSchannel(
TlsContext->Connection,
"Writing 1-RTT data starts at %u",
State->BufferOffset1Rtt);
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (TlsContext->TlsSecrets != NULL) {
TlsContext->TlsSecrets->SecretLength = (uint8_t)NewOwnTrafficSecrets[i]->TrafficSecretSize;
if (TlsContext->IsServer) {
memcpy(
TlsContext->TlsSecrets->ServerTrafficSecret0,
NewOwnTrafficSecrets[i]->TrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ServerTrafficSecret0 = TRUE;
} else {
memcpy(
TlsContext->TlsSecrets->ClientTrafficSecret0,
NewOwnTrafficSecrets[i]->TrafficSecret,
NewOwnTrafficSecrets[i]->TrafficSecretSize);
TlsContext->TlsSecrets->IsSet.ClientTrafficSecret0 = TRUE;
}
}
#endif
}
}
}
}
#ifdef QUIC_TLS_SECRETS_SUPPORT
if (SecStatus == SEC_E_OK) {
//
// We're done with the TlsSecrets.
//
TlsContext->TlsSecrets = NULL;
}
#endif
if (OutputTokenBuffer != NULL && OutputTokenBuffer->cbBuffer > 0) {
//
// There is output data to send back.

Просмотреть файл

@ -132,6 +132,8 @@ uint16_t CustomPort = 0;
bool CustomUrlPath = false;
std::vector<std::string> Urls;
const char* SslKeyLogFileParam = nullptr;
extern "C" void QuicTraceRundown(void) { }
void
@ -353,6 +355,8 @@ class InteropConnection {
char* NegotiatedAlpn;
const uint8_t* ResumptionTicket;
uint32_t ResumptionTicketLength;
QUIC_TLS_SECRETS TlsSecrets;
const char* SslKeyLogFile;
public:
bool VersionUnsupported : 1;
bool Connected : 1;
@ -364,6 +368,8 @@ public:
NegotiatedAlpn(nullptr),
ResumptionTicket(nullptr),
ResumptionTicketLength(0),
TlsSecrets({}),
SslKeyLogFile(SslKeyLogFileParam),
VersionUnsupported(false),
Connected(false),
Resumed(false),
@ -407,9 +413,25 @@ public:
sizeof(RandomTransportParameter),
&RandomTransportParameter));
}
if (SslKeyLogFile != nullptr) {
QUIC_STATUS Status =
MsQuic->SetParam(
Connection,
QUIC_PARAM_LEVEL_CONNECTION,
QUIC_PARAM_CONN_TLS_SECRETS,
sizeof(TlsSecrets),
(uint8_t*)&TlsSecrets);
if (QUIC_FAILED(Status)) {
SslKeyLogFile = nullptr;
VERIFY_QUIC_SUCCESS(Status);
}
}
}
~InteropConnection()
{
if (SslKeyLogFile != nullptr) {
WriteSslKeyLogFile(SslKeyLogFile, TlsSecrets);
}
for (InteropStream* Stream : Streams) {
delete Stream;
}
@ -1197,6 +1219,8 @@ main(
Urls.push_back("/");
}
TryGetValue(argc, argv, "sslkeylogfile", &SslKeyLogFileParam);
const char* Target, *Custom;
if (TryGetValue(argc, argv, "target", &Target)) {
bool Found = false;

Просмотреть файл

@ -69,6 +69,7 @@ main(
//
uint16_t LocalPort = DEFAULT_QUIC_HTTP_SERVER_PORT;
BOOLEAN Retry = DEFAULT_QUIC_HTTP_SERVER_RETRY;
const char* SslKeyLogFileParam = nullptr;
TryGetValue(argc, argv, "port", &LocalPort);
TryGetValue(argc, argv, "retry", &Retry);
if (Retry) {
@ -76,6 +77,7 @@ main(
printf("Enabling forced RETRY on server.\n");
}
TryGetValue(argc, argv, "upload", &UploadFolderPath);
TryGetValue(argc, argv, "sslkeylogfile", &SslKeyLogFileParam);
//
// Required parameters.
@ -107,7 +109,7 @@ main(
}
{
HttpServer Server(Registration, SupportedALPNs, ARRAYSIZE(SupportedALPNs), &ListenAddr);
HttpServer Server(Registration, SupportedALPNs, ARRAYSIZE(SupportedALPNs), &ListenAddr, SslKeyLogFileParam);
if (!GetValue(argc, argv, "noexit")) {
printf("Press Enter to exit.\n\n");
getchar();

Просмотреть файл

@ -128,10 +128,13 @@ private:
struct HttpConnection {
HttpConnection(HQUIC connection) :
QuicConnection(connection), RefCount(1) {
QuicConnection(connection), SslKeyLogFile(nullptr), TlsSecrets({}), RefCount(1) {
MsQuic->SetCallbackHandler(QuicConnection, (void*)QuicCallbackHandler, this);
}
~HttpConnection() {
if (SslKeyLogFile != nullptr) {
WriteSslKeyLogFile(SslKeyLogFile, TlsSecrets);
}
MsQuic->ConnectionClose(QuicConnection);
}
void AddRef() {
@ -142,8 +145,22 @@ struct HttpConnection {
delete this;
}
}
QUIC_STATUS SetSslKeyLogFile(const char* InSslKeyLogFile) {
QUIC_STATUS Status =
MsQuic->SetParam(
QuicConnection,
QUIC_PARAM_LEVEL_CONNECTION,
QUIC_PARAM_CONN_TLS_SECRETS,
sizeof(TlsSecrets), &TlsSecrets);
if (QUIC_SUCCEEDED(Status)) {
SslKeyLogFile = InSslKeyLogFile;
}
return Status;
}
private:
HQUIC QuicConnection;
const char* SslKeyLogFile;
QUIC_TLS_SECRETS TlsSecrets;
long RefCount;
private:
static
@ -230,7 +247,9 @@ struct HttpServer {
_In_reads_(AlpnBufferCount) _Pre_defensive_
const QUIC_BUFFER* const AlpnBuffers,
_In_range_(>, 0) uint32_t AlpnBufferCount,
const QUIC_ADDR* LocalAddress) {
const QUIC_ADDR* LocalAddress,
const char* SslKeyLogFile) :
SslKeyLogFile(SslKeyLogFile) {
EXIT_ON_FAILURE(
MsQuic->ListenerOpen(
@ -250,21 +269,32 @@ struct HttpServer {
}
private:
HQUIC QuicListener;
const char* SslKeyLogFile;
private:
static
QUIC_STATUS
QUIC_API
QuicCallbackHandler(
_In_ HQUIC,
_In_opt_ void*,
_In_opt_ void* Context,
_Inout_ QUIC_LISTENER_EVENT* Event
) {
HttpServer* This = (HttpServer*)Context;
if (Event->Type == QUIC_LISTENER_EVENT_NEW_CONNECTION) {
if (Event->NEW_CONNECTION.Info->NegotiatedAlpnLength >= 6 &&
!memcmp(Event->NEW_CONNECTION.Info->NegotiatedAlpn, "siduck", 6)) {
new DatagramConnection(Event->NEW_CONNECTION.Connection);
} else {
new HttpConnection(Event->NEW_CONNECTION.Connection);
HttpConnection* HttpConn = new HttpConnection(Event->NEW_CONNECTION.Connection);
if (This->SslKeyLogFile != nullptr) {
if (QUIC_FAILED(HttpConn->SetSslKeyLogFile(This->SslKeyLogFile))) {
printf("%s:%d %s\n", __FILE__, __LINE__, "Setting SslKeyLogFile on Connection Failed! Did you build with -SslKeyLogFileSupport?");
//
// Disable this instead of printing on every connection.
//
This->SslKeyLogFile = nullptr;
}
}
}
return MsQuic->ConnectionSetConfiguration(Event->NEW_CONNECTION.Connection, Configuration);
}