]>
Commit | Line | Data |
---|---|---|
b54c578e A |
1 | /* |
2 | * Copyright (c) 2018 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | * | |
23 | */ | |
24 | ||
25 | #include <AssertMacros.h> | |
26 | #import <XCTest/XCTest.h> | |
27 | #include <Security/SecCertificatePriv.h> | |
28 | #include <Security/SecPolicyPriv.h> | |
29 | #include <Security/SecTrustPriv.h> | |
30 | #include <Security/SecTrustInternal.h> | |
31 | #include "OSX/utilities/SecCFWrappers.h" | |
32 | #include "OSX/utilities/array_size.h" | |
33 | #include "OSX/sec/ipc/securityd_client.h" | |
34 | ||
35 | #include "../TestMacroConversions.h" | |
36 | #include "../TrustEvaluationTestHelpers.h" | |
37 | #include "TrustFrameworkTestCase.h" | |
38 | #include "TrustInterfaceTests_data.h" | |
39 | ||
40 | @interface TrustInterfaceTests : TrustFrameworkTestCase | |
41 | @end | |
42 | ||
43 | @implementation TrustInterfaceTests | |
44 | ||
45 | - (void)testCreateWithCertificates { | |
46 | SecTrustRef trust = NULL; | |
47 | CFArrayRef certs = NULL; | |
48 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
49 | SecPolicyRef policy = NULL; | |
50 | ||
51 | isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), | |
52 | NULL, "create cert0"); | |
53 | isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), | |
54 | NULL, "create cert1"); | |
55 | const void *v_certs[] = { cert0, cert1 }; | |
56 | ||
57 | certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); | |
58 | policy = SecPolicyCreateSSL(false, NULL); | |
59 | ||
60 | /* SecTrustCreateWithCertificates failures. */ | |
61 | is_status(SecTrustCreateWithCertificates(kCFBooleanTrue, policy, &trust), | |
62 | errSecParam, "create trust with boolean instead of cert"); | |
63 | is_status(SecTrustCreateWithCertificates(cert0, kCFBooleanTrue, &trust), | |
64 | errSecParam, "create trust with boolean instead of policy"); | |
65 | ||
66 | NSArray *badValues = @[ [NSData dataWithBytes:_c0 length:sizeof(_c0)], [NSData dataWithBytes:_c1 length:sizeof(_c1)]]; | |
67 | XCTAssert(errSecParam == SecTrustCreateWithCertificates((__bridge CFArrayRef)badValues, policy, &trust), | |
68 | "create trust with array of datas instead of certs"); | |
69 | XCTAssert(errSecParam == SecTrustCreateWithCertificates(certs, (__bridge CFArrayRef)badValues, &trust), | |
70 | "create trust with array of datas instead of policies"); | |
71 | ||
72 | /* SecTrustCreateWithCertificates using array of certs. */ | |
73 | ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); | |
74 | ||
75 | CFReleaseNull(trust); | |
76 | CFReleaseNull(cert0); | |
77 | CFReleaseNull(cert1); | |
78 | CFReleaseNull(certs); | |
79 | CFReleaseNull(policy); | |
80 | } | |
81 | ||
82 | - (void)testGetCertificate { | |
83 | SecTrustRef trust = NULL; | |
84 | CFArrayRef certs = NULL; | |
85 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
86 | SecPolicyRef policy = NULL; | |
87 | ||
88 | isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), | |
89 | NULL, "create cert0"); | |
90 | isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), | |
91 | NULL, "create cert1"); | |
92 | const void *v_certs[] = { cert0, cert1 }; | |
93 | ||
94 | certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); | |
95 | policy = SecPolicyCreateSSL(false, NULL); | |
96 | ||
97 | ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); | |
98 | ||
99 | /* NOTE: prior to <rdar://11810677 SecTrustGetCertificateCount would return 1 at this point. | |
100 | * Now, however, we do an implicit SecTrustEvaluate to build the chain if it has not yet been | |
101 | * evaluated, so we now expect the full chain length. */ | |
102 | #if !TARGET_OS_BRIDGE | |
103 | is(SecTrustGetCertificateCount(trust), 3, "cert count is 3"); | |
104 | #else | |
105 | /* bridgeOS has no system anchors, so trustd never finds the root */ | |
106 | is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); | |
107 | #endif | |
108 | is(SecTrustGetCertificateAtIndex(trust, 0), cert0, "cert 0 is leaf"); | |
109 | ||
110 | CFReleaseNull(trust); | |
111 | CFReleaseNull(cert0); | |
112 | CFReleaseNull(cert1); | |
113 | CFReleaseNull(certs); | |
114 | CFReleaseNull(policy); | |
115 | } | |
116 | ||
117 | - (void)testRestoreOS { | |
118 | SecTrustRef trust = NULL; | |
119 | CFArrayRef certs = NULL; | |
120 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
121 | SecPolicyRef policy = NULL; | |
122 | CFDateRef date = NULL; | |
123 | SecTrustResultType trustResult = kSecTrustResultOtherError; | |
124 | ||
125 | /* Apr 14 2018. */ | |
126 | isnt(date = CFDateCreateForGregorianZuluMoment(NULL, 2018, 4, 14, 12, 0, 0), | |
127 | NULL, "create verify date"); | |
128 | if (!date) { goto errOut; } | |
129 | ||
130 | isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), | |
131 | NULL, "create cert0"); | |
132 | isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), | |
133 | NULL, "create cert1"); | |
134 | const void *v_certs[] = { cert0, cert1 }; | |
135 | ||
136 | certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); | |
137 | policy = SecPolicyCreateSSL(false, NULL); | |
138 | ||
139 | ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); | |
140 | ok_status(SecTrustSetVerifyDate(trust, date), "set date"); | |
141 | ||
142 | // Test Restore OS environment | |
143 | SecServerSetTrustdMachServiceName("com.apple.security.doesn't-exist"); | |
144 | ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust without securityd running"); | |
145 | is_status(trustResult, kSecTrustResultInvalid, "trustResult is kSecTrustResultInvalid"); | |
146 | is(SecTrustGetCertificateCount(trust), 1, "cert count is 1 without securityd running"); | |
147 | SecKeyRef pubKey = NULL; | |
d64be36e | 148 | ok(pubKey = SecTrustCopyKey(trust), "copy public key without securityd running"); |
b54c578e A |
149 | CFReleaseNull(pubKey); |
150 | SecServerSetTrustdMachServiceName("com.apple.trustd"); | |
151 | // End of Restore OS environment tests | |
152 | ||
153 | errOut: | |
154 | CFReleaseNull(trust); | |
155 | CFReleaseNull(cert0); | |
156 | CFReleaseNull(cert1); | |
157 | CFReleaseNull(certs); | |
158 | CFReleaseNull(policy); | |
159 | } | |
160 | ||
161 | - (void)testAnchorCerts { | |
162 | SecTrustRef trust = NULL; | |
163 | CFArrayRef certs = NULL, anchors = NULL; | |
164 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
165 | SecPolicyRef policy = NULL; | |
166 | CFDateRef date = NULL; | |
167 | ||
168 | /* Apr 14 2018. */ | |
169 | isnt(date = CFDateCreateForGregorianZuluMoment(NULL, 2018, 4, 14, 12, 0, 0), | |
170 | NULL, "create verify date"); | |
171 | if (!date) { goto errOut; } | |
172 | ||
173 | isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), | |
174 | NULL, "create cert0"); | |
175 | isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), | |
176 | NULL, "create cert1"); | |
177 | const void *v_certs[] = { cert0, cert1 }; | |
178 | ||
179 | certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); | |
180 | policy = SecPolicyCreateSSL(false, NULL); | |
181 | ||
182 | ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); | |
183 | ok_status(SecTrustSetVerifyDate(trust, date), "set date"); | |
184 | ||
185 | anchors = CFArrayCreate(NULL, (const void **)&cert1, 1, &kCFTypeArrayCallBacks); | |
186 | ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors"); | |
187 | XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
188 | is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); | |
189 | ||
190 | CFReleaseNull(anchors); | |
191 | anchors = CFArrayCreate(NULL, NULL, 0, NULL); | |
192 | ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set empty anchors list"); | |
193 | XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
194 | CFReleaseNull(anchors); | |
195 | ||
196 | ok_status(SecTrustSetAnchorCertificatesOnly(trust, false), "trust passed in anchors and system anchors"); | |
197 | #if !TARGET_OS_BRIDGE | |
198 | XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
199 | #else | |
200 | /* BridgeOS has no system anchors */ | |
201 | XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
202 | #endif | |
203 | ||
204 | ok_status(SecTrustSetAnchorCertificatesOnly(trust, true), "only trust passed in anchors (default)"); | |
205 | XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
206 | ||
207 | ok_status(SecTrustSetAnchorCertificates(trust, NULL), "reset anchors"); | |
208 | #if !TARGET_OS_BRIDGE | |
209 | XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
210 | is(SecTrustGetCertificateCount(trust), 3, "cert count is 3"); | |
211 | #else | |
212 | /* bridgeOS has no system anchors */ | |
213 | XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
214 | is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); | |
215 | #endif | |
216 | ||
217 | XCTAssert(errSecParam == SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)@[ [NSData dataWithBytes:_c0 length:sizeof(_c0)]]), | |
218 | "set anchor with data instead of certificate"); | |
219 | #if !TARGET_OS_BRIDGE | |
220 | XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
221 | is(SecTrustGetCertificateCount(trust), 3, "cert count is 3"); | |
222 | #else | |
223 | /* bridgeOS has no system anchors */ | |
224 | XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
225 | is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); | |
226 | #endif | |
227 | ||
228 | errOut: | |
229 | CFReleaseNull(trust); | |
230 | CFReleaseNull(cert0); | |
231 | CFReleaseNull(cert1); | |
232 | CFReleaseNull(certs); | |
233 | CFReleaseNull(anchors); | |
234 | CFReleaseNull(policy); | |
235 | } | |
236 | ||
237 | - (void)testInputCertificates { | |
238 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
239 | SecPolicyRef policy = NULL; | |
240 | SecTrustRef trust = NULL; | |
241 | CFArrayRef certificates = NULL; | |
242 | ||
243 | require(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), errOut); | |
244 | require(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), errOut); | |
245 | require(policy = SecPolicyCreateBasicX509(), errOut); | |
246 | require_noerr(SecTrustCreateWithCertificates(cert0, policy, &trust), errOut); | |
247 | ||
248 | ok_status(SecTrustCopyInputCertificates(trust, &certificates), "SecTrustCopyInputCertificates failed"); | |
249 | is(CFArrayGetCount(certificates), 1, "got too many input certs back"); | |
250 | is(CFArrayGetValueAtIndex(certificates, 0), cert0, "wrong input cert"); | |
251 | CFReleaseNull(certificates); | |
252 | ||
253 | XCTAssert(errSecParam == SecTrustAddToInputCertificates(trust, (__bridge CFDataRef)[NSData dataWithBytes:_c1 length:sizeof(_c1)]), | |
254 | "add data instead of cert"); | |
255 | XCTAssert(errSecParam == SecTrustAddToInputCertificates(trust, (__bridge CFArrayRef)@[[NSData dataWithBytes:_c1 length:sizeof(_c1)]]), | |
256 | "add array of data instead of cert"); | |
257 | ||
258 | ok_status(SecTrustAddToInputCertificates(trust, cert0), "SecTrustAddToInputCertificates failed"); | |
259 | ok_status(SecTrustCopyInputCertificates(trust, &certificates), "SecTrustCopyInputCertificates failed"); | |
260 | is(CFArrayGetCount(certificates), 2, "got wrong number of input certs back"); | |
261 | is(CFArrayGetValueAtIndex(certificates, 0), cert0, "wrong input cert0"); | |
262 | is(CFArrayGetValueAtIndex(certificates, 1), cert0, "wrong input cert0"); | |
263 | ||
264 | ok_status(SecTrustAddToInputCertificates(trust, (__bridge CFArrayRef)@[ (__bridge id)cert1]), "SecTrustAddToInputCertificates failed"); | |
265 | ok_status(SecTrustCopyInputCertificates(trust, &certificates), "SecTrustCopyInputCertificates failed"); | |
266 | is(CFArrayGetCount(certificates), 3, "got wrong number of input certs back"); | |
267 | is(CFArrayGetValueAtIndex(certificates, 0), cert0, "wrong input cert0"); | |
268 | is(CFArrayGetValueAtIndex(certificates, 1), cert0, "wrong input cert0"); | |
269 | is(CFArrayGetValueAtIndex(certificates, 2), cert1, "wrong input cert1"); | |
270 | #if !TARGET_OS_BRIDGE | |
271 | is(SecTrustGetCertificateCount(trust), 3, "cert count is 3"); | |
272 | #else | |
273 | /* bridgeOS has no system anchors, so trustd never finds the root */ | |
274 | is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); | |
275 | #endif | |
276 | ||
277 | errOut: | |
278 | CFReleaseNull(cert0); | |
279 | CFReleaseNull(cert1); | |
280 | CFReleaseNull(policy); | |
281 | CFReleaseNull(trust); | |
282 | CFReleaseNull(certificates); | |
283 | } | |
284 | ||
285 | - (void)testSetPolicies { | |
286 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
287 | SecPolicyRef policy = NULL, replacementPolicy = NULL; | |
288 | SecTrustRef trust = NULL; | |
289 | CFDateRef date = NULL; | |
290 | CFArrayRef anchors = NULL, policies = NULL; | |
291 | ||
292 | require(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), errOut); | |
293 | require(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), errOut); | |
294 | require(policy = SecPolicyCreateSSL(true, CFSTR("example.com")), errOut); | |
295 | require_noerr(SecTrustCreateWithCertificates(cert0, policy, &trust), errOut); | |
296 | ||
297 | isnt(date = CFDateCreateForGregorianZuluMoment(NULL, 2018, 4, 14, 12, 0, 0), | |
298 | NULL, "create verify date"); | |
299 | ok_status(SecTrustSetVerifyDate(trust, date), "set date"); | |
300 | anchors = CFArrayCreate(NULL, (const void **)&cert1, 1, &kCFTypeArrayCallBacks); | |
301 | ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors"); | |
302 | XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
303 | ||
304 | /* replace with one policy */ | |
305 | require(replacementPolicy = SecPolicyCreateSSL(true, CFSTR("store.apple.com")), errOut); | |
306 | ok_status(SecTrustSetPolicies(trust, replacementPolicy)); | |
307 | XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
308 | ||
309 | /* replace with policy array */ | |
310 | CFReleaseNull(trust); | |
311 | require_noerr(SecTrustCreateWithCertificates(cert0, policy, &trust), errOut); | |
312 | isnt(date = CFDateCreateForGregorianZuluMoment(NULL, 2018, 4, 14, 12, 0, 0), | |
313 | NULL, "create verify date"); | |
314 | ok_status(SecTrustSetVerifyDate(trust, date), "set date"); | |
315 | ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors"); | |
316 | policies = CFArrayCreate(kCFAllocatorDefault, (CFTypeRef*)&replacementPolicy, 1, &kCFTypeArrayCallBacks); | |
317 | ok_status(SecTrustSetPolicies(trust, policies)); | |
318 | XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust"); | |
319 | ||
320 | /* replace with non-policy */ | |
321 | XCTAssert(errSecParam == SecTrustSetPolicies(trust, cert0), "set with cert instead of policy"); | |
322 | XCTAssert(errSecParam == SecTrustSetPolicies(trust, anchors), "set with array of certs instead of polciies"); | |
323 | ||
324 | /* copy policies */ | |
325 | CFReleaseNull(policies); | |
326 | ok_status(SecTrustCopyPolicies(trust, &policies)); | |
327 | XCTAssertEqual(CFArrayGetCount(policies), 1, "one policy set"); | |
328 | XCTAssertTrue(CFEqual(CFArrayGetValueAtIndex(policies, 0), replacementPolicy), "set policy is replacement policy"); | |
329 | ||
330 | errOut: | |
331 | CFReleaseNull(cert0); | |
332 | CFReleaseNull(cert1); | |
333 | CFReleaseNull(policy); | |
334 | CFReleaseNull(trust); | |
335 | CFReleaseNull(date); | |
336 | CFReleaseNull(anchors); | |
337 | CFReleaseNull(replacementPolicy); | |
338 | CFReleaseNull(policies); | |
339 | } | |
340 | ||
341 | - (void)testAsyncTrustEval { | |
342 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
343 | SecPolicyRef policy = NULL; | |
344 | SecTrustRef trust = NULL; | |
345 | CFArrayRef certificates = NULL; | |
346 | CFDateRef date = NULL; | |
347 | dispatch_queue_t queue = dispatch_queue_create("com.apple.trusttests.async", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); | |
348 | ||
349 | XCTestExpectation *blockExpectation = [self expectationWithDescription:@"callback occurs"]; | |
350 | ||
351 | require(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), errOut); | |
352 | require(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), errOut); | |
353 | const void *v_certs[] = { | |
354 | cert0, | |
355 | cert1 | |
356 | }; | |
357 | certificates = CFArrayCreate(NULL, v_certs, | |
358 | array_size(v_certs), | |
359 | &kCFTypeArrayCallBacks); | |
360 | ||
361 | require(policy = SecPolicyCreateBasicX509(), errOut); | |
362 | require_noerr(SecTrustCreateWithCertificates(certificates, policy, &trust), errOut); | |
363 | ||
364 | /* Jul 30 2014. */ | |
365 | require(date = CFDateCreateForGregorianZuluMoment(NULL, 2014, 7, 30, 12, 0, 0), errOut); | |
366 | require_noerr(SecTrustSetVerifyDate(trust, date), errOut); | |
367 | ||
368 | /* This shouldn't crash. */ | |
369 | #pragma clang diagnostic push | |
370 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
371 | ok_status(SecTrustEvaluateAsync(trust, queue, ^(SecTrustRef _Nonnull trustRef, SecTrustResultType trustResult) { | |
372 | if ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified)) { | |
373 | // Evaluation succeeded! | |
d64be36e A |
374 | SecKeyRef publicKey = SecTrustCopyKey(trustRef); |
375 | XCTAssert(publicKey != NULL); | |
b54c578e A |
376 | CFReleaseSafe(publicKey); |
377 | } else if (trustResult == kSecTrustResultRecoverableTrustFailure) { | |
378 | // Evaluation failed, but may be able to recover . . . | |
379 | } else { | |
380 | // Evaluation failed | |
381 | } | |
382 | [blockExpectation fulfill]; | |
383 | }), "evaluate trust asynchronously"); | |
384 | CFReleaseNull(trust); | |
385 | #pragma clang diagnostic pop | |
386 | ||
387 | [self waitForExpectations:@[blockExpectation] timeout:1.0]; | |
388 | ||
389 | errOut: | |
390 | CFReleaseNull(cert0); | |
391 | CFReleaseNull(cert1); | |
392 | CFReleaseNull(policy); | |
393 | CFReleaseNull(certificates); | |
394 | CFReleaseNull(date); | |
395 | } | |
396 | ||
397 | - (void)testExpiredOnly { | |
398 | SecCertificateRef cert0 = NULL, cert1 = NULL, cert2 = NULL; | |
399 | SecPolicyRef policy = NULL; | |
400 | SecTrustRef trust = NULL; | |
401 | CFArrayRef certificates = NULL, roots = NULL; | |
402 | CFDateRef date = NULL; | |
403 | ||
404 | require(cert0 = SecCertificateCreateWithBytes(NULL, _expired_badssl, sizeof(_expired_badssl)), errOut); | |
405 | require(cert1 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_dvss, sizeof(_comodo_rsa_dvss)), errOut); | |
406 | require(cert2 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_root, sizeof(_comodo_rsa_root)), errOut); | |
407 | ||
408 | const void *v_certs[] = {cert0, cert1 }; | |
409 | certificates = CFArrayCreate(NULL, v_certs, | |
410 | array_size(v_certs), | |
411 | &kCFTypeArrayCallBacks); | |
412 | ||
413 | const void *v_roots[] = { cert2 }; | |
414 | roots = CFArrayCreate(NULL, v_roots, | |
415 | array_size(v_roots), | |
416 | &kCFTypeArrayCallBacks); | |
417 | ||
418 | require(policy = SecPolicyCreateSSL(true, CFSTR("expired.badssl.com")), errOut); | |
419 | require_noerr(SecTrustCreateWithCertificates(certificates, policy, &trust), errOut); | |
420 | require_noerr(SecTrustSetAnchorCertificates(trust, roots), errOut); | |
421 | ||
422 | /* Mar 21 2017 (cert expired in 2015, so this will cause a validity error.) */ | |
423 | require(date = CFDateCreateForGregorianZuluMoment(NULL, 2017, 3, 21, 12, 0, 0), errOut); | |
424 | require_noerr(SecTrustSetVerifyDate(trust, date), errOut); | |
425 | ||
426 | /* SecTrustIsExpiredOnly implicitly evaluates the trust */ | |
427 | ok(SecTrustIsExpiredOnly(trust), "REGRESSION: has new error as well as expiration"); | |
428 | ||
429 | CFReleaseNull(policy); | |
430 | require(policy = SecPolicyCreateSSL(true, CFSTR("expired.terriblessl.com")), errOut); | |
431 | require_noerr(SecTrustSetPolicies(trust, policy), errOut); | |
432 | /* expect a hostname mismatch as well as expiration */ | |
433 | ok(!SecTrustIsExpiredOnly(trust), "REGRESSION: should have found multiple errors"); | |
434 | ||
435 | errOut: | |
436 | CFReleaseNull(trust); | |
437 | CFReleaseNull(cert0); | |
438 | CFReleaseNull(cert1); | |
439 | CFReleaseNull(cert2); | |
440 | CFReleaseNull(policy); | |
441 | CFReleaseNull(certificates); | |
442 | CFReleaseNull(roots); | |
443 | CFReleaseNull(date); | |
444 | } | |
445 | ||
446 | - (void)testEvaluateWithError { | |
447 | SecCertificateRef cert0 = NULL, cert1 = NULL, cert2 = NULL; | |
448 | SecPolicyRef policy = NULL; | |
449 | SecTrustRef trust = NULL; | |
450 | CFArrayRef certificates = NULL, roots = NULL; | |
451 | CFDateRef date = NULL, validDate = NULL; | |
452 | CFErrorRef error = NULL; | |
453 | ||
454 | require(cert0 = SecCertificateCreateWithBytes(NULL, _expired_badssl, sizeof(_expired_badssl)), errOut); | |
455 | require(cert1 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_dvss, sizeof(_comodo_rsa_dvss)), errOut); | |
456 | require(cert2 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_root, sizeof(_comodo_rsa_root)), errOut); | |
457 | ||
458 | const void *v_certs[] = { | |
459 | cert0, | |
460 | cert1, | |
461 | cert2, | |
462 | }; | |
463 | certificates = CFArrayCreate(NULL, v_certs, | |
464 | array_size(v_certs), | |
465 | &kCFTypeArrayCallBacks); | |
466 | ||
467 | const void *v_roots[] = { | |
468 | cert2 | |
469 | }; | |
470 | roots = CFArrayCreate(NULL, v_roots, | |
471 | array_size(v_roots), | |
472 | &kCFTypeArrayCallBacks); | |
473 | ||
474 | require(policy = SecPolicyCreateSSL(true, CFSTR("expired.badssl.com")), errOut); | |
475 | require_noerr(SecTrustCreateWithCertificates(certificates, policy, &trust), errOut); | |
476 | require_noerr(SecTrustSetAnchorCertificates(trust, roots), errOut); | |
477 | ||
478 | /* April 10 2015 (cert expired in 2015) */ | |
479 | require(validDate = CFDateCreateForGregorianZuluMoment(NULL, 2015, 4, 10, 12, 0, 0), errOut); | |
480 | require_noerr(SecTrustSetVerifyDate(trust, validDate), errOut); | |
481 | ||
482 | is(SecTrustEvaluateWithError(trust, &error), true, "wrong result for valid cert"); | |
483 | is(error, NULL, "set error for passing trust evaluation"); | |
484 | CFReleaseNull(error); | |
485 | ||
486 | /* Mar 21 2017 (cert expired in 2015, so this will cause a validity error.) */ | |
487 | require(date = CFDateCreateForGregorianZuluMoment(NULL, 2017, 3, 21, 12, 0, 0), errOut); | |
488 | require_noerr(SecTrustSetVerifyDate(trust, date), errOut); | |
489 | ||
490 | /* expect expiration error */ | |
491 | is(SecTrustEvaluateWithError(trust, &error), false, "wrong result for expired cert"); | |
492 | isnt(error, NULL, "failed to set error for failing trust evaluation"); | |
493 | is(CFErrorGetCode(error), errSecCertificateExpired, "Got wrong error code for evaluation"); | |
494 | CFReleaseNull(error); | |
495 | ||
496 | CFReleaseNull(policy); | |
497 | require(policy = SecPolicyCreateSSL(true, CFSTR("expired.terriblessl.com")), errOut); | |
498 | require_noerr(SecTrustSetPolicies(trust, policy), errOut); | |
499 | ||
500 | /* expect a hostname mismatch as well as expiration; hostname mismatch must be a higher priority */ | |
501 | is(SecTrustEvaluateWithError(trust, &error), false, "wrong result for expired cert with hostname mismatch"); | |
502 | isnt(error, NULL, "failed to set error for failing trust evaluation"); | |
503 | is(CFErrorGetCode(error), errSecHostNameMismatch, "Got wrong error code for evaluation"); | |
504 | CFReleaseNull(error); | |
505 | ||
506 | /* expect only a hostname mismatch*/ | |
507 | require_noerr(SecTrustSetVerifyDate(trust, validDate), errOut); | |
508 | is(SecTrustEvaluateWithError(trust, &error), false, "wrong result for valid cert with hostname mismatch"); | |
509 | isnt(error, NULL, "failed to set error for failing trust evaluation"); | |
510 | is(CFErrorGetCode(error), errSecHostNameMismatch, "Got wrong error code for evaluation"); | |
511 | CFReleaseNull(error); | |
512 | ||
513 | /* pinning failure */ | |
514 | CFReleaseNull(policy); | |
515 | require(policy = SecPolicyCreateAppleSSLPinned(CFSTR("test"), CFSTR("expired.badssl.com"), | |
516 | NULL, CFSTR("1.2.840.113635.100.6.27.1")), errOut); | |
517 | require_noerr(SecTrustSetPolicies(trust, policy), errOut); | |
518 | ||
519 | is(SecTrustEvaluateWithError(trust, &error), false, "wrong result for valid cert with pinning failure"); | |
520 | isnt(error, NULL, "failed to set error for failing trust evaluation"); | |
521 | CFIndex errorCode = CFErrorGetCode(error); | |
522 | // failed checks: AnchorApple, LeafMarkerOid, or IntermediateMarkerOid | |
523 | ok(errorCode == errSecMissingRequiredExtension || errorCode == errSecInvalidRoot, "Got wrong error code for evaluation"); | |
524 | CFReleaseNull(error); | |
525 | ||
526 | /* trust nothing, trust errors higher priority than hostname mismatch */ | |
527 | CFReleaseNull(policy); | |
528 | require(policy = SecPolicyCreateSSL(true, CFSTR("expired.terriblessl.com")), errOut); | |
529 | require_noerr(SecTrustSetPolicies(trust, policy), errOut); | |
530 | ||
531 | CFReleaseNull(roots); | |
532 | roots = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); | |
533 | require_noerr(SecTrustSetAnchorCertificates(trust, roots), errOut); | |
534 | is(SecTrustEvaluateWithError(trust, &error), false, "wrong result for expired cert with hostname mismatch"); | |
535 | isnt(error, NULL, "failed to set error for failing trust evaluation"); | |
536 | is(CFErrorGetCode(error), errSecNotTrusted, "Got wrong error code for evaluation"); | |
537 | CFReleaseNull(error); | |
538 | ||
539 | errOut: | |
540 | CFReleaseNull(trust); | |
541 | CFReleaseNull(cert0); | |
542 | CFReleaseNull(cert1); | |
543 | CFReleaseNull(cert2); | |
544 | CFReleaseNull(policy); | |
545 | CFReleaseNull(certificates); | |
546 | CFReleaseNull(roots); | |
547 | CFReleaseNull(date); | |
548 | CFReleaseNull(validDate); | |
549 | CFReleaseNull(error); | |
550 | } | |
551 | ||
552 | - (void)testSerialization { | |
553 | SecCertificateRef cert0 = NULL, cert1 = NULL, root = NULL; | |
554 | SecTrustRef trust = NULL, deserializedTrust = NULL; | |
555 | SecPolicyRef policy = NULL; | |
556 | CFArrayRef certs = NULL, anchors = NULL, deserializedCerts = NULL; | |
557 | CFDateRef date = NULL; | |
558 | CFDataRef serializedTrust = NULL; | |
559 | CFErrorRef error = NULL; | |
560 | ||
561 | require_action(cert0 = SecCertificateCreateWithBytes(NULL, _expired_badssl, sizeof(_expired_badssl)), errOut, | |
562 | fail("unable to create cert")); | |
563 | require_action(cert1 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_dvss, sizeof(_comodo_rsa_dvss)), errOut, | |
564 | fail("unable to create cert")); | |
565 | require_action(root = SecCertificateCreateWithBytes(NULL, _comodo_rsa_root, sizeof(_comodo_rsa_root)), errOut, | |
566 | fail("unable to create cert")); | |
567 | ||
568 | const void *v_certs[] = { cert0, cert1 }; | |
569 | require_action(certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks), errOut, | |
570 | fail("unable to create array")); | |
571 | require_action(anchors = CFArrayCreate(NULL, (const void **)&root, 1, &kCFTypeArrayCallBacks), errOut, | |
572 | fail("unable to create anchors array")); | |
573 | require_action(date = CFDateCreateForGregorianZuluMoment(NULL, 2015, 4, 10, 12, 0, 0), errOut, fail("unable to create date")); | |
574 | ||
575 | require_action(policy = SecPolicyCreateBasicX509(), errOut, fail("unable to create policy")); | |
576 | ||
577 | ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "failed to create trust"); | |
578 | require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, | |
579 | fail("unable to set anchors")); | |
580 | require_noerr_action(SecTrustSetVerifyDate(trust, date), errOut, fail("unable to set verify date")); | |
581 | ||
582 | ok(serializedTrust = SecTrustSerialize(trust, NULL), "failed to serialize trust"); | |
583 | ok(deserializedTrust = SecTrustDeserialize(serializedTrust, NULL), "Failed to deserialize trust"); | |
584 | CFReleaseNull(serializedTrust); | |
585 | ||
586 | require_noerr_action(SecTrustCopyCustomAnchorCertificates(deserializedTrust, &deserializedCerts), errOut, | |
587 | fail("unable to get anchors from deserialized trust")); | |
588 | ok(CFEqual(anchors, deserializedCerts), "Failed to get the same anchors after serialization/deserialization"); | |
589 | CFReleaseNull(deserializedCerts); | |
590 | ||
591 | require_noerr_action(SecTrustCopyInputCertificates(trust, &deserializedCerts), errOut, | |
592 | fail("unable to get input certificates from deserialized trust")); | |
593 | ok(CFEqual(certs, deserializedCerts), "Failed to get same input certificates after serialization/deserialization"); | |
594 | CFReleaseNull(deserializedCerts); | |
595 | ||
596 | /* correct API behavior */ | |
597 | #pragma clang diagnostic push | |
598 | #pragma clang diagnostic ignored "-Wnonnull" | |
599 | is(SecTrustSerialize(NULL, &error), NULL, "serialize succeeded with null input"); | |
600 | is(CFErrorGetCode(error), errSecParam, "Incorrect error code for bad serialization input"); | |
601 | CFReleaseNull(error); | |
602 | is(SecTrustDeserialize(NULL, &error), NULL, "deserialize succeeded with null input"); | |
603 | is(CFErrorGetCode(error), errSecParam, "Incorrect error code for bad deserialization input"); | |
604 | CFReleaseNull(error); | |
605 | #pragma clang diagnostic pop | |
606 | ||
607 | errOut: | |
608 | CFReleaseNull(cert0); | |
609 | CFReleaseNull(cert1); | |
610 | CFReleaseNull(root); | |
611 | CFReleaseNull(certs); | |
612 | CFReleaseNull(anchors); | |
613 | CFReleaseNull(date); | |
614 | CFReleaseNull(policy); | |
615 | CFReleaseNull(trust); | |
616 | CFReleaseNull(deserializedTrust); | |
617 | } | |
618 | ||
619 | - (void)testSerializationSCTs { | |
620 | SecCertificateRef certA = NULL, certCA_alpha = NULL, certCA_beta = NULL; | |
621 | NSURL *trustedLogsURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"CTlogs" | |
622 | withExtension:@"plist" | |
623 | subdirectory:@"si-82-sectrust-ct-data"]; | |
624 | CFArrayRef trustedLogs= CFBridgingRetain([NSArray arrayWithContentsOfURL:trustedLogsURL]); | |
625 | SecTrustRef trust = NULL, deserializedTrust = NULL; | |
626 | SecPolicyRef policy = SecPolicyCreateBasicX509(); // <rdar://problem/50066309> Need to generate new certs for CTTests | |
627 | NSData *proofA_1 = NULL, *proofA_2 = NULL; | |
628 | NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:447450000.0]; // March 7, 2015 at 11:40:00 AM PST | |
629 | CFErrorRef error = NULL; | |
630 | ||
631 | NSURL *url = [[NSBundle bundleForClass:[self class]] URLForResource:@"serverA" withExtension:@".cer" subdirectory:@"si-82-sectrust-ct-data"]; | |
632 | NSData *certData = [NSData dataWithContentsOfURL:url]; | |
633 | isnt(certA = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certData), NULL, "create certA"); | |
634 | ||
635 | url = [[NSBundle bundleForClass:[self class]] URLForResource:@"CA_beta" withExtension:@".cer" subdirectory:@"si-82-sectrust-ct-data"]; | |
636 | certData = [NSData dataWithContentsOfURL:url]; | |
637 | isnt(certCA_alpha = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certData), NULL, "create ca-alpha cert"); | |
638 | ||
639 | NSArray *anchors = @[ (__bridge id)certCA_alpha ]; | |
640 | ||
641 | url = [[NSBundle bundleForClass:[self class]] URLForResource:@"serverA_proof_Alfa_3" withExtension:@".bin" subdirectory:@"si-82-sectrust-ct-data"]; | |
642 | isnt(proofA_1 = [NSData dataWithContentsOfURL:url], NULL, "creat proofA_1"); | |
643 | url = [[NSBundle bundleForClass:[self class]] URLForResource:@"serverA_proof_Bravo_3" withExtension:@".bin" subdirectory:@"si-82-sectrust-ct-data"]; | |
644 | isnt(proofA_2 = [NSData dataWithContentsOfURL:url], NULL, "creat proofA_2"); | |
645 | NSArray *scts = @[ proofA_1, proofA_2 ]; | |
646 | ||
647 | /* Make a SecTrustRef and then serialize it */ | |
648 | ok_status(SecTrustCreateWithCertificates(certA, policy, &trust), "failed to create trust object"); | |
649 | ok_status(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), "failed to set anchors"); | |
650 | ok_status(SecTrustSetTrustedLogs(trust, trustedLogs), "failed to set trusted logs"); | |
651 | ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), "failed to set verify date"); | |
652 | ok_status(SecTrustSetSignedCertificateTimestamps(trust, (__bridge CFArrayRef)scts), "failed to set SCTS"); | |
653 | ||
654 | NSData *serializedTrust = CFBridgingRelease(SecTrustSerialize(trust, &error)); | |
655 | isnt(serializedTrust, NULL, "failed to serialize trust: %@", error); | |
656 | ||
657 | /* Evaluate it to make sure it's CT */ | |
658 | ok(SecTrustEvaluateWithError(trust, &error), "failed to evaluate trust: %@", error); | |
659 | NSDictionary *results = CFBridgingRelease(SecTrustCopyResult(trust)); | |
660 | isnt(results[(__bridge NSString*)kSecTrustCertificateTransparency], NULL, "failed get CT result"); | |
661 | ok([results[(__bridge NSString*)kSecTrustCertificateTransparency] boolValue], "CT failed"); | |
662 | ||
663 | /* Make a new trust object by deserializing the previous trust object */ | |
664 | ok(deserializedTrust = SecTrustDeserialize((__bridge CFDataRef)serializedTrust, &error), "failed to deserialize trust: %@", error); | |
665 | ||
666 | /* Evaluate the new one to make sure it's CT (because the SCTs were serialized) */ | |
667 | ok(SecTrustEvaluateWithError(deserializedTrust, &error), "failed to evaluate trust: %@", error); | |
668 | results = CFBridgingRelease(SecTrustCopyResult(deserializedTrust)); | |
669 | isnt(results[(__bridge NSString*)kSecTrustCertificateTransparency], NULL, "failed get CT result"); | |
670 | ok([results[(__bridge NSString*)kSecTrustCertificateTransparency] boolValue], "CT failed"); | |
671 | ||
672 | CFReleaseNull(certA); | |
673 | CFReleaseNull(certCA_alpha); | |
674 | CFReleaseNull(certCA_beta); | |
675 | CFReleaseNull(trustedLogs); | |
676 | CFReleaseNull(policy); | |
677 | CFReleaseNull(trust); | |
678 | CFReleaseNull(deserializedTrust); | |
679 | CFReleaseNull(error); | |
680 | } | |
681 | ||
682 | - (void)testTLSAnalytics { | |
683 | xpc_object_t metric = xpc_dictionary_create(NULL, NULL, 0); | |
684 | ok(metric != NULL); | |
685 | ||
686 | const char *TLS_METRIC_PROCESS_IDENTIFIER = "process"; | |
687 | const char *TLS_METRIC_CIPHERSUITE = "cipher_name"; | |
688 | const char *TLS_METRIC_PROTOCOL_VERSION = "version"; | |
689 | const char *TLS_METRIC_SESSION_RESUMED = "resumed"; | |
690 | ||
691 | xpc_dictionary_set_string(metric, TLS_METRIC_PROCESS_IDENTIFIER, "super awesome unit tester"); | |
692 | xpc_dictionary_set_uint64(metric, TLS_METRIC_CIPHERSUITE, 0x0304); | |
693 | xpc_dictionary_set_uint64(metric, TLS_METRIC_PROTOCOL_VERSION, 0x0304); | |
694 | xpc_dictionary_set_bool(metric, TLS_METRIC_SESSION_RESUMED, false); | |
695 | // ... TLS would fill in the rest | |
696 | ||
697 | // Invoke the callback | |
698 | CFErrorRef error = NULL; | |
699 | bool reported = SecTrustReportTLSAnalytics(CFSTR("TLSConnectionEvent"), metric, &error); | |
700 | ok(reported, "Failed to report analytics with error %@", error); | |
701 | } | |
702 | ||
703 | - (void)testEvaluateFastAsync | |
704 | { | |
705 | SecCertificateRef cert0 = NULL, cert1 = NULL, cert2 = NULL; | |
706 | SecPolicyRef policy = NULL; | |
707 | __block SecTrustRef trust = NULL; | |
708 | NSArray *certificates = nil, *roots = nil; | |
709 | NSDate *validDate = nil; | |
710 | dispatch_queue_t queue = dispatch_queue_create("com.apple.trusttests.EvalAsync", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); | |
711 | __block XCTestExpectation *blockExpectation = [self expectationWithDescription:@"callback occurs"]; | |
712 | ||
713 | cert0 = SecCertificateCreateWithBytes(NULL, _expired_badssl, sizeof(_expired_badssl)); | |
714 | cert1 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_dvss, sizeof(_comodo_rsa_dvss)); | |
715 | cert2 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_root, sizeof(_comodo_rsa_root)); | |
716 | ||
717 | certificates = @[ (__bridge id)cert0, (__bridge id)cert1 ]; | |
718 | roots = @[ (__bridge id)cert2 ]; | |
719 | ||
720 | policy = SecPolicyCreateSSL(true, CFSTR("expired.badssl.com")); | |
721 | XCTAssert(errSecSuccess == SecTrustCreateWithCertificates((__bridge CFArrayRef)certificates, policy, &trust)); | |
722 | XCTAssert(errSecSuccess == SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)roots)); | |
723 | ||
724 | /* April 10 2015 (cert expired in 2015) */ | |
725 | validDate = CFBridgingRelease(CFDateCreateForGregorianZuluMoment(NULL, 2015, 4, 10, 12, 0, 0)); | |
726 | XCTAssert(errSecSuccess == SecTrustSetVerifyDate(trust, (__bridge CFDateRef)validDate)); | |
727 | ||
728 | #pragma clang diagnostic push | |
729 | #pragma clang diagnostic ignored "-Wnonnull" | |
730 | XCTAssert(errSecParam == SecTrustEvaluateFastAsync(trust, NULL, ^(SecTrustRef _Nonnull trustRef, SecTrustResultType trustResult) { | |
731 | XCTAssert(false, "callback called with invalid parameter"); | |
732 | })); | |
733 | #pragma clang diagnostic pop | |
734 | ||
735 | /* expect success */ | |
736 | dispatch_async(queue, ^{ | |
737 | XCTAssert(errSecSuccess == SecTrustEvaluateFastAsync(trust, queue, ^(SecTrustRef _Nonnull trustRef, SecTrustResultType trustResult) { | |
738 | XCTAssert(trustRef != NULL); | |
739 | XCTAssert(trustResult == kSecTrustResultUnspecified); | |
740 | [blockExpectation fulfill]; | |
741 | })); | |
742 | }); | |
743 | ||
744 | [self waitForExpectations:@[blockExpectation] timeout:1.0]; | |
745 | ||
746 | /* Mar 21 2017 (cert expired in 2015, so this will cause a validity error.) */ | |
747 | validDate = CFBridgingRelease(CFDateCreateForGregorianZuluMoment(NULL, 2017, 3, 21, 12, 0, 0)); | |
748 | XCTAssert(errSecSuccess == SecTrustSetVerifyDate(trust, (__bridge CFDateRef)validDate)); | |
749 | ||
750 | /* expect failure */ | |
751 | blockExpectation = [self expectationWithDescription:@"callback occurs"]; | |
752 | dispatch_async(queue, ^{ | |
753 | XCTAssert(errSecSuccess == SecTrustEvaluateFastAsync(trust, queue, ^(SecTrustRef _Nonnull trustRef, SecTrustResultType trustResult) { | |
754 | XCTAssert(trustRef != NULL); | |
755 | XCTAssert(trustResult == kSecTrustResultRecoverableTrustFailure); | |
756 | [blockExpectation fulfill]; | |
757 | })); | |
758 | }); | |
759 | ||
760 | [self waitForExpectations:@[blockExpectation] timeout:1.0]; | |
761 | ||
762 | CFReleaseNull(cert0); | |
763 | CFReleaseNull(cert1); | |
764 | CFReleaseNull(cert2); | |
765 | CFReleaseNull(policy); | |
766 | CFReleaseNull(trust); | |
767 | } | |
768 | ||
769 | - (void)testEvaluateAsyncWithError | |
770 | { | |
771 | SecCertificateRef cert0 = NULL, cert1 = NULL, cert2 = NULL; | |
772 | SecPolicyRef policy = NULL; | |
773 | SecTrustRef trust = NULL; | |
774 | NSArray *certificates = nil, *roots = nil; | |
775 | NSDate *validDate = nil; | |
776 | dispatch_queue_t queue = dispatch_queue_create("com.apple.trusttests.EvalAsync", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); | |
777 | __block XCTestExpectation *blockExpectation = [self expectationWithDescription:@"callback occurs"]; | |
778 | ||
779 | cert0 = SecCertificateCreateWithBytes(NULL, _expired_badssl, sizeof(_expired_badssl)); | |
780 | cert1 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_dvss, sizeof(_comodo_rsa_dvss)); | |
781 | cert2 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_root, sizeof(_comodo_rsa_root)); | |
782 | ||
783 | certificates = @[ (__bridge id)cert0, (__bridge id)cert1 ]; | |
784 | roots = @[ (__bridge id)cert2 ]; | |
785 | ||
786 | policy = SecPolicyCreateSSL(true, CFSTR("expired.badssl.com")); | |
787 | XCTAssert(errSecSuccess == SecTrustCreateWithCertificates((__bridge CFArrayRef)certificates, policy, &trust)); | |
788 | XCTAssert(errSecSuccess == SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)roots)); | |
789 | ||
790 | /* April 10 2015 (cert expired in 2015) */ | |
791 | validDate = CFBridgingRelease(CFDateCreateForGregorianZuluMoment(NULL, 2015, 4, 10, 12, 0, 0)); | |
792 | XCTAssert(errSecSuccess == SecTrustSetVerifyDate(trust, (__bridge CFDateRef)validDate)); | |
793 | ||
794 | #pragma clang diagnostic push | |
795 | #pragma clang diagnostic ignored "-Wnonnull" | |
796 | XCTAssert(errSecParam == SecTrustEvaluateAsyncWithError(trust, NULL, ^(SecTrustRef _Nonnull trustRef, bool result, CFErrorRef _Nullable error) { | |
797 | XCTAssert(false, "callback called with invalid parameter"); | |
798 | })); | |
799 | #pragma clang diagnostic pop | |
800 | ||
801 | /* expect success */ | |
802 | dispatch_async(queue, ^{ | |
803 | XCTAssert(errSecSuccess == SecTrustEvaluateAsyncWithError(trust, queue, ^(SecTrustRef _Nonnull trustRef, bool result, CFErrorRef _Nullable error) { | |
804 | XCTAssert(trust != NULL); | |
805 | XCTAssertTrue(result); | |
806 | XCTAssert(error == NULL); | |
807 | [blockExpectation fulfill]; | |
808 | })); | |
809 | }); | |
810 | ||
811 | [self waitForExpectations:@[blockExpectation] timeout:1.0]; | |
812 | ||
813 | /* Mar 21 2017 (cert expired in 2015, so this will cause a validity error.) */ | |
814 | validDate = CFBridgingRelease(CFDateCreateForGregorianZuluMoment(NULL, 2017, 3, 21, 12, 0, 0)); | |
815 | XCTAssert(errSecSuccess == SecTrustSetVerifyDate(trust, (__bridge CFDateRef)validDate)); | |
816 | ||
817 | /* expect expiration error */ | |
818 | blockExpectation = [self expectationWithDescription:@"callback occurs"]; | |
819 | dispatch_async(queue, ^{ | |
820 | XCTAssert(errSecSuccess == SecTrustEvaluateAsyncWithError(trust, queue, ^(SecTrustRef _Nonnull trustRef, bool result, CFErrorRef _Nullable error) { | |
821 | XCTAssert(trust != NULL); | |
822 | XCTAssertFalse(result); | |
823 | XCTAssert(error != NULL); | |
824 | XCTAssert(CFErrorGetCode(error) == errSecCertificateExpired); | |
825 | [blockExpectation fulfill]; | |
826 | })); | |
827 | }); | |
828 | ||
829 | [self waitForExpectations:@[blockExpectation] timeout:1.0]; | |
830 | ||
831 | CFReleaseNull(cert0); | |
832 | CFReleaseNull(cert1); | |
833 | CFReleaseNull(cert2); | |
834 | CFReleaseNull(policy); | |
835 | CFReleaseNull(trust); | |
836 | } | |
837 | ||
838 | - (void)testCopyProperties_ios | |
839 | { | |
840 | /* Test null input */ | |
841 | #pragma clang diagnostic push | |
842 | #pragma clang diagnostic ignored "-Wnonnull" | |
843 | #if TARGET_OS_IPHONE | |
844 | XCTAssertEqual(NULL, SecTrustCopyProperties(NULL)); | |
845 | #else | |
846 | XCTAssertEqual(NULL, SecTrustCopyProperties_ios(NULL)); | |
847 | #endif | |
848 | #pragma clang diagnostic pop | |
849 | ||
850 | NSURL *testPlist = nil; | |
851 | NSArray *testsArray = nil; | |
852 | ||
853 | testPlist = [[NSBundle bundleForClass:[self class]] URLForResource:@"debugging" withExtension:@"plist" | |
854 | subdirectory:@"TestCopyProperties_ios-data"]; | |
855 | if (!testPlist) { | |
856 | testPlist = [[NSBundle bundleForClass:[self class]] URLForResource:nil withExtension:@"plist" | |
857 | subdirectory:(NSString *)@"TestCopyProperties_ios-data"]; | |
858 | } | |
859 | if (!testPlist) { | |
860 | fail("Failed to get tests plist from TestCopyProperties-data"); | |
861 | return; | |
862 | } | |
863 | ||
864 | testsArray = [NSArray arrayWithContentsOfURL: testPlist]; | |
865 | if (!testsArray) { | |
866 | fail("Failed to create array from plist"); | |
867 | return; | |
868 | } | |
869 | ||
870 | [testsArray enumerateObjectsUsingBlock:^(NSDictionary *testDict, NSUInteger idx, BOOL * _Nonnull stop) { | |
871 | TestTrustEvaluation *testObj = [[TestTrustEvaluation alloc] initWithTrustDictionary:testDict]; | |
872 | XCTAssertNotNil(testObj, "failed to create test object for %lu", (unsigned long)idx); | |
873 | ||
874 | #if TARGET_OS_BRIDGE | |
875 | // Skip disabled bridgeOS tests on bridgeOS | |
876 | if (testObj.bridgeOSDisabled) { | |
877 | return; | |
878 | } | |
879 | #endif | |
880 | ||
881 | #if TARGET_OS_IPHONE | |
882 | NSArray *properties = CFBridgingRelease(SecTrustCopyProperties(testObj.trust)); | |
883 | #else | |
884 | NSArray *properties = CFBridgingRelease(SecTrustCopyProperties_ios(testObj.trust)); | |
885 | #endif | |
886 | ||
887 | if (testDict[@"ExpectedProperties"]) { | |
888 | XCTAssertEqualObjects(testDict[@"ExpectedProperties"], properties, @"%@ test failed", testObj.fullTestName); | |
889 | } else { | |
890 | XCTAssertNil(properties, @"%@ test failed", testObj.fullTestName); | |
891 | } | |
892 | }]; | |
893 | } | |
894 | ||
d64be36e A |
895 | - (void)testCopyKey |
896 | { | |
897 | SecTrustRef trust = NULL; | |
898 | CFArrayRef certs = NULL; | |
899 | SecCertificateRef cert0 = NULL, cert1 = NULL; | |
900 | SecPolicyRef policy = NULL; | |
901 | ||
902 | isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), | |
903 | NULL, "create cert0"); | |
904 | isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), | |
905 | NULL, "create cert1"); | |
906 | const void *v_certs[] = { cert0, cert1 }; | |
907 | ||
908 | certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); | |
909 | policy = SecPolicyCreateSSL(false, NULL); | |
910 | ||
911 | ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); | |
912 | ||
913 | SecKeyRef trustPubKey = NULL, certPubKey = NULL; | |
914 | ok(trustPubKey = SecTrustCopyKey(trust), "copy public key without securityd running"); | |
915 | ok(certPubKey = SecCertificateCopyKey(cert0)); | |
916 | XCTAssert(CFEqualSafe(trustPubKey, certPubKey)); | |
917 | ||
918 | ||
919 | CFReleaseNull(trustPubKey); | |
920 | CFReleaseNull(certPubKey); | |
921 | CFReleaseNull(trust); | |
922 | CFReleaseNull(cert0); | |
923 | CFReleaseNull(cert1); | |
924 | CFReleaseNull(certs); | |
925 | CFReleaseNull(policy); | |
926 | } | |
927 | ||
b54c578e | 928 | @end |