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 * SecTrustSettings.cpp - Public interface for manipulation of Trust Settings.
26 *
27 */
28
29#include "SecBridge.h"
30#include "SecTrustSettings.h"
31#include "SecTrustSettingsPriv.h"
32#include "TrustSettingsUtils.h"
33#include "TrustSettings.h"
34#include "TrustSettingsSchema.h"
35#include "TrustKeychains.h"
36#include "Trust.h"
37#include "SecKeychainPriv.h"
38#include "Globals.h"
39#include <security_utilities/threading.h>
40#include <security_utilities/globalizer.h>
41#include <security_utilities/errors.h>
42#include <security_cdsa_utilities/cssmerrors.h>
43#include <security_utilities/logging.h>
44#include <security_utilities/debugging.h>
45#include <security_utilities/simpleprefs.h>
46#include <securityd_client/dictionary.h>
47#include <securityd_client/ssclient.h>
48#include <assert.h>
49#include <vector>
50#include <CommonCrypto/CommonDigest.h>
51
52#define trustSettingsDbg(args...)	secdebug("trustSettings", ## args)
53
54/*
55 * Ideally we'd like to implement our own lock to protect the state of the cert stores
56 * without grabbing the global Sec API lock, but we deal with SecCFObjects, so we'll have
57 * to bite the bullet and grab the big lock. We also have our own lock protecting the
58 * global trust settings cache which is also used by the keychain callback function
59 * (which does not grab the Sec API lock).
60 */
61
62#define BEGIN_RCSAPI	\
63	OSStatus __secapiresult; \
64	try {
65#define END_RCSAPI		\
66		__secapiresult=errSecSuccess; \
67	} \
68	catch (const MacOSError &err) { __secapiresult=err.osStatus(); } \
69	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } \
70	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } \
71	catch (...) { __secapiresult=errSecInternalComponent; } \
72	return __secapiresult;
73
74#define END_RCSAPI0		\
75	catch (...) {} \
76	return;
77
78
79#pragma mark --- TrustSettings preferences ---
80
81/*
82 * If Colonel Klink wants to disable user-level Trust Settings, he'll have
83 * to restart the apps which will be affected after he does so. We are not
84 * going to consult system prefs every time we do a cert evaluation. We
85 * consult it once per process and cache the results here.
86 */
87static bool tsUserTrustDisableValid = false;	/* true once we consult prefs */
88static bool tsUserTrustDisable = false;			/* the cached value */
89
90/*
91 * Determine whether user-level Trust Settings disabled.
92 */
93static bool tsUserTrustSettingsDisabled()
94{
95	if(tsUserTrustDisableValid) {
96		return tsUserTrustDisable;
97	}
98	tsUserTrustDisable = false;
99
100	Dictionary* dictionary = Dictionary::CreateDictionary(kSecTrustSettingsPrefsDomain, Dictionary::US_System);
101	if (dictionary)
102	{
103		auto_ptr<Dictionary> prefsDict(dictionary);
104		/* this returns false if the pref isn't there, just like we want */
105		tsUserTrustDisable = prefsDict->getBoolValue(kSecTrustSettingsDisableUserTrustSettings);
106	}
107
108	tsUserTrustDisableValid = true;
109	return tsUserTrustDisable;
110}
111
112#pragma mark --- TrustSettings global cache ---
113
114/***
115 *** cache submodule - keeps per-app copy of zero or one TrustSettings
116 ***  				   for each domain. Used only by SecTrustSettingsEvaluateCert()
117 ***				   and SecTrustSettingsCopyQualifiedCerts(); results of
118 ***				   manipulation by public API functions are not cached.
119 ***/
120
121/*
122 * API/client code has to hold this lock when doing anything with any of
123 * the TrustSettings maintained here.
124 * It's recursive to accomodate CodeSigning's need to do cert verification
125 * (while we evaluate app equivalence).
126 */
127static ModuleNexus<RecursiveMutex> sutCacheLock;
128
129#define TRUST_SETTINGS_NUM_DOMAINS		3
130
131/*
132 * The three global TrustSettings.
133 * We rely on the fact the the domain enums start with 0; we use
134 * the domain value as an index into the following two arrays.
135 */
136static TrustSettings *globalTrustSettings[TRUST_SETTINGS_NUM_DOMAINS] =
137		{NULL, NULL, NULL};
138
139/*
140 * Indicates "the associated global here is currently valid; if there isn't a
141 * globalTrustSettings[domain], don't try to find one"
142 */
143static bool globalTrustSettingsValid[TRUST_SETTINGS_NUM_DOMAINS] =
144		{false, false, false};
145
146/* remember the fact that we've registered our KC callback */
147static bool sutRegisteredCallback = false;
148
149static void tsRegisterCallback();
150
151/*
152 * Assign global TrustSetting to new incoming value, which may be NULL.
153 * Caller holds sutCacheLock.
154 */
155static void tsSetGlobalTrustSettings(
156	TrustSettings *ts,
157	SecTrustSettingsDomain domain)
158{
159	assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS));
160
161	trustSettingsDbg("tsSetGlobalTrustSettings domain %d: caching TS %p old TS %p",
162		(int)domain, ts, globalTrustSettings[domain]);
163	delete globalTrustSettings[domain];
164	globalTrustSettings[domain] = ts;
165	globalTrustSettingsValid[domain] = ts ? true : false;
166	tsRegisterCallback();
167}
168
169/*
170 * Obtain global TrustSettings for specified domain if it exists.
171 * Returns NULL if there is simply no TS for that domain.
172 * The TS, if returned, belongs to this cache module.
173 * Caller holds sutCacheLock.
174 */
175static TrustSettings *tsGetGlobalTrustSettings(
176	SecTrustSettingsDomain domain)
177{
178	assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS));
179
180	if((domain == kSecTrustSettingsDomainUser) && tsUserTrustSettingsDisabled()) {
181		trustSettingsDbg("tsGetGlobalTrustSettings: skipping DISABLED user domain");
182		return NULL;
183	}
184
185	if(globalTrustSettingsValid[domain]) {
186		// ready or not, use this
187		return globalTrustSettings[domain];
188	}
189	assert(globalTrustSettings[domain] == NULL);
190
191	/* try to find one */
192	OSStatus result = errSecSuccess;
193	TrustSettings *ts = NULL;
194	/* don't create; trim if found */
195	result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_YES, ts);
196    if (   (domain != kSecTrustSettingsDomainSystem)
197        && (result == errSecInternalComponent)) {
198        /*
199         * Could not connect to ocspd to get the user/admin domain trust settings
200         * This happens in single user mode for example.
201         * Valid flag is set to false and continue.
202         */
203        trustSettingsDbg("tsGetGlobalTrustSettings: could not connect to ocspd for domain (%d)",(int)domain);
204        globalTrustSettingsValid[domain] = false;
205        tsRegisterCallback();
206        return NULL;
207    }
208    else if (result == errSecNoTrustSettings) {
209		/*
210		 * No TrustSettings for this domain, actually a fairly common case.
211		 * Optimize: don't bother trying this again.
212		 */
213		trustSettingsDbg("tsGetGlobalTrustSettings: flagging known NULL");
214		globalTrustSettingsValid[domain] = true;
215		tsRegisterCallback();
216		return NULL;
217	}
218    else if(result != errSecSuccess) {
219        /* gross error */
220        MacOSError::throwMe(result);
221    }
222
223	tsSetGlobalTrustSettings(ts, domain);
224	return ts;
225}
226
227/*
228 * Purge TrustSettings cache.
229 * Called by Keychain Event callback and by our API functions that
230 * modify trust settings.
231 * Caller can NOT hold sutCacheLock.
232 */
233static void tsPurgeCache()
234{
235	int domain;
236
237	StLock<Mutex>	_(sutCacheLock());
238	trustSettingsDbg("tsPurgeCache");
239	for(domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
240		tsSetGlobalTrustSettings(NULL, domain);
241	}
242}
243
244/*
245 * Keychain event callback function, for notification by other processes that
246 * user trust list(s) has/have changed.
247 */
248static OSStatus tsTrustSettingsCallback (
249   SecKeychainEvent keychainEvent,
250   SecKeychainCallbackInfo *info,
251   void *context)
252{
253	trustSettingsDbg("tsTrustSettingsCallback, event %d", (int)keychainEvent);
254	if(keychainEvent != kSecTrustSettingsChangedEvent) {
255		/* should not happen, right? */
256		return errSecSuccess;
257	}
258	if(info->pid == getpid()) {
259		/*
260		 * Avoid dup cache invalidates: we already dealt with this event.
261		 */
262		trustSettingsDbg("cacheEventCallback: our pid, skipping");
263	}
264	else {
265		tsPurgeCache();
266	}
267	return errSecSuccess;
268}
269
270/*
271 * Ensure that we've registered for kSecTrustSettingsChangedEvent callbacks
272 */
273static void tsRegisterCallback()
274{
275	if(sutRegisteredCallback) {
276		return;
277	}
278	trustSettingsDbg("tsRegisterCallback: registering callback");
279	OSStatus ortn = SecKeychainAddCallback(tsTrustSettingsCallback,
280		kSecTrustSettingsChangedEventMask, NULL);
281	if(ortn) {
282		trustSettingsDbg("tsRegisterCallback: SecKeychainAddCallback returned %d", (int)ortn);
283		/* Not sure how this could ever happen - maybe if there is no run loop active? */
284	}
285	sutRegisteredCallback = true;
286}
287
288#pragma mark --- Static functions ---
289
290
291/*
292 * Called by API code when a trust list has changed; we notify other processes
293 * and purge our own cache.
294 */
295static void tsTrustSettingsChanged()
296{
297	tsPurgeCache();
298
299	/* The only interesting data is our pid */
300	NameValueDictionary nvd;
301	pid_t ourPid = getpid();
302	nvd.Insert (new NameValuePair (PID_KEY,
303		CssmData (reinterpret_cast<void*>(&ourPid), sizeof (pid_t))));
304	CssmData data;
305	nvd.Export (data);
306
307	trustSettingsDbg("tsTrustSettingsChanged: posting notification");
308	SecurityServer::ClientSession cs (Allocator::standard(), Allocator::standard());
309	cs.postNotification (SecurityServer::kNotificationDomainDatabase,
310		kSecTrustSettingsChangedEvent, data);
311	free (data.data ());
312}
313
314/*
315 * Common code for SecTrustSettingsCopyTrustSettings(),
316 * SecTrustSettingsCopyModificationDate().
317 */
318static OSStatus tsCopyTrustSettings(
319	SecCertificateRef cert,
320	SecTrustSettingsDomain domain,
321	CFArrayRef *trustSettings,		/* optionally RETURNED */
322	CFDateRef *modDate)				/* optionally RETURNED */
323{
324	BEGIN_RCSAPI
325
326	TS_REQUIRED(cert)
327
328	/* obtain fresh full copy from disk */
329	OSStatus result;
330	TrustSettings* ts;
331
332	result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
333
334	// rather than throw these results, just return them because we are at the top level
335	if (result == errSecNoTrustSettings) {
336		return errSecItemNotFound;
337	}
338	else if (result != errSecSuccess) {
339		return result;
340	}
341
342	auto_ptr<TrustSettings>_(ts); // make sure this gets deleted just in case something throws underneath
343
344	if(trustSettings) {
345		*trustSettings = ts->copyTrustSettings(cert);
346	}
347	if(modDate) {
348		*modDate = ts->copyModDate(cert);
349	}
350
351	END_RCSAPI
352}
353
354/*
355 * Common code for SecTrustSettingsCopyQualifiedCerts() and
356 * SecTrustSettingsCopyUnrestrictedRoots().
357 */
358static OSStatus tsCopyCertsCommon(
359	/* usage constraints, all optional */
360	const CSSM_OID			*policyOID,
361	const char				*policyString,
362	SecTrustSettingsKeyUsage keyUsage,
363	/* constrain to only roots */
364	bool					onlyRoots,
365	/* per-domain enables */
366	bool					user,
367	bool					admin,
368	bool					system,
369	CFArrayRef				*certArray)		/* RETURNED */
370{
371	StLock<Mutex> _TC(sutCacheLock());
372	StLock<Mutex> _TK(SecTrustKeychainsGetMutex());
373
374	TS_REQUIRED(certArray)
375
376	/* this relies on the domain enums being numbered 0..2, user..system */
377	bool domainEnable[3] = {user, admin, system};
378
379	/* we'll retain it again before successful exit */
380	CFRef<CFMutableArrayRef> outArray(CFArrayCreateMutable(NULL, 0,
381		&kCFTypeArrayCallBacks));
382
383	/*
384	 * Search all keychains - user's, System.keychain, system root store,
385	 * system intermdiates as appropriate
386  	 */
387	StorageManager::KeychainList keychains;
388	Keychain adminKc;
389	if(user) {
390		globals().storageManager.getSearchList(keychains);
391	}
392	if(user || admin) {
393		adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false);
394		keychains.push_back(adminKc);
395	}
396	Keychain sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false);
397	keychains.push_back(sysRootKc);
398	Keychain sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false);
399	keychains.push_back(sysCertKc);
400
401	assert(kSecTrustSettingsDomainUser == 0);
402	for(unsigned domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
403		if(!domainEnable[domain]) {
404			continue;
405		}
406		TrustSettings *ts = tsGetGlobalTrustSettings(domain);
407		if(ts == NULL) {
408			continue;
409		}
410		ts->findQualifiedCerts(keychains,
411			false, 		/* !findAll */
412			onlyRoots,
413			policyOID, policyString, keyUsage,
414			outArray);
415	}
416	*certArray = outArray;
417	CFRetain(*certArray);
418	trustSettingsDbg("tsCopyCertsCommon: %ld certs found",
419		CFArrayGetCount(outArray));
420	return errSecSuccess;
421}
422
423#pragma mark --- SPI functions ---
424
425
426/*
427 * Fundamental routine used by TP to ascertain status of one cert.
428 *
429 * Returns true in *foundMatchingEntry if a trust setting matching
430 * specific constraints was found for the cert. Returns true in
431 * *foundAnyEntry if any entry was found for the cert, even if it
432 * did not match the specified constraints. The TP uses this to
433 * optimize for the case where a cert is being evaluated for
434 * one type of usage, and then later for another type. If
435 * foundAnyEntry is false, the second evaluation need not occur.
436 *
437 * Returns the domain in which a setting was found in *foundDomain.
438 *
439 * Allowed errors applying to the specified cert evaluation
440 * are returned in a mallocd array in *allowedErrors and must
441 * be freed by caller.
442 *
443 * The design of the entire TrustSettings module is centered around
444 * optimizing the performance of this routine (security concerns
445 * aside, that is). It's why the per-cert dictionaries are stored
446 * as a dictionary, keyed off of the cert hash. It's why TrustSettings
447 * are cached in memory by tsGetGlobalTrustSettings(), and why those
448 * cached TrustSettings objects are 'trimmed' of dictionary fields
449 * which are not needed to verify a cert.
450 *
451 * The API functions which are used to manipulate Trust Settings
452 * are called infrequently and need not be particularly fast since
453 * they result in user interaction for authentication. Thus they do
454 * not use cached TrustSettings as this function does.
455 */
456OSStatus SecTrustSettingsEvaluateCert(
457	CFStringRef				certHashStr,
458	/* parameters describing the current cert evalaution */
459	const CSSM_OID			*policyOID,
460	const char				*policyString,		/* optional */
461	uint32					policyStringLen,
462	SecTrustSettingsKeyUsage keyUsage,			/* optional */
463	bool					isRootCert,			/* for checking default setting */
464	/* RETURNED values */
465	SecTrustSettingsDomain	*foundDomain,
466	CSSM_RETURN				**allowedErrors,	/* mallocd */
467	uint32					*numAllowedErrors,
468	SecTrustSettingsResult	*resultType,
469	bool					*foundMatchingEntry,
470	bool					*foundAnyEntry)
471{
472	BEGIN_RCSAPI
473
474	StLock<Mutex>	_(sutCacheLock());
475
476	TS_REQUIRED(certHashStr)
477	TS_REQUIRED(foundDomain)
478	TS_REQUIRED(allowedErrors)
479	TS_REQUIRED(numAllowedErrors)
480	TS_REQUIRED(resultType)
481	TS_REQUIRED(foundMatchingEntry)
482	TS_REQUIRED(foundAnyEntry)
483
484	/* ensure a NULL_terminated string */
485	auto_array<char> polStr;
486	if(policyString != NULL && policyStringLen > 0) {
487		polStr.allocate(policyStringLen + 1);
488		memmove(polStr.get(), policyString, policyStringLen);
489		if(policyString[policyStringLen - 1] != '\0') {
490			(polStr.get())[policyStringLen] = '\0';
491		}
492	}
493
494	/* initial condition - this can grow if we inspect multiple TrustSettings */
495	*allowedErrors = NULL;
496	*numAllowedErrors = 0;
497
498	/*
499	 * This loop relies on the ordering of the SecTrustSettingsDomain enum:
500	 * search user first, then admin, then system.
501	 */
502	assert(kSecTrustSettingsDomainAdmin == (kSecTrustSettingsDomainUser + 1));
503	assert(kSecTrustSettingsDomainSystem == (kSecTrustSettingsDomainAdmin + 1));
504	bool foundAny = false;
505	for(unsigned domain=kSecTrustSettingsDomainUser;
506			     domain<=kSecTrustSettingsDomainSystem;
507				 domain++) {
508		TrustSettings *ts = tsGetGlobalTrustSettings(domain);
509		if(ts == NULL) {
510			continue;
511		}
512
513		/* validate cert returns true if matching entry was found */
514		bool foundAnyHere = false;
515		bool found = ts->evaluateCert(certHashStr, policyOID,
516			polStr.get(), keyUsage, isRootCert,
517			allowedErrors, numAllowedErrors, resultType, &foundAnyHere);
518
519		if(found) {
520			/*
521			 * Note this, even though we may overwrite it later if this
522			 * is an Unspecified entry and we find a definitive entry
523			 * later
524			 */
525			*foundDomain = domain;
526		}
527		if(found && (*resultType != kSecTrustSettingsResultUnspecified)) {
528			trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain);
529			*foundAnyEntry = true;
530			*foundMatchingEntry = true;
531			return errSecSuccess;
532		}
533		foundAny |= foundAnyHere;
534	}
535	trustSettingsDbg("SecTrustSettingsEvaluateCert: NOT FOUND");
536	*foundAnyEntry = foundAny;
537	*foundMatchingEntry = false;
538	return errSecSuccess;
539	END_RCSAPI
540}
541
542/*
543 * Obtain trusted certs which match specified usage.
544 * Only certs with a SecTrustSettingsResult of
545 * kSecTrustSettingsResultTrustRoot or
546 * or kSecTrustSettingsResultTrustAsRoot will be returned.
547 * To be used by SecureTransport for its SSLSetTrustedRoots() call;
548 * I hope nothing else has to use this...
549 * Caller must CFRelease the returned CFArrayRef.
550 */
551OSStatus SecTrustSettingsCopyQualifiedCerts(
552	const CSSM_OID				*policyOID,
553	const char					*policyString,		/* optional */
554	uint32						policyStringLen,
555	SecTrustSettingsKeyUsage	keyUsage,			/* optional */
556	CFArrayRef					*certArray)			/* RETURNED */
557{
558	BEGIN_RCSAPI
559
560	/* ensure a NULL_terminated string */
561	auto_array<char> polStr;
562	if(policyString != NULL) {
563		polStr.allocate(policyStringLen + 1);
564		memmove(polStr.get(), policyString, policyStringLen);
565		if(policyString[policyStringLen - 1] != '\0') {
566			(polStr.get())[policyStringLen] = '\0';
567		}
568	}
569
570	return tsCopyCertsCommon(policyOID, polStr.get(), keyUsage,
571		false,				/* !onlyRoots */
572		true, true, true,	/* all domains */
573		certArray);
574
575	END_RCSAPI
576}
577
578/*
579 * Obtain unrestricted root certs fromt eh specified domain(s).
580 * Only returns roots with no usage constraints.
581 * Caller must CFRelease the returned CFArrayRef.
582 */
583OSStatus SecTrustSettingsCopyUnrestrictedRoots(
584	Boolean					user,
585	Boolean					admin,
586	Boolean					system,
587	CFArrayRef				*certArray)		/* RETURNED */
588{
589	BEGIN_RCSAPI
590
591	return tsCopyCertsCommon(NULL, NULL, NULL,	/* no constraints */
592		true,				/* onlyRoots */
593		user, admin, system,
594		certArray);
595
596	END_RCSAPI
597}
598
599static const char hexChars[16] = {
600	'0', '1', '2', '3', '4', '5', '6', '7',
601	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
602};
603
604/*
605 * Obtain a string representing a cert's SHA1 digest. This string is
606 * the key used to look up per-cert trust settings in a TrustSettings record.
607 */
608CFStringRef SecTrustSettingsCertHashStrFromCert(
609	SecCertificateRef certRef)
610{
611	if(certRef == NULL) {
612		return NULL;
613	}
614
615	if(certRef == kSecTrustSettingsDefaultRootCertSetting) {
616		/* use this string instead of the cert hash as the dictionary key */
617		trustSettingsDbg("SecTrustSettingsCertHashStrFromCert: DefaultSetting");
618		return kSecTrustRecordDefaultRootCert;
619	}
620
621	CSSM_DATA certData;
622	OSStatus ortn = SecCertificateGetData(certRef, &certData);
623	if(ortn) {
624		return NULL;
625	}
626	return SecTrustSettingsCertHashStrFromData(certData.Data, certData.Length);
627}
628
629CFStringRef SecTrustSettingsCertHashStrFromData(
630	const void *cert,
631	size_t certLen)
632{
633	unsigned char digest[CC_SHA1_DIGEST_LENGTH];
634	char asciiDigest[(2 * CC_SHA1_DIGEST_LENGTH) + 1];
635	unsigned dex;
636	char *outp = asciiDigest;
637	unsigned char *inp = digest;
638
639	if(cert == NULL) {
640		return NULL;
641	}
642
643	CC_SHA1(cert, (CC_LONG)certLen, digest);
644
645	for(dex=0; dex<CC_SHA1_DIGEST_LENGTH; dex++) {
646		unsigned c = *inp++;
647		outp[1] = hexChars[c & 0xf];
648		c >>= 4;
649		outp[0] = hexChars[c];
650		outp += 2;
651	}
652	*outp = 0;
653	return CFStringCreateWithCString(NULL, asciiDigest, kCFStringEncodingASCII);
654}
655
656/*
657 * Add a cert's TrustSettings to a non-persistent TrustSettings record.
658 * No locking or cache flushing here; it's all local to the TrustSettings
659 * we construct here.
660 */
661OSStatus SecTrustSettingsSetTrustSettingsExternal(
662	CFDataRef			settingsIn,					/* optional */
663	SecCertificateRef	certRef,					/* optional */
664	CFTypeRef			trustSettingsDictOrArray,	/* optional */
665	CFDataRef			*settingsOut)				/* RETURNED */
666{
667	BEGIN_RCSAPI
668
669	TS_REQUIRED(settingsOut)
670
671	OSStatus result;
672	TrustSettings* ts;
673
674	result = TrustSettings::CreateTrustSettings(kSecTrustSettingsDomainMemory, settingsIn, ts);
675	if (result != errSecSuccess) {
676		return result;
677	}
678
679	auto_ptr<TrustSettings>_(ts);
680
681	if(certRef != NULL) {
682		ts->setTrustSettings(certRef, trustSettingsDictOrArray);
683	}
684	*settingsOut = ts->createExternal();
685	return errSecSuccess;
686
687	END_RCSAPI
688}
689
690#pragma mark --- API functions ---
691
692OSStatus SecTrustSettingsCopyTrustSettings(
693	SecCertificateRef certRef,
694	SecTrustSettingsDomain domain,
695	CFArrayRef *trustSettings)				/* RETURNED */
696{
697	TS_REQUIRED(trustSettings)
698
699	OSStatus result = tsCopyTrustSettings(certRef, domain, trustSettings, NULL);
700	if (result == errSecSuccess && *trustSettings == NULL) {
701		result = errSecItemNotFound; /* documented result if no trust settings exist */
702	}
703	return result;
704}
705
706OSStatus SecTrustSettingsCopyModificationDate(
707	SecCertificateRef		certRef,
708	SecTrustSettingsDomain	domain,
709	CFDateRef				*modificationDate)	/* RETURNED */
710{
711	TS_REQUIRED(modificationDate)
712
713	OSStatus result = tsCopyTrustSettings(certRef, domain, NULL, modificationDate);
714	if (result == errSecSuccess && *modificationDate == NULL) {
715		result = errSecItemNotFound; /* documented result if no trust settings exist */
716	}
717	return result;
718}
719
720/* works with existing and with new cert */
721OSStatus SecTrustSettingsSetTrustSettings(
722	SecCertificateRef certRef,
723	SecTrustSettingsDomain domain,
724	CFTypeRef trustSettingsDictOrArray)
725{
726	BEGIN_RCSAPI
727
728	TS_REQUIRED(certRef)
729
730	if(domain == kSecTrustSettingsDomainSystem) {
731		return errSecDataNotModifiable;
732	}
733
734	OSStatus result;
735	TrustSettings* ts;
736
737	result = TrustSettings::CreateTrustSettings(domain, CREATE_YES, TRIM_NO, ts);
738	if (result != errSecSuccess) {
739		return result;
740	}
741
742	auto_ptr<TrustSettings>_(ts);
743
744	ts->setTrustSettings(certRef, trustSettingsDictOrArray);
745	ts->flushToDisk();
746	tsTrustSettingsChanged();
747	return errSecSuccess;
748
749	END_RCSAPI
750}
751
752OSStatus SecTrustSettingsRemoveTrustSettings(
753	SecCertificateRef cert,
754	SecTrustSettingsDomain domain)
755{
756	BEGIN_RCSAPI
757
758	TS_REQUIRED(cert)
759
760	if(domain == kSecTrustSettingsDomainSystem) {
761		return errSecDataNotModifiable;
762	}
763
764	OSStatus result;
765	TrustSettings* ts;
766
767	result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
768	if (result != errSecSuccess) {
769		return result;
770	}
771
772	auto_ptr<TrustSettings>_(ts);
773
774	/* deleteTrustSettings throws if record not found */
775	trustSettingsDbg("SecTrustSettingsRemoveTrustSettings: deleting from domain %d",
776		(int)domain);
777	ts->deleteTrustSettings(cert);
778	ts->flushToDisk();
779	tsTrustSettingsChanged();
780	return errSecSuccess;
781
782	END_RCSAPI
783}
784
785/* get all certs listed in specified domain */
786OSStatus SecTrustSettingsCopyCertificates(
787	SecTrustSettingsDomain	domain,
788	CFArrayRef				*certArray)
789{
790	BEGIN_RCSAPI
791
792	TS_REQUIRED(certArray)
793
794	OSStatus result;
795	TrustSettings* ts;
796
797	result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
798	if (result != errSecSuccess) {
799		return result;
800	}
801
802	auto_ptr<TrustSettings>_(ts);
803
804	CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
805
806	/*
807 	 * Keychains to search: user's search list, System.keychain, system root store,
808	 * system intermdiates, as appropriate
809	 */
810	StorageManager::KeychainList keychains;
811	Keychain adminKc;
812	Keychain sysCertKc;
813	Keychain sysRootKc;
814	switch(domain) {
815		case kSecTrustSettingsDomainUser:
816			/* user search list */
817			globals().storageManager.getSearchList(keychains);
818			/* drop thru to next case */
819		case kSecTrustSettingsDomainAdmin:
820			/* admin certs in system keychain */
821			adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false);
822			keychains.push_back(adminKc);
823			/* system-wide intermediate certs */
824			sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false);
825			keychains.push_back(sysCertKc);
826			/* drop thru to next case */
827		case kSecTrustSettingsDomainSystem:
828			/* and, for all cases, immutable system root store */
829			sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false);
830			keychains.push_back(sysRootKc);
831		default:
832			/* already validated when we created the TrustSettings */
833			break;
834	}
835	ts->findCerts(keychains, outArray);
836	if(CFArrayGetCount(outArray) == 0) {
837		CFRelease(outArray);
838		return errSecNoTrustSettings;
839	}
840	*certArray = outArray;
841	END_RCSAPI
842}
843
844/*
845 * Obtain an external, portable representation of the specified
846 * domain's TrustSettings. Caller must CFRelease the returned data.
847 */
848OSStatus SecTrustSettingsCreateExternalRepresentation(
849	SecTrustSettingsDomain	domain,
850	CFDataRef				*trustSettings)
851{
852	BEGIN_RCSAPI
853
854	TS_REQUIRED(trustSettings)
855
856	OSStatus result;
857	TrustSettings* ts;
858
859	result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
860	if (result != errSecSuccess) {
861		return result;
862	}
863
864	auto_ptr<TrustSettings>_(ts);
865
866	*trustSettings = ts->createExternal();
867	return errSecSuccess;
868
869	END_RCSAPI
870}
871
872/*
873 * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation,
874 * into the specified domain.
875 */
876OSStatus SecTrustSettingsImportExternalRepresentation(
877	SecTrustSettingsDomain	domain,
878	CFDataRef				trustSettings)		/* optional - NULL means empty settings */
879{
880	BEGIN_RCSAPI
881
882	if(domain == kSecTrustSettingsDomainSystem) {
883		return errSecDataNotModifiable;
884	}
885
886	OSStatus result;
887	TrustSettings* ts;
888
889	result = TrustSettings::CreateTrustSettings(domain, trustSettings, ts);
890	if (result != errSecSuccess) {
891		return result;
892	}
893
894	auto_ptr<TrustSettings>_(ts);
895
896	ts->flushToDisk();
897	tsTrustSettingsChanged();
898	return errSecSuccess;
899
900	END_RCSAPI
901}
902
903