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 "SecPolicyPriv.h"
35 #include <security_utilities/cfutilities.h>
36 #include <security_utilities/cfmunge.h>
37 #include <CoreFoundation/CoreFoundation.h>
40 // forward declarations
41 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
);
42 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
);
43 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
);
44 static CSSM_TP_APPLE_EVIDENCE_INFO
* SecTrustGetEvidenceInfo(SecTrustRef trust
);
46 typedef struct SecTrustCheckExceptionContext
{
47 CFDictionaryRef exception
;
48 bool exceptionNotFound
;
49 } SecTrustCheckExceptionContext
;
51 // public trust result constants
52 const CFStringRef kSecTrustEvaluationDate
= CFSTR("TrustEvaluationDate");
53 const CFStringRef kSecTrustExtendedValidation
= CFSTR("TrustExtendedValidation");
54 const CFStringRef kSecTrustOrganizationName
= CFSTR("Organization");
55 const CFStringRef kSecTrustResultValue
= CFSTR("TrustResultValue");
56 const CFStringRef kSecTrustRevocationChecked
= CFSTR("TrustRevocationChecked");
57 const CFStringRef kSecTrustRevocationReason
= CFSTR("TrustRevocationReason");
58 const CFStringRef kSecTrustRevocationValidUntilDate
= CFSTR("TrustExpirationDate");
59 const CFStringRef kSecTrustResultDetails
= CFSTR("TrustResultDetails");
62 // Sec* API bridge functions
64 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
65 OSStatus
SecTrustSetParameters(
67 CSSM_TP_ACTION action
,
70 /* bridge to support API functionality for legacy callers */
72 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
74 CSSM_APPLE_TP_ACTION_DATA
*actionDataPtr
= (CSSM_APPLE_TP_ACTION_DATA
*) CFDataGetBytePtr(actionData
);
76 actionFlags
= actionDataPtr
->ActionFlags
;
79 // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS;
80 // both are sizeof(uint32) and the flag values have identical meanings
81 status
= SecTrustSetOptions(trustRef
, (SecTrustOptionFlags
)actionFlags
);
83 #if SECTRUST_DEPRECATION_WARNINGS
84 syslog(LOG_ERR
, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
90 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
91 OSStatus
SecTrustSetKeychains(SecTrustRef trust
, CFTypeRef keychainOrArray
)
93 /* this function is currently unsupported in unified SecTrust */
94 // TODO: pull all certs out of the specified keychains for the evaluation?
95 #if SECTRUST_DEPRECATION_WARNINGS
96 syslog(LOG_ERR
, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors.");
102 // Construct the "official" result evidence and return it
104 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
105 OSStatus
SecTrustGetResult(
106 SecTrustRef trustRef
,
107 SecTrustResultType
*result
,
108 CFArrayRef
*certChain
, CSSM_TP_APPLE_EVIDENCE_INFO
**statusChain
)
110 /* bridge to support old functionality */
111 #if SECTRUST_DEPRECATION_WARNINGS
112 syslog(LOG_ERR
, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
114 SecTrustResultType trustResult
;
115 OSStatus status
= SecTrustGetTrustResult(trustRef
, &trustResult
);
116 if (status
!= errSecSuccess
) {
120 *result
= trustResult
;
123 *certChain
= SecTrustCopyConstructedChain(trustRef
);
126 *statusChain
= SecTrustGetEvidenceInfo(trustRef
);
132 // Retrieve extended validation trust results
134 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
135 OSStatus
SecTrustCopyExtendedResult(SecTrustRef trust
, CFDictionaryRef
*result
)
137 /* bridge to support old functionality */
138 #if SECTRUST_DEPRECATION_WARNINGS
139 syslog(LOG_ERR
, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead.");
141 CFDictionaryRef resultDict
= SecTrustCopyResult(trust
);
143 CFReleaseNull(resultDict
);
146 *result
= resultDict
;
147 return errSecSuccess
;
151 // Retrieve CSSM-level information for those who want to dig down
153 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
154 OSStatus
SecTrustGetCssmResult(SecTrustRef trust
, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR
*result
)
156 /* this function is unsupported in unified SecTrust */
157 #if SECTRUST_DEPRECATION_WARNINGS
158 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead.");
163 return errSecServiceNotAvailable
;
166 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode
) {
167 switch (resultCode
) {
168 /* explicitly not trusted */
169 case CSSMERR_TP_CERT_REVOKED
:
170 case CSSMERR_APPLETP_TRUST_SETTING_DENY
:
172 /* failure to comply with X.509 */
173 case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
:
174 case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
:
175 case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
:
176 case CSSMERR_APPLETP_INVALID_AUTHORITY_ID
:
177 case CSSMERR_TP_INVALID_CERTIFICATE
:
178 case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
:
180 case CSSMERR_TP_CERT_EXPIRED
:
182 /* doesn't chain to trusted root */
183 case CSSMERR_TP_NOT_TRUSTED
:
184 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
:
186 /* all others are policy-specific failures */
192 #include <libDER/oidsPriv.h>
193 #include <Security/oidscert.h>
194 static bool isSoftwareUpdateDevelopment(SecTrustRef trust
) {
195 bool isPolicy
= false, isEKU
= false;
196 CFArrayRef policies
= NULL
;
198 /* Policy used to evaluate was SWUpdateSigning */
199 SecTrustCopyPolicies(trust
, &policies
);
201 SecPolicyRef swUpdatePolicy
= SecPolicyCreateAppleSWUpdateSigning();
202 if (swUpdatePolicy
&& CFArrayContainsValue(policies
, CFRangeMake(0, CFArrayGetCount(policies
)),
206 if (swUpdatePolicy
) { CFRelease(swUpdatePolicy
); }
213 /* Only error was EKU on the leaf */
214 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
215 CFIndex ix
, count
= CFArrayGetCount(details
);
216 bool hasDisqualifyingError
= false;
217 for (ix
= 0; ix
< count
; ix
++) {
218 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
219 if (ix
== 0) { // Leaf
220 if (CFDictionaryGetCount(detail
) != 1 || // One error
221 CFDictionaryGetValue(detail
, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse
) { // kSecPolicyCheckExtendedKeyUsage
222 hasDisqualifyingError
= true;
226 if (CFDictionaryGetCount(detail
) > 0) { // No errors on other certs
227 hasDisqualifyingError
= true;
232 CFReleaseSafe(details
);
233 if (hasDisqualifyingError
) {
237 /* EKU on the leaf is the Apple Development Code Signing OID */
238 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
239 CSSM_DATA
*fieldValue
= NULL
;
240 if (errSecSuccess
!= SecCertificateCopyFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, &fieldValue
)) {
243 if (fieldValue
&& fieldValue
->Data
&& fieldValue
->Length
== sizeof(CSSM_X509_EXTENSION
)) {
244 const CSSM_X509_EXTENSION
*ext
= (const CSSM_X509_EXTENSION
*)fieldValue
->Data
;
245 if (ext
->format
== CSSM_X509_DATAFORMAT_PARSED
) {
246 const CE_ExtendedKeyUsage
*ekus
= (const CE_ExtendedKeyUsage
*)ext
->value
.parsedValue
;
247 if (ekus
&& (ekus
->numPurposes
== 1) && ekus
->purposes
[0].Data
&&
248 (ekus
->purposes
[0].Length
== CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Length
) &&
249 (memcmp(ekus
->purposes
[0].Data
, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Data
,
250 ekus
->purposes
[0].Length
) == 0)) {
255 SecCertificateReleaseFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, fieldValue
);
260 // Retrieve CSSM_LEVEL TP return code
262 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
263 OSStatus
SecTrustGetCssmResultCode(SecTrustRef trustRef
, OSStatus
*result
)
265 /* bridge to support old functionality */
266 #if SECTRUST_DEPRECATION_WARNINGS
267 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
269 if (!trustRef
|| !result
) {
273 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
274 (void) SecTrustGetTrustResult(trustRef
, &trustResult
);
275 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
276 if (result
) { *result
= 0; }
277 return errSecSuccess
;
280 /* Development Software Update certs return a special error code when evaluated
281 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
282 if (isSoftwareUpdateDevelopment(trustRef
)) {
284 *result
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
;
286 return errSecSuccess
;
289 OSStatus cssmResultCode
= errSecSuccess
;
290 uint8_t resultCodePriority
= 0xFF;
291 CFIndex ix
, count
= SecTrustGetCertificateCount(trustRef
);
292 for (ix
= 0; ix
< count
; ix
++) {
293 CFIndex numStatusCodes
;
294 CSSM_RETURN
*statusCodes
= NULL
;
295 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trustRef
, ix
, &numStatusCodes
);
296 if (statusCodes
&& numStatusCodes
> 0) {
297 unsigned int statusIX
;
298 for (statusIX
= 0; statusIX
< numStatusCodes
; statusIX
++) {
299 CSSM_RETURN currStatus
= statusCodes
[statusIX
];
300 uint8_t currPriority
= convertCssmResultToPriority(currStatus
);
301 if (resultCodePriority
> currPriority
) {
302 cssmResultCode
= currStatus
;
303 resultCodePriority
= currPriority
;
307 if (statusCodes
) { free(statusCodes
); }
308 if (resultCodePriority
== 1) { break; }
312 *result
= cssmResultCode
;
314 return errSecSuccess
;
317 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
318 OSStatus
SecTrustGetTPHandle(SecTrustRef trust
, CSSM_TP_HANDLE
*handle
)
320 /* this function is unsupported in unified SecTrust */
321 #if SECTRUST_DEPRECATION_WARNINGS
322 syslog(LOG_ERR
, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
327 return errSecServiceNotAvailable
;
331 // Get the user's default anchor certificate set
334 OSStatus
SecTrustCopyAnchorCertificates(CFArrayRef
*anchorCertificates
)
338 OSStatus status
= SecTrustSettingsCopyUnrestrictedRoots(
339 true, true, true, /* all domains */
341 if (status
!= errSecSuccess
) {
344 CFIndex count
= outArray
? CFArrayGetCount(outArray
) : 0;
346 return errSecNoTrustSettings
;
349 /* Go through outArray and do a SecTrustEvaluate */
351 SecPolicyRef policy
= SecPolicyCreateBasicX509();
352 CFMutableArrayRef trustedCertArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
353 for (i
= 0; i
< count
; i
++) {
355 SecTrustResultType result
;
356 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(outArray
, i
);
357 status
= SecTrustCreateWithCertificates(certificate
, policy
, &trust
);
358 if (status
!= errSecSuccess
) {
359 CFReleaseSafe(trustedCertArray
);
362 status
= SecTrustEvaluate(trust
, &result
);
363 if (status
!= errSecSuccess
) {
364 CFReleaseSafe(trustedCertArray
);
367 if (result
!= kSecTrustResultFatalTrustFailure
) {
368 CFArrayAppendValue(trustedCertArray
, certificate
);
371 if (CFArrayGetCount(trustedCertArray
) == 0) {
372 status
= errSecNoTrustSettings
;
373 CFReleaseSafe(trustedCertArray
);
376 *anchorCertificates
= trustedCertArray
;
378 CFReleaseSafe(outArray
);
379 CFReleaseSafe(policy
);
384 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
386 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
388 SecKeyRef pubKey
= NULL
;
389 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, 0);
390 (void) SecCertificateCopyPublicKey(certificate
, &pubKey
);
394 // cannot link against the new iOS SecTrust from this implementation,
395 // so there are no possible accessors for the fields of this struct
396 typedef struct __TSecTrust
{
398 CFArrayRef _certificates
;
401 CFArrayRef _responses
;
403 CFArrayRef _trustedLogs
;
404 CFDateRef _verifyDate
;
406 SecKeyRef _publicKey
;
408 CFDictionaryRef _info
;
409 CFArrayRef _exceptions
;
410 SecTrustResultType _trustResult
;
412 bool _keychainsAllowed
;
413 void* _legacy_info_array
;
414 void* _legacy_status_array
;
415 dispatch_queue_t _trustQueue
;
418 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
)
420 if (!trust
) { return NULL
; };
421 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
422 if (secTrust
->_certificates
) {
423 CFRetain(secTrust
->_certificates
);
425 return secTrust
->_certificates
;
428 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
)
430 if (!trust
) { return NULL
; };
431 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
432 if (secTrust
->_anchors
) {
433 CFRetain(secTrust
->_anchors
);
435 return secTrust
->_anchors
;
438 // Return the constructed certificate chain for this trust reference,
439 // making output certificates pointer-equivalent to any provided input
440 // certificates (where possible) for legacy behavioral compatibility.
441 // Caller must release this array.
443 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
)
445 CFMutableArrayRef certChain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
446 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
447 for (idx
=0; idx
< count
; idx
++) {
448 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, idx
);
450 CFArrayAppendValue(certChain
, certificate
);
454 // Some callers make the assumption that the certificates in
455 // this chain are pointer-equivalent to ones they passed to the
456 // SecTrustCreateWithCertificates function. We'll maintain that
457 // behavior here for compatibility.
459 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
460 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
461 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
462 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
463 for (idx
=0; idx
< count
; idx
++) {
464 SecCertificateRef tmpCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, idx
);
466 SecCertificateRef matchCert
= NULL
;
467 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
&& !matchCert
; inputCertIdx
++) {
468 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
469 if (inputCert
&& CFEqual(inputCert
, tmpCert
)) {
470 matchCert
= inputCert
;
473 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
&& !matchCert
; inputAnchorIdx
++) {
474 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
475 if (inputAnchor
&& CFEqual(inputAnchor
, tmpCert
)) {
476 matchCert
= inputAnchor
;
480 CFArraySetValueAtIndex(certChain
, idx
, matchCert
);
484 if (inputCertArray
) {
485 CFRelease(inputCertArray
);
487 if (inputAnchorArray
) {
488 CFRelease(inputAnchorArray
);
494 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
495 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
496 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
497 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
498 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
499 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
500 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
501 // which would force re-evaluation.
503 static CSSM_TP_APPLE_EVIDENCE_INFO
*
504 SecTrustGetEvidenceInfo(SecTrustRef trust
)
506 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
510 if (secTrust
->_trustResult
!= kSecTrustResultInvalid
&&
511 secTrust
->_legacy_info_array
) {
512 // we've already got valid evidence info, return it now.
513 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
516 // Getting the count implicitly evaluates the chain if necessary.
517 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
518 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
519 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
520 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
521 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
523 CSSM_TP_APPLE_EVIDENCE_INFO
*infoArray
= (CSSM_TP_APPLE_EVIDENCE_INFO
*)calloc(count
, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO
));
524 CSSM_RETURN
*statusArray
= NULL
;
525 CFIndex numStatusCodes
= 0;
527 // Set status codes for each certificate in the constructed chain
528 for (idx
=0; idx
< count
; idx
++) {
529 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, idx
);
533 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
535 /* first the booleans (StatusBits flags) */
536 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
537 if (secTrust
->_verifyDate
) {
538 now
= CFDateGetAbsoluteTime(secTrust
->_verifyDate
);
540 CFAbsoluteTime na
= SecCertificateNotValidAfter(cert
);
542 evInfo
->StatusBits
|= CSSM_CERT_STATUS_EXPIRED
;
544 CFAbsoluteTime nb
= SecCertificateNotValidBefore(cert
);
546 evInfo
->StatusBits
|= CSSM_CERT_STATUS_NOT_VALID_YET
;
548 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
; inputAnchorIdx
++) {
549 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
550 if (inputAnchor
&& CFEqual(inputAnchor
, cert
)) {
551 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_ANCHORS
;
555 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
; inputCertIdx
++) {
556 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
557 if (inputCert
&& CFEqual(inputCert
, cert
)) {
558 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
;
563 /* See if there are trust settings for this certificate. */
564 CFStringRef hashStr
= SecTrustSettingsCertHashStrFromCert(cert
);
565 bool foundMatch
= false;
566 bool foundAny
= false;
567 CSSM_RETURN
*errors
= NULL
;
568 uint32 errorCount
= 0;
570 SecTrustSettingsDomain foundDomain
= kSecTrustSettingsDomainUser
;
571 SecTrustSettingsResult foundResult
= kSecTrustSettingsResultInvalid
;
572 bool isSelfSigned
= false;
573 if ((count
- 1) == idx
) {
574 // Only the last cert in the chain needs to be considered
576 status
= SecCertificateIsSelfSigned(cert
, &selfSigned
);
577 isSelfSigned
= (status
) ? false : ((selfSigned
) ? true : false);
579 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_ROOT
;
582 // STU: rdar://25554967
583 // %%% need to get policyOID, policyString, and keyUsage here!
585 status
= SecTrustSettingsEvaluateCert(
586 hashStr
, /* certHashStr */
587 NULL
, /* policyOID (optional) */
588 NULL
, /* policyString (optional) */
589 0, /* policyStringLen */
591 isSelfSigned
, /* isRootCert */
592 &foundDomain
, /* foundDomain */
593 &errors
, /* allowedErrors -- MUST FREE */
594 &errorCount
, /* numAllowedErrors */
595 &foundResult
, /* resultType */
596 &foundMatch
, /* foundMatchingEntry */
597 &foundAny
); /* foundAnyEntry */
599 if (status
== errSecSuccess
) {
601 switch (foundResult
) {
602 case kSecTrustSettingsResultTrustRoot
:
603 case kSecTrustSettingsResultTrustAsRoot
:
604 /* these two can be disambiguated by IS_ROOT */
605 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
;
607 case kSecTrustSettingsResultDeny
:
608 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
;
610 case kSecTrustSettingsResultUnspecified
:
611 case kSecTrustSettingsResultInvalid
:
625 CSSM_RETURN
*statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, idx
, &numCodes
);
627 // Realloc space for these status codes at end of our status codes block.
628 // Two important things to note:
629 // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes
630 // allocates one more element at the end for the CrlReason value.
631 // 2. realloc may cause the pointer to move, which means we will
632 // need to fix up the StatusCodes fields after we're done with this loop.
633 CFIndex totalStatusCodes
= numStatusCodes
+ numCodes
+ 1;
634 statusArray
= (CSSM_RETURN
*)realloc(statusArray
, totalStatusCodes
* sizeof(CSSM_RETURN
));
635 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
636 evInfo
->NumStatusCodes
= (uint32
)numCodes
;
637 // Copy the new codes (plus one) into place
638 for (unsigned int cpix
= 0; cpix
<= numCodes
; cpix
++) {
639 evInfo
->StatusCodes
[cpix
] = statusCodes
[cpix
];
641 numStatusCodes
= totalStatusCodes
;
645 if(evInfo
->StatusBits
& (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
|
646 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
|
647 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR
)) {
648 /* Something noteworthy happened involving TrustSettings */
649 uint32 whichDomain
= 0;
650 switch(foundDomain
) {
651 case kSecTrustSettingsDomainUser
:
652 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
;
654 case kSecTrustSettingsDomainAdmin
:
655 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
;
657 case kSecTrustSettingsDomainSystem
:
658 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
;
661 evInfo
->StatusBits
|= whichDomain
;
664 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
665 //evInfo->Index = certInfo->index();
666 /* nonzero if cert came from a DLDB */
667 //evInfo->DlDbHandle = certInfo->dlDbHandle();
668 //evInfo->UniqueRecord = certInfo->uniqueRecord();
671 // Now that all the status codes have been allocated in a contiguous block,
672 // refresh the StatusCodes pointer in each array element.
674 for (idx
=0; idx
< count
; idx
++) {
675 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
676 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
677 numStatusCodes
+= evInfo
->NumStatusCodes
+ 1;
680 secTrust
->_legacy_info_array
= infoArray
;
681 secTrust
->_legacy_status_array
= statusArray
;
683 if (inputCertArray
) {
684 CFRelease(inputCertArray
);
686 if (inputAnchorArray
) {
687 CFRelease(inputAnchorArray
);
690 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
693 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
) {
694 /* OS X creates a completely different structure with one dictionary for each certificate */
695 CFIndex ix
, count
= SecTrustGetCertificateCount(trust
);
697 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, count
,
698 &kCFTypeArrayCallBacks
);
700 for (ix
= 0; ix
< count
; ix
++) {
701 CFMutableDictionaryRef certDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
702 &kCFTypeDictionaryValueCallBacks
);
703 /* Populate the certificate title */
704 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, ix
);
706 CFStringRef subjectSummary
= SecCertificateCopySubjectSummary(cert
);
707 if (subjectSummary
) {
708 CFDictionaryAddValue(certDict
, kSecPropertyTypeTitle
, subjectSummary
);
709 CFRelease(subjectSummary
);
713 /* Populate a revocation reason if the cert was revoked */
714 CFIndex numStatusCodes
;
715 CSSM_RETURN
*statusCodes
= NULL
;
716 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, ix
, &numStatusCodes
);
718 SInt32 reason
= statusCodes
[numStatusCodes
]; // stored at end of status codes array
720 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
722 CFDictionarySetValue(certDict
, kSecTrustRevocationReason
, cfreason
);
729 /* Populate the error in the leaf dictionary */
731 OSStatus error
= errSecSuccess
;
732 (void)SecTrustGetCssmResultCode(trust
, &error
);
733 CFStringRef errorStr
= SecCopyErrorMessageString(error
, NULL
);
735 CFDictionarySetValue(certDict
, kSecPropertyTypeError
, errorStr
);
740 CFArrayAppendValue(properties
, certDict
);
747 /* deprecated in 10.5 */
748 OSStatus
SecTrustGetCSSMAnchorCertificates(const CSSM_DATA
**cssmAnchors
,
749 uint32
*cssmAnchorCount
)
751 /* this function is unsupported in unified SecTrust */
752 #if SECTRUST_DEPRECATION_WARNINGS
753 syslog(LOG_ERR
, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
758 if (cssmAnchorCount
) {
759 *cssmAnchorCount
= 0;
761 return errSecServiceNotAvailable
;
766 // Get and set user trust settings. Deprecated in 10.5.
767 // User Trust getter, deprecated, works as it always has.
769 OSStatus
SecTrustGetUserTrust(SecCertificateRef certificate
,
770 SecPolicyRef policy
, SecTrustUserSetting
*trustSetting
)
772 /* this function is unsupported in unified SecTrust */
773 #if SECTRUST_DEPRECATION_WARNINGS
774 syslog(LOG_ERR
, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
776 return errSecServiceNotAvailable
;
780 // The public setter, also deprecated; it maps to the appropriate
781 // Trust Settings call if possible, else throws errSecUnimplemented.
783 OSStatus
SecTrustSetUserTrust(SecCertificateRef certificate
,
784 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
786 /* this function is unsupported in unified SecTrust */
787 #if SECTRUST_DEPRECATION_WARNINGS
788 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
790 return errSecServiceNotAvailable
;
794 // This one is the now-private version of what SecTrustSetUserTrust() used to
795 // be. The public API can no longer manipulate User Trust settings, only
798 OSStatus
SecTrustSetUserTrustLegacy(SecCertificateRef certificate
,
799 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
801 /* this function is unsupported in unified SecTrust */
802 #if SECTRUST_DEPRECATION_WARNINGS
803 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
805 return errSecServiceNotAvailable
;