@@ -217,6 +217,14 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
217217 static int _DtlsCheckWindow(WOLFSSL* ssl);
218218#endif
219219
220+ #if defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS)
221+ #include <Security/SecCertificate.h>
222+ #include <Security/SecTrust.h>
223+ #include <Security/SecPolicy.h>
224+ static int DoAppleNativeCertValidation(const WOLFSSL_BUFFER_INFO* certs,
225+ int totalCerts);
226+ #endif /* #if defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
227+
220228#ifdef WOLFSSL_DTLS13
221229#ifndef WOLFSSL_DTLS13_SEND_MOREACK_DEFAULT
222230#define WOLFSSL_DTLS13_SEND_MOREACK_DEFAULT 0
@@ -271,6 +279,7 @@ static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
271279 const unsigned char* secret, int secretSz, void* ctx);
272280#endif
273281
282+
274283 /* Label string for client random. */
275284 #define SSC_CR "CLIENT_RANDOM"
276285
@@ -2426,6 +2435,11 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap)
24262435 maxq10xx_SetupPkCallbacks(ctx, &method->version);
24272436#endif /* WOLFSSL_MAXQ10XX_TLS */
24282437
2438+ #if defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS)
2439+ /* Should only be set when wolfSSL_CTX_load_system_CA_certs() is called */
2440+ ctx->doAppleNativeCertValidationFlag = 0;
2441+ #endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
2442+
24292443 return ret;
24302444}
24312445
@@ -14205,6 +14219,24 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1420514219 }
1420614220 #endif /* WOLFSSL_ALT_CERT_CHAINS */
1420714221
14222+ #if defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS)
14223+ /* If we are using native Apple CA validation, it is okay
14224+ * for a CA cert to fail validation here, as we will verify
14225+ * the entire chain when we hit the peer (leaf) cert */
14226+ if (ssl->ctx->doAppleNativeCertValidationFlag) {
14227+ WOLFSSL_MSG("Bypassing errors to allow for Apple native"
14228+ " CA validation");
14229+ ret = 0; /* clear errors and continue */
14230+ args->verifyErr = 0;
14231+ #if defined(OPENSSL_EXTRA) \
14232+ || defined(OPENSSL_EXTRA_X509_SMALL)
14233+ ssl->peerVerifyRet = 0;
14234+ #endif
14235+ /* do not add to certificate manager */
14236+ skipAddCA = 1;
14237+ }
14238+ #endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
14239+
1420814240 /* Do verify callback */
1420914241 ret = DoVerifyCallback(SSL_CM(ssl), ssl, ret, args);
1421014242 if (ssl->options.verifyNone &&
@@ -14273,7 +14305,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1427314305 FreeDecodedCert(args->dCert);
1427414306 args->dCertInit = 0;
1427514307 args->count--;
14276- } /* while (count > 0 && !args->haveTrustPeer) */
14308+ } /* while (count > 1 && !args->haveTrustPeer) */
1427714309 } /* if (count > 0) */
1427814310
1427914311 /* Check for error */
@@ -14394,6 +14426,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1439414426 }
1439514427 else {
1439614428 WOLFSSL_MSG("Failed to verify Peer's cert");
14429+
1439714430 #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
1439814431 if (ssl->peerVerifyRet == 0) { /* Return first cert error here */
1439914432 if (ret == ASN_BEFORE_DATE_E) {
@@ -14411,6 +14444,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1441114444 }
1441214445 }
1441314446 #endif
14447+
1441414448 if (ssl->verifyCallback) {
1441514449 WOLFSSL_MSG(
1441614450 "\tCallback override available, will continue");
@@ -14419,6 +14453,18 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1441914453 if (args->fatal)
1442014454 DoCertFatalAlert(ssl, ret);
1442114455 }
14456+ #if defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS)
14457+ /* Disregard failure to verify peer cert, as we will verify
14458+ * the whole chain with the native API later */
14459+ else if (ssl->ctx->doAppleNativeCertValidationFlag) {
14460+ WOLFSSL_MSG("\tApple native CA validation override"
14461+ " available, will continue");
14462+ /* check if fatal error */
14463+ args->fatal = (args->verifyErr) ? 1 : 0;
14464+ if (args->fatal)
14465+ DoCertFatalAlert(ssl, ret);
14466+ }
14467+ #endif/*defined(__APPLE__)&& defined(WOLFSSL_SYS_CA_CERTS)*/
1442214468 else {
1442314469 WOLFSSL_MSG("\tNo callback override available, fatal");
1442414470 args->fatal = 1;
@@ -15178,6 +15224,22 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1517815224 }
1517915225 #endif
1518015226
15227+ #if defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS)
15228+ /* If we can't validate the peer cert chain against the CAs loaded
15229+ * into wolfSSL, try to validate against the system certificates
15230+ * using Apple's native trust APIs */
15231+ if ((ret != 0) && (ssl->ctx->doAppleNativeCertValidationFlag)) {
15232+ if (DoAppleNativeCertValidation(args->certs,
15233+ args->totalCerts)) {
15234+ WOLFSSL_MSG("Apple native cert chain validation SUCCESS");
15235+ ret = 0;
15236+ }
15237+ else {
15238+ WOLFSSL_MSG("Apple native cert chain validation FAIL");
15239+ }
15240+ }
15241+ #endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
15242+
1518115243 /* Do verify callback */
1518215244 ret = DoVerifyCallback(SSL_CM(ssl), ssl, ret, args);
1518315245
@@ -39353,6 +39415,139 @@ int wolfSSL_sk_BY_DIR_entry_push(WOLF_STACK_OF(WOLFSSL_BY_DIR_entry)* sk,
3935339415
3935439416#endif /* OPENSSL_ALL */
3935539417
39418+ #if defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS)
39419+
39420+ /*
39421+ * Converts a DER formatted certificate to a SecCertificateRef
39422+ *
39423+ * @param derCert pointer to the DER formatted certificate
39424+ * @param derLen length of the DER formatted cert, in bytes
39425+ *
39426+ * @return The newly created SecCertificateRef. Must be freed by caller when
39427+ * no longer in use
39428+ */
39429+ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
39430+ int derLen)
39431+ {
39432+ CFDataRef derData = NULL;
39433+ SecCertificateRef secCert = NULL;
39434+
39435+ WOLFSSL_ENTER("ConvertToSecCertificateRef");
39436+
39437+ /* Create a CFDataRef from the DER encoded certificate */
39438+ derData = CFDataCreate(kCFAllocatorDefault, derCert, derLen);
39439+ if (!derData) {
39440+ WOLFSSL_MSG("Error: can't create CFDataRef object for DER cert");
39441+ goto cleanup;
39442+ }
39443+
39444+ /* Create a SecCertificateRef from the CFDataRef */
39445+ secCert = SecCertificateCreateWithData(kCFAllocatorDefault, derData);
39446+ if (!secCert) {
39447+ WOLFSSL_MSG("Error: can't create SecCertificateRef from CFDataRef");
39448+ goto cleanup;
39449+ }
39450+
39451+ cleanup:
39452+ if (derData) {
39453+ CFRelease(derData);
39454+ }
39455+
39456+ WOLFSSL_LEAVE("ConvertToSecCertificateRef", !!secCert);
39457+
39458+ return secCert;
39459+ }
39460+
39461+
39462+ /*
39463+ * Validates a chain of certificates using the Apple system trust APIs
39464+ *
39465+ * @param certs pointer to the certificate chain to validate
39466+ * @param totalCerts the number of certificates in certs
39467+ *
39468+ * @return 1 if chain is valid and trusted
39469+ * @return 0 if chain is invalid or untrusted
39470+ *
39471+ * As of MacOS 14.0 we are still able to access system certificates and load
39472+ * them manually into wolfSSL. For other apple devices, apple has removed the
39473+ * ability to obtain certificates from the trust store, so we can't use
39474+ * wolfSSL's built-in certificate validation mechanisms anymore. We instead
39475+ * must call into the Security Framework APIs to authenticate peer certificates
39476+ */
39477+ static int DoAppleNativeCertValidation(const WOLFSSL_BUFFER_INFO* certs,
39478+ int totalCerts)
39479+ {
39480+ int i;
39481+ int ret;
39482+ OSStatus status;
39483+ CFMutableArrayRef certArray = NULL;
39484+ SecCertificateRef secCert = NULL;
39485+ SecTrustRef trust = NULL;
39486+ SecPolicyRef policy = NULL ;
39487+
39488+ WOLFSSL_ENTER("DoAppleNativeCertValidation");
39489+
39490+ certArray = CFArrayCreateMutable(kCFAllocatorDefault,
39491+ totalCerts,
39492+ &kCFTypeArrayCallBacks);
39493+ if (!certArray) {
39494+ WOLFSSL_MSG("Error: can't allocate CFArray for certificates");
39495+ ret = 0;
39496+ goto cleanup;
39497+ }
39498+
39499+ for (i = 0; i < totalCerts; i++) {
39500+ secCert = ConvertToSecCertificateRef(certs[i].buffer, certs[i].length);
39501+ if (!secCert) {
39502+ WOLFSSL_MSG("Error: can't convert DER cert to SecCertificateRef");
39503+ ret = 0;
39504+ goto cleanup;
39505+ }
39506+ else {
39507+ CFArrayAppendValue(certArray, secCert);
39508+ /* Release, since the array now holds the reference */
39509+ CFRelease(secCert);
39510+ }
39511+ }
39512+
39513+ /* Create trust object for SecCertifiate Ref */
39514+ policy = SecPolicyCreateSSL(true, NULL);
39515+ status = SecTrustCreateWithCertificates(certArray, policy, &trust);
39516+ if (status != errSecSuccess) {
39517+ WOLFSSL_MSG_EX("Error creating trust object, "
39518+ "SecTrustCreateWithCertificates returned %d",status);
39519+ ret = 0;
39520+ goto cleanup;
39521+ }
39522+
39523+ /* Evaluate the certificate's authenticity */
39524+ if (SecTrustEvaluateWithError(trust, NULL) == 1) {
39525+ WOLFSSL_MSG("Cert chain is trusted");
39526+ ret = 1;
39527+ }
39528+ else {
39529+ WOLFSSL_MSG("Cert chain trust evaluation failed"
39530+ "SecTrustEvaluateWithError returned 0");
39531+ ret = 0;
39532+ }
39533+
39534+ /* Cleanup */
39535+ cleanup:
39536+ if (certArray) {
39537+ CFRelease(certArray);
39538+ }
39539+ if (trust) {
39540+ CFRelease(trust);
39541+ }
39542+ if (policy) {
39543+ CFRelease(policy);
39544+ }
39545+
39546+ WOLFSSL_LEAVE("DoAppleNativeCertValidation", ret);
39547+
39548+ return ret;
39549+ }
39550+ #endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */
3935639551
3935739552#undef ERROR_OUT
3935839553
0 commit comments