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 "SecTrustSettings.h" 
  31 #include "SecTrustSettingsPriv.h" 
  32 #include "SecCertificatePriv.h" 
  33 #include "SecCertificateP.h" 
  34 #include "SecCertificatePrivP.h" 
  35 #include "SecPolicyPriv.h" 
  36 #include <security_utilities/cfutilities.h> 
  37 #include <security_utilities/cfmunge.h> 
  38 #include <CoreFoundation/CoreFoundation.h> 
  41 // forward declarations 
  42 CFArrayRef 
SecTrustCopyInputCertificates(SecTrustRef trust
); 
  43 CFArrayRef 
SecTrustCopyInputAnchors(SecTrustRef trust
); 
  44 CFArrayRef 
SecTrustCopyConstructedChain(SecTrustRef trust
); 
  45 static CSSM_TP_APPLE_EVIDENCE_INFO 
* SecTrustGetEvidenceInfo(SecTrustRef trust
); 
  47 typedef struct SecTrustCheckExceptionContext 
{ 
  48         CFDictionaryRef exception
; 
  49         bool exceptionNotFound
; 
  50 } SecTrustCheckExceptionContext
; 
  52 // public trust result constants 
  53 const CFStringRef kSecTrustEvaluationDate           
= CFSTR("TrustEvaluationDate"); 
  54 const CFStringRef kSecTrustExtendedValidation       
= CFSTR("TrustExtendedValidation"); 
  55 const CFStringRef kSecTrustOrganizationName         
= CFSTR("Organization"); 
  56 const CFStringRef kSecTrustResultValue              
= CFSTR("TrustResultValue"); 
  57 const CFStringRef kSecTrustRevocationChecked        
= CFSTR("TrustRevocationChecked"); 
  58 const CFStringRef kSecTrustRevocationReason         
= CFSTR("TrustRevocationReason"); 
  59 const CFStringRef kSecTrustRevocationValidUntilDate 
= CFSTR("TrustExpirationDate"); 
  60 const CFStringRef kSecTrustResultDetails            
