]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCertificatePath.c
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / sec / Security / SecCertificatePath.c
1 /*
2 * Copyright (c) 2007-2010,2012-2016 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 * SecCertificatePath.c - CoreFoundation based certificate path object
26 */
27
28 #include "SecCertificatePath.h"
29
30 #include <Security/SecTrust.h>
31 #include <Security/SecTrustStore.h>
32 #include <Security/SecItem.h>
33 #include <Security/SecCertificateInternal.h>
34 #include <Security/SecFramework.h>
35 #include <utilities/SecIOFormat.h>
36 #include <CoreFoundation/CFRuntime.h>
37 #include <CoreFoundation/CFSet.h>
38 #include <CoreFoundation/CFString.h>
39 #include <CoreFoundation/CFNumber.h>
40 #include <CoreFoundation/CFArray.h>
41 #include <CoreFoundation/CFPropertyList.h>
42 #include <AssertMacros.h>
43 #include <stdbool.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <pthread.h>
47 #include <Security/SecBase.h>
48 #include "SecRSAKey.h"
49 #include <libDER/oidsPriv.h>
50 #include <utilities/debugging.h>
51 #include <Security/SecInternal.h>
52 #include <AssertMacros.h>
53 #include <utilities/SecCFError.h>
54 #include <utilities/SecCFWrappers.h>
55
56 // MARK: -
57 // MARK: SecCertificatePath
58 /********************************************************
59 ************* SecCertificatePath object ****************
60 ********************************************************/
61 struct SecCertificatePath {
62 CFRuntimeBase _base;
63 CFIndex count;
64
65 /* Index of next parent source to search for parents. */
66 CFIndex nextParentSource;
67
68 /* Index of last certificate in chain who's signature has been verified.
69 0 means nothing has been checked. 1 means the leaf has been verified
70 against it's issuer, etc. */
71 CFIndex lastVerifiedSigner;
72
73 /* Index of first self issued certificate in the chain. -1 mean there is
74 none. 0 means the leaf is self signed. */
75 CFIndex selfIssued;
76
77 /* True iff cert at index selfIssued does in fact self verify. */
78 bool isSelfSigned;
79
80 /* True if the root of this path is a trusted anchor.
81 FIXME get rid of this since it's a property of the evaluation, not a
82 static feature of a certificate path? */
83 bool isAnchored;
84
85 /* Usage constraints derived from trust settings. */
86 CFMutableArrayRef usageConstraints;
87
88 SecCertificateRef certificates[];
89 };
90
91 CFGiblisWithHashFor(SecCertificatePath)
92
93 static void SecCertificatePathDestroy(CFTypeRef cf) {
94 SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
95 CFIndex ix;
96 for (ix = 0; ix < certificatePath->count; ++ix) {
97 CFRelease(certificatePath->certificates[ix]);
98 }
99 CFRelease(certificatePath->usageConstraints);
100 }
101
102 static Boolean SecCertificatePathCompare(CFTypeRef cf1, CFTypeRef cf2) {
103 SecCertificatePathRef cp1 = (SecCertificatePathRef) cf1;
104 SecCertificatePathRef cp2 = (SecCertificatePathRef) cf2;
105 if (cp1->count != cp2->count)
106 return false;
107 CFIndex ix;
108 for (ix = 0; ix < cp1->count; ++ix) {
109 if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix]))
110 return false;
111 }
112 if (!CFEqual(cp1->usageConstraints, cp2->usageConstraints))
113 return false;
114
115 return true;
116 }
117
118 static CFHashCode SecCertificatePathHash(CFTypeRef cf) {
119 SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
120 CFHashCode hashCode = 0;
121 // hashCode = 31 * SecCertificatePathGetTypeID();
122 CFIndex ix;
123 for (ix = 0; ix < certificatePath->count; ++ix) {
124 hashCode += CFHash(certificatePath->certificates[ix]);
125 }
126 hashCode += CFHash(certificatePath->usageConstraints);
127 return hashCode;
128 }
129
130 static CFStringRef SecCertificatePathCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
131 SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
132 CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
133 CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf));
134 CFStringAppendFormat(desc, NULL,
135 CFSTR("<%@ lvs: %" PRIdCFIndex " certs: "), typeStr,
136 certificatePath->lastVerifiedSigner);
137 CFRelease(typeStr);
138 CFIndex ix;
139 for (ix = 0; ix < certificatePath->count; ++ix) {
140 if (ix > 0) {
141 CFStringAppend(desc, CFSTR(", "));
142 }
143 CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]);
144 CFStringAppend(desc, str);
145 CFRelease(str);
146 }
147 CFStringAppend(desc, CFSTR(" >"));
148
149 return desc;
150 }
151
152 /* Create a new certificate path from an old one. */
153 SecCertificatePathRef SecCertificatePathCreate(SecCertificatePathRef path,
154 SecCertificateRef certificate, CFArrayRef usageConstraints) {
155 CFAllocatorRef allocator = kCFAllocatorDefault;
156 check(certificate);
157 CFIndex count;
158 CFIndex selfIssued, lastVerifiedSigner;
159 bool isSelfSigned;
160 if (path) {
161 count = path->count + 1;
162 lastVerifiedSigner = path->lastVerifiedSigner;
163 selfIssued = path->selfIssued;
164 isSelfSigned = path->isSelfSigned;
165 } else {
166 count = 1;
167 lastVerifiedSigner = 0;
168 selfIssued = -1;
169 isSelfSigned = false;
170 }
171
172 CFIndex size = sizeof(struct SecCertificatePath) +
173 count * sizeof(SecCertificateRef);
174 SecCertificatePathRef result =
175 (SecCertificatePathRef)_CFRuntimeCreateInstance(allocator,
176 SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0);
177 if (!result)
178 return NULL;
179
180 result->count = count;
181 result->nextParentSource = 0;
182 result->lastVerifiedSigner = lastVerifiedSigner;
183 result->selfIssued = selfIssued;
184 result->isSelfSigned = isSelfSigned;
185 result->isAnchored = false;
186 CFIndex ix;
187 for (ix = 0; ix < count - 1; ++ix) {
188 result->certificates[ix] = path->certificates[ix];
189 CFRetain(result->certificates[ix]);
190 }
191 result->certificates[count - 1] = certificate;
192 CFRetainSafe(certificate);
193
194 CFArrayRef emptyArray = NULL;
195 if (!usageConstraints) {
196 require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result));
197 usageConstraints = emptyArray;
198 }
199 CFMutableArrayRef constraints;
200 if (path) {
201 require_action_quiet(constraints = CFArrayCreateMutableCopy(kCFAllocatorDefault, count, path->usageConstraints), exit, CFReleaseNull(result));
202 } else {
203 require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result));
204 }
205 CFArrayAppendValue(constraints, usageConstraints);
206 result->usageConstraints = constraints;
207
208 exit:
209 CFReleaseSafe(emptyArray);
210 return result;
211 }
212
213 /* Create a new certificate path from an xpc_array of data. */
214 SecCertificatePathRef SecCertificatePathCreateWithXPCArray(xpc_object_t xpc_path, CFErrorRef *error) {
215 SecCertificatePathRef result = NULL;
216 require_action_quiet(xpc_path, exit, SecError(errSecParam, error, CFSTR("xpc_path is NULL")));
217 require_action_quiet(xpc_get_type(xpc_path) == XPC_TYPE_ARRAY, exit, SecError(errSecDecode, error, CFSTR("xpc_path value is not an array")));
218 size_t count;
219 require_action_quiet(count = xpc_array_get_count(xpc_path), exit, SecError(errSecDecode, error, CFSTR("xpc_path array count == 0")));
220 size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
221 require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit, SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
222 CFMutableArrayRef constraints;
223 require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, SecError(errSecAllocate, error, CFSTR("failed to create constraints")); CFReleaseNull(result));
224
225 result->count = count;
226 result->nextParentSource = 0;
227 result->lastVerifiedSigner = count;
228 result->selfIssued = -1;
229 result->isSelfSigned = false;
230 result->isAnchored = false;
231 result->usageConstraints = constraints;
232
233 size_t ix;
234 for (ix = 0; ix < count; ++ix) {
235 SecCertificateRef certificate = SecCertificateCreateWithXPCArrayAtIndex(xpc_path, ix, error);
236 if (certificate) {
237 result->certificates[ix] = certificate;
238 CFArrayRef emptyArray;
239 require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, SecError(errSecAllocate, error, CFSTR("failed to create emptyArray")); CFReleaseNull(result));
240 CFArrayAppendValue(result->usageConstraints, emptyArray);
241 CFRelease(emptyArray);
242 } else {
243 result->count = ix; // total allocated
244 CFReleaseNull(result);
245 break;
246 }
247 }
248
249 exit:
250 return result;
251 }
252
253 SecCertificatePathRef SecCertificatePathCreateDeserialized(CFArrayRef certificates, CFErrorRef *error) {
254 SecCertificatePathRef result = NULL;
255 require_action_quiet(isArray(certificates), exit,
256 SecError(errSecParam, error, CFSTR("certificates is not an array")));
257 size_t count = 0;
258 require_action_quiet(count = CFArrayGetCount(certificates), exit,
259 SecError(errSecDecode, error, CFSTR("certificates array count == 0")));
260 size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
261 require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit,
262 SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
263 CFMutableArrayRef constraints;
264 require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit,
265 SecError(errSecAllocate, error, CFSTR("failed to create constraints")); CFReleaseNull(result));
266
267 result->count = count;
268 result->nextParentSource = 0;
269 result->lastVerifiedSigner = count;
270 result->selfIssued = -1;
271 result->isSelfSigned = false;
272 result->isAnchored = false;
273 result->usageConstraints = constraints;
274
275 size_t ix;
276 for (ix = 0; ix < count; ++ix) {
277 SecCertificateRef certificate = SecCertificateCreateWithData(NULL, CFArrayGetValueAtIndex(certificates, ix));
278 if (certificate) {
279 result->certificates[ix] = certificate;
280 CFArrayRef emptyArray;
281 require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit,
282 SecError(errSecAllocate, error, CFSTR("failed to create emptyArray")); CFReleaseNull(result));
283 CFArrayAppendValue(result->usageConstraints, emptyArray);
284 CFRelease(emptyArray);
285 } else {
286 result->count = ix; // total allocated
287 CFReleaseNull(result);
288 break;
289 }
290 }
291
292 exit:
293 return result;
294 }
295
296 SecCertificatePathRef SecCertificatePathCopyFromParent(
297 SecCertificatePathRef path, CFIndex skipCount) {
298 CFAllocatorRef allocator = kCFAllocatorDefault;
299 CFIndex count;
300 CFIndex selfIssued, lastVerifiedSigner;
301 bool isSelfSigned;
302
303 /* Ensure we are at least returning a path of length 1. */
304 if (skipCount < 0 || path->count < 1 + skipCount)
305 return NULL;
306
307 count = path->count - skipCount;
308 lastVerifiedSigner = path->lastVerifiedSigner > skipCount
309 ? path->lastVerifiedSigner - skipCount : 0;
310 selfIssued = path->selfIssued >= skipCount
311 ? path->selfIssued - skipCount : -1;
312 isSelfSigned = path->selfIssued >= 0 ? path->isSelfSigned : false;
313
314 CFIndex size = sizeof(struct SecCertificatePath) +
315 count * sizeof(SecCertificateRef);
316 SecCertificatePathRef result =
317 (SecCertificatePathRef)_CFRuntimeCreateInstance(allocator,
318 SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0);
319 if (!result)
320 return NULL;
321
322 CFMutableArrayRef constraints;
323 require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result));
324
325 result->count = count;
326 result->nextParentSource = 0;
327 result->lastVerifiedSigner = lastVerifiedSigner;
328 result->selfIssued = selfIssued;
329 result->isSelfSigned = isSelfSigned;
330 result->isAnchored = path->isAnchored;
331 result->usageConstraints = constraints;
332 CFIndex ix;
333 for (ix = 0; ix < count; ++ix) {
334 CFIndex pathIX = ix + skipCount;
335 result->certificates[ix] = path->certificates[pathIX];
336 CFRetain(result->certificates[ix]);
337 CFArrayAppendValue(result->usageConstraints, CFArrayGetValueAtIndex(path->usageConstraints, pathIX));
338 }
339
340 exit:
341 return result;
342 }
343
344 SecCertificatePathRef SecCertificatePathCopyAddingLeaf(SecCertificatePathRef path,
345 SecCertificateRef leaf) {
346 CFAllocatorRef allocator = kCFAllocatorDefault;
347 CFIndex count;
348 CFIndex selfIssued, lastVerifiedSigner;
349 bool isSelfSigned;
350
351 /* First make sure the new leaf is signed by path's current leaf. */
352 SecKeyRef issuerKey = SecCertificatePathCopyPublicKeyAtIndex(path, 0);
353 if (!issuerKey)
354 return NULL;
355 OSStatus status = SecCertificateIsSignedBy(leaf, issuerKey);
356 CFRelease(issuerKey);
357 if (status)
358 return NULL;
359
360 count = path->count + 1;
361 lastVerifiedSigner = path->lastVerifiedSigner + 1;
362 selfIssued = path->selfIssued;
363 isSelfSigned = path->isSelfSigned;
364
365 CFIndex size = sizeof(struct SecCertificatePath) +
366 count * sizeof(SecCertificateRef);
367 SecCertificatePathRef result =
368 (SecCertificatePathRef)_CFRuntimeCreateInstance(allocator,
369 SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0);
370 if (!result)
371 return NULL;
372
373 CFMutableArrayRef constraints;
374 require_action_quiet(constraints = CFArrayCreateMutableCopy(kCFAllocatorDefault, count, path->usageConstraints), exit, CFReleaseNull(result));
375
376 result->count = count;
377 result->nextParentSource = 0;
378 result->lastVerifiedSigner = lastVerifiedSigner;
379 result->selfIssued = selfIssued;
380 result->isSelfSigned = isSelfSigned;
381 result->isAnchored = path->isAnchored;
382 result->usageConstraints = constraints;
383 CFIndex ix;
384 for (ix = 1; ix < count; ++ix) {
385 result->certificates[ix] = path->certificates[ix - 1];
386 CFRetain(result->certificates[ix]);
387 }
388 result->certificates[0] = leaf;
389 CFRetain(leaf);
390
391 CFArrayRef emptyArray;
392 require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result));
393 CFArrayInsertValueAtIndex(result->usageConstraints, 0, emptyArray);
394 CFRelease(emptyArray);
395
396 exit:
397 return result;
398 }
399
400 /* Create an array of CFDataRefs from a certificate path. */
401 xpc_object_t SecCertificatePathCopyXPCArray(SecCertificatePathRef path, CFErrorRef *error) {
402 xpc_object_t xpc_chain = NULL;
403 size_t ix, count = path->count;
404 require_action_quiet(xpc_chain = xpc_array_create(NULL, 0), exit, SecError(errSecParam, error, CFSTR("xpc_array_create failed")));
405 for (ix = 0; ix < count; ++ix) {
406 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
407 if (!SecCertificateAppendToXPCArray(cert, xpc_chain, error)) {
408 xpc_release(xpc_chain);
409 return NULL;
410 }
411 }
412
413 exit:
414 return xpc_chain;
415 }
416
417 /* Create an array of SecCertificateRefs from a certificate path. */
418 CFArrayRef SecCertificatePathCopyCertificates(SecCertificatePathRef path, CFErrorRef *error) {
419 CFMutableArrayRef outCerts = NULL;
420 size_t ix, count = path->count;
421 require_action_quiet(outCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit,
422 SecError(errSecParam, error, CFSTR("CFArray failed to create")));
423 for (ix = 0; ix < count; ++ix) {
424 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
425 if (cert) {
426 CFArrayAppendValue(outCerts, cert);
427 }
428 }
429 exit:
430 return outCerts;
431 }
432
433 CFArrayRef SecCertificatePathCreateSerialized(SecCertificatePathRef path, CFErrorRef *error) {
434 CFMutableArrayRef serializedCerts = NULL;
435 require_quiet(path, exit);
436 size_t ix, count = path->count;
437 require_action_quiet(serializedCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit,
438 SecError(errSecParam, error, CFSTR("CFArray failed to create")));
439 for (ix = 0; ix < count; ++ix) {
440 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
441 CFDataRef certData = SecCertificateCopyData(cert);
442 if (certData) {
443 CFArrayAppendValue(serializedCerts, certData);
444 CFRelease(certData);
445 }
446 }
447 exit:
448 return serializedCerts;
449 }
450
451 /* Record the fact that we found our own root cert as our parent
452 certificate. */
453 void SecCertificatePathSetSelfIssued(
454 SecCertificatePathRef certificatePath) {
455 if (certificatePath->selfIssued >= 0) {
456 secdebug("trust", "%@ is already issued at %" PRIdCFIndex, certificatePath,
457 certificatePath->selfIssued);
458 return;
459 }
460 secdebug("trust", "%@ is self issued", certificatePath);
461 certificatePath->selfIssued = certificatePath->count - 1;
462
463 /* now check that the selfIssued cert was actually self-signed */
464 if (certificatePath->selfIssued >= 0 && !certificatePath->isSelfSigned) {
465 SecCertificateRef cert = certificatePath->certificates[certificatePath->selfIssued];
466 Boolean isSelfSigned = false;
467 OSStatus status = SecCertificateIsSelfSigned(cert, &isSelfSigned);
468 if ((status == errSecSuccess) && isSelfSigned) {
469 certificatePath->isSelfSigned = true;
470 } else {
471 certificatePath->selfIssued = -1;
472 }
473 }
474 }
475
476 void SecCertificatePathSetIsAnchored(
477 SecCertificatePathRef certificatePath) {
478 secdebug("trust", "%@ is anchored", certificatePath);
479 certificatePath->isAnchored = true;
480
481 /* Now check if that anchor (last cert) was actually self-signed.
482 * In the non-anchor case, this is handled by SecCertificatePathSetSelfIssued.
483 * Because anchored chains immediately go into the candidate bucket in the trust
484 * server, we need to ensure that the self-signed/self-issued members are set
485 * for the purposes of scoring. */
486 if (!certificatePath->isSelfSigned && certificatePath->count > 0) {
487 SecCertificateRef cert = certificatePath->certificates[certificatePath->count - 1];
488 Boolean isSelfSigned = false;
489 OSStatus status = SecCertificateIsSelfSigned(cert, &isSelfSigned);
490 if ((status == errSecSuccess) && isSelfSigned) {
491 certificatePath->isSelfSigned = true;
492 if (certificatePath->selfIssued == -1) {
493 certificatePath->selfIssued = certificatePath->count - 1;
494 }
495 }
496 }
497 }
498
499 /* Return the index of the first non anchor certificate in the chain that is
500 self signed counting from the leaf up. Return -1 if there is none. */
501 CFIndex SecCertificatePathSelfSignedIndex(
502 SecCertificatePathRef certificatePath) {
503 if (certificatePath->isSelfSigned)
504 return certificatePath->selfIssued;
505 return -1;
506 }
507
508 Boolean SecCertificatePathIsAnchored(
509 SecCertificatePathRef certificatePath) {
510 return certificatePath->isAnchored;
511 }
512
513 void SecCertificatePathSetNextSourceIndex(
514 SecCertificatePathRef certificatePath, CFIndex sourceIndex) {
515 certificatePath->nextParentSource = sourceIndex;
516 }
517
518 CFIndex SecCertificatePathGetNextSourceIndex(
519 SecCertificatePathRef certificatePath) {
520 return certificatePath->nextParentSource;
521 }
522
523 CFIndex SecCertificatePathGetCount(
524 SecCertificatePathRef certificatePath) {
525 check(certificatePath);
526 return certificatePath ? certificatePath->count : 0;
527 }
528
529 SecCertificateRef SecCertificatePathGetCertificateAtIndex(
530 SecCertificatePathRef certificatePath, CFIndex ix) {
531 check(certificatePath && ix >= 0 && ix < certificatePath->count);
532 return certificatePath->certificates[ix];
533 }
534
535 CFIndex SecCertificatePathGetIndexOfCertificate(SecCertificatePathRef path,
536 SecCertificateRef certificate) {
537 CFIndex ix, count = path->count;
538 for (ix = 0; ix < count; ++ix) {
539 if (CFEqual(path->certificates[ix], certificate))
540 return ix;
541 }
542 return kCFNotFound;
543 }
544
545 #if 0
546 /* Return the leaf certificate for certificatePath. */
547 SecCertificateRef SecCertificatePathGetLeaf(
548 SecCertificatePathRef certificatePath) {
549 return SecCertificatePathGetCertificateAtIndex(certificatePath, 0);
550 }
551 #endif
552
553 /* Return the root certificate for certificatePath. Note that root is just
554 the top of the path as far as it is constructed. It may or may not be
555 trusted or self signed. */
556 SecCertificateRef SecCertificatePathGetRoot(
557 SecCertificatePathRef certificatePath) {
558 return SecCertificatePathGetCertificateAtIndex(certificatePath,
559 SecCertificatePathGetCount(certificatePath) - 1);
560 }
561
562 SecKeyRef SecCertificatePathCopyPublicKeyAtIndex(
563 SecCertificatePathRef certificatePath, CFIndex ix) {
564 SecCertificateRef certificate =
565 SecCertificatePathGetCertificateAtIndex(certificatePath, ix);
566 #if TARGET_OS_OSX
567 return SecCertificateCopyPublicKey_ios(certificate);
568 #else
569 return SecCertificateCopyPublicKey(certificate);
570 #endif
571 }
572
573 CFArrayRef SecCertificatePathGetUsageConstraintsAtIndex(
574 SecCertificatePathRef certificatePath, CFIndex ix) {
575 return (CFArrayRef)CFArrayGetValueAtIndex(certificatePath->usageConstraints, ix);
576 }
577
578 SecPathVerifyStatus SecCertificatePathVerify(
579 SecCertificatePathRef certificatePath) {
580 check(certificatePath);
581 if (!certificatePath)
582 return kSecPathVerifyFailed;
583 for (;
584 certificatePath->lastVerifiedSigner < certificatePath->count - 1;
585 ++certificatePath->lastVerifiedSigner) {
586 SecKeyRef issuerKey =
587 SecCertificatePathCopyPublicKeyAtIndex(certificatePath,
588 certificatePath->lastVerifiedSigner + 1);
589 if (!issuerKey)
590 return kSecPathVerifiesUnknown;
591 OSStatus status = SecCertificateIsSignedBy(
592 certificatePath->certificates[certificatePath->lastVerifiedSigner],
593 issuerKey);
594 CFRelease(issuerKey);
595 if (status) {
596 return kSecPathVerifyFailed;
597 }
598 }
599
600 return kSecPathVerifySuccess;
601 }
602
603 bool SecCertificatePathIsValid(SecCertificatePathRef certificatePath, CFAbsoluteTime verifyTime) {
604 CFIndex ix;
605 for (ix = 0; ix < certificatePath->count; ++ix) {
606 if (!SecCertificateIsValid(certificatePath->certificates[ix],
607 verifyTime))
608 return false;
609 }
610 return true;
611 }
612
613 bool SecCertificatePathHasWeakHash(SecCertificatePathRef certificatePath) {
614 CFIndex ix, count = certificatePath->count;
615
616 if (SecCertificatePathIsAnchored(certificatePath)) {
617 /* For anchored paths, don't check the hash algorithm of the anchored cert,
618 * since we already decided to trust it. */
619 count--;
620 }
621 for (ix = 0; ix < count; ++ix) {
622 if (SecCertificateIsWeakHash(certificatePath->certificates[ix])) {
623 return true;
624 }
625 }
626 return false;
627 }
628
629 bool SecCertificatePathHasWeakKeySize(SecCertificatePathRef certificatePath) {
630 CFDictionaryRef keySizes = NULL;
631 CFNumberRef rsaSize = NULL, ecSize = NULL;
632 bool result = true;
633
634 /* RSA key sizes are 2048-bit or larger. EC key sizes are P-224 or larger. */
635 require(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), errOut);
636 require(ecSize = CFNumberCreateWithCFIndex(NULL, 224), errOut);
637 const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC };
638 const void *values[] = { rsaSize, ecSize };
639 require(keySizes = CFDictionaryCreate(NULL, keys, values, 2,
640 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
641
642 CFIndex ix;
643 for (ix = 0; ix < certificatePath->count; ++ix) {
644 if (!SecCertificateIsAtLeastMinKeySize(certificatePath->certificates[ix],
645 keySizes)) {
646 result = true;
647 goto errOut;
648 }
649 }
650 result = false;
651
652 errOut:
653 CFReleaseSafe(keySizes);
654 CFReleaseSafe(rsaSize);
655 CFReleaseSafe(ecSize);
656 return result;
657 }
658
659 /* Return a score for this certificate chain. */
660 CFIndex SecCertificatePathScore(
661 SecCertificatePathRef certificatePath, CFAbsoluteTime verifyTime) {
662 CFIndex score = 0;
663
664 /* Paths that don't verify score terribly.c */
665 if (certificatePath->lastVerifiedSigner != certificatePath->count - 1) {
666 secdebug("trust", "lvs: %" PRIdCFIndex " count: %" PRIdCFIndex,
667 certificatePath->lastVerifiedSigner, certificatePath->count);
668 score -= 100000;
669 }
670
671 if (certificatePath->isAnchored) {
672 /* Anchored paths for the win! */
673 score += 10000;
674 }
675
676 if (certificatePath->isSelfSigned && (certificatePath->selfIssued == certificatePath->count - 1)) {
677 /* Chains that terminate in a self-signed certificate are preferred,
678 even if they don't end in an anchor. */
679 score += 1000;
680 /* Shorter chains ending in a self-signed cert are preferred. */
681 score -= 1 * certificatePath->count;
682 } else {
683 /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */
684 score += 1 * certificatePath->count;
685 }
686
687 if (SecCertificatePathIsValid(certificatePath, verifyTime)) {
688 score += 100;
689 }
690
691 if (!SecCertificatePathHasWeakHash(certificatePath)) {
692 score += 10;
693 }
694
695 if (!SecCertificatePathHasWeakKeySize(certificatePath)) {
696 score += 10;
697 }
698
699 return score;
700 }