Add support for Schannel in-proc certificate API. (#2785)

This commit is contained in:
Anthony Rossi 2022-07-29 06:31:04 -07:00 коммит произвёл GitHub
Родитель a8f3325cd7
Коммит c3ac816b66
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 421 добавлений и 67 удалений

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

@ -531,7 +531,7 @@ stages:
platform: linux
tls: openssl
config: Release
extraTestArgs: -Filter -*CredValidation*
extraTestArgs: -Filter -*CredValidation*:TlsTest.InProc*
- stage: test_bvt_winkernel_release
displayName: BVT Windows Kernel Release
@ -602,7 +602,7 @@ stages:
platform: windows
tls: schannel
logProfile: Full.Light
extraTestArgs: -Filter -*ValidateConfiguration:*ValidAlpnLengths:*ResumeRejection*:*ClientCertificate*:*LoadBalanced*
extraTestArgs: -Filter -*ValidateConfiguration:*ValidAlpnLengths:*ResumeRejection*:*ClientCertificate*:*LoadBalanced*:TlsTest.InProc*
- template: ./templates/run-bvt.yml
parameters:
pool: MsQuic-Win-Latest
@ -618,48 +618,48 @@ stages:
extraArtifactDir: '_Xdp'
extraPrepareArgs: -InstallDuoNic -InstallXdpDriver
# TODO: reenable these testcases: *Unreachable*:*DrillInitialPacket*
extraTestArgs: -DuoNic -Filter -*ValidateConfiguration:*ValidAlpnLengths:*ResumeRejection*:*ClientCertificate*:*LoadBalanced*:*Tcp*:*Unreachable*:*DrillInitialPacket* -ExtraArtifactDir Xdp
extraTestArgs: -DuoNic -Filter -*ValidateConfiguration:*ValidAlpnLengths:*ResumeRejection*:*ClientCertificate*:*LoadBalanced*:*Tcp*:*Unreachable*:*DrillInitialPacket*:TlsTest.InProc* -ExtraArtifactDir Xdp
- template: ./templates/run-bvt.yml
parameters:
image: windows-2019
platform: windows
tls: openssl
logProfile: Full.Light
extraTestArgs: -Filter -*Unreachable/0:CredValidation*:*NthAllocFail*
extraTestArgs: -Filter -*Unreachable/0:CredValidation*:*NthAllocFail*:TlsTest.InProc*
- template: ./templates/run-bvt.yml
parameters:
image: windows-2022
platform: windows
tls: openssl
logProfile: Full.Light
extraTestArgs: -Filter -*CredValidation*:*NthAllocFail*
extraTestArgs: -Filter -*CredValidation*:*NthAllocFail*:TlsTest.InProc*
- template: ./templates/run-bvt.yml
parameters:
image: ubuntu-latest
platform: linux
tls: openssl
extraTestArgs: -Filter -*CredValidation*
extraTestArgs: -Filter -*CredValidation*:TlsTest.InProc*
- template: ./templates/run-bvt.yml
parameters:
image: ubuntu-latest
platform: linux
tls: openssl
extraArtifactDir: '_Sanitize'
extraTestArgs: -Filter -*CredValidation* -ExtraArtifactDir Sanitize
extraTestArgs: -Filter -*CredValidation*:TlsTest.InProc* -ExtraArtifactDir Sanitize
- template: ./templates/run-bvt.yml
parameters:
image: macOS-10.15
platform: macos
tls: openssl
logProfile: None
extraTestArgs: -Filter -*CredValidation* -ErrorsAsWarnings
extraTestArgs: -Filter -*CredValidation*:TlsTest.InProc* -ErrorsAsWarnings
- template: ./templates/run-bvt.yml
parameters:
image: ubuntu-latest
platform: linux
tls: openssl
extraArtifactDir: '_SystemCrypto'
extraTestArgs: -Filter -*CredValidation* -ExtraArtifactDir SystemCrypto
extraTestArgs: -Filter -*CredValidation*:TlsTest.InProc* -ExtraArtifactDir SystemCrypto
#
# SpinQuic Tests

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

@ -152,6 +152,10 @@ Only use certificates already cached when doing URL retrieval to build a certifi
Only use cached revocation information when checking a certificate chain. Only valid on Windows.
`QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE`
Obtain the peer certificate using a faster in-process API call. Only available on Schannel in the latest Windows 11 builds.
#### `CertificateHash`
Must **only** use with `QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH` type.

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

@ -76,6 +76,7 @@ namespace Microsoft.Quic
USE_SYSTEM_MAPPER = 0x00010000,
CACHE_ONLY_URL_RETRIEVAL = 0x00020000,
REVOCATION_CHECK_CACHE_ONLY = 0x00040000,
INPROC_PEER_CERTIFICATE = 0x00080000,
}
[System.Flags]

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

