]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_keychain/lib/SecTrust.cpp
Security-58286.70.7.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecTrust.cpp
CommitLineData
b1ab9ed8 1/*
866f8763 2 * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved.
b1ab9ed8
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
d87e1158 5 *
b1ab9ed8
A
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.
d87e1158 12 *
b1ab9ed8
A
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.
d87e1158 20 *
b1ab9ed8
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
ecaf5866
A
24#include <libDER/oids.h>
25#include <Security/oidscert.h>
26
b1ab9ed8
A
27#include "SecTrust.h"
28#include "SecTrustPriv.h"
29#include "Trust.h"
5c19dc3a 30#include "SecBase.h"
b1ab9ed8 31#include "SecBridge.h"
427c49bc 32#include "SecInternal.h"
b1ab9ed8 33#include "SecTrustSettings.h"
fa7225c8 34#include "SecTrustSettingsPriv.h"
866f8763 35#include "SecTrustStatusCodes.h"
b1ab9ed8 36#include "SecCertificatePriv.h"
5c19dc3a 37#include "SecPolicyPriv.h"
b1ab9ed8 38#include <security_utilities/cfutilities.h>
427c49bc 39#include <security_utilities/cfmunge.h>
b1ab9ed8 40#include <CoreFoundation/CoreFoundation.h>
5c19dc3a 41#include <syslog.h>
b1ab9ed8 42
427c49bc 43// forward declarations
fa7225c8
A
44CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust);
45CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust);
46CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust);
47static CSSM_TP_APPLE_EVIDENCE_INFO * SecTrustGetEvidenceInfo(SecTrustRef trust);
427c49bc
A
48
49typedef struct SecTrustCheckExceptionContext {
50 CFDictionaryRef exception;
51 bool exceptionNotFound;
52} SecTrustCheckExceptionContext;
53
54// public trust result constants
5c19dc3a
A
55const CFStringRef kSecTrustEvaluationDate = CFSTR("TrustEvaluationDate");
56const CFStringRef kSecTrustExtendedValidation = CFSTR("TrustExtendedValidation");
57const CFStringRef kSecTrustOrganizationName = CFSTR("Organization");
58const CFStringRef kSecTrustResultValue = CFSTR("TrustResultValue");
59const CFStringRef kSecTrustRevocationChecked = CFSTR("TrustRevocationChecked");
60const CFStringRef kSecTrustRevocationReason = CFSTR("TrustRevocationReason");
61const CFStringRef kSecTrustRevocationValidUntilDate = CFSTR("TrustExpirationDate");
62const CFStringRef kSecTrustResultDetails = CFSTR("TrustResultDetails");
b1ab9ed8 63
b1ab9ed8
A
64//
65// Sec* API bridge functions
66//
5c19dc3a 67/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
b1ab9ed8
A
68OSStatus SecTrustSetParameters(
69 SecTrustRef trustRef,
70 CSSM_TP_ACTION action,
71 CFDataRef actionData)
72{
5c19dc3a
A
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
b1ab9ed8 89
5c19dc3a 90 return status;
5c19dc3a
A
91}
92
5c19dc3a 93/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
b1ab9ed8
A
94OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray)
95{
5c19dc3a
A
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;
b1ab9ed8 102}
b1ab9ed8
A
103
104//
105// Construct the "official" result evidence and return it
106//
5c19dc3a 107/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
b1ab9ed8
A
108OSStatus SecTrustGetResult(
109 SecTrustRef trustRef,
110 SecTrustResultType *result,
111 CFArrayRef *certChain, CSSM_TP_APPLE_EVIDENCE_INFO **statusChain)
112{
5c19dc3a
A
113 /* bridge to support old functionality */
114#if SECTRUST_DEPRECATION_WARNINGS
fa7225c8 115 syslog(LOG_ERR, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
5c19dc3a 116#endif
fa7225c8
A
117 SecTrustResultType trustResult;
118 OSStatus status = SecTrustGetTrustResult(trustRef, &trustResult);
119 if (status != errSecSuccess) {
120 return status;
121 }
5c19dc3a
A
122 if (result) {
123 *result = trustResult;
124 }
fa7225c8
A
125 if (certChain) {
126 *certChain = SecTrustCopyConstructedChain(trustRef);
127 }
128 if (statusChain) {
129 *statusChain = SecTrustGetEvidenceInfo(trustRef);
5c19dc3a
A
130 }
131 return status;
b1ab9ed8
A
132}
133
134//
135// Retrieve extended validation trust results
136//
5c19dc3a 137/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
b1ab9ed8
A
138OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result)
139{
5c19dc3a
A
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) {
6b200bc3 146 CFReleaseNull(resultDict);
5c19dc3a
A
147 return errSecParam;
148 }
149 *result = resultDict;
150 return errSecSuccess;
b1ab9ed8
A
151}
152
153//
154// Retrieve CSSM-level information for those who want to dig down
155//
5c19dc3a 156/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
b1ab9ed8
A
157OSStatus SecTrustGetCssmResult(SecTrustRef trust, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR *result)
158{
5c19dc3a
A
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;
b1ab9ed8
A
167}
168
fa7225c8
A
169static 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
fa7225c8
A
195static 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 */
6b200bc3 215 CFArrayRef details = SecTrustCopyFilteredDetails(trust);
fa7225c8 216 CFIndex ix, count = CFArrayGetCount(details);
6b200bc3 217 bool hasDisqualifyingError = false;
fa7225c8
A
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
6b200bc3
A
222 CFDictionaryGetValue(detail, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse) { // kSecPolicyCheckExtendedKeyUsage
223 hasDisqualifyingError = true;
224 break;
225 }
fa7225c8
A
226 } else {
227 if (CFDictionaryGetCount(detail) > 0) { // No errors on other certs
6b200bc3
A
228 hasDisqualifyingError = true;
229 break;
fa7225c8
A
230 }
231 }
232 }
6b200bc3
A
233 CFReleaseSafe(details);
234 if (hasDisqualifyingError) {
235 return false;
236 }
fa7225c8
A
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;
5c19dc3a 258}
5c19dc3a 259
b1ab9ed8
A
260//
261// Retrieve CSSM_LEVEL TP return code
262//
5c19dc3a 263/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
b1ab9ed8
A
264OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result)
265{
5c19dc3a
A
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 }
fa7225c8
A
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++) {
866f8763 294 CFIndex numStatusCodes;
fa7225c8 295 CSSM_RETURN *statusCodes = NULL;
866f8763 296 statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trustRef, ix, &numStatusCodes);
fa7225c8
A
297 if (statusCodes && numStatusCodes > 0) {
298 unsigned int statusIX;
299 for (statusIX = 0; statusIX < numStatusCodes; statusIX++) {
300 CSSM_RETURN currStatus = statusCodes[statusIX];
6b200bc3
A
301 uint8_t currPriority = convertCssmResultToPriority(currStatus);
302 if (resultCodePriority > currPriority) {
fa7225c8 303 cssmResultCode = currStatus;
6b200bc3 304 resultCodePriority = currPriority;
fa7225c8
A
305 }
306 }
307 }
308 if (statusCodes) { free(statusCodes); }
309 if (resultCodePriority == 1) { break; }
310 }
311
5c19dc3a
A
312 if (result) {
313 *result = cssmResultCode;
314 }
5c19dc3a 315 return errSecSuccess;
b1ab9ed8
A
316}
317
5c19dc3a 318/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
b1ab9ed8
A
319OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle)
320{
5c19dc3a
A
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;
427c49bc 329}
b1ab9ed8
A
330
331//
332// Get the user's default anchor certificate set
333//
5c19dc3a 334/* OS X only */
b1ab9ed8
A
335OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates)
336{
427c49bc 337 BEGIN_SECAPI
866f8763
A
338 CFArrayRef outArray;
339 OSStatus status = SecTrustSettingsCopyUnrestrictedRoots(
427c49bc 340 true, true, true, /* all domains */
866f8763
A
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;
378out:
379 CFReleaseSafe(outArray);
380 CFReleaseSafe(policy);
381 return status;
427c49bc 382 END_SECAPI
b1ab9ed8
A
383}
384
5c19dc3a
A
385/* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
386 */
387SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
388{
389 SecKeyRef pubKey = NULL;
390 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0);
391 (void) SecCertificateCopyPublicKey(certificate, &pubKey);
392 return pubKey;
393}
b1ab9ed8 394
fa7225c8
A
395// cannot link against the new iOS SecTrust from this implementation,
396// so there are no possible accessors for the fields of this struct
397typedef 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;
6b200bc3 416 dispatch_queue_t _trustQueue;
fa7225c8
A
417} TSecTrust;
418
fa7225c8
A
419CFArrayRef 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}
fa7225c8 428
fa7225c8
A
429CFArrayRef 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}
fa7225c8 438
fa7225c8
A
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//
444CFArrayRef 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}
fa7225c8 493
fa7225c8
A
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//
504static CSSM_TP_APPLE_EVIDENCE_INFO *
505SecTrustGetEvidenceInfo(SecTrustRef trust)
506{
507 TSecTrust *secTrust = (TSecTrust *)trust;
508 if (!secTrust) {
509 return NULL;
510 }
6b200bc3 511 if (secTrust->_trustResult != kSecTrustResultInvalid &&
fa7225c8
A
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;
866f8763 526 CFIndex numStatusCodes = 0;
fa7225c8
A
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;
6b200bc3 571 SecTrustSettingsDomain foundDomain = kSecTrustSettingsDomainUser;
fa7225c8
A
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
866f8763
A
625 CFIndex numCodes=0;
626 CSSM_RETURN *statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, idx, &numCodes);
fa7225c8
A
627 if (statusCodes) {
628 // Realloc space for these status codes at end of our status codes block.
629 // Two important things to note:
866f8763 630 // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes
fa7225c8
A
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.
866f8763 634 CFIndex totalStatusCodes = numStatusCodes + numCodes + 1;
fa7225c8
A
635 statusArray = (CSSM_RETURN *)realloc(statusArray, totalStatusCodes * sizeof(CSSM_RETURN));
636 evInfo->StatusCodes = &statusArray[numStatusCodes];
866f8763 637 evInfo->NumStatusCodes = (uint32)numCodes;
fa7225c8
A
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}
427c49bc 693
fa7225c8
A
694CFArrayRef 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 */
866f8763 715 CFIndex numStatusCodes;
fa7225c8 716 CSSM_RETURN *statusCodes = NULL;
866f8763 717 statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, ix, &numStatusCodes);
fa7225c8 718 if (statusCodes) {
866f8763 719 SInt32 reason = statusCodes[numStatusCodes]; // stored at end of status codes array
fa7225c8
A
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);
6b200bc3 742 CFRelease(certDict);
fa7225c8
A
743 }
744
745 return properties;
746}
b1ab9ed8
A
747
748/* deprecated in 10.5 */
749OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors,
750 uint32 *cssmAnchorCount)
751{
5c19dc3a
A
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;
b1ab9ed8
A
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//
770OSStatus SecTrustGetUserTrust(SecCertificateRef certificate,
771 SecPolicyRef policy, SecTrustUserSetting *trustSetting)
772{
5c19dc3a
A
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;
b1ab9ed8
A
778}
779
780//
781// The public setter, also deprecated; it maps to the appropriate
427c49bc 782// Trust Settings call if possible, else throws errSecUnimplemented.
b1ab9ed8
A
783//
784OSStatus SecTrustSetUserTrust(SecCertificateRef certificate,
785 SecPolicyRef policy, SecTrustUserSetting trustSetting)
786{
5c19dc3a
A
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;
b1ab9ed8
A
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//
799OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate,
800 SecPolicyRef policy, SecTrustUserSetting trustSetting)
801{
5c19dc3a
A
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;
b1ab9ed8 807}