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