This commit is contained in:
Nick Banks 2021-05-25 08:04:07 -07:00 коммит произвёл GitHub
Родитель 74d7e4401a
Коммит 0a3344ba00
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 1800 добавлений и 2251 удалений

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

@ -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")

469
src/platform/crypt.c Normal file
Просмотреть файл

@ -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;
}

749
src/platform/crypt_bcrypt.c Normal file
Просмотреть файл

@ -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;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу