Skip to content

Commit 89148f9

Browse files
authored
Merge pull request #8921 from rlm2002/appleNativeCertTests
Apple native cert tests code modifications
2 parents 018ee97 + 0302dbc commit 89148f9

File tree

5 files changed

+356
-49
lines changed

5 files changed

+356
-49
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: MacOS apple native cert validation tests
2+
3+
# START OF COMMON SECTION
4+
on:
5+
push:
6+
branches: [ 'master', 'main', 'release/**' ]
7+
pull_request:
8+
branches: [ '*' ]
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
# END OF COMMON SECTION
14+
15+
jobs:
16+
make_check:
17+
strategy:
18+
fail-fast: false
19+
runs-on: macos-latest
20+
# This should be a safe limit for the tests to run.
21+
timeout-minutes: 5
22+
steps:
23+
- name: Build and configure wolfSSL
24+
uses: wolfSSL/actions-build-autotools-project@v1
25+
with:
26+
configure: CFLAGS='-DWOLFSSL_APPLE_NATIVE_CERT_VALIDATION -DWOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION -DRSA_MIN_SIZE=2048 -DNO_WOLFSSL_CIPHER_SUITE_TEST'
27+

src/internal.c

Lines changed: 221 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)