Add client certificate support to OpenSSL (#1930)

This commit is contained in:
Anthony Rossi 2021-09-07 13:47:45 -07:00 коммит произвёл GitHub
Родитель d2a2570fd3
Коммит d340ff7c74
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 470 добавлений и 360 удалений

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

@ -331,10 +331,6 @@ endif()
if(QUIC_TLS STREQUAL "openssl")
message(STATUS "Enabling OpenSsl configuration tests")
list(APPEND QUIC_COMMON_DEFINES QUIC_TEST_OPENSSL_FLAGS=1)
message(STATUS "Disabling client certificate tests")
list(APPEND QUIC_COMMON_DEFINES QUIC_DISABLE_CLIENT_CERT_TESTS)
message(STATUS "Disabling deferred certificate tests")
list(APPEND QUIC_COMMON_DEFINES QUIC_DISABLE_DEFERRED_CERT_TESTS)
endif()
if(WIN32)

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

@ -20,8 +20,6 @@ On Linux, MsQuic relies on [OpenSSL](https://www.openssl.org/) for TLS 1.3 funct
> **Important** This configuration relies on a [fork of OpenSSL](https://github.com/quictls/openssl) for QUIC/TLS support. It is still currently unknown as to when mainline will support QUIC. See [here](https://www.openssl.org/blog/blog/2020/02/17/QUIC-and-OpenSSL/) for more details. MsQuic with OpenSSL **does** fully support 0-RTT.
> **Important** This configuration does not yet support client certificates ([#1803](https://github.com/microsoft/msquic/issues/1803)).
## Other
For testing or experimentation purposes, MsQuic may be built with other configurations, but they are not to be considered officially supported unless they are listed above. Any bugs found while using these configurations may be looked at, but no guarantees are provided that they will be fixed.

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

@ -384,9 +384,9 @@ tracepoint(CLOG_CERT_CAPI_C, LibraryError , arg2);\
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
GetLastError(),
Error,
"CertGetCertificateChain failed");
// arg2 = arg2 = GetLastError()
// arg2 = arg2 = Error
// arg3 = arg3 = "CertGetCertificateChain failed"
----------------------------------------------------------*/
#define _clog_4_ARGS_TRACE_LibraryErrorStatus(uniqueId, encoded_arg_string, arg2, arg3)\

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

@ -320,26 +320,6 @@ tracepoint(CLOG_SELFSIGN_OPENSSL_C, LibraryError , arg2);\
#ifndef _clog_3_ARGS_TRACE_LibraryError
/*----------------------------------------------------------
// Decoder Ring for LibraryError
// [ lib] ERROR, %s.
// QuicTraceEvent(
LibraryError,
"[ lib] ERROR, %s.",
"Client Certificate is not supported in OpenSSL");
// arg2 = arg2 = "Client Certificate is not supported in OpenSSL"
----------------------------------------------------------*/
#define _clog_3_ARGS_TRACE_LibraryError(uniqueId, encoded_arg_string, arg2)\
#endif
#ifndef _clog_3_ARGS_TRACE_LibraryError

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

@ -581,10 +581,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, OpenSslProcessData , arg1, arg3);\
// Decoder Ring for TlsError
// [ tls][%p] ERROR, %s.
// QuicTraceEvent(
TlsError,
"[ tls][%p] ERROR, %s.",
TlsContext->Connection,
"No certificate passed");
TlsError,
"[ tls][%p] ERROR, %s.",
TlsContext->Connection,
"No certificate passed");
// arg2 = arg2 = TlsContext->Connection
// arg3 = arg3 = "No certificate passed"
----------------------------------------------------------*/
@ -1161,10 +1161,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "SSL_CTX_use_PrivateKey_file failed"
----------------------------------------------------------*/
@ -1183,10 +1183,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate_chain_file failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate_chain_file failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "SSL_CTX_use_certificate_chain_file failed"
----------------------------------------------------------*/
@ -1205,10 +1205,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"BIO_new failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"BIO_new failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "BIO_new failed"
----------------------------------------------------------*/
@ -1227,10 +1227,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"d2i_PKCS12_bio failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"d2i_PKCS12_bio failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "d2i_PKCS12_bio failed"
----------------------------------------------------------*/
@ -1249,10 +1249,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"PKCS12_parse failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"PKCS12_parse failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "PKCS12_parse failed"
----------------------------------------------------------*/
@ -1271,10 +1271,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "SSL_CTX_use_PrivateKey_file failed"
----------------------------------------------------------*/
@ -1293,10 +1293,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "SSL_CTX_use_certificate failed"
----------------------------------------------------------*/
@ -1315,10 +1315,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_RSAPrivateKey_file failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_RSAPrivateKey_file failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "SSL_CTX_use_RSAPrivateKey_file failed"
----------------------------------------------------------*/
@ -1337,10 +1337,10 @@ tracepoint(CLOG_TLS_OPENSSL_C, LibraryErrorStatus , arg2, arg3);\
// Decoder Ring for LibraryErrorStatus
// [ lib] ERROR, %u, %s.
// QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
// arg2 = arg2 = ERR_get_error()
// arg3 = arg3 = "SSL_CTX_use_certificate failed"
----------------------------------------------------------*/

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

@ -495,10 +495,10 @@ TRACEPOINT_EVENT(CLOG_TLS_OPENSSL_C, OpenSslProcessData,
// Decoder Ring for TlsError
// [ tls][%p] ERROR, %s.
// QuicTraceEvent(
TlsError,
"[ tls][%p] ERROR, %s.",
TlsContext->Connection,
"No certificate passed");
TlsError,
"[ tls][%p] ERROR, %s.",
TlsContext->Connection,
"No certificate passed");
// arg2 = arg2 = TlsContext->Connection
// arg3 = arg3 = "No certificate passed"
----------------------------------------------------------*/

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