@ -118,6 +118,7 @@ typedef enum QUIC_CREDENTIAL_FLAGS {
QUIC_CREDENTIAL_FLAG_USE_SYSTEM_MAPPER = 0x00010000, // Schannel only
QUIC_CREDENTIAL_FLAG_CACHE_ONLY_URL_RETRIEVAL = 0x00020000, // Windows only currently
QUIC_CREDENTIAL_FLAG_REVOCATION_CHECK_CACHE_ONLY = 0x00040000, // Windows only currently
QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE = 0x00080000, // Schannel only
} QUIC_CREDENTIAL_FLAGS;
DEFINE_ENUM_FLAG_OPERATORS(QUIC_CREDENTIAL_FLAGS)

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

@ -76,6 +76,17 @@ CxPlatGetPortableCertificate(
_Out_ QUIC_PORTABLE_CERTIFICATE* PortableCertificate
);
//
// Gets a portable certificate and chain in PKCS7 format from
// a serialized certificate store.
//
_Success_(return != 0)
QUIC_STATUS
CxPlatGetPortableCertificateFromSerialized(
_In_ QUIC_CERTIFICATE* SerializedCertificate,
_Out_ QUIC_PORTABLE_CERTIFICATE* PortableCertificate
);
//
// Frees a portable certificate and chain returned from CxPlatGetPortableCertificate
//

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

