mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2025-07-31 19:24:42 +02:00
Apple native cert validation: add WOLFSSL_TEST_APPLE_CERT_VALIDATION feature macro that forces system CA certs on and makes all CA certs added to CM via xxx_load_verify_xxx APIs to instead be loaded as system trust anchors when used for TLS cert verification
This commit is contained in:
195
src/internal.c
195
src/internal.c
@@ -2915,6 +2915,12 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
|
||||
ctx->x509Chain = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
if (ctx->testTrustedCAs != NULL) {
|
||||
CFRelease(ctx->testTrustedCAs);
|
||||
ctx->testTrustedCAs = NULL;
|
||||
}
|
||||
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
||||
#endif /* !NO_CERTS */
|
||||
|
||||
#ifdef HAVE_TLS_EXTENSIONS
|
||||
@@ -42777,6 +42783,79 @@ cleanup:
|
||||
return secCert;
|
||||
}
|
||||
|
||||
static int DisplaySecTrustError(CFErrorRef error, SecTrustRef trust)
|
||||
{
|
||||
CFStringRef desc;
|
||||
CFStringRef domain;
|
||||
SecTrustResultType trustResult;
|
||||
CFDictionaryRef info;
|
||||
|
||||
/* Description */
|
||||
desc = CFErrorCopyDescription(error);
|
||||
if (desc) {
|
||||
char buffer[256];
|
||||
if (CFStringGetCString(desc, buffer, sizeof(buffer),
|
||||
kCFStringEncodingUTF8)) {
|
||||
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Error description: %s\n",
|
||||
buffer);
|
||||
}
|
||||
CFRelease(desc);
|
||||
}
|
||||
|
||||
/* Domain */
|
||||
domain = CFErrorGetDomain(error);
|
||||
if (domain) {
|
||||
char domainStr[128];
|
||||
if (CFStringGetCString(domain, domainStr, sizeof(domainStr),
|
||||
kCFStringEncodingUTF8)) {
|
||||
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Domain: %s\n", domainStr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get additional trust result info */
|
||||
if (SecTrustGetTrustResult(trust, &trustResult) == errSecSuccess) {
|
||||
WOLFSSL_MSG_EX("SecTrustResultType: %d\n", trustResult);
|
||||
/* Optional: decode the enum */
|
||||
switch (trustResult) {
|
||||
case kSecTrustResultInvalid:
|
||||
WOLFSSL_MSG("TrustResult: Invalid\n");
|
||||
break;
|
||||
case kSecTrustResultProceed:
|
||||
WOLFSSL_MSG("TrustResult: Proceed\n");
|
||||
break;
|
||||
case kSecTrustResultDeny:
|
||||
WOLFSSL_MSG("TrustResult: Deny\n");
|
||||
break;
|
||||
case kSecTrustResultUnspecified:
|
||||
WOLFSSL_MSG("TrustResult: Unspecified (implicitly trusted)\n");
|
||||
break;
|
||||
case kSecTrustResultRecoverableTrustFailure:
|
||||
WOLFSSL_MSG("TrustResult: Recoverable trust failure\n");
|
||||
break;
|
||||
case kSecTrustResultFatalTrustFailure:
|
||||
WOLFSSL_MSG("TrustResult: Fatal trust failure\n");
|
||||
break;
|
||||
case kSecTrustResultOtherError:
|
||||
WOLFSSL_MSG("TrustResult: Other error\n");
|
||||
break;
|
||||
default:
|
||||
WOLFSSL_MSG("TrustResult: Unknown\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("SecTrustGetTrustResult failed\n");
|
||||
}
|
||||
|
||||
info = CFErrorCopyUserInfo(error);
|
||||
if (info) {
|
||||
printf("Trust error info dump:\n");
|
||||
CFShow(info);
|
||||
CFRelease(info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validates a chain of certificates using the Apple system trust APIs
|
||||
@@ -42793,13 +42872,13 @@ cleanup:
|
||||
* wolfSSL's built-in certificate validation mechanisms anymore. We instead
|
||||
* must call into the Security Framework APIs to authenticate peer certificates
|
||||
*/
|
||||
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
|
||||
const WOLFSSL_BUFFER_INFO* certs,
|
||||
int totalCerts)
|
||||
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
|
||||
const WOLFSSL_BUFFER_INFO* certs,
|
||||
int totalCerts)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
OSStatus status;
|
||||
int i;
|
||||
int ret;
|
||||
OSStatus status;
|
||||
CFMutableArrayRef certArray = NULL;
|
||||
SecCertificateRef secCert = NULL;
|
||||
SecTrustRef trust = NULL;
|
||||
@@ -42808,8 +42887,7 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
|
||||
|
||||
WOLFSSL_ENTER("DoAppleNativeCertValidation");
|
||||
|
||||
certArray = CFArrayCreateMutable(kCFAllocatorDefault,
|
||||
totalCerts,
|
||||
certArray = CFArrayCreateMutable(kCFAllocatorDefault, totalCerts,
|
||||
&kCFTypeArrayCallBacks);
|
||||
if (!certArray) {
|
||||
WOLFSSL_MSG("Error: can't allocate CFArray for certificates");
|
||||
@@ -42818,8 +42896,8 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
|
||||
}
|
||||
|
||||
for (i = 0; i < totalCerts; i++) {
|
||||
secCert = ConvertToSecCertificateRef(certs[i].buffer,
|
||||
(int)certs[i].length);
|
||||
secCert =
|
||||
ConvertToSecCertificateRef(certs[i].buffer, (int)certs[i].length);
|
||||
if (!secCert) {
|
||||
WOLFSSL_MSG("Error: can't convert DER cert to SecCertificateRef");
|
||||
ret = 0;
|
||||
@@ -42833,35 +42911,74 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
|
||||
}
|
||||
|
||||
/* Create trust object for SecCertifiate Ref */
|
||||
if (ssl->buffers.domainName.buffer &&
|
||||
ssl->buffers.domainName.length > 0) {
|
||||
if (ssl->buffers.domainName.buffer && ssl->buffers.domainName.length > 0) {
|
||||
/* Create policy with specified value to require host name match */
|
||||
hostname = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
(const char*)ssl->buffers.domainName.buffer,
|
||||
kCFStringEncodingUTF8);
|
||||
hostname = CFStringCreateWithCString(
|
||||
kCFAllocatorDefault, (const char*)ssl->buffers.domainName.buffer,
|
||||
kCFStringEncodingUTF8);
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
policy = SecPolicyCreateSSL(true, hostname);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
policy = SecPolicyCreateSSL(true, NULL);
|
||||
}
|
||||
status = SecTrustCreateWithCertificates(certArray, policy, &trust);
|
||||
if (status != errSecSuccess) {
|
||||
WOLFSSL_MSG_EX("Error creating trust object, "
|
||||
"SecTrustCreateWithCertificates returned %d",status);
|
||||
"SecTrustCreateWithCertificates returned %d",
|
||||
status);
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
|
||||
/* TEST ONLY CODE:
|
||||
* Set accumulated list of trusted CA certificates as trust anchors */
|
||||
if (ssl->ctx->testTrustedCAs != NULL) {
|
||||
status = SecTrustSetAnchorCertificates(trust, ssl->ctx->testTrustedCAs);
|
||||
if (status != errSecSuccess) {
|
||||
WOLFSSL_MSG_EX("Error setting anchor certificates: %d", status);
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Evaluate the certificate's authenticity */
|
||||
if (SecTrustEvaluateWithError(trust, NULL) == 1) {
|
||||
WOLFSSL_MSG("Cert chain is trusted");
|
||||
ret = 1;
|
||||
WOLFSSL_MSG("Performing Apple native cert validation via "
|
||||
"SecTrustEvaluateWithError");
|
||||
CFErrorRef error = NULL;
|
||||
ret = SecTrustEvaluateWithError(trust, &error);
|
||||
if (ret != 1) {
|
||||
if (error) {
|
||||
CFIndex code;
|
||||
code = CFErrorGetCode(error);
|
||||
WOLFSSL_MSG_EX("SecTrustEvaluateWithError failed with code: %ld\n",
|
||||
code);
|
||||
DisplaySecTrustError(error, trust);
|
||||
|
||||
#if WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
/* TEST ONLY CODE:
|
||||
* wolfSSL API tests use a cert with a validity period that is too
|
||||
* long for the Apple system trust APIs
|
||||
* (See: https://support.apple.com/en-us/103769)
|
||||
* therefore we should skip over this particular error */
|
||||
if (code == errSecCertificateValidityPeriodTooLong) {
|
||||
WOLFSSL_MSG("Skipping certificate validity period error");
|
||||
ret = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
CFRelease(error);
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG(
|
||||
"SecTrustEvaluateWithError failed with unknown error.\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Cert chain trust evaluation failed"
|
||||
"SecTrustEvaluateWithError returned 0");
|
||||
ret = 0;
|
||||
WOLFSSL_MSG("SecTrustEvaluateWithError succeeded");
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
@@ -42883,6 +43000,38 @@ cleanup:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
|
||||
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
|
||||
const byte* derCert,
|
||||
int derLen)
|
||||
{
|
||||
SecCertificateRef certRef;
|
||||
|
||||
if (derCert == NULL || derLen == 0) {
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
/* Create the base array for trust anchors if it doesn't exist */
|
||||
if (ctx->testTrustedCAs == NULL) {
|
||||
ctx->testTrustedCAs =
|
||||
CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
|
||||
if (!ctx->testTrustedCAs) {
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
certRef = ConvertToSecCertificateRef(derCert, derLen);
|
||||
if (!certRef) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CFArrayAppendValue(ctx->testTrustedCAs, certRef);
|
||||
CFRelease(certRef);
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
||||
|
||||
#endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
|
||||
|
||||
#undef ERROR_OUT
|
||||
|
@@ -42,9 +42,14 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
|
||||
#if defined(__APPLE__)
|
||||
#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
|
||||
#include <Security/SecTrustSettings.h>
|
||||
#endif
|
||||
#endif /* HAVE_SECURITY_SECTRUSTSETTINGS_H */
|
||||
#if WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#endif /* WOLFSSL_SYS_CA_CERTS */
|
||||
|
||||
@@ -2153,8 +2158,40 @@ static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
|
||||
|
||||
/* CA certificate to verify with. */
|
||||
if (type == CA_TYPE) {
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
word32 derLen;
|
||||
byte* derBuf;
|
||||
if (ctx->doAppleNativeCertValidationFlag == 1) {
|
||||
derLen = der->length;
|
||||
derBuf = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (derBuf == NULL) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
XMEMCPY(derBuf, der->buffer, derLen);
|
||||
}
|
||||
else {
|
||||
(void)derLen;
|
||||
(void)derBuf;
|
||||
}
|
||||
#endif
|
||||
/* verify CA unless user set to no verify */
|
||||
ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify);
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
if (ret == 1 && ctx->doAppleNativeCertValidationFlag == 1) {
|
||||
WOLFSSL_MSG("Appending CA to cert list for native cert validation test");
|
||||
ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf, (int)derLen);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
WOLFSSL_MSG("Clearing CA table for native cert validation test");
|
||||
/* Clear the CA table so we can ensure they won't be used for
|
||||
* verification */
|
||||
ret = wolfSSL_CertManagerUnloadCAs(ctx->cm);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
#endif /* !WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
||||
if (ret == 1) {
|
||||
ret = 0;
|
||||
}
|
||||
@@ -2978,6 +3015,12 @@ int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
|
||||
ret = NOT_COMPILED_IN;
|
||||
(void)flags;
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
if (ret == 1) {
|
||||
wolfSSL_CTX_load_system_CA_certs(ctx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -3422,6 +3465,12 @@ int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
|
||||
GET_VERIFY_SETTING_CTX(ctx));
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
if (ret == 1) {
|
||||
wolfSSL_CTX_load_system_CA_certs(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 on success or 0 on failure. */
|
||||
return WS_RC(ret);
|
||||
}
|
||||
@@ -3950,6 +3999,12 @@ int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, const unsigned char* in,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
if (ret == 1) {
|
||||
wolfSSL_CTX_load_system_CA_certs(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -300,6 +300,10 @@
|
||||
#include <wolfssl/sniffer.h>
|
||||
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
|
||||
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -4242,6 +4246,10 @@ struct WOLFSSL_CTX {
|
||||
#if defined(WOLFSSL_SYS_CRYPTO_POLICY)
|
||||
int secLevel; /* The security level of system-wide crypto policy. */
|
||||
#endif /* WOLFSSL_SYS_CRYPTO_POLICY */
|
||||
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
CFMutableArrayRef testTrustedCAs;
|
||||
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
||||
};
|
||||
|
||||
WOLFSSL_LOCAL
|
||||
@@ -4278,6 +4286,13 @@ int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
|
||||
WOLFSSL_API
|
||||
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
|
||||
const byte* derCert,
|
||||
int derLen);
|
||||
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
||||
|
||||
/* All cipher suite related info
|
||||
* Keep as a constant size (no ifdefs) for session export */
|
||||
typedef struct CipherSpecs {
|
||||
|
Reference in New Issue
Block a user