= CFSTR("TrustResultDetails"); 
  62 // Policy check string to CSSM_RETURN mapping 
  64 struct resultmap_entry_s 
{ 
  65         const CFStringRef checkstr
; 
  66         const CSSM_RETURN resultcode
; 
  68 typedef struct resultmap_entry_s resultmap_entry_t
; 
  70 const resultmap_entry_t cssmresultmap
[] = { 
  71     { CFSTR("SSLHostname"), CSSMERR_APPLETP_HOSTNAME_MISMATCH 
}, 
  72     { CFSTR("email"), CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND 
}, 
  73     { CFSTR("IssuerCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING 
}, 
  74     { CFSTR("SubjectCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING 
}, 
  75     { CFSTR("SubjectCommonNamePrefix"), CSSMERR_APPLETP_IDENTIFIER_MISSING 
}, 
  76     { CFSTR("SubjectCommonNameTEST"), CSSMERR_APPLETP_IDENTIFIER_MISSING 
}, 
  77     { CFSTR("SubjectOrganization"), CSSMERR_APPLETP_IDENTIFIER_MISSING 
}, 
  78     { CFSTR("SubjectOrganizationalUnit"), CSSMERR_APPLETP_IDENTIFIER_MISSING 
}, 
  79     { CFSTR("EAPTrustedServerNames"), CSSMERR_APPLETP_HOSTNAME_MISMATCH 
}, 
  80     { CFSTR("CertificatePolicy"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION 
}, 
  81     { CFSTR("KeyUsage"), CSSMERR_APPLETP_INVALID_KEY_USAGE 
}, 
  82     { CFSTR("ExtendedKeyUsage"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE 
}, 
  83     { CFSTR("BasicConstraints"), CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS 
}, 
  84     { CFSTR("QualifiedCertStatements"), CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT 
}, 
  85     { CFSTR("IntermediateSPKISHA256"), CSSMERR_APPLETP_IDENTIFIER_MISSING 
}, 
  86     { CFSTR("IntermediateEKU"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE 
}, 
  87     { CFSTR("AnchorSHA1"), CSSMERR_TP_NOT_TRUSTED 
}, 
  88     { CFSTR("AnchorSHA256"), CSSMERR_TP_NOT_TRUSTED 
}, 
  89     { CFSTR("AnchorTrusted"), CSSMERR_TP_NOT_TRUSTED 
}, 
  90     { CFSTR("AnchorApple"), CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH 
}, 
  91     { CFSTR("NonEmptySubject"), CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT 
}, 
  92     { CFSTR("IdLinkage"), CSSMERR_APPLETP_INVALID_AUTHORITY_ID 
}, 
  93     { CFSTR("WeakIntermediates"), CSSMERR_TP_INVALID_CERTIFICATE 
}, 
  94     { CFSTR("WeakLeaf"), CSSMERR_TP_INVALID_CERTIFICATE 
}, 
  95     { CFSTR("WeakRoot"), CSSMERR_TP_INVALID_CERTIFICATE 
}, 
  96     { CFSTR("KeySize"), CSSMERR_CSP_UNSUPPORTED_KEY_SIZE 
}, 
  97     { CFSTR("SignatureHashAlgorithms"), CSSMERR_CSP_ALGID_MISMATCH 
}, 
  98     { CFSTR("SystemTrustedWeakHash"), CSSMERR_CSP_INVALID_DIGEST_ALGORITHM 
}, 
  99     { CFSTR("CriticalExtensions"), CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN 
}, 
 100     { CFSTR("ChainLength"), CSSMERR_APPLETP_PATH_LEN_CONSTRAINT 
}, 
 101     { CFSTR("BasicCertificateProcessing"), CSSMERR_TP_INVALID_CERTIFICATE 
}, 
 102     { CFSTR("ExtendedValidation"), CSSMERR_TP_NOT_TRUSTED 
}, 
 103     { CFSTR("Revocation"), CSSMERR_TP_CERT_REVOKED 
}, 
 104     { CFSTR("RevocationResponseRequired"), CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK 
}, 
 105     { CFSTR("CertificateTransparency"), CSSMERR_TP_NOT_TRUSTED 
}, 
 106     { CFSTR("BlackListedLeaf"), CSSMERR_TP_CERT_REVOKED 
}, 
 107     { CFSTR("GrayListedLeaf"), CSSMERR_TP_NOT_TRUSTED 
}, 
 108     { CFSTR("GrayListedKey"), CSSMERR_TP_NOT_TRUSTED 
}, 
 109     { CFSTR("BlackListedKey"), CSSMERR_TP_CERT_REVOKED 
}, 
 110     { CFSTR("CheckLeafMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION 
}, 
 111     { CFSTR("CheckLeafMarkerOidNoValueCheck"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION 
}, 
 112     { CFSTR("CheckIntermediateMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION 
}, 
 113     { CFSTR("UsageConstraints"), CSSMERR_APPLETP_TRUST_SETTING_DENY 
}, 
 114     { CFSTR("NotValidBefore"), CSSMERR_TP_CERT_NOT_VALID_YET 
}, 
 115     { CFSTR("ValidIntermediates"), CSSMERR_TP_CERT_EXPIRED 
}, 
 116     { CFSTR("ValidLeaf"), CSSMERR_TP_CERT_EXPIRED 
}, 
 117     { CFSTR("ValidRoot"), CSSMERR_TP_CERT_EXPIRED 
}, 
 118 //  { CFSTR("AnchorAppleTestRoots"),  }, 
 119 //  { CFSTR("AnchorAppleTestRootsOnProduction"),  }, 
 120 //  { CFSTR("NoNetworkAccess"),  }, 
 125 // Sec* API bridge functions 
 128         SecTrustOptionFlags flags
; 
 130         SecTrustRef trustRef
; 
 131         CFMutableDictionaryRef filteredException
; 
 132         CFDictionaryRef oldException
; 
 133 } SecExceptionFilterContext
; 
 135 // inline function from SecCFWrappers.h 
 136 static inline char *CFStringToCString(CFStringRef inStr
) 
 139         return (char *)strdup(""); 
 140     CFRetain(inStr
);        // compensate for release on exit 
 142     // need to extract into buffer 
 143     CFIndex length 
= CFStringGetLength(inStr
);  // in 16-bit character units 
 144     size_t len 
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
); 
 145     char *buffer 
= (char *)malloc(len
);                 // pessimistic 
 146     if (!CFStringGetCString(inStr
, buffer
, len
, kCFStringEncodingUTF8
)) 
 154 filter_exception(const void *key
, const void *value
, void *context
) 
 156         SecExceptionFilterContext 
*ctx 
= (SecExceptionFilterContext 
*)context
; 
 157         if (!ctx
) { return; } 
 159         SecTrustOptionFlags options 
= ctx
->flags
; 
 160         CFMutableDictionaryRef filteredException 
= ctx
->filteredException
; 
 161         CFStringRef keystr 
= (CFStringRef
)key
; 
 163         if (ctx
->oldException 
&& CFDictionaryContainsKey(ctx
->oldException
, key
)) { 
 164                 // Keep existing exception in filtered dictionary, regardless of options 
 165                 CFDictionaryAddValue(filteredException
, key
, CFDictionaryGetValue(ctx
->oldException
, key
)); 
 169         bool allowed 
= false; 
 171         if (CFEqual(keystr
, CFSTR("SHA1Digest"))) { 
 172                 allowed 
= true; // this key is informational and always permitted 
 174         else if (CFEqual(keystr
, CFSTR("NotValidBefore"))) { 
 175                 allowed 
= ((options 
& kSecTrustOptionAllowExpired
) != 0); 
 177         else if (CFEqual(keystr
, CFSTR("ValidLeaf"))) { 
 178                 allowed 
= ((options 
& kSecTrustOptionAllowExpired
) != 0); 
 180         else if (CFEqual(keystr
, CFSTR("ValidIntermediates"))) { 
 181                 allowed 
= ((options 
& kSecTrustOptionAllowExpired
) != 0); 
 183         else if (CFEqual(keystr
, CFSTR("ValidRoot"))) { 
 184         if (((options 
& kSecTrustOptionAllowExpired
) != 0) || 
 185             ((options 
& kSecTrustOptionAllowExpiredRoot
) != 0)) { 
 189         else if (CFEqual(keystr
, CFSTR("AnchorTrusted"))) { 
 190                 bool implicitAnchors 
= ((options 
& kSecTrustOptionImplicitAnchors
) != 0); 
 191                 // Implicit anchors option only filters exceptions for self-signed certs 
 192                 if (implicitAnchors 
&& ctx
->trustRef 
&& 
 193                     (ctx
->certIX 
< SecTrustGetCertificateCount(ctx
->trustRef
))) { 
 194                         Boolean isSelfSigned 
= false; 
 195                         SecCertificateRef cert 
= SecTrustGetCertificateAtIndex(ctx
->trustRef
, ctx
->certIX
); 
 196                         if (cert 
&& (errSecSuccess 
== SecCertificateIsSelfSigned(cert
, &isSelfSigned
)) && 
 202         else if (CFEqual(keystr
, CFSTR("KeyUsage")) || 
 203                  CFEqual(keystr
, CFSTR("ExtendedKeyUsage")) || 
 204                  CFEqual(keystr
, CFSTR("BasicConstraints")) || 
 205                  CFEqual(keystr
, CFSTR("NonEmptySubject")) || 
 206                  CFEqual(keystr
, CFSTR("IdLinkage"))) { 
 207                 // Cannot override these exceptions 
 211                 // Unhandled exceptions should not be overridden, 
 212                 // but we want to know which ones we're missing 
 213                 char *cstr 
= CFStringToCString(keystr
); 
 214                 syslog(LOG_ERR
, "Unfiltered exception: %s", (cstr
) ? cstr 
: "<NULL>"); 
 215                 if (cstr
) { free(cstr
); } 
 220                 CFDictionaryAddValue(filteredException
, key
, value
); 
 224 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ 
 226 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
) 
 228         /* bridge to support API functionality for legacy callers */ 
 229         OSStatus status 
= errSecSuccess
; 
 230         CFDataRef encodedExceptions 
= SecTrustCopyExceptions(trustRef
); 
 231         CFArrayRef exceptions 
= NULL
, 
 232             oldExceptions 
= SecTrustGetTrustExceptionsArray(trustRef
); 
 234         if (encodedExceptions
) { 
 235                 exceptions 
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
, 
 236                         encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
); 
 237                 CFRelease(encodedExceptions
); 
 238                 encodedExceptions 
= NULL
; 
 241         if (exceptions 
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) { 
 242                 CFRelease(exceptions
); 
 246         if (oldExceptions 
&& exceptions 
&& 
 247                 CFArrayGetCount(oldExceptions
) > CFArrayGetCount(exceptions
)) { 
 248                 oldExceptions 
= NULL
; 
 251         /* verify both exceptions are for the same leaf */ 
 252         if (oldExceptions 
&& exceptions 
&& CFArrayGetCount(oldExceptions
) > 0) { 
 253                 CFDictionaryRef oldLeafExceptions 
= (CFDictionaryRef
)CFArrayGetValueAtIndex(oldExceptions
, 0); 
 254                 CFDictionaryRef leafExceptions 
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, 0); 
 255                 CFDataRef oldDigest 
= (CFDataRef
)CFDictionaryGetValue(oldLeafExceptions
, CFSTR("SHA1Digest")); 
 256                 CFDataRef digest 
= (CFDataRef
)CFDictionaryGetValue(leafExceptions
, CFSTR("SHA1Digest")); 
 257                 if (!oldDigest 
|| !digest 
|| !CFEqual(oldDigest
, digest
)) { 
 258                         oldExceptions 
= NULL
; 
 262         /* add only those exceptions which are allowed by the supplied options */ 
 264                 CFMutableArrayRef filteredExceptions 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 265                 CFIndex i
, exceptionCount 
= (filteredExceptions
) ? CFArrayGetCount(exceptions
) : 0; 
 267                 for (i 
= 0; i 
< exceptionCount
; ++i
) { 
 268                         CFDictionaryRef exception 
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, i
); 
 269                         CFDictionaryRef oldException 
= NULL
; 
 270                         if (oldExceptions 
&& i 
< CFArrayGetCount(oldExceptions
)) { 
 271                                 oldException 
= (CFDictionaryRef
)CFArrayGetValueAtIndex(oldExceptions
, i
); 
 273                         CFMutableDictionaryRef filteredException 
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, 
 274                                                                                                                                                                  &kCFTypeDictionaryValueCallBacks
); 
 275                         if (exception 
&& filteredException
) { 
 276                                 SecExceptionFilterContext filterContext 
= { options
, i
, trustRef
, filteredException
, oldException 
}; 
 277                                 CFDictionaryApplyFunction(exception
, filter_exception
, &filterContext
); 
 278                                 CFArrayAppendValue(filteredExceptions
, filteredException
); 
 279                                 CFRelease(filteredException
); 
 283                 if (filteredExceptions
) { 
 284                         CFIndex filteredCount 
= CFArrayGetCount(filteredExceptions
); 
 285                         /* remove empty trailing entries to match iOS behavior */ 
 286                         for (i 
= filteredCount
; i
-- > 1;) { 
 287                                 CFDictionaryRef exception 
= (CFDictionaryRef
)CFArrayGetValueAtIndex(filteredExceptions
, i
); 
 288                                 if (CFDictionaryGetCount(exception
) == 0) { 
 289                                         CFArrayRemoveValueAtIndex(filteredExceptions
, i
); 
 294                         encodedExceptions 
= CFPropertyListCreateData(kCFAllocatorDefault
, 
 295                                 filteredExceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
); 
 296                         CFRelease(filteredExceptions
); 
 298                         SecTrustSetExceptions(trustRef
, encodedExceptions
); 
 299                         CFRelease(encodedExceptions
); 
 301                 CFRelease(exceptions
); 
 304 #if SECTRUST_DEPRECATION_WARNINGS 
 305         bool displayModifyMsg 
= false; 
 306         bool displayNetworkMsg 
= false; 
 307         bool displayPolicyMsg 
= false; 
 308         const char *baseMsg 
= "WARNING: SecTrustSetOptions called with"; 
 309         const char *modifyMsg 
= "Use SecTrustSetExceptions and SecTrustCopyExceptions to modify default trust results."; 
 310         const char *networkMsg 
= "Use SecTrustSetNetworkFetchAllowed to specify whether missing certificates can be fetched from the network."; 
 311         const char *policyMsg 
= "Use SecPolicyCreateRevocation to specify revocation policy requirements."; 
 313         if (options 
& kSecTrustOptionAllowExpired
) { 
 314                 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionAllowExpired"); 
 315                 displayModifyMsg 
= true; 
 317         if (options 
& kSecTrustOptionAllowExpiredRoot
) { 
 318                 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionAllowExpiredRoot"); 
 319                 displayModifyMsg 
= true; 
 321         if (options 
& kSecTrustOptionFetchIssuerFromNet
) { 
 322                 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionFetchIssuerFromNet"); 
 323                 displayNetworkMsg 
= true; 
 325         if (options 
& kSecTrustOptionRequireRevPerCert
) { 
 326                 syslog(LOG_ERR
, "%s %s.", baseMsg
, "kSecTrustOptionRequireRevPerCert"); 
 327                 displayPolicyMsg 
= true; 
 329         if (displayModifyMsg 
|| displayNetworkMsg 
|| displayPolicyMsg
) { 
 330                 syslog(LOG_ERR
, "%s %s %s", 
 331                         (displayModifyMsg
) ? modifyMsg 
: "", 
 332                         (displayNetworkMsg
) ? networkMsg 
: "", 
 333                         (displayPolicyMsg
) ? policyMsg 
: ""); 
 340 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ 
 341 OSStatus 
SecTrustSetParameters( 
 342     SecTrustRef trustRef
, 
 343     CSSM_TP_ACTION action
, 
 344     CFDataRef actionData
) 
 346         /* bridge to support API functionality for legacy callers */ 
 348         CSSM_APPLE_TP_ACTION_FLAGS actionFlags 
= 0; 
 350                 CSSM_APPLE_TP_ACTION_DATA 
*actionDataPtr 
= (CSSM_APPLE_TP_ACTION_DATA 
*) CFDataGetBytePtr(actionData
); 
 352                         actionFlags 
= actionDataPtr
->ActionFlags
; 
 355         // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS; 
 356         // both are sizeof(uint32) and the flag values have identical meanings 
 357     status 
= SecTrustSetOptions(trustRef
, (SecTrustOptionFlags
)actionFlags
); 
 359 #if SECTRUST_DEPRECATION_WARNINGS 
 360         syslog(LOG_ERR
, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead."); 
 366 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */ 
 367 OSStatus 
SecTrustSetKeychains(SecTrustRef trust
, CFTypeRef keychainOrArray
) 
 369         /* this function is currently unsupported in unified SecTrust */ 
 370     // TODO: pull all certs out of the specified keychains for the evaluation? 
 371 #if SECTRUST_DEPRECATION_WARNINGS 
 372         syslog(LOG_ERR
, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors."); 
 374         return errSecSuccess
; 
 378 // Construct the "official" result evidence and return it 
 380 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ 
 381 OSStatus 
SecTrustGetResult( 
 382     SecTrustRef trustRef
, 
 383     SecTrustResultType 
*result
, 
 384         CFArrayRef 
*certChain
, CSSM_TP_APPLE_EVIDENCE_INFO 
**statusChain
) 
 386         /* bridge to support old functionality */ 
 387 #if SECTRUST_DEPRECATION_WARNINGS 
 388         syslog(LOG_ERR
, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead."); 
 390     SecTrustResultType trustResult
; 
 391     OSStatus status 
= SecTrustGetTrustResult(trustRef
, &trustResult
); 
 392     if (status 
!= errSecSuccess
) { 
 396                 *result 
= trustResult
; 
 399         *certChain 
= SecTrustCopyConstructedChain(trustRef
); 
 402         *statusChain 
= SecTrustGetEvidenceInfo(trustRef
); 
 408 // Retrieve extended validation trust results 
 410 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */ 
 411 OSStatus 
SecTrustCopyExtendedResult(SecTrustRef trust
, CFDictionaryRef 
*result
) 
 413         /* bridge to support old functionality */ 
 414 #if SECTRUST_DEPRECATION_WARNINGS 
 415     syslog(LOG_ERR
, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead."); 
 417         CFDictionaryRef resultDict 
= SecTrustCopyResult(trust
); 
 419         CFReleaseNull(resultDict
); 
 422         *result 
= resultDict
; 
 423         return errSecSuccess
; 
 427 // Retrieve CSSM-level information for those who want to dig down 
 429 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ 
 430 OSStatus 
SecTrustGetCssmResult(SecTrustRef trust
, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR 
*result
) 
 432         /* this function is unsupported in unified SecTrust */ 
 433 #if SECTRUST_DEPRECATION_WARNINGS 
 434         syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead."); 
 439         return errSecServiceNotAvailable
; 
 443 // Returns a malloced array of CSSM_RETURN values, with the length in numStatusCodes, 
 444 // for the certificate specified by chain index in the given SecTrustRef. 
 446 // To match legacy behavior, the array actually allocates one element more than the 
 447 // value of numStatusCodes; if the certificate is revoked, the additional element 
 448 // at the end contains the CrlReason value. 
 450 // Caller must free the returned pointer. 
 452 static CSSM_RETURN 
*copyCssmStatusCodes(SecTrustRef trust
, 
 453         unsigned int index
, unsigned int *numStatusCodes
) 
 455         if (!trust 
|| !numStatusCodes
) { 
 459         CFArrayRef details 
= SecTrustCopyFilteredDetails(trust
); 
 460         CFIndex chainLength 
= (details
) ? CFArrayGetCount(details
) : 0; 
 461         if (!(index 
< chainLength
)) { 
 462                 CFReleaseSafe(details
); 
 465         CFDictionaryRef detail 
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, index
); 
 466         CFIndex ix
, detailCount 
= CFDictionaryGetCount(detail
); 
 467         *numStatusCodes 
= (unsigned int)detailCount
; 
 469         // Allocate one more entry than we need; this is used to store a CrlReason 
 470         // at the end of the array. 
 471         CSSM_RETURN 
*statusCodes 
= (CSSM_RETURN
*)malloc((detailCount
+1) * sizeof(CSSM_RETURN
)); 
 472         statusCodes
[*numStatusCodes
] = 0; 
 474         const unsigned int resultmaplen 
= sizeof(cssmresultmap
) / sizeof(resultmap_entry_t
); 
 475         const void *keys
[detailCount
]; 
 476         CFDictionaryGetKeysAndValues(detail
, &keys
[0], NULL
); 
 477         for (ix 
= 0; ix 
< detailCount
; ix
++) { 
 478                 CFStringRef key 
= (CFStringRef
)keys
[ix
]; 
 479                 CSSM_RETURN statusCode 
= CSSM_OK
; 
 480                 for (unsigned int mapix 
= 0; mapix 
< resultmaplen
; mapix
++) { 
 481                         CFStringRef str 
= (CFStringRef
) cssmresultmap
[mapix
].checkstr
; 
 482                         if (CFStringCompare(str
, key
, 0) == kCFCompareEqualTo
) { 
 483                                 statusCode 
= (CSSM_RETURN
) cssmresultmap
[mapix
].resultcode
; 
 487                 if (statusCode 
== CSSMERR_TP_CERT_REVOKED
) { 
 489                         CFNumberRef number 
= (CFNumberRef
)CFDictionaryGetValue(detail
, key
); 
 490                         if (number 
&& CFNumberGetValue(number
, kCFNumberSInt32Type
, &reason
)) { 
 491                                 statusCodes
[*numStatusCodes
] = (CSSM_RETURN
)reason
; 
 494                 statusCodes
[ix
] = statusCode
; 
 497         CFReleaseSafe(details
); 
 501 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode
) { 
 502     switch (resultCode
) { 
 503         /* explicitly not trusted */ 
 504         case CSSMERR_TP_CERT_REVOKED
: 
 505         case CSSMERR_APPLETP_TRUST_SETTING_DENY
: 
 507         /* failure to comply with X.509 */ 
 508         case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
: 
 509         case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
: 
 510         case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
: 
 511         case CSSMERR_APPLETP_INVALID_AUTHORITY_ID
: 
 512         case CSSMERR_TP_INVALID_CERTIFICATE
: 
 513         case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
: 
 515         case CSSMERR_TP_CERT_EXPIRED
: 
 517         /* doesn't chain to trusted root */ 
 518         case CSSMERR_TP_NOT_TRUSTED
: 
 519         case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
: 
 521         /* all others are policy-specific failures */ 
 527 #include <libDER/oidsPriv.h> 
 528 #include <Security/oidscert.h> 
 529 static bool isSoftwareUpdateDevelopment(SecTrustRef trust
) { 
 530     bool isPolicy 
= false, isEKU 
= false; 
 531     CFArrayRef policies 
= NULL
; 
 533     /* Policy used to evaluate was SWUpdateSigning */ 
 534     SecTrustCopyPolicies(trust
, &policies
); 
 536         SecPolicyRef swUpdatePolicy 
= SecPolicyCreateAppleSWUpdateSigning(); 
 537         if (swUpdatePolicy 
&& CFArrayContainsValue(policies
, CFRangeMake(0, CFArrayGetCount(policies
)), 
 541         if (swUpdatePolicy
) { CFRelease(swUpdatePolicy
); } 
 548     /* Only error was EKU on the leaf */ 
 549     CFArrayRef details 
= SecTrustCopyFilteredDetails(trust
); 
 550     CFIndex ix
, count 
= CFArrayGetCount(details
); 
 551     bool hasDisqualifyingError 
= false; 
 552     for (ix 
= 0; ix 
< count
; ix
++) { 
 553         CFDictionaryRef detail 
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
); 
 554         if (ix 
== 0) { // Leaf 
 555             if (CFDictionaryGetCount(detail
) != 1 || // One error 
 556                 CFDictionaryGetValue(detail
, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse
) { // kSecPolicyCheckExtendedKeyUsage 
 557                 hasDisqualifyingError 
= true; 
 561             if (CFDictionaryGetCount(detail
) > 0) { // No errors on other certs 
 562                 hasDisqualifyingError 
= true; 
 567     CFReleaseSafe(details
); 
 568     if (hasDisqualifyingError
) { 
 572     /* EKU on the leaf is the Apple Development Code Signing OID */ 
 573     SecCertificateRef leaf 
= SecTrustGetCertificateAtIndex(trust
, 0); 
 574     CSSM_DATA 
*fieldValue 
= NULL
; 
 575     if (errSecSuccess 
!= SecCertificateCopyFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, &fieldValue
)) { 
 578     if (fieldValue 
&& fieldValue
->Data 
&& fieldValue
->Length 
== sizeof(CSSM_X509_EXTENSION
)) { 
 579         const CSSM_X509_EXTENSION 
*ext 
= (const CSSM_X509_EXTENSION 
*)fieldValue
->Data
; 
 580         if (ext
->format 
== CSSM_X509_DATAFORMAT_PARSED
) { 
 581             const CE_ExtendedKeyUsage 
*ekus 
= (const CE_ExtendedKeyUsage 
*)ext
->value
.parsedValue
; 
 582             if (ekus 
&& (ekus
->numPurposes 
== 1) && ekus
->purposes
[0].Data 
&& 
 583                 (ekus
->purposes
[0].Length 
== CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Length
) && 
 584                 (memcmp(ekus
->purposes
[0].Data
, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
.Data
, 
 585                         ekus
->purposes
[0].Length
) == 0)) { 
 590     SecCertificateReleaseFirstFieldValue(leaf
, &CSSMOID_ExtendedKeyUsage
, fieldValue
); 
 595 // Retrieve CSSM_LEVEL TP return code 
 597 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ 
 598 OSStatus 
SecTrustGetCssmResultCode(SecTrustRef trustRef
, OSStatus 
*result
) 
 600         /* bridge to support old functionality */ 
 601 #if SECTRUST_DEPRECATION_WARNINGS 
 602     syslog(LOG_ERR
, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead."); 
 604         if (!trustRef 
|| !result
) { 
 608     SecTrustResultType trustResult 
= kSecTrustResultInvalid
; 
 609     (void) SecTrustGetTrustResult(trustRef
, &trustResult
); 
 610     if (trustResult 
== kSecTrustResultProceed 
|| trustResult 
== kSecTrustResultUnspecified
) { 
 611         if (result
) { *result 
= 0; } 
 612         return errSecSuccess
; 
 615     /* Development Software Update certs return a special error code when evaluated 
 616      * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */ 
 617     if (isSoftwareUpdateDevelopment(trustRef
)) { 
 619             *result 
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
; 
 621         return errSecSuccess
; 
 624     OSStatus cssmResultCode 
= errSecSuccess
; 
 625     uint8_t resultCodePriority 
= 0xFF; 
 626     CFIndex ix
, count 
= SecTrustGetCertificateCount(trustRef
); 
 627     for (ix 
= 0; ix 
< count
; ix
++) { 
 628         unsigned int numStatusCodes
; 
 629         CSSM_RETURN 
*statusCodes 
= NULL
; 
 630         statusCodes 
= copyCssmStatusCodes(trustRef
, (uint32_t)ix
, &numStatusCodes
); 
 631         if (statusCodes 
&& numStatusCodes 
> 0) { 
 632             unsigned int statusIX
; 
 633             for (statusIX 
= 0; statusIX 
< numStatusCodes
; statusIX
++) { 
 634                 CSSM_RETURN currStatus 
= statusCodes
[statusIX
]; 
 635                 uint8_t currPriority 
= convertCssmResultToPriority(currStatus
); 
 636                 if (resultCodePriority 
> currPriority
) { 
 637                     cssmResultCode 
= currStatus
; 
 638                     resultCodePriority 
= currPriority
; 
 642         if (statusCodes
) { free(statusCodes
); } 
 643         if (resultCodePriority 
== 1) { break; } 
 647                 *result 
= cssmResultCode
; 
 649         return errSecSuccess
; 
 652 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ 
 653 OSStatus 
SecTrustGetTPHandle(SecTrustRef trust
, CSSM_TP_HANDLE 
*handle
) 
 655         /* this function is unsupported in unified SecTrust */ 
 656 #if SECTRUST_DEPRECATION_WARNINGS 
 657         syslog(LOG_ERR
, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it."); 
 662         return errSecServiceNotAvailable
; 
 666 // Get the user's default anchor certificate set 
 669 OSStatus 
SecTrustCopyAnchorCertificates(CFArrayRef 
*anchorCertificates
) 
 673         return SecTrustSettingsCopyUnrestrictedRoots( 
 674                         true, true, true,               /* all domains */ 
 680 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef. 
 682 SecKeyRef 
SecTrustCopyPublicKey(SecTrustRef trust
) 
 684         SecKeyRef pubKey 
= NULL
; 
 685         SecCertificateRef certificate 
= SecTrustGetCertificateAtIndex(trust
, 0); 
 686         (void) SecCertificateCopyPublicKey(certificate
, &pubKey
); 
 690 // cannot link against the new iOS SecTrust from this implementation, 
 691 // so there are no possible accessors for the fields of this struct 
 692 typedef struct __TSecTrust 
{ 
 694     CFArrayRef              _certificates
; 
 697     CFArrayRef              _responses
; 
 699     CFArrayRef              _trustedLogs
; 
 700     CFDateRef               _verifyDate
; 
 702     SecKeyRef               _publicKey
; 
 704     CFDictionaryRef         _info
; 
 705     CFArrayRef              _exceptions
; 
 706     SecTrustResultType      _trustResult
; 
 708     bool                    _keychainsAllowed
; 
 709     void*                   _legacy_info_array
; 
 710     void*                   _legacy_status_array
; 
 711     SecTrustResultType      _trustResultBeforeExceptions
; 
 712     dispatch_queue_t        _trustQueue
; 
 715 CFArrayRef 
SecTrustCopyInputCertificates(SecTrustRef trust
) 
 717         if (!trust
) { return NULL
; }; 
 718         TSecTrust 
*secTrust 
= (TSecTrust 
*)trust
; 
 719         if (secTrust
->_certificates
) { 
 720                 CFRetain(secTrust
->_certificates
); 
 722         return secTrust
->_certificates
; 
 725 CFArrayRef 
SecTrustCopyInputAnchors(SecTrustRef trust
) 
 727         if (!trust
) { return NULL
; }; 
 728         TSecTrust 
*secTrust 
= (TSecTrust 
*)trust
; 
 729         if (secTrust
->_anchors
) { 
 730                 CFRetain(secTrust
->_anchors
); 
 732         return secTrust
->_anchors
; 
 735 // Return the constructed certificate chain for this trust reference, 
 736 // making output certificates pointer-equivalent to any provided input 
 737 // certificates (where possible) for legacy behavioral compatibility. 
 738 // Caller must release this array. 
 740 CFArrayRef 
SecTrustCopyConstructedChain(SecTrustRef trust
) 
 742         CFMutableArrayRef certChain 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 743         CFIndex idx
, count 
= SecTrustGetCertificateCount(trust
); 
 744         for (idx
=0; idx 
< count
; idx
++) { 
 745                 SecCertificateRef certificate 
= SecTrustGetCertificateAtIndex(trust
, idx
); 
 747                         CFArrayAppendValue(certChain
, certificate
); 
 751         // Some callers make the assumption that the certificates in 
 752         // this chain are pointer-equivalent to ones they passed to the 
 753         // SecTrustCreateWithCertificates function. We'll maintain that 
 754         // behavior here for compatibility. 
 756         CFArrayRef inputCertArray 
= SecTrustCopyInputCertificates(trust
); 
 757         CFArrayRef inputAnchorArray 
= SecTrustCopyInputAnchors(trust
); 
 758         CFIndex inputCertIdx
, inputCertCount 
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0; 
 759         CFIndex inputAnchorIdx
, inputAnchorCount 
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0; 
 760         for (idx
=0; idx 
< count
; idx
++) { 
 761                 SecCertificateRef tmpCert 
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, idx
); 
 763                         SecCertificateRef matchCert 
= NULL
; 
 764                         for (inputCertIdx
=0; inputCertIdx 
< inputCertCount 
&& !matchCert
; inputCertIdx
++) { 
 765                                 SecCertificateRef inputCert 
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
); 
 766                                 if (inputCert 
&& CFEqual(inputCert
, tmpCert
)) { 
 767                                         matchCert 
= inputCert
; 
 770                         for (inputAnchorIdx
=0; inputAnchorIdx 
< inputAnchorCount 
&& !matchCert
; inputAnchorIdx
++) { 
 771                                 SecCertificateRef inputAnchor 
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
); 
 772                                 if (inputAnchor 
&& CFEqual(inputAnchor
, tmpCert
)) { 
 773                                         matchCert 
= inputAnchor
; 
 777                                 CFArraySetValueAtIndex(certChain
, idx
, matchCert
); 
 781         if (inputCertArray
) { 
 782                 CFRelease(inputCertArray
); 
 784         if (inputAnchorArray
) { 
 785                 CFRelease(inputAnchorArray
); 
 791 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist 
 792 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs 
 793 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes. 
 794 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns 
 795 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields 
 796 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected 
 797 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed, 
 798 // which would force re-evaluation. 
 800 static CSSM_TP_APPLE_EVIDENCE_INFO 
* 
 801 SecTrustGetEvidenceInfo(SecTrustRef trust
) 
 803         TSecTrust 
*secTrust 
= (TSecTrust 
*)trust
; 
 807         if (secTrust
->_trustResult 
!= kSecTrustResultInvalid 
&& 
 808                 secTrust
->_legacy_info_array
) { 
 809                 // we've already got valid evidence info, return it now. 
 810                 return (CSSM_TP_APPLE_EVIDENCE_INFO 
*)secTrust
->_legacy_info_array
; 
 813         // Getting the count implicitly evaluates the chain if necessary. 
 814         CFIndex idx
, count 
= SecTrustGetCertificateCount(trust
); 
 815         CFArrayRef inputCertArray 
= SecTrustCopyInputCertificates(trust
); 
 816         CFArrayRef inputAnchorArray 
= SecTrustCopyInputAnchors(trust
); 
 817         CFIndex inputCertIdx
, inputCertCount 
= (inputCertArray
) ? CFArrayGetCount(inputCertArray
) : 0; 
 818         CFIndex inputAnchorIdx
, inputAnchorCount 
= (inputAnchorArray
) ? CFArrayGetCount(inputAnchorArray
) : 0; 
 820         CSSM_TP_APPLE_EVIDENCE_INFO 
*infoArray 
= (CSSM_TP_APPLE_EVIDENCE_INFO 
*)calloc(count
, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO
)); 
 821         CSSM_RETURN 
*statusArray 
= NULL
; 
 822         unsigned int numStatusCodes 
= 0; 
 824         // Set status codes for each certificate in the constructed chain 
 825         for (idx
=0; idx 
< count
; idx
++) { 
 826                 SecCertificateRef cert 
= SecTrustGetCertificateAtIndex(trust
, idx
); 
 830                 CSSM_TP_APPLE_EVIDENCE_INFO 
*evInfo 
= &infoArray
[idx
]; 
 832                 /* first the booleans (StatusBits flags) */ 
 833                 CFAbsoluteTime now 
= CFAbsoluteTimeGetCurrent(); 
 834                 if (secTrust
->_verifyDate
) { 
 835                         now 
= CFDateGetAbsoluteTime(secTrust
->_verifyDate
); 
 837                 CFAbsoluteTime na 
= SecCertificateNotValidAfter(cert
); 
 839                         evInfo
->StatusBits 
|= CSSM_CERT_STATUS_EXPIRED
; 
 841                 CFAbsoluteTime nb 
= SecCertificateNotValidBefore(cert
); 
 843                         evInfo
->StatusBits 
|= CSSM_CERT_STATUS_NOT_VALID_YET
; 
 845                 for (inputAnchorIdx
=0; inputAnchorIdx 
< inputAnchorCount
; inputAnchorIdx
++) { 
 846                         SecCertificateRef inputAnchor 
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputAnchorArray
, inputAnchorIdx
); 
 847                         if (inputAnchor 
&& CFEqual(inputAnchor
, cert
)) { 
 848                                 evInfo
->StatusBits 
|= CSSM_CERT_STATUS_IS_IN_ANCHORS
; 
 852                 for (inputCertIdx
=0; inputCertIdx 
< inputCertCount
; inputCertIdx
++) { 
 853                         SecCertificateRef inputCert 
= (SecCertificateRef
) CFArrayGetValueAtIndex(inputCertArray
, inputCertIdx
); 
 854                         if (inputCert 
&& CFEqual(inputCert
, cert
)) { 
 855                                 evInfo
->StatusBits 
|= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
; 
 860                 /* See if there are trust settings for this certificate. */ 
 861                 CFStringRef hashStr 
= SecTrustSettingsCertHashStrFromCert(cert
); 
 862                 bool foundMatch 
= false; 
 863                 bool foundAny 
= false; 
 864                 CSSM_RETURN 
*errors 
= NULL
; 
 865                 uint32 errorCount 
= 0; 
 867                 SecTrustSettingsDomain foundDomain 
= kSecTrustSettingsDomainUser
; 
 868                 SecTrustSettingsResult foundResult 
= kSecTrustSettingsResultInvalid
; 
 869                 bool isSelfSigned 
= false; 
 870                 if ((count 
- 1) == idx
) { 
 871                         // Only the last cert in the chain needs to be considered 
 873                         status 
= SecCertificateIsSelfSigned(cert
, &selfSigned
); 
 874                         isSelfSigned 
= (status
) ? false : ((selfSigned
) ? true : false); 
 876                                 evInfo
->StatusBits 
|= CSSM_CERT_STATUS_IS_ROOT
; 
 879                 // STU: rdar://25554967 
 880                 // %%% need to get policyOID, policyString, and keyUsage here! 
 882                 status 
= SecTrustSettingsEvaluateCert( 
 883                                 hashStr
,                /* certHashStr */ 
 884                                 NULL
,                   /* policyOID (optional) */ 
 885                                 NULL
,                   /* policyString (optional) */ 
 886                                 0,                              /* policyStringLen */ 
 888                                 isSelfSigned
,   /* isRootCert */ 
 889                                 &foundDomain
,   /* foundDomain */ 
 890                                 &errors
,                /* allowedErrors -- MUST FREE */ 
 891                                 &errorCount
,    /* numAllowedErrors */ 
 892                                 &foundResult
,   /* resultType */ 
 893                                 &foundMatch
,    /* foundMatchingEntry */ 
 894                                 &foundAny
);             /* foundAnyEntry */ 
 896                 if (status 
== errSecSuccess
) { 
 898                                 switch (foundResult
) { 
 899                                         case kSecTrustSettingsResultTrustRoot
: 
 900                                         case kSecTrustSettingsResultTrustAsRoot
: 
 901                                                 /* these two can be disambiguated by IS_ROOT */ 
 902                                                 evInfo
->StatusBits 
|= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
; 
 904                                         case kSecTrustSettingsResultDeny
: 
 905                                                 evInfo
->StatusBits 
|= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
; 
 907                                         case kSecTrustSettingsResultUnspecified
: 
 908                                         case kSecTrustSettingsResultInvalid
: 
 921                 unsigned int numCodes
=0; 
 922                 CSSM_RETURN 
*statusCodes 
= copyCssmStatusCodes(trust
, (unsigned int)idx
, &numCodes
); 
 924                         // Realloc space for these status codes at end of our status codes block. 
 925                         // Two important things to note: 
 926                         // 1. the actual length is numCodes+1 because copyCssmStatusCodes 
 927                         // allocates one more element at the end for the CrlReason value. 
 928                         // 2. realloc may cause the pointer to move, which means we will 
 929                         // need to fix up the StatusCodes fields after we're done with this loop. 
 930                         unsigned int totalStatusCodes 
= numStatusCodes 
+ numCodes 
+ 1; 
 931                         statusArray 
= (CSSM_RETURN 
*)realloc(statusArray
, totalStatusCodes 
* sizeof(CSSM_RETURN
)); 
 932                         evInfo
->StatusCodes 
= &statusArray
[numStatusCodes
]; 
 933                         evInfo
->NumStatusCodes 
= numCodes
; 
 934                         // Copy the new codes (plus one) into place 
 935                         for (unsigned int cpix 
= 0; cpix 
<= numCodes
; cpix
++) { 
 936                                 evInfo
->StatusCodes
[cpix
] = statusCodes
[cpix
]; 
 938                         numStatusCodes 
= totalStatusCodes
; 
 942                 if(evInfo
->StatusBits 
& (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST 
| 
 943                                                                  CSSM_CERT_STATUS_TRUST_SETTINGS_DENY 
| 
 944                                                                  CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR
)) { 
 945                         /* Something noteworthy happened involving TrustSettings */ 
 946                         uint32 whichDomain 
= 0; 
 947                         switch(foundDomain
) { 
 948                                 case kSecTrustSettingsDomainUser
: 
 949                                         whichDomain 
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
; 
 951                                 case kSecTrustSettingsDomainAdmin
: 
 952                                         whichDomain 
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
; 
 954                                 case kSecTrustSettingsDomainSystem
: 
 955                                         whichDomain 
= CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
; 
 958                         evInfo
->StatusBits 
|= whichDomain
; 
 961                 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */ 
 962                 //evInfo->Index = certInfo->index(); 
 963                 /* nonzero if cert came from a DLDB */ 
 964                 //evInfo->DlDbHandle = certInfo->dlDbHandle(); 
 965                 //evInfo->UniqueRecord = certInfo->uniqueRecord(); 
 968         // Now that all the status codes have been allocated in a contiguous block, 
 969         // refresh the StatusCodes pointer in each array element. 
 971         for (idx
=0; idx 
< count
; idx
++) { 
 972                 CSSM_TP_APPLE_EVIDENCE_INFO 
*evInfo 
= &infoArray
[idx
]; 
 973                 evInfo
->StatusCodes 
= &statusArray
[numStatusCodes
]; 
 974                 numStatusCodes 
+= evInfo
->NumStatusCodes 
+ 1; 
 977         secTrust
->_legacy_info_array 
= infoArray
; 
 978         secTrust
->_legacy_status_array 
= statusArray
; 
 980         if (inputCertArray
) { 
 981                 CFRelease(inputCertArray
); 
 983         if (inputAnchorArray
) { 
 984                 CFRelease(inputAnchorArray
); 
 987         return (CSSM_TP_APPLE_EVIDENCE_INFO 
*)secTrust
->_legacy_info_array
; 
 990 CFArrayRef 
SecTrustCopyProperties(SecTrustRef trust
) { 
 991     /* OS X creates a completely different structure with one dictionary for each certificate */ 
 992     CFIndex ix
, count 
= SecTrustGetCertificateCount(trust
); 
 994     CFMutableArrayRef properties 
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, 
 995                                                         &kCFTypeArrayCallBacks
); 
 997     for (ix 
= 0; ix 
< count
; ix
++) { 
 998         CFMutableDictionaryRef certDict 
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, 
 999                                                                     &kCFTypeDictionaryValueCallBacks
); 
1000         /* Populate the certificate title */ 
1001         SecCertificateRef cert 
= SecTrustGetCertificateAtIndex(trust
, ix
); 
1003             CFStringRef subjectSummary 
= SecCertificateCopySubjectSummary(cert
); 
1004             if (subjectSummary
) { 
1005                 CFDictionaryAddValue(certDict
, kSecPropertyTypeTitle
, subjectSummary
); 
1006                 CFRelease(subjectSummary
); 
1010         /* Populate a revocation reason if the cert was revoked */ 
1011         unsigned int numStatusCodes
; 
1012         CSSM_RETURN 
*statusCodes 
= NULL
; 
1013         statusCodes 
= copyCssmStatusCodes(trust
, (uint32_t)ix
, &numStatusCodes
); 
1015             int32_t reason 
= statusCodes
[numStatusCodes
];  // stored at end of status codes array 
1017                 CFNumberRef cfreason 
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
); 
1019                     CFDictionarySetValue(certDict
, kSecTrustRevocationReason
, cfreason
); 
1020                     CFRelease(cfreason
); 
1026         /* Populate the error in the leaf dictionary */ 
1028             OSStatus error 
= errSecSuccess
; 
1029             (void)SecTrustGetCssmResultCode(trust
, &error
); 
1030             CFStringRef errorStr 
= SecCopyErrorMessageString(error
, NULL
); 
1032                 CFDictionarySetValue(certDict
, kSecPropertyTypeError
, errorStr
); 
1033                 CFRelease(errorStr
); 
1037         CFArrayAppendValue(properties
, certDict
); 
1038         CFRelease(certDict
); 
1044 /* deprecated in 10.5 */ 
1045 OSStatus 
SecTrustGetCSSMAnchorCertificates(const CSSM_DATA 
**cssmAnchors
, 
1046         uint32 
*cssmAnchorCount
) 
1048         /* this function is unsupported in unified SecTrust */ 
1049 #if SECTRUST_DEPRECATION_WARNINGS 
1050         syslog(LOG_ERR
, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it."); 
1053                 *cssmAnchors 
= NULL
; 
1055         if (cssmAnchorCount
) { 
1056                 *cssmAnchorCount 
= 0; 
1058         return errSecServiceNotAvailable
; 
1063 // Get and set user trust settings. Deprecated in 10.5. 
1064 // User Trust getter, deprecated, works as it always has. 
1066 OSStatus 
SecTrustGetUserTrust(SecCertificateRef certificate
, 
1067     SecPolicyRef policy
, SecTrustUserSetting 
*trustSetting
) 
1069         /* this function is unsupported in unified SecTrust */ 
1070 #if SECTRUST_DEPRECATION_WARNINGS 
1071         syslog(LOG_ERR
, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it."); 
1073         return errSecServiceNotAvailable
; 
1077 // The public setter, also deprecated; it maps to the appropriate 
1078 // Trust Settings call if possible, else throws errSecUnimplemented. 
1080 OSStatus 
SecTrustSetUserTrust(SecCertificateRef certificate
, 
1081     SecPolicyRef policy
, SecTrustUserSetting trustSetting
) 
1083         /* this function is unsupported in unified SecTrust */ 
1084 #if SECTRUST_DEPRECATION_WARNINGS 
1085         syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it."); 
1087         return errSecServiceNotAvailable
; 
1091 // This one is the now-private version of what SecTrustSetUserTrust() used to 
1092 // be. The public API can no longer manipulate User Trust settings, only 
1095 OSStatus 
SecTrustSetUserTrustLegacy(SecCertificateRef certificate
, 
1096     SecPolicyRef policy
, SecTrustUserSetting trustSetting
) 
1098         /* this function is unsupported in unified SecTrust */ 
1099 #if SECTRUST_DEPRECATION_WARNINGS 
1100         syslog(LOG_ERR
, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it."); 
1102         return errSecServiceNotAvailable
;