Correct client certificate validation policy on Windows and macOS. (#1966)

This commit is contained in:
Anthony Rossi 2021-09-21 10:42:07 -07:00 коммит произвёл GitHub
Родитель dee6c6c423
Коммит 4429da0673
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 377 добавлений и 21 удалений

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

@ -38,10 +38,10 @@ extern "C" {
CertCapiVerifiedChain,
"CertVerifyChain: %S 0x%x, result=0x%x",
ServerName,
IgnoreFlags,
CredFlags,
Status);
// arg2 = arg2 = ServerName
// arg3 = arg3 = IgnoreFlags
// arg3 = arg3 = CredFlags
// arg4 = arg4 = Status
----------------------------------------------------------*/
#define _clog_5_ARGS_TRACE_CertCapiVerifiedChain(uniqueId, encoded_arg_string, arg2, arg3, arg4)\

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

@ -8,10 +8,10 @@
CertCapiVerifiedChain,
"CertVerifyChain: %S 0x%x, result=0x%x",
ServerName,
IgnoreFlags,
CredFlags,
Status);
// arg2 = arg2 = ServerName
// arg3 = arg3 = IgnoreFlags
// arg3 = arg3 = CredFlags
// arg4 = arg4 = Status
----------------------------------------------------------*/
TRACEPOINT_EVENT(CLOG_CERT_CAPI_C, CertCapiVerifiedChain,

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

@ -314,6 +314,138 @@ tracepoint(CLOG_CERT_CAPI_OPENSSL_C, AllocFailure , arg2, arg3);\
#ifndef _clog_4_ARGS_TRACE_LibraryErrorStatus
/*----------------------------------------------------------
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
Type,
"Unsupported Type passed to CxPlatGetTestCertificate");
// arg2 = arg2 = Type
// arg3 = arg3 = "Unsupported Type passed to CxPlatGetTestCertificate"
----------------------------------------------------------*/
#define _clog_4_ARGS_TRACE_LibraryErrorStatus(uniqueId, encoded_arg_string, arg2, arg3)\
#endif
#ifndef _clog_4_ARGS_TRACE_LibraryErrorStatus
/*----------------------------------------------------------
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
(unsigned int)QUIC_STATUS_INVALID_PARAMETER,
"NULL CertHash passed to CxPlatGetTestCertificate");
// arg2 = arg2 = (unsigned int)QUIC_STATUS_INVALID_PARAMETER
// arg3 = arg3 = "NULL CertHash passed to CxPlatGetTestCertificate"
----------------------------------------------------------*/
#define _clog_4_ARGS_TRACE_LibraryErrorStatus(uniqueId, encoded_arg_string, arg2, arg3)\
#endif
#ifndef _clog_4_ARGS_TRACE_LibraryErrorStatus
/*----------------------------------------------------------
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
(unsigned int)QUIC_STATUS_INVALID_PARAMETER,
"NULL CertHashStore passed to CxPlatGetTestCertificate");
// arg2 = arg2 = (unsigned int)QUIC_STATUS_INVALID_PARAMETER
// arg3 = arg3 = "NULL CertHashStore passed to CxPlatGetTestCertificate"
----------------------------------------------------------*/
#define _clog_4_ARGS_TRACE_LibraryErrorStatus(uniqueId, encoded_arg_string, arg2, arg3)\
#endif
#ifndef _clog_4_ARGS_TRACE_LibraryErrorStatus
/*----------------------------------------------------------
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
(unsigned int)QUIC_STATUS_INVALID_PARAMETER,
"NULL Principal passed to CxPlatGetTestCertificate");
// arg2 = arg2 = (unsigned int)QUIC_STATUS_INVALID_PARAMETER
// arg3 = arg3 = "NULL Principal passed to CxPlatGetTestCertificate"
----------------------------------------------------------*/
#define _clog_4_ARGS_TRACE_LibraryErrorStatus(uniqueId, encoded_arg_string, arg2, arg3)\
#endif
#ifndef _clog_4_ARGS_TRACE_LibraryErrorStatus
/*----------------------------------------------------------
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
CredType,
"Unsupported CredType passed to CxPlatGetTestCertificate");
// arg2 = arg2 = CredType
// arg3 = arg3 = "Unsupported CredType passed to CxPlatGetTestCertificate"
----------------------------------------------------------*/
#define _clog_4_ARGS_TRACE_LibraryErrorStatus(uniqueId, encoded_arg_string, arg2, arg3)\
#endif
#ifndef _clog_4_ARGS_TRACE_LibraryErrorStatus
/*----------------------------------------------------------
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
GetLastError(),
"CertOpenStore failed");
// arg2 = arg2 = GetLastError()
// arg3 = arg3 = "CertOpenStore failed"
----------------------------------------------------------*/
#define _clog_4_ARGS_TRACE_LibraryErrorStatus(uniqueId, encoded_arg_string, arg2, arg3)\
#endif
#ifdef __cplusplus
}
#endif

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

