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