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