зеркало из https://github.com/microsoft/msquic.git
Add SSLKEYLOGFILE support to quicinterop client (#1020)
This commit is contained in:
Родитель
b75c881f25
Коммит
077a4e9c14
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче