Skip to content

Commit 7232b3a

Browse files
bigbrettrlm2002
authored andcommitted
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 981ba4b commit 7232b3a

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
@@ -42777,6 +42783,79 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
4277742783
return secCert;
4277842784
}
4277942785

42786+
static int DisplaySecTrustError(CFErrorRef error, SecTrustRef trust)
42787+
{
42788+
CFStringRef desc;
42789+
CFStringRef domain;
42790+
SecTrustResultType trustResult;
42791+
CFDictionaryRef info;
42792+
42793+
/* Description */
42794+
desc = CFErrorCopyDescription(error);
42795+
if (desc) {
42796+
char buffer[256];
42797+
if (CFStringGetCString(desc, buffer, sizeof(buffer),
42798+
kCFStringEncodingUTF8)) {
42799+
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Error description: %s\n",
42800+
buffer);
42801+
}
42802+
CFRelease(desc);
42803+
}
42804+
42805+
/* Domain */
42806+
domain = CFErrorGetDomain(error);
42807+
if (domain) {
42808+
char domainStr[128];
42809+
if (CFStringGetCString(domain, domainStr, sizeof(domainStr),
42810+
kCFStringEncodingUTF8)) {
42811+
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Domain: %s\n", domainStr);
42812+
}
42813+
}
42814+
42815+
/* Get additional trust result info */
42816+
if (SecTrustGetTrustResult(trust, &trustResult) == errSecSuccess) {
42817+
WOLFSSL_MSG_EX("SecTrustResultType: %d\n", trustResult);
42818+
/* Optional: decode the enum */
42819+
switch (trustResult) {
42820+
case kSecTrustResultInvalid:
42821+
WOLFSSL_MSG("TrustResult: Invalid\n");
42822+
break;
42823+
case kSecTrustResultProceed:
42824+
WOLFSSL_MSG("TrustResult: Proceed\n");
42825+
break;
42826+
case kSecTrustResultDeny:
42827+
WOLFSSL_MSG("TrustResult: Deny\n");
42828+
break;
42829+
case kSecTrustResultUnspecified:
42830+
WOLFSSL_MSG("TrustResult: Unspecified (implicitly trusted)\n");
42831+
break;
42832+
case kSecTrustResultRecoverableTrustFailure:
42833+
WOLFSSL_MSG("TrustResult: Recoverable trust failure\n");
42834+
break;
42835+
case kSecTrustResultFatalTrustFailure:
42836+
WOLFSSL_MSG("TrustResult: Fatal trust failure\n");
42837+
break;
42838+
case kSecTrustResultOtherError:
42839+
WOLFSSL_MSG("TrustResult: Other error\n");
42840+
break;
42841+
default:
42842+
WOLFSSL_MSG("TrustResult: Unknown\n");
42843+
break;
42844+
}
42845+
}
42846+
else {
42847+
WOLFSSL_MSG("SecTrustGetTrustResult failed\n");
42848+
}
42849+
42850+
info = CFErrorCopyUserInfo(error);
42851+
if (info) {
42852+
printf("Trust error info dump:\n");
42853+
CFShow(info);
42854+
CFRelease(info);
42855+
}
42856+
42857+
return 0;
42858+
}
4278042859

