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@
24 #include <libDER/oids.h>
25 #include <Security/oidscert.h>
28 #include "SecTrustPriv.h"
31 #include "SecBridge.h"
32 #include "SecInternal.h"
33 #include "SecTrustSettings.h"
34 #include "SecTrustSettingsPriv.h"
35 #include "SecTrustStatusCodes.h"
36 #include "SecCertificatePriv.h"
37 #include "SecPolicyPriv.h"
38 #include <security_utilities/cfutilities.h>
39 #include <security_utilities/cfmunge.h>
40 #include <CoreFoundation/CoreFoundation.h>
43 // forward declarations
44 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
);
45 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
);
46 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
);
47 static CSSM_TP_APPLE_EVIDENCE_INFO
* SecTrustGetEvidenceInfo(SecTrustRef trust
);
49 typedef struct SecTrustCheckExceptionContext
{
50 CFDictionaryRef exception
;
51 bool exceptionNotFound
;
52 } SecTrustCheckExceptionContext
;
54 // public trust result constants
55 const CFStringRef kSecTrustEvaluationDate
= CFSTR("TrustEvaluationDate");
56 const CFStringRef kSecTrustExtendedValidation
= CFSTR("TrustExtendedValidation");
57 const CFStringRef kSecTrustOrganizationName
= CFSTR("Organization");
58 const CFStringRef kSecTrustResultValue
= CFSTR("TrustResultValue");
59 const CFStringRef kSecTrustRevocationChecked
= CFSTR("TrustRevocationChecked");
60 const CFStringRef kSecTrustRevocationReason
= CFSTR("TrustRevocationReason");
61 const CFStringRef kSecTrustRevocationValidUntilDate
= CFSTR("TrustExpirationDate");
62 const CFStringRef kSecTrustResultDetails
= CFSTR("TrustResultDetails");
65 // Sec* API bridge functions
67 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
68 OSStatus
SecTrustSetParameters(
70 CSSM_TP_ACTION action
,
73 /* bridge to support API functionality for legacy callers */
75 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
77 CSSM_APPLE_TP_ACTION_DATA
*actionDataPtr
= (CSSM_APPLE_TP_ACTION_DATA
*) CFDataGetBytePtr(actionData
);
79 actionFlags
= actionDataPtr
->ActionFlags
;
82 // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS;
83 // both are sizeof(uint32) and the flag values have identical meanings
84 status
= SecTrustSetOptions(trustRef
, (SecTrustOptionFlags
)actionFlags
);
86 #if SECTRUST_DEPRECATION_WARNINGS
87 syslog(LOG_ERR
, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
93 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
94 OSStatus
SecTrustSetKeychains(SecTrustRef trust
, CFTypeRef keychainOrArray
)
96 /* this function is currently unsupported in unified SecTrust */
97 // TODO: pull all certs out of the specified keychains for the evaluation?
98 #if SECTRUST_DEPRECATION_WARNINGS
99 syslog(LOG_ERR
, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors.");
101 return errSecSuccess
;
105 // Construct the "official" result evidence and return it
107 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
108 OSStatus
SecTrustGetResult(
109 SecTrustRef trustRef
,
110 SecTrustResultType
*result
,
111 CFArrayRef
*certChain
, CSSM_TP_APPLE_EVIDENCE_INFO
**statusChain
)
113 /* bridge to support old functionality */
114 #if SECTRUST_DEPRECATION_WARNINGS
115 syslog(LOG_ERR
, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
117 SecTrustResultType trustResult
;
118 OSStatus status
= SecTrustGetTrustResult(trustRef
, &trustResult
);
119 if (status
!= errSecSuccess
) {
123 *result
= trustResult
;
126 *certChain
= SecTrustCopyConstructedChain(trustRef
);
129 *statusChain
= SecTrustGetEvidenceInfo(trustRef
);
135 // Retrieve extended validation trust results
137 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
138 OSStatus
SecTrustCopyExtendedResult(SecTrustRef trust
, CFDictionaryRef
*result
)
140 /* bridge to support old functionality */
141 #if SECTRUST_DEPRECATION_WARNINGS
142 syslog(LOG_ERR
, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead.");
144 CFDictionaryRef resultDict
= SecTrustCopyResult(trust
);
146 CFReleaseNull(resultDict
);
149 *result
= resultDict
;
150 return errSecSuccess
;
154 // Retrieve CSSM-level information for those who want to dig down
156 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
157 OSStatus
SecTrustGetCssmResult(SecTrustRef trust
, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR
*result
)
159 /* this function is unsupported in unified SecTrust */
160 #if SECTRUST_DEPRECATION_WARNINGS
161 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead.");
166 return errSecServiceNotAvailable
;
169 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode
) {
170 switch (resultCode
) {
171 /* explicitly not trusted */
172 case CSSMERR_TP_CERT_REVOKED
:
173 case CSSMERR_APPLETP_TRUST_SETTING_DENY
:
175 /* failure to comply with X.509 */
176 case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
:
177 case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
:
178 case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
:
179 case CSSMERR_APPLETP_INVALID_AUTHORITY_ID
:
180 case CSSMERR_TP_INVALID_CERTIFICATE
:
181 case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
:
183 case CSSMERR_TP_CERT_EXPIRED
:
185 /* doesn't chain to trusted root */
186 case CSSMERR_TP_NOT_TRUSTED
:
187 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
:
189 /* all others are policy-specific failures */
195 static bool isSoftwareUpdateDevelopment(SecTrustRef trust
) {
196 bool isPolicy
= false, isEKU
= false;
197 CFArrayRef policies
= NULL
;
199 /* Policy used to evaluate was SWUpdateSigning */
200 SecTrustCopyPolicies(trust
, &policies
);
202 SecPolicyRef swUpdatePolicy
= SecPolicyCreateAppleSWUpdateSigning();
203 if (swUpdatePolicy
&& CFArrayContainsValue(policies
, CFRangeMake(0, CFArrayGetCount(policies
)),
207 if (swUpdatePolicy
) { CFRelease(swUpdatePolicy
); }
214 /* Only error was EKU on the leaf */
215 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
216 CFIndex ix
, count
= CFArrayGetCount(details
);
217 bool hasDisqualifyingError
= false;
218 for (ix
= 0; ix
< count
; ix
++) {
219 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
220 if (ix
== 0) { // Leaf
221 if (CFDictionaryGetCount(detail
) != 1 || // One error
222 CFDictionaryGetValue(detail
, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse
) { // kSecPolicyCheckExtendedKeyUsage
223 hasDisqualifyingError
= true;
227 if (CFDictionaryGetCount(detail
) > 0) { // No errors on other certs
228 hasDisqualifyingError
= true;
233 CFReleaseSafe(details
);
234 if (hasDisqualifyingError
) {
238 /* EKU on the leaf is the Apple Development Code Signing OID */
239 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
240 CSSM_DATA
*fieldValue
= NULL
;
241 if (errSecSuccess
!= SecCertificateCopyFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, &fieldValue
)) {
244 if (fieldValue
&& fieldValue
->Data
&& fieldValue
->Length
== sizeof(CSSM_X509_EXTENSION
)) {
245 const CSSM_X509_EXTENSION
*ext
= (const CSSM_X509_EXTENSION
*)fieldValue
->Data
;
246 if (ext
->format
== CSSM_X509_DATAFORMAT_PARSED
) {
247 const CE_ExtendedKeyUsage
*ekus
= (const CE_ExtendedKeyUsage
*)ext
->value
.parsedValue
;
248 if (ekus
&& (ekus
->numPurposes
== 1) && ekus
->purposes
[0].Data
&&
249 (ekus
->purposes
[0].Length
== CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Length
) &&
250 (memcmp(ekus
->purposes
[0].Data
, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Data
,
251 ekus
->purposes
[0].Length
) == 0)) {
256 SecCertificateReleaseFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, fieldValue
);
261 // Retrieve CSSM_LEVEL TP return code
263 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
264 OSStatus
SecTrustGetCssmResultCode(SecTrustRef trustRef
, OSStatus
*result
)
266 /* bridge to support old functionality */
267 #if SECTRUST_DEPRECATION_WARNINGS
268 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
270 if (!trustRef
|| !result
) {
274 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
275 (void) SecTrustGetTrustResult(trustRef
, &trustResult
);
276 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
277 if (result
) { *result
= 0; }
278 return errSecSuccess
;
281 /* Development Software Update certs return a special error code when evaluated
282 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
283 if (isSoftwareUpdateDevelopment(trustRef
)) {
285 *result
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
;
287 return errSecSuccess
;
290 OSStatus cssmResultCode
= errSecSuccess
;
291 uint8_t resultCodePriority
= 0xFF;
292 CFIndex ix
, count
= SecTrustGetCertificateCount(trustRef
);
293 for (ix
= 0; ix
< count
; ix
++) {
294 CFIndex numStatusCodes
;
295 CSSM_RETURN
*statusCodes
= NULL
;
296 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trustRef
, ix
, &numStatusCodes
);
297 if (statusCodes
&& numStatusCodes
> 0) {
298 unsigned int statusIX
;
299 for (statusIX
= 0; statusIX
< numStatusCodes
; statusIX
++) {
300 CSSM_RETURN currStatus
= statusCodes
[statusIX
];
301 uint8_t currPriority
= convertCssmResultToPriority(currStatus
);
302 if (resultCodePriority
> currPriority
) {
303 cssmResultCode
= currStatus
;
304 resultCodePriority
= currPriority
;
308 if (statusCodes
) { free(statusCodes
); }
309 if (resultCodePriority
== 1) { break; }
313 *result
= cssmResultCode
;
315 return errSecSuccess
;
318 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
319 OSStatus
SecTrustGetTPHandle(SecTrustRef trust
, CSSM_TP_HANDLE
*handle
)
321 /* this function is unsupported in unified SecTrust */
322 #if SECTRUST_DEPRECATION_WARNINGS
323 syslog(LOG_ERR
, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
328 return errSecServiceNotAvailable
;
332 // Get the user's default anchor certificate set
335 OSStatus
SecTrustCopyAnchorCertificates(CFArrayRef
*anchorCertificates
)
339 OSStatus status
= SecTrustSettingsCopyUnrestrictedRoots(
340 true, true, true, /* all domains */
342 if (status
!= errSecSuccess
) {
345 CFIndex count
= outArray
? CFArrayGetCount(outArray
) : 0;
347 return errSecNoTrustSettings
;
350 /* Go through outArray and do a SecTrustEvaluate */
352 SecPolicyRef policy
= SecPolicyCreateBasicX509();
353 CFMutableArrayRef trustedCertArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
354 for (i
= 0; i
< count
; i
++) {
356 SecTrustResultType result
;
357 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(outArray
, i
);
358 status
= SecTrustCreateWithCertificates(certificate
, policy
, &trust
);
359 if (status
!= errSecSuccess
) {
360 CFReleaseSafe(trustedCertArray
);
363 status
= SecTrustEvaluate(trust
, &result
);
364 if (status
!= errSecSuccess
) {
365 CFReleaseSafe(trustedCertArray
);
368 if (result
!= kSecTrustResultFatalTrustFailure
) {
369 CFArrayAppendValue(trustedCertArray
, certificate
);
372 if (CFArrayGetCount(trustedCertArray
) == 0) {
373 status
= errSecNoTrustSettings
;
374 CFReleaseSafe(trustedCertArray
);
377 *anchorCertificates
= trustedCertArray
;
379 CFReleaseSafe(outArray
);
380 CFReleaseSafe(policy
);
385 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
387 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
389 SecKeyRef pubKey
= NULL
;
390 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, 0);
391 (void) SecCertificateCopyPublicKey(certificate
, &pubKey
);
395 // cannot link against the new iOS SecTrust from this implementation,
396 // so there are no possible accessors for the fields of this struct
397 typedef struct __TSecTrust
{
399 CFArrayRef _certificates
;
402 CFArrayRef _responses
;
404 CFArrayRef _trustedLogs
;
405 CFDateRef _verifyDate
;
407 SecKeyRef _publicKey
;
409 CFDictionaryRef _info
;
410 CFArrayRef _exceptions
;
411 SecTrustResultType _trustResult
;
413 bool _keychainsAllowed
;
414 void* _legacy_info_array
;
415 void* _legacy_status_array
;
416 dispatch_queue_t _trustQueue
;
419 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
)
421 if (!trust
) { return NULL
; };
422 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
423 if (secTrust
->_certificates
) {
424 CFRetain(secTrust
->_certificates
);
426 return secTrust
->_certificates
;
429 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
)
431 if (!trust
) { return NULL
; };
432 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
433 if (secTrust
->_anchors
) {
434 CFRetain(secTrust
->_anchors
);
436 return secTrust
->_anchors
;
439 // Return the constructed certificate chain for this trust reference,
440 // making output certificates pointer-equivalent to any provided input
441 // certificates (where possible) for legacy behavioral compatibility.
442 // Caller must release this array.
444 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
)
446 CFMutableArrayRef certChain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
447 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
448 for (idx
=0; idx
< count
; idx
++) {
449 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, idx
);
451 CFArrayAppendValue(certChain
, certificate
);
455 // Some callers make the assumption that the certificates in
456 // this chain are pointer-equivalent to ones they passed to the
457 // SecTrustCreateWithCertificates function. We'll maintain that
458 // behavior here for compatibility.
460 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
461 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
462 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
463 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
464 for (idx
=0; idx
< count
; idx
++) {
465 SecCertificateRef tmpCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, idx
);
467 SecCertificateRef matchCert
= NULL
;
468 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
&& !matchCert
; inputCertIdx
++) {
469 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
470 if (inputCert
&& CFEqual(inputCert
, tmpCert
)) {
471 matchCert
= inputCert
;
474 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
&& !matchCert
; inputAnchorIdx
++) {
475 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
476 if (inputAnchor
&& CFEqual(inputAnchor
, tmpCert
)) {
477 matchCert
= inputAnchor
;
481 CFArraySetValueAtIndex(certChain
, idx
, matchCert
);
485 if (inputCertArray
) {
486 CFRelease(inputCertArray
);
488 if (inputAnchorArray
) {
489 CFRelease(inputAnchorArray
);
495 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
496 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
497 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
498 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
499 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
500 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
501 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
502 // which would force re-evaluation.
504 static CSSM_TP_APPLE_EVIDENCE_INFO
*
505 SecTrustGetEvidenceInfo(SecTrustRef trust
)
507 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
511 if (secTrust
->_trustResult
!= kSecTrustResultInvalid
&&
512 secTrust
->_legacy_info_array
) {
513 // we've already got valid evidence info, return it now.
514 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
517 // Getting the count implicitly evaluates the chain if necessary.
518 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
519 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
520 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
521 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
522 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
524 CSSM_TP_APPLE_EVIDENCE_INFO
*infoArray
= (CSSM_TP_APPLE_EVIDENCE_INFO
*)calloc(count
, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO
));
525 CSSM_RETURN
*statusArray
= NULL
;
526 CFIndex numStatusCodes
= 0;
528 // Set status codes for each certificate in the constructed chain
529 for (idx
=0; idx
< count
; idx
++) {
530 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, idx
);
534 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
536 /* first the booleans (StatusBits flags) */
537 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
538 if (secTrust
->_verifyDate
) {
539 now
= CFDateGetAbsoluteTime(secTrust
->_verifyDate
);
541 CFAbsoluteTime na
= SecCertificateNotValidAfter(cert
);
543 evInfo
->StatusBits
|= CSSM_CERT_STATUS_EXPIRED
;
545 CFAbsoluteTime nb
= SecCertificateNotValidBefore(cert
);
547 evInfo
->StatusBits
|= CSSM_CERT_STATUS_NOT_VALID_YET
;
549 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
; inputAnchorIdx
++) {
550 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
551 if (inputAnchor
&& CFEqual(inputAnchor
, cert
)) {
552 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_ANCHORS
;
556 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
; inputCertIdx
++) {
557 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
558 if (inputCert
&& CFEqual(inputCert
, cert
)) {
559 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
;
564 /* See if there are trust settings for this certificate. */
565 CFStringRef hashStr
= SecTrustSettingsCertHashStrFromCert(cert
);
566 bool foundMatch
= false;
567 bool foundAny
= false;
568 CSSM_RETURN
*errors
= NULL
;
569 uint32 errorCount
= 0;
571 SecTrustSettingsDomain foundDomain
= kSecTrustSettingsDomainUser
;
572 SecTrustSettingsResult foundResult
= kSecTrustSettingsResultInvalid
;
573 bool isSelfSigned
= false;
574 if ((count
- 1) == idx
) {
575 // Only the last cert in the chain needs to be considered
577 status
= SecCertificateIsSelfSigned(cert
, &selfSigned
);
578 isSelfSigned
= (status
) ? false : ((selfSigned
) ? true : false);
580 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_ROOT
;
583 // STU: rdar://25554967
584 // %%% need to get policyOID, policyString, and keyUsage here!
586 status
= SecTrustSettingsEvaluateCert(
587 hashStr
, /* certHashStr */
588 NULL
, /* policyOID (optional) */
589 NULL
, /* policyString (optional) */
590 0, /* policyStringLen */
592 isSelfSigned
, /* isRootCert */
593 &foundDomain
, /* foundDomain */
594 &errors
, /* allowedErrors -- MUST FREE */
595 &errorCount
, /* numAllowedErrors */
596 &foundResult
, /* resultType */
597 &foundMatch
, /* foundMatchingEntry */
598 &foundAny
); /* foundAnyEntry */
600 if (status
== errSecSuccess
) {
602 switch (foundResult
) {
603 case kSecTrustSettingsResultTrustRoot
:
604 case kSecTrustSettingsResultTrustAsRoot
:
605 /* these two can be disambiguated by IS_ROOT */
606 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
;
608 case kSecTrustSettingsResultDeny
:
609 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
;
611 case kSecTrustSettingsResultUnspecified
:
612 case kSecTrustSettingsResultInvalid
:
626 CSSM_RETURN
*statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, idx
, &numCodes
);
628 // Realloc space for these status codes at end of our status codes block.
629 // Two important things to note:
630 // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes
631 // allocates one more element at the end for the CrlReason value.
632 // 2. realloc may cause the pointer to move, which means we will
633 // need to fix up the StatusCodes fields after we're done with this loop.
634 CFIndex totalStatusCodes
= numStatusCodes
+ numCodes
+ 1;
635 statusArray
= (CSSM_RETURN
*)realloc(statusArray
, totalStatusCodes
* sizeof(CSSM_RETURN
));
636 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
637 evInfo
->NumStatusCodes
= (uint32
)numCodes
;
638 // Copy the new codes (plus one) into place
639 for (unsigned int cpix
= 0; cpix
<= numCodes
; cpix
++) {
640 evInfo
->StatusCodes
[cpix
] = statusCodes
[cpix
];
642 numStatusCodes
= totalStatusCodes
;
646 if(evInfo
->StatusBits
& (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
|
647 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
|
648 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR
)) {
649 /* Something noteworthy happened involving TrustSettings */
650 uint32 whichDomain
= 0;
651 switch(foundDomain
) {
652 case kSecTrustSettingsDomainUser
:
653 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
;
655 case kSecTrustSettingsDomainAdmin
:
656 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
;
658 case kSecTrustSettingsDomainSystem
:
659 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
;
662 evInfo
->StatusBits
|= whichDomain
;
665 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
666 //evInfo->Index = certInfo->index();
667 /* nonzero if cert came from a DLDB */
668 //evInfo->DlDbHandle = certInfo->dlDbHandle();
669 //evInfo->UniqueRecord = certInfo->uniqueRecord();
672 // Now that all the status codes have been allocated in a contiguous block,
673 // refresh the StatusCodes pointer in each array element.
675 for (idx
=0; idx
< count
; idx
++) {
676 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
677 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
678 numStatusCodes
+= evInfo
->NumStatusCodes
+ 1;
681 secTrust
->_legacy_info_array
= infoArray
;
682 secTrust
->_legacy_status_array
= statusArray
;
684 if (inputCertArray
) {
685 CFRelease(inputCertArray
);
687 if (inputAnchorArray
) {
688 CFRelease(inputAnchorArray
);
691 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
694 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
) {
695 /* OS X creates a completely different structure with one dictionary for each certificate */
696 CFIndex ix
, count
= SecTrustGetCertificateCount(trust
);
698 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, count
,
699 &kCFTypeArrayCallBacks
);
701 for (ix
= 0; ix
< count
; ix
++) {
702 CFMutableDictionaryRef certDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
703 &kCFTypeDictionaryValueCallBacks
);
704 /* Populate the certificate title */
705 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, ix
);
707 CFStringRef subjectSummary
= SecCertificateCopySubjectSummary(cert
);
708 if (subjectSummary
) {
709 CFDictionaryAddValue(certDict
, kSecPropertyTypeTitle
, subjectSummary
);
710 CFRelease(subjectSummary
);
714 /* Populate a revocation reason if the cert was revoked */
715 CFIndex numStatusCodes
;
716 CSSM_RETURN
*statusCodes
= NULL
;
717 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, ix
, &numStatusCodes
);
719 SInt32 reason
= statusCodes
[numStatusCodes
]; // stored at end of status codes array
721 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
723 CFDictionarySetValue(certDict
, kSecTrustRevocationReason
, cfreason
);
730 /* Populate the error in the leaf dictionary */
732 OSStatus error
= errSecSuccess
;
733 (void)SecTrustGetCssmResultCode(trust
, &error
);
734 CFStringRef errorStr
= SecCopyErrorMessageString(error
, NULL
);
736 CFDictionarySetValue(certDict
, kSecPropertyTypeError
, errorStr
);
741 CFArrayAppendValue(properties
, certDict
);
748 /* deprecated in 10.5 */
749 OSStatus
SecTrustGetCSSMAnchorCertificates(const CSSM_DATA
**cssmAnchors
,
750 uint32
*cssmAnchorCount
)
752 /* this function is unsupported in unified SecTrust */
753 #if SECTRUST_DEPRECATION_WARNINGS
754 syslog(LOG_ERR
, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
759 if (cssmAnchorCount
) {
760 *cssmAnchorCount
= 0;
762 return errSecServiceNotAvailable
;
767 // Get and set user trust settings. Deprecated in 10.5.
768 // User Trust getter, deprecated, works as it always has.
770 OSStatus
SecTrustGetUserTrust(SecCertificateRef certificate
,
771 SecPolicyRef policy
, SecTrustUserSetting
*trustSetting
)
773 /* this function is unsupported in unified SecTrust */
774 #if SECTRUST_DEPRECATION_WARNINGS
775 syslog(LOG_ERR
, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
777 return errSecServiceNotAvailable
;
781 // The public setter, also deprecated; it maps to the appropriate
782 // Trust Settings call if possible, else throws errSecUnimplemented.
784 OSStatus
SecTrustSetUserTrust(SecCertificateRef certificate
,
785 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
787 /* this function is unsupported in unified SecTrust */
788 #if SECTRUST_DEPRECATION_WARNINGS
789 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
791 return errSecServiceNotAvailable
;
795 // This one is the now-private version of what SecTrustSetUserTrust() used to
796 // be. The public API can no longer manipulate User Trust settings, only
799 OSStatus
SecTrustSetUserTrustLegacy(SecCertificateRef certificate
,
800 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
802 /* this function is unsupported in unified SecTrust */
803 #if SECTRUST_DEPRECATION_WARNINGS
804 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
806 return errSecServiceNotAvailable
;