Skip to content

Commit b09b747

Browse files
committed
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
1 parent c207e2d commit b09b747

3 files changed

Lines changed: 244 additions & 25 deletions

File tree

src/internal.c

Lines changed: 172 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,6 +2915,12 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
29152915
ctx->x509Chain = NULL;
29162916
}
29172917
#endif
2918+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
2919+
if (ctx->testTrustedCAs != NULL) {
2920+
CFRelease(ctx->testTrustedCAs);
2921+
ctx->testTrustedCAs = NULL;
2922+
}
2923+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
29182924
#endif /* !NO_CERTS */
29192925

29202926
#ifdef HAVE_TLS_EXTENSIONS
@@ -42729,6 +42735,79 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
4272942735
return secCert;
4273042736
}
4273142737

42738+
static int DisplaySecTrustError(CFErrorRef error, SecTrustRef trust)
42739+
{
42740+
CFStringRef desc;
42741+
CFStringRef domain;
42742+
SecTrustResultType trustResult;
42743+
CFDictionaryRef info;
42744+
42745+
/* Description */
42746+
desc = CFErrorCopyDescription(error);
42747+
if (desc) {
42748+
char buffer[256];
42749+
if (CFStringGetCString(desc, buffer, sizeof(buffer),
42750+
kCFStringEncodingUTF8)) {
42751+
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Error description: %s\n",
42752+
buffer);
42753+
}
42754+
CFRelease(desc);
42755+
}
42756+
42757+
/* Domain */
42758+
domain = CFErrorGetDomain(error);
42759+
if (domain) {
42760+
char domainStr[128];
42761+
if (CFStringGetCString(domain, domainStr, sizeof(domainStr),
42762+
kCFStringEncodingUTF8)) {
42763+
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Domain: %s\n", domainStr);
42764+
}
42765+
}
42766+
42767+
/* Get additional trust result info */
42768+
if (SecTrustGetTrustResult(trust, &trustResult) == errSecSuccess) {
42769+
WOLFSSL_MSG_EX("SecTrustResultType: %d\n", trustResult);
42770+
/* Optional: decode the enum */
42771+
switch (trustResult) {
42772+
case kSecTrustResultInvalid:
42773+
WOLFSSL_MSG("TrustResult: Invalid\n");
42774+
break;
42775+
case kSecTrustResultProceed:
42776+
WOLFSSL_MSG("TrustResult: Proceed\n");
42777+
break;
42778+
case kSecTrustResultDeny:
42779+
WOLFSSL_MSG("TrustResult: Deny\n");
42780+
break;
42781+
case kSecTrustResultUnspecified:
42782+
WOLFSSL_MSG("TrustResult: Unspecified (implicitly trusted)\n");
42783+
break;
42784+
case kSecTrustResultRecoverableTrustFailure:
42785+
WOLFSSL_MSG("TrustResult: Recoverable trust failure\n");
42786+
break;
42787+
case kSecTrustResultFatalTrustFailure:
42788+
WOLFSSL_MSG("TrustResult: Fatal trust failure\n");
42789+
break;
42790+
case kSecTrustResultOtherError:
42791+
WOLFSSL_MSG("TrustResult: Other error\n");
42792+
break;
42793+
default:
42794+
WOLFSSL_MSG("TrustResult: Unknown\n");
42795+
break;
42796+
}
42797+
}
42798+
else {
42799+
WOLFSSL_MSG("SecTrustGetTrustResult failed\n");
42800+
}
42801+
42802+
info = CFErrorCopyUserInfo(error);
42803+
if (info) {
42804+
printf("Trust error info dump:\n");
42805+
CFShow(info);
42806+
CFRelease(info);
42807+
}
42808+
42809+
return 0;
42810+
}
4273242811

