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