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