@ -958,7 +958,7 @@ typedef struct QUIC_CONNECTION_EVENT {
} RESUMPTION_TICKET_RECEIVED;
struct {
QUIC_CERTIFICATE* Certificate; // Peer certificate (platform specific). Valid only during QUIC_CONNECTION_EVENT_PEER_CERTIFICATE_RECEIVED callback.
uint32_t DeferredErrorFlags; // Bit flag of errors (only valid with QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION)
uint32_t DeferredErrorFlags; // Bit flag of errors (only valid with QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION) - Schannel only, zero otherwise.
QUIC_STATUS DeferredStatus; // Most severe error status (only valid with QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION)
QUIC_CERTIFICATE_CHAIN* Chain; // Peer certificate chain (platform specific). Valid only during QUIC_CONNECTION_EVENT_PEER_CERTIFICATE_RECEIVED callback.
} PEER_CERTIFICATE_RECEIVED;

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

@ -133,6 +133,7 @@ inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) throw() { return (ENUMTYP
#define QUIC_STATUS_REVOKED_CERTIFICATE QUIC_STATUS_TLS_ALERT(44) // 0xBEBC32C - Revoked Certificate
#define QUIC_STATUS_EXPIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(45) // 0xBEBC32D - Expired Certificate
#define QUIC_STATUS_UNKNOWN_CERTIFICATE QUIC_STATUS_TLS_ALERT(46) // 0xBEBC32E - Unknown Certificate
#define QUIC_STATUS_REQUIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(116) // 0xBEBC374 - Required Certificate
#define QUIC_STATUS_CERT_ERROR(Val) ((QUIC_STATUS)Val + CERT_ERROR_BASE)

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

@ -113,6 +113,7 @@ typedef UINT64 uint64_t;
#define QUIC_STATUS_CLOSE_NOTIFY QUIC_STATUS_TLS_ALERT(0) // Close notify
#define QUIC_STATUS_BAD_CERTIFICATE QUIC_STATUS_TLS_ALERT(42) // Bad Certificate
#define QUIC_STATUS_EXPIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(45) // Expired Certificate
#define QUIC_STATUS_REQUIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(116) // Required Certificate
#define QUIC_STATUS_CERT_EXPIRED ((NTSTATUS)0x800B0101L) // CERT_E_EXPIRED
#define QUIC_STATUS_CERT_UNTRUSTED_ROOT ((NTSTATUS)0x800B0109L) // CERT_E_UNTRUSTEDROOT

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

@ -116,6 +116,7 @@ Environment:
#define QUIC_STATUS_REVOKED_CERTIFICATE QUIC_STATUS_TLS_ALERT(44) // Revoked Certificate
#define QUIC_STATUS_EXPIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(45) // Expired Certificate
#define QUIC_STATUS_UNKNOWN_CERTIFICATE QUIC_STATUS_TLS_ALERT(46) // Unknown Certificate
#define QUIC_STATUS_REQUIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(116) // Required Certificate
#define QUIC_STATUS_CERT_EXPIRED CERT_E_EXPIRED
#define QUIC_STATUS_CERT_UNTRUSTED_ROOT CERT_E_UNTRUSTEDROOT

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

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

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

@ -860,12 +860,14 @@ CxPlatCertValidateChain(
_In_ const QUIC_CERTIFICATE* Certificate,
_In_opt_z_ PCSTR Host,
_In_ uint32_t CertFlags,
_In_ uint32_t IgnoreFlags
_In_ uint32_t IgnoreFlags,
_Out_opt_ uint32_t* ValidationError
)
{
BOOLEAN Result = FALSE;
PCCERT_CHAIN_CONTEXT ChainContext = NULL;
LPWSTR ServerName = NULL;
DWORD Error = NO_ERROR;
PCCERT_CONTEXT LeafCertCtx = (PCCERT_CONTEXT)Certificate;
@ -877,6 +879,10 @@ CxPlatCertValidateChain(
szOID_SGC_NETSCAPE
};
if (ValidationError != NULL) {
*ValidationError = NO_ERROR;
}
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
@ -892,10 +898,11 @@ CxPlatCertValidateChain(
CertFlags,
NULL,
&ChainContext)) {
Error = GetLastError();
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
GetLastError(),
Error,
"CertGetCertificateChain failed");
goto Exit;
}
@ -916,13 +923,14 @@ CxPlatCertValidateChain(
}
}
Result =
NO_ERROR ==
Error =
CxPlatCertVerifyCertChainPolicy(
ChainContext,
ServerName,
IgnoreFlags);
Result = NO_ERROR == Error;
Exit:
if (ChainContext != NULL) {
@ -931,6 +939,9 @@ Exit:
if (ServerName != NULL) {
CXPLAT_FREE(ServerName, QUIC_POOL_PLATFORM_TMP_ALLOC);
}
if (ValidationError != NULL && !Result) {
*ValidationError = (uint32_t)Error;
}
return Result;
}

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