@ -82,7 +82,7 @@ CxPlatCertValidateChain(
_In_ const QUIC_CERTIFICATE* Certificate,
_In_opt_z_ const char* Host,
_In_ uint32_t CertFlags,
_In_ uint32_t IgnoreFlags,
_In_ uint32_t CredFlags,
_Out_opt_ uint32_t* ValidationError
);

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

@ -796,7 +796,7 @@ DWORD
CxPlatCertVerifyCertChainPolicy(
_In_ PCCERT_CHAIN_CONTEXT ChainContext,
_In_opt_ PWSTR ServerName,
_In_ ULONG IgnoreFlags
_In_ uint32_t CredFlags
)
{
DWORD Status = NO_ERROR;
@ -807,9 +807,10 @@ CxPlatCertVerifyCertChainPolicy(
memset(&HttpsPolicy, 0, sizeof(HTTPSPolicyCallbackData));
HttpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
HttpsPolicy.dwAuthType = AUTHTYPE_SERVER;
HttpsPolicy.dwAuthType =
(CredFlags & QUIC_CREDENTIAL_FLAG_CLIENT) ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT;
HttpsPolicy.fdwChecks = 0;
HttpsPolicy.pwszServerName = ServerName;
HttpsPolicy.pwszServerName = (CredFlags & QUIC_CREDENTIAL_FLAG_CLIENT) ? ServerName : NULL;
memset(&PolicyPara, 0, sizeof(PolicyPara));
PolicyPara.cbSize = sizeof(PolicyPara);
@ -832,10 +833,10 @@ CxPlatCertVerifyCertChainPolicy(
goto Exit;
} else if (PolicyStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK &&
(IgnoreFlags & QUIC_CREDENTIAL_FLAG_IGNORE_NO_REVOCATION_CHECK)) {
(CredFlags & QUIC_CREDENTIAL_FLAG_IGNORE_NO_REVOCATION_CHECK)) {
Status = NO_ERROR;
} else if (PolicyStatus.dwError == CRYPT_E_REVOCATION_OFFLINE &&
(IgnoreFlags & QUIC_CREDENTIAL_FLAG_IGNORE_REVOCATION_OFFLINE)) {
(CredFlags & QUIC_CREDENTIAL_FLAG_IGNORE_REVOCATION_OFFLINE)) {
Status = NO_ERROR;
} else if (PolicyStatus.dwError != NO_ERROR) {
@ -854,7 +855,7 @@ Exit:
CertCapiVerifiedChain,
"CertVerifyChain: %S 0x%x, result=0x%x",
ServerName,
IgnoreFlags,
CredFlags,
Status);
return Status;
@ -866,7 +867,7 @@ CxPlatCertValidateChain(
_In_ const QUIC_CERTIFICATE* Certificate,
_In_opt_z_ PCSTR Host,
_In_ uint32_t CertFlags,
_In_ uint32_t IgnoreFlags,
_In_ uint32_t CredFlags,
_Out_opt_ uint32_t* ValidationError
)
{
@ -879,12 +880,16 @@ CxPlatCertValidateChain(
CERT_CHAIN_PARA ChainPara;
static const LPSTR UsageOids[] = {
static const LPSTR ServerUsageOids[] = {
szOID_PKIX_KP_SERVER_AUTH,
szOID_SERVER_GATED_CRYPTO,
szOID_SGC_NETSCAPE
};
static const LPSTR ClientUsageOids[] = {
szOID_PKIX_KP_CLIENT_AUTH
};
if (ValidationError != NULL) {
*ValidationError = NO_ERROR;
}
@ -892,8 +897,10 @@ CxPlatCertValidateChain(
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = ARRAYSIZE(UsageOids);
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = (LPSTR*)UsageOids;
ChainPara.RequestedUsage.Usage.cUsageIdentifier =
(CredFlags & QUIC_CREDENTIAL_FLAG_CLIENT) ? ARRAYSIZE(ServerUsageOids) : ARRAYSIZE(ClientUsageOids);
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier =
(CredFlags & QUIC_CREDENTIAL_FLAG_CLIENT) ? (LPSTR*)ServerUsageOids : (LPSTR*)ClientUsageOids;
if (!CertGetCertificateChain(
NULL,
@ -933,7 +940,7 @@ CxPlatCertValidateChain(
CxPlatCertVerifyCertChainPolicy(
ChainContext,
ServerName,
IgnoreFlags);
CredFlags);
Result = NO_ERROR == Error;

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

@ -14,6 +14,7 @@ Environment:
--*/
#define QUIC_TEST_APIS 1
#include "platform_internal.h"
#define OPENSSL_SUPPRESS_DEPRECATED 1 // For hmac.h, which was deprecated in 3.0
@ -35,6 +36,22 @@ Environment:
#include <wincrypt.h>
#include "msquic.h"
#define CXPLAT_CERT_CREATION_EVENT_NAME L"MsQuicCertEvent"
#define CXPLAT_CERT_CREATION_EVENT_WAIT 10000
#define CXPLAT_CERTIFICATE_TEST_FRIENDLY_NAME L"MsQuicTestCert2"
#define CXPLAT_CERTIFICATE_TEST_CLIENT_FRIENDLY_NAME L"MsQuicTestClientCert"
#define CXPLAT_KEY_CONTAINER_NAME L"MsQuicSelfSignKey2"
#define CXPLAT_KEY_SIZE 2048
#define CXPLAT_TEST_CERT_VALID_SERVER_FRIENDLY_NAME L"MsQuicTestServer"
#define CXPLAT_TEST_CERT_VALID_CLIENT_FRIENDLY_NAME L"MsQuicTestClient"
#define CXPLAT_TEST_CERT_EXPIRED_SERVER_FRIENDLY_NAME L"MsQuicTestExpiredServer"
#define CXPLAT_TEST_CERT_EXPIRED_CLIENT_FRIENDLY_NAME L"MsQuicTestExpiredClient"
#define CXPLAT_TEST_CERT_VALID_SERVER_SUBJECT_NAME "MsQuicTestServer"
#define CXPLAT_TEST_CERT_VALID_CLIENT_SUBJECT_NAME "MsQuicTestClient"
#define CXPLAT_TEST_CERT_EXPIRED_SERVER_SUBJECT_NAME "MsQuicTestExpiredServer"
#define CXPLAT_TEST_CERT_EXPIRED_CLIENT_SUBJECT_NAME "MsQuicTestExpiredClient"
_Success_(return != FALSE)
BOOLEAN
CxPlatTlsVerifyCertificate(
@ -87,15 +104,12 @@ CxPlatTlsVerifyCertificate(
CertFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
}
uint32_t IgnoreFlags =
CredFlags & (QUIC_CREDENTIAL_FLAG_IGNORE_REVOCATION_OFFLINE | QUIC_CREDENTIAL_FLAG_IGNORE_NO_REVOCATION_CHECK);
Result =
CxPlatCertValidateChain(
CertContext,
SNI,
CertFlags,
IgnoreFlags,
CredFlags,
PlatformVerificationError);
Exit:
@ -349,3 +363,187 @@ Exit:
return Status;
}
_Success_(return != NULL)
PCCERT_CONTEXT
FindCertificate(
_In_ HCERTSTORE CertStore,
_In_ BOOLEAN IncludeInvalid,
_In_z_ const wchar_t* SearchFriendlyName,
_Out_writes_all_(20) uint8_t* CertHash
);
_Success_(return == TRUE)
BOOLEAN
CxPlatGetTestCertificateWindows(
_In_ CXPLAT_TEST_CERT_TYPE Type,
_In_ CXPLAT_SELF_SIGN_CERT_TYPE StoreType,
_In_ uint32_t CredType,
_Out_ QUIC_CREDENTIAL_CONFIG* Params,
_When_(CredType == QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH, _Out_)
_When_(CredType != QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH, _Reserved_)
QUIC_CERTIFICATE_HASH* CertHash,
_When_(CredType == QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE, _Out_)
_When_(CredType != QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE, _Reserved_)
QUIC_CERTIFICATE_HASH_STORE* CertHashStore,
_When_(CredType == QUIC_CREDENTIAL_TYPE_NONE, _Out_z_bytecap_(100))
_When_(CredType != QUIC_CREDENTIAL_TYPE_NONE, _Reserved_)
char Principal[100]
)
{
BOOLEAN Success = FALSE;
PCCERT_CONTEXT Cert = NULL;
const wchar_t* FriendlyName = NULL;
const char* SubjectName = NULL;
switch (Type) {
case CXPLAT_TEST_CERT_VALID_SERVER:
FriendlyName = CXPLAT_TEST_CERT_VALID_SERVER_FRIENDLY_NAME;
SubjectName = CXPLAT_TEST_CERT_VALID_SERVER_SUBJECT_NAME;
break;
case CXPLAT_TEST_CERT_VALID_CLIENT:
FriendlyName = CXPLAT_TEST_CERT_VALID_CLIENT_FRIENDLY_NAME;
SubjectName = CXPLAT_TEST_CERT_VALID_CLIENT_SUBJECT_NAME;
break;
case CXPLAT_TEST_CERT_EXPIRED_SERVER:
FriendlyName = CXPLAT_TEST_CERT_EXPIRED_SERVER_FRIENDLY_NAME;
SubjectName = CXPLAT_TEST_CERT_EXPIRED_SERVER_SUBJECT_NAME;
break;
case CXPLAT_TEST_CERT_EXPIRED_CLIENT:
FriendlyName = CXPLAT_TEST_CERT_EXPIRED_CLIENT_FRIENDLY_NAME;
SubjectName = CXPLAT_TEST_CERT_EXPIRED_CLIENT_SUBJECT_NAME;
break;
default:
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
Type,
"Unsupported Type passed to CxPlatGetTestCertificate");
return FALSE;
}
switch (CredType) {
case QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH:
if (CertHash == NULL) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
(unsigned int)QUIC_STATUS_INVALID_PARAMETER,
"NULL CertHash passed to CxPlatGetTestCertificate");
return FALSE;
}
break;
case QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE:
if (CertHashStore == NULL) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
(unsigned int)QUIC_STATUS_INVALID_PARAMETER,
"NULL CertHashStore passed to CxPlatGetTestCertificate");
return FALSE;
}
break;
case QUIC_CREDENTIAL_TYPE_NONE:
if (Principal == NULL) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
(unsigned int)QUIC_STATUS_INVALID_PARAMETER,
"NULL Principal passed to CxPlatGetTestCertificate");
return FALSE;
}
break;
case QUIC_CREDENTIAL_TYPE_CERTIFICATE_CONTEXT:
break;
default:
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
CredType,
"Unsupported CredType passed to CxPlatGetTestCertificate");
return FALSE;
}
CxPlatZeroMemory(Params, sizeof(*Params));
HCERTSTORE CertStore =
CertOpenStore(
CERT_STORE_PROV_SYSTEM_A,
0,
0,
StoreType == CXPLAT_SELF_SIGN_CERT_USER ?
CERT_SYSTEM_STORE_CURRENT_USER :
CERT_SYSTEM_STORE_LOCAL_MACHINE,
"MY");
if (CertStore == NULL) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
GetLastError(),
"CertOpenStore failed");
goto Done;
}
uint8_t CertHashBytes[20];
Cert = FindCertificate(
CertStore,
TRUE,
FriendlyName,
CertHashBytes);
if (Cert == NULL) {
goto Done;
}
switch (CredType) {
case QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH:
Params->Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH;
Params->CertificateHash = CertHash;
CxPlatCopyMemory(CertHash->ShaHash, CertHashBytes, sizeof(CertHash->ShaHash));
break;
case QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE:
Params->Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE;
Params->CertificateHashStore = CertHashStore;
CxPlatCopyMemory(CertHashStore->ShaHash, CertHashBytes, sizeof(CertHashStore->ShaHash));
strncpy_s(CertHashStore->StoreName, sizeof(CertHashStore->StoreName), "MY", sizeof("MY"));
CertHashStore->Flags =
StoreType == CXPLAT_SELF_SIGN_CERT_USER ?
QUIC_CERTIFICATE_HASH_STORE_FLAG_NONE :
QUIC_CERTIFICATE_HASH_STORE_FLAG_MACHINE_STORE;
break;
case QUIC_CREDENTIAL_TYPE_NONE:
//
// Assume Principal in use here
//
Params->Type = QUIC_CREDENTIAL_TYPE_NONE;
Params->Principal = Principal;
strncpy_s(Principal, 100, SubjectName, 100);
break;
case QUIC_CREDENTIAL_TYPE_CERTIFICATE_CONTEXT:
Params->Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_CONTEXT;
Params->CertificateContext = (QUIC_CERTIFICATE*)Cert;
Cert = NULL;
break;
}
Success = TRUE;
Done:
if (Cert != NULL) {
CertFreeCertificateContext(Cert);
}
if (CertStore != NULL) {
CertCloseStore(CertStore, 0);
}
return Success;
}
_IRQL_requires_max_(PASSIVE_LEVEL)
void
CxPlatFreeTestCertWindows(
_In_ QUIC_CREDENTIAL_CONFIG* Params
)
{
if (Params->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_CONTEXT) {
CertFreeCertificateContext((PCCERT_CONTEXT)Params->CertificateContext);
}
}

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

