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