2 * Copyright (c) 2007-2010,2012-2016 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 * SecCertificatePath.c - CoreFoundation based certificate path object
28 #include "SecCertificatePath.h"
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>
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>
57 // MARK: SecCertificatePath
58 /********************************************************
59 ************* SecCertificatePath object ****************
60 ********************************************************/
61 struct SecCertificatePath
{
65 /* Index of next parent source to search for parents. */
66 CFIndex nextParentSource
;
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
;
73 /* Index of first self issued certificate in the chain. -1 mean there is
74 none. 0 means the leaf is self signed. */
77 /* True iff cert at index selfIssued does in fact self verify. */
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? */
85 /* Usage constraints derived from trust settings. */
86 CFMutableArrayRef usageConstraints
;
88 SecCertificateRef certificates
[];
91 CFGiblisWithHashFor(SecCertificatePath
)
93 static void SecCertificatePathDestroy(CFTypeRef cf
) {
94 SecCertificatePathRef certificatePath
= (SecCertificatePathRef
) cf
;
96 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
97 CFRelease(certificatePath
->certificates
[ix
]);
99 CFRelease(certificatePath
->usageConstraints
);
102 static Boolean
SecCertificatePathCompare(CFTypeRef cf1
, CFTypeRef cf2
) {
103 SecCertificatePathRef cp1
= (SecCertificatePathRef
) cf1
;
104 SecCertificatePathRef cp2
= (SecCertificatePathRef
) cf2
;
105 if (cp1
->count
!= cp2
->count
)
108 for (ix
= 0; ix
< cp1
->count
; ++ix
) {
109 if (!CFEqual(cp1
->certificates
[ix
], cp2
->certificates
[ix
]))
112 if (!CFEqual(cp1
->usageConstraints
, cp2
->usageConstraints
))
118 static CFHashCode
SecCertificatePathHash(CFTypeRef cf
) {
119 SecCertificatePathRef certificatePath
= (SecCertificatePathRef
) cf
;
120 CFHashCode hashCode
= 0;
121 // hashCode = 31 * SecCertificatePathGetTypeID();
123 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
124 hashCode
+= CFHash(certificatePath
->certificates
[ix
]);
126 hashCode
+= CFHash(certificatePath
->usageConstraints
);
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
);
139 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
141 CFStringAppend(desc
, CFSTR(", "));
143 CFStringRef str
= CFCopyDescription(certificatePath
->certificates
[ix
]);
144 CFStringAppend(desc
, str
);
147 CFStringAppend(desc
, CFSTR(" >"));
152 /* Create a new certificate path from an old one. */
153 SecCertificatePathRef
SecCertificatePathCreate(SecCertificatePathRef path
,
154 SecCertificateRef certificate
, CFArrayRef usageConstraints
) {
155 CFAllocatorRef allocator
= kCFAllocatorDefault
;
158 CFIndex selfIssued
, lastVerifiedSigner
;
161 count
= path
->count
+ 1;
162 lastVerifiedSigner
= path
->lastVerifiedSigner
;
163 selfIssued
= path
->selfIssued
;
164 isSelfSigned
= path
->isSelfSigned
;
167 lastVerifiedSigner
= 0;
169 isSelfSigned
= false;
172 CFIndex size
= sizeof(struct SecCertificatePath
) +
173 count
* sizeof(SecCertificateRef
);
174 SecCertificatePathRef result
=
175 (SecCertificatePathRef
)_CFRuntimeCreateInstance(allocator
,
176 SecCertificatePathGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
180 result
->count
= count
;
181 result
->nextParentSource
= 0;
182 result
->lastVerifiedSigner
= lastVerifiedSigner
;
183 result
->selfIssued
= selfIssued
;
184 result
->isSelfSigned
= isSelfSigned
;
185 result
->isAnchored
= false;
187 for (ix
= 0; ix
< count
- 1; ++ix
) {
188 result
->certificates
[ix
] = path
->certificates
[ix
];
189 CFRetain(result
->certificates
[ix
]);
191 result
->certificates
[count
- 1] = certificate
;
192 CFRetainSafe(certificate
);
194 CFArrayRef emptyArray
= NULL
;
195 if (!usageConstraints
) {
196 require_action_quiet(emptyArray
= CFArrayCreate(kCFAllocatorDefault
, NULL
, 0, &kCFTypeArrayCallBacks
), exit
, CFReleaseNull(result
));
197 usageConstraints
= emptyArray
;
199 CFMutableArrayRef constraints
;
201 require_action_quiet(constraints
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, count
, path
->usageConstraints
), exit
, CFReleaseNull(result
));
203 require_action_quiet(constraints
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
), exit
, CFReleaseNull(result
));
205 CFArrayAppendValue(constraints
, usageConstraints
);
206 result
->usageConstraints
= constraints
;
209 CFReleaseSafe(emptyArray
);
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")));
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
));
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
;
234 for (ix
= 0; ix
< count
; ++ix
) {
235 SecCertificateRef certificate
= SecCertificateCreateWithXPCArrayAtIndex(xpc_path
, ix
, error
);
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
);
243 result
->count
= ix
; // total allocated
244 CFReleaseNull(result
);
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")));
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
));
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
;
276 for (ix
= 0; ix
< count
; ++ix
) {
277 SecCertificateRef certificate
= SecCertificateCreateWithData(NULL
, CFArrayGetValueAtIndex(certificates
, ix
));
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
);
286 result
->count
= ix
; // total allocated
287 CFReleaseNull(result
);
296 SecCertificatePathRef
SecCertificatePathCopyFromParent(
297 SecCertificatePathRef path
, CFIndex skipCount
) {
298 CFAllocatorRef allocator
= kCFAllocatorDefault
;
300 CFIndex selfIssued
, lastVerifiedSigner
;
303 /* Ensure we are at least returning a path of length 1. */
304 if (skipCount
< 0 || path
->count
< 1 + skipCount
)
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;
314 CFIndex size
= sizeof(struct SecCertificatePath
) +
315 count
* sizeof(SecCertificateRef
);
316 SecCertificatePathRef result
=
317 (SecCertificatePathRef
)_CFRuntimeCreateInstance(allocator
,
318 SecCertificatePathGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
322 CFMutableArrayRef constraints
;
323 require_action_quiet(constraints
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
), exit
, CFReleaseNull(result
));
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
;
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
));
344 SecCertificatePathRef
SecCertificatePathCopyAddingLeaf(SecCertificatePathRef path
,
345 SecCertificateRef leaf
) {
346 CFAllocatorRef allocator
= kCFAllocatorDefault
;
348 CFIndex selfIssued
, lastVerifiedSigner
;
351 /* First make sure the new leaf is signed by path's current leaf. */
352 SecKeyRef issuerKey
= SecCertificatePathCopyPublicKeyAtIndex(path
, 0);
355 OSStatus status
= SecCertificateIsSignedBy(leaf
, issuerKey
);
356 CFRelease(issuerKey
);
360 count
= path
->count
+ 1;
361 lastVerifiedSigner
= path
->lastVerifiedSigner
+ 1;
362 selfIssued
= path
->selfIssued
;
363 isSelfSigned
= path
->isSelfSigned
;
365 CFIndex size
= sizeof(struct SecCertificatePath
) +
366 count
* sizeof(SecCertificateRef
);
367 SecCertificatePathRef result
=
368 (SecCertificatePathRef
)_CFRuntimeCreateInstance(allocator
,
369 SecCertificatePathGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
373 CFMutableArrayRef constraints
;
374 require_action_quiet(constraints
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, count
, path
->usageConstraints
), exit
, CFReleaseNull(result
));
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
;
384 for (ix
= 1; ix
< count
; ++ix
) {
385 result
->certificates
[ix
] = path
->certificates
[ix
- 1];
386 CFRetain(result
->certificates
[ix
]);
388 result
->certificates
[0] = leaf
;
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
);
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
);
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
);
426 CFArrayAppendValue(outCerts
, cert
);
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
);
443 CFArrayAppendValue(serializedCerts
, certData
);
448 return serializedCerts
;
451 /* Record the fact that we found our own root cert as our parent
453 void SecCertificatePathSetSelfIssued(
454 SecCertificatePathRef certificatePath
) {
455 if (certificatePath
->selfIssued
>= 0) {
456 secdebug("trust", "%@ is already issued at %" PRIdCFIndex
, certificatePath
,
457 certificatePath
->selfIssued
);
460 secdebug("trust", "%@ is self issued", certificatePath
);
461 certificatePath
->selfIssued
= certificatePath
->count
- 1;
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;
471 certificatePath
->selfIssued
= -1;
476 void SecCertificatePathSetIsAnchored(
477 SecCertificatePathRef certificatePath
) {
478 secdebug("trust", "%@ is anchored", certificatePath
);
479 certificatePath
->isAnchored
= true;
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;
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
;
508 Boolean
SecCertificatePathIsAnchored(
509 SecCertificatePathRef certificatePath
) {
510 return certificatePath
->isAnchored
;
513 void SecCertificatePathSetNextSourceIndex(
514 SecCertificatePathRef certificatePath
, CFIndex sourceIndex
) {
515 certificatePath
->nextParentSource
= sourceIndex
;
518 CFIndex
SecCertificatePathGetNextSourceIndex(
519 SecCertificatePathRef certificatePath
) {
520 return certificatePath
->nextParentSource
;
523 CFIndex
SecCertificatePathGetCount(
524 SecCertificatePathRef certificatePath
) {
525 check(certificatePath
);
526 return certificatePath
? certificatePath
->count
: 0;
529 SecCertificateRef
SecCertificatePathGetCertificateAtIndex(
530 SecCertificatePathRef certificatePath
, CFIndex ix
) {
531 check(certificatePath
&& ix
>= 0 && ix
< certificatePath
->count
);
532 return certificatePath
->certificates
[ix
];
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
))
546 /* Return the leaf certificate for certificatePath. */
547 SecCertificateRef
SecCertificatePathGetLeaf(
548 SecCertificatePathRef certificatePath
) {
549 return SecCertificatePathGetCertificateAtIndex(certificatePath
, 0);
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);
562 SecKeyRef
SecCertificatePathCopyPublicKeyAtIndex(
563 SecCertificatePathRef certificatePath
, CFIndex ix
) {
564 SecCertificateRef certificate
=
565 SecCertificatePathGetCertificateAtIndex(certificatePath
, ix
);
567 return SecCertificateCopyPublicKey_ios(certificate
);
569 return SecCertificateCopyPublicKey(certificate
);
573 CFArrayRef
SecCertificatePathGetUsageConstraintsAtIndex(
574 SecCertificatePathRef certificatePath
, CFIndex ix
) {
575 return (CFArrayRef
)CFArrayGetValueAtIndex(certificatePath
->usageConstraints
, ix
);
578 SecPathVerifyStatus
SecCertificatePathVerify(
579 SecCertificatePathRef certificatePath
) {
580 check(certificatePath
);
581 if (!certificatePath
)
582 return kSecPathVerifyFailed
;
584 certificatePath
->lastVerifiedSigner
< certificatePath
->count
- 1;
585 ++certificatePath
->lastVerifiedSigner
) {
586 SecKeyRef issuerKey
=
587 SecCertificatePathCopyPublicKeyAtIndex(certificatePath
,
588 certificatePath
->lastVerifiedSigner
+ 1);
590 return kSecPathVerifiesUnknown
;
591 OSStatus status
= SecCertificateIsSignedBy(
592 certificatePath
->certificates
[certificatePath
->lastVerifiedSigner
],
594 CFRelease(issuerKey
);
596 return kSecPathVerifyFailed
;
600 return kSecPathVerifySuccess
;
603 bool SecCertificatePathIsValid(SecCertificatePathRef certificatePath
, CFAbsoluteTime verifyTime
) {
605 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
606 if (!SecCertificateIsValid(certificatePath
->certificates
[ix
],
613 bool SecCertificatePathHasWeakHash(SecCertificatePathRef certificatePath
) {
614 CFIndex ix
, count
= certificatePath
->count
;
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. */
621 for (ix
= 0; ix
< count
; ++ix
) {
622 if (SecCertificateIsWeakHash(certificatePath
->certificates
[ix
])) {
629 bool SecCertificatePathHasWeakKeySize(SecCertificatePathRef certificatePath
) {
630 CFDictionaryRef keySizes
= NULL
;
631 CFNumberRef rsaSize
= NULL
, ecSize
= NULL
;
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
);
643 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
644 if (!SecCertificateIsAtLeastMinKeySize(certificatePath
->certificates
[ix
],
653 CFReleaseSafe(keySizes
);
654 CFReleaseSafe(rsaSize
);
655 CFReleaseSafe(ecSize
);
659 /* Return a score for this certificate chain. */
660 CFIndex
SecCertificatePathScore(
661 SecCertificatePathRef certificatePath
, CFAbsoluteTime verifyTime
) {
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
);
671 if (certificatePath
->isAnchored
) {
672 /* Anchored paths for the win! */
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. */
680 /* Shorter chains ending in a self-signed cert are preferred. */
681 score
-= 1 * certificatePath
->count
;
683 /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */
684 score
+= 1 * certificatePath
->count
;
687 if (SecCertificatePathIsValid(certificatePath
, verifyTime
)) {
691 if (!SecCertificatePathHasWeakHash(certificatePath
)) {
695 if (!SecCertificatePathHasWeakKeySize(certificatePath
)) {