@ -123,7 +123,10 @@ CxPlatTlsVerifyCertificate(
goto Exit;
}
SSLPolicy = SecPolicyCreateSSL(TRUE, SNIString);
SSLPolicy =
SecPolicyCreateSSL(
(CredFlags & QUIC_CREDENTIAL_FLAG_CLIENT) ? TRUE : FALSE,
SNIString);
if (SSLPolicy == NULL) {
QuicTraceEvent(
LibraryError,

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

@ -459,6 +459,17 @@ CxPlatGetTestCertificate(
char Principal[100]
)
{
#ifdef _WIN32
return
CxPlatGetTestCertificateWindows(
Type,
StoreType,
CredType,
Params,
CertHash,
CertHashStore,
Principal);
#else
// Not yet supported
UNREFERENCED_PARAMETER(Type);
UNREFERENCED_PARAMETER(StoreType);
@ -468,6 +479,7 @@ CxPlatGetTestCertificate(
UNREFERENCED_PARAMETER(CertHashStore);
UNREFERENCED_PARAMETER(Principal);
return FALSE;
#endif
}
_IRQL_requires_max_(PASSIVE_LEVEL)
@ -476,7 +488,11 @@ CxPlatFreeTestCert(
_In_ QUIC_CREDENTIAL_CONFIG* Params
)
{
#ifdef _WIN32
CxPlatFreeTestCertWindows(Params);
#else
UNREFERENCED_PARAMETER(Params);
#endif
}
_IRQL_requires_max_(PASSIVE_LEVEL)