2 * si-84-sectrust-allowlist.c
5 * Copyright (c) 2015-2016 Apple Inc. All Rights Reserved.
8 #include <AssertMacros.h>
9 #import <Foundation/Foundation.h>
10 #include <CoreFoundation/CoreFoundation.h>
11 #include <Security/Security.h>
12 #include <Security/SecCertificatePriv.h>
13 #include <Security/SecPolicyPriv.h>
14 #include <utilities/SecCFRelease.h>
15 #include <AssertMacros.h>
17 #include "shared_regressions.h"
19 #include "si-84-sectrust-allowlist/cnnic_certs.h"
20 #include "si-84-sectrust-allowlist/wosign_certs.h"
21 #include "si-84-sectrust-allowlist/date_testing_certs.h"
24 static SecCertificateRef createCertFromStaticData(const UInt8 *certData, CFIndex certLength)
26 SecCertificateRef cert = NULL;
27 CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, certData, certLength, kCFAllocatorNull);
29 cert = SecCertificateCreateWithData(NULL, data);
35 static void TestLeafOnAllowList()
37 SecCertificateRef certs[4];
38 SecPolicyRef policy = NULL;
39 SecTrustRef trust = NULL;
40 CFDateRef date = NULL;
41 CFArrayRef certArray = NULL;
42 CFArrayRef anchorsArray = NULL;
44 isnt(certs[0] = createCertFromStaticData(leafOnAllowList_Cert, sizeof(leafOnAllowList_Cert)),
45 NULL, "allowlist: create leaf cert");
46 isnt(certs[1] = createCertFromStaticData(ca1_Cert, sizeof(ca1_Cert)),
47 NULL, "allowlist: create intermediate ca 1");
48 isnt(certs[2] = createCertFromStaticData(ca2_Cert, sizeof(ca2_Cert)),
49 NULL, "allowlist: create intermediate ca 2");
50 isnt(certs[3] = createCertFromStaticData(root_Cert, sizeof(root_Cert)),
51 NULL, "allowlist: create root");
53 isnt(certArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&certs[0], 4, &kCFTypeArrayCallBacks),
54 NULL, "allowlist: create cert array");
56 /* create a trust reference with basic policy */
57 isnt(policy = SecPolicyCreateBasicX509(), NULL, "allowlist: create policy");
58 ok_status(SecTrustCreateWithCertificates(certArray, policy, &trust), "allowlist: create trust");
60 /* set evaluate date: September 12, 2016 at 1:30:00 PM PDT */
61 isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "allowlist: create date");
62 ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "allowlist: set verify date");
64 /* use a known root CA at this point in time to anchor the chain */
65 isnt(anchorsArray = CFArrayCreate(NULL, (const void **)&certs[3], 1, &kCFTypeArrayCallBacks),
66 NULL, "allowlist: create anchors array");
67 ok_status((anchorsArray) ? SecTrustSetAnchorCertificates(trust, anchorsArray) : errSecParam, "allowlist: set anchors");
69 SecTrustResultType trustResult = kSecTrustResultInvalid;
70 ok_status(SecTrustEvaluate(trust, &trustResult), "allowlist: evaluate");
72 /* expected result is kSecTrustResultUnspecified since cert is on allow list and its issuer chains to a trusted root */
73 ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
77 for(CFIndex idx=0; idx < 4; idx++) {
78 if (certs[idx]) { CFRelease(certs[idx]); }
80 if (policy) { CFRelease(policy); }
81 if (trust) { CFRelease(trust); }
82 if (date) { CFRelease(date); }
83 if (certArray) { CFRelease(certArray); }
84 if (anchorsArray) { CFRelease(anchorsArray); }
87 static void TestLeafNotOnAllowList()
89 SecCertificateRef certs[4];
90 SecPolicyRef policy = NULL;
91 SecTrustRef trust = NULL;
92 CFDateRef date = NULL;
93 CFArrayRef certArray = NULL;
94 CFArrayRef anchorsArray = NULL;
96 isnt(certs[0] = createCertFromStaticData(leafNotOnAllowList_Cert, sizeof(leafNotOnAllowList_Cert)),
97 NULL, "!allowlist: create leaf cert");
98 isnt(certs[1] = createCertFromStaticData(ca1_Cert, sizeof(ca1_Cert)),
99 NULL, "!allowlist: create intermediate ca 1");
100 isnt(certs[2] = createCertFromStaticData(ca2_Cert, sizeof(ca2_Cert)),
101 NULL, "!allowlist: create intermediate ca 2");
102 isnt(certs[3] = createCertFromStaticData(root_Cert, sizeof(root_Cert)),
103 NULL, "!allowlist: create root");
105 isnt(certArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&certs[0], 4, &kCFTypeArrayCallBacks),
106 NULL, "!allowlist: create cert array");
108 /* create a trust reference with basic policy */
109 isnt(policy = SecPolicyCreateBasicX509(), NULL, "!allowlist: create policy");
110 ok_status(SecTrustCreateWithCertificates(certArray, policy, &trust), "!allowlist: create trust");
112 /* set evaluate date: September 7, 2016 at 9:00:00 PM PDT */
113 isnt(date = CFDateCreate(NULL, 495000000.0), NULL, "!allowlist: create date");
114 ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "!allowlist: set verify date");
116 /* use a known root CA at this point in time to anchor the chain */
117 isnt(anchorsArray = CFArrayCreate(NULL, (const void **)&certs[3], 1, &kCFTypeArrayCallBacks),
118 NULL, "allowlist: create anchors array");
119 ok_status((anchorsArray) ? SecTrustSetAnchorCertificates(trust, anchorsArray) : errSecParam, "!allowlist: set anchors");
121 SecTrustResultType trustResult = kSecTrustResultInvalid;
122 ok_status(SecTrustEvaluate(trust, &trustResult), "!allowlist: evaluate");
124 /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
125 or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
126 ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
127 trustResult == kSecTrustResultFatalTrustFailure,
128 "trustResult 5 or 6 expected (got %d)", (int)trustResult);
131 for(CFIndex idx=0; idx < 4; idx++) {
132 if (certs[idx]) { CFRelease(certs[idx]); }
134 if (policy) { CFRelease(policy); }
135 if (trust) { CFRelease(trust); }
136 if (date) { CFRelease(date); }
137 if (certArray) { CFRelease(certArray); }
138 if (anchorsArray) { CFRelease(anchorsArray); }
141 static void TestAllowListForRootCA(void)
143 SecCertificateRef test0[2] = {NULL,NULL};
144 SecCertificateRef test1[2] = {NULL,NULL};
145 SecCertificateRef test1e[2] = {NULL,NULL};
146 SecCertificateRef test2[2] = {NULL,NULL};
147 SecPolicyRef policy = NULL;
148 SecTrustRef trust = NULL;
149 CFDateRef date = NULL;
150 SecTrustResultType trustResult;
152 isnt(test0[0] = createCertFromStaticData(cert0, sizeof(cert0)),
153 NULL, "create first leaf");
154 isnt(test1[0] = createCertFromStaticData(cert1, sizeof(cert1)),
155 NULL, "create second leaf");
156 isnt(test1e[0] = createCertFromStaticData(cert1_expired, sizeof(cert1_expired)),
157 NULL, "create second leaf (expired)");
158 isnt(test2[0] = createCertFromStaticData(cert2, sizeof(cert2)),
159 NULL, "create third leaf");
161 isnt(test0[1] = createCertFromStaticData(intermediate0, sizeof(intermediate0)),
162 NULL, "create intermediate");
163 isnt(test1[1] = createCertFromStaticData(intermediate1, sizeof(intermediate1)),
164 NULL, "create intermediate");
165 isnt(test1e[1] = createCertFromStaticData(intermediate1, sizeof(intermediate1)),
166 NULL, "create intermediate");
167 isnt(test2[1] = createCertFromStaticData(intermediate2, sizeof(intermediate2)),
168 NULL, "create intermediate");
170 CFArrayRef certs0 = CFArrayCreate(kCFAllocatorDefault, (const void **)test0, 2, &kCFTypeArrayCallBacks);
171 CFArrayRef certs1 = CFArrayCreate(kCFAllocatorDefault, (const void **)test1, 2, &kCFTypeArrayCallBacks);
172 CFArrayRef certs1e = CFArrayCreate(kCFAllocatorDefault, (const void **)test1e, 2, &kCFTypeArrayCallBacks);
173 CFArrayRef certs2 = CFArrayCreate(kCFAllocatorDefault, (const void **)test2, 2, &kCFTypeArrayCallBacks);
176 * Whitelisted certificates issued by untrusted root CA.
178 isnt(policy = SecPolicyCreateBasicX509(), NULL, "create policy");
179 ok_status(SecTrustCreateWithCertificates(certs0, policy, &trust), "create trust");
180 /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
181 isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
182 ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
183 ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
184 ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
186 if (trust) { CFRelease(trust); }
187 if (date) { CFRelease(date); }
189 ok_status(SecTrustCreateWithCertificates(certs1, policy, &trust), "create trust");
190 /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
191 isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
192 ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
193 ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
194 ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
196 if (trust) { CFRelease(trust); }
197 if (date) { CFRelease(date); }
199 ok_status(SecTrustCreateWithCertificates(certs2, policy, &trust), "create trust");
200 /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
201 isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
202 ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
203 ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
204 ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
207 * Same certificate, on allow list but past expiration. Expect to fail.
209 if (date) { CFRelease(date); }
210 isnt(date = CFDateCreate(NULL, 667680000.0), NULL, "create date");
211 ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set date to far future so certs are expired");
212 ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
213 ok(trustResult == kSecTrustResultRecoverableTrustFailure, "trustResult 5 expected (got %d)",
215 if (trust) { CFRelease(trust); }
216 if (date) { CFRelease(date); }
219 * Expired certificate not on allow list. Expect to fail.
221 ok_status(SecTrustCreateWithCertificates(certs1e, policy, &trust), "create trust");
222 /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
223 isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
224 ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
225 ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
226 ok(trustResult == kSecTrustResultRecoverableTrustFailure, "trustResult 5 expected (got %d)",
228 if (trust) { CFRelease(trust); }
229 if (date) { CFRelease(date); }
233 if (policy) { CFRelease(policy); }
234 if (certs0) { CFRelease(certs0); }
235 if (certs1) { CFRelease(certs1); }
236 if (certs1e) { CFRelease(certs1e); }
237 if (certs2) { CFRelease(certs2); }
239 if (test0[0]) { CFRelease(test0[0]); }
240 if (test0[1]) { CFRelease(test0[1]); }
241 if (test1[0]) { CFRelease(test1[0]); }
242 if (test1[1]) { CFRelease(test1[1]); }
243 if (test1e[0]) { CFRelease(test1e[0]); }
244 if (test1e[1]) { CFRelease(test1e[1]); }
245 if (test2[0]) { CFRelease(test2[0]); }
246 if (test2[1]) { CFRelease(test2[1]); }
249 static void TestDateBasedAllowListForRootCA(void) {
250 SecCertificateRef root = NULL, beforeInt = NULL, afterInt = NULL,
251 beforeLeaf = NULL, afterLeaf = NULL;
252 SecPolicyRef policy = NULL;
253 SecTrustRef trust = NULL;
254 NSArray *anchors = nil, *certs = nil;
255 NSDate *verifyDate = nil;
256 SecTrustResultType trustResult = kSecTrustResultInvalid;
258 require(root = SecCertificateCreateWithBytes(NULL, _datetest_root, sizeof(_datetest_root)), out);
259 require(beforeInt = SecCertificateCreateWithBytes(NULL, _datetest_before_int, sizeof(_datetest_before_int)), out);
260 require(afterInt = SecCertificateCreateWithBytes(NULL, _datetest_after_int, sizeof(_datetest_after_int)), out);
261 require(beforeLeaf = SecCertificateCreateWithBytes(NULL, _datetest_before_leaf, sizeof(_datetest_before_leaf)), out);
262 require(afterLeaf = SecCertificateCreateWithBytes(NULL, _datetest_after_leaf, sizeof(_datetest_after_leaf)), out);
264 anchors = @[(__bridge id)root];
265 require(policy = SecPolicyCreateSSL(true, CFSTR("testserver.apple.com")), out);
266 verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:504000000.0]; /* 21 Dec 2016 */
268 /* Leaf issued before cutoff should pass */
269 certs = @[(__bridge id)beforeLeaf, (__bridge id)beforeInt];
270 require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
271 require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
272 require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
273 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
274 is(trustResult, kSecTrustResultUnspecified, "leaf issued before cutoff failed evaluation");
275 CFReleaseNull(trust);
276 trustResult = kSecTrustResultInvalid;
278 /* Leaf issued after cutoff should fail */
279 certs = @[(__bridge id)afterLeaf, (__bridge id)beforeInt];
280 require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
281 require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
282 require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
283 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
284 is(trustResult, kSecTrustResultFatalTrustFailure, "leaf issued after cutoff succeeded evaluation");
285 CFReleaseNull(trust);
286 trustResult = kSecTrustResultInvalid;
288 /* Intermediate issued after cutoff should fail (even for leaf issued before) */
289 certs = @[(__bridge id)beforeLeaf, (__bridge id)afterInt];
290 require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
291 require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
292 require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
293 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
294 is(trustResult, kSecTrustResultFatalTrustFailure, "intermediate issued after cutoff succeeded evaluation");
295 CFReleaseNull(trust);
296 trustResult = kSecTrustResultInvalid;
298 /* Intermediate issued after cutoff should fail */
299 certs = @[(__bridge id)afterLeaf, (__bridge id)afterInt];
300 require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
301 require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
302 require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
303 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
304 is(trustResult, kSecTrustResultFatalTrustFailure, "intermediate issued before cutoff succeeded evaluation");
305 CFReleaseNull(trust);
306 trustResult = kSecTrustResultInvalid;
308 /* Leaf issued before cutoff should choose acceptable path */
309 certs = @[(__bridge id)beforeLeaf, (__bridge id) afterInt, (__bridge id)beforeInt];
310 require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
311 require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
312 require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
313 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
314 is(trustResult, kSecTrustResultUnspecified, "leaf issued before cutoff failed evaluation (multi-path)");
315 CFReleaseNull(trust);
316 trustResult = kSecTrustResultInvalid;
318 /* No good path for leaf issued after cutoff */
319 certs = @[(__bridge id)afterLeaf, (__bridge id)beforeInt, (__bridge id)afterInt];
320 require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
321 require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
322 require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
323 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
324 is(trustResult, kSecTrustResultFatalTrustFailure, "leaf issued after cutoff succeeded evaluation (multi-path)");
328 CFReleaseNull(beforeInt);
329 CFReleaseNull(afterInt);
330 CFReleaseNull(beforeLeaf);
331 CFReleaseNull(afterLeaf);
332 CFReleaseNull(policy);
333 CFReleaseNull(trust);
336 static void TestLeafOnAllowListOtherFailures(void)
338 SecCertificateRef certs[4];
339 SecPolicyRef policy = NULL;
340 SecTrustRef trust = NULL;
341 NSArray *anchors = nil, *certArray = nil;
342 NSDate *verifyDate = nil;
343 SecTrustResultType trustResult = kSecTrustResultInvalid;
345 memset(certs, 0, 4 * sizeof(SecCertificateRef));
347 require(certs[0] = SecCertificateCreateWithBytes(NULL, leafOnAllowList_Cert, sizeof(leafOnAllowList_Cert)), out);
348 require(certs[1] = SecCertificateCreateWithBytes(NULL, ca1_Cert, sizeof(ca1_Cert)), out);
349 require(certs[2] = SecCertificateCreateWithBytes(NULL, ca2_Cert, sizeof(ca2_Cert)), out);
350 require(certs[3] = SecCertificateCreateWithBytes(NULL, root_Cert, sizeof(root_Cert)), out);
352 anchors = @[(__bridge id)certs[3]];
353 certArray = @[(__bridge id)certs[0], (__bridge id)certs[1], (__bridge id)certs[2], (__bridge id)certs[3]];
354 verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:495405000.0];
356 /* Mismatched hostname, should fail */
357 require(policy = SecPolicyCreateSSL(true, (__bridge CFStringRef)@"wrong.hostname.com"), out);
358 require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certArray, policy, &trust), out);
359 require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
360 require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
361 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
362 is(trustResult, kSecTrustResultRecoverableTrustFailure, "hostname failure with cert on allow list succeeded evaluation");
363 CFReleaseNull(policy);
364 trustResult = kSecTrustResultInvalid;
366 /* Wrong EKU, should fail */
367 require(policy = SecPolicyCreateCodeSigning(), out);
368 require_noerr(SecTrustSetPolicies(trust, policy), out);
369 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
370 is(trustResult, kSecTrustResultRecoverableTrustFailure, "EKU failure with cert on allow list succeeded evaluation");
371 CFReleaseNull(policy);
372 trustResult = kSecTrustResultInvalid;
374 /* Apple pinning policy, should fail */
375 require(policy = SecPolicyCreateAppleSSLPinned((__bridge CFStringRef)@"aPolicy",
376 (__bridge CFStringRef)@"telegram.im", NULL,
377 (__bridge CFStringRef)@"1.2.840.113635.100.6.27.12"), out);
378 require_noerr(SecTrustSetPolicies(trust, policy), out);
379 require_noerr(SecTrustEvaluate(trust, &trustResult), out);
380 is(trustResult, kSecTrustResultRecoverableTrustFailure, "Apple pinning policy with cert on allow list succeeded evaluation");
383 CFReleaseNull(certs[0]);
384 CFReleaseNull(certs[1]);
385 CFReleaseNull(certs[2]);
386 CFReleaseNull(certs[3]);
387 CFReleaseNull(policy);
388 CFReleaseNull(trust);
391 static void tests(void)
393 TestAllowListForRootCA();
394 TestLeafOnAllowList();
395 TestLeafNotOnAllowList();
396 TestDateBasedAllowListForRootCA();
397 TestLeafOnAllowListOtherFailures();
400 int si_84_sectrust_allowlist(int argc, char *const *argv)