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
;
55 // Sec* API bridge functions
57 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
58 OSStatus
SecTrustSetParameters(
60 CSSM_TP_ACTION action
,
63 /* bridge to support API functionality for legacy callers */
65 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
67 CSSM_APPLE_TP_ACTION_DATA
*actionDataPtr
= (CSSM_APPLE_TP_ACTION_DATA
*) CFDataGetBytePtr(actionData
);
69 actionFlags
= actionDataPtr
->ActionFlags
;
72 // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS;
73 // both are sizeof(uint32) and the flag values have identical meanings
74 status
= SecTrustSetOptions(trustRef
, (SecTrustOptionFlags
)actionFlags
);
76 #if SECTRUST_DEPRECATION_WARNINGS
77 syslog(LOG_ERR
, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
83 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
84 OSStatus
SecTrustSetKeychains(SecTrustRef trust
, CFTypeRef keychainOrArray
)
86 /* this function is currently unsupported in unified SecTrust */
87 // TODO: pull all certs out of the specified keychains for the evaluation?
88 #if SECTRUST_DEPRECATION_WARNINGS
89 syslog(LOG_ERR
, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors.");
95 // Construct the "official" result evidence and return it
97 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
98 OSStatus
SecTrustGetResult(
100 SecTrustResultType
*result
,
101 CFArrayRef
*certChain
, CSSM_TP_APPLE_EVIDENCE_INFO
**statusChain
)
103 /* bridge to support old functionality */
104 #if SECTRUST_DEPRECATION_WARNINGS
105 syslog(LOG_ERR
, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
107 SecTrustResultType trustResult
;
108 OSStatus status
= SecTrustGetTrustResult(trustRef
, &trustResult
);
109 if (status
!= errSecSuccess
) {
113 *result
= trustResult
;
116 *certChain
= SecTrustCopyConstructedChain(trustRef
);
119 *statusChain
= SecTrustGetEvidenceInfo(trustRef
);
125 // Retrieve extended validation trust results
127 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
128 OSStatus
SecTrustCopyExtendedResult(SecTrustRef trust
, CFDictionaryRef
*result
)
130 /* bridge to support old functionality */
131 #if SECTRUST_DEPRECATION_WARNINGS
132 syslog(LOG_ERR
, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead.");
134 CFDictionaryRef resultDict
= SecTrustCopyResult(trust
);
136 CFReleaseNull(resultDict
);
139 *result
= resultDict
;
140 return errSecSuccess
;
144 // Retrieve CSSM-level information for those who want to dig down
146 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
147 OSStatus
SecTrustGetCssmResult(SecTrustRef trust
, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR
*result
)
149 /* this function is unsupported in unified SecTrust */
150 #if SECTRUST_DEPRECATION_WARNINGS
151 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead.");
156 return errSecServiceNotAvailable
;
159 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode
) {
160 switch (resultCode
) {
161 /* explicitly not trusted */
162 case CSSMERR_TP_CERT_REVOKED
:
163 case CSSMERR_APPLETP_TRUST_SETTING_DENY
:
165 /* failure to comply with X.509 */
166 case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
:
167 case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
:
168 case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
:
169 case CSSMERR_APPLETP_INVALID_AUTHORITY_ID
:
170 case CSSMERR_TP_INVALID_CERTIFICATE
:
171 case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
:
173 case CSSMERR_TP_CERT_EXPIRED
:
175 /* doesn't chain to trusted root */
176 case CSSMERR_TP_NOT_TRUSTED
:
177 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
:
179 /* all others are policy-specific failures */
185 static bool isSoftwareUpdateDevelopment(SecTrustRef trust
) {
186 bool isPolicy
= false, isEKU
= false;
187 CFArrayRef policies
= NULL
;
189 /* Policy used to evaluate was SWUpdateSigning */
190 SecTrustCopyPolicies(trust
, &policies
);
192 SecPolicyRef swUpdatePolicy
= SecPolicyCreateAppleSWUpdateSigning();
193 if (swUpdatePolicy
&& CFArrayContainsValue(policies
, CFRangeMake(0, CFArrayGetCount(policies
)),
197 if (swUpdatePolicy
) { CFRelease(swUpdatePolicy
); }
204 /* Only error was EKU on the leaf */
205 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
206 CFIndex ix
, count
= CFArrayGetCount(details
);
207 bool hasDisqualifyingError
= false;
208 for (ix
= 0; ix
< count
; ix
++) {
209 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
210 if (ix
== 0) { // Leaf
211 if (CFDictionaryGetCount(detail
) != 1 || // One error
212 CFDictionaryGetValue(detail
, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse
) { // kSecPolicyCheckExtendedKeyUsage
213 hasDisqualifyingError
= true;
217 if (CFDictionaryGetCount(detail
) > 0) { // No errors on other certs
218 hasDisqualifyingError
= true;
223 CFReleaseSafe(details
);
224 if (hasDisqualifyingError
) {
228 /* EKU on the leaf is the Apple Development Code Signing OID */
229 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
230 CSSM_DATA
*fieldValue
= NULL
;
231 if (errSecSuccess
!= SecCertificateCopyFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, &fieldValue
)) {
234 if (fieldValue
&& fieldValue
->Data
&& fieldValue
->Length
== sizeof(CSSM_X509_EXTENSION
)) {
235 const CSSM_X509_EXTENSION
*ext
= (const CSSM_X509_EXTENSION
*)fieldValue
->Data
;
236 if (ext
->format
== CSSM_X509_DATAFORMAT_PARSED
) {
237 const CE_ExtendedKeyUsage
*ekus
= (const CE_ExtendedKeyUsage
*)ext
->value
.parsedValue
;
238 if (ekus
&& (ekus
->numPurposes
== 1) && ekus
->purposes
[0].Data
&&
239 (ekus
->purposes
[0].Length
== CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Length
) &&
240 (memcmp(ekus
->purposes
[0].Data
, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Data
,
241 ekus
->purposes
[0].Length
) == 0)) {
246 SecCertificateReleaseFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, fieldValue
);
251 // Retrieve CSSM_LEVEL TP return code
253 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
254 OSStatus
SecTrustGetCssmResultCode(SecTrustRef trustRef
, OSStatus
*result
)
256 /* bridge to support old functionality */
257 #if SECTRUST_DEPRECATION_WARNINGS
258 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
260 if (!trustRef
|| !result
) {
264 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
265 (void) SecTrustGetTrustResult(trustRef
, &trustResult
);
266 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
267 if (result
) { *result
= 0; }
268 return errSecSuccess
;
271 /* Development Software Update certs return a special error code when evaluated
272 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
273 if (isSoftwareUpdateDevelopment(trustRef
)) {
275 *result
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
;
277 return errSecSuccess
;
280 OSStatus cssmResultCode
= errSecSuccess
;
281 uint8_t resultCodePriority
= 0xFF;
282 CFIndex ix
, count
= SecTrustGetCertificateCount(trustRef
);
283 for (ix
= 0; ix
< count
; ix
++) {
284 CFIndex numStatusCodes
;
285 CSSM_RETURN
*statusCodes
= NULL
;
286 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trustRef
, ix
, &numStatusCodes
);
287 if (statusCodes
&& numStatusCodes
> 0) {
288 unsigned int statusIX
;
289 for (statusIX
= 0; statusIX
< numStatusCodes
; statusIX
++) {
290 CSSM_RETURN currStatus
= statusCodes
[statusIX
];
291 uint8_t currPriority
= convertCssmResultToPriority(currStatus
);
292 if (resultCodePriority
> currPriority
) {
293 cssmResultCode
= currStatus
;
294 resultCodePriority
= currPriority
;
298 if (statusCodes
) { free(statusCodes
); }
299 if (resultCodePriority
== 1) { break; }
303 *result
= cssmResultCode
;
305 return errSecSuccess
;
308 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
309 OSStatus
SecTrustGetTPHandle(SecTrustRef trust
, CSSM_TP_HANDLE
*handle
)
311 /* this function is unsupported in unified SecTrust */
312 #if SECTRUST_DEPRECATION_WARNINGS
313 syslog(LOG_ERR
, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
318 return errSecServiceNotAvailable
;
322 // Get the user's default anchor certificate set
325 OSStatus
SecTrustCopyAnchorCertificates(CFArrayRef
*anchorCertificates
)
329 OSStatus status
= SecTrustSettingsCopyUnrestrictedRoots(
330 true, true, true, /* all domains */
332 if (status
!= errSecSuccess
) {
335 CFIndex count
= outArray
? CFArrayGetCount(outArray
) : 0;
337 return errSecNoTrustSettings
;
340 /* Go through outArray and do a SecTrustEvaluate */
342 SecPolicyRef policy
= SecPolicyCreateBasicX509();
343 SecTrustRef trust
= NULL
;
344 CFMutableArrayRef trustedCertArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
345 for (i
= 0; i
< count
; i
++) {
346 SecTrustResultType result
;
347 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(outArray
, i
);
348 status
= SecTrustCreateWithCertificates(certificate
, policy
, &trust
);
349 if (status
!= errSecSuccess
) {
350 CFReleaseSafe(trustedCertArray
);
353 status
= SecTrustEvaluate(trust
, &result
);
354 if (status
!= errSecSuccess
) {
355 CFReleaseSafe(trustedCertArray
);
358 if (result
!= kSecTrustResultFatalTrustFailure
) {
359 CFArrayAppendValue(trustedCertArray
, certificate
);
361 CFReleaseNull(trust
);
363 if (CFArrayGetCount(trustedCertArray
) == 0) {
364 status
= errSecNoTrustSettings
;
365 CFReleaseSafe(trustedCertArray
);
368 *anchorCertificates
= trustedCertArray
;
370 CFReleaseSafe(outArray
);
371 CFReleaseSafe(policy
);
372 CFReleaseSafe(trust
);
377 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
379 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
381 SecKeyRef pubKey
= NULL
;
382 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, 0);
383 #pragma clang diagnostic push
384 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
385 (void) SecCertificateCopyPublicKey(certificate
, &pubKey
);
386 #pragma clang diagnostic pop
390 // cannot link against the new iOS SecTrust from this implementation,
391 // so there are no possible accessors for the fields of this struct
392 typedef struct __TSecTrust
{
394 CFArrayRef _certificates
;
397 CFArrayRef _responses
;
399 CFArrayRef _trustedLogs
;
400 CFDateRef _verifyDate
;
402 SecKeyRef _publicKey
;
404 CFDictionaryRef _info
;
405 CFArrayRef _exceptions
;
406 SecTrustResultType _trustResult
;
408 bool _keychainsAllowed
;
409 void* _legacy_info_array
;
410 void* _legacy_status_array
;
411 dispatch_queue_t _trustQueue
;
414 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
)
416 if (!trust
) { return NULL
; };
417 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
418 if (secTrust
->_certificates
) {
419 CFRetain(secTrust
->_certificates
);
421 return secTrust
->_certificates
;
424 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
)
426 if (!trust
) { return NULL
; };
427 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
428 if (secTrust
->_anchors
) {
429 CFRetain(secTrust
->_anchors
);
431 return secTrust
->_anchors
;
434 // Return the constructed certificate chain for this trust reference,
435 // making output certificates pointer-equivalent to any provided input
436 // certificates (where possible) for legacy behavioral compatibility.
437 // Caller must release this array.
439 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
)
441 CFMutableArrayRef certChain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
442 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
443 for (idx
=0; idx
< count
; idx
++) {
444 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, idx
);
446 CFArrayAppendValue(certChain
, certificate
);
450 // Some callers make the assumption that the certificates in
451 // this chain are pointer-equivalent to ones they passed to the
452 // SecTrustCreateWithCertificates function. We'll maintain that
453 // behavior here for compatibility.
455 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
456 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
457 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
458 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
459 for (idx
=0; idx
< count
; idx
++) {
460 SecCertificateRef tmpCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, idx
);
462 SecCertificateRef matchCert
= NULL
;
463 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
&& !matchCert
; inputCertIdx
++) {
464 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
465 if (inputCert
&& CFEqual(inputCert
, tmpCert
)) {
466 matchCert
= inputCert
;
469 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
&& !matchCert
; inputAnchorIdx
++) {
470 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
471 if (inputAnchor
&& CFEqual(inputAnchor
, tmpCert
)) {
472 matchCert
= inputAnchor
;
476 CFArraySetValueAtIndex(certChain
, idx
, matchCert
);
480 if (inputCertArray
) {
481 CFRelease(inputCertArray
);
483 if (inputAnchorArray
) {
484 CFRelease(inputAnchorArray
);
490 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
491 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
492 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
493 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
494 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
495 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
496 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
497 // which would force re-evaluation.
499 static CSSM_TP_APPLE_EVIDENCE_INFO
*
500 SecTrustGetEvidenceInfo(SecTrustRef trust
)
502 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
506 if (secTrust
->_trustResult
!= kSecTrustResultInvalid
&&
507 secTrust
->_legacy_info_array
) {
508 // we've already got valid evidence info, return it now.
509 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
512 // Getting the count implicitly evaluates the chain if necessary.
513 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
514 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
515 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
516 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
517 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
519 CSSM_TP_APPLE_EVIDENCE_INFO
*infoArray
= (CSSM_TP_APPLE_EVIDENCE_INFO
*)calloc(count
, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO
));
520 CSSM_RETURN
*statusArray
= NULL
;
521 CFIndex numStatusCodes
= 0;
523 // Set status codes for each certificate in the constructed chain
524 for (idx
=0; idx
< count
; idx
++) {
525 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, idx
);
529 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
531 /* first the booleans (StatusBits flags) */
532 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
533 if (secTrust
->_verifyDate
) {
534 now
= CFDateGetAbsoluteTime(secTrust
->_verifyDate
);
536 CFAbsoluteTime na
= SecCertificateNotValidAfter(cert
);
538 evInfo
->StatusBits
|= CSSM_CERT_STATUS_EXPIRED
;
540 CFAbsoluteTime nb
= SecCertificateNotValidBefore(cert
);
542 evInfo
->StatusBits
|= CSSM_CERT_STATUS_NOT_VALID_YET
;
544 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
; inputAnchorIdx
++) {
545 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
546 if (inputAnchor
&& CFEqual(inputAnchor
, cert
)) {
547 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_ANCHORS
;
551 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
; inputCertIdx
++) {
552 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
553 if (inputCert
&& CFEqual(inputCert
, cert
)) {
554 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
;
559 /* See if there are trust settings for this certificate. */
560 CFStringRef hashStr
= SecTrustSettingsCertHashStrFromCert(cert
);
561 bool foundMatch
= false;
562 bool foundAny
= false;
563 CSSM_RETURN
*errors
= NULL
;
564 uint32 errorCount
= 0;
566 SecTrustSettingsDomain foundDomain
= kSecTrustSettingsDomainUser
;
567 SecTrustSettingsResult foundResult
= kSecTrustSettingsResultInvalid
;
568 bool isSelfSigned
= false;
569 if ((count
- 1) == idx
) {
570 // Only the last cert in the chain needs to be considered
572 status
= SecCertificateIsSelfSigned(cert
, &selfSigned
);
573 isSelfSigned
= (status
) ? false : ((selfSigned
) ? true : false);
575 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_ROOT
;
578 // STU: rdar://25554967
579 // %%% need to get policyOID, policyString, and keyUsage here!
581 status
= SecTrustSettingsEvaluateCert(
582 hashStr
, /* certHashStr */
583 NULL
, /* policyOID (optional) */
584 NULL
, /* policyString (optional) */
585 0, /* policyStringLen */
587 isSelfSigned
, /* isRootCert */
588 &foundDomain
, /* foundDomain */
589 &errors
, /* allowedErrors -- MUST FREE */
590 &errorCount
, /* numAllowedErrors */
591 &foundResult
, /* resultType */
592 &foundMatch
, /* foundMatchingEntry */
593 &foundAny
); /* foundAnyEntry */
595 if (status
== errSecSuccess
) {
597 switch (foundResult
) {
598 case kSecTrustSettingsResultTrustRoot
:
599 case kSecTrustSettingsResultTrustAsRoot
:
600 /* these two can be disambiguated by IS_ROOT */
601 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
;
603 case kSecTrustSettingsResultDeny
:
604 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
;
606 case kSecTrustSettingsResultUnspecified
:
607 case kSecTrustSettingsResultInvalid
:
621 CSSM_RETURN
*statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, idx
, &numCodes
);
623 // Realloc space for these status codes at end of our status codes block.
624 // Two important things to note:
625 // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes
626 // allocates one more element at the end for the CrlReason value.
627 // 2. realloc may cause the pointer to move, which means we will
628 // need to fix up the StatusCodes fields after we're done with this loop.
629 CFIndex totalStatusCodes
= numStatusCodes
+ numCodes
+ 1;
630 statusArray
= (CSSM_RETURN
*)realloc(statusArray
, totalStatusCodes
* sizeof(CSSM_RETURN
));
631 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
632 evInfo
->NumStatusCodes
= (uint32
)numCodes
;
633 // Copy the new codes (plus one) into place
634 for (unsigned int cpix
= 0; cpix
<= numCodes
; cpix
++) {
635 evInfo
->StatusCodes
[cpix
] = statusCodes
[cpix
];
637 numStatusCodes
= totalStatusCodes
;
641 if(evInfo
->StatusBits
& (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
|
642 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
|
643 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR
)) {
644 /* Something noteworthy happened involving TrustSettings */
645 uint32 whichDomain
= 0;
646 switch(foundDomain
) {
647 case kSecTrustSettingsDomainUser
:
648 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
;
650 case kSecTrustSettingsDomainAdmin
:
651 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
;
653 case kSecTrustSettingsDomainSystem
:
654 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
;
657 evInfo
->StatusBits
|= whichDomain
;
660 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
661 //evInfo->Index = certInfo->index();
662 /* nonzero if cert came from a DLDB */
663 //evInfo->DlDbHandle = certInfo->dlDbHandle();
664 //evInfo->UniqueRecord = certInfo->uniqueRecord();
667 // Now that all the status codes have been allocated in a contiguous block,
668 // refresh the StatusCodes pointer in each array element.
670 for (idx
=0; idx
< count
; idx
++) {
671 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
672 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
673 numStatusCodes
+= evInfo
->NumStatusCodes
+ 1;
676 secTrust
->_legacy_info_array
= infoArray
;
677 secTrust
->_legacy_status_array
= statusArray
;
679 if (inputCertArray
) {
680 CFRelease(inputCertArray
);
682 if (inputAnchorArray
) {
683 CFRelease(inputAnchorArray
);
686 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
689 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
) {
690 /* OS X creates a completely different structure with one dictionary for each certificate */
691 CFIndex ix
, count
= SecTrustGetCertificateCount(trust
);
693 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, count
,
694 &kCFTypeArrayCallBacks
);
696 for (ix
= 0; ix
< count
; ix
++) {
697 CFMutableDictionaryRef certDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
698 &kCFTypeDictionaryValueCallBacks
);
699 /* Populate the certificate title */
700 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, ix
);
702 CFStringRef subjectSummary
= SecCertificateCopySubjectSummary(cert
);
703 if (subjectSummary
) {
704 CFDictionaryAddValue(certDict
, kSecPropertyTypeTitle
, subjectSummary
);
705 CFRelease(subjectSummary
);
709 /* Populate a revocation reason if the cert was revoked */
710 CFIndex numStatusCodes
;
711 CSSM_RETURN
*statusCodes
= NULL
;
712 statusCodes
= (CSSM_RETURN
*)SecTrustCopyStatusCodes(trust
, ix
, &numStatusCodes
);
714 SInt32 reason
= statusCodes
[numStatusCodes
]; // stored at end of status codes array
716 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
718 CFDictionarySetValue(certDict
, kSecTrustRevocationReason
, cfreason
);
725 /* Populate the error in the leaf dictionary */
727 OSStatus error
= errSecSuccess
;
728 (void)SecTrustGetCssmResultCode(trust
, &error
);
729 CFStringRef errorStr
= SecCopyErrorMessageString(error
, NULL
);
731 CFDictionarySetValue(certDict
, kSecPropertyTypeError
, errorStr
);
736 CFArrayAppendValue(properties
, certDict
);
743 /* deprecated in 10.5 */
744 OSStatus
SecTrustGetCSSMAnchorCertificates(const CSSM_DATA
**cssmAnchors
,
745 uint32
*cssmAnchorCount
)
747 /* this function is unsupported in unified SecTrust */
748 #if SECTRUST_DEPRECATION_WARNINGS
749 syslog(LOG_ERR
, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
754 if (cssmAnchorCount
) {
755 *cssmAnchorCount
= 0;
757 return errSecServiceNotAvailable
;
762 // Get and set user trust settings. Deprecated in 10.5.
763 // User Trust getter, deprecated, works as it always has.
765 OSStatus
SecTrustGetUserTrust(SecCertificateRef certificate
,
766 SecPolicyRef policy
, SecTrustUserSetting
*trustSetting
)
768 /* this function is unsupported in unified SecTrust */
769 #if SECTRUST_DEPRECATION_WARNINGS
770 syslog(LOG_ERR
, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
772 return errSecServiceNotAvailable
;
776 // The public setter, also deprecated; it maps to the appropriate
777 // Trust Settings call if possible, else throws errSecUnimplemented.
779 OSStatus
SecTrustSetUserTrust(SecCertificateRef certificate
,
780 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
782 /* this function is unsupported in unified SecTrust */
783 #if SECTRUST_DEPRECATION_WARNINGS
784 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
786 return errSecServiceNotAvailable
;
790 // This one is the now-private version of what SecTrustSetUserTrust() used to
791 // be. The public API can no longer manipulate User Trust settings, only
794 OSStatus
SecTrustSetUserTrustLegacy(SecCertificateRef certificate
,
795 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
797 /* this function is unsupported in unified SecTrust */
798 #if SECTRUST_DEPRECATION_WARNINGS
799 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
801 return errSecServiceNotAvailable
;