2 * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "SecTrustPriv.h"
28 #include "SecBridge.h"
29 #include "SecInternal.h"
30 #include "SecInternalP.h"
31 #include "SecTrustSettings.h"
32 #include "SecTrustSettingsPriv.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
44 CFArrayRef
SecTrustCopyDetails(SecTrustRef trust
);
45 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
);
46 static void SecTrustCheckException(const void *key
, const void *value
, void *context
);
48 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
);
49 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
);
50 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
);
51 static CSSM_TP_APPLE_EVIDENCE_INFO
* SecTrustGetEvidenceInfo(SecTrustRef trust
);
54 typedef struct SecTrustCheckExceptionContext
{
55 CFDictionaryRef exception
;
56 bool exceptionNotFound
;
57 } SecTrustCheckExceptionContext
;
59 // public trust result constants
60 const CFStringRef kSecTrustEvaluationDate
= CFSTR("TrustEvaluationDate");
61 const CFStringRef kSecTrustExtendedValidation
= CFSTR("TrustExtendedValidation");
62 const CFStringRef kSecTrustOrganizationName
= CFSTR("Organization");
63 const CFStringRef kSecTrustResultValue
= CFSTR("TrustResultValue");
64 const CFStringRef kSecTrustRevocationChecked
= CFSTR("TrustRevocationChecked");
65 const CFStringRef kSecTrustRevocationReason
= CFSTR("TrustRevocationReason");
66 const CFStringRef kSecTrustRevocationValidUntilDate
= CFSTR("TrustExpirationDate");
67 const CFStringRef kSecTrustResultDetails
= CFSTR("TrustResultDetails");
69 // Policy check string to CSSM_RETURN mapping
71 struct resultmap_entry_s
{
72 const CFStringRef checkstr
;
73 const CSSM_RETURN resultcode
;
75 typedef struct resultmap_entry_s resultmap_entry_t
;
78 const resultmap_entry_t cssmresultmap
[] = {
79 { CFSTR("SSLHostname"), CSSMERR_APPLETP_HOSTNAME_MISMATCH
},
80 { CFSTR("email"), CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
},
81 { CFSTR("IssuerCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING
},
82 { CFSTR("SubjectCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING
},
83 { CFSTR("SubjectCommonNamePrefix"), CSSMERR_APPLETP_IDENTIFIER_MISSING
},
84 { CFSTR("SubjectCommonNameTEST"), CSSMERR_APPLETP_IDENTIFIER_MISSING
},
85 { CFSTR("SubjectOrganization"), CSSMERR_APPLETP_IDENTIFIER_MISSING
},
86 { CFSTR("SubjectOrganizationalUnit"), CSSMERR_APPLETP_IDENTIFIER_MISSING
},
87 { CFSTR("EAPTrustedServerNames"), CSSMERR_APPLETP_HOSTNAME_MISMATCH
},
88 { CFSTR("CertificatePolicy"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
},
89 { CFSTR("KeyUsage"), CSSMERR_APPLETP_INVALID_KEY_USAGE
},
90 { CFSTR("ExtendedKeyUsage"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
},
91 { CFSTR("BasicConstraints"), CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
},
92 { CFSTR("QualifiedCertStatements"), CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
},
93 { CFSTR("IntermediateSPKISHA256"), CSSMERR_APPLETP_IDENTIFIER_MISSING
},
94 { CFSTR("IntermediateEKU"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
},
95 { CFSTR("AnchorSHA1"), CSSMERR_TP_NOT_TRUSTED
},
96 { CFSTR("AnchorSHA256"), CSSMERR_TP_NOT_TRUSTED
},
97 { CFSTR("AnchorTrusted"), CSSMERR_TP_NOT_TRUSTED
},
98 { CFSTR("AnchorApple"), CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
},
99 { CFSTR("NonEmptySubject"), CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
},
100 { CFSTR("IdLinkage"), CSSMERR_APPLETP_INVALID_AUTHORITY_ID
},
101 { CFSTR("WeakIntermediates"), CSSMERR_TP_INVALID_CERTIFICATE
},
102 { CFSTR("WeakLeaf"), CSSMERR_TP_INVALID_CERTIFICATE
},
103 { CFSTR("WeakRoot"), CSSMERR_TP_INVALID_CERTIFICATE
},
104 { CFSTR("KeySize"), CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
},
105 { CFSTR("SignatureHashAlgorithms"), CSSMERR_CSP_ALGID_MISMATCH
},
106 { CFSTR("CriticalExtensions"), CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
},
107 { CFSTR("ChainLength"), CSSMERR_APPLETP_PATH_LEN_CONSTRAINT
},
108 { CFSTR("BasicCertificateProcessing"), CSSMERR_TP_INVALID_CERTIFICATE
},
109 { CFSTR("ExtendedValidation"), CSSMERR_TP_NOT_TRUSTED
},
110 { CFSTR("Revocation"), CSSMERR_TP_CERT_REVOKED
},
111 { CFSTR("RevocationResponseRequired"), CSSMERR_TP_VERIFY_ACTION_FAILED
},
112 { CFSTR("CertificateTransparency"), CSSMERR_TP_NOT_TRUSTED
},
113 { CFSTR("BlackListedLeaf"), CSSMERR_TP_CERT_REVOKED
},
114 { CFSTR("GrayListedLeaf"), CSSMERR_TP_NOT_TRUSTED
},
115 { CFSTR("GrayListedKey"), CSSMERR_TP_NOT_TRUSTED
},
116 { CFSTR("BlackListedKey"), CSSMERR_TP_CERT_REVOKED
},
117 { CFSTR("CheckLeafMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
},
118 { CFSTR("CheckLeafMarkerOidNoValueCheck"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
},
119 { CFSTR("CheckIntermediateMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
},
120 { CFSTR("UsageConstraints"), CSSMERR_APPLETP_TRUST_SETTING_DENY
},
121 { CFSTR("NotValidBefore"), CSSMERR_TP_CERT_NOT_VALID_YET
},
122 { CFSTR("ValidIntermediates"), CSSMERR_TP_CERT_EXPIRED
},
123 { CFSTR("ValidLeaf"), CSSMERR_TP_CERT_EXPIRED
},
124 { CFSTR("ValidRoot"), CSSMERR_TP_CERT_EXPIRED
},
125 // { CFSTR("AnchorAppleTestRoots"), },
126 // { CFSTR("AnchorAppleTestRootsOnProduction"), },
127 // { CFSTR("NoNetworkAccess"), },
135 CFTypeID
SecTrustGetTypeID(void)
139 return gTypes().Trust
.typeID
;
141 END_SECAPI1(_kCFRuntimeNotATypeID
)
146 // Sec* API bridge functions
149 OSStatus
SecTrustCreateWithCertificates(
150 CFTypeRef certificates
,
152 SecTrustRef
*trustRef
)
156 *trustRef
= (new Trust(certificates
, policies
))->handle();
163 SecTrustSetPolicies(SecTrustRef trustRef
, CFTypeRef policies
)
166 Trust::required(trustRef
)->policies(policies
);
173 SecTrustOptionFlags flags
;
175 SecTrustRef trustRef
;
176 CFMutableDictionaryRef filteredException
;
177 CFDictionaryRef oldException
;
178 } SecExceptionFilterContext
;
181 //%%%FIXME SecCFWrappers produces some conflicting definitions on OSX
182 #include <utilities/SecCFWrappers.h>
184 // inline function from SecCFWrappers.h
185 static inline char *CFStringToCString(CFStringRef inStr
)
188 return (char *)strdup("");
189 CFRetain(inStr
); // compensate for release on exit
191 // need to extract into buffer
192 CFIndex length
= CFStringGetLength(inStr
); // in 16-bit character units
193 size_t len
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
);
194 char *buffer
= (char *)malloc(len
); // pessimistic
195 if (!CFStringGetCString(inStr
, buffer
, len
, kCFStringEncodingUTF8
))
204 filter_exception(const void *key
, const void *value
, void *context
)
206 SecExceptionFilterContext
*ctx
= (SecExceptionFilterContext
*)context
;
207 if (!ctx
) { return; }
209 SecTrustOptionFlags options
= ctx
->flags
;
210 CFMutableDictionaryRef filteredException
= ctx
->filteredException
;
211 CFStringRef keystr
= (CFStringRef
)key
;
213 if (ctx
->oldException
&& CFDictionaryContainsKey(ctx
->oldException
, key
)) {
214 // Keep existing exception in filtered dictionary, regardless of options
215 CFDictionaryAddValue(filteredException
, key
, CFDictionaryGetValue(ctx
->oldException
, key
));
219 bool allowed
= false;
221 if (CFEqual(keystr
, CFSTR("SHA1Digest"))) {
222 allowed
= true; // this key is informational and always permitted
224 else if (CFEqual(keystr
, CFSTR("NotValidBefore"))) {
225 allowed
= ((options
& kSecTrustOptionAllowExpired
) != 0);
227 else if (CFEqual(keystr
, CFSTR("ValidLeaf"))) {
228 allowed
= ((options
& kSecTrustOptionAllowExpired
) != 0);
230 else if (CFEqual(keystr
, CFSTR("ValidIntermediates"))) {
231 allowed
= ((options
& kSecTrustOptionAllowExpired
) != 0);
233 else if (CFEqual(keystr
, CFSTR("ValidRoot"))) {
234 if (((options
& kSecTrustOptionAllowExpired
) != 0) ||
235 ((options
& kSecTrustOptionAllowExpiredRoot
) != 0)) {
239 else if (CFEqual(keystr
, CFSTR("AnchorTrusted"))) {
240 bool implicitAnchors
= ((options
& kSecTrustOptionImplicitAnchors
) != 0);
241 // Implicit anchors option only filters exceptions for self-signed certs
242 if (implicitAnchors
&& ctx
->trustRef
&&
243 (ctx
->certIX
< SecTrustGetCertificateCount(ctx
->trustRef
))) {
244 Boolean isSelfSigned
= false;
245 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(ctx
->trustRef
, ctx
->certIX
);
246 if (cert
&& (errSecSuccess
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) &&
252 else if (CFEqual(keystr
, CFSTR("KeyUsage")) ||
253 CFEqual(keystr
, CFSTR("ExtendedKeyUsage")) ||
254 CFEqual(keystr
, CFSTR("BasicConstraints")) ||
255 CFEqual(keystr
, CFSTR("NonEmptySubject")) ||
256 CFEqual(keystr
, CFSTR("IdLinkage"))) {
257 // Cannot override these exceptions
261 // Unhandled exceptions should not be overridden,
262 // but we want to know which ones we're missing
263 char *cstr
= CFStringToCString(keystr
);
264 syslog(LOG_ERR
, "Unfiltered exception: %s", (cstr
) ? cstr
: "<NULL>");
265 if (cstr
) { free(cstr
); }
270 CFDictionaryAddValue(filteredException
, key
, value
);
276 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
278 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
282 CSSM_APPLE_TP_ACTION_DATA actionData
= {
283 CSSM_APPLE_TP_ACTION_VERSION
,
284 (CSSM_APPLE_TP_ACTION_FLAGS
)options
286 Trust
*trust
= Trust::required(trustRef
);
287 CFDataRef actionDataRef
= CFDataCreate(NULL
,
288 (const UInt8
*)&actionData
,
289 (CFIndex
)sizeof(CSSM_APPLE_TP_ACTION_DATA
));
290 trust
->action(CSSM_TP_ACTION_DEFAULT
);
291 trust
->actionData(actionDataRef
);
292 if (actionDataRef
) CFRelease(actionDataRef
);
295 /* bridge to support API functionality for legacy callers */
296 OSStatus status
= errSecSuccess
;
297 CFDataRef encodedExceptions
= SecTrustCopyExceptions(trustRef
);
298 CFArrayRef exceptions
= NULL
,
299 oldExceptions
= SecTrustGetTrustExceptionsArray(trustRef
);
301 if (encodedExceptions
) {
302 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
303 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
304 CFRelease(encodedExceptions
);
305 encodedExceptions
= NULL
;
308 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
309 CFRelease(exceptions
);
313 if (oldExceptions
&& exceptions
&&
314 CFArrayGetCount(oldExceptions
) > CFArrayGetCount(exceptions
)) {
315 oldExceptions
= NULL
;
318 /* verify both exceptions are for the same leaf */
319 if (oldExceptions
&& exceptions
&& CFArrayGetCount(oldExceptions
) > 0) {
320 CFDictionaryRef oldLeafExceptions
= (CFDictionaryRef
)CFArrayGetValueAtIndex(oldExceptions
, 0);
321 CFDictionaryRef leafExceptions
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, 0);
322 CFDataRef oldDigest
= (CFDataRef
)CFDictionaryGetValue(oldLeafExceptions
, CFSTR("SHA1Digest"));
323 CFDataRef digest
= (CFDataRef
)CFDictionaryGetValue(leafExceptions
, CFSTR("SHA1Digest"));
324 if (!oldDigest
|| !digest
|| !CFEqual(oldDigest
, digest
)) {
325 oldExceptions
= NULL
;
329 /* add only those exceptions which are allowed by the supplied options */
331 CFMutableArrayRef filteredExceptions
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
332 CFIndex i
, exceptionCount
= (filteredExceptions
) ? CFArrayGetCount(exceptions
) : 0;
334 for (i
= 0; i
< exceptionCount
; ++i
) {
335 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, i
);
336 CFDictionaryRef oldException
= NULL
;
337 if (oldExceptions
&& i
< CFArrayGetCount(oldExceptions
)) {
338 oldException
= (CFDictionaryRef
)CFArrayGetValueAtIndex(oldExceptions
, i
);
340 CFMutableDictionaryRef filteredException
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
341 &kCFTypeDictionaryValueCallBacks
);
342 if (exception
&& filteredException
) {
343 SecExceptionFilterContext filterContext
= { options
, i
, trustRef
, filteredException
, oldException
};
344 CFDictionaryApplyFunction(exception
, filter_exception
, &filterContext
);
345 CFArrayAppendValue(filteredExceptions
, filteredException
);
346 CFRelease(filteredException
);
350 if (filteredExceptions
) {
351 CFIndex filteredCount
= CFArrayGetCount(filteredExceptions
);
352 /* remove empty trailing entries to match iOS behavior */
353 for (i
= filteredCount
; i
-- > 1;) {
354 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(filteredExceptions
, i
);
355 if (CFDictionaryGetCount(exception
) == 0) {
356 CFArrayRemoveValueAtIndex(filteredExceptions
, i
);
361 encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
362 filteredExceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
363 CFRelease(filteredExceptions
);
365 SecTrustSetExceptions(trustRef
, encodedExceptions
);
366 CFRelease(encodedExceptions
);
368 CFRelease(exceptions
);
371 #if SECTRUST_DEPRECATION_WARNINGS
372 bool displayModifyMsg
= false;
373 bool displayNetworkMsg
= false;
374 bool displayPolicyMsg
= false;
375 const char *baseMsg
= "WARNING: SecTrustSetOptions called with";
376 const char *modifyMsg
= "Use SecTrustSetExceptions and SecTrustCopyExceptions to modify default trust results.";
377 const char *networkMsg
= "Use SecTrustSetNetworkFetchAllowed to specify whether missing certificates can be fetched from the network.";
378 const char *policyMsg
= "Use SecPolicyCreateRevocation to specify revocation policy requirements.";
380 if (options
& kSecTrustOptionAllowExpired
) {
381 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionAllowExpired");
382 displayModifyMsg
= true;
384 if (options
& kSecTrustOptionAllowExpiredRoot
) {
385 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionAllowExpiredRoot");
386 displayModifyMsg
= true;
388 if (options
& kSecTrustOptionFetchIssuerFromNet
) {
389 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionFetchIssuerFromNet");
390 displayNetworkMsg
= true;
392 if (options
& kSecTrustOptionRequireRevPerCert
) {
393 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionRequireRevPerCert");
394 displayPolicyMsg
= true;
396 if (displayModifyMsg
|| displayNetworkMsg
|| displayPolicyMsg
) {
397 syslog(LOG_ERR
, "%s %s %s",
398 (displayModifyMsg
) ? modifyMsg
: "",
399 (displayNetworkMsg
) ? networkMsg
: "",
400 (displayPolicyMsg
) ? policyMsg
: "");
409 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
410 OSStatus
SecTrustSetParameters(
411 SecTrustRef trustRef
,
412 CSSM_TP_ACTION action
,
413 CFDataRef actionData
)
417 Trust
*trust
= Trust::required(trustRef
);
418 trust
->action(action
);
419 trust
->actionData(actionData
);
422 /* bridge to support API functionality for legacy callers */
424 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
426 CSSM_APPLE_TP_ACTION_DATA
*actionDataPtr
= (CSSM_APPLE_TP_ACTION_DATA
*) CFDataGetBytePtr(actionData
);
428 actionFlags
= actionDataPtr
->ActionFlags
;
431 // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS;
432 // both are sizeof(uint32) and the flag values have identical meanings
433 status
= SecTrustSetOptions(trustRef
, (SecTrustOptionFlags
)actionFlags
);
435 #if SECTRUST_DEPRECATION_WARNINGS
436 syslog(LOG_ERR
, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
445 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
, CFArrayRef anchorCertificates
)
448 Trust::required(trust
)->anchors(anchorCertificates
);
454 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
, Boolean anchorCertificatesOnly
)
457 Trust::AnchorPolicy policy
= (anchorCertificatesOnly
) ? Trust::useAnchorsOnly
: Trust::useAnchorsAndBuiltIns
;
458 Trust::required(trust
)->anchorPolicy(policy
);
463 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
464 OSStatus
SecTrustSetKeychains(SecTrustRef trust
, CFTypeRef keychainOrArray
)
468 StorageManager::KeychainList keychains
;
469 // avoid unnecessary global initializations if an empty array is passed in
470 if (!( (keychainOrArray
!= NULL
) &&
471 (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) &&
472 (CFArrayGetCount((CFArrayRef
)keychainOrArray
) == 0) )) {
473 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
475 Trust::required(trust
)->searchLibs(keychains
);
478 /* this function is currently unsupported in unified SecTrust */
479 // TODO: pull all certs out of the specified keychains for the evaluation?
480 #if SECTRUST_DEPRECATION_WARNINGS
481 syslog(LOG_ERR
, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors.");
483 return errSecSuccess
;
488 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
)
491 Trust::required(trust
)->time(verifyDate
);
497 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
)
499 CFAbsoluteTime verifyTime
= 0;
500 OSStatus __secapiresult
= errSecSuccess
;
502 CFRef
<CFDateRef
> verifyDate
= Trust::required(trust
)->time();
503 verifyTime
= CFDateGetAbsoluteTime(verifyDate
);
505 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
506 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
507 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
508 catch (...) { __secapiresult
=errSecInternalComponent
; }
516 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*resultP
)
518 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
519 CFArrayRef exceptions
= NULL
;
520 OSStatus __secapiresult
= errSecSuccess
;
522 Trust
*trustObj
= Trust::required(trust
);
523 trustObj
->evaluate();
524 trustResult
= trustObj
->result();
525 exceptions
= trustObj
->exceptions();
527 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
528 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
529 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
530 catch (...) { __secapiresult
=errSecInternalComponent
; }
532 if (__secapiresult
) {
533 return __secapiresult
;
536 /* post-process trust result based on exceptions */
537 if (trustResult
== kSecTrustResultUnspecified
) {
538 /* If leaf is in exceptions -> proceed, otherwise unspecified. */
539 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
540 trustResult
= kSecTrustResultProceed
;
542 else if (trustResult
== kSecTrustResultRecoverableTrustFailure
&& exceptions
) {
543 /* If we have exceptions get details and match to exceptions. */
544 CFArrayRef details
= SecTrustCopyDetails(trust
);
546 CFIndex pathLength
= CFArrayGetCount(details
);
547 struct SecTrustCheckExceptionContext context
= {};
549 for (ix
= 0; ix
< pathLength
; ++ix
) {
550 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
551 // if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf))
552 // trustResult = kSecTrustResultFatalTrustFailure;
553 context
.exception
= SecTrustGetExceptionForCertificateAtIndex(trust
, ix
);
554 CFDictionaryApplyFunction(detail
, SecTrustCheckException
, &context
);
555 if (context
.exceptionNotFound
) {
559 if (!context
.exceptionNotFound
)
560 trustResult
= kSecTrustResultProceed
;
565 secnotice("SecTrustEvaluate", "SecTrustEvaluate trust result = %d", (int)trustResult
);
567 *resultP
= trustResult
;
569 return __secapiresult
;
574 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
575 dispatch_queue_t queue
, SecTrustCallback result
)
578 dispatch_async(queue
, ^{
580 Trust
*trustObj
= Trust::required(trust
);
581 trustObj
->evaluate();
582 SecTrustResultType trustResult
= trustObj
->result();
583 result(trust
, trustResult
);
586 result(trust
, kSecTrustResultInvalid
);
594 // Construct the "official" result evidence and return it
596 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
597 OSStatus
SecTrustGetResult(
598 SecTrustRef trustRef
,
599 SecTrustResultType
*result
,
600 CFArrayRef
*certChain
, CSSM_TP_APPLE_EVIDENCE_INFO
**statusChain
)
604 Trust
*trust
= Trust::required(trustRef
);
606 *result
= trust
->result();
607 if (certChain
&& statusChain
)
608 trust
->buildEvidence(*certChain
, TPEvidenceInfo::overlayVar(*statusChain
));
611 /* bridge to support old functionality */
612 #if SECTRUST_DEPRECATION_WARNINGS
613 syslog(LOG_ERR
, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
615 SecTrustResultType trustResult
;
616 OSStatus status
= SecTrustGetTrustResult(trustRef
, &trustResult
);
617 if (status
!= errSecSuccess
) {
621 *result
= trustResult
;
624 *certChain
= SecTrustCopyConstructedChain(trustRef
);
627 *statusChain
= SecTrustGetEvidenceInfo(trustRef
);
634 // Retrieve result of trust evaluation only
637 OSStatus
SecTrustGetTrustResult(SecTrustRef trustRef
,
638 SecTrustResultType
*result
)
641 Trust
*trust
= Trust::required(trustRef
);
642 if (result
) *result
= trust
->result();
648 // Retrieve extended validation trust results
650 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
651 OSStatus
SecTrustCopyExtendedResult(SecTrustRef trust
, CFDictionaryRef
*result
)
655 Trust
*trustObj
= Trust::required(trust
);
658 trustObj
->extendedResult(*result
);
661 /* bridge to support old functionality */
662 #if SECTRUST_DEPRECATION_WARNINGS
663 syslog(LOG_ERR
, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead.");
665 CFDictionaryRef resultDict
= SecTrustCopyResult(trust
);
669 *result
= resultDict
;
670 return errSecSuccess
;
675 // Retrieve CSSM-level information for those who want to dig down
677 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
678 OSStatus
SecTrustGetCssmResult(SecTrustRef trust
, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR
*result
)
682 Required(result
) = Trust::required(trust
)->cssmResult();
685 /* this function is unsupported in unified SecTrust */
686 #if SECTRUST_DEPRECATION_WARNINGS
687 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead.");
692 return errSecServiceNotAvailable
;
698 // Returns a malloced array of CSSM_RETURN values, with the length in numStatusCodes,
699 // for the certificate specified by chain index in the given SecTrustRef.
701 // To match legacy behavior, the array actually allocates one element more than the
702 // value of numStatusCodes; if the certificate is revoked, the additional element
703 // at the end contains the CrlReason value.
705 // Caller must free the returned pointer.
707 static CSSM_RETURN
*copyCssmStatusCodes(SecTrustRef trust
,
708 unsigned int index
, unsigned int *numStatusCodes
)
710 if (!trust
|| !numStatusCodes
) {
714 CFArrayRef details
= SecTrustGetDetails(trust
);
715 CFIndex chainLength
= (details
) ? CFArrayGetCount(details
) : 0;
716 if (!(index
< chainLength
)) {
719 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, index
);
720 CFIndex ix
, detailCount
= CFDictionaryGetCount(detail
);
721 *numStatusCodes
= (unsigned int)detailCount
;
723 // Allocate one more entry than we need; this is used to store a CrlReason
724 // at the end of the array.
725 CSSM_RETURN
*statusCodes
= (CSSM_RETURN
*)malloc((detailCount
+1) * sizeof(CSSM_RETURN
));
726 statusCodes
[*numStatusCodes
] = 0;
728 const unsigned int resultmaplen
= sizeof(cssmresultmap
) / sizeof(resultmap_entry_t
);
729 const void *keys
[detailCount
];
730 CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
);
731 for (ix
= 0; ix
< detailCount
; ix
++) {
732 CFStringRef key
= (CFStringRef
)keys
[ix
];
733 CSSM_RETURN statusCode
= CSSM_OK
;
734 for (unsigned int mapix
= 0; mapix
< resultmaplen
; mapix
++) {
735 CFStringRef str
= (CFStringRef
) cssmresultmap
[mapix
].checkstr
;
736 if (CFStringCompare(str
, key
, 0) == kCFCompareEqualTo
) {
737 statusCode
= (CSSM_RETURN
) cssmresultmap
[mapix
].resultcode
;
741 if (statusCode
== CSSMERR_TP_CERT_REVOKED
) {
743 CFNumberRef number
= (CFNumberRef
)CFDictionaryGetValue(detail
, key
);
744 if (number
&& CFNumberGetValue(number
, kCFNumberSInt32Type
, &reason
)) {
745 statusCodes
[*numStatusCodes
] = (CSSM_RETURN
)reason
;
748 statusCodes
[ix
] = statusCode
;
754 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode
) {
755 switch (resultCode
) {
756 /* explicitly not trusted */
757 case CSSMERR_TP_CERT_REVOKED
:
758 case CSSMERR_APPLETP_TRUST_SETTING_DENY
:
760 /* failure to comply with X.509 */
761 case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
:
762 case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
:
763 case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
:
764 case CSSMERR_APPLETP_INVALID_AUTHORITY_ID
:
765 case CSSMERR_TP_INVALID_CERTIFICATE
:
766 case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
:
768 case CSSMERR_TP_CERT_EXPIRED
:
770 /* doesn't chain to trusted root */
771 case CSSMERR_TP_NOT_TRUSTED
:
772 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
:
774 /* all others are policy-specific failures */
780 #include <libDER/oidsPriv.h>
781 #include <Security/oidscert.h>
782 static bool isSoftwareUpdateDevelopment(SecTrustRef trust
) {
783 bool isPolicy
= false, isEKU
= false;
784 CFArrayRef policies
= NULL
;
786 /* Policy used to evaluate was SWUpdateSigning */
787 SecTrustCopyPolicies(trust
, &policies
);
789 SecPolicyRef swUpdatePolicy
= SecPolicyCreateAppleSWUpdateSigning();
790 if (swUpdatePolicy
&& CFArrayContainsValue(policies
, CFRangeMake(0, CFArrayGetCount(policies
)),
794 if (swUpdatePolicy
) { CFRelease(swUpdatePolicy
); }
801 /* Only error was EKU on the leaf */
802 CFArrayRef details
= SecTrustGetDetails(trust
);
803 CFIndex ix
, count
= CFArrayGetCount(details
);
804 for (ix
= 0; ix
< count
; ix
++) {
805 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
806 if (ix
== 0) { // Leaf
807 if (CFDictionaryGetCount(detail
) != 1 || // One error
808 CFDictionaryGetValue(detail
, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse
) // kSecPolicyCheckExtendedKeyUsage
811 if (CFDictionaryGetCount(detail
) > 0) { // No errors on other certs
817 /* EKU on the leaf is the Apple Development Code Signing OID */
818 SecCertificateRef leaf
= SecTrustGetCertificateAtIndex(trust
, 0);
819 CSSM_DATA
*fieldValue
= NULL
;
820 if (errSecSuccess
!= SecCertificateCopyFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, &fieldValue
)) {
823 if (fieldValue
&& fieldValue
->Data
&& fieldValue
->Length
== sizeof(CSSM_X509_EXTENSION
)) {
824 const CSSM_X509_EXTENSION
*ext
= (const CSSM_X509_EXTENSION
*)fieldValue
->Data
;
825 if (ext
->format
== CSSM_X509_DATAFORMAT_PARSED
) {
826 const CE_ExtendedKeyUsage
*ekus
= (const CE_ExtendedKeyUsage
*)ext
->value
.parsedValue
;
827 if (ekus
&& (ekus
->numPurposes
== 1) && ekus
->purposes
[0].Data
&&
828 (ekus
->purposes
[0].Length
== CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Length
) &&
829 (memcmp(ekus
->purposes
[0].Data
, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Data
,
830 ekus
->purposes
[0].Length
) == 0)) {
835 SecCertificateReleaseFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, fieldValue
);
841 // Retrieve CSSM_LEVEL TP return code
843 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
844 OSStatus
SecTrustGetCssmResultCode(SecTrustRef trustRef
, OSStatus
*result
)
848 Trust
*trust
= Trust::required(trustRef
);
849 if (trust
->result() == kSecTrustResultInvalid
)
852 Required(result
) = trust
->cssmResultCode();
855 /* bridge to support old functionality */
856 #if SECTRUST_DEPRECATION_WARNINGS
857 syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
859 if (!trustRef
|| !result
) {
863 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
864 (void) SecTrustGetTrustResult(trustRef
, &trustResult
);
865 if (trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
) {
866 if (result
) { *result
= 0; }
867 return errSecSuccess
;
870 /* Development Software Update certs return a special error code when evaluated
871 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
872 if (isSoftwareUpdateDevelopment(trustRef
)) {
874 *result
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
;
876 return errSecSuccess
;
879 OSStatus cssmResultCode
= errSecSuccess
;
880 uint8_t resultCodePriority
= 0xFF;
881 CFIndex ix
, count
= SecTrustGetCertificateCount(trustRef
);
882 for (ix
= 0; ix
< count
; ix
++) {
883 unsigned int numStatusCodes
;
884 CSSM_RETURN
*statusCodes
= NULL
;
885 statusCodes
= copyCssmStatusCodes(trustRef
, (uint32_t)ix
, &numStatusCodes
);
886 if (statusCodes
&& numStatusCodes
> 0) {
887 unsigned int statusIX
;
888 for (statusIX
= 0; statusIX
< numStatusCodes
; statusIX
++) {
889 CSSM_RETURN currStatus
= statusCodes
[statusIX
];
890 uint8_t currPriotiy
= convertCssmResultToPriority(currStatus
);
891 if (resultCodePriority
> currPriotiy
) {
892 cssmResultCode
= currStatus
;
893 resultCodePriority
= currPriotiy
;
897 if (statusCodes
) { free(statusCodes
); }
898 if (resultCodePriority
== 1) { break; }
902 *result
= cssmResultCode
;
904 return errSecSuccess
;
908 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
909 OSStatus
SecTrustGetTPHandle(SecTrustRef trust
, CSSM_TP_HANDLE
*handle
)
913 Required(handle
) = Trust::required(trust
)->getTPHandle();
916 /* this function is unsupported in unified SecTrust */
917 #if SECTRUST_DEPRECATION_WARNINGS
918 syslog(LOG_ERR
, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
923 return errSecServiceNotAvailable
;
928 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
)
931 CFArrayRef currentPolicies
= Trust::required(trust
)->policies();
932 if (currentPolicies
!= NULL
)
934 CFRetain(currentPolicies
);
937 Required(policies
) = currentPolicies
;
943 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
)
946 Trust
*trustObj
= Trust::required(trust
);
947 Trust::NetworkPolicy netPolicy
= (allowFetch
) ?
948 Trust::useNetworkEnabled
: Trust::useNetworkDisabled
;
949 trustObj
->networkPolicy(netPolicy
);
955 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
)
958 Boolean allowed
= false;
959 Trust
*trustObj
= Trust::required(trust
);
960 Trust::NetworkPolicy netPolicy
= trustObj
->networkPolicy();
961 if (netPolicy
== Trust::useNetworkDefault
) {
962 // network fetch is enabled by default for SSL only
963 allowed
= trustObj
->policySpecified(trustObj
->policies(), CSSMOID_APPLE_TP_SSL
);
965 // caller has explicitly set the network policy
966 allowed
= (netPolicy
== Trust::useNetworkEnabled
);
968 Required(allowFetch
) = allowed
;
974 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
)
977 Trust::required(trust
)->responses(responseData
);
983 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
, CFArrayRef
*anchorCertificates
)
986 CFArrayRef customAnchors
= Trust::required(trust
)->anchors();
987 Required(anchorCertificates
) = (customAnchors
) ?
988 (const CFArrayRef
)CFRetain(customAnchors
) : (const CFArrayRef
)NULL
;
994 // Get the user's default anchor certificate set
997 OSStatus
SecTrustCopyAnchorCertificates(CFArrayRef
*anchorCertificates
)
1001 return SecTrustSettingsCopyUnrestrictedRoots(
1002 true, true, true, /* all domains */
1003 anchorCertificates
);
1009 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
1011 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1013 SecKeyRef pubKey
= NULL
;
1014 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, 0);
1015 (void) SecCertificateCopyPublicKey(certificate
, &pubKey
);
1020 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
1022 SecKeyRef pubKey
= NULL
;
1023 CFArrayRef certChain
= NULL
;
1024 CFArrayRef evidenceChain
= NULL
;
1025 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1026 OSStatus __secapiresult
= errSecSuccess
;
1028 Trust
*trustObj
= Trust::required(trust
);
1029 if (trustObj
->result() == kSecTrustResultInvalid
) {
1030 // Trust hasn't been evaluated; attempt to retrieve public key from leaf.
1031 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, 0);
1032 __secapiresult
= SecCertificateCopyPublicKey(cert
, &pubKey
);
1036 // Otherwise, we must evaluate first.
1037 trustObj
->evaluate();
1038 if (trustObj
->result() == kSecTrustResultInvalid
) {
1039 MacOSError::throwMe(errSecTrustNotAvailable
);
1042 if (trustObj
->evidence() == nil
) {
1043 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
1045 evidenceChain
= trustObj
->evidence();
1047 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1048 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1049 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1050 catch (...) { __secapiresult
=errSecInternalComponent
; }
1053 CFRelease(certChain
);
1055 if (evidenceChain
) {
1056 if (CFArrayGetCount(evidenceChain
) > 0) {
1057 SecCertificateRef cert
= (SecCertificateRef
) CFArrayGetValueAtIndex(evidenceChain
, 0);
1058 __secapiresult
= SecCertificateCopyPublicKey(cert
, &pubKey
);
1060 // do not release evidenceChain, as it is owned by the trust object.
1068 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
)
1070 CFIndex chainLen
= 0;
1071 CFArrayRef certChain
= NULL
;
1072 CFArrayRef evidenceChain
= NULL
;
1073 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1074 OSStatus __secapiresult
= errSecSuccess
;
1076 Trust
*trustObj
= Trust::required(trust
);
1077 if (trustObj
->result() == kSecTrustResultInvalid
) {
1078 trustObj
->evaluate();
1079 if (trustObj
->result() == kSecTrustResultInvalid
)
1080 MacOSError::throwMe(errSecTrustNotAvailable
);
1082 if (trustObj
->evidence() == nil
)
1083 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
1084 evidenceChain
= trustObj
->evidence();
1086 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1087 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1088 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1089 catch (...) { __secapiresult
=errSecInternalComponent
; }
1092 CFRelease(certChain
);
1095 chainLen
= CFArrayGetCount(evidenceChain
); // don't release, trust object owns it.
1103 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
, CFIndex ix
)
1105 SecCertificateRef certificate
= NULL
;
1106 CFArrayRef certChain
= NULL
;
1107 CFArrayRef evidenceChain
= NULL
;
1108 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1109 OSStatus __secapiresult
= errSecSuccess
;
1111 Trust
*trustObj
= Trust::required(trust
);
1112 if (trustObj
->result() == kSecTrustResultInvalid
) {
1113 // If caller is asking for the leaf, we can return it without
1114 // having to evaluate the entire chain. Note that we don't retain
1115 // the cert as it's owned by the trust and this is a 'Get' API.
1117 CFArrayRef certs
= trustObj
->certificates();
1118 if (certs
&& (CFArrayGetCount(certs
) > 0)) {
1119 certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certs
, 0);
1125 // Otherwise, we must evaluate first.
1126 trustObj
->evaluate();
1127 if (trustObj
->result() == kSecTrustResultInvalid
) {
1128 MacOSError::throwMe(errSecTrustNotAvailable
);
1131 if (trustObj
->evidence() == nil
) {
1132 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
1134 evidenceChain
= trustObj
->evidence();
1136 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1137 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1138 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1139 catch (...) { __secapiresult
=errSecInternalComponent
; }
1142 CFRelease(certChain
);
1144 if (evidenceChain
) {
1145 if (ix
< CFArrayGetCount(evidenceChain
)) {
1146 certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(evidenceChain
, ix
);
1147 // note: we do not retain this certificate. The assumption here is
1148 // that the certificate is retained by the trust object, so it is
1149 // valid unil the trust is released (or until re-evaluated.)
1150 // also note: we do not release the evidenceChain, as it is owned
1151 // by the trust object.
1158 // cannot link against the new iOS SecTrust from this implementation,
1159 // so there are no possible accessors for the fields of this struct
1160 typedef struct __TSecTrust
{
1161 CFRuntimeBase _base
;
1162 CFArrayRef _certificates
;
1163 CFArrayRef _anchors
;
1164 CFTypeRef _policies
;
1165 CFArrayRef _responses
;
1167 CFArrayRef _trustedLogs
;
1168 CFDateRef _verifyDate
;
1170 SecKeyRef _publicKey
;
1171 CFArrayRef _details
;
1172 CFDictionaryRef _info
;
1173 CFArrayRef _exceptions
;
1174 SecTrustResultType _trustResult
;
1176 bool _keychainsAllowed
;
1177 void* _legacy_info_array
;
1178 void* _legacy_status_array
;
1179 SecTrustResultType _trustResultBeforeExceptions
;
1183 CFArrayRef
SecTrustCopyInputCertificates(SecTrustRef trust
)
1185 if (!trust
) { return NULL
; };
1186 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
1187 if (secTrust
->_certificates
) {
1188 CFRetain(secTrust
->_certificates
);
1190 return secTrust
->_certificates
;
1195 CFArrayRef
SecTrustCopyInputAnchors(SecTrustRef trust
)
1197 if (!trust
) { return NULL
; };
1198 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
1199 if (secTrust
->_anchors
) {
1200 CFRetain(secTrust
->_anchors
);
1202 return secTrust
->_anchors
;
1207 // Return the constructed certificate chain for this trust reference,
1208 // making output certificates pointer-equivalent to any provided input
1209 // certificates (where possible) for legacy behavioral compatibility.
1210 // Caller must release this array.
1212 CFArrayRef
SecTrustCopyConstructedChain(SecTrustRef trust
)
1214 CFMutableArrayRef certChain
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1215 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
1216 for (idx
=0; idx
< count
; idx
++) {
1217 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, idx
);
1219 CFArrayAppendValue(certChain
, certificate
);
1222 // <rdar://24393060>
1223 // Some callers make the assumption that the certificates in
1224 // this chain are pointer-equivalent to ones they passed to the
1225 // SecTrustCreateWithCertificates function. We'll maintain that
1226 // behavior here for compatibility.
1228 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
1229 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
1230 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
1231 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
1232 for (idx
=0; idx
< count
; idx
++) {
1233 SecCertificateRef tmpCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, idx
);
1235 SecCertificateRef matchCert
= NULL
;
1236 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
&& !matchCert
; inputCertIdx
++) {
1237 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
1238 if (inputCert
&& CFEqual(inputCert
, tmpCert
)) {
1239 matchCert
= inputCert
;
1242 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
&& !matchCert
; inputAnchorIdx
++) {
1243 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
1244 if (inputAnchor
&& CFEqual(inputAnchor
, tmpCert
)) {
1245 matchCert
= inputAnchor
;
1249 CFArraySetValueAtIndex(certChain
, idx
, matchCert
);
1253 if (inputCertArray
) {
1254 CFRelease(inputCertArray
);
1256 if (inputAnchorArray
) {
1257 CFRelease(inputAnchorArray
);
1265 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
1266 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
1267 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
1268 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
1269 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
1270 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
1271 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
1272 // which would force re-evaluation.
1274 static CSSM_TP_APPLE_EVIDENCE_INFO
*
1275 SecTrustGetEvidenceInfo(SecTrustRef trust
)
1277 TSecTrust
*secTrust
= (TSecTrust
*)trust
;
1281 if (secTrust
->_trustResult
!= kSecTrustSettingsResultInvalid
&&
1282 secTrust
->_legacy_info_array
) {
1283 // we've already got valid evidence info, return it now.
1284 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
1287 // Getting the count implicitly evaluates the chain if necessary.
1288 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
1289 CFArrayRef inputCertArray
= SecTrustCopyInputCertificates(trust
);
1290 CFArrayRef inputAnchorArray
= SecTrustCopyInputAnchors(trust
);
1291 CFIndex inputCertIdx
, inputCertCount
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0;
1292 CFIndex inputAnchorIdx
, inputAnchorCount
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0;
1294 CSSM_TP_APPLE_EVIDENCE_INFO
*infoArray
= (CSSM_TP_APPLE_EVIDENCE_INFO
*)calloc(count
, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO
));
1295 CSSM_RETURN
*statusArray
= NULL
;
1296 unsigned int numStatusCodes
= 0;
1298 // Set status codes for each certificate in the constructed chain
1299 for (idx
=0; idx
< count
; idx
++) {
1300 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, idx
);
1304 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
1306 /* first the booleans (StatusBits flags) */
1307 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
1308 if (secTrust
->_verifyDate
) {
1309 now
= CFDateGetAbsoluteTime(secTrust
->_verifyDate
);
1311 CFAbsoluteTime na
= SecCertificateNotValidAfter(cert
);
1313 evInfo
->StatusBits
|= CSSM_CERT_STATUS_EXPIRED
;
1315 CFAbsoluteTime nb
= SecCertificateNotValidBefore(cert
);
1317 evInfo
->StatusBits
|= CSSM_CERT_STATUS_NOT_VALID_YET
;
1319 for (inputAnchorIdx
=0; inputAnchorIdx
< inputAnchorCount
; inputAnchorIdx
++) {
1320 SecCertificateRef inputAnchor
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
);
1321 if (inputAnchor
&& CFEqual(inputAnchor
, cert
)) {
1322 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_ANCHORS
;
1326 for (inputCertIdx
=0; inputCertIdx
< inputCertCount
; inputCertIdx
++) {
1327 SecCertificateRef inputCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
);
1328 if (inputCert
&& CFEqual(inputCert
, cert
)) {
1329 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
;
1334 /* See if there are trust settings for this certificate. */
1335 CFStringRef hashStr
= SecTrustSettingsCertHashStrFromCert(cert
);
1336 bool foundMatch
= false;
1337 bool foundAny
= false;
1338 CSSM_RETURN
*errors
= NULL
;
1339 uint32 errorCount
= 0;
1340 OSStatus status
= 0;
1341 SecTrustSettingsDomain foundDomain
= 0;
1342 SecTrustSettingsResult foundResult
= kSecTrustSettingsResultInvalid
;
1343 bool isSelfSigned
= false;
1344 if ((count
- 1) == idx
) {
1345 // Only the last cert in the chain needs to be considered
1347 status
= SecCertificateIsSelfSigned(cert
, &selfSigned
);
1348 isSelfSigned
= (status
) ? false : ((selfSigned
) ? true : false);
1350 evInfo
->StatusBits
|= CSSM_CERT_STATUS_IS_ROOT
;
1353 // STU: rdar://25554967
1354 // %%% need to get policyOID, policyString, and keyUsage here!
1356 status
= SecTrustSettingsEvaluateCert(
1357 hashStr
, /* certHashStr */
1358 NULL
, /* policyOID (optional) */
1359 NULL
, /* policyString (optional) */
1360 0, /* policyStringLen */
1362 isSelfSigned
, /* isRootCert */
1363 &foundDomain
, /* foundDomain */
1364 &errors
, /* allowedErrors -- MUST FREE */
1365 &errorCount
, /* numAllowedErrors */
1366 &foundResult
, /* resultType */
1367 &foundMatch
, /* foundMatchingEntry */
1368 &foundAny
); /* foundAnyEntry */
1370 if (status
== errSecSuccess
) {
1372 switch (foundResult
) {
1373 case kSecTrustSettingsResultTrustRoot
:
1374 case kSecTrustSettingsResultTrustAsRoot
:
1375 /* these two can be disambiguated by IS_ROOT */
1376 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
;
1378 case kSecTrustSettingsResultDeny
:
1379 evInfo
->StatusBits
|= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
;
1381 case kSecTrustSettingsResultUnspecified
:
1382 case kSecTrustSettingsResultInvalid
:
1395 unsigned int numCodes
=0;
1396 CSSM_RETURN
*statusCodes
= copyCssmStatusCodes(trust
, (unsigned int)idx
, &numCodes
);
1398 // Realloc space for these status codes at end of our status codes block.
1399 // Two important things to note:
1400 // 1. the actual length is numCodes+1 because copyCssmStatusCodes
1401 // allocates one more element at the end for the CrlReason value.
1402 // 2. realloc may cause the pointer to move, which means we will
1403 // need to fix up the StatusCodes fields after we're done with this loop.
1404 unsigned int totalStatusCodes
= numStatusCodes
+ numCodes
+ 1;
1405 statusArray
= (CSSM_RETURN
*)realloc(statusArray
, totalStatusCodes
* sizeof(CSSM_RETURN
));
1406 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
1407 evInfo
->NumStatusCodes
= numCodes
;
1408 // Copy the new codes (plus one) into place
1409 for (unsigned int cpix
= 0; cpix
<= numCodes
; cpix
++) {
1410 evInfo
->StatusCodes
[cpix
] = statusCodes
[cpix
];
1412 numStatusCodes
= totalStatusCodes
;
1416 if(evInfo
->StatusBits
& (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
|
1417 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
|
1418 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR
)) {
1419 /* Something noteworthy happened involving TrustSettings */
1420 uint32 whichDomain
= 0;
1421 switch(foundDomain
) {
1422 case kSecTrustSettingsDomainUser
:
1423 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
;
1425 case kSecTrustSettingsDomainAdmin
:
1426 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
;
1428 case kSecTrustSettingsDomainSystem
:
1429 whichDomain
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
;
1432 evInfo
->StatusBits
|= whichDomain
;
1435 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
1436 //evInfo->Index = certInfo->index();
1437 /* nonzero if cert came from a DLDB */
1438 //evInfo->DlDbHandle = certInfo->dlDbHandle();
1439 //evInfo->UniqueRecord = certInfo->uniqueRecord();
1442 // Now that all the status codes have been allocated in a contiguous block,
1443 // refresh the StatusCodes pointer in each array element.
1445 for (idx
=0; idx
< count
; idx
++) {
1446 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &infoArray
[idx
];
1447 evInfo
->StatusCodes
= &statusArray
[numStatusCodes
];
1448 numStatusCodes
+= evInfo
->NumStatusCodes
+ 1;
1451 secTrust
->_legacy_info_array
= infoArray
;
1452 secTrust
->_legacy_status_array
= statusArray
;
1454 if (inputCertArray
) {
1455 CFRelease(inputCertArray
);
1457 if (inputAnchorArray
) {
1458 CFRelease(inputAnchorArray
);
1461 return (CSSM_TP_APPLE_EVIDENCE_INFO
*)secTrust
->_legacy_info_array
;
1466 static CFStringRef kSecCertificateDetailSHA1Digest
= CFSTR("SHA1Digest");
1467 static CFStringRef kSecCertificateDetailStatusCodes
= CFSTR("StatusCodes");
1470 _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
)
1474 SInt32 num
= statusCode
;
1475 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
1478 CFArrayAppendValue(array
, numRef
);
1484 CFArrayRef
SecTrustCopyDetails(SecTrustRef trust
)
1486 // This function returns an array of dictionaries, one per certificate,
1487 // holding status info for each certificate in the evaluated chain.
1489 CFIndex count
, chainLen
= 0;
1490 CFArrayRef certChain
= NULL
;
1491 CFMutableArrayRef details
= NULL
;
1492 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1493 OSStatus __secapiresult
= errSecSuccess
;
1495 Trust
*trustObj
= Trust::required(trust
);
1496 if (trustObj
->result() == kSecTrustResultInvalid
) {
1497 trustObj
->evaluate();
1498 if (trustObj
->result() == kSecTrustResultInvalid
)
1499 MacOSError::throwMe(errSecTrustNotAvailable
);
1501 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
1503 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1504 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1505 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1506 catch (...) { __secapiresult
=errSecInternalComponent
; }
1509 chainLen
= CFArrayGetCount(certChain
);
1510 CFRelease(certChain
);
1513 details
= CFArrayCreateMutable(NULL
, chainLen
, &kCFTypeArrayCallBacks
);
1514 for (count
= 0; count
< chainLen
; count
++) {
1515 CFMutableDictionaryRef certDict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
1516 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1517 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
1518 0, &kCFTypeArrayCallBacks
);
1519 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &statusChain
[count
];
1520 CSSM_TP_APPLE_CERT_STATUS statBits
= evInfo
->StatusBits
;
1522 // translate status bits
1523 if (statBits
& CSSM_CERT_STATUS_EXPIRED
)
1524 _AppendStatusCode(statusCodes
, errSecCertificateExpired
);
1525 if (statBits
& CSSM_CERT_STATUS_NOT_VALID_YET
)
1526 _AppendStatusCode(statusCodes
, errSecCertificateNotValidYet
);
1527 if (statBits
& CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
)
1528 _AppendStatusCode(statusCodes
, errSecTrustSettingDeny
);
1530 // translate status codes
1532 for (i
= 0; i
< evInfo
->NumStatusCodes
; i
++) {
1533 CSSM_RETURN scode
= evInfo
->StatusCodes
[i
];
1534 _AppendStatusCode(statusCodes
, (OSStatus
)scode
);
1537 CFDictionarySetValue(certDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
1538 CFRelease(statusCodes
);
1539 CFArrayAppendValue(details
, certDict
);
1540 CFRelease(certDict
);
1548 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
)
1550 CFArrayRef exceptions
= NULL
;
1551 OSStatus __secapiresult
= errSecSuccess
;
1553 exceptions
= Trust::required(trust
)->exceptions();
1555 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1556 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1557 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1558 catch (...) { __secapiresult
=errSecInternalComponent
; }
1560 if (!exceptions
|| ix
>= CFArrayGetCount(exceptions
))
1562 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1563 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID())
1566 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1570 /* If the exception contains the current certificate's sha1Digest in the
1571 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
1572 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
1573 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
1574 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
1582 static void SecTrustCheckException(const void *key
, const void *value
, void *context
)
1584 struct SecTrustCheckExceptionContext
*cec
= (struct SecTrustCheckExceptionContext
*)context
;
1585 if (cec
->exception
) {
1586 CFTypeRef exceptionValue
= CFDictionaryGetValue(cec
->exception
, key
);
1587 if (!exceptionValue
|| !CFEqual(value
, exceptionValue
)) {
1588 cec
->exceptionNotFound
= true;
1591 cec
->exceptionNotFound
= true;
1598 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
)
1600 CFArrayRef details
= SecTrustCopyDetails(trust
);
1601 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
1602 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
,
1603 pathLength
, &kCFTypeArrayCallBacks
);
1605 for (ix
= 0; ix
< pathLength
; ++ix
) {
1606 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
1607 CFIndex detailCount
= CFDictionaryGetCount(detail
);
1608 CFMutableDictionaryRef exception
;
1609 if (ix
== 0 || detailCount
> 0) {
1610 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
,
1611 detailCount
+ 1, detail
);
1612 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
1613 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
1615 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
1618 /* Add empty exception dictionaries for non leaf certs which have no exceptions
1621 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
,
1623 &kCFTypeDictionaryKeyCallBacks
,
1624 &kCFTypeDictionaryValueCallBacks
);
1626 CFArrayAppendValue(exceptions
, exception
);
1627 CFReleaseNull(exception
);
1629 CFReleaseSafe(details
);
1631 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1632 since it will never be empty). */
1633 for (ix
= pathLength
; ix
-- > 1;) {
1634 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
1635 if (CFDictionaryGetCount(exception
) == 0) {
1636 CFArrayRemoveValueAtIndex(exceptions
, ix
);
1642 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
1643 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
1644 CFRelease(exceptions
);
1646 return encodedExceptions
;
1652 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
)
1654 CFArrayRef exceptions
= NULL
;
1656 if (NULL
!= encodedExceptions
) {
1657 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
1658 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
1661 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
1662 CFRelease(exceptions
);
1666 OSStatus __secapiresult
= errSecSuccess
;
1668 /* Exceptions are being set or cleared, we'll need to re-evaluate trust either way. */
1669 Trust::required(trust
)->setResult(kSecTrustResultInvalid
);
1670 Trust::required(trust
)->exceptions(exceptions
);
1672 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1673 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1674 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1675 catch (...) { __secapiresult
=errSecInternalComponent
; }
1677 /* If there is a valid exception entry for our current leaf we're golden. */
1678 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
1681 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1683 Trust::required(trust
)->exceptions(NULL
);
1684 __secapiresult
= errSecSuccess
;
1686 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1687 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1688 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1689 catch (...) { __secapiresult
=errSecInternalComponent
; }
1698 SecTrustCopyResult(SecTrustRef trust
)
1700 CFDictionaryRef result
= NULL
;
1702 result
= Trust::required(trust
)->results();
1703 // merge details into result
1704 CFArrayRef details
= SecTrustCopyDetails(trust
);
1706 CFDictionarySetValue((CFMutableDictionaryRef
)result
,
1707 kSecTrustResultDetails
, details
);
1724 SecTrustCopyProperties(SecTrustRef trust
)
1726 /* can't use SECAPI macros, since this function does not return OSStatus */
1727 CFArrayRef result
= NULL
;
1729 result
= Trust::required(trust
)->properties();
1740 CFArrayRef
SecTrustCopyProperties(SecTrustRef trust
) {
1741 /* OS X creates a completely different structure with one dictionary for each certificate */
1742 CFIndex ix
, count
= SecTrustGetCertificateCount(trust
);
1744 CFMutableArrayRef properties
= CFArrayCreateMutable(kCFAllocatorDefault
, count
,
1745 &kCFTypeArrayCallBacks
);
1747 for (ix
= 0; ix
< count
; ix
++) {
1748 CFMutableDictionaryRef certDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
1749 &kCFTypeDictionaryValueCallBacks
);
1750 /* Populate the certificate title */
1751 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, ix
);
1753 CFStringRef subjectSummary
= SecCertificateCopySubjectSummary(cert
);
1754 if (subjectSummary
) {
1755 CFDictionaryAddValue(certDict
, kSecPropertyTypeTitle
, subjectSummary
);
1756 CFRelease(subjectSummary
);
1760 /* Populate a revocation reason if the cert was revoked */
1761 unsigned int numStatusCodes
;
1762 CSSM_RETURN
*statusCodes
= NULL
;
1763 statusCodes
= copyCssmStatusCodes(trust
, (uint32_t)ix
, &numStatusCodes
);
1765 int32_t reason
= statusCodes
[numStatusCodes
]; // stored at end of status codes array
1767 CFNumberRef cfreason
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
);
1769 CFDictionarySetValue(certDict
, kSecTrustRevocationReason
, cfreason
);
1770 CFRelease(cfreason
);
1776 /* Populate the error in the leaf dictionary */
1778 OSStatus error
= errSecSuccess
;
1779 (void)SecTrustGetCssmResultCode(trust
, &error
);
1780 CFStringRef errorStr
= SecCopyErrorMessageString(error
, NULL
);
1782 CFDictionarySetValue(certDict
, kSecPropertyTypeError
, errorStr
);
1783 CFRelease(errorStr
);
1787 CFArrayAppendValue(properties
, certDict
);
1794 /* deprecated in 10.5 */
1795 OSStatus
SecTrustGetCSSMAnchorCertificates(const CSSM_DATA
**cssmAnchors
,
1796 uint32
*cssmAnchorCount
)
1801 Trust::gStore().getCssmRootCertificates(certs
);
1802 Required(cssmAnchors
) = certs
.blobCerts();
1803 Required(cssmAnchorCount
) = certs
.count();
1806 /* this function is unsupported in unified SecTrust */
1807 #if SECTRUST_DEPRECATION_WARNINGS
1808 syslog(LOG_ERR
, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
1811 *cssmAnchors
= NULL
;
1813 if (cssmAnchorCount
) {
1814 *cssmAnchorCount
= 0;
1816 return errSecServiceNotAvailable
;
1822 // Get and set user trust settings. Deprecated in 10.5.
1823 // User Trust getter, deprecated, works as it always has.
1825 OSStatus
SecTrustGetUserTrust(SecCertificateRef certificate
,
1826 SecPolicyRef policy
, SecTrustUserSetting
*trustSetting
)
1830 StorageManager::KeychainList searchList
;
1831 globals().storageManager
.getSearchList(searchList
);
1832 Required(trustSetting
) = Trust::gStore().find(
1833 Certificate::required(certificate
),
1834 Policy::required(policy
),
1838 /* this function is unsupported in unified SecTrust */
1839 #if SECTRUST_DEPRECATION_WARNINGS
1840 syslog(LOG_ERR
, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
1842 return errSecServiceNotAvailable
;
1847 // The public setter, also deprecated; it maps to the appropriate
1848 // Trust Settings call if possible, else throws errSecUnimplemented.
1850 OSStatus
SecTrustSetUserTrust(SecCertificateRef certificate
,
1851 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
1854 SecTrustSettingsResult tsResult
= kSecTrustSettingsResultInvalid
;
1858 Policy::required(policy
);
1859 switch(trustSetting
) {
1860 case kSecTrustResultProceed
:
1861 /* different SecTrustSettingsResult depending in root-ness */
1862 ortn
= SecCertificateIsSelfSigned(certificate
, &isRoot
);
1867 tsResult
= kSecTrustSettingsResultTrustRoot
;
1870 tsResult
= kSecTrustSettingsResultTrustAsRoot
;
1873 case kSecTrustResultDeny
:
1874 tsResult
= kSecTrustSettingsResultDeny
;
1877 return errSecUnimplemented
;
1880 /* make a usage constraints dictionary */
1881 CFRef
<CFMutableDictionaryRef
> usageDict(CFDictionaryCreateMutable(NULL
,
1882 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
1883 CFDictionaryAddValue(usageDict
, kSecTrustSettingsPolicy
, policy
);
1884 if(tsResult
!= kSecTrustSettingsResultTrustRoot
) {
1885 /* skip if we're specifying the default */
1886 SInt32 result
= tsResult
;
1887 CFNumberRef cfNum
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &result
);
1888 CFDictionarySetValue(usageDict
, kSecTrustSettingsResult
, cfNum
);
1891 return SecTrustSettingsSetTrustSettings(certificate
, kSecTrustSettingsDomainUser
,
1894 /* this function is unsupported in unified SecTrust */
1895 #if SECTRUST_DEPRECATION_WARNINGS
1896 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
1898 return errSecServiceNotAvailable
;
1903 // This one is the now-private version of what SecTrustSetUserTrust() used to
1904 // be. The public API can no longer manipulate User Trust settings, only
1907 OSStatus
SecTrustSetUserTrustLegacy(SecCertificateRef certificate
,
1908 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
1912 switch (trustSetting
) {
1913 case kSecTrustResultProceed
:
1914 case kSecTrustResultConfirm
:
1915 case kSecTrustResultDeny
:
1916 case kSecTrustResultUnspecified
:
1919 MacOSError::throwMe(errSecInvalidTrustSetting
);
1921 Trust::gStore().assign(
1922 Certificate::required(certificate
),
1923 Policy::required(policy
),
1927 /* this function is unsupported in unified SecTrust */
1928 #if SECTRUST_DEPRECATION_WARNINGS
1929 syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
1931 return errSecServiceNotAvailable
;