4273342812
/*
4273442813
* Validates a chain of certificates using the Apple system trust APIs
@@ -42745,13 +42824,13 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
4274542824
* wolfSSL's built-in certificate validation mechanisms anymore. We instead
4274642825
* must call into the Security Framework APIs to authenticate peer certificates
4274742826
*/
42748-
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
42749-
const WOLFSSL_BUFFER_INFO* certs,
42750-
int totalCerts)
42827+
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
42828+
const WOLFSSL_BUFFER_INFO* certs,
42829+
int totalCerts)
4275142830
{
42752-
int i;
42753-
int ret;
42754-
OSStatus status;
42831+
int i;
42832+
int ret;
42833+
OSStatus status;
4275542834
CFMutableArrayRef certArray = NULL;
4275642835
SecCertificateRef secCert = NULL;
4275742836
SecTrustRef trust = NULL;
@@ -42760,8 +42839,7 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4276042839

4276142840
WOLFSSL_ENTER("DoAppleNativeCertValidation");
4276242841

42763-
certArray = CFArrayCreateMutable(kCFAllocatorDefault,
42764-
totalCerts,
42842+
certArray = CFArrayCreateMutable(kCFAllocatorDefault, totalCerts,
4276542843
&kCFTypeArrayCallBacks);
4276642844
if (!certArray) {
4276742845
WOLFSSL_MSG("Error: can't allocate CFArray for certificates");
@@ -42770,8 +42848,8 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4277042848
}
4277142849

4277242850
for (i = 0; i < totalCerts; i++) {
42773-
secCert = ConvertToSecCertificateRef(certs[i].buffer,
42774-
(int)certs[i].length);
42851+
secCert =
42852+
ConvertToSecCertificateRef(certs[i].buffer, (int)certs[i].length);
4277542853
if (!secCert) {
4277642854
WOLFSSL_MSG("Error: can't convert DER cert to SecCertificateRef");
4277742855
ret = 0;
@@ -42785,35 +42863,74 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4278542863
}
4278642864

4278742865
/* Create trust object for SecCertifiate Ref */
42788-
if (ssl->buffers.domainName.buffer &&
42789-
ssl->buffers.domainName.length > 0) {
42866+
if (ssl->buffers.domainName.buffer && ssl->buffers.domainName.length > 0) {
4279042867
/* Create policy with specified value to require host name match */
42791-
hostname = CFStringCreateWithCString(kCFAllocatorDefault,
42792-
(const char*)ssl->buffers.domainName.buffer,
42793-
kCFStringEncodingUTF8);
42868+
hostname = CFStringCreateWithCString(
42869+
kCFAllocatorDefault, (const char*)ssl->buffers.domainName.buffer,
42870+
kCFStringEncodingUTF8);
4279442871
}
4279542872
if (hostname != NULL) {
4279642873
policy = SecPolicyCreateSSL(true, hostname);
42797-
} else {
42874+
}
42875+
else {
4279842876
policy = SecPolicyCreateSSL(true, NULL);
4279942877
}
4280042878
status = SecTrustCreateWithCertificates(certArray, policy, &trust);
4280142879
if (status != errSecSuccess) {
4280242880
WOLFSSL_MSG_EX("Error creating trust object, "
42803-
"SecTrustCreateWithCertificates returned %d",status);
42881+
"SecTrustCreateWithCertificates returned %d",
42882+
status);
4280442883
ret = 0;
4280542884
goto cleanup;
4280642885
}
4280742886

42887+
#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
42888+
/* TEST ONLY CODE:
42889+
* Set accumulated list of trusted CA certificates as trust anchors */
42890+
if (ssl->ctx->testTrustedCAs != NULL) {
42891+
status = SecTrustSetAnchorCertificates(trust, ssl->ctx->testTrustedCAs);
42892+
if (status != errSecSuccess) {
42893+
WOLFSSL_MSG_EX("Error setting anchor certificates: %d", status);
42894+
ret = 0;
42895+
goto cleanup;
42896+
}
42897+
}
42898+
#endif
42899+
4280842900
/* Evaluate the certificate's authenticity */
42809-
if (SecTrustEvaluateWithError(trust, NULL) == 1) {
42810-
WOLFSSL_MSG("Cert chain is trusted");
42811-
ret = 1;
42901+
WOLFSSL_MSG("Performing Apple native cert validation via "
42902+
"SecTrustEvaluateWithError");
42903+
CFErrorRef error = NULL;
42904+
ret = SecTrustEvaluateWithError(trust, &error);
42905+
if (ret != 1) {
42906+
if (error) {
42907+
CFIndex code;
42908+
code = CFErrorGetCode(error);
42909+
WOLFSSL_MSG_EX("SecTrustEvaluateWithError failed with code: %ld\n",
42910+
code);
42911+
DisplaySecTrustError(error, trust);
42912+
42913+
#if WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
42914+
/* TEST ONLY CODE:
42915+
* wolfSSL API tests use a cert with a validity period that is too
42916+
* long for the Apple system trust APIs
42917+
* (See: https://support.apple.com/en-us/103769)
42918+
* therefore we should skip over this particular error */
42919+
if (code == errSecCertificateValidityPeriodTooLong) {
42920+
WOLFSSL_MSG("Skipping certificate validity period error");
42921+
ret = 1;
42922+
}
42923+
#endif
42924+
42925+
CFRelease(error);
42926+
}
42927+
else {
42928+
WOLFSSL_MSG(
42929+
"SecTrustEvaluateWithError failed with unknown error.\n");
42930+
}
4281242931
}
4281342932
else {
42814-
WOLFSSL_MSG("Cert chain trust evaluation failed"
42815-
"SecTrustEvaluateWithError returned 0");
42816-
ret = 0;
42933+
WOLFSSL_MSG("SecTrustEvaluateWithError succeeded");
4281742934
}
4281842935

4281942936
/* Cleanup */
@@ -42835,6 +42952,38 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4283542952

4283642953
return ret;
4283742954
}
42955+
42956+
#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
42957+
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
42958+
const byte* derCert,
42959+
int derLen)
42960+
{
42961+
SecCertificateRef certRef;
42962+
42963+
if (derCert == NULL || derLen == 0) {
42964+
return WOLFSSL_FAILURE;
42965+
}
42966+
42967+
/* Create the base array for trust anchors if it doesn't exist */
42968+
if (ctx->testTrustedCAs == NULL) {
42969+
ctx->testTrustedCAs =
42970+
CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
42971+
if (!ctx->testTrustedCAs) {
42972+
return WOLFSSL_FAILURE;
42973+
}
42974+
}
42975+
42976+
certRef = ConvertToSecCertificateRef(derCert, derLen);
42977+
if (!certRef) {
42978+
return false;
42979+
}
42980+
42981+
CFArrayAppendValue(ctx->testTrustedCAs, certRef);
42982+
CFRelease(certRef);
42983+
return WOLFSSL_SUCCESS;
42984+
}
42985+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
42986+
4283842987
#endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
4283942988

4284042989
#undef ERROR_OUT

src/ssl_load.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,14 @@
4242
#endif
4343
#endif
4444

45-
#if defined(__APPLE__) && defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
45+
#if defined(__APPLE__)
46+
#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
4647
#include <Security/SecTrustSettings.h>
47-
#endif
48+
#endif /* HAVE_SECURITY_SECTRUSTSETTINGS_H */
49+
#if WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
50+
#include <CoreFoundation/CoreFoundation.h>
51+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
52+
#endif /* __APPLE__ */
4853

4954
#endif /* WOLFSSL_SYS_CA_CERTS */
5055

@@ -2153,8 +2158,40 @@ static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,
21532158

21542159
/* CA certificate to verify with. */
21552160
if (type == CA_TYPE) {
2161+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
2162+
word32 derLen;
2163+
byte* derBuf;
2164+
if (ctx->doAppleNativeCertValidationFlag == 1) {
2165+
derLen = der->length;
2166+
derBuf = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2167+
if (derBuf == NULL) {
2168+
return MEMORY_E;
2169+
}
2170+
XMEMCPY(derBuf, der->buffer, derLen);
2171+
}
2172+
else {
2173+
(void)derLen;
2174+
(void)derBuf;
2175+
}
2176+
#endif
21562177
/* verify CA unless user set to no verify */
21572178
ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify);
2179+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
2180+
if (ret == 1 && ctx->doAppleNativeCertValidationFlag == 1) {
2181+
WOLFSSL_MSG("Appending CA to cert list for native cert validation test");
2182+
ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf, (int)derLen);
2183+
if (ret == WOLFSSL_SUCCESS) {
2184+
WOLFSSL_MSG("Clearing CA table for native cert validation test");
2185+
/* Clear the CA table so we can ensure they won't be used for
2186+
* verification */
2187+
ret = wolfSSL_CertManagerUnloadCAs(ctx->cm);
2188+
if (ret == WOLFSSL_SUCCESS) {
2189+
ret = 0;
2190+
}
2191+
}
2192+
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2193+
}
2194+
#endif /* !WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
21582195
if (ret == 1) {
21592196
ret = 0;
21602197
}
@@ -2978,6 +3015,12 @@ int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
29783015
ret = NOT_COMPILED_IN;
29793016
(void)flags;
29803017
#endif
3018+
3019+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
3020+
if (ret == 1) {
3021+
wolfSSL_CTX_load_system_CA_certs(ctx);
3022+
}
3023+
#endif
29813024
}
29823025

