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