2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <AssertMacros.h>
26 #import <Foundation/Foundation.h>
27 #include <Security/SecCertificatePriv.h>
28 #include <utilities/SecCFWrappers.h>
30 #import "TrustEvaluationTestCase.h"
31 #include "PathScoringTests_data.h"
32 #include "../TestMacroConversions.h"
34 @interface PathScoringTests : TrustEvaluationTestCase
37 @implementation PathScoringTests
39 static SecCertificateRef leaf = NULL;
40 static SecCertificateRef intSHA2 = NULL;
41 static SecCertificateRef intSHA1 = NULL;
42 static SecCertificateRef int1024 = NULL;
43 static SecCertificateRef rootSHA2 = NULL;
44 static SecCertificateRef rootSHA1 = NULL;
45 static SecCertificateRef root1024 = NULL;
46 static SecCertificateRef crossSHA2_SHA1 = NULL;
47 static SecCertificateRef crossSHA2_SHA2 = NULL;
48 static SecCertificateRef rootSHA2_2 = NULL;
49 static SecPolicyRef basicPolicy = NULL;
50 static SecPolicyRef sslPolicy = NULL;
51 static NSDate *verifyDate1 = nil;
52 static NSDate *verifyDate2 = nil;
55 leaf = SecCertificateCreateWithBytes(NULL, _pathScoringLeaf, sizeof(_pathScoringLeaf));
56 intSHA2 = SecCertificateCreateWithBytes(NULL, _pathScoringIntSHA2, sizeof(_pathScoringIntSHA2));
57 intSHA1 = SecCertificateCreateWithBytes(NULL, _pathScoringIntSHA1, sizeof(_pathScoringIntSHA1));
58 int1024 = SecCertificateCreateWithBytes(NULL, _pathScoringInt1024, sizeof(_pathScoringInt1024));
59 rootSHA2 = SecCertificateCreateWithBytes(NULL, _pathScoringSHA2Root, sizeof(_pathScoringSHA2Root));
60 rootSHA1 = SecCertificateCreateWithBytes(NULL, _pathScoringSHA1Root, sizeof(_pathScoringSHA1Root));
61 root1024 = SecCertificateCreateWithBytes(NULL, _pathScoring1024Root, sizeof(_pathScoring1024Root));
62 crossSHA2_SHA1 = SecCertificateCreateWithBytes(NULL, _pathScoringSHA2CrossSHA1, sizeof(_pathScoringSHA2CrossSHA1));
63 crossSHA2_SHA2 = SecCertificateCreateWithBytes(NULL, _pathScoringSHA2CrossSHA2, sizeof(_pathScoringSHA2CrossSHA2));
64 rootSHA2_2 = SecCertificateCreateWithBytes(NULL, _pathScoringSHA2Root2, sizeof(_pathScoringSHA2Root2));
66 basicPolicy = SecPolicyCreateBasicX509();
67 sslPolicy = SecPolicyCreateSSL(true, NULL);
69 // May 1, 2016 at 5:53:20 AM PDT
70 verifyDate1 = [NSDate dateWithTimeIntervalSinceReferenceDate:483800000.0];
71 // May 27, 2016 at 4:20:50 PM PDT
72 verifyDate2 = [NSDate dateWithTimeIntervalSinceReferenceDate:486084050.0];
77 CFReleaseNull(intSHA2);
78 CFReleaseNull(intSHA1);
79 CFReleaseNull(int1024);
80 CFReleaseNull(rootSHA2);
81 CFReleaseNull(rootSHA1);
82 CFReleaseNull(root1024);
83 CFReleaseNull(crossSHA2_SHA1);
84 CFReleaseNull(crossSHA2_SHA2);
85 CFReleaseNull(rootSHA2_2);
87 CFReleaseNull(basicPolicy);
88 CFReleaseNull(sslPolicy);
91 static bool evaluateTrust(NSArray *certs, NSArray *anchors, SecPolicyRef policy,
92 NSDate *verifyDate, bool expectedResult,
93 NSArray *expectedChain) {
94 bool testPassed = false;
95 SecTrustRef trust = NULL;
97 require_noerr_string(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs,
100 errOut, "failed to create trust ref");
102 require_noerr_string(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors),
103 errOut, "failed to set anchors");
105 require_noerr_string(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate),
106 errOut, "failed to set verify date");
107 result = SecTrustEvaluateWithError(trust, NULL);
110 if (expectedResult) {
111 require_string(result == expectedResult,
112 errOut, "unexpected untrusted chain");
114 require_string(result == expectedResult,
115 errOut, "unexpected trusted chain");
118 /* check the chain that returned */
119 require_string((NSUInteger)SecTrustGetCertificateCount(trust) == [expectedChain count],
120 errOut, "wrong number of certs in result chain");
121 NSUInteger ix, count = [expectedChain count];
122 for (ix = 0; ix < count; ix++) {
123 require_string(CFEqual(SecTrustGetCertificateAtIndex(trust, ix),
124 (__bridge SecCertificateRef)[expectedChain objectAtIndex:ix]),
125 errOut, "chain didn't match expected");
130 CFReleaseNull(trust);
134 /* Path Scoring Hierarchy
138 * intSHA2 intSHA1 int1024
141 * rootSHA2 crossSHA2_SHA1 crossSHA2_SHA2 rootSHA1 root1024
144 * rootSHA1 rootSHA2_2
147 - (void)exerciseChainsForPolicy:(SecPolicyRef)policy {
148 NSArray *certs = nil;
149 NSArray *anchors = nil;
150 NSArray *chain = nil;
151 bool expectedTrustResult = ((policy == basicPolicy) ? true : false);
153 /* Choose a short chain over a long chain, when ending in a self-signed cert */
154 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)crossSHA2_SHA2];
155 anchors = @[(__bridge id)rootSHA2, (__bridge id)rootSHA2_2];
156 chain = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)rootSHA2];
157 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
158 "%s test: choose shorter chain over longer chain, SHA-2",
159 (policy == basicPolicy) ? "accept" : "reject");
161 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)intSHA1, (__bridge id)crossSHA2_SHA1];
162 anchors = @[(__bridge id)rootSHA1];
163 chain = @[(__bridge id)leaf, (__bridge id)intSHA1, (__bridge id)rootSHA1];
164 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
165 "%s test: choose shorter chain over longer chain, SHA-1",
166 (policy == basicPolicy) ? "accept" : "reject");
168 /* Choose a SHA-2 chain over a SHA-1 chain */
169 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)intSHA1];
170 anchors = @[(__bridge id)rootSHA1, (__bridge id)rootSHA2];
171 chain = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)rootSHA2];
172 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
173 "%s test: choose SHA-2 chain over SHA-1 chain, order 1",
174 (policy == basicPolicy) ? "accept" : "reject");
176 certs = @[(__bridge id)leaf, (__bridge id)intSHA1, (__bridge id)intSHA2];
177 anchors = @[(__bridge id)rootSHA2, (__bridge id)rootSHA1];
178 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
179 "%s test: choose SHA-2 chain over SHA-1 chain, order 2",
180 (policy == basicPolicy) ? "accept" : "reject");
182 /* Choose a longer SHA-2 chain over the shorter SHA-1 chain */
183 certs = @[(__bridge id)leaf, (__bridge id)intSHA1, (__bridge id)intSHA2, (__bridge id)crossSHA2_SHA2];
184 anchors = @[(__bridge id)rootSHA1, (__bridge id)rootSHA2_2];
185 chain = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)crossSHA2_SHA2, (__bridge id)rootSHA2_2];
186 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
187 "%s test: choose longer SHA-2 chain over shorter SHA-1 chain",
188 (policy == basicPolicy) ? "accept" : "reject");
190 /* Choose 1024-bit temporally valid chain over 2048-bit invalid chain */
191 certs = @[(__bridge id)leaf, (__bridge id)int1024, (__bridge id)intSHA1];
192 anchors = @[(__bridge id)root1024, (__bridge id)rootSHA1];
193 chain = @[(__bridge id)leaf, (__bridge id)int1024, (__bridge id)root1024];
194 ok(evaluateTrust(certs, anchors, policy, verifyDate2, expectedTrustResult, chain),
195 "%s test: choose temporally valid chain over invalid chain",
196 (policy == basicPolicy) ? "accept" : "reject");
198 /* Choose an anchored chain over an unanchored chain */
199 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)intSHA1, (__bridge id)rootSHA2];
200 anchors = @[(__bridge id)rootSHA1];
201 chain = @[(__bridge id)leaf, (__bridge id)intSHA1, (__bridge id)rootSHA1];
202 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
203 "%s test: choose an anchored chain over an unanchored chain",
204 (policy == basicPolicy) ? "accept" : "reject");
206 /* Choose an anchored SHA-1 chain over an unanchored SHA-2 chain */
207 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)intSHA1, (__bridge id)rootSHA2];
208 anchors = @[(__bridge id)rootSHA1];
209 chain = @[(__bridge id)leaf, (__bridge id)intSHA1, (__bridge id)rootSHA1];
210 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
211 "%s test: choose anchored SHA-1 chain over unanchored SHA-2 chain",
212 (policy == basicPolicy) ? "accept" : "reject");
214 /* Choose an anchored SHA-1 cross-signed chain over unanchored SHA-2 chains */
215 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)rootSHA2,
216 (__bridge id)crossSHA2_SHA1, (__bridge id)crossSHA2_SHA2, (__bridge id)rootSHA2_2];
217 chain = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)crossSHA2_SHA1, (__bridge id)rootSHA1];
218 ok(evaluateTrust(certs, anchors, policy, verifyDate1, expectedTrustResult, chain),
219 "%s test: choose anchored cross-signed chain over unanchored chains",
220 (policy == basicPolicy) ? "accept" : "reject");
223 - (void)testPassingEvals {
224 [self exerciseChainsForPolicy:basicPolicy];
227 - (void)testFailingEvals {
228 [self exerciseChainsForPolicy:sslPolicy];
230 /* reject only tests */
231 NSArray *certs = nil;
232 NSArray *anchors = nil;
233 NSArray *chain = nil;
235 /* Choose a 2048-bit chain over a 1024-bit chain */
236 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)int1024];
237 anchors = @[(__bridge id)rootSHA2, (__bridge id)root1024];
238 chain = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)rootSHA2];
239 ok(evaluateTrust(certs, anchors, sslPolicy, verifyDate1, false, chain),
240 "reject test: choose 2048-bit chain over 1024-bit chain, order 1");
242 certs = @[(__bridge id)leaf, (__bridge id)int1024, (__bridge id)intSHA2];
243 anchors = @[(__bridge id)root1024, (__bridge id)rootSHA2];
244 ok(evaluateTrust(certs, anchors, sslPolicy, verifyDate1, false, chain),
245 "reject test: choose 2048-bit chain over 1024-bit chain, order 2");
247 /* Choose a complete chain over an incomplete chain */
248 certs = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)intSHA1, (__bridge id)rootSHA1];
250 chain = @[(__bridge id)leaf, (__bridge id)intSHA1, (__bridge id)rootSHA1];
251 ok(evaluateTrust(certs, anchors, sslPolicy, verifyDate1, false, chain),
252 "reject test: choose a chain that ends in a self-signed cert over one that doesn't");
254 /* Choose a long chain over a short chain when not ending with a self-signed cert */
255 certs = @[(__bridge id)leaf, (__bridge id)crossSHA2_SHA2, (__bridge id)intSHA2];
257 chain = @[(__bridge id)leaf, (__bridge id)intSHA2, (__bridge id)crossSHA2_SHA2];
258 ok(evaluateTrust(certs, anchors, sslPolicy, verifyDate1, false, chain),
259 "reject test: choose longer chain over shorter chain, no roots");