--- source/s2n/s2n_apple_keychain.c 2026-06-04 01:57:49.000000000 +0800 +++ source/s2n/s2n_apple_keychain.c 2026-06-06 17:27:08.000000000 +0800 @@ -14,9 +14,14 @@ /* Check for USE_S2N needed to handle cross-compilation for Apple non-macOS platforms that can't use s2n-tls. */ #if defined(__APPLE__) && defined(USE_S2N) -# include +# include -# include +/* SecCertificateCopyValues (used in s_cert_has_basic_constraints_ca) requires macOS 10.7+. + * On older systems, provide a no-op: TLS still works via s2n's bundled system roots. */ +# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + +# include +# include static bool s_is_cert_trusted(const SecCertificateRef cert) { SecPolicyRef policy = SecPolicyCreateBasicX509(); @@ -30,7 +35,16 @@ SecTrustRef trust = NULL; OSStatus status = SecTrustCreateWithCertificates(cert, policy, &trust); if (status == errSecSuccess) { +# if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 + /* SecTrustEvaluateWithError requires macOS 10.14+ */ is_trusted = SecTrustEvaluateWithError(trust, NULL); +# else + /* Use the deprecated SecTrustEvaluate on macOS 10.7-10.13 */ + SecTrustResultType result = kSecTrustResultInvalid; + if (SecTrustEvaluate(trust, &result) == errSecSuccess) { + is_trusted = (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified); + } +# endif } else { AWS_LOGF_TRACE(AWS_LS_IO_TLS, "Failed to create a trust object, status code %d", (int)status); } @@ -107,6 +121,8 @@ for (CFIndex i = 0; i < count; i++) { SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(results, i); +# if MAC_OS_X_VERSION_MIN_REQUIRED >= 101204 + /* SecCertificateCopyNormalizedSubjectSequence / IssuerSequence require macOS 10.12.4+ */ CFDataRef subject_data = SecCertificateCopyNormalizedSubjectSequence(cert); CFDataRef issuer_data = SecCertificateCopyNormalizedIssuerSequence(cert); @@ -125,6 +141,12 @@ CFRelease(subject_data); CFRelease(issuer_data); +# else + /* Cannot compare normalized subject/issuer DER sequences on macOS < 10.12.4. + * Fall back to Basic Constraints check only; self-signed detection is skipped. */ + bool is_self_signed = false; + bool is_ca = s_cert_has_basic_constraints_ca(cert); +# endif /* We check both conditions: a root CA is typically self-signed (subject == issuer), but some cross-signed CAs * have a different issuer yet are still valid CAs per Basic Constraints. Either condition is sufficient to @@ -179,4 +201,15 @@ CFRelease(results); } +# else /* MAC_OS_X_VERSION_MIN_REQUIRED < 1070 */ + +/* Keychain CA loading requires macOS 10.7 or later. Provide a no-op stub so that TLS + * continues to work via s2n's bundled system roots. User-added keychain CAs are not loaded. */ +void aws_tls_s2n_load_macos_keychain_root_cas(struct s2n_config *config, struct aws_allocator *alloc) { + (void)config; + (void)alloc; +} + +# endif /* MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 */ + #endif /* defined(__APPLE__) && defined(USE_S2N) */