]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecTrust.cpp
Security-58286.200.222.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 "SecTrust.h"
28 #include "SecTrustPriv.h"
29 #include "Trust.h"
30 #include "SecBase.h"
31 #include "SecBridge.h"
32 #include "SecInternal.h"
33 #include "SecTrustSettings.h"
34 #include "SecTrustSettingsPriv.h"
35 #include "SecTrustStatusCodes.h"
36 #include "SecCertificatePriv.h"
37 #include "SecPolicyPriv.h"
38 #include <security_utilities/cfutilities.h>
39 #include <security_utilities/cfmunge.h>
40 #include <CoreFoundation/CoreFoundation.h>
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 static bool isSoftwareUpdateDevelopment(SecTrustRef trust) {
186 bool isPolicy = false, isEKU = false;
187 CFArrayRef policies = NULL;
188
189 /* Policy used to evaluate was SWUpdateSigning */
190 SecTrustCopyPolicies(trust, &policies);
191 if (policies) {
192 SecPolicyRef swUpdatePolicy = SecPolicyCreateAppleSWUpdateSigning();
193 if (swUpdatePolicy && CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)),
194 swUpdatePolicy)) {
195 isPolicy = true;
196 }
197 if (swUpdatePolicy) { CFRelease(swUpdatePolicy); }
198 CFRelease(policies);
199 }
200 if (!isPolicy) {
201 return false;
202 }
203
204 /* Only error was EKU on the leaf */
205 CFArrayRef details = SecTrustCopyFilteredDetails(trust);
206 CFIndex ix, count = CFArrayGetCount(details);
207 bool hasDisqualifyingError = false;
208 for (ix = 0; ix < count; ix++) {
209 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
210 if (ix == 0) { // Leaf
211 if (CFDictionaryGetCount(detail) != 1 || // One error
212 CFDictionaryGetValue(detail, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse) { // kSecPolicyCheckExtendedKeyUsage
213 hasDisqualifyingError = true;
214 break;
215 }
216 } else {
217 if (CFDictionaryGetCount(detail) > 0) { // No errors on other certs
218 hasDisqualifyingError = true;
219 break;
220 }
221 }
222 }
223 CFReleaseSafe(details);
224 if (hasDisqualifyingError) {
225 return false;
226 }
227
228 /* EKU on the leaf is the Apple Development Code Signing OID */
229 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
230 CSSM_DATA *fieldValue = NULL;
231 if (errSecSuccess != SecCertificateCopyFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, &fieldValue)) {
232 return false;
233 }
234 if (fieldValue && fieldValue->Data && fieldValue->Length == sizeof(CSSM_X509_EXTENSION)) {
235 const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)fieldValue->Data;
236 if (ext->format == CSSM_X509_DATAFORMAT_PARSED) {
237 const CE_ExtendedKeyUsage *ekus = (const CE_ExtendedKeyUsage *)ext->value.parsedValue;
238 if (ekus && (ekus->numPurposes == 1) && ekus->purposes[0].Data &&
239 (ekus->purposes[0].Length == CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Length) &&
240 (memcmp(ekus->purposes[0].Data, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Data,
241 ekus->purposes[0].Length) == 0)) {
242 isEKU = true;
243 }
244 }
245 }
246 SecCertificateReleaseFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, fieldValue);
247 return isEKU;
248 }
249
250 //
251 // Retrieve CSSM_LEVEL TP return code
252 //
253 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
254 OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result)
255 {
256 /* bridge to support old functionality */
257 #if SECTRUST_DEPRECATION_WARNINGS
258 syslog(LOG_ERR, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
259 #endif
260 if (!trustRef || !result) {
261 return errSecParam;
262 }
263
264 SecTrustResultType trustResult = kSecTrustResultInvalid;
265 (void) SecTrustGetTrustResult(trustRef, &trustResult);
266 if (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified) {
267 if (result) { *result = 0; }
268 return errSecSuccess;
269 }
270
271 /* Development Software Update certs return a special error code when evaluated
272 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
273 if (isSoftwareUpdateDevelopment(trustRef)) {
274 if (result) {
275 *result = CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT;
276 }
277 return errSecSuccess;
278 }
279
280 OSStatus cssmResultCode = errSecSuccess;
281 uint8_t resultCodePriority = 0xFF;
282 CFIndex ix, count = SecTrustGetCertificateCount(trustRef);
283 for (ix = 0; ix < count; ix++) {
284 CFIndex numStatusCodes;
285 CSSM_RETURN *statusCodes = NULL;
286 statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trustRef, ix, &numStatusCodes);
287 if (statusCodes && numStatusCodes > 0) {
288 unsigned int statusIX;
289 for (statusIX = 0; statusIX < numStatusCodes; statusIX++) {
290 CSSM_RETURN currStatus = statusCodes[statusIX];
291 uint8_t currPriority = convertCssmResultToPriority(currStatus);
292 if (resultCodePriority > currPriority) {
293 cssmResultCode = currStatus;
294 resultCodePriority = currPriority;
295 }
296 }
297 }
298 if (statusCodes) { free(statusCodes); }
299 if (resultCodePriority == 1) { break; }
300 }
301
302 if (result) {
303 *result = cssmResultCode;
304 }
305 return errSecSuccess;
306 }
307
308 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
309 OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle)
310 {
311 /* this function is unsupported in unified SecTrust */
312 #if SECTRUST_DEPRECATION_WARNINGS
313 syslog(LOG_ERR, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
314 #endif
315 if (handle) {
316 *handle = NULL;
317 }
318 return errSecServiceNotAvailable;
319 }
320
321 //
322 // Get the user's default anchor certificate set
323 //
324 /* OS X only */
325 OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates)
326 {
327 BEGIN_SECAPI
328 CFArrayRef outArray;
329 OSStatus status = SecTrustSettingsCopyUnrestrictedRoots(
330 true, true, true, /* all domains */
331 &outArray);
332 if (status != errSecSuccess) {
333 return status;
334 }
335 CFIndex count = outArray ? CFArrayGetCount(outArray) : 0;
336 if(count == 0) {
337 return errSecNoTrustSettings;
338 }
339
340 /* Go through outArray and do a SecTrustEvaluate */
341 CFIndex i;
342 SecPolicyRef policy = SecPolicyCreateBasicX509();
343 SecTrustRef trust = NULL;
344 CFMutableArrayRef trustedCertArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
345 for (i = 0; i < count ; i++) {
346 SecTrustResultType result;
347 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(outArray, i);
348 status = SecTrustCreateWithCertificates(certificate, policy, &trust);
349 if (status != errSecSuccess) {
350 CFReleaseSafe(trustedCertArray);
351 goto out;
352 }
353 status = SecTrustEvaluate(trust, &result);
354 if (status != errSecSuccess) {
355 CFReleaseSafe(trustedCertArray);
356 goto out;
357 }
358 if (result != kSecTrustResultFatalTrustFailure) {
359 CFArrayAppendValue(trustedCertArray, certificate);
360 }
361 CFReleaseNull(trust);
362 }
363 if (CFArrayGetCount(trustedCertArray) == 0) {
364 status = errSecNoTrustSettings;
365 CFReleaseSafe(trustedCertArray);
366 goto out;
367 }
368 *anchorCertificates = trustedCertArray;
369 out:
370 CFReleaseSafe(outArray);
371 CFReleaseSafe(policy);
372 CFReleaseSafe(trust);
373 return status;
374 END_SECAPI
375 }
376
377 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
378 */
379 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
380 {
381 SecKeyRef pubKey = NULL;
382 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0);
383 #pragma clang diagnostic push
384 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
385 (void) SecCertificateCopyPublicKey(certificate, &pubKey);
386 #pragma clang diagnostic pop
387 return pubKey;
388 }
389
390 // cannot link against the new iOS SecTrust from this implementation,
391 // so there are no possible accessors for the fields of this struct
392 typedef struct __TSecTrust {
393 CFRuntimeBase _base;
394 CFArrayRef _certificates;
395 CFArrayRef _anchors;
396 CFTypeRef _policies;
397 CFArrayRef _responses;
398 CFArrayRef _SCTs;
399 CFArrayRef _trustedLogs;
400 CFDateRef _verifyDate;
401 CFTypeRef _chain;
402 SecKeyRef _publicKey;
403 CFArrayRef _details;
404 CFDictionaryRef _info;
405 CFArrayRef _exceptions;
406 SecTrustResultType _trustResult;
407 bool _anchorsOnly;
408 bool _keychainsAllowed;
409 void* _legacy_info_array;
410 void* _legacy_status_array;
411 dispatch_queue_t _trustQueue;
412 } TSecTrust;
413
414 CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust)
415 {
416 if (!trust) { return NULL; };
417 TSecTrust *secTrust = (TSecTrust *)trust;
418 if (secTrust->_certificates) {
419 CFRetain(secTrust->_certificates);
420 }
421 return secTrust->_certificates;
422 }
423
424 CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust)
425 {
426 if (!trust) { return NULL; };
427 TSecTrust *secTrust = (TSecTrust *)trust;
428 if (secTrust->_anchors) {
429 CFRetain(secTrust->_anchors);
430 }
431 return secTrust->_anchors;
432 }
433
434 // Return the constructed certificate chain for this trust reference,
435 // making output certificates pointer-equivalent to any provided input
436 // certificates (where possible) for legacy behavioral compatibility.
437 // Caller must release this array.
438 //
439 CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust)
440 {
441 CFMutableArrayRef certChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
442 CFIndex idx, count = SecTrustGetCertificateCount(trust);
443 for (idx=0; idx < count; idx++) {
444 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, idx);
445 if (certificate) {
446 CFArrayAppendValue(certChain, certificate);
447 }
448 }
449 // <rdar://24393060>
450 // Some callers make the assumption that the certificates in
451 // this chain are pointer-equivalent to ones they passed to the
452 // SecTrustCreateWithCertificates function. We'll maintain that
453 // behavior here for compatibility.
454 //
455 CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
456 CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
457 CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
458 CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
459 for (idx=0; idx < count; idx++) {
460 SecCertificateRef tmpCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, idx);
461 if (tmpCert) {
462 SecCertificateRef matchCert = NULL;
463 for (inputCertIdx=0; inputCertIdx < inputCertCount && !matchCert; inputCertIdx++) {
464 SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
465 if (inputCert && CFEqual(inputCert, tmpCert)) {
466 matchCert = inputCert;
467 }
468 }
469 for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount && !matchCert; inputAnchorIdx++) {
470 SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
471 if (inputAnchor && CFEqual(inputAnchor, tmpCert)) {
472 matchCert = inputAnchor;
473 }
474 }
475 if (matchCert) {
476 CFArraySetValueAtIndex(certChain, idx, matchCert);
477 }
478 }
479 }
480 if (inputCertArray) {
481 CFRelease(inputCertArray);
482 }
483 if (inputAnchorArray) {
484 CFRelease(inputAnchorArray);
485 }
486 return certChain;
487 }
488
489 //
490 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
491 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
492 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
493 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
494 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
495 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
496 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
497 // which would force re-evaluation.
498 //
499 static CSSM_TP_APPLE_EVIDENCE_INFO *
500 SecTrustGetEvidenceInfo(SecTrustRef trust)
501 {
502 TSecTrust *secTrust = (TSecTrust *)trust;
503 if (!secTrust) {
504 return NULL;
505 }
506 if (secTrust->_trustResult != kSecTrustResultInvalid &&
507 secTrust->_legacy_info_array) {
508 // we've already got valid evidence info, return it now.
509 return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
510 }
511
512 // Getting the count implicitly evaluates the chain if necessary.
513 CFIndex idx, count = SecTrustGetCertificateCount(trust);
514 CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
515 CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
516 CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
517 CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
518
519 CSSM_TP_APPLE_EVIDENCE_INFO *infoArray = (CSSM_TP_APPLE_EVIDENCE_INFO *)calloc(count, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO));
520 CSSM_RETURN *statusArray = NULL;
521 CFIndex numStatusCodes = 0;
522
523 // Set status codes for each certificate in the constructed chain
524 for (idx=0; idx < count; idx++) {
525 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx);
526 if (!cert) {
527 continue;
528 }
529 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
530
531 /* first the booleans (StatusBits flags) */
532 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
533 if (secTrust->_verifyDate) {
534 now = CFDateGetAbsoluteTime(secTrust->_verifyDate);
535 }
536 CFAbsoluteTime na = SecCertificateNotValidAfter(cert);
537 if (na < now) {
538 evInfo->StatusBits |= CSSM_CERT_STATUS_EXPIRED;
539 }
540 CFAbsoluteTime nb = SecCertificateNotValidBefore(cert);
541 if (nb > now) {
542 evInfo->StatusBits |= CSSM_CERT_STATUS_NOT_VALID_YET;
543 }
544 for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount; inputAnchorIdx++) {
545 SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
546 if (inputAnchor && CFEqual(inputAnchor, cert)) {
547 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_ANCHORS;
548 break;
549 }
550 }
551 for (inputCertIdx=0; inputCertIdx < inputCertCount; inputCertIdx++) {
552 SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
553 if (inputCert && CFEqual(inputCert, cert)) {
554 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS;
555 break;
556 }
557 }
558
559 /* See if there are trust settings for this certificate. */
560 CFStringRef hashStr = SecTrustSettingsCertHashStrFromCert(cert);
561 bool foundMatch = false;
562 bool foundAny = false;
563 CSSM_RETURN *errors = NULL;
564 uint32 errorCount = 0;
565 OSStatus status = 0;
566 SecTrustSettingsDomain foundDomain = kSecTrustSettingsDomainUser;
567 SecTrustSettingsResult foundResult = kSecTrustSettingsResultInvalid;
568 bool isSelfSigned = false;
569 if ((count - 1) == idx) {
570 // Only the last cert in the chain needs to be considered
571 Boolean selfSigned;
572 status = SecCertificateIsSelfSigned(cert, &selfSigned);
573 isSelfSigned = (status) ? false : ((selfSigned) ? true : false);
574 if (isSelfSigned) {
575 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_ROOT;
576 }
577 }
578 // STU: rdar://25554967
579 // %%% need to get policyOID, policyString, and keyUsage here!
580
581 status = SecTrustSettingsEvaluateCert(
582 hashStr, /* certHashStr */
583 NULL, /* policyOID (optional) */
584 NULL, /* policyString (optional) */
585 0, /* policyStringLen */
586 0, /* keyUsage */
587 isSelfSigned, /* isRootCert */
588 &foundDomain, /* foundDomain */
589 &errors, /* allowedErrors -- MUST FREE */
590 &errorCount, /* numAllowedErrors */
591 &foundResult, /* resultType */
592 &foundMatch, /* foundMatchingEntry */
593 &foundAny); /* foundAnyEntry */
594
595 if (status == errSecSuccess) {
596 if (foundMatch) {
597 switch (foundResult) {
598 case kSecTrustSettingsResultTrustRoot:
599 case kSecTrustSettingsResultTrustAsRoot:
600 /* these two can be disambiguated by IS_ROOT */
601 evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST;
602 break;
603 case kSecTrustSettingsResultDeny:
604 evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY;
605 break;
606 case kSecTrustSettingsResultUnspecified:
607 case kSecTrustSettingsResultInvalid:
608 default:
609 break;
610 }
611 }
612 }
613 if (errors) {
614 free(errors);
615 }
616 if (hashStr) {
617 CFRelease(hashStr);
618 }
619
620 CFIndex numCodes=0;
621 CSSM_RETURN *statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, idx, &numCodes);
622 if (statusCodes) {
623 // Realloc space for these status codes at end of our status codes block.
624 // Two important things to note:
625 // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes
626 // allocates one more element at the end for the CrlReason value.
627 // 2. realloc may cause the pointer to move, which means we will
628 // need to fix up the StatusCodes fields after we're done with this loop.
629 CFIndex totalStatusCodes = numStatusCodes + numCodes + 1;
630 statusArray = (CSSM_RETURN *)realloc(statusArray, totalStatusCodes * sizeof(CSSM_RETURN));
631 evInfo->StatusCodes = &statusArray[numStatusCodes];
632 evInfo->NumStatusCodes = (uint32)numCodes;
633 // Copy the new codes (plus one) into place
634 for (unsigned int cpix = 0; cpix <= numCodes; cpix++) {
635 evInfo->StatusCodes[cpix] = statusCodes[cpix];
636 }
637 numStatusCodes = totalStatusCodes;
638 free(statusCodes);
639 }
640
641 if(evInfo->StatusBits & (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST |
642 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY |
643 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR)) {
644 /* Something noteworthy happened involving TrustSettings */
645 uint32 whichDomain = 0;
646 switch(foundDomain) {
647 case kSecTrustSettingsDomainUser:
648 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER;
649 break;
650 case kSecTrustSettingsDomainAdmin:
651 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN;
652 break;
653 case kSecTrustSettingsDomainSystem:
654 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM;
655 break;
656 }
657 evInfo->StatusBits |= whichDomain;
658 }
659
660 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
661 //evInfo->Index = certInfo->index();
662 /* nonzero if cert came from a DLDB */
663 //evInfo->DlDbHandle = certInfo->dlDbHandle();
664 //evInfo->UniqueRecord = certInfo->uniqueRecord();
665 }
666
667 // Now that all the status codes have been allocated in a contiguous block,
668 // refresh the StatusCodes pointer in each array element.
669 numStatusCodes = 0;
670 for (idx=0; idx < count; idx++) {
671 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
672 evInfo->StatusCodes = &statusArray[numStatusCodes];
673 numStatusCodes += evInfo->NumStatusCodes + 1;
674 }
675
676 secTrust->_legacy_info_array = infoArray;
677 secTrust->_legacy_status_array = statusArray;
678
679 if (inputCertArray) {
680 CFRelease(inputCertArray);
681 }
682 if (inputAnchorArray) {
683 CFRelease(inputAnchorArray);
684 }
685
686 return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
687 }
688
689 CFArrayRef SecTrustCopyProperties(SecTrustRef trust) {
690 /* OS X creates a completely different structure with one dictionary for each certificate */
691 CFIndex ix, count = SecTrustGetCertificateCount(trust);
692
693 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, count,
694 &kCFTypeArrayCallBacks);
695
696 for (ix = 0; ix < count; ix++) {
697 CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
698 &kCFTypeDictionaryValueCallBacks);
699 /* Populate the certificate title */
700 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, ix);
701 if (cert) {
702 CFStringRef subjectSummary = SecCertificateCopySubjectSummary(cert);
703 if (subjectSummary) {
704 CFDictionaryAddValue(certDict, kSecPropertyTypeTitle, subjectSummary);
705 CFRelease(subjectSummary);
706 }
707 }
708
709 /* Populate a revocation reason if the cert was revoked */
710 CFIndex numStatusCodes;
711 CSSM_RETURN *statusCodes = NULL;
712 statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, ix, &numStatusCodes);
713 if (statusCodes) {
714 SInt32 reason = statusCodes[numStatusCodes]; // stored at end of status codes array
715 if (reason > 0) {
716 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
717 if (cfreason) {
718 CFDictionarySetValue(certDict, kSecTrustRevocationReason, cfreason);
719 CFRelease(cfreason);
720 }
721 }
722 free(statusCodes);
723 }
724
725 /* Populate the error in the leaf dictionary */
726 if (ix == 0) {
727 OSStatus error = errSecSuccess;
728 (void)SecTrustGetCssmResultCode(trust, &error);
729 CFStringRef errorStr = SecCopyErrorMessageString(error, NULL);
730 if (errorStr) {
731 CFDictionarySetValue(certDict, kSecPropertyTypeError, errorStr);
732 CFRelease(errorStr);
733 }
734 }
735
736 CFArrayAppendValue(properties, certDict);
737 CFRelease(certDict);
738 }
739
740 return properties;
741 }
742
743 /* deprecated in 10.5 */
744 OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors,
745 uint32 *cssmAnchorCount)
746 {
747 /* this function is unsupported in unified SecTrust */
748 #if SECTRUST_DEPRECATION_WARNINGS
749 syslog(LOG_ERR, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
750 #endif
751 if (cssmAnchors) {
752 *cssmAnchors = NULL;
753 }
754 if (cssmAnchorCount) {
755 *cssmAnchorCount = 0;
756 }
757 return errSecServiceNotAvailable;
758 }
759
760
761 //
762 // Get and set user trust settings. Deprecated in 10.5.
763 // User Trust getter, deprecated, works as it always has.
764 //
765 OSStatus SecTrustGetUserTrust(SecCertificateRef certificate,
766 SecPolicyRef policy, SecTrustUserSetting *trustSetting)
767 {
768 /* this function is unsupported in unified SecTrust */
769 #if SECTRUST_DEPRECATION_WARNINGS
770 syslog(LOG_ERR, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
771 #endif
772 return errSecServiceNotAvailable;
773 }
774
775 //
776 // The public setter, also deprecated; it maps to the appropriate
777 // Trust Settings call if possible, else throws errSecUnimplemented.
778 //
779 OSStatus SecTrustSetUserTrust(SecCertificateRef certificate,
780 SecPolicyRef policy, SecTrustUserSetting trustSetting)
781 {
782 /* this function is unsupported in unified SecTrust */
783 #if SECTRUST_DEPRECATION_WARNINGS
784 syslog(LOG_ERR, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
785 #endif
786 return errSecServiceNotAvailable;
787 }
788
789 //
790 // This one is the now-private version of what SecTrustSetUserTrust() used to
791 // be. The public API can no longer manipulate User Trust settings, only
792 // view them.
793 //
794 OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate,
795 SecPolicyRef policy, SecTrustUserSetting trustSetting)
796 {
797 /* this function is unsupported in unified SecTrust */
798 #if SECTRUST_DEPRECATION_WARNINGS
799 syslog(LOG_ERR, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
800 #endif
801 return errSecServiceNotAvailable;
802 }