Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 172 additions & 23 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2915,6 +2915,12 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
ctx->x509Chain = NULL;
}
#endif
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ctx->testTrustedCAs != NULL) {
CFRelease(ctx->testTrustedCAs);
ctx->testTrustedCAs = NULL;
}
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
#endif /* !NO_CERTS */

#ifdef HAVE_TLS_EXTENSIONS
Expand Down Expand Up @@ -42729,6 +42735,79 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
return secCert;
}

static int DisplaySecTrustError(CFErrorRef error, SecTrustRef trust)
{
CFStringRef desc;
CFStringRef domain;
SecTrustResultType trustResult;
CFDictionaryRef info;

/* Description */
desc = CFErrorCopyDescription(error);
if (desc) {
char buffer[256];
if (CFStringGetCString(desc, buffer, sizeof(buffer),
kCFStringEncodingUTF8)) {
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Error description: %s\n",
buffer);
}
CFRelease(desc);
}

/* Domain */
domain = CFErrorGetDomain(error);
if (domain) {
char domainStr[128];
if (CFStringGetCString(domain, domainStr, sizeof(domainStr),
kCFStringEncodingUTF8)) {
WOLFSSL_MSG_EX("SecTrustEvaluateWithError Domain: %s\n", domainStr);
}
}

/* Get additional trust result info */
if (SecTrustGetTrustResult(trust, &trustResult) == errSecSuccess) {
WOLFSSL_MSG_EX("SecTrustResultType: %d\n", trustResult);
/* Optional: decode the enum */
switch (trustResult) {
case kSecTrustResultInvalid:
WOLFSSL_MSG("TrustResult: Invalid\n");
break;
case kSecTrustResultProceed:
WOLFSSL_MSG("TrustResult: Proceed\n");
break;
case kSecTrustResultDeny:
WOLFSSL_MSG("TrustResult: Deny\n");
break;
case kSecTrustResultUnspecified:
WOLFSSL_MSG("TrustResult: Unspecified (implicitly trusted)\n");
break;
case kSecTrustResultRecoverableTrustFailure:
WOLFSSL_MSG("TrustResult: Recoverable trust failure\n");
break;
case kSecTrustResultFatalTrustFailure:
WOLFSSL_MSG("TrustResult: Fatal trust failure\n");
break;
case kSecTrustResultOtherError:
WOLFSSL_MSG("TrustResult: Other error\n");
break;
default:
WOLFSSL_MSG("TrustResult: Unknown\n");
break;
}
}
else {
WOLFSSL_MSG("SecTrustGetTrustResult failed\n");
}

info = CFErrorCopyUserInfo(error);
if (info) {
printf("Trust error info dump:\n");
CFShow(info);
CFRelease(info);
}

return 0;
}

