2 * Copyright (c) 2006-2019 Apple Inc. All Rights Reserved.
5 #include <AssertMacros.h>
6 #import <XCTest/XCTest.h>
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <Security/SecCertificate.h>
9 #include <Security/SecCertificatePriv.h>
10 #include <Security/SecPolicyPriv.h>
11 #include <Security/SecTrustPriv.h>
12 #include <utilities/array_size.h>
13 #include <utilities/SecCFRelease.h>
14 #include "trust/trustd/SecOCSPCache.h"
16 #import "../TestMacroConversions.h"
17 #import "../TrustEvaluationTestHelpers.h"
18 #import "TrustEvaluationTestCase.h"
20 #include "RevocationTests_data.h"
22 @interface RevocationTests : TrustEvaluationTestCase
25 @implementation RevocationTests
29 // Delete the OCSP cache between each test
31 SecOCSPCacheDeleteContent(nil);
34 #if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE
35 /* watchOS and bridgeOS don't support networking in trustd */
36 - (void)testRevocation
38 if (!ping_host("ocsp.digicert.com")) {
39 XCTAssert(false, "Unable to contact required network resource");
44 SecCertificateRef cert0, cert1;
45 isnt(cert0 = SecCertificateCreateWithBytes(NULL, _ocsp_c0, sizeof(_ocsp_c0)),
46 NULL, "create cert0");
47 isnt(cert1 = SecCertificateCreateWithBytes(NULL, _ocsp_c1, sizeof(_ocsp_c1)),
48 NULL, "create cert1");
49 CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
50 &kCFTypeArrayCallBacks);
51 CFArrayAppendValue(certs, cert0);
52 CFArrayAppendValue(certs, cert1);
54 SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.apple.com"));
55 SecPolicyRef ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
56 const void *v_policies[] = { sslPolicy, ocspPolicy };
57 CFArrayRef policies = CFArrayCreate(NULL, v_policies,
58 array_size(v_policies), &kCFTypeArrayCallBacks);
60 CFRelease(ocspPolicy);
61 ok_status(SecTrustCreateWithCertificates(certs, policies, &trust),
63 /* April 14, 2019 at 10:46:40 PM PDT */
64 CFDateRef date = CFDateCreate(NULL, 577000000.0);
65 ok_status(SecTrustSetVerifyDate(trust, date), "set date");
67 is(SecTrustGetVerifyTime(trust), 577000000.0, "get date");
69 SecTrustResultType trustResult;
70 ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
71 is_status(trustResult, kSecTrustResultUnspecified,
72 "trust is kSecTrustResultUnspecified");
74 /* Certificates are only EV if they are also CT. */
75 CFDictionaryRef info = SecTrustCopyInfo(trust);
76 CFBooleanRef ev = (CFBooleanRef)CFDictionaryGetValue(info,
77 kSecTrustInfoExtendedValidationKey);
78 ok(ev, "extended validation succeeded");
82 CFReleaseSafe(policies);
89 - (void) test_ocsp_responder_policy
91 SecCertificateRef leaf = NULL, subCA = NULL, responderCert = NULL;
92 CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
93 &kCFTypeArrayCallBacks);
94 SecTrustRef trust = NULL;
95 SecPolicyRef ocspSignerPolicy = NULL;
96 SecTrustResultType trustResult = kSecTrustResultInvalid;
98 /* August 14, 2018 at 9:26:40 PM PDT */
99 CFDateRef date = CFDateCreate(NULL, 556000000.0);
101 isnt(leaf = SecCertificateCreateWithBytes(NULL, valid_ist_certificate,
102 sizeof(valid_ist_certificate)), NULL, "create ist leaf");
103 isnt(subCA = SecCertificateCreateWithBytes(NULL, ist_intermediate_certificate,
104 sizeof(ist_intermediate_certificate)), NULL, "create ist subCA");
105 CFArrayAppendValue(certs, leaf);
106 CFArrayAppendValue(certs, subCA);
108 ok(ocspSignerPolicy = SecPolicyCreateOCSPSigner(),
109 "create ocspSigner policy");
111 ok_status(SecTrustCreateWithCertificates(certs, ocspSignerPolicy, &trust),
112 "create trust for c0 -> c1");
113 ok_status(SecTrustSetVerifyDate(trust, date), "set date");
114 ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
115 is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
116 "trust is kSecTrustResultRecoverableTrustFailure");
118 isnt(responderCert = SecCertificateCreateWithBytes(NULL, _responderCert,
119 sizeof(_responderCert)), NULL, "create responderCert");
120 CFArraySetValueAtIndex(certs, 0, responderCert);
121 ok_status(SecTrustCreateWithCertificates(certs, ocspSignerPolicy, &trust),
122 "create trust for ocspResponder -> c1");
123 ok_status(SecTrustSetVerifyDate(trust, date), "set date");
124 ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
125 is_status(trustResult, kSecTrustResultUnspecified,
126 "trust is kSecTrustResultUnspecified");
129 CFReleaseNull(subCA);
130 CFReleaseNull(responderCert);
131 CFReleaseNull(certs);
132 CFReleaseNull(trust);
133 CFReleaseSafe(ocspSignerPolicy);
137 - (void)test_always_honor_cached_revoked_responses {
138 if (!ping_host("ocsp.apple.com")) {
139 XCTAssert(false, "Unable to contact required network resource");
144 SecCertificateRef rcert0, rcert1;
145 isnt(rcert0 = SecCertificateCreateWithBytes(NULL,
146 revoked_ist_certificate, sizeof(revoked_ist_certificate)),
147 NULL, "create rcert0");
148 isnt(rcert1 = SecCertificateCreateWithBytes(NULL,
149 ist_intermediate_certificate, sizeof(ist_intermediate_certificate)),
150 NULL, "create rcert1");
151 CFMutableArrayRef rcerts = CFArrayCreateMutable(kCFAllocatorDefault, 0,
152 &kCFTypeArrayCallBacks);
153 CFArrayAppendValue(rcerts, rcert0);
154 CFArrayAppendValue(rcerts, rcert1);
156 SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, CFSTR("revoked.geotrust-global-ca.test-pages.certificatemanager.apple.com"));
157 SecPolicyRef ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
158 const void *v_policies[] = { sslPolicy, ocspPolicy };
159 CFArrayRef policies = CFArrayCreate(NULL, v_policies,
160 array_size(v_policies), &kCFTypeArrayCallBacks);
161 CFRelease(sslPolicy);
162 CFRelease(ocspPolicy);
163 ok_status(SecTrustCreateWithCertificates(rcerts, policies, &trust),
166 CFDateRef date = CFDateCreate(NULL, 444900000);
167 ok_status(SecTrustSetVerifyDate(trust, date), "set date");
170 is(SecTrustGetVerifyTime(trust), 444900000, "get date");
172 SecTrustResultType trustResult;
173 ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
174 is(trustResult, kSecTrustResultFatalTrustFailure);
175 CFDictionaryRef results = SecTrustCopyResult(trust);
176 CFTypeRef revoked = NULL;
178 CFArrayRef perCertResults = CFDictionaryGetValue(results, CFSTR("TrustResultDetails"));
179 if (perCertResults) {
180 CFDictionaryRef leafResults = CFArrayGetValueAtIndex(perCertResults, 0);
182 revoked = CFDictionaryGetValue(leafResults, CFSTR("Revocation"));
186 is(revoked != NULL, true, "revoked result is %@", revoked);
187 CFReleaseSafe(results);
190 /* Now verify the cert at a date in the past relative to the previous
191 date, but still within the cert's validity period. Although the
192 cached response from our prior attempt will appear to have been
193 produced in the future, it should still be honored since it's
197 date = CFDateCreate(NULL, 440000000);
198 ok_status(SecTrustSetVerifyDate(trust, date), "set date");
201 is(SecTrustGetVerifyTime(trust), 440000000, "get date");
203 ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
204 is(trustResult, kSecTrustResultFatalTrustFailure);
205 results = SecTrustCopyResult(trust);
208 CFArrayRef perCertResults = CFDictionaryGetValue(results, CFSTR("TrustResultDetails"));
209 if (perCertResults) {
210 CFDictionaryRef leafResults = CFArrayGetValueAtIndex(perCertResults, 0);
212 revoked = CFDictionaryGetValue(leafResults, CFSTR("Revocation"));
216 is(revoked != NULL, true, "revoked result is %@", revoked);
217 CFReleaseSafe(results);
219 CFReleaseSafe(trust);
220 CFReleaseSafe(policies);
221 CFReleaseSafe(rcerts);
222 CFReleaseSafe(rcert0);
223 CFReleaseSafe(rcert1);
226 - (void) test_require_positive_response
228 if (!ping_host("ocsp.apple.com")) {
229 XCTAssert(false, "Unable to contact required network resource");
233 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
234 SecPolicyRef policy = NULL, revocationPolicy = NULL;
235 SecTrustRef trust = NULL;
236 CFArrayRef certs = NULL, anchors = NULL;
237 CFDateRef verifyDate = NULL;
238 CFErrorRef error = NULL;
240 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
241 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
242 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
244 const void *v_certs[] = { leaf, subCA };
245 const void *v_anchors[] = { root };
247 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
248 policy = SecPolicyCreateAppleExternalDeveloper();
249 revocationPolicy = SecPolicyCreateRevocation(kSecRevocationRequirePositiveResponse | kSecRevocationOCSPMethod);
250 NSArray *policies = @[ (__bridge id)policy, (__bridge id)revocationPolicy ];
251 require_noerr_action(SecTrustCreateWithCertificates(certs, (__bridge CFArrayRef)policies, &trust), errOut,
252 fail("failed to create trust object"));
254 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
255 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
257 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
258 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
260 /* Set no fetch allowed */
261 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, false), errOut, fail("failed to set network fetch disallowed"));
263 /* Evaluate trust. Since we required a response but disabled networking, should fail. */
264 is(SecTrustEvaluateWithError(trust, &error), false, "non-definitive revoked cert without network failed");
266 is(CFErrorGetCode(error), errSecIncompleteCertRevocationCheck, "got wrong error code for revoked cert, got %ld, expected %d",
267 (long)CFErrorGetCode(error), errSecIncompleteCertRevocationCheck);
269 fail("expected trust evaluation to fail and it did not.");
271 CFReleaseNull(error);
273 /* Set fetch allowed */
274 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, true), errOut, fail("failed to set network fetch allowed"));
276 /* Evaluate trust. We should re-do the evaluation and get a revoked failure from the OCSP check. */
277 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with network succeeded");
279 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
280 (long)CFErrorGetCode(error), errSecCertificateRevoked);
282 fail("expected trust evaluation to fail and it did not.");
287 CFReleaseNull(subCA);
289 CFReleaseNull(policy);
290 CFReleaseNull(trust);
291 CFReleaseNull(certs);
292 CFReleaseNull(anchors);
293 CFReleaseNull(verifyDate);
294 CFReleaseNull(error);
297 - (void) test_set_fetch_allowed {
298 if (!ping_host("ocsp.apple.com")) {
299 XCTAssert(false, "Unable to contact required network resource");
303 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
304 SecPolicyRef policy = NULL;
305 SecTrustRef trust = NULL;
306 CFArrayRef certs = NULL, anchors = NULL;
307 CFDateRef verifyDate = NULL;
308 CFErrorRef error = NULL;
310 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
311 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
312 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
314 const void *v_certs[] = { leaf, subCA };
315 const void *v_anchors[] = { root };
317 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
318 policy = SecPolicyCreateAppleExternalDeveloper();
319 require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
321 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
322 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
324 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
325 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
327 /* Set no fetch allowed */
328 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, false), errOut, fail("failed to set network fetch disallowed"));
330 /* Evaluate trust. This cert is revoked, but is only listed as "probably not revoked" by valid.apple.com.
331 * Since network fetch is not allowed and we fail open, this cert should come back as trusted. */
332 ok(SecTrustEvaluateWithError(trust, &error), "non-definitive revoked cert without network failed");
333 CFReleaseNull(error);
335 /* Set fetch allowed */
336 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, true), errOut, fail("failed to set network fetch allowed"));
338 /* Evaluate trust. SetFetchAllowed should have reset the trust result, so now we should re-do the evaluation and get a revoked failure. */
339 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with network succeeded");
341 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
342 (long)CFErrorGetCode(error), errSecCertificateRevoked);
344 fail("expected trust evaluation to fail and it did not.");
349 CFReleaseNull(subCA);
351 CFReleaseNull(policy);
352 CFReleaseNull(trust);
353 CFReleaseNull(certs);
354 CFReleaseNull(anchors);
355 CFReleaseNull(verifyDate);
356 CFReleaseNull(error);
359 - (void) test_check_if_trusted {
360 if (!ping_host("ocsp.apple.com")) {
361 XCTAssert(false, "Unable to contact required network resource");
365 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
366 SecPolicyRef codesigningPolicy = NULL, revocationPolicy = NULL;
367 SecTrustRef trust = NULL;
368 CFArrayRef certs = NULL, anchors = NULL, policies = NULL;
369 CFDateRef verifyDate = NULL, badVerifyDate = NULL;
370 CFErrorRef error = NULL;
372 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
373 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
374 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
376 codesigningPolicy = SecPolicyCreateAppleExternalDeveloper();
377 revocationPolicy = SecPolicyCreateRevocation(kSecRevocationCheckIfTrusted);
379 const void *v_certs[] = { leaf, subCA };
380 const void *v_anchors[] = { root };
381 const void *v_policies[] = { codesigningPolicy, revocationPolicy };
383 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
384 policies = CFArrayCreate(NULL, v_policies, 2, &kCFTypeArrayCallBacks);
385 require_noerr_action(SecTrustCreateWithCertificates(certs, policies, &trust), errOut, fail("failed to create trust object"));
387 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
388 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
389 badVerifyDate = CFDateCreate(NULL, 490000000.0); // July 12, 2016 at 12:06:40 AM PDT (before cert issued)
390 require_noerr_action(SecTrustSetVerifyDate(trust, badVerifyDate), errOut, fail("failed to set verify date"));
392 /* Set no fetch allowed */
393 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, false), errOut, fail("failed to set network fetch disallowed"));
395 /* Evaluate trust. This cert is revoked, but is only listed as "probably not revoked" by valid.apple.com.
396 * Since we are evaluating it at a time before it was issued, it should come back as untrusted
397 * due to the temporal validity failure, but not due to revocation since we couldn't check for this
398 * untrusted chain. */
399 is(SecTrustEvaluateWithError(trust, &error), false, "not yet valid cert succeeded trust evaluation");
401 is(CFErrorGetCode(error), errSecCertificateExpired, "got wrong error code for expired cert");
403 fail("expected trust evaluation to fail and it did not.");
405 CFReleaseNull(error);
407 /* Set verify date within validity period */
408 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
409 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
411 /* Evaluate trust. Now that we trust the chain, we should do a revocation check and get a revocation failure. */
412 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with network succeeded");
414 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
415 (long)CFErrorGetCode(error), errSecCertificateRevoked);
417 fail("expected trust evaluation to fail and it did not.");
422 CFReleaseNull(subCA);
424 CFReleaseNull(codesigningPolicy);
425 CFReleaseNull(revocationPolicy);
426 CFReleaseNull(trust);
427 CFReleaseNull(certs);
428 CFReleaseNull(anchors);
429 CFReleaseNull(policies);
430 CFReleaseNull(verifyDate);
431 CFReleaseNull(badVerifyDate);
432 CFReleaseNull(error);
435 - (void) test_cache {
436 if (!ping_host("ocsp.apple.com")) {
437 XCTAssert(false, "Unable to contact required network resource");
441 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
442 SecPolicyRef policy = NULL;
443 SecTrustRef trust = NULL;
444 CFArrayRef certs = NULL, anchors = NULL;
445 CFDateRef verifyDate = NULL;
446 CFErrorRef error = NULL;
448 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
449 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
450 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
452 const void *v_certs[] = { leaf, subCA };
453 const void *v_anchors[] = { root };
455 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
456 policy = SecPolicyCreateAppleExternalDeveloper();
457 require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
459 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
460 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
462 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
463 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
465 /* Evaluate trust. This cert is revoked, but is only listed as "probably not revoked" by valid.apple.com.
466 * This cert should come back as revoked after a network-based fetch. */
467 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with network succeeded");
469 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
470 (long)CFErrorGetCode(error), errSecCertificateRevoked);
472 fail("expected trust evaluation to fail and it did not.");
475 /* Set no fetch allowed, so we're relying on the cached response from above */
476 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, false), errOut, fail("failed to set network fetch disallowed"));
478 /* Evaluate trust. Cached response should tell us that it's revoked. */
479 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with cached response succeeded");
481 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
482 (long)CFErrorGetCode(error), errSecCertificateRevoked);
484 fail("expected trust evaluation to fail and it did not.");
489 CFReleaseNull(subCA);
491 CFReleaseNull(policy);
492 CFReleaseNull(trust);
493 CFReleaseNull(certs);
494 CFReleaseNull(anchors);
495 CFReleaseNull(verifyDate);
496 CFReleaseNull(error);
499 - (void)test_revoked_responses_not_flushed_from_cache
501 if (!ping_host("ocsp.apple.com")) {
502 XCTAssert(false, "Unable to contact required network resource");
506 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
507 SecPolicyRef policy = NULL;
508 SecTrustRef trust = NULL;
509 CFArrayRef certs = NULL, anchors = NULL;
510 CFDateRef verifyDate = NULL;
511 CFErrorRef error = NULL;
513 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
514 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
515 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
517 const void *v_certs[] = { leaf, subCA };
518 const void *v_anchors[] = { root };
520 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
521 policy = SecPolicyCreateAppleExternalDeveloper();
522 require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
524 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
525 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
527 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
528 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
530 /* Evaluate trust. This cert is revoked, but is only listed as "probably not revoked" by valid.apple.com.
531 * This cert should come back as revoked after a network-based fetch. */
532 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with network succeeded");
534 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
535 (long)CFErrorGetCode(error), errSecCertificateRevoked);
537 fail("expected trust evaluation to fail and it did not.");
540 /* Set no fetch allowed, so we're relying on the cached response from above */
541 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, false), errOut, fail("failed to set network fetch disallowed"));
543 /* Evaluate trust. Cached response should tell us that it's revoked. */
544 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with cached response succeeded");
546 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
547 (long)CFErrorGetCode(error), errSecCertificateRevoked);
549 fail("expected trust evaluation to fail and it did not.");
552 /* flush the cache and reset the turst, the revoked response should still be present afterwards */
553 XCTAssert(SecTrustFlushResponseCache(NULL));
554 SecTrustSetNeedsEvaluation(trust);
556 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with cached response succeeded");
558 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
559 (long)CFErrorGetCode(error), errSecCertificateRevoked);
561 fail("expected trust evaluation to fail and it did not.");
566 CFReleaseNull(subCA);
568 CFReleaseNull(policy);
569 CFReleaseNull(trust);
570 CFReleaseNull(certs);
571 CFReleaseNull(anchors);
572 CFReleaseNull(verifyDate);
573 CFReleaseNull(error);
576 - (void) test_results_dictionary_revocation_checked {
577 if (!ping_host("ocsp.digicert.com")) {
578 XCTAssert(false, "Unable to contact required network resource");
582 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
583 SecPolicyRef sslPolicy = NULL, ocspPolicy = NULL;
584 SecTrustRef trust = NULL;
585 CFArrayRef certs = NULL, anchors = NULL, policies = NULL;
586 CFDateRef verifyDate = NULL;
587 CFErrorRef error = NULL;
589 leaf = SecCertificateCreateWithBytes(NULL, _ocsp_c0, sizeof(_ocsp_c0));
590 subCA = SecCertificateCreateWithBytes(NULL, _ocsp_c1, sizeof(_ocsp_c1));
591 root = SecCertificateCreateWithBytes(NULL, _ocsp_c2, sizeof(_ocsp_c2));
593 sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.apple.com"));
594 ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
596 const void *v_certs[] = { leaf, subCA };
597 const void *v_anchors[] = { root };
598 const void *v_policies[] = { sslPolicy, ocspPolicy };
600 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
601 policies = CFArrayCreate(NULL, v_policies, 2, &kCFTypeArrayCallBacks);
602 require_noerr_action(SecTrustCreateWithCertificates(certs, policies, &trust), errOut, fail("failed to create trust object"));
604 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
605 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
607 verifyDate = CFDateCreate(NULL, 577000000.0); // April 14, 2019 at 10:46:40 PM PDT
608 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
610 is(SecTrustEvaluateWithError(trust, &error), true, "valid cert failed");
612 /* Verify that the results dictionary contains all the right keys for a valid cert where revocation checked */
613 CFDictionaryRef result = SecTrustCopyResult(trust);
614 isnt(result, NULL, "failed to copy result dictionary");
616 is(CFDictionaryGetValue(result, kSecTrustRevocationChecked), kCFBooleanTrue, "expected revocation checked flag");
617 CFDateRef validUntil = CFDictionaryGetValue(result, kSecTrustRevocationValidUntilDate);
618 isnt(validUntil, NULL, "expected revocation valid until date");
620 ok(CFDateGetAbsoluteTime(validUntil) > CFAbsoluteTimeGetCurrent(), "expected valid until date in the future");
622 fail("did not get valid until date");
625 CFReleaseNull(result);
629 CFReleaseNull(subCA);
631 CFReleaseNull(ocspPolicy);
632 CFReleaseNull(sslPolicy);
633 CFReleaseNull(trust);
634 CFReleaseNull(certs);
635 CFReleaseNull(anchors);
636 CFReleaseNull(policies);
637 CFReleaseNull(verifyDate);
638 CFReleaseNull(error);
641 - (void) test_revocation_checked_via_cache {
642 if (!ping_host("ocsp.digicert.com")) {
643 XCTAssert(false, "Unable to contact required network resource");
647 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
648 SecPolicyRef sslPolicy = NULL, ocspPolicy = NULL;
649 SecTrustRef trust = NULL;
650 CFArrayRef certs = NULL, anchors = NULL, policies = NULL;
651 CFDateRef verifyDate = NULL;
652 CFErrorRef error = NULL;
654 leaf = SecCertificateCreateWithBytes(NULL, _ocsp_c0, sizeof(_ocsp_c0));
655 subCA = SecCertificateCreateWithBytes(NULL, _ocsp_c1, sizeof(_ocsp_c1));
656 root = SecCertificateCreateWithBytes(NULL, _ocsp_c2, sizeof(_ocsp_c2));
658 sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.apple.com"));
659 ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
661 const void *v_certs[] = { leaf, subCA };
662 const void *v_anchors[] = { root };
663 const void *v_policies[] = { sslPolicy, ocspPolicy };
665 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
666 policies = CFArrayCreate(NULL, v_policies, 2, &kCFTypeArrayCallBacks);
667 require_noerr_action(SecTrustCreateWithCertificates(certs, policies, &trust), errOut, fail("failed to create trust object"));
669 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
670 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
672 verifyDate = CFDateCreate(NULL, 577000000.0); // April 14, 2019 at 10:46:40 PM PDT
673 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
675 is(SecTrustEvaluateWithError(trust, &error), true, "valid cert failed");
677 /* Set no fetch allowed, so we're relying on the cached response from above */
678 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, false), errOut, fail("failed to set network fetch disallowed"));
680 /* Evaluate trust. Cached response should tell us that it's revoked. */
681 is(SecTrustEvaluateWithError(trust, &error), true, "valid cert failed");
683 /* Verify that the results dictionary contains the kSecTrustRevocationChecked key for a valid cert where revocation checked */
684 CFDictionaryRef result = SecTrustCopyResult(trust);
685 isnt(result, NULL, "failed to copy result dictionary");
687 is(CFDictionaryGetValue(result, kSecTrustRevocationChecked), kCFBooleanTrue, "expected revocation checked flag");
689 CFReleaseNull(result);
693 CFReleaseNull(subCA);
695 CFReleaseNull(ocspPolicy);
696 CFReleaseNull(sslPolicy);
697 CFReleaseNull(trust);
698 CFReleaseNull(certs);
699 CFReleaseNull(anchors);
700 CFReleaseNull(policies);
701 CFReleaseNull(verifyDate);
702 CFReleaseNull(error);
705 #else /* TARGET_OS_WATCH || TARGET_OS_BRIDGE */
706 - (void)testNoNetworking
708 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
709 SecPolicyRef policy = NULL;
710 SecTrustRef trust = NULL;
711 CFArrayRef certs = NULL, anchors = NULL;
712 CFDateRef verifyDate = NULL;
713 CFErrorRef error = NULL;
715 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
716 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
717 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
719 const void *v_certs[] = { leaf, subCA };
720 const void *v_anchors[] = { root };
722 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
723 policy = SecPolicyCreateAppleExternalDeveloper();
724 require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
726 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
727 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
729 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
730 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
732 /* Evaluate trust. Since we aren't allowed to do networking (and this cert is only "Probably Not Revoked" in Valid),
733 * we shouldn't see this cert as revoked */
734 is(SecTrustEvaluateWithError(trust, &error), true, "revoked cert with no network failed");
738 CFReleaseNull(subCA);
740 CFReleaseNull(policy);
741 CFReleaseNull(trust);
742 CFReleaseNull(certs);
743 CFReleaseNull(anchors);
744 CFReleaseNull(verifyDate);
745 CFReleaseNull(error);
747 #endif /* !TARGET_OS_WATCH && !TARGET_OS_BRIDGE */
749 #if !TARGET_OS_BRIDGE
750 /* bridgeOS doesn't use Valid */
751 - (NSNumber *)runRevocationCheckNoNetwork:(SecCertificateRef)leaf
752 subCA:(SecCertificateRef)subCA
754 CFArrayRef anchors = NULL;
755 SecPolicyRef smimePolicy = NULL, revocationPolicy = NULL;
756 CFArrayRef certs = NULL;
757 SecTrustRef trust = NULL;
758 CFDateRef date = NULL;
759 CFErrorRef error = NULL;
760 NSArray *policies = nil;
761 NSDictionary *result = nil;
762 NSNumber *revocationChecked = nil;
764 const void *v_certs[] = { leaf };
765 require_action(certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks), errOut,
766 fail("unable to create certificates array"));
767 require_action(anchors = CFArrayCreate(NULL, (const void **)&subCA, 1, &kCFTypeArrayCallBacks), errOut,
768 fail("unable to create anchors array"));
770 require_action(smimePolicy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, NULL), errOut, fail("unable to create policy"));
771 revocationPolicy = SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod | kSecRevocationCheckIfTrusted);
772 policies = @[(__bridge id)smimePolicy, (__bridge id)revocationPolicy];
773 ok_status(SecTrustCreateWithCertificates(certs, (__bridge CFArrayRef)policies, &trust), "failed to create trust");
774 ok_status(SecTrustSetNetworkFetchAllowed(trust, false), "SecTrustSetNetworkFetchAllowed failed");
776 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut,
777 fail("unable to set anchors"));
778 ok(SecTrustEvaluateWithError(trust, &error), "Not trusted");
779 result = CFBridgingRelease(SecTrustCopyResult(trust));
780 revocationChecked = result[(__bridge NSString *)kSecTrustRevocationChecked];
783 CFReleaseNull(anchors);
784 CFReleaseNull(smimePolicy);
785 CFReleaseNull(revocationPolicy);
786 CFReleaseNull(certs);
787 CFReleaseNull(trust);
789 CFReleaseNull(error);
791 return revocationChecked;
794 - (void) test_revocation_checked_via_valid {
795 SecCertificateRef leaf = NULL, subCA = NULL;
796 NSNumber *revocationChecked = NULL;
798 require_action(leaf = SecCertificateCreateWithBytes(NULL, _leaf_sha256_valid_cav2_complete_ok1, sizeof(_leaf_sha256_valid_cav2_complete_ok1)), errOut,
799 fail("unable to create cert"));
800 require_action(subCA = SecCertificateCreateWithBytes(NULL, _ca_sha256_valid_cav2_complete, sizeof(_ca_sha256_valid_cav2_complete)), errOut, fail("unable to create cert"));
802 revocationChecked = [self runRevocationCheckNoNetwork:leaf
804 XCTAssert(revocationChecked != NULL, "kSecTrustRevocationChecked is not in the result dictionary");
808 CFReleaseNull(subCA);
811 - (void) test_revocation_not_checked_no_network {
812 /* The intermediate does not have the noCAv2 flag and is "probably not revoked,", so
813 kSecTrustRevocationChecked should not be in the results dictionary */
814 SecCertificateRef leaf = NULL, subCA = NULL;
815 NSNumber *revocationChecked = NULL;
817 require_action(leaf = SecCertificateCreateWithBytes(NULL, _leaf_serial_invalid_incomplete_ok1, sizeof(_leaf_serial_invalid_incomplete_ok1)), errOut,
818 fail("unable to create cert"));
819 require_action(subCA = SecCertificateCreateWithBytes(NULL, _ca_serial_invalid_incomplete, sizeof(_ca_serial_invalid_incomplete)), errOut, fail("unable to create cert"));
821 revocationChecked = [self runRevocationCheckNoNetwork:leaf
823 XCTAssert(revocationChecked == NULL, "kSecTrustRevocationChecked is in the result dictionary");
827 CFReleaseNull(subCA);
829 #endif /* !TARGET_OS_BRIDGE */
831 /* bridgeOS and watchOS do not support networked OCSP but do support stapling */
832 - (void) test_stapled_revoked_response {
833 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
834 SecPolicyRef policy = NULL;
835 SecTrustRef trust = NULL;
836 CFArrayRef certs = NULL, anchors = NULL;
837 CFDateRef verifyDate = NULL;
838 CFErrorRef error = NULL;
839 CFDataRef ocspResponse = NULL;
841 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
842 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
843 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
845 const void *v_certs[] = { leaf, subCA };
846 const void *v_anchors[] = { root };
848 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
849 policy = SecPolicyCreateAppleExternalDeveloper();
850 require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
852 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
853 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
855 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
856 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
858 /* Set the stapled response */
859 ocspResponse = CFDataCreate(NULL, _devID_OCSPResponse, sizeof(_devID_OCSPResponse));
860 ok_status(SecTrustSetOCSPResponse(trust, ocspResponse), "failed to set OCSP response");
862 /* Set no fetch allowed, so we're relying on the stapled response from above */
863 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust, false), errOut, fail("failed to set network fetch disallowed"));
865 /* Evaluate trust. This cert is revoked, but is only listed as "probably not revoked" by valid.apple.com.
866 * This cert should come back as revoked because of the stapled revoked response. */
867 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert with stapled response succeeded");
869 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
870 (long)CFErrorGetCode(error), errSecCertificateRevoked);
872 fail("expected trust evaluation to fail and it did not.");
877 CFReleaseNull(subCA);
879 CFReleaseNull(policy);
880 CFReleaseNull(trust);
881 CFReleaseNull(certs);
882 CFReleaseNull(anchors);
883 CFReleaseNull(verifyDate);
884 CFReleaseNull(error);
885 CFReleaseNull(ocspResponse);
888 - (void) test_results_dictionary_revocation_reason {
889 SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
890 SecPolicyRef policy = NULL;
891 SecTrustRef trust = NULL;
892 CFArrayRef certs = NULL, anchors = NULL;
893 CFDateRef verifyDate = NULL;
894 CFErrorRef error = NULL;
895 CFDataRef ocspResponse = NULL;
897 leaf = SecCertificateCreateWithBytes(NULL, _probablyNotRevokedLeaf, sizeof(_probablyNotRevokedLeaf));
898 subCA = SecCertificateCreateWithBytes(NULL, _devIDCA, sizeof(_devIDCA));
899 root = SecCertificateCreateWithBytes(NULL, _appleRoot, sizeof(_appleRoot));
901 const void *v_certs[] = { leaf, subCA };
902 const void *v_anchors[] = { root };
904 certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
905 policy = SecPolicyCreateAppleExternalDeveloper();
906 require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
908 anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
909 require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
911 verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
912 require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
914 /* Set the stapled response */
915 ocspResponse = CFDataCreate(NULL, _devID_OCSPResponse, sizeof(_devID_OCSPResponse));
916 ok_status(SecTrustSetOCSPResponse(trust, ocspResponse), "failed to set OCSP response");
918 /* Evaluate trust. This cert is revoked, but is only listed as "probably revoked" by valid.apple.com.
919 * This cert should come back as revoked. */
920 is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert succeeded");
922 is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
923 (long)CFErrorGetCode(error), errSecCertificateRevoked);
925 /* Verify that the results dictionary contains all the right keys for a revoked cert */
926 CFDictionaryRef result = SecTrustCopyResult(trust);
927 isnt(result, NULL, "failed to copy result dictionary");
929 int64_t reason = 4; // superceded
930 CFNumberRef cfreason = CFNumberCreate(NULL, kCFNumberSInt64Type, &reason);
931 is(CFNumberCompare(cfreason, CFDictionaryGetValue(result, kSecTrustRevocationReason), NULL), kCFCompareEqualTo, "expected revocation reason 4");
932 CFReleaseNull(cfreason);
934 CFReleaseNull(result);
936 fail("expected trust evaluation to fail and it did not.");
941 CFReleaseNull(subCA);
943 CFReleaseNull(policy);
944 CFReleaseNull(trust);
945 CFReleaseNull(certs);
946 CFReleaseNull(anchors);
947 CFReleaseNull(verifyDate);
948 CFReleaseNull(error);
949 CFReleaseNull(ocspResponse);