29833026
return ret;
@@ -3422,6 +3465,12 @@ int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
34223465
GET_VERIFY_SETTING_CTX(ctx));
34233466
}
34243467

3468+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
3469+
if (ret == 1) {
3470+
wolfSSL_CTX_load_system_CA_certs(ctx);
3471+
}
3472+
#endif
3473+
34253474
/* Return 1 on success or 0 on failure. */
34263475
return WS_RC(ret);
34273476
}
@@ -3950,6 +3999,12 @@ int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, const unsigned char* in,
39503999
}
39514000
#endif
39524001

4002+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
4003+
if (ret == 1) {
4004+
wolfSSL_CTX_load_system_CA_certs(ctx);
4005+
}
4006+
#endif
4007+
39534008
WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret);
39544009
return ret;
39554010
}

wolfssl/internal.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@
300300
#include <wolfssl/sniffer.h>
301301
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
302302

303+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
304+
#include <CoreFoundation/CoreFoundation.h>
305+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
306+
303307
#ifdef __cplusplus
304308
extern "C" {
305309
#endif
@@ -4234,6 +4238,10 @@ struct WOLFSSL_CTX {
42344238
#if defined(WOLFSSL_SYS_CRYPTO_POLICY)
42354239
int secLevel; /* The security level of system-wide crypto policy. */
42364240
#endif /* WOLFSSL_SYS_CRYPTO_POLICY */
4241+
4242+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
4243+
CFMutableArrayRef testTrustedCAs;
4244+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
42374245
};
42384246

42394247
WOLFSSL_LOCAL
@@ -4270,6 +4278,13 @@ int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
42704278
#endif
42714279
#endif
42724280

4281+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
4282+
WOLFSSL_API
4283+
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
4284+
const byte* derCert,
4285+
int derLen);
4286+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
4287+
42734288
/* All cipher suite related info
42744289
* Keep as a constant size (no ifdefs) for session export */
42754290
typedef struct CipherSpecs {

0 commit comments

Comments
 (0)