4278142860
/*
4278242861
* Validates a chain of certificates using the Apple system trust APIs
@@ -42793,13 +42872,13 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
4279342872
* wolfSSL's built-in certificate validation mechanisms anymore. We instead
4279442873
* must call into the Security Framework APIs to authenticate peer certificates
4279542874
*/
42796-
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
42797-
const WOLFSSL_BUFFER_INFO* certs,
42798-
int totalCerts)
42875+
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
42876+
const WOLFSSL_BUFFER_INFO* certs,
42877+
int totalCerts)
4279942878
{
42800-
int i;
42801-
int ret;
42802-
OSStatus status;
42879+
int i;
42880+
int ret;
42881+
OSStatus status;
4280342882
CFMutableArrayRef certArray = NULL;
4280442883
SecCertificateRef secCert = NULL;
4280542884
SecTrustRef trust = NULL;
@@ -42808,8 +42887,7 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4280842887

4280942888
WOLFSSL_ENTER("DoAppleNativeCertValidation");
4281042889

42811-
certArray = CFArrayCreateMutable(kCFAllocatorDefault,
42812-
totalCerts,
42890+
certArray = CFArrayCreateMutable(kCFAllocatorDefault, totalCerts,
4281342891
&kCFTypeArrayCallBacks);
4281442892
if (!certArray) {
4281542893
WOLFSSL_MSG("Error: can't allocate CFArray for certificates");
@@ -42818,8 +42896,8 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4281842896
}
4281942897

4282042898
for (i = 0; i < totalCerts; i++) {
42821-
secCert = ConvertToSecCertificateRef(certs[i].buffer,
42822-
(int)certs[i].length);
42899+
secCert =
42900+
ConvertToSecCertificateRef(certs[i].buffer, (int)certs[i].length);
4282342901
if (!secCert) {
4282442902
WOLFSSL_MSG("Error: can't convert DER cert to SecCertificateRef");
4282542903
ret = 0;
@@ -42833,35 +42911,74 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4283342911
}
4283442912

4283542913
/* Create trust object for SecCertifiate Ref */
42836-
if (ssl->buffers.domainName.buffer &&
42837-
ssl->buffers.domainName.length > 0) {
42914+
if (ssl->buffers.domainName.buffer && ssl->buffers.domainName.length > 0) {
4283842915
/* Create policy with specified value to require host name match */
42839-
hostname = CFStringCreateWithCString(kCFAllocatorDefault,
42840-
(const char*)ssl->buffers.domainName.buffer,
42841-
kCFStringEncodingUTF8);
42916+
hostname = CFStringCreateWithCString(
42917+
kCFAllocatorDefault, (const char*)ssl->buffers.domainName.buffer,
42918+
kCFStringEncodingUTF8);
4284242919
}
4284342920
if (hostname != NULL) {
4284442921
policy = SecPolicyCreateSSL(true, hostname);
42845-
} else {
42922+
}
42923+
else {
4284642924
policy = SecPolicyCreateSSL(true, NULL);
4284742925
}
4284842926
status = SecTrustCreateWithCertificates(certArray, policy, &trust);
4284942927
if (status != errSecSuccess) {
4285042928
WOLFSSL_MSG_EX("Error creating trust object, "
42851-
"SecTrustCreateWithCertificates returned %d",status);
42929+
"SecTrustCreateWithCertificates returned %d",
42930+
status);
4285242931
ret = 0;
4285342932
goto cleanup;
4285442933
}
4285542934

42935+
#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
42936+
/* TEST ONLY CODE:
42937+
* Set accumulated list of trusted CA certificates as trust anchors */
42938+
if (ssl->ctx->testTrustedCAs != NULL) {
42939+
status = SecTrustSetAnchorCertificates(trust, ssl->ctx->testTrustedCAs);
42940+
if (status != errSecSuccess) {
42941+
WOLFSSL_MSG_EX("Error setting anchor certificates: %d", status);
42942+
ret = 0;
42943+
goto cleanup;
42944+
}
42945+
}
42946+
#endif
42947+
4285642948
/* Evaluate the certificate's authenticity */
42857-
if (SecTrustEvaluateWithError(trust, NULL) == 1) {
42858-
WOLFSSL_MSG("Cert chain is trusted");
42859-
ret = 1;
42949+
WOLFSSL_MSG("Performing Apple native cert validation via "
42950+
"SecTrustEvaluateWithError");
42951+
CFErrorRef error = NULL;
42952+
ret = SecTrustEvaluateWithError(trust, &error);
42953+
if (ret != 1) {
42954+
if (error) {
42955+
CFIndex code;
42956+
code = CFErrorGetCode(error);
42957+
WOLFSSL_MSG_EX("SecTrustEvaluateWithError failed with code: %ld\n",
42958+
code);
42959+
DisplaySecTrustError(error, trust);
42960+
42961+
#if WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
42962+
/* TEST ONLY CODE:
42963+
* wolfSSL API tests use a cert with a validity period that is too
42964+
* long for the Apple system trust APIs
42965+
* (See: https://support.apple.com/en-us/103769)
42966+
* therefore we should skip over this particular error */
42967+
if (code == errSecCertificateValidityPeriodTooLong) {
42968+
WOLFSSL_MSG("Skipping certificate validity period error");
42969+
ret = 1;
42970+
}
42971+
#endif
42972+
42973+
CFRelease(error);
42974+
}
42975+
else {
42976+
WOLFSSL_MSG(
42977+
"SecTrustEvaluateWithError failed with unknown error.\n");
42978+
}
4286042979
}
4286142980
else {
42862-
WOLFSSL_MSG("Cert chain trust evaluation failed"
42863-
"SecTrustEvaluateWithError returned 0");
42864-
ret = 0;
42981+
WOLFSSL_MSG("SecTrustEvaluateWithError succeeded");
4286542982
}
4286642983

4286742984
/* Cleanup */
@@ -42883,6 +43000,38 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4288343000

4288443001
return ret;
4288543002
}
43003+
43004+
#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
43005+
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
43006+
const byte* derCert,
43007+
int derLen)
43008+
{
43009+
SecCertificateRef certRef;
43010+
43011+
if (derCert == NULL || derLen == 0) {
43012+
return WOLFSSL_FAILURE;
43013+
}
43014+
43015+
/* Create the base array for trust anchors if it doesn't exist */
43016+
if (ctx->testTrustedCAs == NULL) {
43017+
ctx->testTrustedCAs =
43018+
CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
43019+
if (!ctx->testTrustedCAs) {
43020+
return WOLFSSL_FAILURE;
43021+
}
43022+
}
43023+
43024+
certRef = ConvertToSecCertificateRef(derCert, derLen);
43025+
if (!certRef) {
43026+
return false;
43027+
}
43028+
43029+
CFArrayAppendValue(ctx->testTrustedCAs, certRef);
43030+
CFRelease(certRef);
43031+
return WOLFSSL_SUCCESS;
43032+
}
43033+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
43034+
4288643035
#endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
4288743036

4288843037
#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
@@ -4242,6 +4246,10 @@ struct WOLFSSL_CTX {
42424246
#if defined(WOLFSSL_SYS_CRYPTO_POLICY)
42434247
int secLevel; /* The security level of system-wide crypto policy. */
42444248
#endif /* WOLFSSL_SYS_CRYPTO_POLICY */
4249+
4250+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
4251+
CFMutableArrayRef testTrustedCAs;
4252+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
42454253
};
42464254

42474255
WOLFSSL_LOCAL
@@ -4278,6 +4286,13 @@ int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
42784286
#endif
42794287
#endif
42804288

4289+
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
4290+
WOLFSSL_API
4291+
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
4292+
const byte* derCert,
4293+
int derLen);
4294+
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
4295+
42814296
/* All cipher suite related info
42824297
* Keep as a constant size (no ifdefs) for session export */
42834298
typedef struct CipherSpecs {

0 commit comments

Comments
 (0)