@ -35,11 +35,13 @@ Environment:
#include <wincrypt.h>
#include "msquic.h"
_Success_(return != FALSE)
BOOLEAN
CxPlatTlsVerifyCertificate(
_In_ X509* X509Cert,
_In_opt_ const char* SNI,
_In_ QUIC_CREDENTIAL_FLAGS CredFlags
_In_ QUIC_CREDENTIAL_FLAGS CredFlags,
_Out_opt_ uint32_t* PlatformVerificationError
)
{
BOOLEAN Result = FALSE;
@ -93,7 +95,8 @@ CxPlatTlsVerifyCertificate(
CertContext,
SNI,
CertFlags,
IgnoreFlags);
IgnoreFlags,
PlatformVerificationError);
Exit:

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

@ -31,11 +31,31 @@ Environment:
#include "darwin_openssl.c.clog.h"
#endif
static
QUIC_STATUS
CxPlatTlsMapTrustResultToQuicStatus(
_In_ CFIndex ErrorResult
)
{
switch (ErrorResult) {
case errSecCertificateRevoked:
return QUIC_STATUS_REVOKED_CERTIFICATE;
case errSecCertificateExpired:
return QUIC_STATUS_CERT_EXPIRED;
case errSecNotTrusted:
return QUIC_STATUS_CERT_UNTRUSTED_ROOT;
default:
return QUIC_STATUS_TLS_ERROR;
}
}
_Success_(return != FALSE)
BOOLEAN
CxPlatTlsVerifyCertificate(
_In_ X509* X509Cert,
_In_opt_ const char* SNI,
_In_ QUIC_CREDENTIAL_FLAGS CredFlags
_In_ QUIC_CREDENTIAL_FLAGS CredFlags,
_Out_opt_ uint32_t* PlatformVerificationError
)
{
BOOLEAN Result = FALSE;
@ -48,6 +68,7 @@ CxPlatTlsVerifyCertificate(
CFStringRef SNIString = NULL;
SecPolicyRef SSLPolicy = NULL;
SecPolicyRef RevocationPolicy = NULL;
CFErrorRef ErrorRef = NULL;
int OpenSSLCertLength = 0;
OpenSSLCertLength = i2d_X509(X509Cert, &OpenSSLCertBuffer);
@ -144,10 +165,22 @@ CxPlatTlsVerifyCertificate(
goto Exit;
}
Result = SecTrustEvaluateWithError(TrustRef, NULL);
Result = SecTrustEvaluateWithError(TrustRef, &ErrorRef);
if (!Result) {
if (PlatformVerificationError != NULL) {
*PlatformVerificationError =
CxPlatTlsMapTrustResultToQuicStatus(
CFErrorGetCode(ErrorRef));
}
}
Exit:
if (ErrorRef != NULL) {
CFRelease(ErrorRef);
}
if (TrustRef != NULL) {
CFRelease(TrustRef);
}

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

@ -40,15 +40,19 @@ CxPlatTlsExtractPrivateKey(
UNREFERENCED_PARAMETER(X509Cert);
return QUIC_STATUS_NOT_SUPPORTED;
}
_Success_(return != FALSE)
BOOLEAN
CxPlatTlsVerifyCertificate(
_In_ X509* X509Cert,
_In_ const char* SNI,
_In_ QUIC_CREDENTIAL_FLAGS CredFlags
_In_opt_ const char* SNI,
_In_ QUIC_CREDENTIAL_FLAGS CredFlags,
_Out_opt_ uint32_t* PlatformVerificationError
)
{
UNREFERENCED_PARAMETER(X509Cert);
UNREFERENCED_PARAMETER(SNI);
UNREFERENCED_PARAMETER(CredFlags);
UNREFERENCED_PARAMETER(PlatformVerificationError);
return 0;
}

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

@ -275,8 +275,10 @@ Exit:
return Status;
}
static char* QuicTestCertFilename = (char*)"localhost_cert.pem";
static char* QuicTestPrivateKeyFilename = (char*)"localhost_key.pem";
static char* QuicTestServerCertFilename = (char*)"localhost_cert.pem";
static char* QuicTestServerPrivateKeyFilename = (char*)"localhost_key.pem";
static char* QuicTestClientCertFilename = (char*)"client_cert.pem";
static char* QuicTestClientPrivateKeyFilename = (char*)"client_key.pem";
#ifndef MAX_PATH
#define MAX_PATH 50
@ -305,17 +307,25 @@ CxPlatGetSelfSignedCert(
)
{
UNREFERENCED_PARAMETER(Type);
UNREFERENCED_PARAMETER(ClientCertificate);
const char* CertFileName = NULL;
const char* KeyFileName = NULL;
if (ClientCertificate) {
//
// Client certificate is not supported on OpenSSL (yet)
//
QuicTraceEvent(
LibraryError,
"[ lib] ERROR, %s.",
"Client Certificate is not supported in OpenSSL");
return NULL;
#ifdef _WIN32
CertFileName = "msquicopensslclientcert";
KeyFileName = "msquicopensslclientkey";
#else
CertFileName = QuicTestClientCertFilename;
KeyFileName = QuicTestClientPrivateKeyFilename;
#endif
} else {
#ifdef _WIN32
CertFileName = "msquicopensslservercert";
KeyFileName = "msquicopensslserverkey";
#else
CertFileName = QuicTestServerCertFilename;
KeyFileName = QuicTestServerPrivateKeyFilename;
#endif
}
CXPLAT_CREDENTIAL_CONFIG_INTERNAL* Params =
@ -344,7 +354,7 @@ CxPlatGetSelfSignedCert(
UINT TempFileStatus =
GetTempFileNameA(
Params->TempPath,
"msquicopensslcert",
CertFileName,
0,
Params->CertFilepath);
if (TempFileStatus == 0) {
@ -358,7 +368,7 @@ CxPlatGetSelfSignedCert(
TempFileStatus =
GetTempFileNameA(
Params->TempPath,
"msquicopensslkey",
KeyFileName,
0,
Params->PrivateKeyFilepath);
if (TempFileStatus == 0) {
@ -392,8 +402,8 @@ CxPlatGetSelfSignedCert(
1);
CxPlatCopyMemory(
Params->CertFilepath + strlen(Params->TempDir) + 1,
QuicTestCertFilename,
strlen(QuicTestCertFilename));
CertFileName,
strlen(CertFileName));
CxPlatCopyMemory(
Params->PrivateKeyFilepath,
Params->TempDir,
@ -404,15 +414,17 @@ CxPlatGetSelfSignedCert(
1);
CxPlatCopyMemory(
Params->PrivateKeyFilepath + strlen(Params->TempDir) + 1,
QuicTestPrivateKeyFilename,
strlen(QuicTestPrivateKeyFilename));
KeyFileName,
strlen(KeyFileName));
#endif
if (QUIC_FAILED(
CxPlatTlsGenerateSelfSignedCert(
Params->CertFilepath,
Params->PrivateKeyFilepath,
(char *)"localhost"))) {
ClientCertificate ?
(char *)"MsQuicClient":
(char *)"localhost"))) {
goto Error;
}

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

@ -151,6 +151,28 @@ typedef struct CXPLAT_TLS {
//
#define CXPLAT_TLS_DEFAULT_VERIFY_DEPTH 10
static
QUIC_STATUS
CxPlatTlsMapOpenSSLErrorToQuicStatus(
_In_ int OpenSSLError
)
{
switch (OpenSSLError) {
case X509_V_ERR_CERT_REJECTED:
return QUIC_STATUS_BAD_CERTIFICATE;
case X509_V_ERR_CERT_REVOKED:
return QUIC_STATUS_REVOKED_CERTIFICATE;
case X509_V_ERR_CERT_HAS_EXPIRED:
return QUIC_STATUS_CERT_EXPIRED;
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
__fallthrough;
case X509_V_ERR_CERT_UNTRUSTED:
return QUIC_STATUS_CERT_UNTRUSTED_ROOT;
default:
return QUIC_STATUS_TLS_ERROR;
}
}
static
int
CxPlatTlsAlpnSelectCallback(
@ -180,11 +202,13 @@ CxPlatTlsAlpnSelectCallback(
return SSL_TLSEXT_ERR_OK;
}
_Success_(return != FALSE)
BOOLEAN
CxPlatTlsVerifyCertificate(
_In_ X509* X509Cert,
_In_opt_ const char* SNI,
_In_ QUIC_CREDENTIAL_FLAGS CredFlags
_In_ QUIC_CREDENTIAL_FLAGS CredFlags,
_Out_opt_ uint32_t* PlatformVerificationError
);
static
@ -202,28 +226,49 @@ CxPlatTlsCertificateVerifyCallback(
X509* Cert = X509_STORE_CTX_get0_cert(x509_ctx);
SSL *Ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
CXPLAT_TLS* TlsContext = SSL_get_app_data(Ssl);
int ValidationResult = X509_V_OK;
BOOLEAN IsDeferredValidationOrClientAuth =
(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION ||
TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION);
if (!(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_USE_TLS_BUILTIN_CERTIFICATE_VALIDATION)) {
if (Cert == NULL) {
QuicTraceEvent(
TlsError,
"[ tls][%p] ERROR, %s.",
TlsContext->Connection,
"No certificate passed");
X509_STORE_CTX_set_error(x509_ctx, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
return FALSE;
if (TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_CLIENT ||
IsDeferredValidationOrClientAuth) {
if (!(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_USE_TLS_BUILTIN_CERTIFICATE_VALIDATION)) {
if (Cert == NULL) {
QuicTraceEvent(
TlsError,
"[ tls][%p] ERROR, %s.",
TlsContext->Connection,
"No certificate passed");
X509_STORE_CTX_set_error(x509_ctx, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
return FALSE;
}
CertificateVerified =
CxPlatTlsVerifyCertificate(
Cert,
TlsContext->SNI,
TlsContext->SecConfig->Flags,
IsDeferredValidationOrClientAuth?
(uint32_t*)&ValidationResult :
NULL);
if (!CertificateVerified) {
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REJECTED);
}
} else {
CertificateVerified = X509_verify_cert(x509_ctx);
if (IsDeferredValidationOrClientAuth &&
CertificateVerified <= 0) {
ValidationResult =
(int)CxPlatTlsMapOpenSSLErrorToQuicStatus(X509_STORE_CTX_get_error(x509_ctx));
}
}
CertificateVerified = CxPlatTlsVerifyCertificate(Cert, TlsContext->SNI, TlsContext->SecConfig->Flags);
if (!CertificateVerified) {
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REJECTED);
}
} else {
CertificateVerified = X509_verify_cert(x509_ctx);
}
if (!(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION) &&
!(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION) &&
!CertificateVerified) {
QuicTraceEvent(
TlsError,
@ -277,7 +322,7 @@ CxPlatTlsCertificateVerifyCallback(
(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAGS_USE_PORTABLE_CERTIFICATES) ? (QUIC_CERTIFICATE*)&PortableCertificate : (QUIC_CERTIFICATE*)Cert,
(TlsContext->SecConfig->Flags & QUIC_CREDENTIAL_FLAGS_USE_PORTABLE_CERTIFICATES) ? (QUIC_CERTIFICATE_CHAIN*)&PortableChain : (QUIC_CERTIFICATE_CHAIN*)x509_ctx,
0,
0)) {
ValidationResult)) {
QuicTraceEvent(
TlsError,
"[ tls][%p] ERROR, %s.",
@ -831,9 +876,7 @@ CxPlatTlsSecConfigCreate(
return QUIC_STATUS_INVALID_PARAMETER;
}
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_ENABLE_OCSP ||
CredConfigFlags & QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION ||
CredConfigFlags & QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION) {
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_ENABLE_OCSP) {
return QUIC_STATUS_NOT_SUPPORTED; // Not supported by this TLS implementation
}
@ -841,6 +884,11 @@ CxPlatTlsSecConfigCreate(
CredConfigFlags |= QUIC_CREDENTIAL_FLAG_USE_TLS_BUILTIN_CERTIFICATE_VALIDATION;
#endif
if ((CredConfigFlags & QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION) &&
!(CredConfigFlags & QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED)) {
return QUIC_STATUS_INVALID_PARAMETER; // Defer validation without indication doesn't make sense.
}
if ((CredConfigFlags & QUIC_CREDENTIAL_FLAG_USE_TLS_BUILTIN_CERTIFICATE_VALIDATION) &&
(CredConfigFlags & QUIC_CREDENTIAL_FLAG_REVOCATION_CHECK_END_CERT ||
CredConfigFlags & QUIC_CREDENTIAL_FLAG_REVOCATION_CHECK_CHAIN ||
@ -864,44 +912,38 @@ CxPlatTlsSecConfigCreate(
return QUIC_STATUS_INVALID_PARAMETER; // Not currently used and should be NULL.
}
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_CLIENT) {
if (CredConfig->Type != QUIC_CREDENTIAL_TYPE_NONE) {
return QUIC_STATUS_NOT_SUPPORTED; // Not supported for client (yet)
if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE) {
if (CredConfig->CertificateFile == NULL ||
CredConfig->CertificateFile->CertificateFile == NULL ||
CredConfig->CertificateFile->PrivateKeyFile == NULL) {
return QUIC_STATUS_INVALID_PARAMETER;
}
} else {
if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_NONE) {
} else if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE_PROTECTED) {
if (CredConfig->CertificateFileProtected == NULL ||
CredConfig->CertificateFileProtected->CertificateFile == NULL ||
CredConfig->CertificateFileProtected->PrivateKeyFile == NULL ||
CredConfig->CertificateFileProtected->PrivateKeyPassword == NULL) {
return QUIC_STATUS_INVALID_PARAMETER;
}
} else if(CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_PKCS12) {
if (CredConfig->CertificatePkcs12 == NULL ||
CredConfig->CertificatePkcs12->Asn1Blob == NULL ||
CredConfig->CertificatePkcs12->Asn1BlobLength == 0) {
return QUIC_STATUS_INVALID_PARAMETER;
}
} else if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH ||
CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE ||
CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_CONTEXT) { // NOLINT bugprone-branch-clone
#ifndef _WIN32
return QUIC_STATUS_NOT_SUPPORTED; // Only supported on windows.
#endif
// Windows parameters checked later
} else if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_NONE) {
if (!(CredConfigFlags & QUIC_CREDENTIAL_FLAG_CLIENT)) {
return QUIC_STATUS_INVALID_PARAMETER; // Required for server
}
if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE) {
if (CredConfig->CertificateFile == NULL ||
CredConfig->CertificateFile->CertificateFile == NULL ||
CredConfig->CertificateFile->PrivateKeyFile == NULL) {
return QUIC_STATUS_INVALID_PARAMETER;
}
} else if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE_PROTECTED) {
if (CredConfig->CertificateFileProtected == NULL ||
CredConfig->CertificateFileProtected->CertificateFile == NULL ||
CredConfig->CertificateFileProtected->PrivateKeyFile == NULL ||
CredConfig->CertificateFileProtected->PrivateKeyPassword == NULL) {
return QUIC_STATUS_INVALID_PARAMETER;
}
} else if(CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_PKCS12) {
if (CredConfig->CertificatePkcs12 == NULL ||
CredConfig->CertificatePkcs12->Asn1Blob == NULL ||
CredConfig->CertificatePkcs12->Asn1BlobLength == 0) {
return QUIC_STATUS_INVALID_PARAMETER;
}
} else if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH ||
CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE ||
CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_CONTEXT) { // NOLINT bugprone-branch-clone
#ifndef _WIN32
return QUIC_STATUS_NOT_SUPPORTED; // Only supported on windows.
#endif
// Windows parameters checked later
} else {
return QUIC_STATUS_NOT_SUPPORTED;
}
} else {
return QUIC_STATUS_NOT_SUPPORTED;
}
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_SET_ALLOWED_CIPHER_SUITES &&
@ -1157,10 +1199,187 @@ CxPlatTlsSecConfigCreate(
}
}
//
// Set the certs.
//
if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE ||
CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE_PROTECTED) {
if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE_PROTECTED) {
SSL_CTX_set_default_passwd_cb_userdata(
SecurityConfig->SSLCtx, (void*)CredConfig->CertificateFileProtected->PrivateKeyPassword);
}
Ret =
SSL_CTX_use_PrivateKey_file(
SecurityConfig->SSLCtx,
CredConfig->CertificateFile->PrivateKeyFile,
SSL_FILETYPE_PEM);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_certificate_chain_file(
SecurityConfig->SSLCtx,
CredConfig->CertificateFile->CertificateFile);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate_chain_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
} else if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_PKCS12) {
BIO* Bio = BIO_new(BIO_s_mem());
PKCS12 *Pkcs12 = NULL;
if (!Bio) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"BIO_new failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
BIO_set_mem_eof_return(Bio, 0);
BIO_write(Bio, CredConfig->CertificatePkcs12->Asn1Blob, CredConfig->CertificatePkcs12->Asn1BlobLength);
Pkcs12 = d2i_PKCS12_bio(Bio, NULL);
BIO_free(Bio);
Bio = NULL;
if (!Pkcs12) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"d2i_PKCS12_bio failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
STACK_OF(X509) *CaCertificates = NULL;
Ret =
PKCS12_parse(Pkcs12, CredConfig->CertificatePkcs12->PrivateKeyPassword, &PrivateKey, &X509Cert, &CaCertificates);
if (CaCertificates) {
X509* CaCert;
while ((CaCert = sk_X509_pop(CaCertificates)) != NULL) {
//
// This transfers ownership to SSLCtx and CaCert does not need to be freed.
//
SSL_CTX_add_extra_chain_cert(SecurityConfig->SSLCtx, CaCert);
}
}
if (Pkcs12) {
PKCS12_free(Pkcs12);
}
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"PKCS12_parse failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_PrivateKey(
SecurityConfig->SSLCtx,
PrivateKey);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_certificate(
SecurityConfig->SSLCtx,
X509Cert);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
} else if (CredConfig->Type != QUIC_CREDENTIAL_TYPE_NONE) {
Status =
CxPlatTlsExtractPrivateKey(
CredConfig,
&RsaKey,
&X509Cert);
if (QUIC_FAILED(Status)) {
goto Exit;
}
Ret =
SSL_CTX_use_RSAPrivateKey(
SecurityConfig->SSLCtx,
RsaKey);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_RSAPrivateKey_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_certificate(
SecurityConfig->SSLCtx,
X509Cert);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
}
if (CredConfig->Type != QUIC_CREDENTIAL_TYPE_NONE) {
Ret = SSL_CTX_check_private_key(SecurityConfig->SSLCtx);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_check_private_key failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
}
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_CLIENT) {
SSL_CTX_set_cert_verify_callback(SecurityConfig->SSLCtx, CxPlatTlsCertificateVerifyCallback, NULL);
SSL_CTX_set_verify(SecurityConfig->SSLCtx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(SecurityConfig->SSLCtx, CXPLAT_TLS_DEFAULT_VERIFY_DEPTH);
if (!(CredConfigFlags & QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION)) {
SSL_CTX_set_verify_depth(SecurityConfig->SSLCtx, CXPLAT_TLS_DEFAULT_VERIFY_DEPTH);
}
//
// TODO - Support additional certificate validation parameters, such as
@ -1177,181 +1396,30 @@ CxPlatTlsSecConfigCreate(
SSL_CTX_clear_options(SecurityConfig->SSLCtx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
SSL_CTX_set_mode(SecurityConfig->SSLCtx, SSL_MODE_RELEASE_BUFFERS);
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED ||
CredConfigFlags & QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION) {
SSL_CTX_set_cert_verify_callback(
SecurityConfig->SSLCtx,
CxPlatTlsCertificateVerifyCallback,
NULL);
}
if (CredConfigFlags & QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION) {
int VerifyMode = SSL_VERIFY_PEER;
if (!(CredConfigFlags & QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION)) {
VerifyMode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
SSL_CTX_set_verify_depth(
SecurityConfig->SSLCtx,
CXPLAT_TLS_DEFAULT_VERIFY_DEPTH);
}
SSL_CTX_set_verify(
SecurityConfig->SSLCtx,
VerifyMode,
NULL);
}
SSL_CTX_set_alpn_select_cb(SecurityConfig->SSLCtx, CxPlatTlsAlpnSelectCallback, NULL);
//
// Set the server certs.
//
if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE ||
CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE_PROTECTED) {
if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE_PROTECTED) {
SSL_CTX_set_default_passwd_cb_userdata(
SecurityConfig->SSLCtx, (void*)CredConfig->CertificateFileProtected->PrivateKeyPassword);
}
Ret =
SSL_CTX_use_PrivateKey_file(
SecurityConfig->SSLCtx,
CredConfig->CertificateFile->PrivateKeyFile,
SSL_FILETYPE_PEM);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_certificate_chain_file(
SecurityConfig->SSLCtx,
CredConfig->CertificateFile->CertificateFile);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate_chain_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
} else if (CredConfig->Type == QUIC_CREDENTIAL_TYPE_CERTIFICATE_PKCS12) {
BIO* Bio = BIO_new(BIO_s_mem());
PKCS12 *Pkcs12 = NULL;
if (!Bio) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"BIO_new failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
BIO_set_mem_eof_return(Bio, 0);
BIO_write(Bio, CredConfig->CertificatePkcs12->Asn1Blob, CredConfig->CertificatePkcs12->Asn1BlobLength);
Pkcs12 = d2i_PKCS12_bio(Bio, NULL);
BIO_free(Bio);
Bio = NULL;
if (!Pkcs12) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"d2i_PKCS12_bio failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
STACK_OF(X509) *CaCertificates = NULL;
Ret =
PKCS12_parse(Pkcs12, CredConfig->CertificatePkcs12->PrivateKeyPassword, &PrivateKey, &X509Cert, &CaCertificates);
if (CaCertificates) {
X509* CaCert;
while ((CaCert = sk_X509_pop(CaCertificates)) != NULL) {
//
// This transfers ownership to SSLCtx and CaCert does not need to be freed.
//
SSL_CTX_add_extra_chain_cert(SecurityConfig->SSLCtx, CaCert);
}
}
if (Pkcs12) {
PKCS12_free(Pkcs12);
}
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"PKCS12_parse failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_PrivateKey(
SecurityConfig->SSLCtx,
PrivateKey);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_PrivateKey_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_certificate(
SecurityConfig->SSLCtx,
X509Cert);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
} else {
Status =
CxPlatTlsExtractPrivateKey(
CredConfig,
&RsaKey,
&X509Cert);
if (QUIC_FAILED(Status)) {
goto Exit;
}
Ret =
SSL_CTX_use_RSAPrivateKey(
SecurityConfig->SSLCtx,
RsaKey);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_RSAPrivateKey_file failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
Ret =
SSL_CTX_use_certificate(
SecurityConfig->SSLCtx,
X509Cert);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_use_certificate failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
}
Ret = SSL_CTX_check_private_key(SecurityConfig->SSLCtx);
if (Ret != 1) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
ERR_get_error(),
"SSL_CTX_check_private_key failed");
Status = QUIC_STATUS_TLS_ERROR;
goto Exit;
}
SSL_CTX_set_max_early_data(SecurityConfig->SSLCtx, UINT32_MAX);
SSL_CTX_set_client_hello_cb(SecurityConfig->SSLCtx, CxPlatTlsClientHelloCallback, NULL);
}

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

