@@ -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
0 commit comments