зеркало из https://github.com/microsoft/msquic.git
Refactor Crypt Code Out (#1631)
This commit is contained in:
Родитель
74d7e4401a
Коммит
0a3344ba00
|
@ -8405,6 +8405,26 @@
|
||||||
],
|
],
|
||||||
"macroName": "QuicTraceEvent"
|
"macroName": "QuicTraceEvent"
|
||||||
},
|
},
|
||||||
|
"TlsLogSecret": {
|
||||||
|
"ModuleProperites": {},
|
||||||
|
"TraceString": "[ tls] %s[%u]: %s",
|
||||||
|
"UniqueId": "TlsLogSecret",
|
||||||
|
"splitArgs": [
|
||||||
|
{
|
||||||
|
"DefinationEncoding": "s",
|
||||||
|
"MacroVariableName": "arg2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DefinationEncoding": "u",
|
||||||
|
"MacroVariableName": "arg3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DefinationEncoding": "s",
|
||||||
|
"MacroVariableName": "arg4"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"macroName": "QuicTraceLogVerbose"
|
||||||
|
},
|
||||||
"DatapathOpenUdpSocketFailed": {
|
"DatapathOpenUdpSocketFailed": {
|
||||||
"ModuleProperites": {},
|
"ModuleProperites": {},
|
||||||
"TraceString": "[data] UDP send segmentation helper socket failed to open, 0x%x",
|
"TraceString": "[data] UDP send segmentation helper socket failed to open, 0x%x",
|
||||||
|
@ -9119,26 +9139,6 @@
|
||||||
],
|
],
|
||||||
"macroName": "QuicTraceLogVerbose"
|
"macroName": "QuicTraceLogVerbose"
|
||||||
},
|
},
|
||||||
"OpenSslLogSecret": {
|
|
||||||
"ModuleProperites": {},
|
|
||||||
"TraceString": "[ tls] %s[%u]: %s",
|
|
||||||
"UniqueId": "OpenSslLogSecret",
|
|
||||||
"splitArgs": [
|
|
||||||
{
|
|
||||||
"DefinationEncoding": "s",
|
|
||||||
"MacroVariableName": "arg2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"DefinationEncoding": "u",
|
|
||||||
"MacroVariableName": "arg3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"DefinationEncoding": "s",
|
|
||||||
"MacroVariableName": "arg4"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"macroName": "QuicTraceLogVerbose"
|
|
||||||
},
|
|
||||||
"OpenSslAlert": {
|
"OpenSslAlert": {
|
||||||
"ModuleProperites": {},
|
"ModuleProperites": {},
|
||||||
"TraceString": "[conn][%p] Send alert = %u (Level = %u)",
|
"TraceString": "[conn][%p] Send alert = %u (Level = %u)",
|
||||||
|
@ -9511,20 +9511,6 @@
|
||||||
],
|
],
|
||||||
"macroName": "QuicTraceEvent"
|
"macroName": "QuicTraceEvent"
|
||||||
},
|
},
|
||||||
"SchannelInitialized": {
|
|
||||||
"ModuleProperites": {},
|
|
||||||
"TraceString": "[ tls] Library initialized",
|
|
||||||
"UniqueId": "SchannelInitialized",
|
|
||||||
"splitArgs": [],
|
|
||||||
"macroName": "QuicTraceLogVerbose"
|
|
||||||
},
|
|
||||||
"SchannelUninitialized": {
|
|
||||||
"ModuleProperites": {},
|
|
||||||
"TraceString": "[ tls] Library uninitialized",
|
|
||||||
"UniqueId": "SchannelUninitialized",
|
|
||||||
"splitArgs": [],
|
|
||||||
"macroName": "QuicTraceLogVerbose"
|
|
||||||
},
|
|
||||||
"SchannelAchAsync": {
|
"SchannelAchAsync": {
|
||||||
"ModuleProperites": {},
|
"ModuleProperites": {},
|
||||||
"TraceString": "[ tls] Calling SspiAcquireCredentialsHandleAsyncW",
|
"TraceString": "[ tls] Calling SspiAcquireCredentialsHandleAsyncW",
|
||||||
|
@ -9558,26 +9544,6 @@
|
||||||
],
|
],
|
||||||
"macroName": "QuicTraceLogVerbose"
|
"macroName": "QuicTraceLogVerbose"
|
||||||
},
|
},
|
||||||
"SchannelLogSecret": {
|
|
||||||
"ModuleProperites": {},
|
|
||||||
"TraceString": "[ tls] %s[%u]: %s",
|
|
||||||
"UniqueId": "SchannelLogSecret",
|
|
||||||
"splitArgs": [
|
|
||||||
{
|
|
||||||
"DefinationEncoding": "s",
|
|
||||||
"MacroVariableName": "arg2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"DefinationEncoding": "u",
|
|
||||||
"MacroVariableName": "arg3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"DefinationEncoding": "s",
|
|
||||||
"MacroVariableName": "arg4"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"macroName": "QuicTraceLogVerbose"
|
|
||||||
},
|
|
||||||
"SchannelHandshakeComplete": {
|
"SchannelHandshakeComplete": {
|
||||||
"ModuleProperites": {},
|
"ModuleProperites": {},
|
||||||
"TraceString": "[conn][%p] Handshake complete (resume=%hu)",
|
"TraceString": "[conn][%p] Handshake complete (resume=%hu)",
|
||||||
|
@ -12661,6 +12627,10 @@
|
||||||
"UniquenessHash": "2cbc406b-c1c0-ba4d-eee8-669f30330f4a",
|
"UniquenessHash": "2cbc406b-c1c0-ba4d-eee8-669f30330f4a",
|
||||||
"TraceID": "LibraryError"
|
"TraceID": "LibraryError"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"UniquenessHash": "7512a5e6-b76b-d244-25a2-f27c6b593461",
|
||||||
|
"TraceID": "TlsLogSecret"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"UniquenessHash": "78b2984b-b937-3b8e-7684-9339d9267135",
|
"UniquenessHash": "78b2984b-b937-3b8e-7684-9339d9267135",
|
||||||
"TraceID": "DatapathOpenUdpSocketFailed"
|
"TraceID": "DatapathOpenUdpSocketFailed"
|
||||||
|
@ -12877,10 +12847,6 @@
|
||||||
"UniquenessHash": "86a081de-c71a-7043-b507-672561f5fd36",
|
"UniquenessHash": "86a081de-c71a-7043-b507-672561f5fd36",
|
||||||
"TraceID": "StorageOpenKey"
|
"TraceID": "StorageOpenKey"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"UniquenessHash": "69c5c25e-ab70-9800-8260-aa93a193bd8b",
|
|
||||||
"TraceID": "OpenSslLogSecret"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"UniquenessHash": "c7b17ffc-7649-6294-b6d0-cf4bbf4bc8cb",
|
"UniquenessHash": "c7b17ffc-7649-6294-b6d0-cf4bbf4bc8cb",
|
||||||
"TraceID": "OpenSslAlert"
|
"TraceID": "OpenSslAlert"
|
||||||
|
@ -12977,14 +12943,6 @@
|
||||||
"UniquenessHash": "7312d23f-2305-b54b-e1da-81597fabe281",
|
"UniquenessHash": "7312d23f-2305-b54b-e1da-81597fabe281",
|
||||||
"TraceID": "TlsErrorStatus"
|
"TraceID": "TlsErrorStatus"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"UniquenessHash": "a0f9d887-3cc8-3dd3-f2c7-8143878abe6e",
|
|
||||||
"TraceID": "SchannelInitialized"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"UniquenessHash": "b21a8d0d-c484-ac00-8081-90d5e8de9d1f",
|
|
||||||
"TraceID": "SchannelUninitialized"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"UniquenessHash": "fd2f4dda-2c95-a301-6a5e-8dda859fd5c5",
|
"UniquenessHash": "fd2f4dda-2c95-a301-6a5e-8dda859fd5c5",
|
||||||
"TraceID": "SchannelAchAsync"
|
"TraceID": "SchannelAchAsync"
|
||||||
|
@ -13001,10 +12959,6 @@
|
||||||
"UniquenessHash": "7a6ea81a-5491-2148-a007-711c5a641acc",
|
"UniquenessHash": "7a6ea81a-5491-2148-a007-711c5a641acc",
|
||||||
"TraceID": "SchannelAchCompleteInline"
|
"TraceID": "SchannelAchCompleteInline"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"UniquenessHash": "c04de4b9-64de-c415-dda2-b07f295f9897",
|
|
||||||
"TraceID": "SchannelLogSecret"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"UniquenessHash": "799852e0-2f39-43d4-6888-98a33178b844",
|
"UniquenessHash": "799852e0-2f39-43d4-6888-98a33178b844",
|
||||||
"TraceID": "SchannelHandshakeComplete"
|
"TraceID": "SchannelHandshakeComplete"
|
||||||
|
|
|
@ -9,49 +9,28 @@ if (QUIC_CODE_CHECK)
|
||||||
set(CMAKE_CXX_CPPCHECK ${CMAKE_C_CPPCHECK_AVAILABLE})
|
set(CMAKE_CXX_CPPCHECK ${CMAKE_C_CPPCHECK_AVAILABLE})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(SOURCES crypt.c hashtable.c pcp.c toeplitz.c)
|
||||||
|
|
||||||
if("${CX_PLATFORM}" STREQUAL "windows")
|
if("${CX_PLATFORM}" STREQUAL "windows")
|
||||||
set(SOURCES
|
set(SOURCES ${SOURCES} datapath_winuser.c platform_winuser.c storage_winuser.c)
|
||||||
datapath_winuser.c
|
|
||||||
hashtable.c
|
|
||||||
pcp.c
|
|
||||||
platform_winuser.c
|
|
||||||
storage_winuser.c
|
|
||||||
toeplitz.c
|
|
||||||
)
|
|
||||||
else()
|
else()
|
||||||
if(CX_PLATFORM STREQUAL "linux")
|
if(CX_PLATFORM STREQUAL "linux")
|
||||||
set(SOURCES
|
set(SOURCES ${SOURCES} datapath_epoll.c platform_posix.c storage_posix.c)
|
||||||
datapath_epoll.c
|
|
||||||
hashtable.c
|
|
||||||
inline.c
|
|
||||||
pcp.c
|
|
||||||
platform_posix.c
|
|
||||||
storage_posix.c
|
|
||||||
toeplitz.c
|
|
||||||
)
|
|
||||||
else()
|
else()
|
||||||
set(SOURCES
|
set(SOURCES ${SOURCES} datapath_kqueue.c platform_posix.c storage_posix.c)
|
||||||
datapath_kqueue.c
|
|
||||||
hashtable.c
|
|
||||||
inline.c
|
|
||||||
pcp.c
|
|
||||||
platform_posix.c
|
|
||||||
storage_posix.c
|
|
||||||
toeplitz.c
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (QUIC_TLS STREQUAL "schannel")
|
if (QUIC_TLS STREQUAL "schannel")
|
||||||
message(STATUS "Configuring for Schannel")
|
message(STATUS "Configuring for Schannel")
|
||||||
set(SOURCES ${SOURCES} cert_capi.c selfsign_capi.c tls_schannel.c)
|
set(SOURCES ${SOURCES} cert_capi.c crypt_bcrypt.c selfsign_capi.c tls_schannel.c)
|
||||||
elseif(QUIC_TLS STREQUAL "openssl")
|
elseif(QUIC_TLS STREQUAL "openssl")
|
||||||
message(STATUS "Configuring for OpenSSL")
|
message(STATUS "Configuring for OpenSSL")
|
||||||
set(SOURCES ${SOURCES} tls_openssl.c cert_capi_openssl.c)
|
set(SOURCES ${SOURCES} cert_capi_openssl.c tls_openssl.c)
|
||||||
if ("${CX_PLATFORM}" STREQUAL "windows")
|
if ("${CX_PLATFORM}" STREQUAL "windows")
|
||||||
set(SOURCES ${SOURCES} cert_capi.c selfsign_capi.c)
|
set(SOURCES ${SOURCES} cert_capi.c crypt_openssl.c selfsign_capi.c)
|
||||||
else()
|
else()
|
||||||
set(SOURCES ${SOURCES} selfsign_openssl.c)
|
set(SOURCES ${SOURCES} crypt_openssl.c inline.c selfsign_openssl.c)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "TLS Provider not configured")
|
message(FATAL_ERROR "TLS Provider not configured")
|
||||||
|
|
|
@ -0,0 +1,469 @@
|
||||||
|
/*++
|
||||||
|
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
Licensed under the MIT License.
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Implements the generic platform cryptographic operations.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#include "platform_internal.h"
|
||||||
|
|
||||||
|
#ifdef QUIC_CLOG
|
||||||
|
#include "crypt.c.clog.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
CxPlatTlsLogSecret(
|
||||||
|
_In_z_ const char* const Prefix,
|
||||||
|
_In_reads_(Length)
|
||||||
|
const uint8_t* const Secret,
|
||||||
|
_In_ uint32_t Length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#define HEX_TO_CHAR(x) ((x) > 9 ? ('a' + ((x) - 10)) : '0' + (x))
|
||||||
|
char SecretStr[256 + 1] = {0};
|
||||||
|
CXPLAT_DBG_ASSERT(Length * 2 < sizeof(SecretStr));
|
||||||
|
for (uint32_t i = 0; i < Length; i++) {
|
||||||
|
SecretStr[i*2] = HEX_TO_CHAR(Secret[i] >> 4);
|
||||||
|
SecretStr[i*2 + 1] = HEX_TO_CHAR(Secret[i] & 0xf);
|
||||||
|
}
|
||||||
|
QuicTraceLogVerbose(
|
||||||
|
TlsLogSecret,
|
||||||
|
"[ tls] %s[%u]: %s",
|
||||||
|
Prefix,
|
||||||
|
Length,
|
||||||
|
SecretStr);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define CxPlatTlsLogSecret(Prefix, Secret, Length) UNREFERENCED_PARAMETER(Prefix);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
CxPlatHkdfFormatLabel(
|
||||||
|
_In_z_ const char* const Label,
|
||||||
|
_In_ uint16_t HashLength,
|
||||||
|
_Out_writes_all_(5 + CXPLAT_HKDF_PREFIX_LEN + strlen(Label))
|
||||||
|
uint8_t* const Data,
|
||||||
|
_Inout_ uint32_t* const DataLength
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CXPLAT_DBG_ASSERT(strlen(Label) <= UINT8_MAX - CXPLAT_HKDF_PREFIX_LEN);
|
||||||
|
uint8_t LabelLength = (uint8_t)strlen(Label);
|
||||||
|
|
||||||
|
Data[0] = HashLength >> 8;
|
||||||
|
Data[1] = HashLength & 0xff;
|
||||||
|
Data[2] = CXPLAT_HKDF_PREFIX_LEN + LabelLength;
|
||||||
|
memcpy(Data + 3, CXPLAT_HKDF_PREFIX, CXPLAT_HKDF_PREFIX_LEN);
|
||||||
|
memcpy(Data + 3 + CXPLAT_HKDF_PREFIX_LEN, Label, LabelLength);
|
||||||
|
Data[3 + CXPLAT_HKDF_PREFIX_LEN + LabelLength] = 0;
|
||||||
|
*DataLength = 3 + CXPLAT_HKDF_PREFIX_LEN + LabelLength + 1;
|
||||||
|
|
||||||
|
Data[*DataLength] = 0x1;
|
||||||
|
*DataLength += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHkdfExpandLabel(
|
||||||
|
_In_ CXPLAT_HASH* Hash,
|
||||||
|
_In_z_ const char* const Label,
|
||||||
|
_In_ uint16_t KeyLength,
|
||||||
|
_In_ uint32_t OutputLength, // Writes CxPlatHashLength(HashType) bytes.
|
||||||
|
_Out_writes_all_(OutputLength)
|
||||||
|
uint8_t* const Output
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint8_t LabelBuffer[64];
|
||||||
|
uint32_t LabelLength = sizeof(LabelBuffer);
|
||||||
|
|
||||||
|
_Analysis_assume_(strlen(Label) <= 23);
|
||||||
|
CxPlatHkdfFormatLabel(Label, KeyLength, LabelBuffer, &LabelLength);
|
||||||
|
|
||||||
|
return
|
||||||
|
CxPlatHashCompute(
|
||||||
|
Hash,
|
||||||
|
LabelBuffer,
|
||||||
|
LabelLength,
|
||||||
|
OutputLength,
|
||||||
|
Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatTlsDeriveInitialSecrets(
|
||||||
|
_In_reads_(CXPLAT_VERSION_SALT_LENGTH)
|
||||||
|
const uint8_t* const Salt,
|
||||||
|
_In_reads_(CIDLength)
|
||||||
|
const uint8_t* const CID,
|
||||||
|
_In_ uint8_t CIDLength,
|
||||||
|
_Out_ CXPLAT_SECRET *ClientInitial,
|
||||||
|
_Out_ CXPLAT_SECRET *ServerInitial
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QUIC_STATUS Status;
|
||||||
|
CXPLAT_HASH* InitialHash = NULL;
|
||||||
|
CXPLAT_HASH* DerivedHash = NULL;
|
||||||
|
uint8_t InitialSecret[CXPLAT_HASH_SHA256_SIZE];
|
||||||
|
|
||||||
|
CxPlatTlsLogSecret("init cid", CID, CIDLength);
|
||||||
|
|
||||||
|
Status =
|
||||||
|
CxPlatHashCreate(
|
||||||
|
CXPLAT_HASH_SHA256,
|
||||||
|
Salt,
|
||||||
|
CXPLAT_VERSION_SALT_LENGTH,
|
||||||
|
&InitialHash);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Extract secret for client and server secret expansion.
|
||||||
|
//
|
||||||
|
Status =
|
||||||
|
CxPlatHashCompute(
|
||||||
|
InitialHash,
|
||||||
|
CID,
|
||||||
|
CIDLength,
|
||||||
|
sizeof(InitialSecret),
|
||||||
|
InitialSecret);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
CxPlatTlsLogSecret("init secret", InitialSecret, sizeof(InitialSecret));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create hash for client and server secret expansion.
|
||||||
|
//
|
||||||
|
Status =
|
||||||
|
CxPlatHashCreate(
|
||||||
|
CXPLAT_HASH_SHA256,
|
||||||
|
InitialSecret,
|
||||||
|
sizeof(InitialSecret),
|
||||||
|
&DerivedHash);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Expand client secret.
|
||||||
|
//
|
||||||
|
ClientInitial->Hash = CXPLAT_HASH_SHA256;
|
||||||
|
ClientInitial->Aead = CXPLAT_AEAD_AES_128_GCM;
|
||||||
|
Status =
|
||||||
|
CxPlatHkdfExpandLabel(
|
||||||
|
DerivedHash,
|
||||||
|
"client in",
|
||||||
|
sizeof(InitialSecret),
|
||||||
|
CXPLAT_HASH_SHA256_SIZE,
|
||||||
|
ClientInitial->Secret);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Expand server secret.
|
||||||
|
//
|
||||||
|
ServerInitial->Hash = CXPLAT_HASH_SHA256;
|
||||||
|
ServerInitial->Aead = CXPLAT_AEAD_AES_128_GCM;
|
||||||
|
Status =
|
||||||
|
CxPlatHkdfExpandLabel(
|
||||||
|
DerivedHash,
|
||||||
|
"server in",
|
||||||
|
sizeof(InitialSecret),
|
||||||
|
CXPLAT_HASH_SHA256_SIZE,
|
||||||
|
ServerInitial->Secret);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
CxPlatHashFree(InitialHash);
|
||||||
|
CxPlatHashFree(DerivedHash);
|
||||||
|
|
||||||
|
CxPlatSecureZeroMemory(InitialSecret, sizeof(InitialSecret));
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
QuicPacketKeyDerive(
|
||||||
|
_In_ QUIC_PACKET_KEY_TYPE KeyType,
|
||||||
|
_In_ const CXPLAT_SECRET* const Secret,
|
||||||
|
_In_z_ const char* const SecretName,
|
||||||
|
_In_ BOOLEAN CreateHpKey,
|
||||||
|
_Out_ QUIC_PACKET_KEY **NewKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const uint16_t SecretLength = CxPlatHashLength(Secret->Hash);
|
||||||
|
const uint16_t KeyLength = CxPlatKeyLength(Secret->Aead);
|
||||||
|
|
||||||
|
CXPLAT_DBG_ASSERT(SecretLength >= KeyLength);
|
||||||
|
CXPLAT_DBG_ASSERT(SecretLength >= CXPLAT_IV_LENGTH);
|
||||||
|
CXPLAT_DBG_ASSERT(SecretLength <= CXPLAT_HASH_MAX_SIZE);
|
||||||
|
|
||||||
|
CxPlatTlsLogSecret(SecretName, Secret->Secret, SecretLength);
|
||||||
|
|
||||||
|
const uint16_t PacketKeyLength =
|
||||||
|
sizeof(QUIC_PACKET_KEY) +
|
||||||
|
(KeyType == QUIC_PACKET_KEY_1_RTT ? sizeof(CXPLAT_SECRET) : 0);
|
||||||
|
QUIC_PACKET_KEY *Key = CXPLAT_ALLOC_NONPAGED(PacketKeyLength, QUIC_POOL_TLS_PACKETKEY);
|
||||||
|
if (Key == NULL) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
AllocFailure,
|
||||||
|
"Allocation of '%s' failed. (%llu bytes)",
|
||||||
|
"QUIC_PACKET_KEY",
|
||||||
|
PacketKeyLength);
|
||||||
|
return QUIC_STATUS_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
CxPlatZeroMemory(Key, sizeof(QUIC_PACKET_KEY));
|
||||||
|
Key->Type = KeyType;
|
||||||
|
|
||||||
|
CXPLAT_HASH* Hash = NULL;
|
||||||
|
uint8_t Temp[CXPLAT_HASH_MAX_SIZE];
|
||||||
|
|
||||||
|
QUIC_STATUS Status =
|
||||||
|
CxPlatHashCreate(
|
||||||
|
Secret->Hash,
|
||||||
|
Secret->Secret,
|
||||||
|
SecretLength,
|
||||||
|
&Hash);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
CxPlatHkdfExpandLabel(
|
||||||
|
Hash,
|
||||||
|
"quic iv",
|
||||||
|
CXPLAT_IV_LENGTH,
|
||||||
|
SecretLength,
|
||||||
|
Temp);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(Key->Iv, Temp, CXPLAT_IV_LENGTH);
|
||||||
|
CxPlatTlsLogSecret("static iv", Key->Iv, CXPLAT_IV_LENGTH);
|
||||||
|
|
||||||
|
Status =
|
||||||
|
CxPlatHkdfExpandLabel(
|
||||||
|
Hash,
|
||||||
|
"quic key",
|
||||||
|
KeyLength,
|
||||||
|
SecretLength,
|
||||||
|
Temp);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
CxPlatTlsLogSecret("key", Temp, KeyLength);
|
||||||
|
|
||||||
|
Status =
|
||||||
|
CxPlatKeyCreate(
|
||||||
|
Secret->Aead,
|
||||||
|
Temp,
|
||||||
|
&Key->PacketKey);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CreateHpKey) {
|
||||||
|
Status =
|
||||||
|
CxPlatHkdfExpandLabel(
|
||||||
|
Hash,
|
||||||
|
"quic hp",
|
||||||
|
KeyLength,
|
||||||
|
SecretLength,
|
||||||
|
Temp);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
CxPlatTlsLogSecret("hp", Temp, KeyLength);
|
||||||
|
|
||||||
|
Status =
|
||||||
|
CxPlatHpKeyCreate(
|
||||||
|
Secret->Aead,
|
||||||
|
Temp,
|
||||||
|
&Key->HeaderKey);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KeyType == QUIC_PACKET_KEY_1_RTT) {
|
||||||
|
CxPlatCopyMemory(Key->TrafficSecret, Secret, sizeof(CXPLAT_SECRET));
|
||||||
|
}
|
||||||
|
|
||||||
|
*NewKey = Key;
|
||||||
|
Key = NULL;
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
QuicPacketKeyFree(Key);
|
||||||
|
CxPlatHashFree(Hash);
|
||||||
|
|
||||||
|
CxPlatSecureZeroMemory(Temp, sizeof(Temp));
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
_When_(NewReadKey != NULL, _At_(*NewReadKey, __drv_allocatesMem(Mem)))
|
||||||
|
_When_(NewWriteKey != NULL, _At_(*NewWriteKey, __drv_allocatesMem(Mem)))
|
||||||
|
QUIC_STATUS
|
||||||
|
QuicPacketKeyCreateInitial(
|
||||||
|
_In_ BOOLEAN IsServer,
|
||||||
|
_In_reads_(CXPLAT_VERSION_SALT_LENGTH)
|
||||||
|
const uint8_t* const Salt, // Version Specific
|
||||||
|
_In_ uint8_t CIDLength,
|
||||||
|
_In_reads_(CIDLength)
|
||||||
|
const uint8_t* const CID,
|
||||||
|
_Out_opt_ QUIC_PACKET_KEY** NewReadKey,
|
||||||
|
_Out_opt_ QUIC_PACKET_KEY** NewWriteKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QUIC_STATUS Status;
|
||||||
|
CXPLAT_SECRET ClientInitial, ServerInitial;
|
||||||
|
QUIC_PACKET_KEY* ReadKey = NULL, *WriteKey = NULL;
|
||||||
|
|
||||||
|
Status =
|
||||||
|
CxPlatTlsDeriveInitialSecrets(
|
||||||
|
Salt,
|
||||||
|
CID,
|
||||||
|
CIDLength,
|
||||||
|
&ClientInitial,
|
||||||
|
&ServerInitial);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewWriteKey != NULL) {
|
||||||
|
Status =
|
||||||
|
QuicPacketKeyDerive(
|
||||||
|
QUIC_PACKET_KEY_INITIAL,
|
||||||
|
IsServer ? &ServerInitial : &ClientInitial,
|
||||||
|
IsServer ? "srv secret" : "cli secret",
|
||||||
|
TRUE,
|
||||||
|
&WriteKey);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewReadKey != NULL) {
|
||||||
|
Status =
|
||||||
|
QuicPacketKeyDerive(
|
||||||
|
QUIC_PACKET_KEY_INITIAL,
|
||||||
|
IsServer ? &ClientInitial : &ServerInitial,
|
||||||
|
IsServer ? "cli secret" : "srv secret",
|
||||||
|
TRUE,
|
||||||
|
&ReadKey);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewWriteKey != NULL) {
|
||||||
|
*NewWriteKey = WriteKey;
|
||||||
|
WriteKey = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewReadKey != NULL) {
|
||||||
|
*NewReadKey = ReadKey;
|
||||||
|
ReadKey = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
QuicPacketKeyFree(ReadKey);
|
||||||
|
QuicPacketKeyFree(WriteKey);
|
||||||
|
|
||||||
|
CxPlatSecureZeroMemory(ClientInitial.Secret, sizeof(ClientInitial.Secret));
|
||||||
|
CxPlatSecureZeroMemory(ServerInitial.Secret, sizeof(ServerInitial.Secret));
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
QuicPacketKeyFree(
|
||||||
|
_In_opt_ __drv_freesMem(Mem) QUIC_PACKET_KEY* Key
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Key != NULL) {
|
||||||
|
CxPlatKeyFree(Key->PacketKey);
|
||||||
|
CxPlatHpKeyFree(Key->HeaderKey);
|
||||||
|
if (Key->Type >= QUIC_PACKET_KEY_1_RTT) {
|
||||||
|
CxPlatSecureZeroMemory(Key->TrafficSecret, sizeof(CXPLAT_SECRET));
|
||||||
|
}
|
||||||
|
CXPLAT_FREE(Key, QUIC_POOL_TLS_PACKETKEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
_At_(*NewKey, __drv_allocatesMem(Mem))
|
||||||
|
QUIC_STATUS
|
||||||
|
QuicPacketKeyUpdate(
|
||||||
|
_In_ QUIC_PACKET_KEY* OldKey,
|
||||||
|
_Out_ QUIC_PACKET_KEY** NewKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (OldKey->Type != QUIC_PACKET_KEY_1_RTT) {
|
||||||
|
return QUIC_STATUS_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CXPLAT_HASH* Hash = NULL;
|
||||||
|
CXPLAT_SECRET NewTrafficSecret;
|
||||||
|
const uint16_t SecretLength = CxPlatHashLength(OldKey->TrafficSecret->Hash);
|
||||||
|
|
||||||
|
QUIC_STATUS Status =
|
||||||
|
CxPlatHashCreate(
|
||||||
|
OldKey->TrafficSecret->Hash,
|
||||||
|
OldKey->TrafficSecret->Secret,
|
||||||
|
SecretLength,
|
||||||
|
&Hash);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
CxPlatHkdfExpandLabel(
|
||||||
|
Hash,
|
||||||
|
"quic ku",
|
||||||
|
SecretLength,
|
||||||
|
SecretLength,
|
||||||
|
NewTrafficSecret.Secret);
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewTrafficSecret.Hash = OldKey->TrafficSecret->Hash;
|
||||||
|
NewTrafficSecret.Aead = OldKey->TrafficSecret->Aead;
|
||||||
|
|
||||||
|
Status =
|
||||||
|
QuicPacketKeyDerive(
|
||||||
|
QUIC_PACKET_KEY_1_RTT,
|
||||||
|
&NewTrafficSecret,
|
||||||
|
"update traffic secret",
|
||||||
|
FALSE,
|
||||||
|
NewKey);
|
||||||
|
|
||||||
|
CxPlatSecureZeroMemory(&NewTrafficSecret, sizeof(CXPLAT_SECRET));
|
||||||
|
CxPlatSecureZeroMemory(OldKey->TrafficSecret, sizeof(CXPLAT_SECRET));
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
CxPlatHashFree(Hash);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
|
@ -0,0 +1,749 @@
|
||||||
|
/*++
|
||||||
|
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
Licensed under the MIT License.
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
BCrypt cryptographic implementation for QUIC
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
|
||||||
|
Windows user mode or kernel mode
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#include "platform_internal.h"
|
||||||
|
#include <security.h>
|
||||||
|
#ifdef QUIC_CLOG
|
||||||
|
#include "crypt_bcrypt.c.clog.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct CXPLAT_HP_KEY {
|
||||||
|
BCRYPT_KEY_HANDLE Key;
|
||||||
|
CXPLAT_AEAD_TYPE Aead;
|
||||||
|
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO Info[0];
|
||||||
|
} CXPLAT_HP_KEY;
|
||||||
|
|
||||||
|
#define SecStatusToQuicStatus(x) (QUIC_STATUS)(x)
|
||||||
|
|
||||||
|
#ifdef _KERNEL_MODE
|
||||||
|
#define NtStatusToQuicStatus(x) (x)
|
||||||
|
#else
|
||||||
|
#define NtStatusToQuicStatus(x) HRESULT_FROM_WIN32(RtlNtStatusToDosError(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// Defines until BCrypt.h updates
|
||||||
|
//
|
||||||
|
#ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM
|
||||||
|
#define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _KERNEL_MODE
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_HMAC_SHA256_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_HMAC_SHA384_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_HMAC_SHA512_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_AES_ECB_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_AES_GCM_ALG_HANDLE;
|
||||||
|
#else
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_HMAC_SHA256_ALG_HANDLE = BCRYPT_HMAC_SHA256_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_HMAC_SHA384_ALG_HANDLE = BCRYPT_HMAC_SHA384_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_HMAC_SHA512_ALG_HANDLE = BCRYPT_HMAC_SHA512_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_AES_ECB_ALG_HANDLE = BCRYPT_AES_ECB_ALG_HANDLE;
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_AES_GCM_ALG_HANDLE = BCRYPT_AES_GCM_ALG_HANDLE;
|
||||||
|
#endif
|
||||||
|
BCRYPT_ALG_HANDLE CXPLAT_CHACHA20_POLY1305_ALG_HANDLE = NULL;
|
||||||
|
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatCryptInitialize(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#ifdef _KERNEL_MODE
|
||||||
|
ULONG Flags = BCRYPT_ALG_HANDLE_HMAC_FLAG | BCRYPT_PROV_DISPATCH;
|
||||||
|
NTSTATUS Status =
|
||||||
|
BCryptOpenAlgorithmProvider(
|
||||||
|
&CXPLAT_HMAC_SHA256_ALG_HANDLE,
|
||||||
|
BCRYPT_SHA256_ALGORITHM,
|
||||||
|
MS_PRIMITIVE_PROVIDER,
|
||||||
|
Flags);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Open HMAC_SHA256 algorithm");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptOpenAlgorithmProvider(
|
||||||
|
&CXPLAT_HMAC_SHA384_ALG_HANDLE,
|
||||||
|
BCRYPT_SHA384_ALGORITHM,
|
||||||
|
MS_PRIMITIVE_PROVIDER,
|
||||||
|
Flags);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Open HMAC_SHA384 algorithm");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptOpenAlgorithmProvider(
|
||||||
|
&CXPLAT_HMAC_SHA512_ALG_HANDLE,
|
||||||
|
BCRYPT_SHA512_ALGORITHM,
|
||||||
|
MS_PRIMITIVE_PROVIDER,
|
||||||
|
Flags);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Open HMAC_SHA512 algorithm");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptOpenAlgorithmProvider(
|
||||||
|
&CXPLAT_AES_ECB_ALG_HANDLE,
|
||||||
|
BCRYPT_AES_ALGORITHM,
|
||||||
|
MS_PRIMITIVE_PROVIDER,
|
||||||
|
BCRYPT_PROV_DISPATCH);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Open AES algorithm");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptSetProperty(
|
||||||
|
CXPLAT_AES_ECB_ALG_HANDLE,
|
||||||
|
BCRYPT_CHAINING_MODE,
|
||||||
|
(PBYTE)BCRYPT_CHAIN_MODE_ECB,
|
||||||
|
sizeof(BCRYPT_CHAIN_MODE_ECB),
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Set ECB chaining mode");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptOpenAlgorithmProvider(
|
||||||
|
&CXPLAT_AES_GCM_ALG_HANDLE,
|
||||||
|
BCRYPT_AES_ALGORITHM,
|
||||||
|
MS_PRIMITIVE_PROVIDER,
|
||||||
|
BCRYPT_PROV_DISPATCH);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Open AES algorithm");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptSetProperty(
|
||||||
|
CXPLAT_AES_GCM_ALG_HANDLE,
|
||||||
|
BCRYPT_CHAINING_MODE,
|
||||||
|
(PBYTE)BCRYPT_CHAIN_MODE_GCM,
|
||||||
|
sizeof(BCRYPT_CHAIN_MODE_GCM),
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Set GCM chaining mode");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptOpenAlgorithmProvider(
|
||||||
|
&CXPLAT_CHACHA20_POLY1305_ALG_HANDLE,
|
||||||
|
BCRYPT_CHACHA20_POLY1305_ALGORITHM,
|
||||||
|
MS_PRIMITIVE_PROVIDER,
|
||||||
|
BCRYPT_PROV_DISPATCH);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Open ChaCha20-Poly1305 algorithm");
|
||||||
|
//
|
||||||
|
// ChaCha20-Poly1305 may not be supported on older OSes, so don't treat
|
||||||
|
// this failure as fatal.
|
||||||
|
//
|
||||||
|
Status = QUIC_STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
Status =
|
||||||
|
BCryptSetProperty(
|
||||||
|
CXPLAT_CHACHA20_POLY1305_ALG_HANDLE,
|
||||||
|
BCRYPT_CHAINING_MODE,
|
||||||
|
(PBYTE)BCRYPT_CHAIN_MODE_NA,
|
||||||
|
sizeof(BCRYPT_CHAIN_MODE_NA),
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Set ChaCha20-Poly1305 chaining mode");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
if (CXPLAT_HMAC_SHA256_ALG_HANDLE) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_HMAC_SHA256_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_HMAC_SHA256_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
if (CXPLAT_HMAC_SHA384_ALG_HANDLE) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_HMAC_SHA384_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_HMAC_SHA384_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
if (CXPLAT_HMAC_SHA512_ALG_HANDLE) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_HMAC_SHA512_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_HMAC_SHA512_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
if (CXPLAT_AES_ECB_ALG_HANDLE) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_AES_ECB_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_AES_ECB_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
if (CXPLAT_AES_GCM_ALG_HANDLE) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_AES_GCM_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_AES_GCM_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
if (CXPLAT_CHACHA20_POLY1305_ALG_HANDLE) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_CHACHA20_POLY1305_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_CHACHA20_POLY1305_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
#else
|
||||||
|
NTSTATUS Status =
|
||||||
|
BCryptOpenAlgorithmProvider(
|
||||||
|
&CXPLAT_CHACHA20_POLY1305_ALG_HANDLE,
|
||||||
|
BCRYPT_CHACHA20_POLY1305_ALGORITHM,
|
||||||
|
MS_PRIMITIVE_PROVIDER,
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Open ChaCha20-Poly1305 algorithm");
|
||||||
|
//
|
||||||
|
// ChaCha20-Poly1305 may not be supported on older OSes, so don't treat
|
||||||
|
// this failure as fatal.
|
||||||
|
//
|
||||||
|
Status = QUIC_STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
Status =
|
||||||
|
BCryptSetProperty(
|
||||||
|
CXPLAT_CHACHA20_POLY1305_ALG_HANDLE,
|
||||||
|
BCRYPT_CHAINING_MODE,
|
||||||
|
(PBYTE)BCRYPT_CHAIN_MODE_NA,
|
||||||
|
sizeof(BCRYPT_CHAIN_MODE_NA),
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"Set ChaCha20-Poly1305 chaining mode");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
if (CXPLAT_CHACHA20_POLY1305_ALG_HANDLE) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_CHACHA20_POLY1305_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_CHACHA20_POLY1305_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CxPlatCryptUninitialize(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#ifdef _KERNEL_MODE
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_HMAC_SHA256_ALG_HANDLE, 0);
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_HMAC_SHA384_ALG_HANDLE, 0);
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_HMAC_SHA512_ALG_HANDLE, 0);
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_AES_ECB_ALG_HANDLE, 0);
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_AES_GCM_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_HMAC_SHA256_ALG_HANDLE = NULL;
|
||||||
|
CXPLAT_HMAC_SHA384_ALG_HANDLE = NULL;
|
||||||
|
CXPLAT_HMAC_SHA512_ALG_HANDLE = NULL;
|
||||||
|
CXPLAT_AES_ECB_ALG_HANDLE = NULL;
|
||||||
|
CXPLAT_AES_GCM_ALG_HANDLE = NULL;
|
||||||
|
#endif
|
||||||
|
if (CXPLAT_CHACHA20_POLY1305_ALG_HANDLE != NULL) {
|
||||||
|
BCryptCloseAlgorithmProvider(CXPLAT_CHACHA20_POLY1305_ALG_HANDLE, 0);
|
||||||
|
CXPLAT_CHACHA20_POLY1305_ALG_HANDLE = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatKeyCreate(
|
||||||
|
_In_ CXPLAT_AEAD_TYPE AeadType,
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_128_GCM, _In_reads_(16))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_256_GCM, _In_reads_(32))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_CHACHA20_POLY1305, _In_reads_(32))
|
||||||
|
const uint8_t* const RawKey,
|
||||||
|
_Out_ CXPLAT_KEY** NewKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint8_t KeyLength;
|
||||||
|
BCRYPT_ALG_HANDLE KeyAlgHandle;
|
||||||
|
|
||||||
|
switch (AeadType) {
|
||||||
|
case CXPLAT_AEAD_AES_128_GCM:
|
||||||
|
KeyLength = 16;
|
||||||
|
KeyAlgHandle = CXPLAT_AES_GCM_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_AES_256_GCM:
|
||||||
|
KeyLength = 32;
|
||||||
|
KeyAlgHandle = CXPLAT_AES_GCM_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_CHACHA20_POLY1305:
|
||||||
|
KeyLength = 32;
|
||||||
|
KeyAlgHandle = CXPLAT_CHACHA20_POLY1305_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return QUIC_STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS Status =
|
||||||
|
BCryptGenerateSymmetricKey(
|
||||||
|
KeyAlgHandle,
|
||||||
|
(BCRYPT_KEY_HANDLE*)NewKey,
|
||||||
|
NULL, // Let BCrypt manage the memory for this key.
|
||||||
|
0,
|
||||||
|
(uint8_t*)RawKey,
|
||||||
|
KeyLength,
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"BCryptGenerateSymmetricKey");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
CxPlatKeyFree(
|
||||||
|
_In_opt_ CXPLAT_KEY* Key
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Key) {
|
||||||
|
BCryptDestroyKey((BCRYPT_KEY_HANDLE)Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatEncrypt(
|
||||||
|
_In_ CXPLAT_KEY* _Key,
|
||||||
|
_In_reads_bytes_(CXPLAT_IV_LENGTH)
|
||||||
|
const uint8_t* const Iv,
|
||||||
|
_In_ uint16_t AuthDataLength,
|
||||||
|
_In_reads_bytes_opt_(AuthDataLength)
|
||||||
|
const uint8_t* const AuthData,
|
||||||
|
_In_ uint16_t BufferLength,
|
||||||
|
_When_(BufferLength > CXPLAT_ENCRYPTION_OVERHEAD, _Inout_updates_bytes_(BufferLength))
|
||||||
|
_When_(BufferLength <= CXPLAT_ENCRYPTION_OVERHEAD, _Out_writes_bytes_(BufferLength))
|
||||||
|
uint8_t* Buffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG CipherTextSize;
|
||||||
|
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO Info;
|
||||||
|
BCRYPT_KEY_HANDLE Key = (BCRYPT_KEY_HANDLE)_Key;
|
||||||
|
|
||||||
|
CXPLAT_DBG_ASSERT(CXPLAT_ENCRYPTION_OVERHEAD <= BufferLength);
|
||||||
|
|
||||||
|
#ifdef QUIC_FUZZER
|
||||||
|
if (MsQuicFuzzerContext.EncryptCallback) {
|
||||||
|
#pragma prefast(suppress: __WARNING_26000, "Auth Data and Buffer are always contiguous")
|
||||||
|
MsQuicFuzzerContext.EncryptCallback(
|
||||||
|
MsQuicFuzzerContext.CallbackContext,
|
||||||
|
(uint8_t*)AuthData,
|
||||||
|
AuthDataLength + BufferLength
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BCRYPT_INIT_AUTH_MODE_INFO(Info);
|
||||||
|
Info.pbAuthData = (uint8_t*)AuthData;
|
||||||
|
Info.cbAuthData = AuthDataLength;
|
||||||
|
Info.pbTag = Buffer + (BufferLength - CXPLAT_ENCRYPTION_OVERHEAD);
|
||||||
|
Info.cbTag = CXPLAT_ENCRYPTION_OVERHEAD;
|
||||||
|
Info.pbNonce = (uint8_t*)Iv;
|
||||||
|
Info.cbNonce = CXPLAT_IV_LENGTH;
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptEncrypt(
|
||||||
|
Key,
|
||||||
|
Buffer,
|
||||||
|
BufferLength - CXPLAT_ENCRYPTION_OVERHEAD,
|
||||||
|
&Info,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
Buffer,
|
||||||
|
BufferLength,
|
||||||
|
&CipherTextSize,
|
||||||
|
0);
|
||||||
|
|
||||||
|
CXPLAT_DBG_ASSERT(CipherTextSize == (ULONG)(BufferLength - CXPLAT_ENCRYPTION_OVERHEAD));
|
||||||
|
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatDecrypt(
|
||||||
|
_In_ CXPLAT_KEY* _Key,
|
||||||
|
_In_reads_bytes_(CXPLAT_IV_LENGTH)
|
||||||
|
const uint8_t* const Iv,
|
||||||
|
_In_ uint16_t AuthDataLength,
|
||||||
|
_In_reads_bytes_opt_(AuthDataLength)
|
||||||
|
const uint8_t* const AuthData,
|
||||||
|
_In_ uint16_t BufferLength,
|
||||||
|
_Inout_updates_bytes_(BufferLength)
|
||||||
|
uint8_t* Buffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG PlainTextSize;
|
||||||
|
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO Info;
|
||||||
|
BCRYPT_KEY_HANDLE Key = (BCRYPT_KEY_HANDLE)_Key;
|
||||||
|
|
||||||
|
CXPLAT_DBG_ASSERT(CXPLAT_ENCRYPTION_OVERHEAD <= BufferLength);
|
||||||
|
|
||||||
|
BCRYPT_INIT_AUTH_MODE_INFO(Info);
|
||||||
|
Info.pbAuthData = (uint8_t*)AuthData;
|
||||||
|
Info.cbAuthData = AuthDataLength;
|
||||||
|
Info.pbTag = Buffer + (BufferLength - CXPLAT_ENCRYPTION_OVERHEAD);
|
||||||
|
Info.cbTag = CXPLAT_ENCRYPTION_OVERHEAD;
|
||||||
|
Info.pbNonce = (uint8_t*)Iv;
|
||||||
|
Info.cbNonce = CXPLAT_IV_LENGTH;
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptDecrypt(
|
||||||
|
Key,
|
||||||
|
Buffer,
|
||||||
|
BufferLength - CXPLAT_ENCRYPTION_OVERHEAD,
|
||||||
|
&Info,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
Buffer,
|
||||||
|
BufferLength - CXPLAT_ENCRYPTION_OVERHEAD,
|
||||||
|
&PlainTextSize,
|
||||||
|
0);
|
||||||
|
|
||||||
|
CXPLAT_DBG_ASSERT(PlainTextSize == (ULONG)(BufferLength - CXPLAT_ENCRYPTION_OVERHEAD));
|
||||||
|
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHpKeyCreate(
|
||||||
|
_In_ CXPLAT_AEAD_TYPE AeadType,
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_128_GCM, _In_reads_(16))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_256_GCM, _In_reads_(32))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_CHACHA20_POLY1305, _In_reads_(32))
|
||||||
|
const uint8_t* const RawKey,
|
||||||
|
_Out_ CXPLAT_HP_KEY** NewKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BCRYPT_ALG_HANDLE AlgHandle;
|
||||||
|
CXPLAT_HP_KEY* Key = NULL;
|
||||||
|
uint32_t AllocLength;
|
||||||
|
uint8_t KeyLength;
|
||||||
|
|
||||||
|
switch (AeadType) {
|
||||||
|
case CXPLAT_AEAD_AES_128_GCM:
|
||||||
|
KeyLength = 16;
|
||||||
|
AllocLength = sizeof(CXPLAT_HP_KEY);
|
||||||
|
AlgHandle = CXPLAT_AES_ECB_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_AES_256_GCM:
|
||||||
|
KeyLength = 32;
|
||||||
|
AllocLength = sizeof(CXPLAT_HP_KEY);
|
||||||
|
AlgHandle = CXPLAT_AES_ECB_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_CHACHA20_POLY1305:
|
||||||
|
KeyLength = 32;
|
||||||
|
AllocLength =
|
||||||
|
sizeof(CXPLAT_HP_KEY) +
|
||||||
|
sizeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO) +
|
||||||
|
CXPLAT_ENCRYPTION_OVERHEAD;
|
||||||
|
AlgHandle = CXPLAT_CHACHA20_POLY1305_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return QUIC_STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key = CXPLAT_ALLOC_NONPAGED(AllocLength, QUIC_POOL_TLS_HP_KEY);
|
||||||
|
if (Key == NULL) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
AllocFailure,
|
||||||
|
"Allocation of '%s' failed. (%llu bytes)",
|
||||||
|
"CXPLAT_HP_KEY",
|
||||||
|
AllocLength);
|
||||||
|
return QUIC_STATUS_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key->Aead = AeadType;
|
||||||
|
|
||||||
|
NTSTATUS Status =
|
||||||
|
BCryptGenerateSymmetricKey(
|
||||||
|
AlgHandle,
|
||||||
|
&Key->Key,
|
||||||
|
NULL, // Let BCrypt manage the memory for this key.
|
||||||
|
0,
|
||||||
|
(uint8_t*)RawKey,
|
||||||
|
KeyLength,
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
(AeadType == CXPLAT_AEAD_CHACHA20_POLY1305) ?
|
||||||
|
"BCryptGenerateSymmetricKey (ChaCha)" :
|
||||||
|
"BCryptGenerateSymmetricKey (ECB)");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AeadType == CXPLAT_AEAD_CHACHA20_POLY1305) {
|
||||||
|
BCRYPT_INIT_AUTH_MODE_INFO(*Key->Info);
|
||||||
|
Key->Info->pbTag = (uint8_t*)(Key->Info + 1);
|
||||||
|
Key->Info->cbTag = CXPLAT_ENCRYPTION_OVERHEAD;
|
||||||
|
Key->Info->pbAuthData = NULL;
|
||||||
|
Key->Info->cbAuthData = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*NewKey = Key;
|
||||||
|
Key = NULL;
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
if (Key) {
|
||||||
|
CXPLAT_FREE(Key, QUIC_POOL_TLS_HP_KEY);
|
||||||
|
Key = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
CxPlatHpKeyFree(
|
||||||
|
_In_opt_ CXPLAT_HP_KEY* Key
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Key) {
|
||||||
|
BCryptDestroyKey(Key->Key);
|
||||||
|
if (Key->Aead == CXPLAT_AEAD_CHACHA20_POLY1305) {
|
||||||
|
CxPlatSecureZeroMemory(Key->Info, sizeof(*Key->Info) + CXPLAT_ENCRYPTION_OVERHEAD);
|
||||||
|
}
|
||||||
|
CXPLAT_FREE(Key, QUIC_POOL_TLS_HP_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHpComputeMask(
|
||||||
|
_In_ CXPLAT_HP_KEY* Key,
|
||||||
|
_In_ uint8_t BatchSize,
|
||||||
|
_In_reads_bytes_(CXPLAT_HP_SAMPLE_LENGTH * BatchSize)
|
||||||
|
const uint8_t* const Cipher,
|
||||||
|
_Out_writes_bytes_(CXPLAT_HP_SAMPLE_LENGTH * BatchSize)
|
||||||
|
uint8_t* Mask
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ULONG TempSize = 0;
|
||||||
|
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
|
||||||
|
if (Key->Aead == CXPLAT_AEAD_CHACHA20_POLY1305) {
|
||||||
|
//
|
||||||
|
// This doesn't work because it needs to set the counter value
|
||||||
|
// and BCrypt doesn't support that.
|
||||||
|
//
|
||||||
|
uint8_t Zero[5] = { 0, 0, 0, 0, 0 };
|
||||||
|
Key->Info->cbNonce = CXPLAT_HP_SAMPLE_LENGTH;
|
||||||
|
for (uint32_t i = 0, Offset = 0; i < BatchSize; ++i, Offset += CXPLAT_HP_SAMPLE_LENGTH) {
|
||||||
|
Key->Info->pbNonce = (uint8_t*)(Cipher + Offset);
|
||||||
|
Status =
|
||||||
|
NtStatusToQuicStatus(
|
||||||
|
BCryptEncrypt(
|
||||||
|
Key->Key,
|
||||||
|
Zero,
|
||||||
|
sizeof(Zero),
|
||||||
|
Key->Info,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
Mask + Offset,
|
||||||
|
CXPLAT_HP_SAMPLE_LENGTH, // This will fail because the Tag won't fit
|
||||||
|
&TempSize,
|
||||||
|
0));
|
||||||
|
if (QUIC_FAILED(Status)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Status =
|
||||||
|
NtStatusToQuicStatus(
|
||||||
|
BCryptEncrypt(
|
||||||
|
Key->Key,
|
||||||
|
(uint8_t*)Cipher,
|
||||||
|
CXPLAT_HP_SAMPLE_LENGTH * BatchSize,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
Mask,
|
||||||
|
CXPLAT_HP_SAMPLE_LENGTH * BatchSize,
|
||||||
|
&TempSize,
|
||||||
|
0));
|
||||||
|
}
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHashCreate(
|
||||||
|
_In_ CXPLAT_HASH_TYPE HashType,
|
||||||
|
_In_reads_(SaltLength)
|
||||||
|
const uint8_t* const Salt,
|
||||||
|
_In_ uint32_t SaltLength,
|
||||||
|
_Out_ CXPLAT_HASH** Hash
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BCRYPT_ALG_HANDLE HashAlgHandle;
|
||||||
|
|
||||||
|
switch (HashType) {
|
||||||
|
case CXPLAT_HASH_SHA256:
|
||||||
|
HashAlgHandle = CXPLAT_HMAC_SHA256_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
case CXPLAT_HASH_SHA384:
|
||||||
|
HashAlgHandle = CXPLAT_HMAC_SHA384_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
case CXPLAT_HASH_SHA512:
|
||||||
|
HashAlgHandle = CXPLAT_HMAC_SHA512_ALG_HANDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return QUIC_STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS Status =
|
||||||
|
BCryptCreateHash(
|
||||||
|
HashAlgHandle,
|
||||||
|
(BCRYPT_HASH_HANDLE*)Hash,
|
||||||
|
NULL, // Let BCrypt manage the memory for this hash object.
|
||||||
|
0,
|
||||||
|
(uint8_t*)Salt,
|
||||||
|
(ULONG)SaltLength,
|
||||||
|
BCRYPT_HASH_REUSABLE_FLAG);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"BCryptCreateHash");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
CxPlatHashFree(
|
||||||
|
_In_opt_ CXPLAT_HASH* Hash
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Hash) {
|
||||||
|
BCryptDestroyHash((BCRYPT_HASH_HANDLE)Hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHashCompute(
|
||||||
|
_In_ CXPLAT_HASH* Hash,
|
||||||
|
_In_reads_(InputLength)
|
||||||
|
const uint8_t* const Input,
|
||||||
|
_In_ uint32_t InputLength,
|
||||||
|
_In_ uint32_t OutputLength,
|
||||||
|
_Out_writes_all_(OutputLength)
|
||||||
|
uint8_t* const Output
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BCRYPT_HASH_HANDLE HashHandle = (BCRYPT_HASH_HANDLE)Hash;
|
||||||
|
|
||||||
|
NTSTATUS Status =
|
||||||
|
BCryptHashData(
|
||||||
|
HashHandle,
|
||||||
|
(uint8_t*)Input,
|
||||||
|
InputLength,
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"BCryptHashData");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status =
|
||||||
|
BCryptFinishHash(
|
||||||
|
HashHandle,
|
||||||
|
Output,
|
||||||
|
OutputLength,
|
||||||
|
0);
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
Status,
|
||||||
|
"BCryptFinishHash");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
|
||||||
|
return NtStatusToQuicStatus(Status);
|
||||||
|
}
|
|
@ -0,0 +1,537 @@
|
||||||
|
/*++
|
||||||
|
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
Licensed under the MIT License.
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Implements the cryptographic functions by calling OpenSSL.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#include "platform_internal.h"
|
||||||
|
|
||||||
|
#define OPENSSL_SUPPRESS_DEPRECATED 1 // For hmac.h, which was deprecated in 3.0
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4100) // Unreferenced parameter errcode in inline function
|
||||||
|
#endif
|
||||||
|
#include "openssl/bio.h"
|
||||||
|
#include "openssl/err.h"
|
||||||
|
#include "openssl/hmac.h"
|
||||||
|
#include "openssl/kdf.h"
|
||||||
|
#include "openssl/pem.h"
|
||||||
|
#include "openssl/pkcs12.h"
|
||||||
|
#include "openssl/pkcs7.h"
|
||||||
|
#include "openssl/rsa.h"
|
||||||
|
#include "openssl/ssl.h"
|
||||||
|
#include "openssl/x509.h"
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
#ifdef QUIC_CLOG
|
||||||
|
#include "crypt_openssl.c.clog.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct CXPLAT_HP_KEY {
|
||||||
|
EVP_CIPHER_CTX* CipherCtx;
|
||||||
|
CXPLAT_AEAD_TYPE Aead;
|
||||||
|
} CXPLAT_HP_KEY;
|
||||||
|
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatCryptInitialize(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"OPENSSL_init_ssl failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// OPENSSL_init_ssl() may leave errors in the error queue while returning
|
||||||
|
// success.
|
||||||
|
//
|
||||||
|
|
||||||
|
ERR_clear_error();
|
||||||
|
|
||||||
|
//
|
||||||
|
// LINUX_TODO:Add Check for openssl library QUIC support.
|
||||||
|
//
|
||||||
|
|
||||||
|
return QUIC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CxPlatCryptUninitialize(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatKeyCreate(
|
||||||
|
_In_ CXPLAT_AEAD_TYPE AeadType,
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_128_GCM, _In_reads_(16))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_256_GCM, _In_reads_(32))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_CHACHA20_POLY1305, _In_reads_(32))
|
||||||
|
const uint8_t* const RawKey,
|
||||||
|
_Out_ CXPLAT_KEY** NewKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
|
||||||
|
const EVP_CIPHER *Aead;
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX* CipherCtx = EVP_CIPHER_CTX_new();
|
||||||
|
if (CipherCtx == NULL) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_CIPHER_CTX_new failed");
|
||||||
|
Status = QUIC_STATUS_OUT_OF_MEMORY;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (AeadType) {
|
||||||
|
case CXPLAT_AEAD_AES_128_GCM:
|
||||||
|
Aead = EVP_aes_128_gcm();
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_AES_256_GCM:
|
||||||
|
Aead = EVP_aes_256_gcm();
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_CHACHA20_POLY1305:
|
||||||
|
Aead = EVP_chacha20_poly1305();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Status = QUIC_STATUS_NOT_SUPPORTED;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_CipherInit_ex(CipherCtx, Aead, NULL, RawKey, NULL, 1) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_CipherInit_ex failed");
|
||||||
|
Status = QUIC_STATUS_TLS_ERROR;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(CipherCtx, EVP_CTRL_AEAD_SET_IVLEN, CXPLAT_IV_LENGTH, NULL) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
ERR_get_error(),
|
||||||
|
"EVP_CIPHER_CTX_ctrl (SET_IVLEN) failed");
|
||||||
|
Status = QUIC_STATUS_TLS_ERROR;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
*NewKey = (CXPLAT_KEY*)CipherCtx;
|
||||||
|
CipherCtx = NULL;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
|
||||||
|
CxPlatKeyFree((CXPLAT_KEY*)CipherCtx);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
CxPlatKeyFree(
|
||||||
|
_In_opt_ CXPLAT_KEY* Key
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatEncrypt(
|
||||||
|
_In_ CXPLAT_KEY* Key,
|
||||||
|
_In_reads_bytes_(CXPLAT_IV_LENGTH)
|
||||||
|
const uint8_t* const Iv,
|
||||||
|
_In_ uint16_t AuthDataLength,
|
||||||
|
_In_reads_bytes_opt_(AuthDataLength)
|
||||||
|
const uint8_t* const AuthData,
|
||||||
|
_In_ uint16_t BufferLength,
|
||||||
|
_When_(BufferLength > CXPLAT_ENCRYPTION_OVERHEAD, _Inout_updates_bytes_(BufferLength))
|
||||||
|
_When_(BufferLength <= CXPLAT_ENCRYPTION_OVERHEAD, _Out_writes_bytes_(BufferLength))
|
||||||
|
uint8_t* Buffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CXPLAT_DBG_ASSERT(CXPLAT_ENCRYPTION_OVERHEAD <= BufferLength);
|
||||||
|
|
||||||
|
const uint16_t PlainTextLength = BufferLength - CXPLAT_ENCRYPTION_OVERHEAD;
|
||||||
|
uint8_t *Tag = Buffer + PlainTextLength;
|
||||||
|
int OutLen;
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX* CipherCtx = (EVP_CIPHER_CTX*)Key;
|
||||||
|
|
||||||
|
if (EVP_EncryptInit_ex(CipherCtx, NULL, NULL, NULL, Iv) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptInit_ex failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AuthData != NULL &&
|
||||||
|
EVP_EncryptUpdate(CipherCtx, NULL, &OutLen, AuthData, (int)AuthDataLength) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptUpdate (AD) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_EncryptUpdate(CipherCtx, Buffer, &OutLen, Buffer, (int)PlainTextLength) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptUpdate (Cipher) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_EncryptFinal_ex(CipherCtx, Tag, &OutLen) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptFinal_ex failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(CipherCtx, EVP_CTRL_AEAD_GET_TAG, CXPLAT_ENCRYPTION_OVERHEAD, Tag) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_CIPHER_CTX_ctrl (GET_TAG) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QUIC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatDecrypt(
|
||||||
|
_In_ CXPLAT_KEY* Key,
|
||||||
|
_In_reads_bytes_(CXPLAT_IV_LENGTH)
|
||||||
|
const uint8_t* const Iv,
|
||||||
|
_In_ uint16_t AuthDataLength,
|
||||||
|
_In_reads_bytes_opt_(AuthDataLength)
|
||||||
|
const uint8_t* const AuthData,
|
||||||
|
_In_ uint16_t BufferLength,
|
||||||
|
_Inout_updates_bytes_(BufferLength)
|
||||||
|
uint8_t* Buffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CXPLAT_DBG_ASSERT(CXPLAT_ENCRYPTION_OVERHEAD <= BufferLength);
|
||||||
|
|
||||||
|
const uint16_t CipherTextLength = BufferLength - CXPLAT_ENCRYPTION_OVERHEAD;
|
||||||
|
uint8_t *Tag = Buffer + CipherTextLength;
|
||||||
|
int OutLen;
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX* CipherCtx = (EVP_CIPHER_CTX*)Key;
|
||||||
|
|
||||||
|
if (EVP_DecryptInit_ex(CipherCtx, NULL, NULL, NULL, Iv) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
ERR_get_error(),
|
||||||
|
"EVP_DecryptInit_ex failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AuthData != NULL &&
|
||||||
|
EVP_DecryptUpdate(CipherCtx, NULL, &OutLen, AuthData, (int)AuthDataLength) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
ERR_get_error(),
|
||||||
|
"EVP_DecryptUpdate (AD) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_DecryptUpdate(CipherCtx, Buffer, &OutLen, Buffer, (int)CipherTextLength) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
ERR_get_error(),
|
||||||
|
"EVP_DecryptUpdate (Cipher) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(CipherCtx, EVP_CTRL_AEAD_SET_TAG, CXPLAT_ENCRYPTION_OVERHEAD, Tag) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
ERR_get_error(),
|
||||||
|
"EVP_CIPHER_CTX_ctrl (SET_TAG) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_DecryptFinal_ex(CipherCtx, Tag, &OutLen) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryErrorStatus,
|
||||||
|
"[ lib] ERROR, %u, %s.",
|
||||||
|
ERR_get_error(),
|
||||||
|
"EVP_DecryptFinal_ex failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QUIC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHpKeyCreate(
|
||||||
|
_In_ CXPLAT_AEAD_TYPE AeadType,
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_128_GCM, _In_reads_(16))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_AES_256_GCM, _In_reads_(32))
|
||||||
|
_When_(AeadType == CXPLAT_AEAD_CHACHA20_POLY1305, _In_reads_(32))
|
||||||
|
const uint8_t* const RawKey,
|
||||||
|
_Out_ CXPLAT_HP_KEY** NewKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
|
||||||
|
const EVP_CIPHER *Aead;
|
||||||
|
CXPLAT_HP_KEY* Key = CXPLAT_ALLOC_NONPAGED(sizeof(CXPLAT_HP_KEY), QUIC_POOL_TLS_HP_KEY);
|
||||||
|
if (Key == NULL) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
AllocFailure,
|
||||||
|
"Allocation of '%s' failed. (%llu bytes)",
|
||||||
|
"CXPLAT_HP_KEY",
|
||||||
|
sizeof(CXPLAT_HP_KEY));
|
||||||
|
return QUIC_STATUS_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key->Aead = AeadType;
|
||||||
|
|
||||||
|
Key->CipherCtx = EVP_CIPHER_CTX_new();
|
||||||
|
if (Key->CipherCtx == NULL) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"Cipherctx alloc failed");
|
||||||
|
Status = QUIC_STATUS_OUT_OF_MEMORY;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (AeadType) {
|
||||||
|
case CXPLAT_AEAD_AES_128_GCM:
|
||||||
|
Aead = EVP_aes_128_ecb();
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_AES_256_GCM:
|
||||||
|
Aead = EVP_aes_256_ecb();
|
||||||
|
break;
|
||||||
|
case CXPLAT_AEAD_CHACHA20_POLY1305:
|
||||||
|
Aead = EVP_chacha20();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Status = QUIC_STATUS_NOT_SUPPORTED;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_EncryptInit_ex(Key->CipherCtx, Aead, NULL, RawKey, NULL) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptInit_ex failed");
|
||||||
|
Status = QUIC_STATUS_TLS_ERROR;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
*NewKey = Key;
|
||||||
|
Key = NULL;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
|
||||||
|
CxPlatHpKeyFree(Key);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
CxPlatHpKeyFree(
|
||||||
|
_In_opt_ CXPLAT_HP_KEY* Key
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (Key != NULL) {
|
||||||
|
EVP_CIPHER_CTX_free(Key->CipherCtx);
|
||||||
|
CXPLAT_FREE(Key, QUIC_POOL_TLS_HP_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHpComputeMask(
|
||||||
|
_In_ CXPLAT_HP_KEY* Key,
|
||||||
|
_In_ uint8_t BatchSize,
|
||||||
|
_In_reads_bytes_(CXPLAT_HP_SAMPLE_LENGTH* BatchSize)
|
||||||
|
const uint8_t* const Cipher,
|
||||||
|
_Out_writes_bytes_(CXPLAT_HP_SAMPLE_LENGTH* BatchSize)
|
||||||
|
uint8_t* Mask
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int OutLen = 0;
|
||||||
|
if (Key->Aead == CXPLAT_AEAD_CHACHA20_POLY1305) {
|
||||||
|
static const uint8_t Zero[] = { 0, 0, 0, 0, 0 };
|
||||||
|
for (uint32_t i = 0, Offset = 0; i < BatchSize; ++i, Offset += CXPLAT_HP_SAMPLE_LENGTH) {
|
||||||
|
if (EVP_EncryptInit_ex(Key->CipherCtx, NULL, NULL, NULL, Cipher + Offset) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptInit_ex (hp) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
if (EVP_EncryptUpdate(Key->CipherCtx, Mask + Offset, &OutLen, Zero, sizeof(Zero)) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptUpdate (hp) failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (EVP_EncryptUpdate(Key->CipherCtx, Mask, &OutLen, Cipher, CXPLAT_HP_SAMPLE_LENGTH * BatchSize) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"EVP_EncryptUpdate failed");
|
||||||
|
return QUIC_STATUS_TLS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QUIC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hash abstraction
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef struct CXPLAT_HASH {
|
||||||
|
//
|
||||||
|
// The message digest.
|
||||||
|
//
|
||||||
|
const EVP_MD *Md;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Context used for hashing.
|
||||||
|
//
|
||||||
|
HMAC_CTX* HashContext;
|
||||||
|
|
||||||
|
} CXPLAT_HASH;
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHashCreate(
|
||||||
|
_In_ CXPLAT_HASH_TYPE HashType,
|
||||||
|
_In_reads_(SaltLength)
|
||||||
|
const uint8_t* const Salt,
|
||||||
|
_In_ uint32_t SaltLength,
|
||||||
|
_Out_ CXPLAT_HASH** NewHash
|
||||||
|
)
|
||||||
|
{
|
||||||
|
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
|
||||||
|
const EVP_MD *Md;
|
||||||
|
|
||||||
|
HMAC_CTX* HashContext = HMAC_CTX_new();
|
||||||
|
if (HashContext == NULL) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"HMAC_CTX_new failed");
|
||||||
|
Status = QUIC_STATUS_OUT_OF_MEMORY;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (HashType) {
|
||||||
|
case CXPLAT_HASH_SHA256:
|
||||||
|
Md = EVP_sha256();
|
||||||
|
break;
|
||||||
|
case CXPLAT_HASH_SHA384:
|
||||||
|
Md = EVP_sha384();
|
||||||
|
break;
|
||||||
|
case CXPLAT_HASH_SHA512:
|
||||||
|
Md = EVP_sha512();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Status = QUIC_STATUS_NOT_SUPPORTED;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HMAC_Init_ex(HashContext, Salt, SaltLength, Md, NULL) != 1) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"HMAC_Init_ex failed");
|
||||||
|
Status = QUIC_STATUS_TLS_ERROR;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
*NewHash = (CXPLAT_HASH*)HashContext;
|
||||||
|
HashContext = NULL;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
|
||||||
|
CxPlatHashFree((CXPLAT_HASH*)HashContext);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
void
|
||||||
|
CxPlatHashFree(
|
||||||
|
_In_opt_ CXPLAT_HASH* Hash
|
||||||
|
)
|
||||||
|
{
|
||||||
|
HMAC_CTX_free((HMAC_CTX*)Hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||||
|
QUIC_STATUS
|
||||||
|
CxPlatHashCompute(
|
||||||
|
_In_ CXPLAT_HASH* Hash,
|
||||||
|
_In_reads_(InputLength)
|
||||||
|
const uint8_t* const Input,
|
||||||
|
_In_ uint32_t InputLength,
|
||||||
|
_In_ uint32_t OutputLength, // CxPlatHashLength(HashType)
|
||||||
|
_Out_writes_all_(OutputLength)
|
||||||
|
uint8_t* const Output
|
||||||
|
)
|
||||||
|
{
|
||||||
|
HMAC_CTX* HashContext = (HMAC_CTX*)Hash;
|
||||||
|
|
||||||
|
if (!HMAC_Init_ex(HashContext, NULL, 0, NULL, NULL)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"HMAC_Init_ex(NULL) failed");
|
||||||
|
return QUIC_STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HMAC_Update(HashContext, Input, InputLength)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"HMAC_Update failed");
|
||||||
|
return QUIC_STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ActualOutputSize = OutputLength;
|
||||||
|
if (!HMAC_Final(HashContext, Output, &ActualOutputSize)) {
|
||||||
|
QuicTraceEvent(
|
||||||
|
LibraryError,
|
||||||
|
"[ lib] ERROR, %s.",
|
||||||
|
"HMAC_Final failed");
|
||||||
|
return QUIC_STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
CXPLAT_FRE_ASSERT(ActualOutputSize == OutputLength);
|
||||||
|
return QUIC_STATUS_SUCCESS;
|
||||||
|
}
|
|
@ -35,6 +35,8 @@
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="crypt.c" />
|
||||||
|
<ClCompile Include="crypt_bcrypt.c" />
|
||||||
<ClCompile Include="datapath_winkernel.c" />
|
<ClCompile Include="datapath_winkernel.c" />
|
||||||
<ClCompile Include="hashtable.c" />
|
<ClCompile Include="hashtable.c" />
|
||||||
<ClCompile Include="pcp.c" />
|
<ClCompile Include="pcp.c" />
|
||||||
|
|
|
@ -213,15 +213,15 @@ CxPlatConvertFromMappedV6(
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// TLS Initialization
|
// Crypt Initialization
|
||||||
//
|
//
|
||||||
|
|
||||||
QUIC_STATUS
|
QUIC_STATUS
|
||||||
CxPlatTlsLibraryInitialize(
|
CxPlatCryptInitialize(
|
||||||
void
|
void
|
||||||
);
|
);
|
||||||
|
|
||||||
void
|
void
|
||||||
CxPlatTlsLibraryUninitialize(
|
CxPlatCryptUninitialize(
|
||||||
void
|
void
|
||||||
);
|
);
|
||||||
|
|
|
@ -146,13 +146,13 @@ CxPlatInitialize(
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = CxPlatTlsLibraryInitialize();
|
Status = CxPlatCryptInitialize();
|
||||||
if (QUIC_FAILED(Status)) {
|
if (QUIC_FAILED(Status)) {
|
||||||
QuicTraceEvent(
|
QuicTraceEvent(
|
||||||
LibraryErrorStatus,
|
LibraryErrorStatus,
|
||||||
"[ lib] ERROR, %u, %s.",
|
"[ lib] ERROR, %u, %s.",
|
||||||
Status,
|
Status,
|
||||||
"CxPlatTlsLibraryInitialize");
|
"CxPlatCryptInitialize");
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ CxPlatUninitialize(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
CxPlatTlsLibraryUninitialize();
|
CxPlatCryptUninitialize();
|
||||||
BCryptCloseAlgorithmProvider(CxPlatform.RngAlgorithm, 0);
|
BCryptCloseAlgorithmProvider(CxPlatform.RngAlgorithm, 0);
|
||||||
CxPlatform.RngAlgorithm = NULL;
|
CxPlatform.RngAlgorithm = NULL;
|
||||||
QuicTraceLogInfo(
|
QuicTraceLogInfo(
|
||||||
|
|
|
@ -309,7 +309,7 @@ CxPlatInitialize(
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = CxPlatTlsLibraryInitialize();
|
Status = CxPlatCryptInitialize();
|
||||||
if (QUIC_FAILED(Status)) {
|
if (QUIC_FAILED(Status)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ CxPlatUninitialize(
|
||||||
void
|
void
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
CxPlatTlsLibraryUninitialize();
|
CxPlatCryptUninitialize();
|
||||||
CXPLAT_DBG_ASSERT(CxPlatform.Heap);
|
CXPLAT_DBG_ASSERT(CxPlatform.Heap);
|
||||||
CXPLAT_FREE(CxPlatNumaMasks, QUIC_POOL_PLATFORM_PROC);
|
CXPLAT_FREE(CxPlatNumaMasks, QUIC_POOL_PLATFORM_PROC);
|
||||||
CxPlatNumaMasks = NULL;
|
CxPlatNumaMasks = NULL;
|
||||||
|
|
|
@ -132,11 +132,6 @@ typedef struct CXPLAT_TLS {
|
||||||
|
|
||||||
} CXPLAT_TLS;
|
} CXPLAT_TLS;
|
||||||
|
|
||||||
typedef struct CXPLAT_HP_KEY {
|
|
||||||
EVP_CIPHER_CTX* CipherCtx;
|
|
||||||
CXPLAT_AEAD_TYPE Aead;
|
|
||||||
} CXPLAT_HP_KEY;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Default list of Cipher used.
|
// Default list of Cipher used.
|
||||||
//
|
//
|
||||||
|
@ -156,40 +151,6 @@ typedef struct CXPLAT_HP_KEY {
|
||||||
//
|
//
|
||||||
#define CXPLAT_TLS_DEFAULT_VERIFY_DEPTH 10
|
#define CXPLAT_TLS_DEFAULT_VERIFY_DEPTH 10
|
||||||
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatTlsLibraryInitialize(
|
|
||||||
void
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"OPENSSL_init_ssl failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// OPENSSL_init_ssl() may leave errors in the error queue while returning
|
|
||||||
// success.
|
|
||||||
//
|
|
||||||
|
|
||||||
ERR_clear_error();
|
|
||||||
|
|
||||||
//
|
|
||||||
// LINUX_TODO:Add Check for openssl library QUIC support.
|
|
||||||
//
|
|
||||||
|
|
||||||
return QUIC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CxPlatTlsLibraryUninitialize(
|
|
||||||
void
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
CxPlatTlsAlpnSelectCallback(
|
CxPlatTlsAlpnSelectCallback(
|
||||||
|
@ -2061,924 +2022,3 @@ CxPlatTlsParamGet(
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Crypto / Key Functionality
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
void
|
|
||||||
CxPlatTlsLogSecret(
|
|
||||||
_In_z_ const char* const Prefix,
|
|
||||||
_In_reads_(Length)
|
|
||||||
const uint8_t* const Secret,
|
|
||||||
_In_ uint32_t Length
|
|
||||||
)
|
|
||||||
{
|
|
||||||
#define HEX_TO_CHAR(x) ((x) > 9 ? ('a' + ((x) - 10)) : '0' + (x))
|
|
||||||
char SecretStr[256 + 1] = {0};
|
|
||||||
CXPLAT_DBG_ASSERT(Length * 2 < sizeof(SecretStr));
|
|
||||||
for (uint32_t i = 0; i < Length; i++) {
|
|
||||||
SecretStr[i*2] = HEX_TO_CHAR(Secret[i] >> 4);
|
|
||||||
SecretStr[i*2 + 1] = HEX_TO_CHAR(Secret[i] & 0xf);
|
|
||||||
}
|
|
||||||
QuicTraceLogVerbose(
|
|
||||||
OpenSslLogSecret,
|
|
||||||
"[ tls] %s[%u]: %s",
|
|
||||||
Prefix,
|
|
||||||
Length,
|
|
||||||
SecretStr);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define CxPlatTlsLogSecret(Prefix, Secret, Length) UNREFERENCED_PARAMETER(Prefix);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
void
|
|
||||||
CxPlatHkdfFormatLabel(
|
|
||||||
_In_z_ const char* const Label,
|
|
||||||
_In_ uint16_t HashLength,
|
|
||||||
_Out_writes_all_(5 + CXPLAT_HKDF_PREFIX_LEN + strlen(Label))
|
|
||||||
uint8_t* const Data,
|
|
||||||
_Inout_ uint32_t* const DataLength
|
|
||||||
)
|
|
||||||
{
|
|
||||||
CXPLAT_DBG_ASSERT(strlen(Label) <= UINT8_MAX - CXPLAT_HKDF_PREFIX_LEN);
|
|
||||||
uint8_t LabelLength = (uint8_t)strlen(Label);
|
|
||||||
|
|
||||||
Data[0] = HashLength >> 8;
|
|
||||||
Data[1] = HashLength & 0xff;
|
|
||||||
Data[2] = CXPLAT_HKDF_PREFIX_LEN + LabelLength;
|
|
||||||
memcpy(Data + 3, CXPLAT_HKDF_PREFIX, CXPLAT_HKDF_PREFIX_LEN);
|
|
||||||
memcpy(Data + 3 + CXPLAT_HKDF_PREFIX_LEN, Label, LabelLength);
|
|
||||||
Data[3 + CXPLAT_HKDF_PREFIX_LEN + LabelLength] = 0;
|
|
||||||
*DataLength = 3 + CXPLAT_HKDF_PREFIX_LEN + LabelLength + 1;
|
|
||||||
|
|
||||||
Data[*DataLength] = 0x1;
|
|
||||||
*DataLength += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatHkdfExpandLabel(
|
|
||||||
_In_ CXPLAT_HASH* Hash,
|
|
||||||
_In_z_ const char* const Label,
|
|
||||||
_In_ uint16_t KeyLength,
|
|
||||||
_In_ uint32_t OutputLength, // Writes CxPlatHashLength(HashType) bytes.
|
|
||||||
_Out_writes_all_(OutputLength)
|
|
||||||
uint8_t* const Output
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uint8_t LabelBuffer[64];
|
|
||||||
uint32_t LabelLength = sizeof(LabelBuffer);
|
|
||||||
|
|
||||||
_Analysis_assume_(strlen(Label) <= 23);
|
|
||||||
CxPlatHkdfFormatLabel(Label, KeyLength, LabelBuffer, &LabelLength);
|
|
||||||
|
|
||||||
return
|
|
||||||
CxPlatHashCompute(
|
|
||||||
Hash,
|
|
||||||
LabelBuffer,
|
|
||||||
LabelLength,
|
|
||||||
OutputLength,
|
|
||||||
Output);
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatTlsDeriveInitialSecrets(
|
|
||||||
_In_reads_(CXPLAT_VERSION_SALT_LENGTH)
|
|
||||||
const uint8_t* const Salt,
|
|
||||||
_In_reads_(CIDLength)
|
|
||||||
const uint8_t* const CID,
|
|
||||||
_In_ uint8_t CIDLength,
|
|
||||||
_Out_ CXPLAT_SECRET *ClientInitial,
|
|
||||||
_Out_ CXPLAT_SECRET *ServerInitial
|
|
||||||
)
|
|
||||||
{
|
|
||||||
QUIC_STATUS Status;
|
|
||||||
CXPLAT_HASH* InitialHash = NULL;
|
|
||||||
CXPLAT_HASH* DerivedHash = NULL;
|
|
||||||
uint8_t InitialSecret[CXPLAT_HASH_SHA256_SIZE];
|
|
||||||
|
|
||||||
CxPlatTlsLogSecret("init cid", CID, CIDLength);
|
|
||||||
|
|
||||||
Status =
|
|
||||||
CxPlatHashCreate(
|
|
||||||
CXPLAT_HASH_SHA256,
|
|
||||||
Salt,
|
|
||||||
CXPLAT_VERSION_SALT_LENGTH,
|
|
||||||
&InitialHash);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Extract secret for client and server secret expansion.
|
|
||||||
//
|
|
||||||
Status =
|
|
||||||
CxPlatHashCompute(
|
|
||||||
InitialHash,
|
|
||||||
CID,
|
|
||||||
CIDLength,
|
|
||||||
sizeof(InitialSecret),
|
|
||||||
InitialSecret);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
CxPlatTlsLogSecret("init secret", InitialSecret, sizeof(InitialSecret));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Create hash for client and server secret expansion.
|
|
||||||
//
|
|
||||||
Status =
|
|
||||||
CxPlatHashCreate(
|
|
||||||
CXPLAT_HASH_SHA256,
|
|
||||||
InitialSecret,
|
|
||||||
sizeof(InitialSecret),
|
|
||||||
&DerivedHash);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Expand client secret.
|
|
||||||
//
|
|
||||||
ClientInitial->Hash = CXPLAT_HASH_SHA256;
|
|
||||||
ClientInitial->Aead = CXPLAT_AEAD_AES_128_GCM;
|
|
||||||
Status =
|
|
||||||
CxPlatHkdfExpandLabel(
|
|
||||||
DerivedHash,
|
|
||||||
"client in",
|
|
||||||
sizeof(InitialSecret),
|
|
||||||
CXPLAT_HASH_SHA256_SIZE,
|
|
||||||
ClientInitial->Secret);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Expand server secret.
|
|
||||||
//
|
|
||||||
ServerInitial->Hash = CXPLAT_HASH_SHA256;
|
|
||||||
ServerInitial->Aead = CXPLAT_AEAD_AES_128_GCM;
|
|
||||||
Status =
|
|
||||||
CxPlatHkdfExpandLabel(
|
|
||||||
DerivedHash,
|
|
||||||
"server in",
|
|
||||||
sizeof(InitialSecret),
|
|
||||||
CXPLAT_HASH_SHA256_SIZE,
|
|
||||||
ServerInitial->Secret);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error:
|
|
||||||
|
|
||||||
CxPlatHashFree(InitialHash);
|
|
||||||
CxPlatHashFree(DerivedHash);
|
|
||||||
|
|
||||||
CxPlatSecureZeroMemory(InitialSecret, sizeof(InitialSecret));
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
QuicPacketKeyDerive(
|
|
||||||
_In_ QUIC_PACKET_KEY_TYPE KeyType,
|
|
||||||
_In_ const CXPLAT_SECRET* const Secret,
|
|
||||||
_In_z_ const char* const SecretName,
|
|
||||||
_In_ BOOLEAN CreateHpKey,
|
|
||||||
_Out_ QUIC_PACKET_KEY **NewKey
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const uint16_t SecretLength = CxPlatHashLength(Secret->Hash);
|
|
||||||
const uint16_t KeyLength = CxPlatKeyLength(Secret->Aead);
|
|
||||||
|
|
||||||
CXPLAT_DBG_ASSERT(SecretLength >= KeyLength);
|
|
||||||
CXPLAT_DBG_ASSERT(SecretLength >= CXPLAT_IV_LENGTH);
|
|
||||||
CXPLAT_DBG_ASSERT(SecretLength <= CXPLAT_HASH_MAX_SIZE);
|
|
||||||
|
|
||||||
CxPlatTlsLogSecret(SecretName, Secret->Secret, SecretLength);
|
|
||||||
|
|
||||||
const uint16_t PacketKeyLength =
|
|
||||||
sizeof(QUIC_PACKET_KEY) +
|
|
||||||
(KeyType == QUIC_PACKET_KEY_1_RTT ? sizeof(CXPLAT_SECRET) : 0);
|
|
||||||
QUIC_PACKET_KEY *Key = CXPLAT_ALLOC_NONPAGED(PacketKeyLength, QUIC_POOL_TLS_PACKETKEY);
|
|
||||||
if (Key == NULL) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
AllocFailure,
|
|
||||||
"Allocation of '%s' failed. (%llu bytes)",
|
|
||||||
"QUIC_PACKET_KEY",
|
|
||||||
PacketKeyLength);
|
|
||||||
return QUIC_STATUS_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
CxPlatZeroMemory(Key, sizeof(QUIC_PACKET_KEY));
|
|
||||||
Key->Type = KeyType;
|
|
||||||
|
|
||||||
CXPLAT_HASH* Hash = NULL;
|
|
||||||
uint8_t Temp[CXPLAT_HASH_MAX_SIZE];
|
|
||||||
|
|
||||||
QUIC_STATUS Status =
|
|
||||||
CxPlatHashCreate(
|
|
||||||
Secret->Hash,
|
|
||||||
Secret->Secret,
|
|
||||||
SecretLength,
|
|
||||||
&Hash);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status =
|
|
||||||
CxPlatHkdfExpandLabel(
|
|
||||||
Hash,
|
|
||||||
"quic iv",
|
|
||||||
CXPLAT_IV_LENGTH,
|
|
||||||
SecretLength,
|
|
||||||
Temp);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(Key->Iv, Temp, CXPLAT_IV_LENGTH);
|
|
||||||
CxPlatTlsLogSecret("static iv", Key->Iv, CXPLAT_IV_LENGTH);
|
|
||||||
|
|
||||||
Status =
|
|
||||||
CxPlatHkdfExpandLabel(
|
|
||||||
Hash,
|
|
||||||
"quic key",
|
|
||||||
KeyLength,
|
|
||||||
SecretLength,
|
|
||||||
Temp);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
CxPlatTlsLogSecret("key", Temp, KeyLength);
|
|
||||||
|
|
||||||
Status =
|
|
||||||
CxPlatKeyCreate(
|
|
||||||
Secret->Aead,
|
|
||||||
Temp,
|
|
||||||
&Key->PacketKey);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CreateHpKey) {
|
|
||||||
Status =
|
|
||||||
CxPlatHkdfExpandLabel(
|
|
||||||
Hash,
|
|
||||||
"quic hp",
|
|
||||||
KeyLength,
|
|
||||||
SecretLength,
|
|
||||||
Temp);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
CxPlatTlsLogSecret("hp", Temp, KeyLength);
|
|
||||||
|
|
||||||
Status =
|
|
||||||
CxPlatHpKeyCreate(
|
|
||||||
Secret->Aead,
|
|
||||||
Temp,
|
|
||||||
&Key->HeaderKey);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KeyType == QUIC_PACKET_KEY_1_RTT) {
|
|
||||||
CxPlatCopyMemory(Key->TrafficSecret, Secret, sizeof(CXPLAT_SECRET));
|
|
||||||
}
|
|
||||||
|
|
||||||
*NewKey = Key;
|
|
||||||
Key = NULL;
|
|
||||||
|
|
||||||
Error:
|
|
||||||
|
|
||||||
QuicPacketKeyFree(Key);
|
|
||||||
CxPlatHashFree(Hash);
|
|
||||||
|
|
||||||
CxPlatSecureZeroMemory(Temp, sizeof(Temp));
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
_When_(NewReadKey != NULL, _At_(*NewReadKey, __drv_allocatesMem(Mem)))
|
|
||||||
_When_(NewWriteKey != NULL, _At_(*NewWriteKey, __drv_allocatesMem(Mem)))
|
|
||||||
QUIC_STATUS
|
|
||||||
QuicPacketKeyCreateInitial(
|
|
||||||
_In_ BOOLEAN IsServer,
|
|
||||||
_In_reads_(CXPLAT_VERSION_SALT_LENGTH)
|
|
||||||
const uint8_t* const Salt, // Version Specific
|
|
||||||
_In_ uint8_t CIDLength,
|
|
||||||
_In_reads_(CIDLength)
|
|
||||||
const uint8_t* const CID,
|
|
||||||
_Out_opt_ QUIC_PACKET_KEY** NewReadKey,
|
|
||||||
_Out_opt_ QUIC_PACKET_KEY** NewWriteKey
|
|
||||||
)
|
|
||||||
{
|
|
||||||
QUIC_STATUS Status;
|
|
||||||
CXPLAT_SECRET ClientInitial, ServerInitial;
|
|
||||||
QUIC_PACKET_KEY* ReadKey = NULL, *WriteKey = NULL;
|
|
||||||
|
|
||||||
Status =
|
|
||||||
CxPlatTlsDeriveInitialSecrets(
|
|
||||||
Salt,
|
|
||||||
CID,
|
|
||||||
CIDLength,
|
|
||||||
&ClientInitial,
|
|
||||||
&ServerInitial);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NewWriteKey != NULL) {
|
|
||||||
Status =
|
|
||||||
QuicPacketKeyDerive(
|
|
||||||
QUIC_PACKET_KEY_INITIAL,
|
|
||||||
IsServer ? &ServerInitial : &ClientInitial,
|
|
||||||
IsServer ? "srv secret" : "cli secret",
|
|
||||||
TRUE,
|
|
||||||
&WriteKey);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NewReadKey != NULL) {
|
|
||||||
Status =
|
|
||||||
QuicPacketKeyDerive(
|
|
||||||
QUIC_PACKET_KEY_INITIAL,
|
|
||||||
IsServer ? &ClientInitial : &ServerInitial,
|
|
||||||
IsServer ? "cli secret" : "srv secret",
|
|
||||||
TRUE,
|
|
||||||
&ReadKey);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NewWriteKey != NULL) {
|
|
||||||
*NewWriteKey = WriteKey;
|
|
||||||
WriteKey = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NewReadKey != NULL) {
|
|
||||||
*NewReadKey = ReadKey;
|
|
||||||
ReadKey = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error:
|
|
||||||
|
|
||||||
QuicPacketKeyFree(ReadKey);
|
|
||||||
QuicPacketKeyFree(WriteKey);
|
|
||||||
|
|
||||||
CxPlatSecureZeroMemory(ClientInitial.Secret, sizeof(ClientInitial.Secret));
|
|
||||||
CxPlatSecureZeroMemory(ServerInitial.Secret, sizeof(ServerInitial.Secret));
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
void
|
|
||||||
QuicPacketKeyFree(
|
|
||||||
_In_opt_ __drv_freesMem(Mem) QUIC_PACKET_KEY* Key
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (Key != NULL) {
|
|
||||||
CxPlatKeyFree(Key->PacketKey);
|
|
||||||
CxPlatHpKeyFree(Key->HeaderKey);
|
|
||||||
if (Key->Type >= QUIC_PACKET_KEY_1_RTT) {
|
|
||||||
CxPlatSecureZeroMemory(Key->TrafficSecret, sizeof(CXPLAT_SECRET));
|
|
||||||
}
|
|
||||||
CXPLAT_FREE(Key, QUIC_POOL_TLS_PACKETKEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
_At_(*NewKey, __drv_allocatesMem(Mem))
|
|
||||||
QUIC_STATUS
|
|
||||||
QuicPacketKeyUpdate(
|
|
||||||
_In_ QUIC_PACKET_KEY* OldKey,
|
|
||||||
_Out_ QUIC_PACKET_KEY** NewKey
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (OldKey->Type != QUIC_PACKET_KEY_1_RTT) {
|
|
||||||
return QUIC_STATUS_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
CXPLAT_HASH* Hash = NULL;
|
|
||||||
CXPLAT_SECRET NewTrafficSecret;
|
|
||||||
const uint16_t SecretLength = CxPlatHashLength(OldKey->TrafficSecret->Hash);
|
|
||||||
|
|
||||||
QUIC_STATUS Status =
|
|
||||||
CxPlatHashCreate(
|
|
||||||
OldKey->TrafficSecret->Hash,
|
|
||||||
OldKey->TrafficSecret->Secret,
|
|
||||||
SecretLength,
|
|
||||||
&Hash);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status =
|
|
||||||
CxPlatHkdfExpandLabel(
|
|
||||||
Hash,
|
|
||||||
"quic ku",
|
|
||||||
SecretLength,
|
|
||||||
SecretLength,
|
|
||||||
NewTrafficSecret.Secret);
|
|
||||||
if (QUIC_FAILED(Status)) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
NewTrafficSecret.Hash = OldKey->TrafficSecret->Hash;
|
|
||||||
NewTrafficSecret.Aead = OldKey->TrafficSecret->Aead;
|
|
||||||
|
|
||||||
Status =
|
|
||||||
QuicPacketKeyDerive(
|
|
||||||
QUIC_PACKET_KEY_1_RTT,
|
|
||||||
&NewTrafficSecret,
|
|
||||||
"update traffic secret",
|
|
||||||
FALSE,
|
|
||||||
NewKey);
|
|
||||||
|
|
||||||
CxPlatSecureZeroMemory(&NewTrafficSecret, sizeof(CXPLAT_SECRET));
|
|
||||||
CxPlatSecureZeroMemory(OldKey->TrafficSecret, sizeof(CXPLAT_SECRET));
|
|
||||||
|
|
||||||
Error:
|
|
||||||
|
|
||||||
CxPlatHashFree(Hash);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatKeyCreate(
|
|
||||||
_In_ CXPLAT_AEAD_TYPE AeadType,
|
|
||||||
_When_(AeadType == CXPLAT_AEAD_AES_128_GCM, _In_reads_(16))
|
|
||||||
_When_(AeadType == CXPLAT_AEAD_AES_256_GCM, _In_reads_(32))
|
|
||||||
_When_(AeadType == CXPLAT_AEAD_CHACHA20_POLY1305, _In_reads_(32))
|
|
||||||
const uint8_t* const RawKey,
|
|
||||||
_Out_ CXPLAT_KEY** NewKey
|
|
||||||
)
|
|
||||||
{
|
|
||||||
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
|
|
||||||
const EVP_CIPHER *Aead;
|
|
||||||
|
|
||||||
EVP_CIPHER_CTX* CipherCtx = EVP_CIPHER_CTX_new();
|
|
||||||
if (CipherCtx == NULL) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_CIPHER_CTX_new failed");
|
|
||||||
Status = QUIC_STATUS_OUT_OF_MEMORY;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (AeadType) {
|
|
||||||
case CXPLAT_AEAD_AES_128_GCM:
|
|
||||||
Aead = EVP_aes_128_gcm();
|
|
||||||
break;
|
|
||||||
case CXPLAT_AEAD_AES_256_GCM:
|
|
||||||
Aead = EVP_aes_256_gcm();
|
|
||||||
break;
|
|
||||||
case CXPLAT_AEAD_CHACHA20_POLY1305:
|
|
||||||
Aead = EVP_chacha20_poly1305();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Status = QUIC_STATUS_NOT_SUPPORTED;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_CipherInit_ex(CipherCtx, Aead, NULL, RawKey, NULL, 1) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_CipherInit_ex failed");
|
|
||||||
Status = QUIC_STATUS_TLS_ERROR;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_CIPHER_CTX_ctrl(CipherCtx, EVP_CTRL_AEAD_SET_IVLEN, CXPLAT_IV_LENGTH, NULL) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryErrorStatus,
|
|
||||||
"[ lib] ERROR, %u, %s.",
|
|
||||||
ERR_get_error(),
|
|
||||||
"EVP_CIPHER_CTX_ctrl (SET_IVLEN) failed");
|
|
||||||
Status = QUIC_STATUS_TLS_ERROR;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
*NewKey = (CXPLAT_KEY*)CipherCtx;
|
|
||||||
CipherCtx = NULL;
|
|
||||||
|
|
||||||
Exit:
|
|
||||||
|
|
||||||
CxPlatKeyFree((CXPLAT_KEY*)CipherCtx);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
void
|
|
||||||
CxPlatKeyFree(
|
|
||||||
_In_opt_ CXPLAT_KEY* Key
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatEncrypt(
|
|
||||||
_In_ CXPLAT_KEY* Key,
|
|
||||||
_In_reads_bytes_(CXPLAT_IV_LENGTH)
|
|
||||||
const uint8_t* const Iv,
|
|
||||||
_In_ uint16_t AuthDataLength,
|
|
||||||
_In_reads_bytes_opt_(AuthDataLength)
|
|
||||||
const uint8_t* const AuthData,
|
|
||||||
_In_ uint16_t BufferLength,
|
|
||||||
_When_(BufferLength > CXPLAT_ENCRYPTION_OVERHEAD, _Inout_updates_bytes_(BufferLength))
|
|
||||||
_When_(BufferLength <= CXPLAT_ENCRYPTION_OVERHEAD, _Out_writes_bytes_(BufferLength))
|
|
||||||
uint8_t* Buffer
|
|
||||||
)
|
|
||||||
{
|
|
||||||
CXPLAT_DBG_ASSERT(CXPLAT_ENCRYPTION_OVERHEAD <= BufferLength);
|
|
||||||
|
|
||||||
const uint16_t PlainTextLength = BufferLength - CXPLAT_ENCRYPTION_OVERHEAD;
|
|
||||||
uint8_t *Tag = Buffer + PlainTextLength;
|
|
||||||
int OutLen;
|
|
||||||
|
|
||||||
EVP_CIPHER_CTX* CipherCtx = (EVP_CIPHER_CTX*)Key;
|
|
||||||
|
|
||||||
if (EVP_EncryptInit_ex(CipherCtx, NULL, NULL, NULL, Iv) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptInit_ex failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AuthData != NULL &&
|
|
||||||
EVP_EncryptUpdate(CipherCtx, NULL, &OutLen, AuthData, (int)AuthDataLength) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptUpdate (AD) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_EncryptUpdate(CipherCtx, Buffer, &OutLen, Buffer, (int)PlainTextLength) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptUpdate (Cipher) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_EncryptFinal_ex(CipherCtx, Tag, &OutLen) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptFinal_ex failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_CIPHER_CTX_ctrl(CipherCtx, EVP_CTRL_AEAD_GET_TAG, CXPLAT_ENCRYPTION_OVERHEAD, Tag) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_CIPHER_CTX_ctrl (GET_TAG) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QUIC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatDecrypt(
|
|
||||||
_In_ CXPLAT_KEY* Key,
|
|
||||||
_In_reads_bytes_(CXPLAT_IV_LENGTH)
|
|
||||||
const uint8_t* const Iv,
|
|
||||||
_In_ uint16_t AuthDataLength,
|
|
||||||
_In_reads_bytes_opt_(AuthDataLength)
|
|
||||||
const uint8_t* const AuthData,
|
|
||||||
_In_ uint16_t BufferLength,
|
|
||||||
_Inout_updates_bytes_(BufferLength)
|
|
||||||
uint8_t* Buffer
|
|
||||||
)
|
|
||||||
{
|
|
||||||
CXPLAT_DBG_ASSERT(CXPLAT_ENCRYPTION_OVERHEAD <= BufferLength);
|
|
||||||
|
|
||||||
const uint16_t CipherTextLength = BufferLength - CXPLAT_ENCRYPTION_OVERHEAD;
|
|
||||||
uint8_t *Tag = Buffer + CipherTextLength;
|
|
||||||
int OutLen;
|
|
||||||
|
|
||||||
EVP_CIPHER_CTX* CipherCtx = (EVP_CIPHER_CTX*)Key;
|
|
||||||
|
|
||||||
if (EVP_DecryptInit_ex(CipherCtx, NULL, NULL, NULL, Iv) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryErrorStatus,
|
|
||||||
"[ lib] ERROR, %u, %s.",
|
|
||||||
ERR_get_error(),
|
|
||||||
"EVP_DecryptInit_ex failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AuthData != NULL &&
|
|
||||||
EVP_DecryptUpdate(CipherCtx, NULL, &OutLen, AuthData, (int)AuthDataLength) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryErrorStatus,
|
|
||||||
"[ lib] ERROR, %u, %s.",
|
|
||||||
ERR_get_error(),
|
|
||||||
"EVP_DecryptUpdate (AD) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_DecryptUpdate(CipherCtx, Buffer, &OutLen, Buffer, (int)CipherTextLength) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryErrorStatus,
|
|
||||||
"[ lib] ERROR, %u, %s.",
|
|
||||||
ERR_get_error(),
|
|
||||||
"EVP_DecryptUpdate (Cipher) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_CIPHER_CTX_ctrl(CipherCtx, EVP_CTRL_AEAD_SET_TAG, CXPLAT_ENCRYPTION_OVERHEAD, Tag) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryErrorStatus,
|
|
||||||
"[ lib] ERROR, %u, %s.",
|
|
||||||
ERR_get_error(),
|
|
||||||
"EVP_CIPHER_CTX_ctrl (SET_TAG) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_DecryptFinal_ex(CipherCtx, Tag, &OutLen) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryErrorStatus,
|
|
||||||
"[ lib] ERROR, %u, %s.",
|
|
||||||
ERR_get_error(),
|
|
||||||
"EVP_DecryptFinal_ex failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QUIC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatHpKeyCreate(
|
|
||||||
_In_ CXPLAT_AEAD_TYPE AeadType,
|
|
||||||
_When_(AeadType == CXPLAT_AEAD_AES_128_GCM, _In_reads_(16))
|
|
||||||
_When_(AeadType == CXPLAT_AEAD_AES_256_GCM, _In_reads_(32))
|
|
||||||
_When_(AeadType == CXPLAT_AEAD_CHACHA20_POLY1305, _In_reads_(32))
|
|
||||||
const uint8_t* const RawKey,
|
|
||||||
_Out_ CXPLAT_HP_KEY** NewKey
|
|
||||||
)
|
|
||||||
{
|
|
||||||
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
|
|
||||||
const EVP_CIPHER *Aead;
|
|
||||||
CXPLAT_HP_KEY* Key = CXPLAT_ALLOC_NONPAGED(sizeof(CXPLAT_HP_KEY), QUIC_POOL_TLS_HP_KEY);
|
|
||||||
if (Key == NULL) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
AllocFailure,
|
|
||||||
"Allocation of '%s' failed. (%llu bytes)",
|
|
||||||
"CXPLAT_HP_KEY",
|
|
||||||
sizeof(CXPLAT_HP_KEY));
|
|
||||||
return QUIC_STATUS_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
Key->Aead = AeadType;
|
|
||||||
|
|
||||||
Key->CipherCtx = EVP_CIPHER_CTX_new();
|
|
||||||
if (Key->CipherCtx == NULL) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"Cipherctx alloc failed");
|
|
||||||
Status = QUIC_STATUS_OUT_OF_MEMORY;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (AeadType) {
|
|
||||||
case CXPLAT_AEAD_AES_128_GCM:
|
|
||||||
Aead = EVP_aes_128_ecb();
|
|
||||||
break;
|
|
||||||
case CXPLAT_AEAD_AES_256_GCM:
|
|
||||||
Aead = EVP_aes_256_ecb();
|
|
||||||
break;
|
|
||||||
case CXPLAT_AEAD_CHACHA20_POLY1305:
|
|
||||||
Aead = EVP_chacha20();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Status = QUIC_STATUS_NOT_SUPPORTED;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EVP_EncryptInit_ex(Key->CipherCtx, Aead, NULL, RawKey, NULL) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptInit_ex failed");
|
|
||||||
Status = QUIC_STATUS_TLS_ERROR;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
*NewKey = Key;
|
|
||||||
Key = NULL;
|
|
||||||
|
|
||||||
Exit:
|
|
||||||
|
|
||||||
CxPlatHpKeyFree(Key);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
void
|
|
||||||
CxPlatHpKeyFree(
|
|
||||||
_In_opt_ CXPLAT_HP_KEY* Key
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (Key != NULL) {
|
|
||||||
EVP_CIPHER_CTX_free(Key->CipherCtx);
|
|
||||||
CXPLAT_FREE(Key, QUIC_POOL_TLS_HP_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatHpComputeMask(
|
|
||||||
_In_ CXPLAT_HP_KEY* Key,
|
|
||||||
_In_ uint8_t BatchSize,
|
|
||||||
_In_reads_bytes_(CXPLAT_HP_SAMPLE_LENGTH* BatchSize)
|
|
||||||
const uint8_t* const Cipher,
|
|
||||||
_Out_writes_bytes_(CXPLAT_HP_SAMPLE_LENGTH* BatchSize)
|
|
||||||
uint8_t* Mask
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int OutLen = 0;
|
|
||||||
if (Key->Aead == CXPLAT_AEAD_CHACHA20_POLY1305) {
|
|
||||||
static const uint8_t Zero[] = { 0, 0, 0, 0, 0 };
|
|
||||||
for (uint32_t i = 0, Offset = 0; i < BatchSize; ++i, Offset += CXPLAT_HP_SAMPLE_LENGTH) {
|
|
||||||
if (EVP_EncryptInit_ex(Key->CipherCtx, NULL, NULL, NULL, Cipher + Offset) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptInit_ex (hp) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
if (EVP_EncryptUpdate(Key->CipherCtx, Mask + Offset, &OutLen, Zero, sizeof(Zero)) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptUpdate (hp) failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (EVP_EncryptUpdate(Key->CipherCtx, Mask, &OutLen, Cipher, CXPLAT_HP_SAMPLE_LENGTH * BatchSize) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"EVP_EncryptUpdate failed");
|
|
||||||
return QUIC_STATUS_TLS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QUIC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Hash abstraction
|
|
||||||
//
|
|
||||||
|
|
||||||
typedef struct CXPLAT_HASH {
|
|
||||||
//
|
|
||||||
// The message digest.
|
|
||||||
//
|
|
||||||
const EVP_MD *Md;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Context used for hashing.
|
|
||||||
//
|
|
||||||
HMAC_CTX* HashContext;
|
|
||||||
|
|
||||||
} CXPLAT_HASH;
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatHashCreate(
|
|
||||||
_In_ CXPLAT_HASH_TYPE HashType,
|
|
||||||
_In_reads_(SaltLength)
|
|
||||||
const uint8_t* const Salt,
|
|
||||||
_In_ uint32_t SaltLength,
|
|
||||||
_Out_ CXPLAT_HASH** NewHash
|
|
||||||
)
|
|
||||||
{
|
|
||||||
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
|
|
||||||
const EVP_MD *Md;
|
|
||||||
|
|
||||||
HMAC_CTX* HashContext = HMAC_CTX_new();
|
|
||||||
if (HashContext == NULL) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"HMAC_CTX_new failed");
|
|
||||||
Status = QUIC_STATUS_OUT_OF_MEMORY;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (HashType) {
|
|
||||||
case CXPLAT_HASH_SHA256:
|
|
||||||
Md = EVP_sha256();
|
|
||||||
break;
|
|
||||||
case CXPLAT_HASH_SHA384:
|
|
||||||
Md = EVP_sha384();
|
|
||||||
break;
|
|
||||||
case CXPLAT_HASH_SHA512:
|
|
||||||
Md = EVP_sha512();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Status = QUIC_STATUS_NOT_SUPPORTED;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HMAC_Init_ex(HashContext, Salt, SaltLength, Md, NULL) != 1) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"HMAC_Init_ex failed");
|
|
||||||
Status = QUIC_STATUS_TLS_ERROR;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
*NewHash = (CXPLAT_HASH*)HashContext;
|
|
||||||
HashContext = NULL;
|
|
||||||
|
|
||||||
Exit:
|
|
||||||
|
|
||||||
CxPlatHashFree((CXPLAT_HASH*)HashContext);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
void
|
|
||||||
CxPlatHashFree(
|
|
||||||
_In_opt_ CXPLAT_HASH* Hash
|
|
||||||
)
|
|
||||||
{
|
|
||||||
HMAC_CTX_free((HMAC_CTX*)Hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
||||||
QUIC_STATUS
|
|
||||||
CxPlatHashCompute(
|
|
||||||
_In_ CXPLAT_HASH* Hash,
|
|
||||||
_In_reads_(InputLength)
|
|
||||||
const uint8_t* const Input,
|
|
||||||
_In_ uint32_t InputLength,
|
|
||||||
_In_ uint32_t OutputLength, // CxPlatHashLength(HashType)
|
|
||||||
_Out_writes_all_(OutputLength)
|
|
||||||
uint8_t* const Output
|
|
||||||
)
|
|
||||||
{
|
|
||||||
HMAC_CTX* HashContext = (HMAC_CTX*)Hash;
|
|
||||||
|
|
||||||
if (!HMAC_Init_ex(HashContext, NULL, 0, NULL, NULL)) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"HMAC_Init_ex(NULL) failed");
|
|
||||||
return QUIC_STATUS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HMAC_Update(HashContext, Input, InputLength)) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"HMAC_Update failed");
|
|
||||||
return QUIC_STATUS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ActualOutputSize = OutputLength;
|
|
||||||
if (!HMAC_Final(HashContext, Output, &ActualOutputSize)) {
|
|
||||||
QuicTraceEvent(
|
|
||||||
LibraryError,
|
|
||||||
"[ lib] ERROR, %s.",
|
|
||||||
"HMAC_Final failed");
|
|
||||||
return QUIC_STATUS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
CXPLAT_FRE_ASSERT(ActualOutputSize == OutputLength);
|
|
||||||
return QUIC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче