1/*
2 * Copyright (c) 2005 Apple Computer, 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 * TrustSettings.h - class to manage cert trust settings.
26 *
27 * Created May 10 2005 by dmitch.
28 */
29
30#include "TrustSettings.h"
31#include "TrustSettingsSchema.h"
32#include "SecTrustSettings.h"
33#include "TrustSettingsUtils.h"
34#include "TrustKeychains.h"
35#include "SecCertificatePriv.h"
36#include "SecPolicyPriv.h"
37#include "Certificate.h"
38#include "cssmdatetime.h"
39#include <Security/SecBase.h>
40#include "SecTrustedApplicationPriv.h"
41#include <security_utilities/errors.h>
42#include <security_utilities/debugging.h>
43#include <security_utilities/logging.h>
44#include <security_utilities/cfutilities.h>
45#include <security_utilities/alloc.h>
46#include <Security/cssmapplePriv.h>
47#include <Security/oidscert.h>
48#include <security_keychain/KCCursor.h>
49#include <security_ocspd/ocspdClient.h>
50#include <CoreFoundation/CoreFoundation.h>
51#include <assert.h>
52#include <Security/Authorization.h>
53#include <sys/stat.h>
54
55#define trustSettingsDbg(args...)		secdebug("trustSettings", ## args)
56#define trustSettingsEvalDbg(args...)	secdebug("trustSettingsEval", ## args)
57
58/*
59 * Common error return for "malformed TrustSettings record"
60 */
61#define errSecInvalidTrustedRootRecord	errSecInvalidTrustSettings
62
63using namespace KeychainCore;
64
65#pragma mark --- Static functions ---
66
67/*
68 * Comparator atoms to determine if an app's specified usage
69 * matches an individual trust setting. Each returns true on a match, false
70 * if the trust setting does not match the app's spec.
71 *
72 * A match fails iff:
73 *
74 * -- the app has specified a field, and the cert has a spec for that
75 *    field, and the two specs do not match;
76 *
77 * OR
78 *
79 * -- the cert has a spec for the field and the app hasn't specified the field
80 */
81static bool tsCheckPolicy(
82	const CSSM_OID *appPolicy,
83	CFDataRef certPolicy)
84{
85	if(certPolicy != NULL) {
86		if(appPolicy == NULL) {
87			trustSettingsEvalDbg("tsCheckPolicy: certPolicy, !appPolicy");
88			return false;
89		}
90		unsigned cLen = (unsigned)CFDataGetLength(certPolicy);
91		const UInt8 *cData = CFDataGetBytePtr(certPolicy);
92		if((cLen != appPolicy->Length) || memcmp(appPolicy->Data, cData, cLen)) {
93			trustSettingsEvalDbg("tsCheckPolicy: policy mismatch");
94			return false;
95		}
96	}
97	return true;
98}
99
100/*
101 * This one's slightly different: the match is for *this* app, not one
102 * specified by the app.
103 */
104static bool tsCheckApp(
105	CFDataRef certApp)
106{
107	if(certApp != NULL) {
108		SecTrustedApplicationRef appRef;
109		OSStatus ortn;
110		ortn = SecTrustedApplicationCreateWithExternalRepresentation(certApp, &appRef);
111		if(ortn) {
112			trustSettingsDbg("tsCheckApp: bad trustedApp data\n");
113			return false;
114		}
115		ortn = SecTrustedApplicationValidateWithPath(appRef, NULL);
116		if(ortn) {
117			/* Not this app */
118			return false;
119		}
120	}
121
122	return true;
123}
124
125static bool tsCheckKeyUse(
126	SecTrustSettingsKeyUsage appKeyUse,
127	CFNumberRef certKeyUse)
128{
129	if(certKeyUse != NULL) {
130		SInt32 certUse;
131		CFNumberGetValue(certKeyUse, kCFNumberSInt32Type, &certUse);
132		SecTrustSettingsKeyUsage cku = (SecTrustSettingsKeyUsage)certUse;
133		if(cku == kSecTrustSettingsKeyUseAny) {
134			/* explicitly allows anything */
135			return true;
136		}
137		/* cert specification must be a superset of app's intended use */
138		if(appKeyUse == 0) {
139			trustSettingsEvalDbg("tsCheckKeyUse: certKeyUsage, !appKeyUsage");
140			return false;
141		}
142
143		if((cku & appKeyUse) != appKeyUse) {
144			trustSettingsEvalDbg("tsCheckKeyUse: keyUse mismatch");
145			return false;
146		}
147	}
148	return true;
149}
150
151static bool tsCheckPolicyStr(
152	const char *appPolicyStr,
153	CFStringRef certPolicyStr)
154{
155	if(certPolicyStr != NULL) {
156		if(appPolicyStr == NULL) {
157			trustSettingsEvalDbg("tsCheckPolicyStr: certPolicyStr, !appPolicyStr");
158			return false;
159		}
160		/* Let CF do the string compare */
161		CFStringRef cfPolicyStr = CFStringCreateWithCString(NULL, appPolicyStr,
162			kCFStringEncodingUTF8);
163		if(cfPolicyStr == NULL) {
164			/* I really don't see how this can happen */
165			trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error");
166			return false;
167		}
168
169		// Some trust setting strings were created with a NULL character at the
170		// end, which was included in the length. Strip those off before compare
171
172		CFMutableStringRef certPolicyStrNoNULL = CFStringCreateMutableCopy(NULL, 0, certPolicyStr);
173		if (certPolicyStrNoNULL == NULL) {
174			/* I really don't see how this can happen either */
175			trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error 2");
176			return false;
177		}
178
179		CFStringFindAndReplace(certPolicyStrNoNULL, CFSTR("\00"),
180			CFSTR(""), CFRangeMake(0, CFStringGetLength(certPolicyStrNoNULL)), kCFCompareBackwards);
181
182		CFComparisonResult res = CFStringCompare(cfPolicyStr, certPolicyStrNoNULL, 0);
183		CFRelease(cfPolicyStr);
184		CFRelease(certPolicyStrNoNULL);
185		if(res != kCFCompareEqualTo) {
186			trustSettingsEvalDbg("tsCheckPolicyStr: policyStr mismatch");
187			return false;
188		}
189	}
190	return true;
191}
192
193/*
194 * Determine if a cert's trust settings dictionary satisfies the specified
195 * usage constraints. Returns true if so.
196 * Only certs with a SecTrustSettingsResult of kSecTrustSettingsResultTrustRoot
197 * or kSecTrustSettingsResultTrustAsRoot will match.
198 */
199static bool qualifyUsageWithCertDict(
200	CFDictionaryRef			certDict,
201	const CSSM_OID			*policyOID,		/* optional */
202	const char				*policyStr,		/* optional */
203	SecTrustSettingsKeyUsage keyUsage,	/* optional; default = any (actually "all" here) */
204	bool					onlyRoots)
205{
206	/* this array is optional */
207	CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict,
208		kTrustRecordTrustSettings);
209	CFIndex numSpecs = 0;
210	if(trustSettings != NULL) {
211		numSpecs = CFArrayGetCount(trustSettings);
212	}
213	if(numSpecs == 0) {
214		/*
215		 * Trivial case: cert has no trust settings, indicating that
216		 * it's used for everything.
217		 */
218		trustSettingsEvalDbg("qualifyUsageWithCertDict: no trust settings");
219		return true;
220	}
221	for(CFIndex addDex=0; addDex<numSpecs; addDex++) {
222		CFDictionaryRef tsDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings,
223			addDex);
224
225		/* per-cert specs: all optional */
226		CFDataRef   certPolicy     = (CFDataRef)CFDictionaryGetValue(tsDict,
227										kSecTrustSettingsPolicy);
228		CFDataRef   certApp        = (CFDataRef)CFDictionaryGetValue(tsDict,
229										kSecTrustSettingsApplication);
230		CFStringRef certPolicyStr  = (CFStringRef)CFDictionaryGetValue(tsDict,
231										kSecTrustSettingsPolicyString);
232		CFNumberRef certKeyUsage   = (CFNumberRef)CFDictionaryGetValue(tsDict,
233										kSecTrustSettingsKeyUsage);
234		CFNumberRef certResultType = (CFNumberRef)CFDictionaryGetValue(tsDict,
235										kSecTrustSettingsResult);
236
237		if(!tsCheckPolicy(policyOID, certPolicy)) {
238			continue;
239		}
240		if(!tsCheckApp(certApp)) {
241			continue;
242		}
243		if(!tsCheckKeyUse(keyUsage, certKeyUsage)) {
244			continue;
245		}
246		if(!tsCheckPolicyStr(policyStr, certPolicyStr)) {
247			continue;
248		}
249
250		/*
251		 * This is a match, take whatever SecTrustSettingsResult is here,
252		 * including the default if not specified.
253		 */
254		SecTrustSettingsResult resultType = kSecTrustSettingsResultTrustRoot;
255		if(certResultType) {
256			SInt32 s;
257			CFNumberGetValue(certResultType, kCFNumberSInt32Type, &s);
258			resultType = (SecTrustSettingsResult)s;
259		}
260		switch(resultType) {
261			case kSecTrustSettingsResultTrustRoot:
262				trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustRoot MATCH");
263				return true;
264			case kSecTrustSettingsResultTrustAsRoot:
265				if(onlyRoots) {
266					trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot but not root");
267					return false;
268				}
269				trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot MATCH");
270				return true;
271			default:
272				trustSettingsEvalDbg("qualifyUsageWithCertDict: bad resultType "
273					"(%lu)", (unsigned long)resultType);
274				return false;
275		}
276	}
277	trustSettingsEvalDbg("qualifyUsageWithCertDict: NO MATCH");
278	return false;
279}
280
281/*
282 * Create initial top-level dictionary when constructing a new TrustSettings.
283 */
284static CFMutableDictionaryRef tsInitialDict()
285{
286	CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL,
287		kSecTrustRecordNumTopDictKeys,
288		&kCFTypeDictionaryKeyCallBacks,	&kCFTypeDictionaryValueCallBacks);
289
290	/* the dictionary of per-cert entries */
291	CFMutableDictionaryRef trustDict = CFDictionaryCreateMutable(NULL, 0,
292		&kCFTypeDictionaryKeyCallBacks,	&kCFTypeDictionaryValueCallBacks);
293	CFDictionaryAddValue(dict, kTrustRecordTrustList, trustDict);
294	CFRelease(trustDict);
295
296	SInt32 vers = kSecTrustRecordVersionCurrent;
297	CFNumberRef cfVers = CFNumberCreate(NULL, kCFNumberSInt32Type, &vers);
298	CFDictionaryAddValue(dict, kTrustRecordVersion, cfVers);
299	CFRelease(cfVers);
300	return dict;
301}
302
303/*
304 * Set the modification date of a per-cert dictionary to current time.
305 */
306static void tsSetModDate(
307	CFMutableDictionaryRef dict)
308{
309	CFDateRef modDate;
310
311	modDate = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
312	CFDictionarySetValue(dict, kTrustRecordModDate, modDate);
313	CFRelease(modDate);
314}
315
316/* make sure a presumed CFNumber can be converted to a 32-bit number */
317static
318bool tsIsGoodCfNum(CFNumberRef cfn, SInt32 *num = NULL)
319{
320	if(cfn == NULL) {
321		/* by convention */
322		if(num) {
323			*num = 0;
324		}
325		return true;
326	}
327	if(CFGetTypeID(cfn) != CFNumberGetTypeID()) {
328		return false;
329	}
330
331	SInt32 s;
332	if(!CFNumberGetValue(cfn, kCFNumberSInt32Type, &s)) {
333		return false;
334	}
335	else {
336		if(num) {
337			*num = s;
338		}
339		return true;
340	}
341}
342
343TrustSettings::TrustSettings(SecTrustSettingsDomain domain)
344		: mPropList(NULL),
345		  mTrustDict(NULL),
346		  mDictVersion(0),
347		  mDomain(domain),
348		  mDirty(false)
349{
350}
351
352
353
354#pragma mark --- Public methods ---
355
356/*
357 * Normal constructor, from disk.
358 * If create is true, the absence of an on-disk TrustSettings file
359 * results in the creation of a new empty TrustSettings. If create is
360 * false and no on-disk TrustSettings exists, errSecNoTrustSettings is
361 * thrown.
362 * If trim is true, the components of the on-disk TrustSettings not
363 * needed for cert evaluation are discarded. This is for TrustSettings
364 * that will be cached in memory long-term.
365 */
366OSStatus TrustSettings::CreateTrustSettings(
367	SecTrustSettingsDomain	domain,
368	bool					create,
369	bool					trim,
370	TrustSettings*&			ts)
371{
372	TrustSettings* t = new TrustSettings(domain);
373
374	Allocator &alloc = Allocator::standard();
375	CSSM_DATA fileData = {0, NULL};
376	OSStatus ortn = errSecSuccess;
377	struct stat sb;
378	const char *path;
379
380	/* get trust settings from file, one way or another */
381	switch(domain) {
382		case kSecTrustSettingsDomainAdmin:
383			/*
384 			 * Quickie optimization: if it's not there, don't try to
385			 * get it from ocspd. This is possible because the name of the
386			 * admin file is hard coded, but the per-user files aren't.
387			 */
388			path = TRUST_SETTINGS_PATH "/" ADMIN_TRUST_SETTINGS;
389			if(stat(path, &sb)) {
390				trustSettingsDbg("TrustSettings: no admin record; skipping");
391				ortn = errSecNoTrustSettings;
392				break;
393			}
394			/* else drop thru, get it from ocspd */
395		case kSecTrustSettingsDomainUser:
396			/* get settings from ocspd */
397			ortn = ocspdTrustSettingsRead(alloc, domain, fileData);
398			break;
399		case kSecTrustSettingsDomainSystem:
400			/* immutable; it's safe for us to read this directly */
401			if(tsReadFile(SYSTEM_TRUST_SETTINGS_PATH, alloc, fileData)) {
402				ortn = errSecNoTrustSettings;
403			}
404			break;
405		default:
406			delete t;
407			return errSecParam;
408	}
409	if(ortn) {
410		if(create) {
411			trustSettingsDbg("TrustSettings: creating new record for domain %d",
412				(int)domain);
413			t->mPropList = tsInitialDict();
414			t->mDirty = true;
415		}
416		else {
417			trustSettingsDbg("TrustSettings: record not found for domain %d",
418				(int)domain);
419			delete t;
420			return ortn;
421		}
422	}
423	else {
424		CFRef<CFDataRef> propList(CFDataCreate(NULL, fileData.Data, fileData.Length));
425		t->initFromData(propList);
426		alloc.free(fileData.Data);
427	}
428	t->validatePropList(trim);
429
430	ts = t;
431	return errSecSuccess;
432}
433
434/*
435 * Create from external data, obtained by createExternal().
436 * If externalData is NULL, we'll create an empty mTrustDict.
437 */
438OSStatus TrustSettings::CreateTrustSettings(
439	SecTrustSettingsDomain				domain,
440	CFDataRef							externalData,
441	TrustSettings*&						ts)
442{
443	switch(domain) {
444		case kSecTrustSettingsDomainUser:
445		case kSecTrustSettingsDomainAdmin:
446		case kSecTrustSettingsDomainMemory:
447			break;
448		case kSecTrustSettingsDomainSystem:		/* no can do, that implies writing to it */
449		default:
450			return errSecParam;
451	}
452
453	TrustSettings* t = new TrustSettings(domain);
454
455	if(externalData != NULL) {
456		t->initFromData(externalData);
457	}
458	else {
459		t->mPropList = tsInitialDict();
460	}
461	t->validatePropList(TRIM_NO);		/* never trim this */
462	t->mDirty = true;
463
464	ts = t;
465	return errSecSuccess;
466}
467
468
469TrustSettings::~TrustSettings()
470{
471	trustSettingsDbg("TrustSettings(domain %d) destructor", (int)mDomain);
472	CFRELEASE(mPropList);		/* may be null if trimmed */
473	CFRELEASE(mTrustDict);		/* normally always non-NULL */
474
475}
476
477/* common code to init mPropList from raw data */
478void TrustSettings::initFromData(
479	CFDataRef	trustSettingsData)
480{
481	CFStringRef errStr = NULL;
482
483	mPropList = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(
484		NULL,
485		trustSettingsData,
486		kCFPropertyListMutableContainersAndLeaves,
487		&errStr);
488	if(mPropList == NULL) {
489		trustSettingsDbg("TrustSettings::initFromData decode err (%s)",
490			errStr ? CFStringGetCStringPtr(errStr, kCFStringEncodingUTF8) : "<no err>");
491		if(errStr != NULL) {
492			CFRelease(errStr);
493		}
494		MacOSError::throwMe(errSecInvalidTrustSettings);
495	}
496}
497
498/*
499 * Flush property list data out to disk if dirty.
500 */
501void TrustSettings::flushToDisk()
502{
503	if(!mDirty) {
504		trustSettingsDbg("flushToDisk, domain %d, !dirty!", (int)mDomain);
505		return;
506	}
507	if(mPropList == NULL) {
508		trustSettingsDbg("flushToDisk, domain %d, trimmed!", (int)mDomain);
509		assert(0);
510		MacOSError::throwMe(errSecInternalComponent);
511	}
512	switch(mDomain) {
513		case kSecTrustSettingsDomainSystem:
514		case kSecTrustSettingsDomainMemory:
515		/* caller shouldn't even try this */
516		default:
517			trustSettingsDbg("flushToDisk, bad domain (%d)", (int)mDomain);
518			MacOSError::throwMe(errSecInternalComponent);
519		case kSecTrustSettingsDomainUser:
520		case kSecTrustSettingsDomainAdmin:
521			break;
522	}
523
524	/*
525	 * Optimization: if there are no certs in the mTrustDict dictionary,
526	 * we tell ocspd to *remove* the settings for the specified domain.
527	 * Having *no* settings uses less memory and is faster than having
528	 * an empty settings file, especially for the admin domain, where we
529	 * can avoid
530	 * an RPC if the settings file is simply not there.
531	 */
532	CFRef<CFDataRef> xmlData;
533	CSSM_DATA cssmXmlData = {0, NULL};
534	CFIndex numCerts = CFDictionaryGetCount(mTrustDict);
535	if(numCerts) {
536		xmlData.take(CFPropertyListCreateXMLData(NULL, mPropList));
537		if(!xmlData) {
538			/* we've been very careful; this should never happen */
539			trustSettingsDbg("flushToDisk, domain %d: error converting to XML", (int)mDomain);
540			MacOSError::throwMe(errSecInternalComponent);
541		}
542		cssmXmlData.Data = (uint8 *)CFDataGetBytePtr(xmlData);
543		cssmXmlData.Length = CFDataGetLength(xmlData);
544	}
545	else {
546		trustSettingsDbg("flushToDisk, domain %d: DELETING trust settings", (int)mDomain);
547	}
548
549	/* cook up auth stuff so ocspd can act on our behalf */
550	AuthorizationRef authRef;
551	OSStatus ortn;
552	ortn = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
553			0, &authRef);
554	if(ortn) {
555		trustSettingsDbg("flushToDisk, domain %d: AuthorizationCreate returned %ld",
556			(int)mDomain, (long)ortn);
557		MacOSError::throwMe(errSecInternalComponent);
558	}
559	AuthorizationExternalForm authExt;
560	CSSM_DATA authBlob = {sizeof(authExt), (uint8 *)&authExt};
561	ortn = AuthorizationMakeExternalForm(authRef, &authExt);
562	if(ortn) {
563		trustSettingsDbg("flushToDisk, domain %d: AuthorizationMakeExternalForm returned %ld",
564			(int)mDomain, (long)ortn);
565		ortn = errSecInternalComponent;
566		goto errOut;
567	}
568
569	ortn = ocspdTrustSettingsWrite(mDomain, authBlob, cssmXmlData);
570	if(ortn) {
571		trustSettingsDbg("flushToDisk, domain %d: ocspdTrustSettingsWrite returned %ld",
572			(int)mDomain, (long)ortn);
573		goto errOut;
574	}
575	trustSettingsDbg("flushToDisk, domain %d: wrote to disk", (int)mDomain);
576	mDirty = false;
577errOut:
578	AuthorizationFree(authRef, 0);
579	if(ortn) {
580		MacOSError::throwMe(ortn);
581	}
582}
583
584/*
585 * Obtain external representation of TrustSettings data.
586 */
587CFDataRef TrustSettings::createExternal()
588{
589	assert(mPropList);
590	CFDataRef xmlData = CFPropertyListCreateXMLData(NULL, mPropList);
591	if(xmlData == NULL) {
592		trustSettingsDbg("createExternal, domain %d: error converting to XML",
593			(int)mDomain);
594		MacOSError::throwMe(errSecInternalComponent);
595	}
596	return xmlData;
597}
598
599/*
600 * Evaluate specified cert. Returns true if we found a record for the cert
601 * matching specified constraints.
602 * Note that a true return with a value of kSecTrustSettingsResultUnspecified for
603 * the resultType means that a cert isn't to be trusted or untrusted
604 * per se; it just means that we only found allowedErrors entries.
605 *
606 * Found "allows errors" values are added to the incoming allowedErrors
607 * array which is reallocd as needed (and which may be NULL or non-NULL on
608 * entry).
609 */
610bool TrustSettings::evaluateCert(
611	CFStringRef				certHashStr,
612	const CSSM_OID			*policyOID,			/* optional */
613	const char				*policyStr,			/* optional */
614	SecTrustSettingsKeyUsage keyUsage,			/* optional */
615	bool					isRootCert,			/* for checking default setting */
616	CSSM_RETURN				**allowedErrors,	/* IN/OUT; reallocd as needed */
617	uint32					*numAllowedErrors,	/* IN/OUT */
618	SecTrustSettingsResult	*resultType,		/* RETURNED */
619	bool					*foundAnyEntry)		/* RETURNED */
620{
621	assert(mTrustDict != NULL);
622
623	/* get trust settings dictionary for this cert */
624	CFDictionaryRef certDict = findDictionaryForCertHash(certHashStr);
625	if((certDict == NULL) && isRootCert) {
626		/* No? How about default root setting for this domain? */
627		certDict = findDictionaryForCertHash(kSecTrustRecordDefaultRootCert);
628	}
629#if CERT_HASH_DEBUG
630	/* @@@ debug only @@@ */
631	/* print certificate hash and found dictionary reference */
632	const size_t maxHashStrLen = 512;
633	char *buf = (char*)malloc(maxHashStrLen);
634	if (buf) {
635		if (!CFStringGetCString(certHashStr, buf, (CFIndex)maxHashStrLen, kCFStringEncodingUTF8)) {
636			buf[0]='\0';
637		}
638		trustSettingsEvalDbg("evaluateCert for \"%s\", found dict %p", buf, certDict);
639		free(buf);
640	}
641#endif
642
643	if(certDict == NULL) {
644		*foundAnyEntry = false;
645		return false;
646	}
647	*foundAnyEntry = true;
648
649	/* to-be-returned array of allowed errors */
650	CSSM_RETURN *allowedErrs = *allowedErrors;
651	uint32 numAllowedErrs = *numAllowedErrors;
652
653	/* this means "we found something other than allowedErrors" if true */
654	bool foundSettings = false;
655
656	/* to be returned in *resultType if it ends up something other than Invalid */
657	SecTrustSettingsResult returnedResult = kSecTrustSettingsResultInvalid;
658
659	/*
660	 * Note since we validated the entire mPropList in our constructor, and we're careful
661	 * about what we put into it, we don't bother typechecking its contents here.
662	 * Also note that the kTrustRecordTrustSettings entry is optional.
663	 */
664	CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict,
665			kTrustRecordTrustSettings);
666	CFIndex numSpecs = 0;
667	if(trustSettings != NULL) {
668		numSpecs = CFArrayGetCount(trustSettings);
669	}
670	if(numSpecs == 0) {
671		/*
672		 * Trivial case: cert has no trust settings, indicating that
673		 * it's used for everything.
674		 */
675		trustSettingsEvalDbg("evaluateCert: no trust settings");
676		/* the default... */
677		*resultType = kSecTrustSettingsResultTrustRoot;
678		return true;
679	}
680
681	/*
682	 * The decidedly nontrivial part: grind thru all of the cert's trust
683	 * settings, see if the cert matches the caller's specified usage.
684	 */
685	for(CFIndex addDex=0; addDex<numSpecs; addDex++) {
686		CFDictionaryRef tsDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings,
687			addDex);
688
689		/* per-cert specs: all optional */
690		CFDataRef   certPolicy     = (CFDataRef)CFDictionaryGetValue(tsDict,
691										kSecTrustSettingsPolicy);
692		CFDataRef   certApp        = (CFDataRef)CFDictionaryGetValue(tsDict,
693										kSecTrustSettingsApplication);
694		CFStringRef certPolicyStr  = (CFStringRef)CFDictionaryGetValue(tsDict,
695										kSecTrustSettingsPolicyString);
696		CFNumberRef certKeyUsage   = (CFNumberRef)CFDictionaryGetValue(tsDict,
697										kSecTrustSettingsKeyUsage);
698		CFNumberRef certResultType = (CFNumberRef)CFDictionaryGetValue(tsDict,
699										kSecTrustSettingsResult);
700		CFNumberRef certAllowedErr = (CFNumberRef)CFDictionaryGetValue(tsDict,
701										kSecTrustSettingsAllowedError);
702
703		/* now, skip if we find a constraint that doesn't match intended use */
704		if(!tsCheckPolicy(policyOID, certPolicy)) {
705			continue;
706		}
707		if(!tsCheckApp(certApp)) {
708			continue;
709		}
710		if(!tsCheckKeyUse(keyUsage, certKeyUsage)) {
711			continue;
712		}
713		if(!tsCheckPolicyStr(policyStr, certPolicyStr)) {
714			continue;
715		}
716
717		trustSettingsEvalDbg("evaluateCert: MATCH");
718		foundSettings = true;
719
720		if(certAllowedErr) {
721			/* note we already validated this value */
722			SInt32 s;
723			CFNumberGetValue(certAllowedErr, kCFNumberSInt32Type, &s);
724			allowedErrs = (CSSM_RETURN *)::realloc(allowedErrs,
725				++numAllowedErrs * sizeof(CSSM_RETURN));
726			allowedErrs[numAllowedErrs-1] = (CSSM_RETURN) s;
727		}
728
729		/*
730		 * We found a match, but we only return the current result type
731		 * to caller if we haven't already returned something other than
732		 * kSecTrustSettingsResultUnspecified. Once we find a valid result type,
733		 * we keep on searching, but only for additional allowed errors.
734		 */
735		switch(returnedResult) {
736			/* found match but no valid resultType yet */
737			case kSecTrustSettingsResultUnspecified:
738			/* haven't been thru here */
739			case kSecTrustSettingsResultInvalid:
740				if(certResultType) {
741					/* note we already validated this */
742					SInt32 s;
743					CFNumberGetValue(certResultType, kCFNumberSInt32Type, &s);
744					returnedResult = (SecTrustSettingsResult)s;
745				}
746				else {
747					/* default is "copacetic" */
748					returnedResult = kSecTrustSettingsResultTrustRoot;
749				}
750				break;
751			default:
752				/* we already have a definitive resultType, don't change it */
753				break;
754		}
755	}	/* for each dictionary in trustSettings */
756
757	*allowedErrors = allowedErrs;
758	*numAllowedErrors = numAllowedErrs;
759	if(returnedResult != kSecTrustSettingsResultInvalid) {
760		*resultType = returnedResult;
761	}
762	return foundSettings;
763}
764
765
766/*
767 * Find all certs in specified keychain list which have entries in this trust record.
768 * Certs already in the array are not added.
769 */
770void TrustSettings::findCerts(
771	StorageManager::KeychainList	&keychains,
772	CFMutableArrayRef				certArray)
773{
774	findQualifiedCerts(keychains,
775		true,		/* findAll */
776		false,		/* onlyRoots */
777		NULL, NULL, kSecTrustSettingsKeyUseAny,
778		certArray);
779}
780
781void TrustSettings::findQualifiedCerts(
782	StorageManager::KeychainList	&keychains,
783	/*
784	 * If findAll is true, all certs are returned and the subsequent
785	 * qualifiers are ignored
786	 */
787	bool							findAll,
788	/* if true, only return root (self-signed) certs */
789	bool							onlyRoots,
790	const CSSM_OID					*policyOID,			/* optional */
791	const char						*policyString,		/* optional */
792	SecTrustSettingsKeyUsage		keyUsage,			/* optional */
793	CFMutableArrayRef				certArray)			/* certs appended here */
794{
795	StLock<Mutex> _(SecTrustKeychainsGetMutex());
796
797	/*
798	 * a set, hopefully with a good hash function for CFData, to keep track of what's
799	 * been added to the outgoing array.
800	 */
801	CFRef<CFMutableSetRef> certSet(CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks));
802
803	/* search: all certs, no attributes */
804	KCCursor cursor(keychains, CSSM_DL_DB_RECORD_X509_CERTIFICATE, NULL);
805	Item certItem;
806	bool found;
807	do {
808		found = cursor->next(certItem);
809		if(!found) {
810			break;
811		}
812		CFRef<SecCertificateRef> certRef((SecCertificateRef)certItem->handle());
813
814		/* do we have an entry for this cert? */
815		CFDictionaryRef certDict = findDictionaryForCert(certRef);
816		if(certDict == NULL) {
817			continue;
818		}
819
820		if(!findAll) {
821			/* qualify */
822			if(!qualifyUsageWithCertDict(certDict, policyOID,
823					policyString, keyUsage, onlyRoots)) {
824				continue;
825			}
826		}
827
828		/* see if we already have this one - get in CFData form */
829		CSSM_DATA certData;
830		OSStatus ortn = SecCertificateGetData(certRef, &certData);
831		if(ortn) {
832			trustSettingsEvalDbg("findQualifiedCerts: SecCertificateGetData error");
833			continue;
834		}
835		CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length));
836		CFDataRef cfd = cfData;
837		if(CFSetContainsValue(certSet, cfd)) {
838			trustSettingsEvalDbg("findQualifiedCerts: dup cert");
839			continue;
840		}
841		else {
842			/* add to the tracking set, which owns the CFData now */
843			CFSetAddValue(certSet, cfd);
844			/* and add the SecCert to caller's array, which owns that now */
845			CFArrayAppendValue(certArray, certRef);
846		}
847	} while(found);
848}
849
850/*
851 * Obtain trust settings for the specified cert. Returned settings array
852 * is in the public API form; caller must release. Returns NULL
853 * (does not throw) if the cert is not present in this TrustRecord.
854 */
855CFArrayRef TrustSettings::copyTrustSettings(
856	SecCertificateRef	certRef)
857{
858	CFDictionaryRef certDict = NULL;
859
860	/* find the on-disk usage constraints for this cert */
861	certDict = findDictionaryForCert(certRef);
862	if(certDict == NULL) {
863		trustSettingsDbg("copyTrustSettings: dictionary not found");
864		return NULL;
865	}
866	CFArrayRef diskTrustSettings = (CFArrayRef)CFDictionaryGetValue(certDict,
867		kTrustRecordTrustSettings);
868	CFIndex numSpecs = 0;
869	if(diskTrustSettings != NULL) {
870		/* this field is optional */
871		numSpecs = CFArrayGetCount(diskTrustSettings);
872	}
873
874	/*
875	 * Convert to API-style array of dictionaries.
876	 * We give the caller an array even if it's empty.
877	 */
878	CFRef<CFMutableArrayRef> outArray(CFArrayCreateMutable(NULL, numSpecs,
879		&kCFTypeArrayCallBacks));
880	for(CFIndex dex=0; dex<numSpecs; dex++) {
881		CFDictionaryRef diskTsDict =
882			(CFDictionaryRef)CFArrayGetValueAtIndex(diskTrustSettings, dex);
883		/* already validated... */
884		assert(CFGetTypeID(diskTsDict) == CFDictionaryGetTypeID());
885
886		CFDataRef   certPolicy = (CFDataRef)  CFDictionaryGetValue(diskTsDict, kSecTrustSettingsPolicy);
887		CFDataRef   certApp    = (CFDataRef)  CFDictionaryGetValue(diskTsDict, kSecTrustSettingsApplication);
888		CFStringRef policyStr  = (CFStringRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsPolicyString);
889		CFNumberRef allowedErr = (CFNumberRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsAllowedError);
890		CFNumberRef resultType = (CFNumberRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsResult);
891		CFNumberRef keyUsage   = (CFNumberRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsKeyUsage);
892
893		if((certPolicy == NULL) &&
894		   (certApp == NULL) &&
895		   (policyStr == NULL) &&
896		   (allowedErr == NULL) &&
897		   (resultType == NULL) &&
898		   (keyUsage == NULL)) {
899			/* weird but legal */
900			continue;
901		}
902		CFRef<CFMutableDictionaryRef> outTsDict(CFDictionaryCreateMutable(NULL,
903			0,			// capacity
904			&kCFTypeDictionaryKeyCallBacks,
905			&kCFTypeDictionaryValueCallBacks));
906
907		if(certPolicy != NULL) {
908			/* convert OID as CFDataRef to SecPolicyRef */
909			SecPolicyRef policyRef = NULL;
910			CSSM_OID policyOid = { CFDataGetLength(certPolicy),
911				(uint8 *)CFDataGetBytePtr(certPolicy) };
912			OSStatus ortn = SecPolicyCopy(CSSM_CERT_X_509v3, &policyOid, &policyRef);
913			if(ortn) {
914				trustSettingsDbg("copyTrustSettings: OID conversion error");
915				abort("Bad Policy OID in trusted root list", errSecInvalidTrustedRootRecord);
916			}
917			CFDictionaryAddValue(outTsDict, kSecTrustSettingsPolicy, policyRef);
918			CFRelease(policyRef);			// owned by dictionary
919		}
920
921		if(certApp != NULL) {
922			/* convert app as CFDataRef to SecTrustedApplicationRef */
923			SecTrustedApplicationRef appRef;
924			OSStatus ortn = SecTrustedApplicationCreateWithExternalRepresentation(certApp, &appRef);
925			if(ortn) {
926				trustSettingsDbg("copyTrustSettings: App conversion error");
927				abort("Bad application data in trusted root list", errSecInvalidTrustedRootRecord);
928			}
929			CFDictionaryAddValue(outTsDict, kSecTrustSettingsApplication, appRef);
930			CFRelease(appRef);			// owned by dictionary
931		}
932
933		/* remaining 4 are trivial */
934		if(policyStr != NULL) {
935			/*
936			 * copy, since policyStr is in our mutable dictionary and could change out from
937			 * under the caller
938			 */
939			CFStringRef str = CFStringCreateCopy(NULL, policyStr);
940			CFDictionaryAddValue(outTsDict, kSecTrustSettingsPolicyString, str);
941			CFRelease(str);			// owned by dictionary
942		}
943		if(allowedErr != NULL) {
944			/* there is no mutable CFNumber, so.... */
945			CFDictionaryAddValue(outTsDict, kSecTrustSettingsAllowedError, allowedErr);
946		}
947		if(resultType != NULL) {
948			CFDictionaryAddValue(outTsDict, kSecTrustSettingsResult, resultType);
949		}
950		if(keyUsage != NULL) {
951			CFDictionaryAddValue(outTsDict, kSecTrustSettingsKeyUsage, keyUsage);
952		}
953		CFArrayAppendValue(outArray, outTsDict);
954		/* outTsDict autoreleases; owned by outArray now */
955	}
956	CFRetain(outArray);		// now that it's good to go....
957	return outArray;
958}
959
960CFDateRef TrustSettings::copyModDate(
961	SecCertificateRef	certRef)
962{
963	CFDictionaryRef certDict = NULL;
964
965	/* find the on-disk usage constraints dictionary for this cert */
966	certDict = findDictionaryForCert(certRef);
967	if(certDict == NULL) {
968		trustSettingsDbg("copyModDate: dictionary not found");
969		return NULL;
970	}
971	CFDateRef modDate = (CFDateRef)CFDictionaryGetValue(certDict, kTrustRecordModDate);
972	if(modDate == NULL) {
973		return NULL;
974	}
975
976	/* this only works becuase there is no mutable CFDateRef */
977	CFRetain(modDate);
978	return modDate;
979}
980
981/*
982 * Modify cert's trust settings, or add a new cert to the record.
983 */
984void TrustSettings::setTrustSettings(
985	SecCertificateRef	certRef,
986	CFTypeRef			trustSettingsDictOrArray)
987{
988	/* to validate, we need to know if the cert is self-signed */
989	OSStatus ortn;
990	Boolean isSelfSigned = false;
991
992	if(certRef == kSecTrustSettingsDefaultRootCertSetting) {
993		/*
994 		 * Validate settings as if this were root, specifically,
995		 * kSecTrustSettingsResultTrustRoot (explicitly or by
996		 * default) is OK.
997		 */
998		isSelfSigned = true;
999	}
1000	else {
1001		ortn = SecCertificateIsSelfSigned(certRef, &isSelfSigned);
1002		if(ortn) {
1003			MacOSError::throwMe(ortn);
1004		}
1005	}
1006
1007	/* caller's app/policy spec OK? */
1008	CFRef<CFArrayRef> trustSettings(validateApiTrustSettings(
1009		trustSettingsDictOrArray, isSelfSigned));
1010
1011	/* caller is responsible for ensuring these */
1012	assert(mPropList != NULL);
1013	assert(mDomain != kSecTrustSettingsDomainSystem);
1014
1015	/* extract issuer and serial number from the cert, if it's a cert */
1016	CFRef<CFDataRef> issuer;
1017	CFRef<CFDataRef> serial;
1018	if(certRef != kSecTrustSettingsDefaultRootCertSetting) {
1019		copyIssuerAndSerial(certRef, issuer.take(), serial.take());
1020	}
1021	else {
1022		UInt8 dummy;
1023		issuer = CFDataCreate(NULL, &dummy, 0);
1024		serial = CFDataCreate(NULL, &dummy, 0);
1025	}
1026
1027	/* SHA1 digest as string */
1028	CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef));
1029	if(!certHashStr) {
1030		trustSettingsDbg("TrustSettings::setTrustSettings: CertHashStrFromCert error");
1031		MacOSError::throwMe(errSecItemNotFound);
1032	}
1033
1034	/*
1035	 * Find entry for this cert, if present.
1036	 */
1037	CFMutableDictionaryRef certDict =
1038		(CFMutableDictionaryRef)findDictionaryForCertHash(certHashStr);
1039	if(certDict == NULL) {
1040		/* create new dictionary */
1041		certDict = CFDictionaryCreateMutable(NULL, kSecTrustRecordNumCertDictKeys,
1042			&kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1043		if(certDict == NULL) {
1044			MacOSError::throwMe(errSecAllocate);
1045		}
1046		CFDictionaryAddValue(certDict, kTrustRecordIssuer, issuer);
1047		CFDictionaryAddValue(certDict, kTrustRecordSerialNumber, serial);
1048		if(CFArrayGetCount(trustSettings) != 0) {
1049			/* skip this if the settings array is empty */
1050			CFDictionaryAddValue(certDict, kTrustRecordTrustSettings, trustSettings);
1051		}
1052		tsSetModDate(certDict);
1053
1054		/* add this new cert dictionary to top-level mTrustDict */
1055		CFDictionaryAddValue(mTrustDict, static_cast<CFStringRef>(certHashStr), certDict);
1056
1057		/* mTrustDict owns the dictionary now */
1058		CFRelease(certDict);
1059	}
1060	else {
1061		/* update */
1062		tsSetModDate(certDict);
1063		if(CFArrayGetCount(trustSettings) != 0) {
1064			CFDictionarySetValue(certDict, kTrustRecordTrustSettings, trustSettings);
1065		}
1066		else {
1067			/* empty settings array: remove from dictionary */
1068			CFDictionaryRemoveValue(certDict, kTrustRecordTrustSettings);
1069		}
1070	}
1071	mDirty = true;
1072}
1073
1074/*
1075 * Delete a certificate's trust settings.
1076 */
1077void TrustSettings::deleteTrustSettings(
1078	SecCertificateRef	certRef)
1079{
1080	CFDictionaryRef certDict = NULL;
1081
1082	/* caller is responsible for ensuring these */
1083	assert(mPropList != NULL);
1084	assert(mDomain != kSecTrustSettingsDomainSystem);
1085
1086	/* SHA1 digest as string */
1087	CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef));
1088	if(!certHashStr) {
1089		MacOSError::throwMe(errSecItemNotFound);
1090	}
1091
1092	/* present in top-level mTrustDict? */
1093	certDict = findDictionaryForCertHash(certHashStr);
1094	if(certDict != NULL) {
1095		CFDictionaryRemoveValue(mTrustDict, static_cast<CFStringRef>(certHashStr));
1096		mDirty = true;
1097	}
1098	else {
1099		/*
1100		 * Throwing this error is the only reason we don't blindly do
1101		 * a CFDictionaryRemoveValue() without first doing
1102		 * findDictionaryForCertHash().
1103		 */
1104		trustSettingsDbg("TrustSettings::deleteRoot: cert dictionary not found");
1105		MacOSError::throwMe(errSecItemNotFound);
1106	}
1107}
1108
1109#pragma mark --- Private methods ---
1110
1111/*
1112 * Find a given cert's entry in the top-level mTrustDict. Return the
1113 * entry as a dictionary. Returned dictionary is not refcounted.
1114 * The mutability of the returned dictionary is the same as the mutability
1115 * of the underlying StickRecord::mPropList, which the caller is just
1116 * going to have to know (and cast accordingly if a mutable dictionary
1117 * is needed).
1118 */
1119CFDictionaryRef TrustSettings::findDictionaryForCert(
1120	SecCertificateRef	certRef)
1121{
1122	CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef));
1123	if (certHashStr.get() == NULL)
1124	{
1125		return NULL;
1126	}
1127
1128	return findDictionaryForCertHash(static_cast<CFStringRef>(certHashStr));
1129}
1130
1131/*
1132 * Find entry in mTrustDict given cert hash string.
1133 */
1134CFDictionaryRef TrustSettings::findDictionaryForCertHash(
1135	CFStringRef		certHashStr)
1136{
1137	assert(mTrustDict != NULL);
1138	return (CFDictionaryRef)CFDictionaryGetValue(mTrustDict, certHashStr);
1139}
1140
1141/*
1142 * Validate incoming trust settings, which may be NULL, a dictionary, or
1143 * an array of dictionaries. Convert from the API-style dictionaries
1144 * to the internal style suitable for writing to disk as part of
1145 * mPropList.
1146 *
1147 * We return a refcounted CFArray in any case if the incoming parameter is good.
1148 */
1149CFArrayRef TrustSettings::validateApiTrustSettings(
1150	CFTypeRef trustSettingsDictOrArray,
1151	Boolean isSelfSigned)
1152{
1153	CFArrayRef tmpInArray = NULL;
1154
1155	if(trustSettingsDictOrArray == NULL) {
1156		/* trivial case, only valid for roots */
1157		if(!isSelfSigned) {
1158			trustSettingsDbg("validateApiUsageConstraints: !isSelfSigned, no settings");
1159			MacOSError::throwMe(errSecParam);
1160		}
1161		return CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
1162	}
1163	else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) {
1164		/* array-ize it */
1165		tmpInArray = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1,
1166			&kCFTypeArrayCallBacks);
1167	}
1168	else if(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID()) {
1169		/* as is, refcount - we'll release later */
1170		tmpInArray = (CFArrayRef)trustSettingsDictOrArray;
1171		CFRetain(tmpInArray);
1172	}
1173	else {
1174		trustSettingsDbg("validateApiUsageConstraints: bad trustSettingsDictOrArray");
1175		MacOSError::throwMe(errSecParam);
1176	}
1177
1178	CFIndex numSpecs = CFArrayGetCount(tmpInArray);
1179	CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, numSpecs, &kCFTypeArrayCallBacks);
1180	CSSM_OID oid;
1181	OSStatus ortn = errSecSuccess;
1182	SecPolicyRef certPolicy;
1183	SecTrustedApplicationRef certApp;
1184
1185	/* convert */
1186	for(CFIndex dex=0; dex<numSpecs; dex++) {
1187		CFDataRef   oidData = NULL;
1188		CFDataRef   appData = NULL;
1189		CFStringRef policyStr = NULL;
1190		CFNumberRef allowedErr = NULL;
1191		CFNumberRef resultType = NULL;
1192		CFNumberRef keyUsage = NULL;
1193		SInt32 resultNum;
1194		SecTrustSettingsResult result;
1195
1196		/* each element is a dictionary */
1197		CFDictionaryRef ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(tmpInArray, dex);
1198		if(CFGetTypeID(ucDict) != CFDictionaryGetTypeID()) {
1199			trustSettingsDbg("validateAppPolicyArray: malformed usageConstraint dictionary");
1200			ortn = errSecParam;
1201			break;
1202		}
1203
1204		/* policy - optional */
1205		certPolicy = (SecPolicyRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy);
1206		if(certPolicy != NULL) {
1207			if(CFGetTypeID(certPolicy) != SecPolicyGetTypeID()) {
1208				trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1209				ortn = errSecParam;
1210				break;
1211			}
1212			ortn = SecPolicyGetOID(certPolicy, &oid);
1213			if(ortn) {
1214				trustSettingsDbg("validateAppPolicyArray: SecPolicyGetOID error");
1215				break;
1216			}
1217			oidData = CFDataCreate(NULL, oid.Data, oid.Length);
1218		}
1219
1220		/* application - optional */
1221		certApp = (SecTrustedApplicationRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsApplication);
1222		if(certApp != NULL) {
1223			if(CFGetTypeID(certApp) != SecTrustedApplicationGetTypeID()) {
1224				trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1225				ortn = errSecParam;
1226				break;
1227			}
1228			ortn = SecTrustedApplicationCopyExternalRepresentation(certApp, &appData);
1229			if(ortn) {
1230				trustSettingsDbg("validateAppPolicyArray: "
1231					"SecTrustedApplicationCopyExternalRepresentation error");
1232				break;
1233			}
1234		}
1235
1236		policyStr  = (CFStringRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicyString);
1237		if(policyStr != NULL) {
1238			if(CFGetTypeID(policyStr) != CFStringGetTypeID()) {
1239				trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1240				ortn = errSecParam;
1241				break;
1242			}
1243		}
1244		allowedErr = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError);
1245		if(!tsIsGoodCfNum(allowedErr)) {
1246			trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1247			ortn = errSecParam;
1248			break;
1249		}
1250		resultType = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult);
1251		if(!tsIsGoodCfNum(resultType, &resultNum)) {
1252			trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1253			ortn = errSecParam;
1254			break;
1255		}
1256		result = resultNum;
1257		/* validate result later */
1258
1259		keyUsage   = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage);
1260		if(!tsIsGoodCfNum(keyUsage)) {
1261			trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1262			ortn = errSecParam;
1263			break;
1264		}
1265
1266		if(!oidData && !appData && !policyStr &&
1267		   !allowedErr && !resultType && !keyUsage) {
1268			/* nothing here - weird, but legal - skip it */
1269			continue;
1270		}
1271
1272		/* create dictionary for this usageConstraint */
1273		CFMutableDictionaryRef outDict = CFDictionaryCreateMutable(NULL,
1274			2,
1275			&kCFTypeDictionaryKeyCallBacks,
1276			&kCFTypeDictionaryValueCallBacks);
1277		if(oidData) {
1278			CFDictionaryAddValue(outDict, kSecTrustSettingsPolicy, oidData);
1279			CFRelease(oidData);			// owned by dictionary
1280		}
1281		if(appData) {
1282			CFDictionaryAddValue(outDict, kSecTrustSettingsApplication, appData);
1283			CFRelease(appData);			// owned by dictionary
1284		}
1285		if(policyStr) {
1286			CFDictionaryAddValue(outDict, kSecTrustSettingsPolicyString, policyStr);
1287			/* still owned by ucDict */
1288		}
1289		if(allowedErr) {
1290			CFDictionaryAddValue(outDict, kSecTrustSettingsAllowedError, allowedErr);
1291		}
1292		if(resultType) {
1293			/* let's be really picky on this one */
1294			switch(result) {
1295				case kSecTrustSettingsResultInvalid:
1296					ortn = errSecParam;
1297					break;
1298				case kSecTrustSettingsResultTrustRoot:
1299					if(!isSelfSigned) {
1300						trustSettingsDbg("validateAppPolicyArray: TrustRoot, !isSelfSigned");
1301						ortn = errSecParam;
1302					}
1303					break;
1304				case kSecTrustSettingsResultTrustAsRoot:
1305					if(isSelfSigned) {
1306						trustSettingsDbg("validateAppPolicyArray: TrustAsRoot, isSelfSigned");
1307						ortn = errSecParam;
1308					}
1309					break;
1310				case kSecTrustSettingsResultDeny:
1311				case kSecTrustSettingsResultUnspecified:
1312					break;
1313				default:
1314					trustSettingsDbg("validateAppPolicyArray: bogus resultType");
1315					ortn = errSecParam;
1316					break;
1317			}
1318			if(ortn) {
1319				break;
1320			}
1321			CFDictionaryAddValue(outDict, kSecTrustSettingsResult, resultType);
1322		}
1323		else {
1324			/* no resultType; default of TrustRoot only valid for root */
1325			if(!isSelfSigned) {
1326				trustSettingsDbg("validateAppPolicyArray: default result, !isSelfSigned");
1327				ortn = errSecParam;
1328				break;
1329			}
1330		}
1331		if(keyUsage) {
1332			CFDictionaryAddValue(outDict, kSecTrustSettingsKeyUsage, keyUsage);
1333		}
1334
1335		/* append dictionary to output */
1336		CFArrayAppendValue(outArray, outDict);
1337		/* array owns the dictionary now */
1338		CFRelease(outDict);
1339
1340	}	/* for each usage constraint dictionary */
1341
1342	CFRelease(tmpInArray);
1343	if(ortn) {
1344		CFRelease(outArray);
1345		MacOSError::throwMe(ortn);
1346	}
1347	return outArray;
1348}
1349
1350/*
1351 * Validate an trust settings array obtained from disk.
1352 * Returns true if OK, else returns false.
1353 */
1354bool TrustSettings::validateTrustSettingsArray(
1355	CFArrayRef trustSettings)
1356{
1357	CFIndex numSpecs = CFArrayGetCount(trustSettings);
1358	for(CFIndex dex=0; dex<numSpecs; dex++) {
1359		CFDictionaryRef ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings,
1360			dex);
1361		if(CFGetTypeID(ucDict) != CFDictionaryGetTypeID()) {
1362			trustSettingsDbg("validateAppPolicyArray: malformed app/policy dictionary");
1363			return false;
1364		}
1365		CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy);
1366		if((certPolicy != NULL) && (CFGetTypeID(certPolicy) != CFDataGetTypeID())) {
1367			trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1368			return false;
1369		}
1370		CFDataRef certApp = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsApplication);
1371		if((certApp != NULL) && (CFGetTypeID(certApp) != CFDataGetTypeID())) {
1372			trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1373			return false;
1374		}
1375		CFStringRef policyStr = (CFStringRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicyString);
1376		if((policyStr != NULL) && (CFGetTypeID(policyStr) != CFStringGetTypeID())) {
1377			trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1378			return false;
1379		}
1380		CFNumberRef cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError);
1381		if(!tsIsGoodCfNum(cfNum)) {
1382			trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1383			return false;
1384		}
1385		cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult);
1386		if(!tsIsGoodCfNum(cfNum)) {
1387			trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1388			return false;
1389		}
1390		cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage);
1391		if(!tsIsGoodCfNum(cfNum)) {
1392			trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1393			return false;
1394		}
1395	}	/* for each usageConstraint dictionary */
1396	return true;
1397}
1398
1399/*
1400 * Validate mPropList after it's read from disk or supplied as an external
1401 * representation. Allows subsequent use of mTrustDict to proceed with
1402 * relative impunity.
1403 */
1404void TrustSettings::validatePropList(bool trim)
1405{
1406	/* top level dictionary */
1407	if(!mPropList) {
1408		trustSettingsDbg("TrustSettings::validatePropList missing mPropList");
1409		abort("missing propList", errSecInvalidTrustedRootRecord);
1410	}
1411
1412	if(CFGetTypeID(mPropList) != CFDictionaryGetTypeID()) {
1413		trustSettingsDbg("TrustSettings::validatePropList: malformed mPropList");
1414		abort("malformed propList", errSecInvalidTrustedRootRecord);
1415	}
1416
1417	/* That dictionary has two entries */
1418	CFNumberRef cfVers = (CFNumberRef)CFDictionaryGetValue(mPropList, kTrustRecordVersion);
1419	if((cfVers == NULL) || (CFGetTypeID(cfVers) != CFNumberGetTypeID())) {
1420		trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1421		abort("malformed version", errSecInvalidTrustedRootRecord);
1422	}
1423	if(!CFNumberGetValue(cfVers, kCFNumberSInt32Type, &mDictVersion)) {
1424		trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1425		abort("malformed version", errSecInvalidTrustedRootRecord);
1426	}
1427	if((mDictVersion > kSecTrustRecordVersionCurrent) ||
1428	   (mDictVersion == kSecTrustRecordVersionInvalid)) {
1429		trustSettingsDbg("TrustSettings::validatePropList: incompatible version");
1430		abort("incompatible version", errSecInvalidTrustedRootRecord);
1431	}
1432	/* other backwards-compatibility handling done later, if needed, per mDictVersion */
1433
1434	mTrustDict = (CFMutableDictionaryRef)CFDictionaryGetValue(mPropList, kTrustRecordTrustList);
1435	if(mTrustDict != NULL) {
1436		CFRetain(mTrustDict);
1437	}
1438	if((mTrustDict == NULL) || (CFGetTypeID(mTrustDict) != CFDictionaryGetTypeID())) {
1439		trustSettingsDbg("TrustSettings::validatePropList: malformed mTrustDict");
1440		abort("malformed TrustArray", errSecInvalidTrustedRootRecord);
1441	}
1442
1443	/* grind through the per-cert entries */
1444	CFIndex numCerts = CFDictionaryGetCount(mTrustDict);
1445	const void *dictKeys[numCerts];
1446	const void *dictValues[numCerts];
1447	CFDictionaryGetKeysAndValues(mTrustDict, dictKeys, dictValues);
1448
1449	for(CFIndex dex=0; dex<numCerts; dex++) {
1450		/* get per-cert dictionary */
1451		CFMutableDictionaryRef certDict = (CFMutableDictionaryRef)dictValues[dex];
1452		if((certDict == NULL) || (CFGetTypeID(certDict) != CFDictionaryGetTypeID())) {
1453			trustSettingsDbg("TrustSettings::validatePropList: malformed certDict");
1454			abort("malformed certDict", errSecInvalidTrustedRootRecord);
1455		}
1456
1457		/*
1458		 * That dictionary has exactly four entries.
1459		 * If we're trimming, all we need is the actual trust settings.
1460		 */
1461
1462		/* issuer */
1463		CFDataRef cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordIssuer);
1464		if(cfd == NULL) {
1465			trustSettingsDbg("TrustSettings::validatePropList: missing issuer");
1466			abort("missing issuer", errSecInvalidTrustedRootRecord);
1467		}
1468		if(CFGetTypeID(cfd) != CFDataGetTypeID()) {
1469			trustSettingsDbg("TrustSettings::validatePropList: malformed issuer");
1470			abort("malformed issuer", errSecInvalidTrustedRootRecord);
1471		}
1472		if(trim) {
1473			CFDictionaryRemoveValue(certDict, kTrustRecordIssuer);
1474		}
1475
1476		/* serial number */
1477		cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordSerialNumber);
1478		if(cfd == NULL) {
1479			trustSettingsDbg("TrustSettings::validatePropList: missing serial number");
1480			abort("missing serial number", errSecInvalidTrustedRootRecord);
1481		}
1482		if(CFGetTypeID(cfd) != CFDataGetTypeID()) {
1483			trustSettingsDbg("TrustSettings::validatePropList: malformed serial number");
1484			abort("malformed serial number", errSecInvalidTrustedRootRecord);
1485		}
1486		if(trim) {
1487			CFDictionaryRemoveValue(certDict, kTrustRecordSerialNumber);
1488		}
1489
1490		/* modification date */
1491		CFDateRef modDate = (CFDateRef)CFDictionaryGetValue(certDict, kTrustRecordModDate);
1492		if(modDate == NULL) {
1493			trustSettingsDbg("TrustSettings::validatePropList: missing modDate");
1494			abort("missing modDate", errSecInvalidTrustedRootRecord);
1495		}
1496		if(CFGetTypeID(modDate) != CFDateGetTypeID()) {
1497			trustSettingsDbg("TrustSettings::validatePropList: malformed modDate");
1498			abort("malformed modDate", errSecInvalidTrustedRootRecord);
1499		}
1500		if(trim) {
1501			CFDictionaryRemoveValue(certDict, kTrustRecordModDate);
1502		}
1503
1504		/* the actual trust settings */
1505		CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict,
1506				kTrustRecordTrustSettings);
1507		if(trustSettings == NULL) {
1508			/* optional; this cert's entry is good */
1509			continue;
1510		}
1511		if(CFGetTypeID(trustSettings) != CFArrayGetTypeID()) {
1512			trustSettingsDbg("TrustSettings::validatePropList: malformed useConstraint"
1513				"array");
1514			abort("malformed useConstraint array", errSecInvalidTrustedRootRecord);
1515		}
1516
1517		/* Now validate the usageConstraint array contents */
1518		if(!validateTrustSettingsArray(trustSettings)) {
1519			abort("malformed useConstraint array", errSecInvalidTrustedRootRecord);
1520		}
1521	} /* for each cert dictionary  in top-level array */
1522
1523	if(trim) {
1524		/* we don't need the top-level dictionary any more */
1525		CFRelease(mPropList);
1526		mPropList = NULL;
1527	}
1528}
1529
1530/*
1531 * Obtain non-normalized issuer and serial number for specified cert, both
1532 * returned as CFDataRefs owned by caller.
1533 */
1534void TrustSettings::copyIssuerAndSerial(
1535	SecCertificateRef	certRef,
1536	CFDataRef			*issuer,		/* optional, RETURNED */
1537	CFDataRef			*serial)		/* RETURNED */
1538{
1539	SecPointer<Certificate> cert = Certificate::required(certRef);
1540	CSSM_DATA_PTR fieldVal;
1541
1542	if(issuer != NULL) {
1543		fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd);
1544		*issuer = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length);
1545		cert->releaseFieldValue(CSSMOID_X509V1IssuerNameStd, fieldVal);
1546	}
1547
1548	fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1SerialNumber);
1549	*serial = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length);
1550	cert->releaseFieldValue(CSSMOID_X509V1SerialNumber, fieldVal);
1551}
1552
1553void TrustSettings::abort(
1554	const char *why,
1555	OSStatus err)
1556{
1557	Syslog::error("TrustSettings: %s", why);
1558	MacOSError::throwMe(err);
1559}
1560
1561