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