@ -379,6 +379,14 @@ static const GUID CxPlatTlsClientCertPolicyGuid =
{ 0x9b, 0x53, 0xd1, 0x3e, 0xea, 0x4e, 0x9f, 0xb }
};
#ifndef TLS1_ALERT_CLOSE_NOTIFY
#define TLS1_ALERT_CLOSE_NOTIFY 0
#endif
#ifndef TLS1_ALERT_CERTIFICATE_REQUIRED
#define TLS1_ALERT_CERTIFICATE_REQUIRED 116
#endif
typedef struct CXPLAT_SEC_CONFIG {
//
@ -2491,6 +2499,13 @@ CxPlatTlsWriteDataToSchannel(
}
Result |= CXPLAT_TLS_RESULT_ERROR;
}
if (SecStatus == SEC_I_INCOMPLETE_CREDENTIALS &&
State->AlertCode == TLS1_ALERT_CLOSE_NOTIFY) {
//
// Work-around for Schannel sending the wrong TLS alert.
//
State->AlertCode = TLS1_ALERT_CERTIFICATE_REQUIRED;
}
*InBufferLength = 0;
QuicTraceEvent(
TlsErrorStatus,

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

@ -159,11 +159,9 @@ protected:
SelfSignedCertParams = (QUIC_CREDENTIAL_CONFIG*)CxPlatGetSelfSignedCert(CXPLAT_SELF_SIGN_CERT_USER, FALSE);
ASSERT_NE(nullptr, SelfSignedCertParams);
SelfSignedCertParamsFlags = SelfSignedCertParams->Flags;
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
ClientCertParams = (QUIC_CREDENTIAL_CONFIG*)CxPlatGetSelfSignedCert(CXPLAT_SELF_SIGN_CERT_USER, TRUE);
ASSERT_NE(nullptr, ClientCertParams);
ClientCertParams->Flags |= QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION;
#endif
#ifndef QUIC_DISABLE_PFX_TESTS
ASSERT_NE(nullptr, PfxPath);
CertParamsFromFile = (QUIC_CREDENTIAL_CONFIG*)CXPLAT_ALLOC_NONPAGED(sizeof(QUIC_CREDENTIAL_CONFIG), QUIC_POOL_TEST);
@ -184,10 +182,8 @@ protected:
{
CxPlatFreeSelfSignedCert(SelfSignedCertParams);
SelfSignedCertParams = nullptr;
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
CxPlatFreeSelfSignedCert(ClientCertParams);
ClientCertParams = nullptr;
#endif
#ifndef QUIC_DISABLE_PFX_TESTS
if (CertParamsFromFile->CertificatePkcs12->Asn1Blob) {
CXPLAT_FREE(CertParamsFromFile->CertificatePkcs12->Asn1Blob, QUIC_POOL_TEST);
@ -524,7 +520,11 @@ protected:
{
auto Context = (TlsContext*)Connection;
Context->ReceivedPeerCertificate = true;
if (Context->ExpectedErrorFlags != DeferredErrorFlags) {
//
// Only validate the error flags if non-zero. OpenSSL doesn't produce error flags
// so treat 0 flags as unsupported.
//
if (DeferredErrorFlags && Context->ExpectedErrorFlags != DeferredErrorFlags) {
std::cout << "Incorrect ErrorFlags: " << DeferredErrorFlags << "\n";
return FALSE;
}
@ -1272,7 +1272,6 @@ TEST_F(TlsTest, CertificateError)
}
}
#ifndef QUIC_DISABLE_DEFERRED_CERT_TESTS
TEST_F(TlsTest, DeferredCertificateValidationAllow)
{
CxPlatClientSecConfig ClientConfig(
@ -1325,7 +1324,6 @@ TEST_F(TlsTest, DeferredCertificateValidationReject)
ASSERT_EQ((0xFF & ClientContext.State.AlertCode), CXPLAT_TLS_ALERT_CODE_BAD_CERTIFICATE);
}
}
#endif // QUIC_DISABLE_DEFERRED_CERT_TESTS
TEST_F(TlsTest, CustomCertificateValidationAllow)
{
@ -1709,7 +1707,6 @@ TEST_F(TlsTest, LockPerfTest)
#endif
}
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
TEST_F(TlsTest, ClientCertificateFailValidation)
{
CxPlatSecConfig ClientConfig;
@ -1735,7 +1732,6 @@ TEST_F(TlsTest, ClientCertificateDeferValidation)
ServerContext.ExpectedValidationStatus = QUIC_STATUS_CERT_UNTRUSTED_ROOT;
DoHandshake(ServerContext, ClientContext);
}
#endif
TEST_F(TlsTest, CipherSuiteSuccess1)
{
@ -1908,7 +1904,7 @@ ValidateSecConfigStatusSchannel(
TEST_F(TlsTest, PlatformSpecificFlagsSchannel)
{
for (auto TestFlag : { QUIC_CREDENTIAL_FLAG_ENABLE_OCSP, QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION,
for (auto TestFlag : { QUIC_CREDENTIAL_FLAG_ENABLE_OCSP,
#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,
@ -1916,7 +1912,7 @@ TEST_F(TlsTest, PlatformSpecificFlagsSchannel)
QUIC_CREDENTIAL_FLAG_REVOCATION_CHECK_CHAIN,
#endif
#endif
(QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION | QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED) }) {
}) {
QUIC_STATUS Status;

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

@ -34,7 +34,6 @@ public:
FALSE
)) != nullptr);
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
ASSERT_TRUE((ClientCertParams =
CxPlatGetSelfSignedCert(
TestingKernelMode ?
@ -42,7 +41,7 @@ public:
CXPLAT_SELF_SIGN_CERT_USER,
TRUE
)) != nullptr);
#endif
if (TestingKernelMode) {
printf("Initializing for Kernel Mode tests\n");
const char* DriverName;
@ -77,10 +76,8 @@ public:
QUIC_CREDENTIAL_FLAG_REQUIRE_CLIENT_AUTHENTICATION |
QUIC_CREDENTIAL_FLAG_DEFER_CERTIFICATE_VALIDATION |
QUIC_CREDENTIAL_FLAG_INDICATE_CERTIFICATE_RECEIVED;
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
memcpy(&ClientCertCredConfig, ClientCertParams, sizeof(QUIC_CREDENTIAL_CONFIG));
ClientCertCredConfig.Flags |= QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION;
#endif
QuicTestInitialize();
}
}
@ -93,9 +90,8 @@ public:
delete MsQuic;
}
CxPlatFreeSelfSignedCert(SelfSignedCertParams);
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
CxPlatFreeSelfSignedCert(ClientCertParams);
#endif
CxPlatUninitialize();
CxPlatSystemUnload();
}
@ -691,7 +687,6 @@ TEST_P(WithHandshakeArgs5, CustomCertificateValidation) {
}
}
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
TEST_P(WithHandshakeArgs6, ConnectClientCertificate) {
TestLoggerT<ParamType> Logger("QuicTestConnectClientCertificate", GetParam());
if (TestingKernelMode) {
@ -704,7 +699,6 @@ TEST_P(WithHandshakeArgs6, ConnectClientCertificate) {
QuicTestConnectClientCertificate(GetParam().Family, GetParam().UseClientCertificate);
}
}
#endif
#if QUIC_TEST_FAILING_TEST_CERTIFICATES
TEST(CredValidation, ConnectExpiredServerCertificate) {
@ -1613,15 +1607,11 @@ INSTANTIATE_TEST_SUITE_P(
WithHandshakeArgs5,
testing::ValuesIn(HandshakeArgs5::Generate()));
#ifndef QUIC_DISABLE_CLIENT_CERT_TESTS
INSTANTIATE_TEST_SUITE_P(
Handshake,
WithHandshakeArgs6,
testing::ValuesIn(HandshakeArgs6::Generate()));
#endif
INSTANTIATE_TEST_SUITE_P(
AppData,
WithSendArgs1,

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

@ -2113,13 +2113,16 @@ QuicTestConnectClientCertificate(
UniquePtr<TestConnection> Server;
ServerAcceptContext ServerAcceptCtx((TestConnection**)&Server);
ServerAcceptCtx.ExpectedClientCertValidationResult = QUIC_STATUS_CERT_UNTRUSTED_ROOT;
if (!UseClientCertificate) {
ServerAcceptCtx.ExpectedTransportCloseStatus = QUIC_STATUS_REQUIRED_CERTIFICATE;
}
Listener.Context = &ServerAcceptCtx;
{
TestConnection Client(Registration);
TEST_TRUE(Client.IsValid());
if (!UseClientCertificate) {
Client.SetExpectedTransportCloseStatus(QUIC_STATUS_CLOSE_NOTIFY);
Client.SetExpectedTransportCloseStatus(QUIC_STATUS_REQUIRED_CERTIFICATE);
}
TEST_QUIC_SUCCEEDED(
@ -2133,15 +2136,12 @@ QuicTestConnectClientCertificate(
if (!Client.WaitForConnectionComplete()) {
return;
}
TEST_EQUAL(UseClientCertificate, Client.GetIsConnected());
TEST_NOT_EQUAL(nullptr, Server);
if (UseClientCertificate) {
if (!Server->WaitForConnectionComplete()) {
return;
}
} else {
Server->SetExpectedTransportCloseStatus(QUIC_STATUS_CLOSE_NOTIFY);
}
TEST_EQUAL(UseClientCertificate, Server->GetIsConnected());
}