зеркало из https://github.com/microsoft/msquic.git
Refactor Crypt Code Out (#1631)
This commit is contained in:
Родитель
74d7e4401a
Коммит
0a3344ba00
|
@ -8405,6 +8405,26 @@
|
|||
],
|
||||
"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": {
|
||||
"ModuleProperites": {},
|
||||
"TraceString": "[data] UDP send segmentation helper socket failed to open, 0x%x",
|
||||
|
@ -9119,26 +9139,6 @@
|
|||
],
|
||||
"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": {
|
||||
"ModuleProperites": {},
|
||||
"TraceString": "[conn][%p] Send alert = %u (Level = %u)",
|
||||
|
@ -9511,20 +9511,6 @@
|
|||
],
|
||||
"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": {
|
||||
"ModuleProperites": {},
|
||||
"TraceString": "[ tls] Calling SspiAcquireCredentialsHandleAsyncW",
|
||||
|
@ -9558,26 +9544,6 @@
|
|||
],
|
||||
"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": {
|
||||
"ModuleProperites": {},
|
||||
"TraceString": "[conn][%p] Handshake complete (resume=%hu)",
|
||||
|
@ -12661,6 +12627,10 @@
|
|||
"UniquenessHash": "2cbc406b-c1c0-ba4d-eee8-669f30330f4a",
|
||||
"TraceID": "LibraryError"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "7512a5e6-b76b-d244-25a2-f27c6b593461",
|
||||
"TraceID": "TlsLogSecret"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "78b2984b-b937-3b8e-7684-9339d9267135",
|
||||
"TraceID": "DatapathOpenUdpSocketFailed"
|
||||
|
@ -12877,10 +12847,6 @@
|
|||
"UniquenessHash": "86a081de-c71a-7043-b507-672561f5fd36",
|
||||
"TraceID": "StorageOpenKey"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "69c5c25e-ab70-9800-8260-aa93a193bd8b",
|
||||
"TraceID": "OpenSslLogSecret"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "c7b17ffc-7649-6294-b6d0-cf4bbf4bc8cb",
|
||||
"TraceID": "OpenSslAlert"
|
||||
|
@ -12977,14 +12943,6 @@
|
|||
"UniquenessHash": "7312d23f-2305-b54b-e1da-81597fabe281",
|
||||
"TraceID": "TlsErrorStatus"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "a0f9d887-3cc8-3dd3-f2c7-8143878abe6e",
|
||||
"TraceID": "SchannelInitialized"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "b21a8d0d-c484-ac00-8081-90d5e8de9d1f",
|
||||
"TraceID": "SchannelUninitialized"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "fd2f4dda-2c95-a301-6a5e-8dda859fd5c5",
|
||||
"TraceID": "SchannelAchAsync"
|
||||
|
@ -13001,10 +12959,6 @@
|
|||
"UniquenessHash": "7a6ea81a-5491-2148-a007-711c5a641acc",
|
||||
"TraceID": "SchannelAchCompleteInline"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "c04de4b9-64de-c415-dda2-b07f295f9897",
|
||||
"TraceID": "SchannelLogSecret"
|
||||
},
|
||||
{
|
||||
"UniquenessHash": "799852e0-2f39-43d4-6888-98a33178b844",
|
||||
"TraceID": "SchannelHandshakeComplete"
|
||||
|
|
|
@ -9,49 +9,28 @@ if (QUIC_CODE_CHECK)
|
|||
set(CMAKE_CXX_CPPCHECK ${CMAKE_C_CPPCHECK_AVAILABLE})
|
||||
endif()
|
||||
|
||||
set(SOURCES crypt.c hashtable.c pcp.c toeplitz.c)
|
||||
|
||||
if("${CX_PLATFORM}" STREQUAL "windows")
|
||||
set(SOURCES
|
||||
datapath_winuser.c
|
||||
hashtable.c
|
||||
pcp.c
|
||||
platform_winuser.c
|
||||
storage_winuser.c
|
||||
toeplitz.c
|
||||
)
|
||||
set(SOURCES ${SOURCES} datapath_winuser.c platform_winuser.c storage_winuser.c)
|
||||
else()
|
||||
if(CX_PLATFORM STREQUAL "linux")
|
||||
set(SOURCES
|
||||
datapath_epoll.c
|
||||
hashtable.c
|
||||
inline.c
|
||||
pcp.c
|
||||
platform_posix.c
|
||||
storage_posix.c
|
||||
toeplitz.c
|
||||
)
|
||||
set(SOURCES ${SOURCES} datapath_epoll.c platform_posix.c storage_posix.c)
|
||||
else()
|
||||
set(SOURCES
|
||||
datapath_kqueue.c
|
||||
hashtable.c
|
||||
inline.c
|
||||
pcp.c
|
||||
platform_posix.c
|
||||
storage_posix.c
|
||||
toeplitz.c
|
||||
)
|
||||
set(SOURCES ${SOURCES} datapath_kqueue.c platform_posix.c storage_posix.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (QUIC_TLS STREQUAL "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")
|
||||
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")
|
||||
set(SOURCES ${SOURCES} cert_capi.c selfsign_capi.c)
|
||||
set(SOURCES ${SOURCES} cert_capi.c crypt_openssl.c selfsign_capi.c)
|
||||
else()
|
||||
set(SOURCES ${SOURCES} selfsign_openssl.c)
|
||||
set(SOURCES ${SOURCES} crypt_openssl.c inline.c selfsign_openssl.c)
|
||||
endif()
|
||||
else()
|
||||
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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="crypt.c" />
|
||||
<ClCompile Include="crypt_bcrypt.c" />
|
||||
<ClCompile Include="datapath_winkernel.c" />
|
||||
<ClCompile Include="hashtable.c" />
|
||||
<ClCompile Include="pcp.c" />
|
||||
|
|
|
@ -213,15 +213,15 @@ CxPlatConvertFromMappedV6(
|
|||
#endif
|
||||
|
||||
//
|
||||
// TLS Initialization
|
||||
// Crypt Initialization
|
||||
//
|
||||
|
||||
QUIC_STATUS
|
||||
CxPlatTlsLibraryInitialize(
|
||||
CxPlatCryptInitialize(
|
||||
void
|
||||
);
|
||||
|
||||
void
|
||||
CxPlatTlsLibraryUninitialize(
|
||||
CxPlatCryptUninitialize(
|
||||
void
|
||||
);
|
||||
|
|
|
@ -146,13 +146,13 @@ CxPlatInitialize(
|
|||
goto Error;
|
||||
}
|
||||
|
||||
Status = CxPlatTlsLibraryInitialize();
|
||||
Status = CxPlatCryptInitialize();
|
||||
if (QUIC_FAILED(Status)) {
|
||||
QuicTraceEvent(
|
||||
LibraryErrorStatus,
|
||||
"[ lib] ERROR, %u, %s.",
|
||||
Status,
|
||||
"CxPlatTlsLibraryInitialize");
|
||||
"CxPlatCryptInitialize");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ CxPlatUninitialize(
|
|||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
CxPlatTlsLibraryUninitialize();
|
||||
CxPlatCryptUninitialize();
|
||||
BCryptCloseAlgorithmProvider(CxPlatform.RngAlgorithm, 0);
|
||||
CxPlatform.RngAlgorithm = NULL;
|
||||
QuicTraceLogInfo(
|
||||
|
|
|
@ -309,7 +309,7 @@ CxPlatInitialize(
|
|||
goto Error;
|
||||
}
|
||||
|
||||
Status = CxPlatTlsLibraryInitialize();
|
||||
Status = CxPlatCryptInitialize();
|
||||
if (QUIC_FAILED(Status)) {
|
||||
goto Error;
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ CxPlatUninitialize(
|
|||
void
|
||||
)
|
||||
{
|
||||
CxPlatTlsLibraryUninitialize();
|
||||
CxPlatCryptUninitialize();
|
||||
CXPLAT_DBG_ASSERT(CxPlatform.Heap);
|
||||
CXPLAT_FREE(CxPlatNumaMasks, QUIC_POOL_PLATFORM_PROC);
|
||||
CxPlatNumaMasks = NULL;
|
||||
|
|
|
@ -132,11 +132,6 @@ typedef struct 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.
|
||||
//
|
||||
|
@ -156,40 +151,6 @@ typedef struct CXPLAT_HP_KEY {
|
|||
//
|
||||
#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
|
||||
int
|
||||
CxPlatTlsAlpnSelectCallback(
|
||||
|
@ -2061,924 +2022,3 @@ CxPlatTlsParamGet(
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче