2 * Copyright (c) 2006-2018 Apple Inc. All Rights Reserved.
5 #include <AssertMacros.h>
6 #include <CoreFoundation/CoreFoundation.h>
7 #include <Security/SecCertificate.h>
8 #include <Security/SecCertificatePriv.h>
9 #include <Security/SecPolicyPriv.h>
10 #include <Security/SecTrustPriv.h>
11 #include <utilities/array_size.h>
12 #include <utilities/SecCFRelease.h>
14 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
22 #include "shared_regressions.h"
24 #include "si-23-sectrust-ocsp.h"
26 static void tests(void)
29 SecCertificateRef cert0
, cert1
;
30 isnt(cert0
= SecCertificateCreateWithBytes(NULL
, _ocsp_c0
, sizeof(_ocsp_c0
)),
31 NULL
, "create cert0");
32 isnt(cert1
= SecCertificateCreateWithBytes(NULL
, _ocsp_c1
, sizeof(_ocsp_c1
)),
33 NULL
, "create cert1");
34 CFMutableArrayRef certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
35 &kCFTypeArrayCallBacks
);
36 CFArrayAppendValue(certs
, cert0
);
37 CFArrayAppendValue(certs
, cert1
);
39 SecPolicyRef sslPolicy
= SecPolicyCreateSSL(true, CFSTR("www.apple.com"));
40 SecPolicyRef ocspPolicy
= SecPolicyCreateRevocation(kSecRevocationOCSPMethod
);
41 const void *v_policies
[] = { sslPolicy
, ocspPolicy
};
42 CFArrayRef policies
= CFArrayCreate(NULL
, v_policies
,
43 array_size(v_policies
), &kCFTypeArrayCallBacks
);
45 CFRelease(ocspPolicy
);
46 ok_status(SecTrustCreateWithCertificates(certs
, policies
, &trust
),
48 /* April 14, 2019 at 10:46:40 PM PDT */
49 CFDateRef date
= CFDateCreate(NULL
, 577000000.0);
50 ok_status(SecTrustSetVerifyDate(trust
, date
), "set date");
52 is(SecTrustGetVerifyTime(trust
), 577000000.0, "get date");
54 SecTrustResultType trustResult
;
55 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
56 is_status(trustResult
, kSecTrustResultUnspecified
,
57 "trust is kSecTrustResultUnspecified");
59 /* Certificates are only EV if they are also CT. */
60 CFDictionaryRef info
= SecTrustCopyInfo(trust
);
61 CFBooleanRef ev
= (CFBooleanRef
)CFDictionaryGetValue(info
,
62 kSecTrustInfoExtendedValidationKey
);
63 ok(ev
, "extended validation succeeded");
67 CFReleaseSafe(policies
);
74 static void test_ocsp_responder_policy() {
75 SecCertificateRef leaf
= NULL
, subCA
= NULL
, responderCert
= NULL
;
76 CFMutableArrayRef certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
77 &kCFTypeArrayCallBacks
);
78 SecTrustRef trust
= NULL
;
79 SecPolicyRef ocspSignerPolicy
= NULL
;
80 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
82 /* August 14, 2018 at 9:26:40 PM PDT */
83 CFDateRef date
= CFDateCreate(NULL
, 556000000.0);
85 isnt(leaf
= SecCertificateCreateWithBytes(NULL
, valid_ist_certificate
,
86 sizeof(valid_ist_certificate
)), NULL
, "create ist leaf");
87 isnt(subCA
= SecCertificateCreateWithBytes(NULL
, ist_intermediate_certificate
,
88 sizeof(ist_intermediate_certificate
)), NULL
, "create ist subCA");
89 CFArrayAppendValue(certs
, leaf
);
90 CFArrayAppendValue(certs
, subCA
);
92 ok(ocspSignerPolicy
= SecPolicyCreateOCSPSigner(),
93 "create ocspSigner policy");
95 ok_status(SecTrustCreateWithCertificates(certs
, ocspSignerPolicy
, &trust
),
96 "create trust for c0 -> c1");
97 ok_status(SecTrustSetVerifyDate(trust
, date
), "set date");
98 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
99 is_status(trustResult
, kSecTrustResultRecoverableTrustFailure
,
100 "trust is kSecTrustResultRecoverableTrustFailure");
102 isnt(responderCert
= SecCertificateCreateWithBytes(NULL
, _responderCert
,
103 sizeof(_responderCert
)), NULL
, "create responderCert");
104 CFArraySetValueAtIndex(certs
, 0, responderCert
);
105 ok_status(SecTrustCreateWithCertificates(certs
, ocspSignerPolicy
, &trust
),
106 "create trust for ocspResponder -> c1");
107 ok_status(SecTrustSetVerifyDate(trust
, date
), "set date");
108 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
109 is_status(trustResult
, kSecTrustResultUnspecified
,
110 "trust is kSecTrustResultUnspecified");
113 CFReleaseNull(subCA
);
114 CFReleaseNull(responderCert
);
115 CFReleaseNull(certs
);
116 CFReleaseNull(trust
);
117 CFReleaseSafe(ocspSignerPolicy
);
121 static void test_revocation() {
123 SecCertificateRef rcert0
, rcert1
;
124 isnt(rcert0
= SecCertificateCreateWithBytes(NULL
,
125 revoked_ist_certificate
, sizeof(revoked_ist_certificate
)),
126 NULL
, "create rcert0");
127 isnt(rcert1
= SecCertificateCreateWithBytes(NULL
,
128 ist_intermediate_certificate
, sizeof(ist_intermediate_certificate
)),
129 NULL
, "create rcert1");
130 CFMutableArrayRef rcerts
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
131 &kCFTypeArrayCallBacks
);
132 CFArrayAppendValue(rcerts
, rcert0
);
133 CFArrayAppendValue(rcerts
, rcert1
);
135 SecPolicyRef sslPolicy
= SecPolicyCreateSSL(true, CFSTR("revoked.geotrust-global-ca.test-pages.certificatemanager.apple.com"));
136 SecPolicyRef ocspPolicy
= SecPolicyCreateRevocation(kSecRevocationOCSPMethod
);
137 const void *v_policies
[] = { sslPolicy
, ocspPolicy
};
138 CFArrayRef policies
= CFArrayCreate(NULL
, v_policies
,
139 array_size(v_policies
), &kCFTypeArrayCallBacks
);
140 CFRelease(sslPolicy
);
141 CFRelease(ocspPolicy
);
142 ok_status(SecTrustCreateWithCertificates(rcerts
, policies
, &trust
),
145 CFDateRef date
= CFDateCreate(NULL
, 444900000);
146 ok_status(SecTrustSetVerifyDate(trust
, date
), "set date");
149 is(SecTrustGetVerifyTime(trust
), 444900000, "get date");
151 SecTrustResultType trustResult
;
152 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
153 is((trustResult
> kSecTrustResultUnspecified
), true,
154 "trust is %d, expected value greater than 4", (int)trustResult
);
155 CFDictionaryRef results
= SecTrustCopyResult(trust
);
156 CFTypeRef revoked
= NULL
;
158 CFArrayRef perCertResults
= CFDictionaryGetValue(results
, CFSTR("TrustResultDetails"));
159 if (perCertResults
) {
160 CFDictionaryRef leafResults
= CFArrayGetValueAtIndex(perCertResults
, 0);
162 revoked
= CFDictionaryGetValue(leafResults
, CFSTR("Revocation"));
166 is(revoked
!= NULL
, true, "revoked result is %@", revoked
);
167 CFReleaseSafe(results
);
170 /* Now verify the cert at a date in the past relative to the previous
171 date, but still within the cert's validity period. Although the
172 cached response from our prior attempt will appear to have been
173 produced in the future, it should still be honored since it's
177 date
= CFDateCreate(NULL
, 440000000);
178 ok_status(SecTrustSetVerifyDate(trust
, date
), "set date");
181 is(SecTrustGetVerifyTime(trust
), 440000000, "get date");
183 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
184 is((trustResult
> kSecTrustResultUnspecified
), true,
185 "trust is %d, expected value greater than 4", (int)trustResult
);
186 results
= SecTrustCopyResult(trust
);
189 CFArrayRef perCertResults
= CFDictionaryGetValue(results
, CFSTR("TrustResultDetails"));
190 if (perCertResults
) {
191 CFDictionaryRef leafResults
= CFArrayGetValueAtIndex(perCertResults
, 0);
193 revoked
= CFDictionaryGetValue(leafResults
, CFSTR("Revocation"));
197 is(revoked
!= NULL
, true, "revoked result is %@", revoked
);
198 CFReleaseSafe(results
);
200 CFReleaseSafe(trust
);
201 CFReleaseSafe(policies
);
202 CFReleaseSafe(rcerts
);
203 CFReleaseSafe(rcert0
);
204 CFReleaseSafe(rcert1
);
207 static void test_forced_revocation()
210 * Test verification requiring a positive response from the revocation server
214 SecCertificateRef smime_leaf_cert
;
215 SecCertificateRef smime_CA_cert
;
216 SecCertificateRef smime_root_cert
;
218 // Import certificates from byte array above
219 isnt(smime_leaf_cert
= SecCertificateCreateWithBytes(NULL
, ocsp_smime_leaf_certificate
, sizeof(ocsp_smime_leaf_certificate
)),
220 NULL
, "SMIME Leaf Cert");
221 isnt(smime_CA_cert
= SecCertificateCreateWithBytes(NULL
, ocsp_smime_CA_certificate
, sizeof(ocsp_smime_CA_certificate
)),
222 NULL
, "SMIME CA Cert");
223 isnt(smime_root_cert
= SecCertificateCreateWithBytes(NULL
, ocsp_smime_root_certificate
, sizeof(ocsp_smime_root_certificate
)),
224 NULL
, "SMIME Root Cert");
226 SecPolicyRef smimePolicy
= SecPolicyCreateWithProperties(kSecPolicyAppleSMIME
, NULL
);
227 SecPolicyRef revocPolicy
= SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod
| kSecRevocationRequirePositiveResponse
);
228 isnt(smimePolicy
, NULL
, "SMIME Policy");
229 isnt(revocPolicy
, NULL
, "SMIME Revocation Policy");
232 CFMutableArrayRef SMIMEDefaultPolicy
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
233 CFArrayAppendValue(SMIMEDefaultPolicy
, smimePolicy
);
235 // Default Policies + explicit revocation
236 CFMutableArrayRef SMIMEDefaultPolicyWithRevocation
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
237 CFArrayAppendValue(SMIMEDefaultPolicyWithRevocation
, smimePolicy
);
238 CFArrayAppendValue(SMIMEDefaultPolicyWithRevocation
, revocPolicy
);
240 // Valid chain of Cert (leaf + CA)
241 CFMutableArrayRef SMIMECertChain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
242 CFArrayAppendValue(SMIMECertChain
, smime_leaf_cert
);
243 CFArrayAppendValue(SMIMECertChain
, smime_CA_cert
);
245 // Valid anchor certs
246 CFMutableArrayRef SMIMEAnchors
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
247 CFArrayAppendValue(SMIMEAnchors
, smime_root_cert
);
249 // Free Resources contained in arrays
250 CFReleaseSafe(smime_leaf_cert
);
251 CFReleaseSafe(smime_CA_cert
);
252 CFReleaseSafe(smime_root_cert
);
253 CFReleaseSafe(smimePolicy
);
254 CFReleaseSafe(revocPolicy
);
256 CFDateRef VerifyDate
;
257 isnt(VerifyDate
= CFDateCreate(NULL
, 332900000.0), NULL
, "Create verify date");
258 if (!VerifyDate
) { goto errOut
; }
260 // Standard evaluation for the given verify date
262 SecTrustRef trust
= NULL
;
263 SecTrustResultType trust_result
;
265 ok_status(status
= SecTrustCreateWithCertificates(SMIMECertChain
, SMIMEDefaultPolicy
, &trust
),
266 "SecTrustCreateWithCertificates");
267 ok_status(SecTrustSetVerifyDate(trust
, VerifyDate
), "Set date");
268 ok_status(SecTrustSetAnchorCertificates(trust
, SMIMEAnchors
), "Set anchors");
270 ok_status(status
= SecTrustEvaluate(trust
, &trust_result
), "SecTrustEvaluate");
273 // NOTE: We now expect a fatal error, since the "TC TrustCenter Class 1 L1 CA IX" CA
274 // is revoked. That CA is no longer present in Valid since the TC root was removed
275 // from the trust store, and as of May 2018, its OCSP server no longer resolves in DNS.
276 // However, the OCSP URI for the CA's issuer is still active and reports the CA as revoked.
278 is_status(trust_result
, kSecTrustResultFatalTrustFailure
, "trust is kSecTrustResultFatalTrustFailure");
280 CFReleaseNull(trust
);
283 // Revocation-required evaluation should fail, since this CA's servers no longer exist
284 // and no valid responses are available
286 SecTrustRef trust
= NULL
;
287 SecTrustResultType trust_result
;
289 ok_status(status
= SecTrustCreateWithCertificates(SMIMECertChain
, SMIMEDefaultPolicyWithRevocation
, &trust
),
290 "SecTrustCreateWithCertificates");
291 ok_status(SecTrustSetVerifyDate(trust
, VerifyDate
), "Set date");
292 ok_status(SecTrustSetAnchorCertificates(trust
, SMIMEAnchors
), "Set anchors");
294 ok_status(status
= SecTrustEvaluate(trust
, &trust_result
), "SecTrustEvaluate");
297 // NOTE: We now expect a fatal error, since the "TC TrustCenter Class 1 L1 CA IX" CA
298 // is revoked. That CA is no longer present in Valid since the TC root was removed
299 // from the trust store, and as of May 2018, its OCSP server no longer resolves in DNS.
300 // However, the OCSP URI for the CA's issuer is still active and reports the CA as revoked.
302 is_status(trust_result
, kSecTrustResultFatalTrustFailure
, "trust is kSecTrustResultFatalTrustFailure");
304 CFReleaseNull(trust
);
307 // Free remaining resources
309 CFReleaseSafe(VerifyDate
);
310 CFReleaseSafe(SMIMEDefaultPolicy
);
311 CFReleaseSafe(SMIMEDefaultPolicyWithRevocation
);
312 CFReleaseSafe(SMIMECertChain
);
313 CFReleaseSafe(SMIMEAnchors
);
317 static void hexdump(const uint8_t *bytes
, size_t len
) {
319 printf("#anchor-sha1: ");
320 for (ix
= 0; ix
< len
; ++ix
) {
321 printf("%02X", bytes
[ix
]);
326 static void datadump(const uint8_t *bytes
, size_t len
) {
328 printf("#anchor-sha1: ");
329 for (ix
= 0; ix
< len
; ++ix
) {
330 printf("%c", bytes
[ix
]);
335 static void display_anchor_digest(SecTrustRef trust
) {
336 CFIndex count
= SecTrustGetCertificateCount(trust
);
337 SecCertificateRef anchor
= SecTrustGetCertificateAtIndex(trust
, count
- 1);
338 CFDataRef digest
= SecCertificateGetSHA1Digest(anchor
);
339 CFDataRef xml
= CFPropertyListCreateXMLData(NULL
, digest
);
340 datadump(CFDataGetBytePtr(xml
), CFDataGetLength(xml
));
344 static void test_aia(void) {
345 SecCertificateRef ovh
= NULL
, comodo_ev
= NULL
, comodo_aia
= NULL
;
346 CFMutableArrayRef certs
= NULL
, policies
= NULL
;
347 SecPolicyRef sslPolicy
= NULL
, revPolicy
= NULL
;
348 CFDateRef verifyDate
= NULL
;
349 CFDictionaryRef info
= NULL
;
350 SecTrustRef trust
= NULL
;
351 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
352 CFBooleanRef ev
= NULL
;
354 /* Initialize common variables */
355 isnt(ovh
= SecCertificateCreateWithBytes(NULL
, ovh_certificate
,
356 sizeof(ovh_certificate
)), NULL
, "create ovh cert");
357 isnt(comodo_ev
= SecCertificateCreateWithBytes(NULL
, comodo_ev_certificate
,
358 sizeof(comodo_ev_certificate
)), NULL
, "create comodo_ev cert");
359 isnt(comodo_aia
= SecCertificateCreateWithBytes(NULL
,
360 comodo_aia_certificate
, sizeof(comodo_aia_certificate
)), NULL
,
361 "create comodo_aia cert");
362 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
363 &kCFTypeArrayCallBacks
);
364 policies
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
365 &kCFTypeArrayCallBacks
);
366 sslPolicy
= SecPolicyCreateSSL(false, NULL
); // For now, use SSL client policy to avoid SHA-1 deprecation
367 revPolicy
= SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod
);
368 CFArrayAppendValue(policies
, sslPolicy
);
369 CFArrayAppendValue(policies
, revPolicy
);
371 verifyDate
= CFDateCreate(NULL
, 547600500);
373 /* First run with no intermediate and disallow network fetching.
374 * Evaluation should fail because it couldn't get the intermediate. */
375 CFArrayAppendValue(certs
, ovh
);
376 ok_status(SecTrustCreateWithCertificates(certs
, policies
, &trust
),
378 ok_status(SecTrustSetVerifyDate(trust
, verifyDate
), "set date");
379 ok_status(SecTrustSetNetworkFetchAllowed(trust
, false), "set no network");
380 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
381 is_status(trustResult
, kSecTrustResultRecoverableTrustFailure
,
382 "trust is kSecTrustResultRecoverableTrustFailure");
384 /* Now allow networking. Evaluation should succeed after fetching
385 * the intermediate. */
386 ok_status(SecTrustSetNetworkFetchAllowed(trust
, true), "set allow network");
387 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
388 is_status(trustResult
, kSecTrustResultUnspecified
,
389 "trust is kSecTrustResultUnspecified");
390 CFReleaseNull(trust
);
392 /* Now run with the intermediate returned by the ssl server. */
393 CFArrayAppendValue(certs
, comodo_ev
);
394 ok_status(SecTrustCreateWithCertificates(certs
, sslPolicy
, &trust
),
396 ok_status(SecTrustSetVerifyDate(trust
, verifyDate
), "set date");
397 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
398 is_status(trustResult
, kSecTrustResultUnspecified
,
399 "trust is kSecTrustResultUnspecified");
400 info
= SecTrustCopyInfo(trust
);
401 ev
= (CFBooleanRef
)CFDictionaryGetValue(info
,
402 kSecTrustInfoExtendedValidationKey
);
403 ok(ev
, "extended validation succeeded due to caissuers fetch");
404 //display_anchor_digest(trust);
406 CFReleaseSafe(trust
);
408 /* Now run with the intermediate returned by following the url in the
409 Certificate Access Information Authority (AIA) extension of the ovh
411 CFArrayAppendValue(certs
, comodo_aia
);
412 ok_status(SecTrustCreateWithCertificates(certs
, sslPolicy
, &trust
),
413 "re-create trust with aia intermediate");
414 ok_status(SecTrustSetVerifyDate(trust
, verifyDate
), "set date");
415 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
416 is_status(trustResult
, kSecTrustResultUnspecified
,
417 "trust is kSecTrustResultUnspecified");
418 info
= SecTrustCopyInfo(trust
);
419 ev
= (CFBooleanRef
)CFDictionaryGetValue(info
,
420 kSecTrustInfoExtendedValidationKey
);
421 ok(ev
, "extended validation succeeded");
422 //display_anchor_digest(trust);
424 CFReleaseSafe(trust
);
426 /* Now run with the intermediate returned by following the url in the
427 Certificate Access Information Authority (AIA) extension of the ovh
429 CFArrayRemoveValueAtIndex(certs
, 1);
430 ok_status(SecTrustCreateWithCertificates(certs
, sslPolicy
, &trust
),
431 "re-create trust with aia intermediate");
432 ok_status(SecTrustSetVerifyDate(trust
, verifyDate
), "set date");
433 ok_status(SecTrustEvaluate(trust
, &trustResult
), "evaluate trust");
434 is_status(trustResult
, kSecTrustResultUnspecified
,
435 "trust is kSecTrustResultUnspecified");
436 info
= SecTrustCopyInfo(trust
);
437 ev
= (CFBooleanRef
)CFDictionaryGetValue(info
,
438 kSecTrustInfoExtendedValidationKey
);
439 ok(ev
, "extended validation succeeded");
440 //display_anchor_digest(trust);
442 CFReleaseSafe(trust
);
444 /* Common variable cleanup. */
445 CFReleaseSafe(sslPolicy
);
446 CFReleaseSafe(revPolicy
);
447 CFReleaseSafe(certs
);
448 CFReleaseSafe(policies
);
449 CFReleaseSafe(comodo_aia
);
450 CFReleaseSafe(comodo_ev
);
452 CFReleaseSafe(verifyDate
);
455 static void test_aia_https(void) {
456 SecCertificateRef leaf
= NULL
;
457 SecPolicyRef policy
= NULL
;
458 SecTrustRef trust
= NULL
;
459 CFArrayRef certs
= NULL
;
460 CFDateRef verifyDate
= NULL
;
461 CFErrorRef error
= NULL
;
463 leaf
= SecCertificateCreateWithBytes(NULL
, _caissuer_https
, sizeof(_caissuer_https
));
464 const void *v_certs
[] = { leaf
};
466 certs
= CFArrayCreate(NULL
, v_certs
, 1, &kCFTypeArrayCallBacks
);
467 policy
= SecPolicyCreateSSL(true, CFSTR("example.com"));
468 require_noerr_action(SecTrustCreateWithCertificates(certs
, policy
, &trust
), errOut
, fail("failed to create trust object"));
470 verifyDate
= CFDateCreate(NULL
, 546700000.0); // April 29, 2018 at 6:06:40 AM PDT
471 require_noerr_action(SecTrustSetVerifyDate(trust
, verifyDate
), errOut
, fail("failed to set verify date"));
473 #pragma clang diagnostic push
474 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
475 /* Evaluate trust. This cert does not chain to anything trusted and we can't fetch an
476 * intermediate because the URI is https. */
477 is(SecTrustEvaluateWithError(trust
, &error
), false, "leaf with missing intermediate and https CAIssuer URI succeeded");
479 is(CFErrorGetCode(error
), errSecCreateChainFailed
, "got wrong error code for revoked cert, got %ld, expected %d",
480 (long)CFErrorGetCode(error
), errSecCreateChainFailed
);
482 fail("expected trust evaluation to fail and it did not.");
484 #pragma clang diagnostic pop
488 CFReleaseNull(policy
);
489 CFReleaseNull(trust
);
490 CFReleaseNull(certs
);
491 CFReleaseNull(verifyDate
);
492 CFReleaseNull(error
);
495 static void test_set_fetch_allowed(void) {
496 SecCertificateRef leaf
= NULL
, subCA
= NULL
, root
= NULL
;
497 SecPolicyRef policy
= NULL
;
498 SecTrustRef trust
= NULL
;
499 CFArrayRef certs
= NULL
, anchors
= NULL
;
500 CFDateRef verifyDate
= NULL
;
501 CFErrorRef error
= NULL
;
503 leaf
= SecCertificateCreateWithBytes(NULL
, _probablyRevokedLeaf
, sizeof(_probablyRevokedLeaf
));
504 subCA
= SecCertificateCreateWithBytes(NULL
, _digiCertSha2SubCA
, sizeof(_digiCertSha2SubCA
));
505 root
= SecCertificateCreateWithBytes(NULL
, _digiCertGlobalRoot
, sizeof(_digiCertGlobalRoot
));
507 const void *v_certs
[] = { leaf
, subCA
};
508 const void *v_anchors
[] = { root
};
510 certs
= CFArrayCreate(NULL
, v_certs
, 2, &kCFTypeArrayCallBacks
);
511 policy
= SecPolicyCreateSSL(true, CFSTR("revoked.badssl.com"));
512 require_noerr_action(SecTrustCreateWithCertificates(certs
, policy
, &trust
), errOut
, fail("failed to create trust object"));
514 anchors
= CFArrayCreate(NULL
, v_anchors
, 1, &kCFTypeArrayCallBacks
);
515 require_noerr_action(SecTrustSetAnchorCertificates(trust
, anchors
), errOut
, fail("failed to set anchors"));
517 verifyDate
= CFDateCreate(NULL
, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
518 require_noerr_action(SecTrustSetVerifyDate(trust
, verifyDate
), errOut
, fail("failed to set verify date"));
520 /* Clear the OCSP cache in case there are old responses for this cert. */
521 ok(SecTrustFlushResponseCache(&error
), "OCSP cache flush failed");
522 CFReleaseNull(error
);
524 /* Set no fetch allowed */
525 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust
, false), errOut
, fail("failed to set network fetch disallowed"));
527 #pragma clang diagnostic push
528 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
529 /* Evaluate trust. This cert is revoked, but is only listed as "probably revoked" by valid.apple.com.
530 * Since network fetch is not allowed and we fail open, this cert should come back as trusted. */
531 ok(SecTrustEvaluateWithError(trust
, &error
), "non-definitive revoked cert without network failed");
532 CFReleaseNull(error
);
534 /* Set fetch allowed */
535 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust
, true), errOut
, fail("failed to set network fetch allowed"));
537 /* Evaluate trust. SetFetchAllowed should have reset the trust result, so now we should re-do the evaluation and get a revoked failure. */
538 is(SecTrustEvaluateWithError(trust
, &error
), false, "revoked cert with network succeeded");
540 is(CFErrorGetCode(error
), errSecCertificateRevoked
, "got wrong error code for revoked cert, got %ld, expected %d",
541 (long)CFErrorGetCode(error
), errSecCertificateRevoked
);
543 fail("expected trust evaluation to fail and it did not.");
546 #pragma clang diagnostic pop
550 CFReleaseNull(subCA
);
552 CFReleaseNull(policy
);
553 CFReleaseNull(trust
);
554 CFReleaseNull(certs
);
555 CFReleaseNull(anchors
);
556 CFReleaseNull(verifyDate
);
557 CFReleaseNull(error
);
560 static void test_check_if_trusted(void) {
561 SecCertificateRef leaf
= NULL
, subCA
= NULL
, root
= NULL
;
562 SecPolicyRef sslPolicy
= NULL
, revocationPolicy
= NULL
;
563 SecTrustRef trust
= NULL
;
564 CFArrayRef certs
= NULL
, anchors
= NULL
, policies
= NULL
;
565 CFDateRef verifyDate
= NULL
, badVerifyDate
= NULL
;
566 CFErrorRef error
= NULL
;
568 leaf
= SecCertificateCreateWithBytes(NULL
, _probablyRevokedLeaf
, sizeof(_probablyRevokedLeaf
));
569 subCA
= SecCertificateCreateWithBytes(NULL
, _digiCertSha2SubCA
, sizeof(_digiCertSha2SubCA
));
570 root
= SecCertificateCreateWithBytes(NULL
, _digiCertGlobalRoot
, sizeof(_digiCertGlobalRoot
));
572 sslPolicy
= SecPolicyCreateSSL(true, CFSTR("revoked.badssl.com"));
573 revocationPolicy
= SecPolicyCreateRevocation(kSecRevocationCheckIfTrusted
);
575 const void *v_certs
[] = { leaf
, subCA
};
576 const void *v_anchors
[] = { root
};
577 const void *v_policies
[] = { sslPolicy
, revocationPolicy
};
579 certs
= CFArrayCreate(NULL
, v_certs
, 2, &kCFTypeArrayCallBacks
);
580 policies
= CFArrayCreate(NULL
, v_policies
, 2, &kCFTypeArrayCallBacks
);
581 require_noerr_action(SecTrustCreateWithCertificates(certs
, policies
, &trust
), errOut
, fail("failed to create trust object"));
583 anchors
= CFArrayCreate(NULL
, v_anchors
, 1, &kCFTypeArrayCallBacks
);
584 require_noerr_action(SecTrustSetAnchorCertificates(trust
, anchors
), errOut
, fail("failed to set anchors"));
585 badVerifyDate
= CFDateCreate(NULL
, 490000000.0); // July 12, 2016 at 12:06:40 AM PDT (before cert issued)
586 require_noerr_action(SecTrustSetVerifyDate(trust
, badVerifyDate
), errOut
, fail("failed to set verify date"));
588 /* Clear the OCSP cache in case there are old responses for this cert. */
589 ok(SecTrustFlushResponseCache(&error
), "OCSP cache flush failed");
590 CFReleaseNull(error
);
592 /* Set no fetch allowed */
593 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust
, false), errOut
, fail("failed to set network fetch disallowed"));
595 #pragma clang diagnostic push
596 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
597 /* Evaluate trust. This cert is revoked, but is only listed as "probably revoked" by valid.apple.com.
598 * Since we are evaluating it at a time before it was issued, it should come back as untrusted
599 * due to the temporal validity failure, but not due to revocation since we couldn't check for this
600 * untrusted chain. */
601 is(SecTrustEvaluateWithError(trust
, &error
), false, "not yet valid cert succeeded trust evaluation");
603 is(CFErrorGetCode(error
), errSecCertificateExpired
, "got wrong error code for expired cert");
605 fail("expected trust evaluation to fail and it did not.");
607 CFReleaseNull(error
);
609 /* Set verify date within validity period */
610 verifyDate
= CFDateCreate(NULL
, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
611 require_noerr_action(SecTrustSetVerifyDate(trust
, verifyDate
), errOut
, fail("failed to set verify date"));
613 /* Evaluate trust. Now that we trust the chain, we should do a revocation check and get a revocation failure. */
614 is(SecTrustEvaluateWithError(trust
, &error
), false, "revoked cert with network succeeded");
616 is(CFErrorGetCode(error
), errSecCertificateRevoked
, "got wrong error code for revoked cert, got %ld, expected %d",
617 (long)CFErrorGetCode(error
), errSecCertificateRevoked
);
619 fail("expected trust evaluation to fail and it did not.");
621 #pragma clang diagnostic pop
625 CFReleaseNull(subCA
);
627 CFReleaseNull(sslPolicy
);
628 CFReleaseNull(revocationPolicy
);
629 CFReleaseNull(trust
);
630 CFReleaseNull(certs
);
631 CFReleaseNull(anchors
);
632 CFReleaseNull(policies
);
633 CFReleaseNull(verifyDate
);
634 CFReleaseNull(badVerifyDate
);
635 CFReleaseNull(error
);
638 static void test_cache(void) {
639 SecCertificateRef leaf
= NULL
, subCA
= NULL
, root
= NULL
;
640 SecPolicyRef policy
= NULL
;
641 SecTrustRef trust
= NULL
;
642 CFArrayRef certs
= NULL
, anchors
= NULL
;
643 CFDateRef verifyDate
= NULL
;
644 CFErrorRef error
= NULL
;
646 leaf
= SecCertificateCreateWithBytes(NULL
, _probablyRevokedLeaf
, sizeof(_probablyRevokedLeaf
));
647 subCA
= SecCertificateCreateWithBytes(NULL
, _digiCertSha2SubCA
, sizeof(_digiCertSha2SubCA
));
648 root
= SecCertificateCreateWithBytes(NULL
, _digiCertGlobalRoot
, sizeof(_digiCertGlobalRoot
));
650 const void *v_certs
[] = { leaf
, subCA
};
651 const void *v_anchors
[] = { root
};
653 certs
= CFArrayCreate(NULL
, v_certs
, 2, &kCFTypeArrayCallBacks
);
654 policy
= SecPolicyCreateSSL(true, CFSTR("revoked.badssl.com"));
655 require_noerr_action(SecTrustCreateWithCertificates(certs
, policy
, &trust
), errOut
, fail("failed to create trust object"));
657 anchors
= CFArrayCreate(NULL
, v_anchors
, 1, &kCFTypeArrayCallBacks
);
658 require_noerr_action(SecTrustSetAnchorCertificates(trust
, anchors
), errOut
, fail("failed to set anchors"));
660 verifyDate
= CFDateCreate(NULL
, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
661 require_noerr_action(SecTrustSetVerifyDate(trust
, verifyDate
), errOut
, fail("failed to set verify date"));
663 /* Clear the OCSP cache in case there are old responses for this cert. */
664 ok(SecTrustFlushResponseCache(&error
), "OCSP cache flush failed");
665 CFReleaseNull(error
);
667 #pragma clang diagnostic push
668 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
669 /* Evaluate trust. This cert is revoked, but is only listed as "probably revoked" by valid.apple.com.
670 * This cert should come back as revoked after a network-based fetch. */
671 is(SecTrustEvaluateWithError(trust
, &error
), false, "revoked cert with network succeeded");
673 is(CFErrorGetCode(error
), errSecCertificateRevoked
, "got wrong error code for revoked cert, got %ld, expected %d",
674 (long)CFErrorGetCode(error
), errSecCertificateRevoked
);
676 fail("expected trust evaluation to fail and it did not.");
679 /* Set no fetch allowed, so we're relying on the cached response from above */
680 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust
, false), errOut
, fail("failed to set network fetch disallowed"));
682 /* Evaluate trust. Cached response should tell us that it's revoked. */
683 is(SecTrustEvaluateWithError(trust
, &error
), false, "revoked cert with cached response succeeded");
685 is(CFErrorGetCode(error
), errSecCertificateRevoked
, "got wrong error code for revoked cert, got %ld, expected %d",
686 (long)CFErrorGetCode(error
), errSecCertificateRevoked
);
688 fail("expected trust evaluation to fail and it did not.");
691 #pragma clang diagnostic pop
695 CFReleaseNull(subCA
);
697 CFReleaseNull(policy
);
698 CFReleaseNull(trust
);
699 CFReleaseNull(certs
);
700 CFReleaseNull(anchors
);
701 CFReleaseNull(verifyDate
);
702 CFReleaseNull(error
);
705 static void test_stapled_revoked_response(void) {
706 SecCertificateRef leaf
= NULL
, subCA
= NULL
, root
= NULL
;
707 SecPolicyRef policy
= NULL
;
708 SecTrustRef trust
= NULL
;
709 CFArrayRef certs
= NULL
, anchors
= NULL
;
710 CFDateRef verifyDate
= NULL
;
711 CFErrorRef error
= NULL
;
712 CFDataRef ocspResponse
= NULL
;
714 leaf
= SecCertificateCreateWithBytes(NULL
, _probablyRevokedLeaf
, sizeof(_probablyRevokedLeaf
));
715 subCA
= SecCertificateCreateWithBytes(NULL
, _digiCertSha2SubCA
, sizeof(_digiCertSha2SubCA
));
716 root
= SecCertificateCreateWithBytes(NULL
, _digiCertGlobalRoot
, sizeof(_digiCertGlobalRoot
));
718 const void *v_certs
[] = { leaf
, subCA
};
719 const void *v_anchors
[] = { root
};
721 certs
= CFArrayCreate(NULL
, v_certs
, 2, &kCFTypeArrayCallBacks
);
722 policy
= SecPolicyCreateSSL(true, CFSTR("revoked.badssl.com"));
723 require_noerr_action(SecTrustCreateWithCertificates(certs
, policy
, &trust
), errOut
, fail("failed to create trust object"));
725 anchors
= CFArrayCreate(NULL
, v_anchors
, 1, &kCFTypeArrayCallBacks
);
726 require_noerr_action(SecTrustSetAnchorCertificates(trust
, anchors
), errOut
, fail("failed to set anchors"));
728 verifyDate
= CFDateCreate(NULL
, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
729 require_noerr_action(SecTrustSetVerifyDate(trust
, verifyDate
), errOut
, fail("failed to set verify date"));
731 /* Set the stapled response */
732 ocspResponse
= CFDataCreate(NULL
, _digicertOCSPResponse
, sizeof(_digicertOCSPResponse
));
733 ok_status(SecTrustSetOCSPResponse(trust
, ocspResponse
), "failed to set OCSP response");
735 /* Clear the OCSP cache in case there are old responses for this cert. */
736 ok(SecTrustFlushResponseCache(&error
), "OCSP cache flush failed");
737 CFReleaseNull(error
);
739 /* Set no fetch allowed, so we're relying on the stapled response from above */
740 require_noerr_action(SecTrustSetNetworkFetchAllowed(trust
, false), errOut
, fail("failed to set network fetch disallowed"));
742 #pragma clang diagnostic push
743 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
744 /* Evaluate trust. This cert is revoked, but is only listed as "probably revoked" by valid.apple.com.
745 * This cert should come back as revoked because of the stapled revoked response. */
746 is(SecTrustEvaluateWithError(trust
, &error
), false, "revoked cert with stapled response succeeded");
748 is(CFErrorGetCode(error
), errSecCertificateRevoked
, "got wrong error code for revoked cert, got %ld, expected %d",
749 (long)CFErrorGetCode(error
), errSecCertificateRevoked
);
751 fail("expected trust evaluation to fail and it did not.");
754 #pragma clang diagnostic pop
758 CFReleaseNull(subCA
);
760 CFReleaseNull(policy
);
761 CFReleaseNull(trust
);
762 CFReleaseNull(certs
);
763 CFReleaseNull(anchors
);
764 CFReleaseNull(verifyDate
);
765 CFReleaseNull(error
);
766 CFReleaseNull(ocspResponse
);
769 static void test_results_dictionary_revocation_reason(void) {
770 SecCertificateRef leaf
= NULL
, subCA
= NULL
, root
= NULL
;
771 SecPolicyRef policy
= NULL
;
772 SecTrustRef trust
= NULL
;
773 CFArrayRef certs
= NULL
, anchors
= NULL
;
774 CFDateRef verifyDate
= NULL
;
775 CFErrorRef error
= NULL
;
776 CFDataRef ocspResponse
= NULL
;
778 leaf
= SecCertificateCreateWithBytes(NULL
, _probablyRevokedLeaf
, sizeof(_probablyRevokedLeaf
));
779 subCA
= SecCertificateCreateWithBytes(NULL
, _digiCertSha2SubCA
, sizeof(_digiCertSha2SubCA
));
780 root
= SecCertificateCreateWithBytes(NULL
, _digiCertGlobalRoot
, sizeof(_digiCertGlobalRoot
));
782 const void *v_certs
[] = { leaf
, subCA
};
783 const void *v_anchors
[] = { root
};
785 certs
= CFArrayCreate(NULL
, v_certs
, 2, &kCFTypeArrayCallBacks
);
786 policy
= SecPolicyCreateSSL(true, CFSTR("revoked.badssl.com"));
787 require_noerr_action(SecTrustCreateWithCertificates(certs
, policy
, &trust
), errOut
, fail("failed to create trust object"));
789 anchors
= CFArrayCreate(NULL
, v_anchors
, 1, &kCFTypeArrayCallBacks
);
790 require_noerr_action(SecTrustSetAnchorCertificates(trust
, anchors
), errOut
, fail("failed to set anchors"));
792 verifyDate
= CFDateCreate(NULL
, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
793 require_noerr_action(SecTrustSetVerifyDate(trust
, verifyDate
), errOut
, fail("failed to set verify date"));
795 /* Set the stapled response */
796 ocspResponse
= CFDataCreate(NULL
, _digicertOCSPResponse
, sizeof(_digicertOCSPResponse
));
797 ok_status(SecTrustSetOCSPResponse(trust
, ocspResponse
), "failed to set OCSP response");
799 #pragma clang diagnostic push
800 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
801 /* Evaluate trust. This cert is revoked, but is only listed as "probably revoked" by valid.apple.com.
802 * This cert should come back as revoked. */
803 is(SecTrustEvaluateWithError(trust
, &error
), false, "revoked cert succeeded");
805 is(CFErrorGetCode(error
), errSecCertificateRevoked
, "got wrong error code for revoked cert, got %ld, expected %d",
806 (long)CFErrorGetCode(error
), errSecCertificateRevoked
);
808 /* Verify that the results dictionary contains all the right keys for a revoked cert */
809 CFDictionaryRef result
= SecTrustCopyResult(trust
);
810 isnt(result
, NULL
, "failed to copy result dictionary");
813 CFNumberRef cfreason
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &reason
);
814 is(CFNumberCompare(cfreason
, CFDictionaryGetValue(result
, kSecTrustRevocationReason
), NULL
), kCFCompareEqualTo
, "expected revocation reason -1");
815 CFReleaseNull(cfreason
);
817 CFReleaseNull(result
);
819 fail("expected trust evaluation to fail and it did not.");
821 #pragma clang diagnostic pop
825 CFReleaseNull(subCA
);
827 CFReleaseNull(policy
);
828 CFReleaseNull(trust
);
829 CFReleaseNull(certs
);
830 CFReleaseNull(anchors
);
831 CFReleaseNull(verifyDate
);
832 CFReleaseNull(error
);
833 CFReleaseNull(ocspResponse
);
836 static void test_results_dictionary_revocation_checked(void) {
837 SecCertificateRef leaf
= NULL
, subCA
= NULL
, root
= NULL
;
838 SecPolicyRef sslPolicy
= NULL
, ocspPolicy
= NULL
;
839 SecTrustRef trust
= NULL
;
840 CFArrayRef certs
= NULL
, anchors
= NULL
, policies
= NULL
;
841 CFDateRef verifyDate
= NULL
;
842 CFErrorRef error
= NULL
;
844 leaf
= SecCertificateCreateWithBytes(NULL
, _ocsp_c0
, sizeof(_ocsp_c0
));
845 subCA
= SecCertificateCreateWithBytes(NULL
, _ocsp_c1
, sizeof(_ocsp_c1
));
846 root
= SecCertificateCreateWithBytes(NULL
, _ocsp_c2
, sizeof(_ocsp_c2
));
848 sslPolicy
= SecPolicyCreateSSL(true, CFSTR("www.apple.com"));
849 ocspPolicy
= SecPolicyCreateRevocation(kSecRevocationOCSPMethod
);
851 const void *v_certs
[] = { leaf
, subCA
};
852 const void *v_anchors
[] = { root
};
853 const void *v_policies
[] = { sslPolicy
, ocspPolicy
};
855 certs
= CFArrayCreate(NULL
, v_certs
, 2, &kCFTypeArrayCallBacks
);
856 policies
= CFArrayCreate(NULL
, v_policies
, 2, &kCFTypeArrayCallBacks
);
857 require_noerr_action(SecTrustCreateWithCertificates(certs
, policies
, &trust
), errOut
, fail("failed to create trust object"));
859 anchors
= CFArrayCreate(NULL
, v_anchors
, 1, &kCFTypeArrayCallBacks
);
860 require_noerr_action(SecTrustSetAnchorCertificates(trust
, anchors
), errOut
, fail("failed to set anchors"));
862 verifyDate
= CFDateCreate(NULL
, 577000000.0); // April 14, 2019 at 10:46:40 PM PDT
863 require_noerr_action(SecTrustSetVerifyDate(trust
, verifyDate
), errOut
, fail("failed to set verify date"));
865 #pragma clang diagnostic push
866 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
867 is(SecTrustEvaluateWithError(trust
, &error
), true, "valid cert failed");
869 /* Verify that the results dictionary contains all the right keys for a valid cert where revocation checked */
870 CFDictionaryRef result
= SecTrustCopyResult(trust
);
871 isnt(result
, NULL
, "failed to copy result dictionary");
873 is(CFDictionaryGetValue(result
, kSecTrustRevocationChecked
), kCFBooleanTrue
, "expected revocation checked flag");
874 CFDateRef validUntil
= CFDictionaryGetValue(result
, kSecTrustRevocationValidUntilDate
);
875 isnt(validUntil
, NULL
, "expected revocation valid until date");
877 ok(CFDateGetAbsoluteTime(validUntil
) > CFAbsoluteTimeGetCurrent(), "expected valid until date in the future");
879 fail("did not get valid until date");
882 CFReleaseNull(result
);
883 #pragma clang diagnostic pop
887 CFReleaseNull(subCA
);
889 CFReleaseNull(ocspPolicy
);
890 CFReleaseNull(sslPolicy
);
891 CFReleaseNull(trust
);
892 CFReleaseNull(certs
);
893 CFReleaseNull(anchors
);
894 CFReleaseNull(policies
);
895 CFReleaseNull(verifyDate
);
896 CFReleaseNull(error
);
899 static int ping_host(char *host_name
){
901 struct sockaddr_in pin
;
902 struct hostent
*nlp_host
;
909 //tries 5 times then give up
910 while ((nlp_host
=gethostbyname(host_name
))==0 && retries
--){
911 printf("Resolve Error! (%s) %d\n", host_name
, h_errno
);
918 bzero(&pin
,sizeof(pin
));
919 pin
.sin_family
=AF_INET
;
920 pin
.sin_addr
.s_addr
=htonl(INADDR_ANY
);
921 pin
.sin_addr
.s_addr
=((struct in_addr
*)(nlp_host
->h_addr
))->s_addr
;
922 pin
.sin_port
=htons(port
);
924 sd
=socket(AF_INET
,SOCK_STREAM
,0);
926 if (connect(sd
,(struct sockaddr
*)&pin
,sizeof(pin
))==-1){
927 printf("connect error! (%s) %d\n", host_name
, errno
);
937 int si_23_sectrust_ocsp(int argc
, char *const *argv
)
940 "EVSecure-ocsp.verisign.com",
941 "EVIntl-ocsp.verisign.com",
942 "EVIntl-aia.verisign.com",
949 unsigned host_cnt
= 0;
953 for (host_cnt
= 0; host_cnt
< sizeof(hosts
)/sizeof(hosts
[0]); host_cnt
++) {
954 if(!ping_host(hosts
[host_cnt
])) {
955 printf("Accessing specific server (%s) failed, check the network!\n", hosts
[host_cnt
]);
961 test_ocsp_responder_policy();
965 test_forced_revocation();
966 test_set_fetch_allowed();
967 test_check_if_trusted();
969 test_stapled_revoked_response();
970 test_results_dictionary_revocation_reason();
971 test_results_dictionary_revocation_checked();