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