Skip to content

Commit 22ab217

Browse files
authored
Merge pull request #6869 from bigbrett/ios-ca-api
Add support for new Apple trust APIs with WOLFSSL_SYS_CA_CERTS
2 parents 2690903 + a1d7684 commit 22ab217

7 files changed

Lines changed: 289 additions & 23 deletions

File tree

CMakeLists.txt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,21 +1724,23 @@ if(WOLFSSL_SYS_CA_CERTS)
17241724
override_cache(WOLFSSL_SYS_CA_CERTS "no")
17251725
elseif(APPLE)
17261726
check_include_file("Security/SecTrustSettings.h" HAVE_SECURITY_SECTRUSTSETTINGS_H)
1727-
if(NOT HAVE_SECURITY_SECTRUSTSETTINGS_H)
1728-
message("Can't enable system CA certs without Security/SecTrustSettings.h.")
1729-
override_cache(WOLFSSL_SYS_CA_CERTS "no")
1730-
else()
1727+
check_include_file("Security/SecCertificate.h" HAVE_SECURITY_SECCERTIFICATE_H)
1728+
check_include_file("Security/SecTrust.h" HAVE_SECURITY_SECTRUST_H)
1729+
check_include_file("Security/SecPolicy.h" HAVE_SECURITY_SECPOLICY_H)
1730+
if(HAVE_SECURITY_SECTRUSTSETTINGS_H OR (HAVE_SECURITY_SECCERTIFICATE_H
1731+
AND HAVE_SECURITY_SECTRUST_H
1732+
AND HAVE_SECURITY_SECPOLICY_H))
17311733
find_library(CORE_FOUNDATION_FRAMEWORK CoreFoundation)
17321734
if(NOT CORE_FOUNDATION_FRAMEWORK)
1733-
message("Can't enable system CA certs without CoreFoundation framework.")
1734-
override_cache(WOLFSSL_SYS_CA_CERTS "no")
1735+
message(FATAL_ERROR "Can't enable system CA certs without CoreFoundation framework.")
17351736
else()
17361737
find_library(SECURITY_FRAMEWORK Security)
17371738
if(NOT SECURITY_FRAMEWORK)
1738-
message("Can't enable system CA certs without Security framework.")
1739-
override_cache(WOLFSSL_SYS_CA_CERTS "no")
1739+
message(FATAL_ERROR "Can't enable system CA certs without Security framework.")
17401740
endif()
17411741
endif()
1742+
else()
1743+
message(FATAL_ERROR "Can't enable system CA certs without Apple Security.framework headers.")
17421744
endif()
17431745
endif()
17441746

configure.ac

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8351,14 +8351,24 @@ then
83518351

83528352
case $host_os in
83538353
*darwin*)
8354-
AC_CHECK_HEADERS([Security/SecTrustSettings.h],
8354+
# Creates the HAVE_SECURITY_SECXXX_H macros in config.h
8355+
AC_CHECK_HEADERS([Security/SecTrustSettings.h])
8356+
AC_CHECK_HEADERS([Security/SecCertificate.h])
8357+
AC_CHECK_HEADERS([Security/SecTrust.h])
8358+
AC_CHECK_HEADERS([Security/SecPolicy.h])
8359+
# Either Security/SecTrustSettings (for MacOS cert loading), or the
8360+
# trio of Security/SecCertificate.h, Security/SecTrust.h, and
8361+
# Security/SecPolicy.h (for native trust APIs other apple devices)
8362+
# must be present
8363+
AS_IF([test -n "$ac_cv_header_Security_SecTrustSettings_h" \
8364+
|| (test -n "$ac_cv_header_Security_SecCertificate_h" \
8365+
&& test -n "$ac_cv_header_Security_SecTrust_h" \
8366+
&& test -n "$ac_cv_header_Security_SecPolicy_h")],
83558367
[
8356-
# For Mac we need these frameworks to load system CA certs
83578368
LDFLAGS="$LDFLAGS -framework CoreFoundation -framework Security"
83588369
],
83598370
[
8360-
AC_MSG_NOTICE([Can't enable system CA certs without Security/SecTrustSettings.h])
8361-
ENABLED_SYS_CA_CERTS="no"
8371+
AC_MSG_ERROR([Unable to find Apple Security.framework headers])
83628372
]
83638373
)
83648374
;;

doc/dox_comments/header_files/ssl.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,9 @@ int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
12361236
12371237
\brief This function returns a pointer to an array of strings representing
12381238
directories wolfSSL will search for system CA certs when
1239-
wolfSSL_CTX_load_system_CA_certs is called.
1239+
wolfSSL_CTX_load_system_CA_certs is called. On systems that don't store
1240+
certificates in an accessible system directory (such as Apple platforms),
1241+
this function will always return NULL.
12401242
12411243
\return Valid pointer on success.
12421244
\return NULL pointer on failure.
@@ -1266,10 +1268,19 @@ const char** wolfSSL_get_system_CA_dirs(word32* num);
12661268
/*!
12671269
\ingroup CertsKeys
12681270
1269-
\brief This function attempts to load CA certificates into a WOLFSSL_CTX
1270-
from an OS-dependent CA certificate store. Loaded certificates will be
1271-
trusted. The platforms supported and tested are: Linux (Debian, Ubuntu,
1272-
Gentoo, Fedora, RHEL), Windows 10/11, Android, Apple OS X and iOS.
1271+
\brief On most platforms (including Linux and Windows), this function
1272+
attempts to load CA certificates into a WOLFSSL_CTX from an OS-dependent
1273+
CA certificate store. Loaded certificates will be trusted.
1274+
1275+
On Apple platforms (excluding macOS), certificates can't be obtained from
1276+
the system, and therefore cannot be loaded into the wolfSSL certificate
1277+
manager. For these platforms, this function enables TLS connections bound to
1278+
the WOLFSSL_CTX to use the native system trust APIs to verify authenticity
1279+
of the peer certificate chain if the authenticity of the peer cannot first
1280+
be authenticated against certificates loaded by the user.
1281+
1282+
The platforms supported and tested are: Linux (Debian, Ubuntu,
1283+
Gentoo, Fedora, RHEL), Windows 10/11, Android, macOS, and iOS.
12731284
12741285
\return WOLFSSL_SUCCESS on success.
12751286
\return WOLFSSL_BAD_PATH if no system CA certs were loaded.

src/internal.c

Lines changed: 196 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)