2 * Copyright (c) 2002-2017 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 "SecTrustPriv.h"
28 #include "SecBridge.h"
29 #include "SecInternal.h"
30 #include "SecTrustSettings.h"
31 #include "SecTrustSettingsPriv.h"
32 #include "SecTrustStatusCodes.h"
33 #include "SecCertificatePriv.h"
34 #include "SecCertificateP.h"
35 #include "SecCertificatePrivP.h"
36 #include "SecPolicyPriv.h"
37 #include <security_utilities/cfutilities.h>
38 #include <security_utilities/cfmunge.h>
39 #include <CoreFoundation/CoreFoundation.h>
42 // forward declarations
43 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
);
44 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
);
45 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
);
46 static CSSM_TP_APPLE_EVIDENCE_INFO
* SecTrustGetEvidenceInfo(SecTrustRef trust
);
48 typedef struct SecTrustCheckExceptionContext
{
49 CFDictionaryRef exception
;
50 bool exceptionNotFound
;
51 } SecTrustCheckExceptionContext
;
53 // public trust result constants
54 const CFStringRef kSecTrustEvaluationDate
= CFSTR("TrustEvaluationDate");
55 const CFStringRef kSecTrustExtendedValidation
= CFSTR("TrustExtendedValidation");
56 const CFStringRef kSecTrustOrganizationName
= CFSTR("Organization");
57 const CFStringRef kSecTrustResultValue
= CFSTR("TrustResultValue");
58 const CFStringRef kSecTrustRevocationChecked
= CFSTR("TrustRevocationChecked");
59 const CFStringRef kSecTrustRevocationReason
= CFSTR("TrustRevocationReason");
60 const CFStringRef kSecTrustRevocationValidUntilDate
= CFSTR("TrustExpirationDate");
61 const CFStringRef kSecTrustResultDetails
= CFSTR("TrustResultDetails");
64 // Sec* API bridge functions
66 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
67 OSStatus
SecTrustSetParameters(
69 CSSM_TP_ACTION action
,
72 /* bridge to support API functionality for legacy callers */
74 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
76 CSSM_APPLE_TP_ACTION_DATA
*actionDataPtr
= (CSSM_APPLE_TP_ACTION_DATA
*) CFDataGetBytePtr(actionData
);
78 actionFlags
= actionDataPtr
->ActionFlags
;
81 // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS;
82 // both are sizeof(uint32) and the flag values have identical meanings
83 status
= SecTrustSetOptions(trustRef
, (SecTrustOptionFlags
)actionFlags
);
85 #if SECTRUST_DEPRECATION_WARNINGS
86 syslog(LOG_ERR
, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
92 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
93 OSStatus
SecTrustSetKeychains(SecTrustRef trust
, CFTypeRef keychainOrArray
)
95 /* this function is currently unsupported in unified SecTrust */
96 // TODO: pull all certs out of the specified keychains for the evaluation?
97 #if SECTRUST_DEPRECATION_WARNINGS
98 syslog(LOG_ERR
, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors.");
100 return errSecSuccess
;
104 // Construct the "official" result evidence and return it
106 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
107 OSStatus
SecTrustGetResult(
108 SecTrustRef trustRef
,
109 SecTrustResultType
*result
,
110 CFArrayRef
*certChain
, CSSM_TP_APPLE_EVIDENCE_INFO
**statusChain
)
112 /* bridge to support old functionality */
113 #if SECTRUST_DEPRECATION_WARNINGS
114 syslog(LOG_ERR
, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
116 SecTrustResultType trustResult
;
117 OSStatus status
= SecTrustGetTrustResult(trustRef
, &trustResult
);
118 if (status
!= errSecSuccess
) {
122 *result
= trustResult
;
125 *certChain
= SecTrustCopyConstructedChain(trustRef
);
128 *statusChain
= SecTrustGetEvidenceInfo(trustRef
);
134 // Retrieve extended validation trust results
136 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
137 OSStatus
SecTrustCopyExtendedResult(SecTrustRef trust
, CFDictionaryRef
*result
)
139 /* bridge to support old functionality */
140 #if SECTRUST_DEPRECATION_WARNINGS
141 syslog(LOG_ERR
, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead.");
143 CFDictionaryRef resultDict
= SecTrustCopyResult(trust
);
145 CFReleaseNull(resultDict
);
148 *result
= resultDict
;
149 return errSecSuccess
;
153 // Retrieve CSSM-level information for those who want to dig down
155 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
156 OSStatus
SecTrustGetCssmResult(SecTrustRef trust
, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR
*result
)
158 /* this function is unsupported in unified SecTrust */
159 #if SECTRUST_DEPRECATION_WARNINGS
160 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead.");
165 return errSecServiceNotAvailable
;
168 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode
) {
169 switch (resultCode
) {
170 /* explicitly not trusted */
171 case CSSMERR_TP_CERT_REVOKED
:
172 case CSSMERR_APPLETP_TRUST_SETTING_DENY
:
174 /* failure to comply with X.509 */
175 case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
:
176 case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
:
177 case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
:
178 case CSSMERR_APPLETP_INVALID_AUTHORITY_ID
:
179 case CSSMERR_TP_INVALID_CERTIFICATE
:
180 case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
:
182 case CSSMERR_TP_CERT_EXPIRED
:
184 /* doesn't chain to trusted root */
185 case CSSMERR_TP_NOT_TRUSTED
:
186 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
:
188 /* all others are policy-specific failures */
194 #include <libDER/oidsPriv.h>
195 #include <Security/oidscert.h>
196 static bool isSoftwareUpdateDevelopment(SecTrustRef trust
) {
197 bool isPolicy
= false, isEKU
= false;
198 CFArrayRef policies
= NULL
;
200 /* Policy used to evaluate was SWUpdateSigning */
201 SecTrustCopyPolicies(trust
, &policies
);
203 SecPolicyRef swUpdatePolicy
= SecPolicyCreateAppleSWUpdateSigning();
204 if (swUpdatePolicy
&& CFArrayContainsValue(policies
, CFRangeMake(0, CFArrayGetCount(policies
)),
208 if (swUpdatePolicy
) { CFRelease(swUpdatePolicy
); }
215 /* Only error was EKU on the leaf */
216 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
217 CFIndex ix
, count
= CFArrayGetCount(details
);
218 bool hasDisqualifyingError
= false;
219 for (ix
= 0; ix
< count
; ix
++) {
220 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
221 if (ix
== 0) { // Leaf
222 if (CFDictionaryGetCount(detail
) != 1 || // One error
223 CFDictionaryGetValue(detail
, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse
) { // kSecPolicyCheckExtendedKeyUsage
224 hasDisqualifyingError
= true;
228 if (CFDictionaryGetCount(detail
) > 0) { // No errors on other certs
229 hasDisqualifyingError
= true;
234 CFReleaseSafe(details
);
235 if (hasDisqualifyingError
) {
239 /* EKU on the leaf is the Apple Development Code Signing OID */
240 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
241 CSSM_DATA
*fieldValue
= NULL
;
242 if (errSecSuccess
!= SecCertificateCopyFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, &fieldValue
)) {
245 if (fieldValue
&& fieldValue
->Data
&& fieldValue
->Length
== sizeof(CSSM_X509_EXTENSION
)) {
246 const CSSM_X509_EXTENSION
*ext
= (const CSSM_X509_EXTENSION
*)fieldValue
->Data
;
247 if (ext
->format
== CSSM_X509_DATAFORMAT_PARSED
) {
248 const CE_ExtendedKeyUsage
*ekus
= (const CE_ExtendedKeyUsage
*)ext
->value
.parsedValue
;
249 if (ekus
&& (ekus
->numPurposes
== 1) && ekus
->purposes
[0].Data
&&
250 (ekus
->purposes
[0].Length
== CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Length
) &&
251 (memcmp(ekus
->purposes
[0].Data
, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Data
,
252 ekus
->purposes
[0].Length
) == 0)) {
257 SecCertificateReleaseFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, fieldValue
);
262 // Retrieve CSSM_LEVEL TP return code
264 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
265 OSStatus
SecTrustGetCssmResultCode(SecTrustRef trustRef
, OSStatus
*result
)
267 /* bridge to support old functionality */
268 #if SECTRUST_DEPRECATION_WARNINGS
269 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
271 if (!trustRef
|| !result
) {
275 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
276 (void) SecTrustGetTrustResult(trustRef
, &trustResult
);
277 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
278 if (result
) { *result
= 0; }
279 return errSecSuccess
;
282 /* Development Software Update certs return a special error code when evaluated
283 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
284 if (isSoftwareUpdateDevelopment(trustRef
)) {
286 *result
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
;
288 return errSecSuccess
;
291 OSStatus cssmResultCode
= errSecSuccess
;
292 uint8_t resultCodePriority
= 0xFF;
293 CFIndex ix
, count
= SecTrustGetCertificateCount(trustRef
);
294 for (ix
= 0; ix
< count
; ix
++) {
295 CFIndex numStatusCodes
;
296 CSSM_RETURN
*statusCodes
= NULL
;
297 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trustRef
, ix
, &numStatusCodes
);
298 if (statusCodes
&& numStatusCodes
> 0) {
299 unsigned int statusIX
;
300 for (statusIX
= 0; statusIX
< numStatusCodes
; statusIX
++) {
301 CSSM_RETURN currStatus
= statusCodes
[statusIX
];
302 uint8_t currPriority
= convertCssmResultToPriority(currStatus
);
303 if (resultCodePriority
> currPriority
) {
304 cssmResultCode
= currStatus
;
305 resultCodePriority
= currPriority
;
309 if (statusCodes
) { free(statusCodes
); }
310 if (resultCodePriority
== 1) { break; }
314 *result
= cssmResultCode
;
316 return errSecSuccess
;
319 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
320 OSStatus
SecTrustGetTPHandle(SecTrustRef trust
, CSSM_TP_HANDLE
*handle
)
322 /* this function is unsupported in unified SecTrust */
323 #if SECTRUST_DEPRECATION_WARNINGS
324 syslog(LOG_ERR
, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
329 return errSecServiceNotAvailable
;
333 // Get the user's default anchor certificate set
336 OSStatus
SecTrustCopyAnchorCertificates(CFArrayRef
*anchorCertificates
)
340 OSStatus status
= SecTrustSettingsCopyUnrestrictedRoots(
341 true, true, true, /* all domains */
343 if (status
!= errSecSuccess
) {
346 CFIndex count
= outArray
? CFArrayGetCount(outArray
) : 0;
348 return errSecNoTrustSettings
;
351 /* Go through outArray and do a SecTrustEvaluate */
353 SecPolicyRef policy
= SecPolicyCreateBasicX509();
354 CFMutableArrayRef trustedCertArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
355 for (i
= 0; i
< count
; i
++) {
357 SecTrustResultType result
;
358 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(outArray
, i
);
359 status
= SecTrustCreateWithCertificates(certificate
, policy
, &trust
);
360 if (status
!= errSecSuccess
) {
361 CFReleaseSafe(trustedCertArray
);
364 status
= SecTrustEvaluate(trust
, &result
);
365 if (status
!= errSecSuccess
) {
366 CFReleaseSafe(trustedCertArray
);
369 if (result
!= kSecTrustResultFatalTrustFailure
) {
370 CFArrayAppendValue(trustedCertArray
, certificate
);
373 if (CFArrayGetCount(trustedCertArray
) == 0) {
374 status
= errSecNoTrustSettings
;
375 CFReleaseSafe(trustedCertArray
);
378 *anchorCertificates
= trustedCertArray
;
380 CFReleaseSafe(outArray
);
381 CFReleaseSafe(policy
);
386 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
388 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
390 SecKeyRef pubKey
= NULL
;
391 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, 0);
392 (void) SecCertificateCopyPublicKey(certificate
, &pubKey
);
396 // cannot link against the new iOS SecTrust from this implementation,
397 // so there are no possible accessors for the fields of this struct
398 typedef struct __TSecTrust
{
400 CFArrayRef _certificates
;
403 CFArrayRef _responses
;
405 CFArrayRef _trustedLogs
;
406 CFDateRef _verifyDate
;
408 SecKeyRef _publicKey
;
410 CFDictionaryRef _info
;
411 CFArrayRef _exceptions
;
412 SecTrustResultType _trustResult
;
414 bool _keychainsAllowed
;
415 void* _legacy_info_array
;
416 void* _legacy_status_array
;
417 dispatch_queue_t _trustQueue
;
420 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
)
422 if (!trust
) { return NULL
; };
423 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
424 if (secTrust
->_certificates
) {
425 CFRetain(secTrust
->_certificates
);
427 return secTrust
->_certificates
;
430 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
)
432 if (!trust
) { return NULL
; };
433 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
434 if (secTrust
->_anchors
) {
435 CFRetain(secTrust
->_anchors
);
437 return secTrust
->_anchors
;
440 // Return the constructed certificate chain for this trust reference,
441 // making output certificates pointer-equivalent to any provided input
442 // certificates (where possible) for legacy behavioral compatibility.
443 // Caller must release this array.
445 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
)
447 CFMutableArrayRef certChain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
448 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
449 for (idx
=0; idx
< count
; idx
++) {
450 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, idx
);
452 CFArrayAppendValue(certChain
, certificate
);
456 // Some callers make the assumption that the certificates in
457 // this chain are pointer-equivalent to ones they passed to the
458 // SecTrustCreateWithCertificates function. We'll maintain that
459 // behavior here for compatibility.
461 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
462 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
463 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
464 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
465 for (idx
=0; idx
< count
; idx
++) {
466 SecCertificateRef tmpCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, idx
);
468 SecCertificateRef matchCert
= NULL
;
469 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
&& !matchCert
; inputCertIdx
++) {
470 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
471 if (inputCert
&& CFEqual(inputCert
, tmpCert
)) {
472 matchCert
= inputCert
;
475 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
&& !matchCert
; inputAnchorIdx
++) {
476 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
477 if (inputAnchor
&& CFEqual(inputAnchor
, tmpCert
)) {
478 matchCert
= inputAnchor
;
482 CFArraySetValueAtIndex(certChain
, idx
, matchCert
);
486 if (inputCertArray
) {
487 CFRelease(inputCertArray
);
489 if (inputAnchorArray
) {
490 CFRelease(inputAnchorArray
);
496 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
497 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
498 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
499 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
500 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
501 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
502 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
503 // which would force re-evaluation.
505 static CSSM_TP_APPLE_EVIDENCE_INFO
*
506 SecTrustGetEvidenceInfo(SecTrustRef trust
)
508 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
512 if (secTrust
->_trustResult
!= kSecTrustResultInvalid
&&
513 secTrust
->_legacy_info_array
) {
514 // we've already got valid evidence info, return it now.
515 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
518 // Getting the count implicitly evaluates the chain if necessary.
519 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
520 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
521 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
522 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
523 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
525 CSSM_TP_APPLE_EVIDENCE_INFO
*infoArray
= (CSSM_TP_APPLE_EVIDENCE_INFO
*)calloc(count
, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO
));
526 CSSM_RETURN
*statusArray
= NULL
;
527 CFIndex numStatusCodes
= 0;
529 // Set status codes for each certificate in the constructed chain
530 for (idx
=0; idx
< count
; idx
++) {
531 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, idx
);
535 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
537 /* first the booleans (StatusBits flags) */
538 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
539 if (secTrust
->_verifyDate
) {
540 now
= CFDateGetAbsoluteTime(secTrust
->_verifyDate
);
542 CFAbsoluteTime na
= SecCertificateNotValidAfter(cert
);
544 evInfo
->StatusBits
|= CSSM_CERT_STATUS_EXPIRED
;
546 CFAbsoluteTime nb
= SecCertificateNotValidBefore(cert
);
548 evInfo
->StatusBits
|= CSSM_CERT_STATUS_NOT_VALID_YET
;
550 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
; inputAnchorIdx
++) {
551 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
552 if (inputAnchor
&& CFEqual(inputAnchor
, cert
)) {
553 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_ANCHORS
;
557 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
; inputCertIdx
++) {
558 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
559 if (inputCert
&& CFEqual(inputCert
, cert
)) {
560 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
;
565 /* See if there are trust settings for this certificate. */
566 CFStringRef hashStr
= SecTrustSettingsCertHashStrFromCert(cert
);
567 bool foundMatch
= false;
568 bool foundAny
= false;
569 CSSM_RETURN
*errors
= NULL
;
570 uint32 errorCount
= 0;
572 SecTrustSettingsDomain foundDomain
= kSecTrustSettingsDomainUser
;
573 SecTrustSettingsResult foundResult
= kSecTrustSettingsResultInvalid
;
574 bool isSelfSigned
= false;
575 if ((count
- 1) == idx
) {
576 // Only the last cert in the chain needs to be considered
578 status
= SecCertificateIsSelfSigned(cert
, &selfSigned
);
579 isSelfSigned
= (status
) ? false : ((selfSigned
) ? true : false);
581 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_ROOT
;
584 // STU: rdar://25554967
585 // %%% need to get policyOID, policyString, and keyUsage here!
587 status
= SecTrustSettingsEvaluateCert(
588 hashStr
, /* certHashStr */
589 NULL
, /* policyOID (optional) */
590 NULL
, /* policyString (optional) */
591 0, /* policyStringLen */
593 isSelfSigned
, /* isRootCert */
594 &foundDomain
, /* foundDomain */
595 &errors
, /* allowedErrors -- MUST FREE */
596 &errorCount
, /* numAllowedErrors */
597 &foundResult
, /* resultType */
598 &foundMatch
, /* foundMatchingEntry */
599 &foundAny
); /* foundAnyEntry */
601 if (status
== errSecSuccess
) {
603 switch (foundResult
) {
604 case kSecTrustSettingsResultTrustRoot
:
605 case kSecTrustSettingsResultTrustAsRoot
:
606 /* these two can be disambiguated by IS_ROOT */
607 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
;
609 case kSecTrustSettingsResultDeny
:
610 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
;
612 case kSecTrustSettingsResultUnspecified
:
613 case kSecTrustSettingsResultInvalid
:
627 CSSM_RETURN
*statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, idx
, &numCodes
);
629 // Realloc space for these status codes at end of our status codes block.
630 // Two important things to note:
631 // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes
632 // allocates one more element at the end for the CrlReason value.
633 // 2. realloc may cause the pointer to move, which means we will
634 // need to fix up the StatusCodes fields after we're done with this loop.
635 CFIndex totalStatusCodes
= numStatusCodes
+ numCodes
+ 1;
636 statusArray
= (CSSM_RETURN
*)realloc(statusArray
, totalStatusCodes
* sizeof(CSSM_RETURN
));
637 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
638 evInfo
->NumStatusCodes
= (uint32
)numCodes
;
639 // Copy the new codes (plus one) into place
640 for (unsigned int cpix
= 0; cpix
<= numCodes
; cpix
++) {
641 evInfo
->StatusCodes
[cpix
] = statusCodes
[cpix
];
643 numStatusCodes
= totalStatusCodes
;
647 if(evInfo
->StatusBits
& (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
|
648 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
|
649 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR
)) {
650 /* Something noteworthy happened involving TrustSettings */
651 uint32 whichDomain
= 0;
652 switch(foundDomain
) {
653 case kSecTrustSettingsDomainUser
:
654 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
;
656 case kSecTrustSettingsDomainAdmin
:
657 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
;
659 case kSecTrustSettingsDomainSystem
:
660 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
;
663 evInfo
->StatusBits
|= whichDomain
;
666 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
667 //evInfo->Index = certInfo->index();
668 /* nonzero if cert came from a DLDB */
669 //evInfo->DlDbHandle = certInfo->dlDbHandle();
670 //evInfo->UniqueRecord = certInfo->uniqueRecord();
673 // Now that all the status codes have been allocated in a contiguous block,
674 // refresh the StatusCodes pointer in each array element.
676 for (idx
=0; idx
< count
; idx
++) {
677 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
678 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
679 numStatusCodes
+= evInfo
->NumStatusCodes
+ 1;
682 secTrust
->_legacy_info_array
= infoArray
;
683 secTrust
->_legacy_status_array
= statusArray
;
685 if (inputCertArray
) {
686 CFRelease(inputCertArray
);
688 if (inputAnchorArray
) {
689 CFRelease(inputAnchorArray
);
692 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
695 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
) {
696 /* OS X creates a completely different structure with one dictionary for each certificate */
697 CFIndex ix
, count
= SecTrustGetCertificateCount(trust
);
699 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, count
,
700 &kCFTypeArrayCallBacks
);
702 for (ix
= 0; ix
< count
; ix
++) {
703 CFMutableDictionaryRef certDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
704 &kCFTypeDictionaryValueCallBacks
);
705 /* Populate the certificate title */
706 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, ix
);
708 CFStringRef subjectSummary
= SecCertificateCopySubjectSummary(cert
);
709 if (subjectSummary
) {
710 CFDictionaryAddValue(certDict
, kSecPropertyTypeTitle
, subjectSummary
);
711 CFRelease(subjectSummary
);
715 /* Populate a revocation reason if the cert was revoked */
716 CFIndex numStatusCodes
;
717 CSSM_RETURN
*statusCodes
= NULL
;
718 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, ix
, &numStatusCodes
);
720 SInt32 reason
= statusCodes
[numStatusCodes
]; // stored at end of status codes array
722 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
724 CFDictionarySetValue(certDict
, kSecTrustRevocationReason
, cfreason
);
731 /* Populate the error in the leaf dictionary */
733 OSStatus error
= errSecSuccess
;
734 (void)SecTrustGetCssmResultCode(trust
, &error
);
735 CFStringRef errorStr
= SecCopyErrorMessageString(error
, NULL
);
737 CFDictionarySetValue(certDict
, kSecPropertyTypeError
, errorStr
);
742 CFArrayAppendValue(properties
, certDict
);
749 /* deprecated in 10.5 */
750 OSStatus
SecTrustGetCSSMAnchorCertificates(const CSSM_DATA
**cssmAnchors
,
751 uint32
*cssmAnchorCount
)
753 /* this function is unsupported in unified SecTrust */
754 #if SECTRUST_DEPRECATION_WARNINGS
755 syslog(LOG_ERR
, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
760 if (cssmAnchorCount
) {
761 *cssmAnchorCount
= 0;
763 return errSecServiceNotAvailable
;
768 // Get and set user trust settings. Deprecated in 10.5.
769 // User Trust getter, deprecated, works as it always has.
771 OSStatus
SecTrustGetUserTrust(SecCertificateRef certificate
,
772 SecPolicyRef policy
, SecTrustUserSetting
*trustSetting
)
774 /* this function is unsupported in unified SecTrust */
775 #if SECTRUST_DEPRECATION_WARNINGS
776 syslog(LOG_ERR
, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
778 return errSecServiceNotAvailable
;
782 // The public setter, also deprecated; it maps to the appropriate
783 // Trust Settings call if possible, else throws errSecUnimplemented.
785 OSStatus
SecTrustSetUserTrust(SecCertificateRef certificate
,
786 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
788 /* this function is unsupported in unified SecTrust */
789 #if SECTRUST_DEPRECATION_WARNINGS
790 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
792 return errSecServiceNotAvailable
;
796 // This one is the now-private version of what SecTrustSetUserTrust() used to
797 // be. The public API can no longer manipulate User Trust settings, only
800 OSStatus
SecTrustSetUserTrustLegacy(SecCertificateRef certificate
,
801 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
803 /* this function is unsupported in unified SecTrust */
804 #if SECTRUST_DEPRECATION_WARNINGS
805 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
807 return errSecServiceNotAvailable
;