@ -25,6 +25,16 @@ Environment:
#pragma warning(pop)
#include "msquic.h"
#ifndef CERT_CHAIN_ORDER_PROP_ID
// Set for certificate stores serialized from a remote chain. The value is a DWORD
// 0 based index for the order received from the peer in certificate_list of the
// certificate message.
// This ID value was randomly chosen from the range of CERT_FIRST_USER_PROP_ID to
// CERT_LAST_USER_PROP_ID to minimize the chance of conflict with ones that end
// users might add.
#define CERT_CHAIN_ORDER_PROP_ID 0xE697U
#endif
#ifdef QUIC_RESTRICTED_BUILD
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
@ -700,6 +710,208 @@ Exit:
return (QUIC_CERTIFICATE*)LeafCertCtx;
}
_Success_(return != 0)
QUIC_STATUS
CxPlatGetPortableCertificateFromSerialized(
_In_ QUIC_CERTIFICATE* SerializedCertificate,
_Out_ QUIC_PORTABLE_CERTIFICATE* PortableCertificate
)
{
QUIC_STATUS Status;
DWORD LastError;
HCERTSTORE TempCertStore = NULL;
CERT_BLOB* SerializedCertificateStore = (CERT_BLOB*)SerializedCertificate;
CERT_BLOB Blob = {0};
PCCERT_CONTEXT CurrentCertContext = NULL;
PCCERT_CONTEXT LeafCertContext = NULL;
PortableCertificate->PlatformCertificate = NULL;
HCERTSTORE SerializedStore =
CertOpenStore(
CERT_STORE_PROV_SERIALIZED,
X509_ASN_ENCODING,
0,
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
SerializedCertificateStore);
if (SerializedStore == NULL) {
LastError = GetLastError();
if (LastError == ERROR_OUTOFMEMORY ||
LastError == ERROR_NOT_ENOUGH_MEMORY) {
return QUIC_STATUS_OUT_OF_MEMORY;
} else {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
LastError,
"CertOpenStore failed");
return QUIC_STATUS_INTERNAL_ERROR;
}
}
TempCertStore =
CertOpenStore(
CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_STORE_ENUM_ARCHIVED_FLAG,
NULL);
if (NULL == TempCertStore) {
LastError = GetLastError();
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
LastError,
"CertOpenStore failed");
goto Exit;
}
//
// Locate the leaf certificate
//
while ((CurrentCertContext = CertEnumCertificatesInStore(SerializedStore, CurrentCertContext)) != NULL) {
DWORD cbCertOrder = sizeof(DWORD);
DWORD dwCertOrder = 0;
if (CertGetCertificateContextProperty(
CurrentCertContext,
CERT_CHAIN_ORDER_PROP_ID,
&dwCertOrder,
&cbCertOrder)) {
if (dwCertOrder == 0) {
LeafCertContext = CertDuplicateCertificateContext(CurrentCertContext);
if (LeafCertContext == NULL) {
LastError = GetLastError();
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
LastError,
"CertDuplicateCertificateContext failed");
goto Exit;
}
} else {
if (!CertAddCertificateLinkToStore(
TempCertStore,
CurrentCertContext,
CERT_STORE_ADD_ALWAYS,
NULL)) {
LastError = GetLastError();
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
LastError,
"CertAddCertificateLinkToStore failed");
goto Exit;
}
}
} else {
// Either the property does not exist or it is not the expected size.
// This can happen if the serialized buffer did not come from schannel.
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
GetLastError(),
"CertGetCertificateContextProperty failed");
Status = QUIC_STATUS_INVALID_PARAMETER;
goto Exit;
}
}
if (LeafCertContext == NULL) {
// Schannel did not mark a leaf. This is bad.
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
QUIC_STATUS_NOT_FOUND,
"No leaf certificate found");
Status = QUIC_STATUS_NOT_FOUND;
goto Exit;
}
if (!CertSaveStore(
TempCertStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CERT_STORE_SAVE_AS_PKCS7,
CERT_STORE_SAVE_TO_MEMORY,
&Blob,
0)) {
LastError = GetLastError();
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
LastError,
"CertSaveStore failed");
goto Exit;
}
Blob.pbData = CXPLAT_ALLOC_NONPAGED(Blob.cbData, QUIC_POOL_TLS_PFX);
if (Blob.pbData == NULL) {
QuicTraceEvent(
AllocFailure,
"Allocation of '%s' failed. (%llu bytes)",
"PKCS7 data",
Blob.cbData);
Status = QUIC_STATUS_OUT_OF_MEMORY;
goto Exit;
}
if (!CertSaveStore(
TempCertStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CERT_STORE_SAVE_AS_PKCS7,
CERT_STORE_SAVE_TO_MEMORY,
&Blob,
0)) {
LastError = GetLastError();
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
LastError,
"CertSaveStore failed");
goto Exit;
}
PortableCertificate->PortableChain.Length = Blob.cbData;
PortableCertificate->PortableChain.Buffer = Blob.pbData;
Blob.pbData = NULL;
PortableCertificate->PortableCertificate.Length =
LeafCertContext->cbCertEncoded;
PortableCertificate->PortableCertificate.Buffer =
LeafCertContext->pbCertEncoded;
PortableCertificate->PlatformCertificate =
(QUIC_CERTIFICATE*)LeafCertContext;
LeafCertContext = NULL;
Status = QUIC_STATUS_SUCCESS;
Exit:
if (LeafCertContext != NULL) {
CertFreeCertificateContext(CurrentCertContext);
}
if (CurrentCertContext != NULL) {
CertFreeCertificateContext(CurrentCertContext);
}
if (Blob.pbData != NULL) {
CXPLAT_FREE(Blob.pbData, QUIC_POOL_TLS_PFX);
}
if (TempCertStore != NULL) {
CertCloseStore(TempCertStore, 0);
}
CertCloseStore(SerializedStore, 0);
return Status;
}
_Success_(return != 0)
QUIC_STATUS
CxPlatGetPortableCertificate(
@ -737,7 +949,7 @@ CxPlatGetPortableCertificate(
NULL,
&ChainContext)) {
LastError = GetLastError();
Status = LastError;
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
@ -755,7 +967,7 @@ CxPlatGetPortableCertificate(
NULL);
if (NULL == TempCertStore) {
LastError = GetLastError();
Status = LastError;
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
@ -775,7 +987,7 @@ CxPlatGetPortableCertificate(
CERT_STORE_ADD_ALWAYS,
NULL)) {
LastError = GetLastError();
Status = LastError;
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
@ -794,7 +1006,7 @@ CxPlatGetPortableCertificate(
&Blob,
0)) {
LastError = GetLastError();
Status = LastError;
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
@ -822,7 +1034,7 @@ CxPlatGetPortableCertificate(
&Blob,
0)) {
LastError = GetLastError();
Status = LastError;
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
@ -834,7 +1046,7 @@ CxPlatGetPortableCertificate(
DuplicateCtx = CertDuplicateCertificateContext(CertCtx);
if (DuplicateCtx == NULL) {
LastError = GetLastError();
Status = LastError;
Status = HRESULT_FROM_WIN32(LastError);
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",

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

@ -955,7 +955,8 @@ CxPlatTlsSecConfigCreate(
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_ENABLE_OCSP ||
CredConfigFlags & QUIC_CREDENTIAL_FLAG_USE_SUPPLIED_CREDENTIALS ||
CredConfigFlags & QUIC_CREDENTIAL_FLAG_USE_SYSTEM_MAPPER) {
CredConfigFlags & QUIC_CREDENTIAL_FLAG_USE_SYSTEM_MAPPER ||
CredConfigFlags & QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE) {
return QUIC_STATUS_NOT_SUPPORTED; // Not supported by this TLS implementation
}

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

@ -189,6 +189,12 @@ typedef struct _SCHANNEL_CERT_HASH_STORE
// Values for SCHANNEL_CERT_HASH dwFlags field.
#define SCH_MACHINE_CERT_HASH 0x00000001
typedef struct _CRYPTOAPI_BLOB {
DWORD cbData;
_Field_size_bytes_(cbData)
BYTE *pbData;
} CERT_BLOB, *PCERT_BLOB;
//
// Schannel credentials data structure.
//
@ -369,6 +375,10 @@ typedef struct _SecPkgCred_SessionTicketKeys
#define SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy
#endif
#ifndef SECPKG_ATTR_SERIALIZED_REMOTE_CERT_CONTEXT_INPROC
#define SECPKG_ATTR_SERIALIZED_REMOTE_CERT_CONTEXT_INPROC 0x74 // returns CERT_BLOB, use only after SSPI handshake loop
#endif
//
// Defines until BCrypt.h updates
//
@ -605,6 +615,22 @@ typedef struct CXPLAT_TLS {
} CXPLAT_TLS;
typedef enum QUIC_CERT_BLOB_TYPE {
QUIC_CERT_BLOB_NONE,
QUIC_CERT_BLOB_CHAIN,
QUIC_CERT_BLOB_CONTEXT,
QUIC_CERT_BLOB_SERIALIZED
} QUIC_CERT_BLOB_TYPE;
typedef struct QUIC_CERT_BLOB {
QUIC_CERT_BLOB_TYPE Type;
union {
SecPkgContext_Certificates Chain;
PCCERT_CONTEXT Context;
CERT_BLOB Serialized;
};
} QUIC_CERT_BLOB;
_Success_(return==TRUE)
BOOLEAN
QuicPacketKeyCreate(
@ -1646,11 +1672,7 @@ CxPlatTlsIndicateCertificateReceived(
_In_ CXPLAT_TLS* TlsContext,
_In_ CXPLAT_TLS_PROCESS_STATE* State,
_In_ SecPkgContext_CertificateValidationResult* CertValidationResult,
#ifdef _KERNEL_MODE
_In_ SecPkgContext_Certificates* PeerCert
#else
_In_ PCCERT_CONTEXT PeerCert
#endif
_In_ QUIC_CERT_BLOB* PeerCertBlob
)
{
CXPLAT_TLS_RESULT_FLAGS Result = 0;
@ -1660,30 +1682,65 @@ CxPlatTlsIndicateCertificateReceived(
QUIC_PORTABLE_CERTIFICATE PortableCertificate = {0};
#endif
#ifdef _KERNEL_MODE
Certificate = (QUIC_CERTIFICATE*)PeerCert;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)PeerCert;
#else
if (PeerCert == NULL) {
if (PeerCertBlob->Type == QUIC_CERT_BLOB_NONE) {
Certificate = NULL;
CertificateChain = NULL;
} else if (TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_USE_PORTABLE_CERTIFICATES) {
QUIC_STATUS Status =
CxPlatGetPortableCertificate(
(QUIC_CERTIFICATE*)PeerCert,
&PortableCertificate);
if (QUIC_FAILED(Status)) {
Result |= CXPLAT_TLS_RESULT_ERROR;
State->AlertCode = CXPLAT_TLS_ALERT_CODE_INTERNAL_ERROR;
goto Exit;
}
Certificate = (QUIC_CERTIFICATE*)&PortableCertificate.PortableCertificate;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)&PortableCertificate.PortableChain;
} else {
Certificate = (QUIC_CERTIFICATE*)PeerCert;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)(PeerCert->hCertStore);
}
} else if (PeerCertBlob->Type == QUIC_CERT_BLOB_CHAIN) {
#ifndef _KERNEL_MODE
CXPLAT_DBG_ASSERT(FALSE);
#endif
Certificate = (QUIC_CERTIFICATE*)&PeerCertBlob->Chain;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)&PeerCertBlob->Chain;
} else if (PeerCertBlob->Type == QUIC_CERT_BLOB_CONTEXT) {
#ifdef _KERNEL_MODE
Certificate = NULL;
CertificateChain = NULL;
CXPLAT_DBG_ASSERT(FALSE);
#else
if (TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_USE_PORTABLE_CERTIFICATES) {
QUIC_STATUS Status =
CxPlatGetPortableCertificate(
(QUIC_CERTIFICATE*)PeerCertBlob->Context,
&PortableCertificate);
if (QUIC_FAILED(Status)) {
Result |= CXPLAT_TLS_RESULT_ERROR;
State->AlertCode = CXPLAT_TLS_ALERT_CODE_INTERNAL_ERROR;
goto Exit;
}
Certificate = (QUIC_CERTIFICATE*)&PortableCertificate.PortableCertificate;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)&PortableCertificate.PortableChain;
} else {
Certificate = (QUIC_CERTIFICATE*)PeerCertBlob->Context;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)(PeerCertBlob->Context->hCertStore);
}
#endif
} else if (PeerCertBlob->Type == QUIC_CERT_BLOB_SERIALIZED) {
#ifndef _KERNEL_MODE
if (TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_USE_PORTABLE_CERTIFICATES) {
QUIC_STATUS Status =
CxPlatGetPortableCertificateFromSerialized(
(QUIC_CERTIFICATE*)&PeerCertBlob->Serialized,
&PortableCertificate);
if (QUIC_FAILED(Status)) {
Result |= CXPLAT_TLS_RESULT_ERROR;
State->AlertCode = CXPLAT_TLS_ALERT_CODE_INTERNAL_ERROR;
goto Exit;
}
Certificate = (QUIC_CERTIFICATE*)&PortableCertificate.PortableCertificate;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)&PortableCertificate.PortableChain;
} else {
Certificate = (QUIC_CERTIFICATE*)&PeerCertBlob->Serialized;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)(&PeerCertBlob->Serialized);
}
#else
Certificate = (QUIC_CERTIFICATE*)&PeerCertBlob->Serialized;
CertificateChain = (QUIC_CERTIFICATE_CHAIN*)(&PeerCertBlob->Serialized);
#endif
} else {
CXPLAT_DBG_ASSERTMSG(FALSE, "QUIC_CERT_BLOB_TYPE out of range!");
Certificate = NULL;
CertificateChain = NULL;
}
if (!TlsContext->SecConfig->Callbacks.CertificateReceived(
TlsContext->Connection,
@ -2150,32 +2207,44 @@ CxPlatTlsWriteDataToSchannel(
State->SessionResumed = TRUE;
}
const BOOLEAN RequirePeerCert =
!TlsContext->IsServer ||
TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION;
const BOOLEAN RequirePeerCert =
!TlsContext->IsServer ||
TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION;
QUIC_CERT_BLOB PeerCertBlob;
CxPlatZeroMemory(&PeerCertBlob, sizeof(PeerCertBlob));
if (TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE) {
PeerCertBlob.Type = QUIC_CERT_BLOB_SERIALIZED;
SecStatus =
QueryContextAttributesW(
&TlsContext->SchannelContext,
SECPKG_ATTR_SERIALIZED_REMOTE_CERT_CONTEXT_INPROC,
(PVOID)&(PeerCertBlob.Serialized));
} else {
#ifdef _KERNEL_MODE
SecPkgContext_Certificates _PeerCert;
CxPlatZeroMemory(&_PeerCert, sizeof(_PeerCert));
SecPkgContext_Certificates* PeerCert = &_PeerCert;
SecStatus =
QueryContextAttributesW(
&TlsContext->SchannelContext,
SECPKG_ATTR_REMOTE_CERTIFICATES,
(PVOID)PeerCert);
PeerCertBlob.Type = QUIC_CERT_BLOB_CHAIN;
SecStatus =
QueryContextAttributesW(
&TlsContext->SchannelContext,
SECPKG_ATTR_REMOTE_CERTIFICATES,
(PVOID)&PeerCertBlob.Chain);
#else
PCCERT_CONTEXT PeerCert = NULL;
SecStatus =
QueryContextAttributesW(
&TlsContext->SchannelContext,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
(PVOID)&PeerCert);
SecStatus =
QueryContextAttributesW(
&TlsContext->SchannelContext,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
(PVOID)&PeerCertBlob.Context);
PeerCertBlob.Type =
PeerCertBlob.Context ?
QUIC_CERT_BLOB_CONTEXT : QUIC_CERT_BLOB_NONE;
#endif
}
if (SecStatus == SEC_E_NO_CREDENTIALS &&
(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION)) {
//
// Ignore this case.
//
PeerCertBlob.Type = QUIC_CERT_BLOB_NONE;
CertValidationResult.hrVerifyChainStatus = SecStatus;
} else if (SecStatus == SEC_E_OK &&
!(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION) &&
@ -2220,18 +2289,24 @@ CxPlatTlsWriteDataToSchannel(
TlsContext,
State,
&CertValidationResult,
PeerCert);
&PeerCertBlob);
}
if (TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE) {
if (PeerCertBlob.Serialized.pbData != NULL) {
FreeContextBuffer(PeerCertBlob.Serialized.pbData);
}
} else {
#ifdef _KERNEL_MODE
if (_PeerCert.pbCertificateChain != NULL) {
FreeContextBuffer(_PeerCert.pbCertificateChain);
}
if (PeerCertBlob.Chain.pbCertificateChain != NULL) {
FreeContextBuffer(PeerCertBlob.Chain.pbCertificateChain);
}
#else
if (PeerCert != NULL) {
CertFreeCertificateContext(PeerCert);
}
if (PeerCertBlob.Context != NULL) {
CertFreeCertificateContext(PeerCertBlob.Context);
}
#endif
}
if ((Result & CXPLAT_TLS_RESULT_ERROR) != 0) {
break;

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

@ -1473,8 +1473,57 @@ TEST_F(TlsTest, PortableCertificateValidation)
ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_HANDSHAKE_COMPLETE);
}
}
TEST_F(TlsTest, InProcPortableCertificateValidation)
{
CxPlatClientSecConfig ClientConfig(
QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION |
QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED |
QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE |
QUIC_CREDENTIAL_FLAG_USE_PORTABLE_CERTIFICATES);
CxPlatServerSecConfig ServerConfig;
TlsContext ServerContext, ClientContext;
ClientContext.InitializeClient(ClientConfig);
ServerContext.InitializeServer(ServerConfig);
{
auto Result = ClientContext.ProcessData(nullptr);
ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_DATA);
Result = ServerContext.ProcessData(&ClientContext.State);
ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_DATA);
ASSERT_NE(nullptr, ServerContext.State.WriteKeys[QUIC_PACKET_KEY_1_RTT]);
Result = ClientContext.ProcessData(&ServerContext.State, DefaultFragmentSize, true);
ASSERT_TRUE(ClientContext.ReceivedPeerCertificate);
ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_HANDSHAKE_COMPLETE);
}
}
#endif
TEST_F(TlsTest, InProcCertificateValidation)
{
CxPlatClientSecConfig ClientConfig(
QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION |
QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED |
QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE);
CxPlatServerSecConfig ServerConfig;
TlsContext ServerContext, ClientContext;
ClientContext.InitializeClient(ClientConfig);
ServerContext.InitializeServer(ServerConfig);
{
auto Result = ClientContext.ProcessData(nullptr);
ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_DATA);
Result = ServerContext.ProcessData(&ClientContext.State);
ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_DATA);
ASSERT_NE(nullptr, ServerContext.State.WriteKeys[QUIC_PACKET_KEY_1_RTT]);
Result = ClientContext.ProcessData(&ServerContext.State, DefaultFragmentSize, true);
ASSERT_TRUE(ClientContext.ReceivedPeerCertificate);
ASSERT_TRUE(Result & CXPLAT_TLS_RESULT_HANDSHAKE_COMPLETE);
}
}
TEST_P(TlsTest, One1RttKey)
{
bool PNE = GetParam();
@ -2048,7 +2097,7 @@ ValidateSecConfigStatusSchannel(
TEST_F(TlsTest, PlatformSpecificFlagsSchannel)
{
for (auto TestFlag : { QUIC_CREDENTIAL_FLAG_ENABLE_OCSP, QUIC_CREDENTIAL_FLAG_USE_SUPPLIED_CREDENTIALS,
QUIC_CREDENTIAL_FLAG_USE_SYSTEM_MAPPER,
QUIC_CREDENTIAL_FLAG_USE_SYSTEM_MAPPER, QUIC_CREDENTIAL_FLAG_INPROC_PEER_CERTIFICATE,
#ifndef _WIN32
QUIC_CREDENTIAL_FLAG_REVOCATION_CHECK_END_CERT, QUIC_CREDENTIAL_FLAG_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
QUIC_CREDENTIAL_FLAG_IGNORE_NO_REVOCATION_CHECK, QUIC_CREDENTIAL_FLAG_IGNORE_REVOCATION_OFFLINE,