@@ -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
@@ -16330,7 +16336,6 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1633016336 }
1633116337 #endif
1633216338
16333-
1633416339 if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) {
1633516340 #ifndef WOLFSSL_ALLOW_NO_CN_IN_SAN
1633616341 /* Per RFC 5280 section 4.2.1.6, "Whenever such identities
@@ -42777,7 +42782,122 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
4277742782 return secCert;
4277842783}
4277942784
42785+ static int DisplaySecTrustError(CFErrorRef error, SecTrustRef trust)
42786+ {
42787+ CFStringRef desc;
42788+ CFStringRef domain;
42789+ SecTrustResultType trustResult;
42790+ CFDictionaryRef info;
42791+
42792+ /* Description */
42793+ desc = CFErrorCopyDescription(error);
42794+ if (desc) {
42795+ char buffer[256];
42796+ if (CFStringGetCString(desc, buffer, sizeof(buffer),
42797+ kCFStringEncodingUTF8)) {
42798+ WOLFSSL_MSG_EX("SecTrustEvaluateWithError Error description: %s\n",
42799+ buffer);
42800+ }
42801+ CFRelease(desc);
42802+ }
42803+
42804+ /* Domain */
42805+ domain = CFErrorGetDomain(error);
42806+ if (domain) {
42807+ char domainStr[128];
42808+ if (CFStringGetCString(domain, domainStr, sizeof(domainStr),
42809+ kCFStringEncodingUTF8)) {
42810+ WOLFSSL_MSG_EX("SecTrustEvaluateWithError Domain: %s\n", domainStr);
42811+ }
42812+ }
4278042813
42814+ /* Get additional trust result info */
42815+ if (SecTrustGetTrustResult(trust, &trustResult) == errSecSuccess) {
42816+ WOLFSSL_MSG_EX("SecTrustResultType: %d\n", trustResult);
42817+ /* Optional: decode the enum */
42818+ switch (trustResult) {
42819+ case kSecTrustResultInvalid:
42820+ WOLFSSL_MSG("TrustResult: Invalid\n");
42821+ break;
42822+ case kSecTrustResultProceed:
42823+ WOLFSSL_MSG("TrustResult: Proceed\n");
42824+ break;
42825+ case kSecTrustResultDeny:
42826+ WOLFSSL_MSG("TrustResult: Deny\n");
42827+ break;
42828+ case kSecTrustResultUnspecified:
42829+ WOLFSSL_MSG("TrustResult: Unspecified (implicitly trusted)\n");
42830+ break;
42831+ case kSecTrustResultRecoverableTrustFailure:
42832+ WOLFSSL_MSG("TrustResult: Recoverable trust failure\n");
42833+ break;
42834+ case kSecTrustResultFatalTrustFailure:
42835+ WOLFSSL_MSG("TrustResult: Fatal trust failure\n");
42836+ break;
42837+ case kSecTrustResultOtherError:
42838+ WOLFSSL_MSG("TrustResult: Other error\n");
42839+ break;
42840+ default:
42841+ WOLFSSL_MSG("TrustResult: Unknown\n");
42842+ break;
42843+ }
42844+ }
42845+ else {
42846+ WOLFSSL_MSG("SecTrustGetTrustResult failed\n");
42847+ }
42848+
42849+ info = CFErrorCopyUserInfo(error);
42850+ if (info) {
42851+ WOLFSSL_MSG("Trust error info dump:\n");
42852+ CFShow(info);
42853+ CFRelease(info);
42854+ }
42855+
42856+ return 0;
42857+ }
42858+
42859+ #if defined(WOLFSSL_APPLE_NATIVE_CERT_VALIDATION) && \
42860+ defined (WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
42861+ static int MaxValidityPeriodErrorOnly(CFErrorRef error)
42862+ {
42863+ int multiple = 0;
42864+
42865+ CFDictionaryRef userInfo = CFErrorCopyUserInfo(error);
42866+ if (userInfo) {
42867+ /* Get underlying error */
42868+ CFTypeRef underlying =
42869+ CFDictionaryGetValue(userInfo, kCFErrorUnderlyingErrorKey);
42870+ if (underlying) {
42871+ /* Get underlying error value*/
42872+ CFDictionaryRef underlyingDict =
42873+ CFErrorCopyUserInfo((CFErrorRef)underlying);
42874+ if (underlyingDict) {
42875+ char buffer[512];
42876+ CFStringRef values =
42877+ CFDictionaryGetValue(underlyingDict,
42878+ kCFErrorLocalizedDescriptionKey);
42879+ if(CFStringGetCString(values, buffer, sizeof(buffer),
42880+ kCFStringEncodingUTF8)) {
42881+ if (XSTRSTR(buffer, "Certificate exceeds maximum "
42882+ "temporal validity period") &&
42883+ (!XSTRSTR(buffer, "Certificate exceeds maximum "
42884+ "temporal validity period,") ||
42885+ !XSTRSTR(buffer, ", Certificate exceeds maximum "
42886+ "temporal validity period"))) {
42887+ WOLFSSL_MSG("Maximum validity period error only");
42888+ } else {
42889+ WOLFSSL_MSG("Found other errors");
42890+ multiple = 1;
42891+ }
42892+ }
42893+ CFRelease(underlyingDict);
42894+ }
42895+ }
42896+ CFRelease(userInfo);
42897+ }
42898+ return multiple;
42899+ }
42900+ #endif
4278142901/*
4278242902 * Validates a chain of certificates using the Apple system trust APIs
4278342903 *
@@ -42793,23 +42913,23 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
4279342913 * wolfSSL's built-in certificate validation mechanisms anymore. We instead
4279442914 * must call into the Security Framework APIs to authenticate peer certificates
4279542915 */
42796- static int DoAppleNativeCertValidation(WOLFSSL* ssl,
42797- const WOLFSSL_BUFFER_INFO* certs,
42798- int totalCerts)
42916+ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
42917+ const WOLFSSL_BUFFER_INFO* certs,
42918+ int totalCerts)
4279942919{
42800- int i;
42801- int ret;
42802- OSStatus status;
42920+ int i;
42921+ int ret;
42922+ OSStatus status;
4280342923 CFMutableArrayRef certArray = NULL;
4280442924 SecCertificateRef secCert = NULL;
4280542925 SecTrustRef trust = NULL;
4280642926 SecPolicyRef policy = NULL;
4280742927 CFStringRef hostname = NULL;
42928+ CFErrorRef error = NULL;
4280842929
4280942930 WOLFSSL_ENTER("DoAppleNativeCertValidation");
4281042931
42811- certArray = CFArrayCreateMutable(kCFAllocatorDefault,
42812- totalCerts,
42932+ certArray = CFArrayCreateMutable(kCFAllocatorDefault, totalCerts,
4281342933 &kCFTypeArrayCallBacks);
4281442934 if (!certArray) {
4281542935 WOLFSSL_MSG("Error: can't allocate CFArray for certificates");
@@ -42818,8 +42938,8 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4281842938 }
4281942939
4282042940 for (i = 0; i < totalCerts; i++) {
42821- secCert = ConvertToSecCertificateRef(certs[i].buffer,
42822- (int)certs[i].length);
42941+ secCert =
42942+ ConvertToSecCertificateRef(certs[i].buffer, (int)certs[i].length);
4282342943 if (!secCert) {
4282442944 WOLFSSL_MSG("Error: can't convert DER cert to SecCertificateRef");
4282542945 ret = 0;
@@ -42833,35 +42953,80 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4283342953 }
4283442954
4283542955 /* Create trust object for SecCertifiate Ref */
42836- if (ssl->buffers.domainName.buffer &&
42837- ssl->buffers.domainName.length > 0) {
42956+ if (ssl->buffers.domainName.buffer && ssl->buffers.domainName.length > 0) {
4283842957 /* Create policy with specified value to require host name match */
42839- hostname = CFStringCreateWithCString(kCFAllocatorDefault,
42840- (const char*)ssl->buffers.domainName.buffer,
42841- kCFStringEncodingUTF8);
42958+ hostname = CFStringCreateWithCString(
42959+ kCFAllocatorDefault, (const char*)ssl->buffers.domainName.buffer,
42960+ kCFStringEncodingUTF8);
4284242961 }
4284342962 if (hostname != NULL) {
4284442963 policy = SecPolicyCreateSSL(true, hostname);
42845- } else {
42964+ }
42965+ else {
4284642966 policy = SecPolicyCreateSSL(true, NULL);
4284742967 }
4284842968 status = SecTrustCreateWithCertificates(certArray, policy, &trust);
4284942969 if (status != errSecSuccess) {
4285042970 WOLFSSL_MSG_EX("Error creating trust object, "
42851- "SecTrustCreateWithCertificates returned %d",status);
42971+ "SecTrustCreateWithCertificates returned %d",
42972+ status);
4285242973 ret = 0;
4285342974 goto cleanup;
4285442975 }
4285542976
42977+ #if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
42978+ /* TEST ONLY CODE:
42979+ * Set accumulated list of trusted CA certificates as trust anchors */
42980+ WOLFSSL_MSG("Setting anchor certificates");
42981+ if (ssl->ctx->testTrustedCAs != NULL) {
42982+ status = SecTrustSetAnchorCertificates(trust, ssl->ctx->testTrustedCAs);
42983+ if (status != errSecSuccess) {
42984+ WOLFSSL_MSG_EX("Error setting anchor certificates: %d", status);
42985+ ret = 0;
42986+ goto cleanup;
42987+ }
42988+ }
42989+ #endif
42990+
4285642991 /* Evaluate the certificate's authenticity */
42857- if (SecTrustEvaluateWithError(trust, NULL) == 1) {
42858- WOLFSSL_MSG("Cert chain is trusted");
42859- ret = 1;
42992+ WOLFSSL_MSG("Performing Apple native cert validation via "
42993+ "SecTrustEvaluateWithError");
42994+ ret = SecTrustEvaluateWithError(trust, &error);
42995+ if (ret != 1) {
42996+ if (error) {
42997+ CFIndex code;
42998+ code = CFErrorGetCode(error);
42999+ WOLFSSL_MSG_EX("SecTrustEvaluateWithError failed with code: %ld\n",
43000+ code);
43001+ DisplaySecTrustError(error, trust);
43002+
43003+ #ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
43004+ /* TEST ONLY CODE:
43005+ * wolfSSL API tests use a cert with a validity period that is too
43006+ * long for the Apple system trust APIs
43007+ * (See: https://support.apple.com/en-us/103769)
43008+ * therefore we should skip over this particular error */
43009+ if (code == errSecCertificateValidityPeriodTooLong) {
43010+ if (MaxValidityPeriodErrorOnly(error)) {
43011+ WOLFSSL_MSG("Multiple reasons for validity period error, "
43012+ "not skipping");
43013+ ret = 0;
43014+ } else {
43015+ WOLFSSL_MSG("Skipping certificate validity period error");
43016+ ret = 1;
43017+ }
43018+ }
43019+ #endif
43020+ (void)code;
43021+ CFRelease(error);
43022+ }
43023+ else {
43024+ WOLFSSL_MSG(
43025+ "SecTrustEvaluateWithError failed with unknown error.\n");
43026+ }
4286043027 }
4286143028 else {
42862- WOLFSSL_MSG("Cert chain trust evaluation failed"
42863- "SecTrustEvaluateWithError returned 0");
42864- ret = 0;
43029+ WOLFSSL_MSG("SecTrustEvaluateWithError succeeded");
4286543030 }
4286643031
4286743032 /* Cleanup */
@@ -42883,6 +43048,38 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
4288343048
4288443049 return ret;
4288543050}
43051+
43052+ #if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
43053+ int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
43054+ const byte* derCert,
43055+ int derLen)
43056+ {
43057+ SecCertificateRef certRef;
43058+
43059+ if (derCert == NULL || derLen == 0) {
43060+ return WOLFSSL_FAILURE;
43061+ }
43062+
43063+ /* Create the base array for trust anchors if it doesn't exist */
43064+ if (ctx->testTrustedCAs == NULL) {
43065+ ctx->testTrustedCAs =
43066+ CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
43067+ if (!ctx->testTrustedCAs) {
43068+ return WOLFSSL_FAILURE;
43069+ }
43070+ }
43071+
43072+ certRef = ConvertToSecCertificateRef(derCert, derLen);
43073+ if (!certRef) {
43074+ return false;
43075+ }
43076+
43077+ CFArrayAppendValue(ctx->testTrustedCAs, certRef);
43078+ CFRelease(certRef);
43079+ return WOLFSSL_SUCCESS;
43080+ }
43081+ #endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
43082+
4288643083#endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
4288743084
4288843085#undef ERROR_OUT
0 commit comments