зеркало из https://github.com/microsoft/msquic.git
Add support for Schannel in-proc certificate API. (#2785)
This commit is contained in:
Родитель
a8f3325cd7
Коммит
c3ac816b66
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче