]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/Trust.cpp
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Trust.cpp
1 /*
2 * Copyright (c) 2002-2015 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 //
25 // Trust.cpp
26 //
27 #include <security_keychain/Trust.h>
28 #include <security_keychain/TrustSettingsSchema.h>
29 #include <security_cdsa_utilities/cssmdates.h>
30 #include <security_utilities/cfutilities.h>
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <Security/SecCertificate.h>
33 #include <Security/SecTrust.h>
34 #include "SecBridge.h"
35 #include "TrustAdditions.h"
36 #include "TrustKeychains.h"
37 #include <security_cdsa_client/dlclient.h>
38 #include <security_keychain/Keychains.h>
39
40
41 using namespace Security;
42 using namespace KeychainCore;
43
44 //
45 // Translate CFDataRef to CssmData. The output shares the input's buffer.
46 //
47 static inline CssmData cfData(CFDataRef data)
48 {
49 return CssmData(const_cast<UInt8 *>(CFDataGetBytePtr(data)),
50 CFDataGetLength(data));
51 }
52
53 //
54 // Convert a SecPointer to a CF object.
55 //
56 static SecCertificateRef
57 convert(const SecPointer<Certificate> &certificate)
58 {
59 return *certificate;
60 }
61
62 //
63 // For now, we use a global TrustStore
64 //
65 ModuleNexus<TrustStore> Trust::gStore;
66
67 #pragma mark -- TrustKeychains --
68
69 //
70 // Singleton maintaining open references to standard system keychains,
71 // to avoid having them be opened anew every time SecTrust is used.
72 //
73
74 static ModuleNexus<TrustKeychains> trustKeychains;
75 static ModuleNexus<RecursiveMutex> trustKeychainsMutex;
76
77 extern "C" bool GetServerMode();
78
79 TrustKeychains::TrustKeychains() :
80 mRootStoreHandle(nullCSSMDLDBHandle),
81 mSystem(globals().storageManager.make(ADMIN_CERT_STORE_PATH, false))
82 {
83 if (GetServerMode()) // in server mode? Don't go through StorageManager to make a keychain
84 {
85 mRootStoreDL = new DL(gGuidAppleFileDL),
86 mRootStoreDb = new Db(*mRootStoreDL, SYSTEM_ROOT_STORE_PATH),
87 mRootStore = new Keychain(*mRootStoreDb);
88 }
89 else
90 {
91 mRootStoreDL = NULL;
92 mRootStoreDb = NULL;
93 mRootStore = new Keychain(globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false));
94 }
95 (*mRootStore)->database()->activate();
96 mRootStoreHandle = (*mRootStore)->database()->handle();
97 }
98
99 RecursiveMutex& SecTrustKeychainsGetMutex()
100 {
101 return trustKeychainsMutex();
102 }
103
104 #pragma mark -- Trust --
105 //
106 // Construct a Trust object with suitable defaults.
107 // Use setters for additional arguments before calling evaluate().
108 //
109 Trust::Trust(CFTypeRef certificates, CFTypeRef policies)
110 : mTP(gGuidAppleX509TP), mAction(CSSM_TP_ACTION_DEFAULT),
111 mCerts(cfArrayize(certificates)), mPolicies(cfArrayize(policies)),
112 mSearchLibs(NULL), mSearchLibsSet(false), mResult(kSecTrustResultInvalid),
113 mUsingTrustSettings(false), mAnchorPolicy(useAnchorsDefault), mMutex(Mutex::recursive)
114 {
115 if (!mPolicies) {
116 mPolicies.take(CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
117 }
118 }
119
120
121 //
122 // Clean up a Trust object
123 //
124 Trust::~Trust()
125 {
126 clearResults();
127 if (mSearchLibs) {
128 delete mSearchLibs;
129 }
130
131 mPolicies = NULL;
132 }
133
134
135 //
136 // Get searchLibs (a vector of Keychain objects);
137 // normally initialized to default search list
138 //
139 StorageManager::KeychainList& Trust::searchLibs(bool init)
140 {
141 if (!mSearchLibs) {
142 mSearchLibs = new StorageManager::KeychainList;
143 if (init) {
144 globals().storageManager.getSearchList(*mSearchLibs);
145 }
146 }
147 return *mSearchLibs;
148 }
149
150
151 //
152 // Set searchLibs to provided vector of Keychain objects
153 //
154 void Trust::searchLibs(StorageManager::KeychainList &libs)
155 {
156 searchLibs(false) = libs;
157 mSearchLibsSet = true;
158 }
159
160
161 //
162 // Retrieve the last TP evaluation result, if any
163 //
164 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR Trust::cssmResult()
165 {
166 if (mResult == kSecTrustResultInvalid)
167 MacOSError::throwMe(errSecTrustNotAvailable);
168 return &mTpResult;
169 }
170
171
172 // SecCertificateRef -> CssmData
173 static
174 CssmData cfCertificateData(SecCertificateRef certificate)
175 {
176 return Certificate::required(certificate)->data();
177 }
178
179 // SecPolicyRef -> CssmField (CFDataRef/NULL or oid/value of a SecPolicy)
180 static
181 CssmField cfField(SecPolicyRef item)
182 {
183 SecPointer<Policy> policy = Policy::required(SecPolicyRef(item));
184 return CssmField(policy->oid(), policy->value());
185 }
186
187 // SecKeychain -> CssmDlDbHandle
188 #if 0
189 static
190 CSSM_DL_DB_HANDLE cfKeychain(SecKeychainRef ref)
191 {
192 Keychain keychain = KeychainImpl::required(ref);
193 return keychain->database()->handle();
194 }
195 #endif
196
197 #if !defined(NDEBUG)
198 void showCertSKID(const void *value, void *context);
199 #endif
200
201 //
202 // Here's the big "E" - evaluation.
203 // We build most of the CSSM-layer input structures dynamically right here;
204 // they will auto-destruct when we're done. The output structures are kept
205 // around (in our data members) for later analysis.
206 // Note that evaluate() can be called repeatedly, so we must be careful to
207 // dispose of prior results.
208 //
209 void Trust::evaluate(bool disableEV)
210 {
211 bool isEVCandidate=false;
212 // begin evaluation block with stack-based mutex
213 {
214 StLock<Mutex>_(mMutex);
215 // if we have evaluated before, release prior result
216 clearResults();
217
218 // determine whether the leaf certificate is an EV candidate
219 CFArrayRef allowedAnchors = NULL;
220 if (!disableEV) {
221 allowedAnchors = allowedEVRootsForLeafCertificate(mCerts);
222 isEVCandidate = (allowedAnchors != NULL);
223 }
224 CFArrayRef filteredCerts = NULL;
225 if (isEVCandidate) {
226 secdebug("evTrust", "Trust::evaluate() certificate is EV candidate");
227 filteredCerts = potentialEVChainWithCertificates(mCerts);
228 mCerts = filteredCerts;
229 } else {
230 secdebug("evTrust", "Trust::evaluate() performing standard evaluation");
231 if (mCerts) {
232 filteredCerts = CFArrayCreateMutableCopy(NULL, 0, mCerts);
233 }
234 if (mAnchors) {
235 allowedAnchors = CFArrayCreateMutableCopy(NULL, 0, mAnchors);
236 }
237 }
238 // retain these certs as long as we potentially could have results involving them
239 // (note that assignment to a CFRef type performs an implicit retain)
240 mAllowedAnchors = allowedAnchors;
241 mFilteredCerts = filteredCerts;
242
243 if (allowedAnchors)
244 CFRelease(allowedAnchors);
245 if (filteredCerts)
246 CFRelease(filteredCerts);
247
248 if (mAllowedAnchors)
249 {
250 secdebug("trusteval", "Trust::evaluate: anchors: %ld", CFArrayGetCount(mAllowedAnchors));
251 #if !defined(NDEBUG)
252 CFArrayApplyFunction(mAllowedAnchors, CFRangeMake(0, CFArrayGetCount(mAllowedAnchors)), showCertSKID, NULL);
253 #endif
254 }
255
256 // set default search list from user's default, if caller did not explicitly supply it
257 if(!mSearchLibsSet) {
258 globals().storageManager.getSearchList(searchLibs());
259 mSearchLibsSet = true;
260 }
261
262 // build the target cert group
263 CFToVector<CssmData, SecCertificateRef, cfCertificateData> subjects(mFilteredCerts);
264 CertGroup subjectCertGroup(CSSM_CERT_X_509v3,
265 CSSM_CERT_ENCODING_BER, CSSM_CERTGROUP_DATA);
266 subjectCertGroup.count() = subjects;
267 subjectCertGroup.blobCerts() = subjects;
268
269 // build a TP_VERIFY_CONTEXT, a veritable nightmare of a data structure
270 TPBuildVerifyContext context(mAction);
271
272 /*
273 * Guarantee *some* action data...
274 * NOTE this only works with the local X509 TP. When this module can deal
275 * with other TPs, this must be revisited.
276 */
277 CSSM_APPLE_TP_ACTION_DATA localActionData;
278 memset(&localActionData, 0, sizeof(localActionData));
279 CssmData localActionCData((uint8 *)&localActionData, sizeof(localActionData));
280 CSSM_APPLE_TP_ACTION_DATA *actionDataP = &localActionData;
281 if (mActionData) {
282 context.actionData() = cfData(mActionData);
283 actionDataP = (CSSM_APPLE_TP_ACTION_DATA *)context.actionData().data();
284 }
285 else {
286 context.actionData() = localActionCData;
287 }
288
289 bool hasSSLPolicy = policySpecified(mPolicies, CSSMOID_APPLE_TP_SSL);
290 bool hasEAPPolicy = policySpecified(mPolicies, CSSMOID_APPLE_TP_EAP);
291
292 if (!mAnchors) {
293 // always check trust settings if caller did not provide explicit trust anchors
294 actionDataP->ActionFlags |= CSSM_TP_ACTION_TRUST_SETTINGS;
295 }
296
297 if (mNetworkPolicy == useNetworkDefault) {
298 if (hasSSLPolicy) {
299 // enable network cert fetch for SSL only: <rdar://7422356>
300 actionDataP->ActionFlags |= CSSM_TP_ACTION_FETCH_CERT_FROM_NET;
301 }
302 }
303 else if (mNetworkPolicy == useNetworkEnabled)
304 actionDataP->ActionFlags |= CSSM_TP_ACTION_FETCH_CERT_FROM_NET;
305 else if (mNetworkPolicy == useNetworkDisabled)
306 actionDataP->ActionFlags &= ~(CSSM_TP_ACTION_FETCH_CERT_FROM_NET);
307
308 if (policySpecified(mPolicies, CSSMOID_APPLE_TP_ESCROW_SERVICE)) {
309 // ignore expiration dates, per rdar://21943474
310 actionDataP->ActionFlags |= (CSSM_TP_ACTION_ALLOW_EXPIRED |
311 CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT);
312 }
313
314 /*
315 * Policies (one at least, please).
316 * For revocation policies, see if any have been explicitly specified...
317 */
318 CFMutableArrayRef allPolicies = NULL;
319 uint32 numRevocationAdded = 0;
320 bool requirePerCert = (actionDataP->ActionFlags & CSSM_TP_ACTION_REQUIRE_REV_PER_CERT);
321
322 // If a new unified revocation policy was explicitly specified,
323 // convert into old-style individual OCSP and CRL policies.
324 // Note that the caller could configure revocation policy options
325 // to explicitly disable both methods, so 0 policies might be added,
326 // in which case we must no longer consider the cert an EV candidate.
327
328 allPolicies = convertRevocationPolicy(numRevocationAdded, context.allocator);
329 if (allPolicies) {
330 // caller has explicitly set the revocation policy they want to use
331 secdebug("evTrust", "Trust::evaluate() using explicit revocation policy (%d)",
332 numRevocationAdded);
333 if (numRevocationAdded == 0)
334 isEVCandidate = false;
335 }
336 else if (mAnchors && (CFArrayGetCount(mAnchors)==0) && (searchLibs().size()==0)) {
337 // caller explicitly provided empty anchors and no keychain list,
338 // and did not explicitly specify the revocation policy;
339 // override global revocation check setting for this evaluation
340 secdebug("evTrust", "Trust::evaluate() has empty anchors and no keychains");
341 allPolicies = NULL; // use only mPolicies
342 isEVCandidate = false;
343 }
344 else if (isEVCandidate || requirePerCert) {
345 // force revocation checking for this evaluation
346 secdebug("evTrust", "Trust::evaluate() forcing OCSP/CRL revocation check");
347 allPolicies = forceRevocationPolicies(true, requirePerCert,
348 numRevocationAdded, context.allocator, requirePerCert);
349 }
350 else if(!(revocationPolicySpecified(mPolicies))) {
351 // none specified in mPolicies; try preferences
352 allPolicies = addPreferenceRevocationPolicies(!(hasSSLPolicy || hasEAPPolicy),
353 !(hasSSLPolicy || hasEAPPolicy), numRevocationAdded, context.allocator);
354 }
355 if (allPolicies == NULL) {
356 // use mPolicies; no revocation checking will be performed
357 secdebug("evTrust", "Trust::evaluate() will not perform revocation check");
358 CFIndex numPolicies = CFArrayGetCount(mPolicies);
359 CFAllocatorRef allocator = CFGetAllocator(mPolicies);
360 allPolicies = CFArrayCreateMutableCopy(allocator, numPolicies, mPolicies);
361 }
362 orderRevocationPolicies(allPolicies);
363 CFToVector<CssmField, SecPolicyRef, cfField> policies(allPolicies);
364 #if 0
365 // error exit here if empty policies are not supported
366 if (policies.empty())
367 MacOSError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS);
368 #endif
369 context.setPolicies(policies, policies);
370
371 // anchor certificates (if caller provides them, or if cert requires EV)
372 CFCopyRef<CFArrayRef> anchors(mAllowedAnchors);
373 CFToVector<CssmData, SecCertificateRef, cfCertificateData> roots(anchors);
374 if (!anchors) {
375 // no anchor certificates were provided;
376 // built-in anchors will be trusted unless explicitly disabled.
377 mUsingTrustSettings = (mAnchorPolicy < useAnchorsOnly);
378 secdebug("userTrust", "Trust::evaluate() %s",
379 (mUsingTrustSettings) ? "using UserTrust" : "has no trusted anchors!");
380 }
381 else {
382 // anchor certificates were provided;
383 // built-in anchors will NOT also be trusted unless explicitly enabled.
384 mUsingTrustSettings = (mAnchorPolicy == useAnchorsAndBuiltIns);
385 secdebug("userTrust", "Trust::evaluate() using %s %s anchors",
386 (mUsingTrustSettings) ? "UserTrust AND" : "only",
387 (isEVCandidate) ? "EV" : "caller");
388 context.anchors(roots, roots);
389 }
390
391 // dlDbList (keychain list)
392 vector<CSSM_DL_DB_HANDLE> dlDbList;
393 {
394 StLock<Mutex> _(SecTrustKeychainsGetMutex());
395 StorageManager::KeychainList& list = searchLibs();
396 for (StorageManager::KeychainList::const_iterator it = list.begin();
397 it != list.end(); it++)
398 {
399 try
400 {
401 // For the purpose of looking up intermediate certificates to establish trust,
402 // do not include the network-based LDAP or DotMac pseudo-keychains. (The only
403 // time the network should be consulted for certificates is if there is an AIA
404 // extension with a specific URL, which will be handled by the TP code.)
405 CSSM_DL_DB_HANDLE dldbHandle = (*it)->database()->handle();
406 if (dldbHandle.DLHandle) {
407 CSSM_GUID guid = {};
408 CSSM_RETURN crtn = CSSM_GetModuleGUIDFromHandle(dldbHandle.DLHandle, &guid);
409 if (crtn == CSSM_OK) {
410 if ((memcmp(&guid, &gGuidAppleLDAPDL, sizeof(CSSM_GUID))==0) ||
411 (memcmp(&guid, &gGuidAppleDotMacDL, sizeof(CSSM_GUID))==0)) {
412 continue; // don't add to dlDbList
413 }
414 }
415 }
416 // This DB is OK to search for intermediate certificates.
417 dlDbList.push_back(dldbHandle);
418 }
419 catch (...)
420 {
421 }
422 }
423 if(mUsingTrustSettings) {
424 /* Append system anchors for use with Trust Settings */
425 try {
426 CSSM_DL_DB_HANDLE rootStoreHandle = trustKeychains().rootStoreHandle();
427 if (rootStoreHandle.DBHandle)
428 dlDbList.push_back(rootStoreHandle);
429 actionDataP->ActionFlags |= CSSM_TP_ACTION_TRUST_SETTINGS;
430 }
431 catch (...) {
432 // no root store or system keychain; don't use trust settings but continue
433 mUsingTrustSettings = false;
434 }
435 try {
436 CSSM_DL_DB_HANDLE systemKcHandle = trustKeychains().systemKcHandle();
437 if (systemKcHandle.DBHandle)
438 dlDbList.push_back(systemKcHandle);
439 }
440 catch(...) {
441 /* Oh well, at least we got the root store DB */
442 }
443 }
444 context.setDlDbList((uint32)dlDbList.size(), &dlDbList[0]);
445 }
446
447 // verification time
448 char timeString[15];
449 if (mVerifyTime) {
450 CssmUniformDate(static_cast<CFDateRef>(mVerifyTime)).convertTo(
451 timeString, sizeof(timeString));
452 context.time(timeString);
453 }
454
455 // to avoid keychain open/close thrashing, hold a copy of the search list
456 StorageManager::KeychainList *holdSearchList = NULL;
457 if (searchLibs().size() > 0) {
458 holdSearchList = new StorageManager::KeychainList;
459 globals().storageManager.getSearchList(*holdSearchList);
460 }
461
462 // Go TP!
463 try {
464 mTP->certGroupVerify(subjectCertGroup, context, &mTpResult);
465 mTpReturn = errSecSuccess;
466 } catch (CommonError &err) {
467 mTpReturn = err.osStatus();
468 secdebug("trusteval", "certGroupVerify exception: %d", (int)mTpReturn);
469 }
470 mResult = diagnoseOutcome();
471
472 // see if we can use the evidence
473 if (mTpResult.count() > 0
474 && mTpResult[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER
475 && mTpResult[0].as<CSSM_TP_APPLE_EVIDENCE_HEADER>()->Version == CSSM_TP_APPLE_EVIDENCE_VERSION
476 && mTpResult.count() == 3
477 && mTpResult[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
478 && mTpResult[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) {
479 evaluateUserTrust(*mTpResult[1].as<CertGroup>(),
480 mTpResult[2].as<CSSM_TP_APPLE_EVIDENCE_INFO>(), anchors);
481 } else {
482 // unexpected evidence information. Can't use it
483 secdebug("trusteval", "unexpected evidence ignored");
484 }
485
486 /* do post-processing for the evaluated certificate chain */
487 CFArrayRef fullChain = makeCFArrayFrom(convert, mCertChain);
488 CFDictionaryRef etResult = extendedTrustResults(fullChain, mResult, mTpReturn, isEVCandidate);
489 mExtendedResult = etResult; // assignment to CFRef type is an implicit retain
490 if (etResult) {
491 CFRelease(etResult);
492 }
493 if (fullChain) {
494 CFRelease(fullChain);
495 }
496
497 if (allPolicies) {
498 /* clean up revocation policies we created implicitly */
499 if(numRevocationAdded) {
500 freeAddedRevocationPolicyData(allPolicies, numRevocationAdded, context.allocator);
501 }
502 CFRelease(allPolicies);
503 }
504
505 if (holdSearchList) {
506 delete holdSearchList;
507 holdSearchList = NULL;
508 }
509 } // end evaluation block with mutex; releases all temporary allocations in this scope
510
511
512 if (isEVCandidate && mResult == kSecTrustResultRecoverableTrustFailure &&
513 (mTpReturn == CSSMERR_TP_NOT_TRUSTED || isRevocationServerMetaError(mTpReturn))) {
514 // re-do the evaluation, this time disabling EV
515 evaluate(true);
516 }
517 }
518
519 // CSSM_RETURN values that map to kSecTrustResultRecoverableTrustFailure.
520 static const CSSM_RETURN recoverableErrors[] =
521 {
522 CSSMERR_TP_INVALID_ANCHOR_CERT,
523 CSSMERR_TP_NOT_TRUSTED,
524 CSSMERR_TP_VERIFICATION_FAILURE,
525 CSSMERR_TP_VERIFY_ACTION_FAILED,
526 CSSMERR_TP_INVALID_REQUEST_INPUTS,
527 CSSMERR_TP_CERT_EXPIRED,
528 CSSMERR_TP_CERT_NOT_VALID_YET,
529 CSSMERR_TP_CERTIFICATE_CANT_OPERATE,
530 CSSMERR_TP_INVALID_CERT_AUTHORITY,
531 CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK,
532 CSSMERR_APPLETP_HOSTNAME_MISMATCH,
533 CSSMERR_TP_VERIFY_ACTION_FAILED,
534 CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND,
535 CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS,
536 CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE,
537 CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH,
538 CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS,
539 CSSMERR_APPLETP_CS_BAD_PATH_LENGTH,
540 CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE,
541 CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE,
542 CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT,
543 CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH,
544 CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN,
545 CSSMERR_APPLETP_CRL_NOT_FOUND,
546 CSSMERR_APPLETP_CRL_SERVER_DOWN,
547 CSSMERR_APPLETP_CRL_NOT_VALID_YET,
548 CSSMERR_APPLETP_OCSP_UNAVAILABLE,
549 CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK,
550 CSSMERR_APPLETP_NETWORK_FAILURE,
551 CSSMERR_APPLETP_OCSP_RESP_TRY_LATER,
552 CSSMERR_APPLETP_IDENTIFIER_MISSING,
553 };
554 #define NUM_RECOVERABLE_ERRORS (sizeof(recoverableErrors) / sizeof(CSSM_RETURN))
555
556 //
557 // Classify the TP outcome in terms of a SecTrustResultType
558 //
559 SecTrustResultType Trust::diagnoseOutcome()
560 {
561 StLock<Mutex>_(mMutex);
562
563 uint32 chainLength = 0;
564 if (mTpResult.count() == 3 &&
565 mTpResult[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP &&
566 mTpResult[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO)
567 {
568 const CertGroup &chain = *mTpResult[1].as<CertGroup>();
569 chainLength = chain.count();
570 }
571
572 switch (mTpReturn) {
573 case errSecSuccess: // peachy
574 if (mUsingTrustSettings)
575 {
576 if (chainLength)
577 {
578 const CSSM_TP_APPLE_EVIDENCE_INFO *infoList = mTpResult[2].as<CSSM_TP_APPLE_EVIDENCE_INFO>();
579 const TPEvidenceInfo &info = TPEvidenceInfo::overlay(infoList[chainLength-1]);
580 const CSSM_TP_APPLE_CERT_STATUS resultCertStatus = info.status();
581 bool hasUserDomainTrust = ((resultCertStatus & CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST) &&
582 (resultCertStatus & CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER));
583 bool hasAdminDomainTrust = ((resultCertStatus & CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST) &&
584 (resultCertStatus & CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN));
585 if (hasUserDomainTrust || hasAdminDomainTrust)
586 {
587 return kSecTrustResultProceed; // explicitly allowed
588 }
589 }
590 }
591 return kSecTrustResultUnspecified; // cert evaluates OK
592 case CSSMERR_TP_INVALID_CERTIFICATE: // bad certificate
593 return kSecTrustResultFatalTrustFailure;
594 case CSSMERR_APPLETP_TRUST_SETTING_DENY: // authoritative denial
595 return kSecTrustResultDeny;
596 default:
597 break;
598 }
599
600 // a known list of returns maps to kSecTrustResultRecoverableTrustFailure
601 const CSSM_RETURN *errp=recoverableErrors;
602 for(unsigned dex=0; dex<NUM_RECOVERABLE_ERRORS; dex++, errp++) {
603 if(*errp == mTpReturn) {
604 return kSecTrustResultRecoverableTrustFailure;
605 }
606 }
607 return kSecTrustResultOtherError; // unknown
608 }
609
610
611 //
612 // Assuming a good evidence chain, check user trust
613 // settings and set mResult accordingly.
614 //
615 void Trust::evaluateUserTrust(const CertGroup &chain,
616 const CSSM_TP_APPLE_EVIDENCE_INFO *infoList, CFCopyRef<CFArrayRef> anchors)
617 {
618 StLock<Mutex>_(mMutex);
619 // extract cert chain as Certificate objects
620 mCertChain.resize(chain.count());
621 for (uint32 n = 0; n < mCertChain.size(); n++) {
622 const TPEvidenceInfo &info = TPEvidenceInfo::overlay(infoList[n]);
623 if (info.recordId()) {
624 Keychain keychain = keychainByDLDb(info.DlDbHandle);
625 DbUniqueRecord uniqueId(keychain->database()->newDbUniqueRecord());
626 secdebug("trusteval", "evidence %lu from keychain \"%s\"", (unsigned long)n, keychain->name());
627 *static_cast<CSSM_DB_UNIQUE_RECORD_PTR *>(uniqueId) = info.UniqueRecord;
628 uniqueId->activate(); // transfers ownership
629 Item ii = keychain->item(CSSM_DL_DB_RECORD_X509_CERTIFICATE, uniqueId);
630 Certificate* cert = dynamic_cast<Certificate*>(ii.get());
631 if (cert == NULL) {
632 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
633 }
634 mCertChain[n] = cert;
635 } else if (info.status(CSSM_CERT_STATUS_IS_IN_INPUT_CERTS)) {
636 secdebug("trusteval", "evidence %lu from input cert %lu", (unsigned long)n, (unsigned long)info.index());
637 assert(info.index() < uint32(CFArrayGetCount(mCerts)));
638 SecCertificateRef cert = SecCertificateRef(CFArrayGetValueAtIndex(mCerts,
639 info.index()));
640 mCertChain[n] = Certificate::required(cert);
641 } else if (info.status(CSSM_CERT_STATUS_IS_IN_ANCHORS)) {
642 secdebug("trusteval", "evidence %lu from anchor cert %lu", (unsigned long)n, (unsigned long)info.index());
643 assert(info.index() < uint32(CFArrayGetCount(anchors)));
644 SecCertificateRef cert = SecCertificateRef(CFArrayGetValueAtIndex(anchors,
645 info.index()));
646 mCertChain[n] = Certificate::required(cert);
647 } else {
648 // unknown source; make a new Certificate for it
649 secdebug("trusteval", "evidence %lu from unknown source", (unsigned long)n);
650 mCertChain[n] =
651 new Certificate(chain.blobCerts()[n],
652 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER);
653 }
654 }
655
656 // now walk the chain, leaf-to-root, checking for user settings
657 TrustStore &store = gStore();
658 SecPointer<Policy> policy = (CFArrayGetCount(mPolicies)) ?
659 Policy::required(SecPolicyRef(CFArrayGetValueAtIndex(mPolicies, 0))) : NULL;
660 for (mResultIndex = 0;
661 mResult == kSecTrustResultUnspecified && mResultIndex < mCertChain.size() && policy;
662 mResultIndex++) {
663 if (!mCertChain[mResultIndex]) {
664 assert(false);
665 continue;
666 }
667 mResult = store.find(mCertChain[mResultIndex], policy, searchLibs());
668 secdebug("trusteval", "trustResult=%d from cert %d", (int)mResult, (int)mResultIndex);
669 }
670 }
671
672
673 //
674 // Release TP evidence information.
675 // This information is severely under-defined by CSSM, so we proceed
676 // as follows:
677 // (a) If the evidence matches an Apple-defined pattern, use specific
678 // knowledge of that format.
679 // (b) Otherwise, assume that the void * are flat blocks of memory.
680 //
681 void Trust::releaseTPEvidence(TPVerifyResult &result, Allocator &allocator)
682 {
683 if (result.count() > 0) { // something to do
684 if (result[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER) {
685 // Apple defined evidence form -- use intimate knowledge
686 if (result[0].as<CSSM_TP_APPLE_EVIDENCE_HEADER>()->Version == CSSM_TP_APPLE_EVIDENCE_VERSION
687 && result.count() == 3
688 && result[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
689 && result[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) {
690 // proper format
691 CertGroup& certs = *result[1].as<CertGroup>();
692 CSSM_TP_APPLE_EVIDENCE_INFO *evidence = result[2].as<CSSM_TP_APPLE_EVIDENCE_INFO>();
693 uint32 count = certs.count();
694 allocator.free(result[0].data()); // just a struct
695 certs.destroy(allocator); // certgroup contents
696 allocator.free(result[1].data()); // the CertGroup itself
697 for (uint32 n = 0; n < count; n++)
698 allocator.free(evidence[n].StatusCodes);
699 allocator.free(result[2].data()); // array of (flat) info structs
700 } else {
701 secdebug("trusteval", "unrecognized Apple TP evidence format");
702 // drop it -- better leak than kill
703 }
704 } else {
705 // unknown format -- blindly assume flat blobs
706 secdebug("trusteval", "destroying unknown TP evidence format");
707 for (uint32 n = 0; n < result.count(); n++)
708 {
709 allocator.free(result[n].data());
710 }
711 }
712
713 allocator.free (result.Evidence);
714 }
715 }
716
717
718 //
719 // Clear evaluation results unless state is initial (invalid)
720 //
721 void Trust::clearResults()
722 {
723 StLock<Mutex>_(mMutex);
724 if (mResult != kSecTrustResultInvalid) {
725 releaseTPEvidence(mTpResult, mTP.allocator());
726 mResult = kSecTrustResultInvalid;
727 }
728 }
729
730
731 //
732 // Build evidence information
733 //
734 void Trust::buildEvidence(CFArrayRef &certChain, TPEvidenceInfo * &statusChain)
735 {
736 StLock<Mutex>_(mMutex);
737 if (mResult == kSecTrustResultInvalid)
738 MacOSError::throwMe(errSecTrustNotAvailable);
739 certChain = mEvidenceReturned =
740 makeCFArrayFrom(convert, mCertChain);
741 if(mTpResult.count() >= 3) {
742 statusChain = mTpResult[2].as<TPEvidenceInfo>();
743 }
744 else {
745 statusChain = NULL;
746 }
747 }
748
749
750 //
751 // Return extended result dictionary
752 //
753 void Trust::extendedResult(CFDictionaryRef &result)
754 {
755 if (mResult == kSecTrustResultInvalid)
756 MacOSError::throwMe(errSecTrustNotAvailable);
757 if (mExtendedResult)
758 CFRetain(mExtendedResult); // retain before handing out to caller
759 result = mExtendedResult;
760 }
761
762
763 //
764 // Return properties array (a CFDictionaryRef for each certificate in chain)
765 //
766 CFArrayRef Trust::properties()
767 {
768 // Builds and returns an array which the caller must release.
769 StLock<Mutex>_(mMutex);
770 CFMutableArrayRef properties = CFArrayCreateMutable(NULL, 0,
771 &kCFTypeArrayCallBacks);
772 if (mResult == kSecTrustResultInvalid) // chain not built or evaluated
773 return properties;
774
775 /* Get evidence pointer */
776 CSSM_TP_APPLE_EVIDENCE_INFO *evidence = NULL;
777 uint32 evidenceChainLen = 0;
778 if (mTpResult.count() > 0) {
779 if (mTpResult[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER) {
780 if (mTpResult[0].as<CSSM_TP_APPLE_EVIDENCE_HEADER>()->Version == CSSM_TP_APPLE_EVIDENCE_VERSION
781 && mTpResult.count() == 3
782 && mTpResult[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
783 && mTpResult[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) {
784 // proper format
785 CertGroup& certs = *mTpResult[1].as<CertGroup>();
786 evidence = mTpResult[2].as<CSSM_TP_APPLE_EVIDENCE_INFO>();
787 evidenceChainLen = certs.count();
788 }
789 }
790 }
791
792 // Walk the chain from leaf to anchor, building properties dictionaries
793 for (uint32 idx=0; idx < mCertChain.size(); idx++) {
794 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0,
795 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
796 if (dict) {
797 CFStringRef title = NULL;
798 mCertChain[idx]->inferLabel(false, &title);
799 if (title) {
800 CFDictionarySetValue(dict, (const void *)kSecPropertyTypeTitle, (const void *)title);
801 CFRelease(title);
802 }
803 if (idx == 0 && mTpReturn != errSecSuccess) {
804 CFStringRef error = SecCopyErrorMessageString(mTpReturn, NULL);
805 if (error) {
806 CFDictionarySetValue(dict, (const void *)kSecPropertyTypeError, (const void *)error);
807 CFRelease(error);
808 }
809 }
810 if (idx < evidenceChainLen) {
811 uint32 numCodes = evidence[idx].NumStatusCodes;
812 sint32 reason = evidence[idx].StatusCodes[numCodes]; // stored at end of status codes array
813 if (reason > 0) {
814 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
815 if (cfreason) {
816 CFDictionarySetValue(dict, (const void *)kSecTrustRevocationReason, (const void *)cfreason);
817 CFRelease(cfreason);
818 }
819 }
820 }
821 CFArrayAppendValue(properties, (const void *)dict);
822 CFRelease(dict);
823 }
824 }
825
826 return properties;
827 }
828
829 //
830 // Return dictionary of evaluation results
831 //
832 CFDictionaryRef Trust::results()
833 {
834 // Builds and returns a dictionary which the caller must release.
835 StLock<Mutex>_(mMutex);
836 CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
837 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
838
839 // kSecTrustResultValue
840 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &mResult);
841 if (numValue) {
842 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
843 CFRelease(numValue);
844 }
845 if (mResult == kSecTrustResultInvalid || !mExtendedResult)
846 return results; // we have nothing more to add
847
848 // kSecTrustEvaluationDate
849 CFTypeRef evaluationDate;
850 if (CFDictionaryGetValueIfPresent(mExtendedResult, kSecTrustEvaluationDate, &evaluationDate))
851 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
852
853 // kSecTrustExtendedValidation, kSecTrustOrganizationName
854 CFTypeRef organizationName;
855 if (CFDictionaryGetValueIfPresent(mExtendedResult, kSecEVOrganizationName, &organizationName)) {
856 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
857 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)kCFBooleanTrue);
858 }
859
860 // kSecTrustRevocationChecked, kSecTrustRevocationValidUntilDate
861 CFTypeRef expirationDate;
862 if (CFDictionaryGetValueIfPresent(mExtendedResult, kSecTrustExpirationDate, &expirationDate)) {
863 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)expirationDate);
864 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)kCFBooleanTrue);
865 }
866
867 return results;
868 }
869
870
871
872 //* ===========================================================================
873 //* We need a way to compare two CSSM_DL_DB_HANDLEs WITHOUT using a operator
874 //* overload
875 //* ===========================================================================
876 static
877 bool Compare_CSSM_DL_DB_HANDLE(const CSSM_DL_DB_HANDLE &h1, const CSSM_DL_DB_HANDLE &h2)
878 {
879 return (h1.DLHandle == h2.DLHandle && h1.DBHandle == h2.DBHandle);
880 }
881
882
883
884 //
885 // Given a DL_DB_HANDLE, locate the Keychain object (from the search list)
886 //
887 Keychain Trust::keychainByDLDb(const CSSM_DL_DB_HANDLE &handle)
888 {
889 StLock<Mutex>_(mMutex);
890 StorageManager::KeychainList& list = searchLibs();
891 for (StorageManager::KeychainList::const_iterator it = list.begin();
892 it != list.end(); it++)
893 {
894 try
895 {
896
897 if (Compare_CSSM_DL_DB_HANDLE((*it)->database()->handle(), handle))
898 return *it;
899 }
900 catch (...)
901 {
902 }
903 }
904 if(mUsingTrustSettings) {
905 try {
906 if(Compare_CSSM_DL_DB_HANDLE(trustKeychains().rootStoreHandle(), handle)) {
907 return trustKeychains().rootStore();
908 }
909 if(Compare_CSSM_DL_DB_HANDLE(trustKeychains().systemKcHandle(), handle)) {
910 return trustKeychains().systemKc();
911 }
912 }
913 catch(...) {
914 /* one of those is missing; proceed */
915 }
916 }
917
918 // could not find in search list - internal error
919
920 // we now throw an error here rather than assert and silently fail. That way our application won't crash...
921 MacOSError::throwMe(errSecInternal);
922 }