/*
* Validates a chain of certificates using the Apple system trust APIs
Expand All @@ -42745,13 +42824,13 @@ static SecCertificateRef ConvertToSecCertificateRef(const byte* derCert,
* wolfSSL's built-in certificate validation mechanisms anymore. We instead
* must call into the Security Framework APIs to authenticate peer certificates
*/
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
const WOLFSSL_BUFFER_INFO* certs,
int totalCerts)
static int DoAppleNativeCertValidation(WOLFSSL* ssl,
const WOLFSSL_BUFFER_INFO* certs,
int totalCerts)
{
int i;
int ret;
OSStatus status;
int i;
int ret;
OSStatus status;
CFMutableArrayRef certArray = NULL;
SecCertificateRef secCert = NULL;
SecTrustRef trust = NULL;
Expand All @@ -42760,8 +42839,7 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,

WOLFSSL_ENTER("DoAppleNativeCertValidation");

certArray = CFArrayCreateMutable(kCFAllocatorDefault,
totalCerts,
certArray = CFArrayCreateMutable(kCFAllocatorDefault, totalCerts,
&kCFTypeArrayCallBacks);
if (!certArray) {
WOLFSSL_MSG("Error: can't allocate CFArray for certificates");
Expand All @@ -42770,8 +42848,8 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
}

for (i = 0; i < totalCerts; i++) {
secCert = ConvertToSecCertificateRef(certs[i].buffer,
(int)certs[i].length);
secCert =
ConvertToSecCertificateRef(certs[i].buffer, (int)certs[i].length);
if (!secCert) {
WOLFSSL_MSG("Error: can't convert DER cert to SecCertificateRef");
ret = 0;
Expand All @@ -42785,35 +42863,74 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,
}

/* Create trust object for SecCertifiate Ref */
if (ssl->buffers.domainName.buffer &&
ssl->buffers.domainName.length > 0) {
if (ssl->buffers.domainName.buffer && ssl->buffers.domainName.length > 0) {
/* Create policy with specified value to require host name match */
hostname = CFStringCreateWithCString(kCFAllocatorDefault,
(const char*)ssl->buffers.domainName.buffer,
kCFStringEncodingUTF8);
hostname = CFStringCreateWithCString(
kCFAllocatorDefault, (const char*)ssl->buffers.domainName.buffer,
kCFStringEncodingUTF8);
}
if (hostname != NULL) {
policy = SecPolicyCreateSSL(true, hostname);
} else {
}
else {
policy = SecPolicyCreateSSL(true, NULL);
}
status = SecTrustCreateWithCertificates(certArray, policy, &trust);
if (status != errSecSuccess) {
WOLFSSL_MSG_EX("Error creating trust object, "
"SecTrustCreateWithCertificates returned %d",status);
"SecTrustCreateWithCertificates returned %d",
status);
ret = 0;
goto cleanup;
}

#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
/* TEST ONLY CODE:
* Set accumulated list of trusted CA certificates as trust anchors */
if (ssl->ctx->testTrustedCAs != NULL) {
status = SecTrustSetAnchorCertificates(trust, ssl->ctx->testTrustedCAs);
if (status != errSecSuccess) {
WOLFSSL_MSG_EX("Error setting anchor certificates: %d", status);
ret = 0;
goto cleanup;
}
}
#endif

/* Evaluate the certificate's authenticity */
if (SecTrustEvaluateWithError(trust, NULL) == 1) {
WOLFSSL_MSG("Cert chain is trusted");
ret = 1;
WOLFSSL_MSG("Performing Apple native cert validation via "
"SecTrustEvaluateWithError");
CFErrorRef error = NULL;
ret = SecTrustEvaluateWithError(trust, &error);
if (ret != 1) {
if (error) {
CFIndex code;
code = CFErrorGetCode(error);
WOLFSSL_MSG_EX("SecTrustEvaluateWithError failed with code: %ld\n",
code);
DisplaySecTrustError(error, trust);

#if WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
/* TEST ONLY CODE:
* wolfSSL API tests use a cert with a validity period that is too
* long for the Apple system trust APIs
* (See: https://support.apple.com/en-us/103769)
* therefore we should skip over this particular error */
if (code == errSecCertificateValidityPeriodTooLong) {
WOLFSSL_MSG("Skipping certificate validity period error");
ret = 1;
}
#endif

CFRelease(error);
}
else {
WOLFSSL_MSG(
"SecTrustEvaluateWithError failed with unknown error.\n");
}
}
else {
WOLFSSL_MSG("Cert chain trust evaluation failed"
"SecTrustEvaluateWithError returned 0");
ret = 0;
WOLFSSL_MSG("SecTrustEvaluateWithError succeeded");
}

/* Cleanup */
Expand All @@ -42835,6 +42952,38 @@ static int DoAppleNativeCertValidation(WOLFSSL* ssl,

return ret;
}

#if defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
const byte* derCert,
int derLen)
{
SecCertificateRef certRef;

if (derCert == NULL || derLen == 0) {
return WOLFSSL_FAILURE;
}

/* Create the base array for trust anchors if it doesn't exist */
if (ctx->testTrustedCAs == NULL) {
ctx->testTrustedCAs =
CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (!ctx->testTrustedCAs) {
return WOLFSSL_FAILURE;
}
}

certRef = ConvertToSecCertificateRef(derCert, derLen);
if (!certRef) {
return false;
}

CFArrayAppendValue(ctx->testTrustedCAs, certRef);
CFRelease(certRef);
return WOLFSSL_SUCCESS;
}
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */

#endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */

#undef ERROR_OUT
Expand Down
59 changes: 57 additions & 2 deletions src/ssl_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@
#endif
#endif

#if defined(__APPLE__) && defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
#if defined(__APPLE__)
#if defined(HAVE_SECURITY_SECTRUSTSETTINGS_H)
#include <Security/SecTrustSettings.h>
#endif
#endif /* HAVE_SECURITY_SECTRUSTSETTINGS_H */
#if WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
#include <CoreFoundation/CoreFoundation.h>
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
#endif /* __APPLE__ */

#endif /* WOLFSSL_SYS_CA_CERTS */

Expand Down Expand Up @@ -2153,8 +2158,40 @@ static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl,

/* CA certificate to verify with. */
if (type == CA_TYPE) {
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
word32 derLen;
byte* derBuf;
if (ctx->doAppleNativeCertValidationFlag == 1) {
derLen = der->length;
derBuf = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (derBuf == NULL) {
return MEMORY_E;
}
XMEMCPY(derBuf, der->buffer, derLen);
}
else {
(void)derLen;
(void)derBuf;
}
#endif
/* verify CA unless user set to no verify */
ret = AddCA(ctx->cm, &der, WOLFSSL_USER_CA, verify);
#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ret == 1 && ctx->doAppleNativeCertValidationFlag == 1) {
WOLFSSL_MSG("Appending CA to cert list for native cert validation test");
ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf, (int)derLen);
if (ret == WOLFSSL_SUCCESS) {
WOLFSSL_MSG("Clearing CA table for native cert validation test");
/* Clear the CA table so we can ensure they won't be used for
* verification */
ret = wolfSSL_CertManagerUnloadCAs(ctx->cm);
if (ret == WOLFSSL_SUCCESS) {
ret = 0;
}
}
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif /* !WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
if (ret == 1) {
ret = 0;
}
Expand Down Expand Up @@ -2978,6 +3015,12 @@ int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
ret = NOT_COMPILED_IN;
(void)flags;
#endif

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ret == 1) {
wolfSSL_CTX_load_system_CA_certs(ctx);
}
#endif
}

return ret;
Expand Down Expand Up @@ -3422,6 +3465,12 @@ int wolfSSL_CTX_der_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
GET_VERIFY_SETTING_CTX(ctx));
}

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ret == 1) {
wolfSSL_CTX_load_system_CA_certs(ctx);
}
#endif

/* Return 1 on success or 0 on failure. */
return WS_RC(ret);
}
Expand Down Expand Up @@ -3950,6 +3999,12 @@ int wolfSSL_CTX_load_verify_buffer_ex(WOLFSSL_CTX* ctx, const unsigned char* in,
}
#endif

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
if (ret == 1) {
wolfSSL_CTX_load_system_CA_certs(ctx);
}
#endif

WOLFSSL_LEAVE("wolfSSL_CTX_load_verify_buffer_ex", ret);
return ret;
}
Expand Down
15 changes: 15 additions & 0 deletions wolfssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,10 @@
#include <wolfssl/sniffer.h>
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
#include <CoreFoundation/CoreFoundation.h>
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -4234,6 +4238,10 @@ struct WOLFSSL_CTX {
#if defined(WOLFSSL_SYS_CRYPTO_POLICY)
int secLevel; /* The security level of system-wide crypto policy. */
#endif /* WOLFSSL_SYS_CRYPTO_POLICY */

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
CFMutableArrayRef testTrustedCAs;
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
};

WOLFSSL_LOCAL
Expand Down Expand Up @@ -4270,6 +4278,13 @@ int ProcessOldClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif
#endif

#ifdef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
WOLFSSL_API
int wolfSSL_TestAppleNativeCertValidation_AppendCA(WOLFSSL_CTX* ctx,
const byte* derCert,
int derLen);
#endif /* WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */

/* All cipher suite related info
* Keep as a constant size (no ifdefs) for session export */
typedef struct CipherSpecs {
Expand Down