]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecTrust.cpp
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecTrust.cpp
1 /*
2 * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "SecTrust.h"
25 #include "SecTrustPriv.h"
26 #include "Trust.h"
27 #include "SecBase.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>
40 #include <syslog.h>
41
42 // forward declarations
43 #if !SECTRUST_OSX
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);
47 #else
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);
52 #endif
53
54 typedef struct SecTrustCheckExceptionContext {
55 CFDictionaryRef exception;
56 bool exceptionNotFound;
57 } SecTrustCheckExceptionContext;
58
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");
68
69 // Policy check string to CSSM_RETURN mapping
70
71 struct resultmap_entry_s {
72 const CFStringRef checkstr;
73 const CSSM_RETURN resultcode;
74 };
75 typedef struct resultmap_entry_s resultmap_entry_t;
76
77 #if SECTRUST_OSX
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"), },
128 };
129 #endif
130
131 //
132 // CF boilerplate
133 //
134 #if !SECTRUST_OSX
135 CFTypeID SecTrustGetTypeID(void)
136 {
137 BEGIN_SECAPI
138
139 return gTypes().Trust.typeID;
140
141 END_SECAPI1(_kCFRuntimeNotATypeID)
142 }
143 #endif
144
145 //
146 // Sec* API bridge functions
147 //
148 #if !SECTRUST_OSX
149 OSStatus SecTrustCreateWithCertificates(
150 CFTypeRef certificates,
151 CFTypeRef policies,
152 SecTrustRef *trustRef)
153 {
154 BEGIN_SECAPI
155 Required(trustRef);
156 *trustRef = (new Trust(certificates, policies))->handle();
157 END_SECAPI
158 }
159 #endif
160
161 #if !SECTRUST_OSX
162 OSStatus
163 SecTrustSetPolicies(SecTrustRef trustRef, CFTypeRef policies)
164 {
165 BEGIN_SECAPI
166 Trust::required(trustRef)->policies(policies);
167 END_SECAPI
168 }
169 #endif
170
171 #if SECTRUST_OSX
172 typedef struct {
173 SecTrustOptionFlags flags;
174 CFIndex certIX;
175 SecTrustRef trustRef;
176 CFMutableDictionaryRef filteredException;
177 CFDictionaryRef oldException;
178 } SecExceptionFilterContext;
179
180 #if 0
181 //%%%FIXME SecCFWrappers produces some conflicting definitions on OSX
182 #include <utilities/SecCFWrappers.h>
183 #else
184 // inline function from SecCFWrappers.h
185 static inline char *CFStringToCString(CFStringRef inStr)
186 {
187 if (!inStr)
188 return (char *)strdup("");
189 CFRetain(inStr); // compensate for release on exit
190
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))
196 buffer[0] = 0;
197
198 CFRelease(inStr);
199 return buffer;
200 }
201 #endif
202
203 static void
204 filter_exception(const void *key, const void *value, void *context)
205 {
206 SecExceptionFilterContext *ctx = (SecExceptionFilterContext *)context;
207 if (!ctx) { return; }
208
209 SecTrustOptionFlags options = ctx->flags;
210 CFMutableDictionaryRef filteredException = ctx->filteredException;
211 CFStringRef keystr = (CFStringRef)key;
212
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));
216 return;
217 }
218
219 bool allowed = false;
220
221 if (CFEqual(keystr, CFSTR("SHA1Digest"))) {
222 allowed = true; // this key is informational and always permitted
223 }
224 else if (CFEqual(keystr, CFSTR("NotValidBefore"))) {
225 allowed = ((options & kSecTrustOptionAllowExpired) != 0);
226 }
227 else if (CFEqual(keystr, CFSTR("ValidLeaf"))) {
228 allowed = ((options & kSecTrustOptionAllowExpired) != 0);
229 }
230 else if (CFEqual(keystr, CFSTR("ValidIntermediates"))) {
231 allowed = ((options & kSecTrustOptionAllowExpired) != 0);
232 }
233 else if (CFEqual(keystr, CFSTR("ValidRoot"))) {
234 if (((options & kSecTrustOptionAllowExpired) != 0) ||
235 ((options & kSecTrustOptionAllowExpiredRoot) != 0)) {
236 allowed = true;
237 }
238 }
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)) &&
247 isSelfSigned) {
248 allowed = true;
249 }
250 }
251 }
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
258 allowed = false;
259 }
260 else {
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); }
266 allowed = false;
267 }
268
269 if (allowed) {
270 CFDictionaryAddValue(filteredException, key, value);
271 }
272 }
273
274 #endif
275
276 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
277 OSStatus
278 SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
279 {
280 #if !SECTRUST_OSX
281 BEGIN_SECAPI
282 CSSM_APPLE_TP_ACTION_DATA actionData = {
283 CSSM_APPLE_TP_ACTION_VERSION,
284 (CSSM_APPLE_TP_ACTION_FLAGS)options
285 };
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);
293 END_SECAPI
294 #else
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);
300
301 if (encodedExceptions) {
302 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
303 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
304 CFRelease(encodedExceptions);
305 encodedExceptions = NULL;
306 }
307
308 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
309 CFRelease(exceptions);
310 exceptions = NULL;
311 }
312
313 if (oldExceptions && exceptions &&
314 CFArrayGetCount(oldExceptions) > CFArrayGetCount(exceptions)) {
315 oldExceptions = NULL;
316 }
317
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;
326 }
327 }
328
329 /* add only those exceptions which are allowed by the supplied options */
330 if (exceptions) {
331 CFMutableArrayRef filteredExceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
332 CFIndex i, exceptionCount = (filteredExceptions) ? CFArrayGetCount(exceptions) : 0;
333
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);
339 }
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);
347 }
348 }
349
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);
357 } else {
358 break;
359 }
360 }
361 encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
362 filteredExceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
363 CFRelease(filteredExceptions);
364
365 SecTrustSetExceptions(trustRef, encodedExceptions);
366 CFRelease(encodedExceptions);
367 }
368 CFRelease(exceptions);
369 }
370
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.";
379
380 if (options & kSecTrustOptionAllowExpired) {
381 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpired");
382 displayModifyMsg = true;
383 }
384 if (options & kSecTrustOptionAllowExpiredRoot) {
385 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpiredRoot");
386 displayModifyMsg = true;
387 }
388 if (options & kSecTrustOptionFetchIssuerFromNet) {
389 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionFetchIssuerFromNet");
390 displayNetworkMsg = true;
391 }
392 if (options & kSecTrustOptionRequireRevPerCert) {
393 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionRequireRevPerCert");
394 displayPolicyMsg = true;
395 }
396 if (displayModifyMsg || displayNetworkMsg || displayPolicyMsg) {
397 syslog(LOG_ERR, "%s %s %s",
398 (displayModifyMsg) ? modifyMsg : "",
399 (displayNetworkMsg) ? networkMsg : "",
400 (displayPolicyMsg) ? policyMsg : "");
401 }
402 #endif
403
404 return status;
405
406 #endif
407 }
408
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)
414 {
415 #if !SECTRUST_OSX
416 BEGIN_SECAPI
417 Trust *trust = Trust::required(trustRef);
418 trust->action(action);
419 trust->actionData(actionData);
420 END_SECAPI
421 #else
422 /* bridge to support API functionality for legacy callers */
423 OSStatus status;
424 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
425 if (actionData) {
426 CSSM_APPLE_TP_ACTION_DATA *actionDataPtr = (CSSM_APPLE_TP_ACTION_DATA *) CFDataGetBytePtr(actionData);
427 if (actionDataPtr) {
428 actionFlags = actionDataPtr->ActionFlags;
429 }
430 }
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);
434
435 #if SECTRUST_DEPRECATION_WARNINGS
436 syslog(LOG_ERR, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
437 #endif
438
439 return status;
440
441 #endif
442 }
443
444 #if !SECTRUST_OSX
445 OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, CFArrayRef anchorCertificates)
446 {
447 BEGIN_SECAPI
448 Trust::required(trust)->anchors(anchorCertificates);
449 END_SECAPI
450 }
451 #endif
452
453 #if !SECTRUST_OSX
454 OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust, Boolean anchorCertificatesOnly)
455 {
456 BEGIN_SECAPI
457 Trust::AnchorPolicy policy = (anchorCertificatesOnly) ? Trust::useAnchorsOnly : Trust::useAnchorsAndBuiltIns;
458 Trust::required(trust)->anchorPolicy(policy);
459 END_SECAPI
460 }
461 #endif
462
463 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
464 OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray)
465 {
466 #if !SECTRUST_OSX
467 BEGIN_SECAPI
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);
474 }
475 Trust::required(trust)->searchLibs(keychains);
476 END_SECAPI
477 #else
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.");
482 #endif
483 return errSecSuccess;
484 #endif
485 }
486
487 #if !SECTRUST_OSX
488 OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate)
489 {
490 BEGIN_SECAPI
491 Trust::required(trust)->time(verifyDate);
492 END_SECAPI
493 }
494 #endif
495
496 #if !SECTRUST_OSX
497 CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust)
498 {
499 CFAbsoluteTime verifyTime = 0;
500 OSStatus __secapiresult = errSecSuccess;
501 try {
502 CFRef<CFDateRef> verifyDate = Trust::required(trust)->time();
503 verifyTime = CFDateGetAbsoluteTime(verifyDate);
504 }
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; }
509 return verifyTime;
510 }
511 #endif
512
513
514
515 #if !SECTRUST_OSX
516 OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *resultP)
517 {
518 SecTrustResultType trustResult = kSecTrustResultInvalid;
519 CFArrayRef exceptions = NULL;
520 OSStatus __secapiresult = errSecSuccess;
521 try {
522 Trust *trustObj = Trust::required(trust);
523 trustObj->evaluate();
524 trustResult = trustObj->result();
525 exceptions = trustObj->exceptions();
526 }
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; }
531
532 if (__secapiresult) {
533 return __secapiresult;
534 }
535
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;
541 }
542 else if (trustResult == kSecTrustResultRecoverableTrustFailure && exceptions) {
543 /* If we have exceptions get details and match to exceptions. */
544 CFArrayRef details = SecTrustCopyDetails(trust);
545 if (details) {
546 CFIndex pathLength = CFArrayGetCount(details);
547 struct SecTrustCheckExceptionContext context = {};
548 CFIndex ix;
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) {
556 break;
557 }
558 }
559 if (!context.exceptionNotFound)
560 trustResult = kSecTrustResultProceed;
561 }
562 }
563
564
565 secnotice("SecTrustEvaluate", "SecTrustEvaluate trust result = %d", (int)trustResult);
566 if (resultP) {
567 *resultP = trustResult;
568 }
569 return __secapiresult;
570 }
571 #endif
572
573 #if !SECTRUST_OSX
574 OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
575 dispatch_queue_t queue, SecTrustCallback result)
576 {
577 BEGIN_SECAPI
578 dispatch_async(queue, ^{
579 try {
580 Trust *trustObj = Trust::required(trust);
581 trustObj->evaluate();
582 SecTrustResultType trustResult = trustObj->result();
583 result(trust, trustResult);
584 }
585 catch (...) {
586 result(trust, kSecTrustResultInvalid);
587 };
588 });
589 END_SECAPI
590 }
591 #endif
592
593 //
594 // Construct the "official" result evidence and return it
595 //
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)
601 {
602 #if !SECTRUST_OSX
603 BEGIN_SECAPI
604 Trust *trust = Trust::required(trustRef);
605 if (result)
606 *result = trust->result();
607 if (certChain && statusChain)
608 trust->buildEvidence(*certChain, TPEvidenceInfo::overlayVar(*statusChain));
609 END_SECAPI
610 #else
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.");
614 #endif
615 SecTrustResultType trustResult;
616 OSStatus status = SecTrustGetTrustResult(trustRef, &trustResult);
617 if (status != errSecSuccess) {
618 return status;
619 }
620 if (result) {
621 *result = trustResult;
622 }
623 if (certChain) {
624 *certChain = SecTrustCopyConstructedChain(trustRef);
625 }
626 if (statusChain) {
627 *statusChain = SecTrustGetEvidenceInfo(trustRef);
628 }
629 return status;
630 #endif
631 }
632
633 //
634 // Retrieve result of trust evaluation only
635 //
636 #if !SECTRUST_OSX
637 OSStatus SecTrustGetTrustResult(SecTrustRef trustRef,
638 SecTrustResultType *result)
639 {
640 BEGIN_SECAPI
641 Trust *trust = Trust::required(trustRef);
642 if (result) *result = trust->result();
643 END_SECAPI
644 }
645 #endif
646
647 //
648 // Retrieve extended validation trust results
649 //
650 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
651 OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result)
652 {
653 #if !SECTRUST_OSX
654 BEGIN_SECAPI
655 Trust *trustObj = Trust::required(trust);
656 if (result == nil)
657 return errSecParam;
658 trustObj->extendedResult(*result);
659 END_SECAPI
660 #else
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.");
664 #endif
665 CFDictionaryRef resultDict = SecTrustCopyResult(trust);
666 if (result == nil) {
667 return errSecParam;
668 }
669 *result = resultDict;
670 return errSecSuccess;
671 #endif
672 }
673
674 //
675 // Retrieve CSSM-level information for those who want to dig down
676 //
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)
679 {
680 #if !SECTRUST_OSX
681 BEGIN_SECAPI
682 Required(result) = Trust::required(trust)->cssmResult();
683 END_SECAPI
684 #else
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.");
688 #endif
689 if (result) {
690 *result = NULL;
691 }
692 return errSecServiceNotAvailable;
693 #endif
694 }
695
696 #if SECTRUST_OSX
697 //
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.
700 //
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.
704 //
705 // Caller must free the returned pointer.
706 //
707 static CSSM_RETURN *copyCssmStatusCodes(SecTrustRef trust,
708 unsigned int index, unsigned int *numStatusCodes)
709 {
710 if (!trust || !numStatusCodes) {
711 return NULL;
712 }
713 *numStatusCodes = 0;
714 CFArrayRef details = SecTrustGetDetails(trust);
715 CFIndex chainLength = (details) ? CFArrayGetCount(details) : 0;
716 if (!(index < chainLength)) {
717 return NULL;
718 }
719 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, index);
720 CFIndex ix, detailCount = CFDictionaryGetCount(detail);
721 *numStatusCodes = (unsigned int)detailCount;
722
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;
727
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;
738 break;
739 }
740 }
741 if (statusCode == CSSMERR_TP_CERT_REVOKED) {
742 SInt32 reason;
743 CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(detail, key);
744 if (number && CFNumberGetValue(number, kCFNumberSInt32Type, &reason)) {
745 statusCodes[*numStatusCodes] = (CSSM_RETURN)reason;
746 }
747 }
748 statusCodes[ix] = statusCode;
749 }
750
751 return statusCodes;
752 }
753
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:
759 return 1;
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:
767 return 2;
768 case CSSMERR_TP_CERT_EXPIRED:
769 return 3;
770 /* doesn't chain to trusted root */
771 case CSSMERR_TP_NOT_TRUSTED:
772 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH:
773 return 4;
774 /* all others are policy-specific failures */
775 default:
776 return 5;
777 }
778 }
779
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;
785
786 /* Policy used to evaluate was SWUpdateSigning */
787 SecTrustCopyPolicies(trust, &policies);
788 if (policies) {
789 SecPolicyRef swUpdatePolicy = SecPolicyCreateAppleSWUpdateSigning();
790 if (swUpdatePolicy && CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)),
791 swUpdatePolicy)) {
792 isPolicy = true;
793 }
794 if (swUpdatePolicy) { CFRelease(swUpdatePolicy); }
795 CFRelease(policies);
796 }
797 if (!isPolicy) {
798 return false;
799 }
800
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
809 return false;
810 } else {
811 if (CFDictionaryGetCount(detail) > 0) { // No errors on other certs
812 return false;
813 }
814 }
815 }
816
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)) {
821 return false;
822 }
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)) {
831 isEKU = true;
832 }
833 }
834 }
835 SecCertificateReleaseFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, fieldValue);
836 return isEKU;
837 }
838 #endif
839
840 //
841 // Retrieve CSSM_LEVEL TP return code
842 //
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)
845 {
846 #if !SECTRUST_OSX
847 BEGIN_SECAPI
848 Trust *trust = Trust::required(trustRef);
849 if (trust->result() == kSecTrustResultInvalid)
850 return errSecParam;
851 else
852 Required(result) = trust->cssmResultCode();
853 END_SECAPI
854 #else
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.");
858 #endif
859 if (!trustRef || !result) {
860 return errSecParam;
861 }
862
863 SecTrustResultType trustResult = kSecTrustResultInvalid;
864 (void) SecTrustGetTrustResult(trustRef, &trustResult);
865 if (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified) {
866 if (result) { *result = 0; }
867 return errSecSuccess;
868 }
869
870 /* Development Software Update certs return a special error code when evaluated
871 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
872 if (isSoftwareUpdateDevelopment(trustRef)) {
873 if (result) {
874 *result = CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT;
875 }
876 return errSecSuccess;
877 }
878
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;
894 }
895 }
896 }
897 if (statusCodes) { free(statusCodes); }
898 if (resultCodePriority == 1) { break; }
899 }
900
901 if (result) {
902 *result = cssmResultCode;
903 }
904 return errSecSuccess;
905 #endif
906 }
907
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)
910 {
911 #if !SECTRUST_OSX
912 BEGIN_SECAPI
913 Required(handle) = Trust::required(trust)->getTPHandle();
914 END_SECAPI
915 #else
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.");
919 #endif
920 if (handle) {
921 *handle = NULL;
922 }
923 return errSecServiceNotAvailable;
924 #endif
925 }
926
927 #if !SECTRUST_OSX
928 OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies)
929 {
930 BEGIN_SECAPI
931 CFArrayRef currentPolicies = Trust::required(trust)->policies();
932 if (currentPolicies != NULL)
933 {
934 CFRetain(currentPolicies);
935 }
936
937 Required(policies) = currentPolicies;
938 END_SECAPI
939 }
940 #endif
941
942 #if !SECTRUST_OSX
943 OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch)
944 {
945 BEGIN_SECAPI
946 Trust *trustObj = Trust::required(trust);
947 Trust::NetworkPolicy netPolicy = (allowFetch) ?
948 Trust::useNetworkEnabled : Trust::useNetworkDisabled;
949 trustObj->networkPolicy(netPolicy);
950 END_SECAPI
951 }
952 #endif
953
954 #if !SECTRUST_OSX
955 OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch)
956 {
957 BEGIN_SECAPI
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);
964 } else {
965 // caller has explicitly set the network policy
966 allowed = (netPolicy == Trust::useNetworkEnabled);
967 }
968 Required(allowFetch) = allowed;
969 END_SECAPI
970 }
971 #endif
972
973 #if !SECTRUST_OSX
974 OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData)
975 {
976 BEGIN_SECAPI
977 Trust::required(trust)->responses(responseData);
978 END_SECAPI
979 }
980 #endif
981
982 #if !SECTRUST_OSX
983 OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, CFArrayRef *anchorCertificates)
984 {
985 BEGIN_SECAPI
986 CFArrayRef customAnchors = Trust::required(trust)->anchors();
987 Required(anchorCertificates) = (customAnchors) ?
988 (const CFArrayRef)CFRetain(customAnchors) : (const CFArrayRef)NULL;
989 END_SECAPI
990 }
991 #endif
992
993 //
994 // Get the user's default anchor certificate set
995 //
996 /* OS X only */
997 OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates)
998 {
999 BEGIN_SECAPI
1000
1001 return SecTrustSettingsCopyUnrestrictedRoots(
1002 true, true, true, /* all domains */
1003 anchorCertificates);
1004
1005 END_SECAPI
1006 }
1007
1008 #if SECTRUST_OSX
1009 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
1010 */
1011 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
1012 {
1013 SecKeyRef pubKey = NULL;
1014 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0);
1015 (void) SecCertificateCopyPublicKey(certificate, &pubKey);
1016 return pubKey;
1017 }
1018 #else
1019 /* new in 10.6 */
1020 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
1021 {
1022 SecKeyRef pubKey = NULL;
1023 CFArrayRef certChain = NULL;
1024 CFArrayRef evidenceChain = NULL;
1025 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
1026 OSStatus __secapiresult = errSecSuccess;
1027 try {
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);
1033 if (pubKey) {
1034 return pubKey;
1035 }
1036 // Otherwise, we must evaluate first.
1037 trustObj->evaluate();
1038 if (trustObj->result() == kSecTrustResultInvalid) {
1039 MacOSError::throwMe(errSecTrustNotAvailable);
1040 }
1041 }
1042 if (trustObj->evidence() == nil) {
1043 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
1044 }
1045 evidenceChain = trustObj->evidence();
1046 }
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; }
1051
1052 if (certChain)
1053 CFRelease(certChain);
1054
1055 if (evidenceChain) {
1056 if (CFArrayGetCount(evidenceChain) > 0) {
1057 SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, 0);
1058 __secapiresult = SecCertificateCopyPublicKey(cert, &pubKey);
1059 }
1060 // do not release evidenceChain, as it is owned by the trust object.
1061 }
1062 return pubKey;
1063 }
1064 #endif
1065
1066 #if !SECTRUST_OSX
1067 /* new in 10.6 */
1068 CFIndex SecTrustGetCertificateCount(SecTrustRef trust)
1069 {
1070 CFIndex chainLen = 0;
1071 CFArrayRef certChain = NULL;
1072 CFArrayRef evidenceChain = NULL;
1073 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
1074 OSStatus __secapiresult = errSecSuccess;
1075 try {
1076 Trust *trustObj = Trust::required(trust);
1077 if (trustObj->result() == kSecTrustResultInvalid) {
1078 trustObj->evaluate();
1079 if (trustObj->result() == kSecTrustResultInvalid)
1080 MacOSError::throwMe(errSecTrustNotAvailable);
1081 }
1082 if (trustObj->evidence() == nil)
1083 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
1084 evidenceChain = trustObj->evidence();
1085 }
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; }
1090
1091 if (certChain)
1092 CFRelease(certChain);
1093
1094 if (evidenceChain)
1095 chainLen = CFArrayGetCount(evidenceChain); // don't release, trust object owns it.
1096
1097 return chainLen;
1098 }
1099 #endif
1100
1101 #if !SECTRUST_OSX
1102 /* new in 10.6 */
1103 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix)
1104 {
1105 SecCertificateRef certificate = NULL;
1106 CFArrayRef certChain = NULL;
1107 CFArrayRef evidenceChain = NULL;
1108 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
1109 OSStatus __secapiresult = errSecSuccess;
1110 try {
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.
1116 if (ix == 0) {
1117 CFArrayRef certs = trustObj->certificates();
1118 if (certs && (CFArrayGetCount(certs) > 0)) {
1119 certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certs, 0);
1120 if (certificate) {
1121 return certificate;
1122 }
1123 }
1124 }
1125 // Otherwise, we must evaluate first.
1126 trustObj->evaluate();
1127 if (trustObj->result() == kSecTrustResultInvalid) {
1128 MacOSError::throwMe(errSecTrustNotAvailable);
1129 }
1130 }
1131 if (trustObj->evidence() == nil) {
1132 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
1133 }
1134 evidenceChain = trustObj->evidence();
1135 }
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; }
1140
1141 if (certChain)
1142 CFRelease(certChain);
1143
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.
1152 }
1153 }
1154 return certificate;
1155 }
1156 #endif
1157
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;
1166 CFArrayRef _SCTs;
1167 CFArrayRef _trustedLogs;
1168 CFDateRef _verifyDate;
1169 CFTypeRef _chain;
1170 SecKeyRef _publicKey;
1171 CFArrayRef _details;
1172 CFDictionaryRef _info;
1173 CFArrayRef _exceptions;
1174 SecTrustResultType _trustResult;
1175 bool _anchorsOnly;
1176 bool _keychainsAllowed;
1177 void* _legacy_info_array;
1178 void* _legacy_status_array;
1179 SecTrustResultType _trustResultBeforeExceptions;
1180 } TSecTrust;
1181
1182 #if SECTRUST_OSX
1183 CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust)
1184 {
1185 if (!trust) { return NULL; };
1186 TSecTrust *secTrust = (TSecTrust *)trust;
1187 if (secTrust->_certificates) {
1188 CFRetain(secTrust->_certificates);
1189 }
1190 return secTrust->_certificates;
1191 }
1192 #endif
1193
1194 #if SECTRUST_OSX
1195 CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust)
1196 {
1197 if (!trust) { return NULL; };
1198 TSecTrust *secTrust = (TSecTrust *)trust;
1199 if (secTrust->_anchors) {
1200 CFRetain(secTrust->_anchors);
1201 }
1202 return secTrust->_anchors;
1203 }
1204 #endif
1205
1206 #if SECTRUST_OSX
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.
1211 //
1212 CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust)
1213 {
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);
1218 if (certificate) {
1219 CFArrayAppendValue(certChain, certificate);
1220 }
1221 }
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.
1227 //
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);
1234 if (tmpCert) {
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;
1240 }
1241 }
1242 for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount && !matchCert; inputAnchorIdx++) {
1243 SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
1244 if (inputAnchor && CFEqual(inputAnchor, tmpCert)) {
1245 matchCert = inputAnchor;
1246 }
1247 }
1248 if (matchCert) {
1249 CFArraySetValueAtIndex(certChain, idx, matchCert);
1250 }
1251 }
1252 }
1253 if (inputCertArray) {
1254 CFRelease(inputCertArray);
1255 }
1256 if (inputAnchorArray) {
1257 CFRelease(inputAnchorArray);
1258 }
1259 return certChain;
1260 }
1261 #endif
1262
1263 #if SECTRUST_OSX
1264 //
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.
1273 //
1274 static CSSM_TP_APPLE_EVIDENCE_INFO *
1275 SecTrustGetEvidenceInfo(SecTrustRef trust)
1276 {
1277 TSecTrust *secTrust = (TSecTrust *)trust;
1278 if (!secTrust) {
1279 return NULL;
1280 }
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;
1285 }
1286
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;
1293
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;
1297
1298 // Set status codes for each certificate in the constructed chain
1299 for (idx=0; idx < count; idx++) {
1300 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx);
1301 if (!cert) {
1302 continue;
1303 }
1304 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
1305
1306 /* first the booleans (StatusBits flags) */
1307 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
1308 if (secTrust->_verifyDate) {
1309 now = CFDateGetAbsoluteTime(secTrust->_verifyDate);
1310 }
1311 CFAbsoluteTime na = SecCertificateNotValidAfter(cert);
1312 if (na < now) {
1313 evInfo->StatusBits |= CSSM_CERT_STATUS_EXPIRED;
1314 }
1315 CFAbsoluteTime nb = SecCertificateNotValidBefore(cert);
1316 if (nb > now) {
1317 evInfo->StatusBits |= CSSM_CERT_STATUS_NOT_VALID_YET;
1318 }
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;
1323 break;
1324 }
1325 }
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;
1330 break;
1331 }
1332 }
1333
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
1346 Boolean selfSigned;
1347 status = SecCertificateIsSelfSigned(cert, &selfSigned);
1348 isSelfSigned = (status) ? false : ((selfSigned) ? true : false);
1349 if (isSelfSigned) {
1350 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_ROOT;
1351 }
1352 }
1353 // STU: rdar://25554967
1354 // %%% need to get policyOID, policyString, and keyUsage here!
1355
1356 status = SecTrustSettingsEvaluateCert(
1357 hashStr, /* certHashStr */
1358 NULL, /* policyOID (optional) */
1359 NULL, /* policyString (optional) */
1360 0, /* policyStringLen */
1361 0, /* keyUsage */
1362 isSelfSigned, /* isRootCert */
1363 &foundDomain, /* foundDomain */
1364 &errors, /* allowedErrors -- MUST FREE */
1365 &errorCount, /* numAllowedErrors */
1366 &foundResult, /* resultType */
1367 &foundMatch, /* foundMatchingEntry */
1368 &foundAny); /* foundAnyEntry */
1369
1370 if (status == errSecSuccess) {
1371 if (foundMatch) {
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;
1377 break;
1378 case kSecTrustSettingsResultDeny:
1379 evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY;
1380 break;
1381 case kSecTrustSettingsResultUnspecified:
1382 case kSecTrustSettingsResultInvalid:
1383 default:
1384 break;
1385 }
1386 }
1387 }
1388 if (errors) {
1389 free(errors);
1390 }
1391 if (hashStr) {
1392 CFRelease(hashStr);
1393 }
1394
1395 unsigned int numCodes=0;
1396 CSSM_RETURN *statusCodes = copyCssmStatusCodes(trust, (unsigned int)idx, &numCodes);
1397 if (statusCodes) {
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];
1411 }
1412 numStatusCodes = totalStatusCodes;
1413 free(statusCodes);
1414 }
1415
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;
1424 break;
1425 case kSecTrustSettingsDomainAdmin:
1426 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN;
1427 break;
1428 case kSecTrustSettingsDomainSystem:
1429 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM;
1430 break;
1431 }
1432 evInfo->StatusBits |= whichDomain;
1433 }
1434
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();
1440 }
1441
1442 // Now that all the status codes have been allocated in a contiguous block,
1443 // refresh the StatusCodes pointer in each array element.
1444 numStatusCodes = 0;
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;
1449 }
1450
1451 secTrust->_legacy_info_array = infoArray;
1452 secTrust->_legacy_status_array = statusArray;
1453
1454 if (inputCertArray) {
1455 CFRelease(inputCertArray);
1456 }
1457 if (inputAnchorArray) {
1458 CFRelease(inputAnchorArray);
1459 }
1460
1461 return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
1462 }
1463 #endif
1464
1465 #if !SECTRUST_OSX
1466 static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest");
1467 static CFStringRef kSecCertificateDetailStatusCodes = CFSTR("StatusCodes");
1468
1469 static void
1470 _AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode)
1471 {
1472 if (!array)
1473 return;
1474 SInt32 num = statusCode;
1475 CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num);
1476 if (!numRef)
1477 return;
1478 CFArrayAppendValue(array, numRef);
1479 CFRelease(numRef);
1480 }
1481 #endif
1482
1483 #if !SECTRUST_OSX
1484 CFArrayRef SecTrustCopyDetails(SecTrustRef trust)
1485 {
1486 // This function returns an array of dictionaries, one per certificate,
1487 // holding status info for each certificate in the evaluated chain.
1488 //
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;
1494 try {
1495 Trust *trustObj = Trust::required(trust);
1496 if (trustObj->result() == kSecTrustResultInvalid) {
1497 trustObj->evaluate();
1498 if (trustObj->result() == kSecTrustResultInvalid)
1499 MacOSError::throwMe(errSecTrustNotAvailable);
1500 }
1501 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
1502 }
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; }
1507
1508 if (certChain) {
1509 chainLen = CFArrayGetCount(certChain);
1510 CFRelease(certChain);
1511 }
1512 if (statusChain) {
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;
1521
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);
1529
1530 // translate status codes
1531 unsigned int i;
1532 for (i = 0; i < evInfo->NumStatusCodes; i++) {
1533 CSSM_RETURN scode = evInfo->StatusCodes[i];
1534 _AppendStatusCode(statusCodes, (OSStatus)scode);
1535 }
1536
1537 CFDictionarySetValue(certDict, kSecCertificateDetailStatusCodes, statusCodes);
1538 CFRelease(statusCodes);
1539 CFArrayAppendValue(details, certDict);
1540 CFRelease(certDict);
1541 }
1542 }
1543 return details;
1544 }
1545 #endif
1546
1547 #if !SECTRUST_OSX
1548 static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix)
1549 {
1550 CFArrayRef exceptions = NULL;
1551 OSStatus __secapiresult = errSecSuccess;
1552 try {
1553 exceptions = Trust::required(trust)->exceptions();
1554 }
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; }
1559
1560 if (!exceptions || ix >= CFArrayGetCount(exceptions))
1561 return NULL;
1562 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
1563 if (CFGetTypeID(exception) != CFDictionaryGetTypeID())
1564 return NULL;
1565
1566 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1567 if (!certificate)
1568 return NULL;
1569
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))
1575 exception = NULL;
1576
1577 return exception;
1578 }
1579 #endif
1580
1581 #if !SECTRUST_OSX
1582 static void SecTrustCheckException(const void *key, const void *value, void *context)
1583 {
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;
1589 }
1590 } else {
1591 cec->exceptionNotFound = true;
1592 }
1593 }
1594 #endif
1595
1596 #if !SECTRUST_OSX
1597 /* new in 10.9 */
1598 CFDataRef SecTrustCopyExceptions(SecTrustRef trust)
1599 {
1600 CFArrayRef details = SecTrustCopyDetails(trust);
1601 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1602 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault,
1603 pathLength, &kCFTypeArrayCallBacks);
1604 CFIndex ix;
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);
1614 if (digest) {
1615 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
1616 }
1617 } else {
1618 /* Add empty exception dictionaries for non leaf certs which have no exceptions
1619 * to save space.
1620 */
1621 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault,
1622 NULL, NULL, 0,
1623 &kCFTypeDictionaryKeyCallBacks,
1624 &kCFTypeDictionaryValueCallBacks);
1625 }
1626 CFArrayAppendValue(exceptions, exception);
1627 CFReleaseNull(exception);
1628 }
1629 CFReleaseSafe(details);
1630
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);
1637 } else {
1638 break;
1639 }
1640 }
1641
1642 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
1643 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
1644 CFRelease(exceptions);
1645
1646 return encodedExceptions;
1647 }
1648 #endif
1649
1650 #if !SECTRUST_OSX
1651 /* new in 10.9 */
1652 bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions)
1653 {
1654 CFArrayRef exceptions = NULL;
1655
1656 if (NULL != encodedExceptions) {
1657 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
1658 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
1659 }
1660
1661 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
1662 CFRelease(exceptions);
1663 exceptions = NULL;
1664 }
1665
1666 OSStatus __secapiresult = errSecSuccess;
1667 try {
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);
1671 }
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; }
1676
1677 /* If there is a valid exception entry for our current leaf we're golden. */
1678 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
1679 return true;
1680
1681 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1682 try {
1683 Trust::required(trust)->exceptions(NULL);
1684 __secapiresult = errSecSuccess;
1685 }
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; }
1690
1691 return false;
1692 }
1693 #endif
1694
1695 #if !SECTRUST_OSX
1696 /* new in 10.9 */
1697 CFDictionaryRef
1698 SecTrustCopyResult(SecTrustRef trust)
1699 {
1700 CFDictionaryRef result = NULL;
1701 try {
1702 result = Trust::required(trust)->results();
1703 // merge details into result
1704 CFArrayRef details = SecTrustCopyDetails(trust);
1705 if (details) {
1706 CFDictionarySetValue((CFMutableDictionaryRef)result,
1707 kSecTrustResultDetails, details);
1708 CFRelease(details);
1709 }
1710 }
1711 catch (...) {
1712 if (result) {
1713 CFRelease(result);
1714 result = NULL;
1715 }
1716 }
1717 return result;
1718 }
1719 #endif
1720
1721 #if !SECTRUST_OSX
1722 /* new in 10.7 */
1723 CFArrayRef
1724 SecTrustCopyProperties(SecTrustRef trust)
1725 {
1726 /* can't use SECAPI macros, since this function does not return OSStatus */
1727 CFArrayRef result = NULL;
1728 try {
1729 result = Trust::required(trust)->properties();
1730 }
1731 catch (...) {
1732 if (result) {
1733 CFRelease(result);
1734 result = NULL;
1735 }
1736 }
1737 return result;
1738 }
1739 #else
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);
1743
1744 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, count,
1745 &kCFTypeArrayCallBacks);
1746
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);
1752 if (cert) {
1753 CFStringRef subjectSummary = SecCertificateCopySubjectSummary(cert);
1754 if (subjectSummary) {
1755 CFDictionaryAddValue(certDict, kSecPropertyTypeTitle, subjectSummary);
1756 CFRelease(subjectSummary);
1757 }
1758 }
1759
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);
1764 if (statusCodes) {
1765 int32_t reason = statusCodes[numStatusCodes]; // stored at end of status codes array
1766 if (reason > 0) {
1767 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
1768 if (cfreason) {
1769 CFDictionarySetValue(certDict, kSecTrustRevocationReason, cfreason);
1770 CFRelease(cfreason);
1771 }
1772 }
1773 free(statusCodes);
1774 }
1775
1776 /* Populate the error in the leaf dictionary */
1777 if (ix == 0) {
1778 OSStatus error = errSecSuccess;
1779 (void)SecTrustGetCssmResultCode(trust, &error);
1780 CFStringRef errorStr = SecCopyErrorMessageString(error, NULL);
1781 if (errorStr) {
1782 CFDictionarySetValue(certDict, kSecPropertyTypeError, errorStr);
1783 CFRelease(errorStr);
1784 }
1785 }
1786
1787 CFArrayAppendValue(properties, certDict);
1788 }
1789
1790 return properties;
1791 }
1792 #endif
1793
1794 /* deprecated in 10.5 */
1795 OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors,
1796 uint32 *cssmAnchorCount)
1797 {
1798 #if !SECTRUST_OSX
1799 BEGIN_SECAPI
1800 CertGroup certs;
1801 Trust::gStore().getCssmRootCertificates(certs);
1802 Required(cssmAnchors) = certs.blobCerts();
1803 Required(cssmAnchorCount) = certs.count();
1804 END_SECAPI
1805 #else
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.");
1809 #endif
1810 if (cssmAnchors) {
1811 *cssmAnchors = NULL;
1812 }
1813 if (cssmAnchorCount) {
1814 *cssmAnchorCount = 0;
1815 }
1816 return errSecServiceNotAvailable;
1817 #endif
1818 }
1819
1820
1821 //
1822 // Get and set user trust settings. Deprecated in 10.5.
1823 // User Trust getter, deprecated, works as it always has.
1824 //
1825 OSStatus SecTrustGetUserTrust(SecCertificateRef certificate,
1826 SecPolicyRef policy, SecTrustUserSetting *trustSetting)
1827 {
1828 #if !SECTRUST_OSX
1829 BEGIN_SECAPI
1830 StorageManager::KeychainList searchList;
1831 globals().storageManager.getSearchList(searchList);
1832 Required(trustSetting) = Trust::gStore().find(
1833 Certificate::required(certificate),
1834 Policy::required(policy),
1835 searchList);
1836 END_SECAPI
1837 #else
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.");
1841 #endif
1842 return errSecServiceNotAvailable;
1843 #endif
1844 }
1845
1846 //
1847 // The public setter, also deprecated; it maps to the appropriate
1848 // Trust Settings call if possible, else throws errSecUnimplemented.
1849 //
1850 OSStatus SecTrustSetUserTrust(SecCertificateRef certificate,
1851 SecPolicyRef policy, SecTrustUserSetting trustSetting)
1852 {
1853 #if !SECTRUST_OSX
1854 SecTrustSettingsResult tsResult = kSecTrustSettingsResultInvalid;
1855 OSStatus ortn;
1856 Boolean isRoot;
1857
1858 Policy::required(policy);
1859 switch(trustSetting) {
1860 case kSecTrustResultProceed:
1861 /* different SecTrustSettingsResult depending in root-ness */
1862 ortn = SecCertificateIsSelfSigned(certificate, &isRoot);
1863 if(ortn) {
1864 return ortn;
1865 }
1866 if(isRoot) {
1867 tsResult = kSecTrustSettingsResultTrustRoot;
1868 }
1869 else {
1870 tsResult = kSecTrustSettingsResultTrustAsRoot;
1871 }
1872 break;
1873 case kSecTrustResultDeny:
1874 tsResult = kSecTrustSettingsResultDeny;
1875 break;
1876 default:
1877 return errSecUnimplemented;
1878 }
1879
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);
1889 CFRelease(cfNum);
1890 }
1891 return SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainUser,
1892 usageDict);
1893 #else
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.");
1897 #endif
1898 return errSecServiceNotAvailable;
1899 #endif
1900 }
1901
1902 //
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
1905 // view them.
1906 //
1907 OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate,
1908 SecPolicyRef policy, SecTrustUserSetting trustSetting)
1909 {
1910 #if !SECTRUST_OSX
1911 BEGIN_SECAPI
1912 switch (trustSetting) {
1913 case kSecTrustResultProceed:
1914 case kSecTrustResultConfirm:
1915 case kSecTrustResultDeny:
1916 case kSecTrustResultUnspecified:
1917 break;
1918 default:
1919 MacOSError::throwMe(errSecInvalidTrustSetting);
1920 }
1921 Trust::gStore().assign(
1922 Certificate::required(certificate),
1923 Policy::required(policy),
1924 trustSetting);
1925 END_SECAPI
1926 #else
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.");
1930 #endif
1931 return errSecServiceNotAvailable;
1932 #endif
1933 }