]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecTrust.cpp
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecTrust.cpp
1 /*
2 * Copyright (c) 2002-2017 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 <libDER/oids.h>
25 #include <Security/oidscert.h>
26
27 #include <Security/SecTrust.h>
28 #include <Security/SecTrustPriv.h>
29 #include "Trust.h"
30 #include <Security/SecBase.h>
31 #include "SecBridge.h"
32 #include <Security/SecInternal.h>
33 #include <Security/SecTrustSettings.h>
34 #include <Security/SecTrustSettingsPriv.h>
35 #include <Security/SecTrustStatusCodes.h>
36 #include <Security/SecCertificatePriv.h>
37 #include <Security/SecPolicyPriv.h>
38 #include <security_utilities/cfutilities.h>
39 #include <security_utilities/cfmunge.h>
40 #include <CoreFoundation/CoreFoundation.h>
41 #include <syslog.h>
42
43 // forward declarations
44 CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust);
45 CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust);
46 CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust);
47 static CSSM_TP_APPLE_EVIDENCE_INFO * SecTrustGetEvidenceInfo(SecTrustRef trust);
48
49 typedef struct SecTrustCheckExceptionContext {
50 CFDictionaryRef exception;
51 bool exceptionNotFound;
52 } SecTrustCheckExceptionContext;
53
54 //
55 // Sec* API bridge functions
56 //
57 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
58 OSStatus SecTrustSetParameters(
59 SecTrustRef trustRef,
60 CSSM_TP_ACTION action,
61 CFDataRef actionData)
62 {
63 /* bridge to support API functionality for legacy callers */
64 OSStatus status;
65 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
66 if (actionData) {
67 CSSM_APPLE_TP_ACTION_DATA *actionDataPtr = (CSSM_APPLE_TP_ACTION_DATA *) CFDataGetBytePtr(actionData);
68 if (actionDataPtr) {
69 actionFlags = actionDataPtr->ActionFlags;
70 }
71 }
72 // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS;
73 // both are sizeof(uint32) and the flag values have identical meanings
74 status = SecTrustSetOptions(trustRef, (SecTrustOptionFlags)actionFlags);
75
76 #if SECTRUST_DEPRECATION_WARNINGS
77 syslog(LOG_ERR, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
78 #endif
79
80 return status;
81 }
82
83 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
84 OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray)
85 {
86 /* this function is currently unsupported in unified SecTrust */
87 // TODO: pull all certs out of the specified keychains for the evaluation?
88 #if SECTRUST_DEPRECATION_WARNINGS
89 syslog(LOG_ERR, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors.");
90 #endif
91 return errSecSuccess;
92 }
93
94 //
95 // Construct the "official" result evidence and return it
96 //
97 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
98 OSStatus SecTrustGetResult(
99 SecTrustRef trustRef,
100 SecTrustResultType *result,
101 CFArrayRef *certChain, CSSM_TP_APPLE_EVIDENCE_INFO **statusChain)
102 {
103 /* bridge to support old functionality */
104 #if SECTRUST_DEPRECATION_WARNINGS
105 syslog(LOG_ERR, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
106 #endif
107 SecTrustResultType trustResult;
108 OSStatus status = SecTrustGetTrustResult(trustRef, &trustResult);
109 if (status != errSecSuccess) {
110 return status;
111 }
112 if (result) {
113 *result = trustResult;
114 }
115 if (certChain) {
116 *certChain = SecTrustCopyConstructedChain(trustRef);
117 }
118 if (statusChain) {
119 *statusChain = SecTrustGetEvidenceInfo(trustRef);
120 }
121 return status;
122 }
123
124 //
125 // Retrieve extended validation trust results
126 //
127 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
128 OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result)
129 {
130 /* bridge to support old functionality */
131 #if SECTRUST_DEPRECATION_WARNINGS
132 syslog(LOG_ERR, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead.");
133 #endif
134 CFDictionaryRef resultDict = SecTrustCopyResult(trust);
135 if (result == nil) {
136 CFReleaseNull(resultDict);
137 return errSecParam;
138 }
139 *result = resultDict;
140 return errSecSuccess;
141 }
142
143 //
144 // Retrieve CSSM-level information for those who want to dig down
145 //
146 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
147 OSStatus SecTrustGetCssmResult(SecTrustRef trust, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR *result)
148 {
149 /* this function is unsupported in unified SecTrust */
150 #if SECTRUST_DEPRECATION_WARNINGS
151 syslog(LOG_ERR, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead.");
152 #endif
153 if (result) {
154 *result = NULL;
155 }
156 return errSecServiceNotAvailable;
157 }
158
159 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode) {
160 switch (resultCode) {
161 /* explicitly not trusted */
162 case CSSMERR_TP_CERT_REVOKED:
163 case CSSMERR_APPLETP_TRUST_SETTING_DENY:
164 return 1;
165 /* failure to comply with X.509 */
166 case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS:
167 case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT:
168 case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT:
169 case CSSMERR_APPLETP_INVALID_AUTHORITY_ID:
170 case CSSMERR_TP_INVALID_CERTIFICATE:
171 case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN:
172 return 2;
173 case CSSMERR_TP_CERT_EXPIRED:
174 return 3;
175 /* doesn't chain to trusted root */
176 case CSSMERR_TP_NOT_TRUSTED:
177 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH:
178 return 4;
179 /* all others are policy-specific failures */
180 default:
181 return 5;
182 }
183 }
184
185 //
186 // Retrieve CSSM_LEVEL TP return code
187 //
188 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
189 OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result)
190 {
191 /* bridge to support old functionality */
192 #if SECTRUST_DEPRECATION_WARNINGS
193 syslog(LOG_ERR, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
194 #endif
195 if (!trustRef || !result) {
196 return errSecParam;
197 }
198
199 SecTrustResultType trustResult = kSecTrustResultInvalid;
200 (void) SecTrustGetTrustResult(trustRef, &trustResult);
201 if (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified) {
202 if (result) { *result = 0; }
203 return errSecSuccess;
204 }
205
206 OSStatus cssmResultCode = errSecSuccess;
207 uint8_t resultCodePriority = 0xFF;
208 CFIndex ix, count = SecTrustGetCertificateCount(trustRef);
209 for (ix = 0; ix < count; ix++) {
210 CFIndex numStatusCodes;
211 CSSM_RETURN *statusCodes = NULL;
212 statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trustRef, ix, &numStatusCodes);
213 if (statusCodes && numStatusCodes > 0) {
214 unsigned int statusIX;
215 for (statusIX = 0; statusIX < numStatusCodes; statusIX++) {
216 CSSM_RETURN currStatus = statusCodes[statusIX];
217 uint8_t currPriority = convertCssmResultToPriority(currStatus);
218 if (resultCodePriority > currPriority) {
219 cssmResultCode = currStatus;
220 resultCodePriority = currPriority;
221 }
222 }
223 }
224 if (statusCodes) { free(statusCodes); }
225 if (resultCodePriority == 1) { break; }
226 }
227
228 if (result) {
229 *result = cssmResultCode;
230 }
231 return errSecSuccess;
232 }
233
234 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
235 OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle)
236 {
237 /* this function is unsupported in unified SecTrust */
238 #if SECTRUST_DEPRECATION_WARNINGS
239 syslog(LOG_ERR, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
240 #endif
241 if (handle) {
242 *handle = NULL;
243 }
244 return errSecServiceNotAvailable;
245 }
246
247 //
248 // Get the user's default anchor certificate set
249 //
250 /* OS X only */
251 OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates)
252 {
253 BEGIN_SECAPI
254 CFArrayRef outArray;
255 OSStatus status = SecTrustSettingsCopyUnrestrictedRoots(
256 true, true, true, /* all domains */
257 &outArray);
258 if (status != errSecSuccess) {
259 return status;
260 }
261 CFIndex count = outArray ? CFArrayGetCount(outArray) : 0;
262 if(count == 0) {
263 return errSecNoTrustSettings;
264 }
265
266 /* Go through outArray and do a SecTrustEvaluate */
267 CFIndex i;
268 SecPolicyRef policy = SecPolicyCreateBasicX509();
269 SecTrustRef trust = NULL;
270 CFMutableArrayRef trustedCertArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
271 for (i = 0; i < count ; i++) {
272 SecTrustResultType result;
273 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(outArray, i);
274 status = SecTrustCreateWithCertificates(certificate, policy, &trust);
275 if (status != errSecSuccess) {
276 CFReleaseSafe(trustedCertArray);
277 goto out;
278 }
279 status = SecTrustEvaluate(trust, &result);
280 if (status != errSecSuccess) {
281 CFReleaseSafe(trustedCertArray);
282 goto out;
283 }
284 if (result != kSecTrustResultFatalTrustFailure) {
285 CFArrayAppendValue(trustedCertArray, certificate);
286 }
287 CFReleaseNull(trust);
288 }
289 if (CFArrayGetCount(trustedCertArray) == 0) {
290 status = errSecNoTrustSettings;
291 CFReleaseSafe(trustedCertArray);
292 goto out;
293 }
294 *anchorCertificates = trustedCertArray;
295 out:
296 CFReleaseSafe(outArray);
297 CFReleaseSafe(policy);
298 CFReleaseSafe(trust);
299 return status;
300 END_SECAPI
301 }
302
303 /*
304 * We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
305 *
306 * If you need a SecKeyRef based of the iOS based SecKey, check certificate chain
307 * length, get certificate with SecTrustGetCertificateAtIndex(0), use
308 * SecCertificateCopyKey() to get a iOS based key.
309 */
310 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
311 {
312 SecKeyRef pubKey = NULL;
313 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0);
314 #pragma clang diagnostic push
315 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
316 (void) SecCertificateCopyPublicKey(certificate, &pubKey);
317 #pragma clang diagnostic pop
318 return pubKey;
319 }
320
321 // cannot link against the new iOS SecTrust from this implementation,
322 // so there are no possible accessors for the fields of this struct
323 typedef struct __TSecTrust {
324 CFRuntimeBase _base;
325 CFArrayRef _certificates;
326 CFArrayRef _anchors;
327 CFTypeRef _policies;
328 CFArrayRef _responses;
329 CFArrayRef _SCTs;
330 CFArrayRef _trustedLogs;
331 CFDateRef _verifyDate;
332 CFTypeRef _chain;
333 SecKeyRef _publicKey;
334 CFArrayRef _details;
335 CFDictionaryRef _info;
336 CFArrayRef _exceptions;
337 SecTrustResultType _trustResult;
338 bool _anchorsOnly;
339 bool _keychainsAllowed;
340 void* _legacy_info_array;
341 void* _legacy_status_array;
342 dispatch_queue_t _trustQueue;
343 } TSecTrust;
344
345 CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust)
346 {
347 if (!trust) { return NULL; };
348 TSecTrust *secTrust = (TSecTrust *)trust;
349 if (secTrust->_certificates) {
350 CFRetain(secTrust->_certificates);
351 }
352 return secTrust->_certificates;
353 }
354
355 CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust)
356 {
357 if (!trust) { return NULL; };
358 TSecTrust *secTrust = (TSecTrust *)trust;
359 if (secTrust->_anchors) {
360 CFRetain(secTrust->_anchors);
361 }
362 return secTrust->_anchors;
363 }
364
365 // Return the constructed certificate chain for this trust reference,
366 // making output certificates pointer-equivalent to any provided input
367 // certificates (where possible) for legacy behavioral compatibility.
368 // Caller must release this array.
369 //
370 CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust)
371 {
372 CFMutableArrayRef certChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
373 CFIndex idx, count = SecTrustGetCertificateCount(trust);
374 for (idx=0; idx < count; idx++) {
375 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, idx);
376 if (certificate) {
377 CFArrayAppendValue(certChain, certificate);
378 }
379 }
380 // <rdar://24393060>
381 // Some callers make the assumption that the certificates in
382 // this chain are pointer-equivalent to ones they passed to the
383 // SecTrustCreateWithCertificates function. We'll maintain that
384 // behavior here for compatibility.
385 //
386 CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
387 CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
388 CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
389 CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
390 for (idx=0; idx < count; idx++) {
391 SecCertificateRef tmpCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, idx);
392 if (tmpCert) {
393 SecCertificateRef matchCert = NULL;
394 for (inputCertIdx=0; inputCertIdx < inputCertCount && !matchCert; inputCertIdx++) {
395 SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
396 if (inputCert && CFEqual(inputCert, tmpCert)) {
397 matchCert = inputCert;
398 }
399 }
400 for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount && !matchCert; inputAnchorIdx++) {
401 SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
402 if (inputAnchor && CFEqual(inputAnchor, tmpCert)) {
403 matchCert = inputAnchor;
404 }
405 }
406 if (matchCert) {
407 CFArraySetValueAtIndex(certChain, idx, matchCert);
408 }
409 }
410 }
411 if (inputCertArray) {
412 CFRelease(inputCertArray);
413 }
414 if (inputAnchorArray) {
415 CFRelease(inputAnchorArray);
416 }
417 return certChain;
418 }
419
420 //
421 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
422 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
423 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
424 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
425 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
426 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
427 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
428 // which would force re-evaluation.
429 //
430 static CSSM_TP_APPLE_EVIDENCE_INFO *
431 SecTrustGetEvidenceInfo(SecTrustRef trust)
432 {
433 TSecTrust *secTrust = (TSecTrust *)trust;
434 if (!secTrust) {
435 return NULL;
436 }
437 if (secTrust->_trustResult != kSecTrustResultInvalid &&
438 secTrust->_legacy_info_array) {
439 // we've already got valid evidence info, return it now.
440 return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
441 }
442
443 // Getting the count implicitly evaluates the chain if necessary.
444 CFIndex idx, count = SecTrustGetCertificateCount(trust);
445 CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
446 CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
447 CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
448 CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
449
450 CSSM_TP_APPLE_EVIDENCE_INFO *infoArray = (CSSM_TP_APPLE_EVIDENCE_INFO *)calloc(count, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO));
451 CSSM_RETURN *statusArray = NULL;
452 CFIndex numStatusCodes = 0;
453
454 // Set status codes for each certificate in the constructed chain
455 for (idx=0; idx < count; idx++) {
456 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx);
457 if (!cert) {
458 continue;
459 }
460 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
461
462 /* first the booleans (StatusBits flags) */
463 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
464 if (secTrust->_verifyDate) {
465 now = CFDateGetAbsoluteTime(secTrust->_verifyDate);
466 }
467 CFAbsoluteTime na = SecCertificateNotValidAfter(cert);
468 if (na < now) {
469 evInfo->StatusBits |= CSSM_CERT_STATUS_EXPIRED;
470 }
471 CFAbsoluteTime nb = SecCertificateNotValidBefore(cert);
472 if (nb > now) {
473 evInfo->StatusBits |= CSSM_CERT_STATUS_NOT_VALID_YET;
474 }
475 for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount; inputAnchorIdx++) {
476 SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
477 if (inputAnchor && CFEqual(inputAnchor, cert)) {
478 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_ANCHORS;
479 break;
480 }
481 }
482 for (inputCertIdx=0; inputCertIdx < inputCertCount; inputCertIdx++) {
483 SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
484 if (inputCert && CFEqual(inputCert, cert)) {
485 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS;
486 break;
487 }
488 }
489
490 /* See if there are trust settings for this certificate. */
491 CFStringRef hashStr = SecTrustSettingsCertHashStrFromCert(cert);
492 bool foundMatch = false;
493 bool foundAny = false;
494 CSSM_RETURN *errors = NULL;
495 uint32 errorCount = 0;
496 OSStatus status = 0;
497 SecTrustSettingsDomain foundDomain = kSecTrustSettingsDomainUser;
498 SecTrustSettingsResult foundResult = kSecTrustSettingsResultInvalid;
499 bool isSelfSigned = false;
500 if ((count - 1) == idx) {
501 // Only the last cert in the chain needs to be considered
502 Boolean selfSigned;
503 status = SecCertificateIsSelfSigned(cert, &selfSigned);
504 isSelfSigned = (status) ? false : ((selfSigned) ? true : false);
505 if (isSelfSigned) {
506 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_ROOT;
507 }
508 }
509 // STU: rdar://25554967
510 // %%% need to get policyOID, policyString, and keyUsage here!
511
512 status = SecTrustSettingsEvaluateCert(
513 hashStr, /* certHashStr */
514 NULL, /* policyOID (optional) */
515 NULL, /* policyString (optional) */
516 0, /* policyStringLen */
517 0, /* keyUsage */
518 isSelfSigned, /* isRootCert */
519 &foundDomain, /* foundDomain */
520 &errors, /* allowedErrors -- MUST FREE */
521 &errorCount, /* numAllowedErrors */
522 &foundResult, /* resultType */
523 &foundMatch, /* foundMatchingEntry */
524 &foundAny); /* foundAnyEntry */
525
526 if (status == errSecSuccess) {
527 if (foundMatch) {
528 switch (foundResult) {
529 case kSecTrustSettingsResultTrustRoot:
530 case kSecTrustSettingsResultTrustAsRoot:
531 /* these two can be disambiguated by IS_ROOT */
532 evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST;
533 break;
534 case kSecTrustSettingsResultDeny:
535 evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY;
536 break;
537 case kSecTrustSettingsResultUnspecified:
538 case kSecTrustSettingsResultInvalid:
539 default:
540 break;
541 }
542 }
543 }
544 if (errors) {
545 free(errors);
546 }
547 if (hashStr) {
548 CFRelease(hashStr);
549 }
550
551 CFIndex numCodes=0;
552 CSSM_RETURN *statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, idx, &numCodes);
553 if (statusCodes) {
554 // Realloc space for these status codes at end of our status codes block.
555 // Two important things to note:
556 // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes
557 // allocates one more element at the end for the CrlReason value.
558 // 2. realloc may cause the pointer to move, which means we will
559 // need to fix up the StatusCodes fields after we're done with this loop.
560 CFIndex totalStatusCodes = numStatusCodes + numCodes + 1;
561 statusArray = (CSSM_RETURN *)realloc(statusArray, totalStatusCodes * sizeof(CSSM_RETURN));
562 evInfo->StatusCodes = &statusArray[numStatusCodes];
563 evInfo->NumStatusCodes = (uint32)numCodes;
564 // Copy the new codes (plus one) into place
565 for (unsigned int cpix = 0; cpix <= numCodes; cpix++) {
566 evInfo->StatusCodes[cpix] = statusCodes[cpix];
567 }
568 numStatusCodes = totalStatusCodes;
569 free(statusCodes);
570 }
571
572 if(evInfo->StatusBits & (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST |
573 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY |
574 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR)) {
575 /* Something noteworthy happened involving TrustSettings */
576 uint32 whichDomain = 0;
577 switch(foundDomain) {
578 case kSecTrustSettingsDomainUser:
579 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER;
580 break;
581 case kSecTrustSettingsDomainAdmin:
582 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN;
583 break;
584 case kSecTrustSettingsDomainSystem:
585 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM;
586 break;
587 }
588 evInfo->StatusBits |= whichDomain;
589 }
590
591 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
592 //evInfo->Index = certInfo->index();
593 /* nonzero if cert came from a DLDB */
594 //evInfo->DlDbHandle = certInfo->dlDbHandle();
595 //evInfo->UniqueRecord = certInfo->uniqueRecord();
596 }
597
598 // Now that all the status codes have been allocated in a contiguous block,
599 // refresh the StatusCodes pointer in each array element.
600 numStatusCodes = 0;
601 for (idx=0; idx < count; idx++) {
602 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
603 evInfo->StatusCodes = &statusArray[numStatusCodes];
604 numStatusCodes += evInfo->NumStatusCodes + 1;
605 }
606
607 secTrust->_legacy_info_array = infoArray;
608 secTrust->_legacy_status_array = statusArray;
609
610 if (inputCertArray) {
611 CFRelease(inputCertArray);
612 }
613 if (inputAnchorArray) {
614 CFRelease(inputAnchorArray);
615 }
616
617 return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
618 }
619
620 CFArrayRef SecTrustCopyProperties(SecTrustRef trust) {
621 /* OS X creates a completely different structure with one dictionary for each certificate */
622 CFIndex ix, count = SecTrustGetCertificateCount(trust);
623
624 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, count,
625 &kCFTypeArrayCallBacks);
626
627 for (ix = 0; ix < count; ix++) {
628 CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
629 &kCFTypeDictionaryValueCallBacks);
630 /* Populate the certificate title */
631 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, ix);
632 if (cert) {
633 CFStringRef subjectSummary = SecCertificateCopySubjectSummary(cert);
634 if (subjectSummary) {
635 CFDictionaryAddValue(certDict, kSecPropertyTypeTitle, subjectSummary);
636 CFRelease(subjectSummary);
637 }
638 }
639
640 /* Populate a revocation reason if the cert was revoked */
641 CFIndex numStatusCodes;
642 CSSM_RETURN *statusCodes = NULL;
643 statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, ix, &numStatusCodes);
644 if (statusCodes) {
645 SInt32 reason = statusCodes[numStatusCodes]; // stored at end of status codes array
646 if (reason > 0) {
647 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
648 if (cfreason) {
649 CFDictionarySetValue(certDict, kSecTrustRevocationReason, cfreason);
650 CFRelease(cfreason);
651 }
652 }
653 free(statusCodes);
654 }
655
656 /* Populate the error in the leaf dictionary */
657 if (ix == 0) {
658 OSStatus error = errSecSuccess;
659 (void)SecTrustGetCssmResultCode(trust, &error);
660 CFStringRef errorStr = SecCopyErrorMessageString(error, NULL);
661 if (errorStr) {
662 CFDictionarySetValue(certDict, kSecPropertyTypeError, errorStr);
663 CFRelease(errorStr);
664 }
665 }
666
667 CFArrayAppendValue(properties, certDict);
668 CFRelease(certDict);
669 }
670
671 return properties;
672 }
673
674 /* deprecated in 10.5 */
675 OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors,
676 uint32 *cssmAnchorCount)
677 {
678 /* this function is unsupported in unified SecTrust */
679 #if SECTRUST_DEPRECATION_WARNINGS
680 syslog(LOG_ERR, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
681 #endif
682 if (cssmAnchors) {
683 *cssmAnchors = NULL;
684 }
685 if (cssmAnchorCount) {
686 *cssmAnchorCount = 0;
687 }
688 return errSecServiceNotAvailable;
689 }
690
691
692 //
693 // Get and set user trust settings. Deprecated in 10.5.
694 // User Trust getter, deprecated, works as it always has.
695 //
696 OSStatus SecTrustGetUserTrust(SecCertificateRef certificate,
697 SecPolicyRef policy, SecTrustUserSetting *trustSetting)
698 {
699 /* this function is unsupported in unified SecTrust */
700 #if SECTRUST_DEPRECATION_WARNINGS
701 syslog(LOG_ERR, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
702 #endif
703 return errSecServiceNotAvailable;
704 }
705
706 //
707 // The public setter, also deprecated; it maps to the appropriate
708 // Trust Settings call if possible, else throws errSecUnimplemented.
709 //
710 OSStatus SecTrustSetUserTrust(SecCertificateRef certificate,
711 SecPolicyRef policy, SecTrustUserSetting trustSetting)
712 {
713 /* this function is unsupported in unified SecTrust */
714 #if SECTRUST_DEPRECATION_WARNINGS
715 syslog(LOG_ERR, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
716 #endif
717 return errSecServiceNotAvailable;
718 }
719
720 //
721 // This one is the now-private version of what SecTrustSetUserTrust() used to
722 // be. The public API can no longer manipulate User Trust settings, only
723 // view them.
724 //
725 OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate,
726 SecPolicyRef policy, SecTrustUserSetting trustSetting)
727 {
728 /* this function is unsupported in unified SecTrust */
729 #if SECTRUST_DEPRECATION_WARNINGS
730 syslog(LOG_ERR, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
731 #endif
732 return errSecServiceNotAvailable;
733 }