1/*
2 * Copyright (c) 2002-2004,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// TrustStore.h - Abstract interface to permanent user trust assignments
26//
27#include <security_keychain/TrustStore.h>
28#include <security_keychain/Globals.h>
29#include <security_keychain/Certificate.h>
30#include <security_keychain/KCCursor.h>
31#include <security_keychain/SecCFTypes.h>
32#include <security_cdsa_utilities/Schema.h>
33#include <security_keychain/SecTrustSettingsPriv.h>
34
35namespace Security {
36namespace KeychainCore {
37
38
39//
40// Make and break: trivial
41//
42TrustStore::TrustStore(Allocator &alloc)
43	: allocator(alloc), mRootsValid(false), mRootBytes(allocator), mMutex(Mutex::recursive)
44{
45}
46
47TrustStore::~TrustStore()
48{ }
49
50//
51// Retrieve the trust setting for a (certificate, policy) pair.
52//
53SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy,
54	StorageManager::KeychainList &keychainList)
55{
56	StLock<Mutex> _(mMutex);
57
58	if (Item item = findItem(cert, policy, keychainList)) {
59		// Make sure that the certificate is available in some keychain,
60		// to provide a basis for editing the trust setting that we're returning.
61		if (cert->keychain() == NULL) {
62			if (cert->findInKeychain(keychainList) == NULL) {
63				Keychain defaultKeychain = Keychain::optional(NULL);
64				if (Keychain location = item->keychain()) {
65					try {
66						cert->copyTo(location);	// add cert to the trust item's keychain
67					} catch (...) {
68						secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
69							cert, location->name());
70						try {
71							if (&*location != &*defaultKeychain)
72								cert->copyTo(defaultKeychain);	// try the default (if it's not the same)
73						} catch (...) {
74							// unable to add the certificate
75							secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
76								cert, defaultKeychain->name());
77						}
78					}
79				}
80			}
81		}
82		CssmDataContainer data;
83		item->getData(data);
84		if (data.length() != sizeof(TrustData))
85			MacOSError::throwMe(errSecInvalidTrustSetting);
86		TrustData &trust = *data.interpretedAs<TrustData>();
87		if (trust.version != UserTrustItem::currentVersion)
88			MacOSError::throwMe(errSecInvalidTrustSetting);
89		return trust.trust;
90	} else {
91		return kSecTrustResultUnspecified;
92	}
93}
94
95
96//
97// Set an individual trust element
98//
99void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust)
100{
101	StLock<Mutex> _(mMutex);
102
103	TrustData trustData = { UserTrustItem::currentVersion, trust };
104	Keychain defaultKeychain = Keychain::optional(NULL);
105	Keychain trustLocation = defaultKeychain;	// default keychain, unless trust entry found
106	StorageManager::KeychainList searchList;
107	globals().storageManager.getSearchList(searchList);
108
109	if (Item item = findItem(cert, policy, searchList)) {
110		// user has a trust setting in a keychain - modify that
111		trustLocation = item->keychain();
112		if (trust == kSecTrustResultUnspecified)
113			item->keychain()->deleteItem(item);
114		else
115			item->modifyContent(NULL, sizeof(trustData), &trustData);
116	} else {
117		// no trust entry: make one
118		if (trust != kSecTrustResultUnspecified) {
119			Item item = new UserTrustItem(cert, policy, trustData);
120			if (Keychain location = cert->keychain()) {
121				try {
122					location->add(item);				// try the cert's keychain first
123					trustLocation = location;
124				} catch (...) {
125					if (&*location != &*defaultKeychain)
126						defaultKeychain->add(item);		// try the default (if it's not the same)
127				}
128			} else {
129				defaultKeychain->add(item);				// raw cert - use default keychain
130			}
131		}
132	}
133
134	// Make sure that the certificate is available in some keychain,
135	// to provide a basis for editing the trust setting that we're assigning.
136	if (cert->keychain() == NULL) {
137		if (cert->findInKeychain(searchList) == NULL) {
138			try {
139				cert->copyTo(trustLocation);	// add cert to the trust item's keychain
140			} catch (...) {
141				secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
142					cert, trustLocation->name());
143				try {
144					if (&*trustLocation != &*defaultKeychain)
145						cert->copyTo(defaultKeychain);	// try the default (if it's not the same)
146				} catch (...) {
147					// unable to add the certificate
148					secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
149						cert, defaultKeychain->name());
150				}
151			}
152		}
153	}
154}
155
156
157//
158// Search the user's configured keychains for a trust setting.
159// If found, return it (as a TrustItem). Otherwise, return NULL.
160// Note that this function throws if a "real" error is encountered.
161//
162Item TrustStore::findItem(Certificate *cert, Policy *policy,
163	StorageManager::KeychainList &keychainList)
164{
165	// As of OS X 10.5, user trust records are no longer stored in keychains.
166	// SecTrustSetUserTrust was replaced with SecTrustSettingsSetTrustSettings,
167	// which stores per-user trust in a separate root-owned file. This method,
168	// however, would continue to find old trust records created prior to 10.5.
169	// Since those are increasingly unlikely to exist (and cannot be edited),
170	// we no longer need or want to look for them anymore.
171	return ((ItemImpl*)NULL);
172
173	StLock<Mutex> _(mMutex);
174
175	try {
176		SecKeychainAttribute attrs[2];
177		CssmAutoData certIndex(Allocator::standard());
178		UserTrustItem::makeCertIndex(cert, certIndex);
179		attrs[0].tag = kSecTrustCertAttr;
180		attrs[0].length = (UInt32)certIndex.length();
181		attrs[0].data = certIndex.data();
182		const CssmOid &policyOid = policy->oid();
183		attrs[1].tag = kSecTrustPolicyAttr;
184		attrs[1].length = (UInt32)policyOid.length();
185		attrs[1].data = policyOid.data();
186		SecKeychainAttributeList attrList = { 2, attrs };
187		KCCursor cursor(keychainList, CSSM_DL_DB_RECORD_USER_TRUST, &attrList);
188		Item item;
189		if (cursor->next(item))
190			return item;
191	}
192	catch (const CommonError &error) {}
193
194	return ((ItemImpl*)NULL);	// no trust schema, no records, no error
195}
196
197void TrustStore::getCssmRootCertificates(CertGroup &rootCerts)
198{
199	StLock<Mutex> _(mMutex);
200
201	if (!mRootsValid)
202		loadRootCertificates();
203	rootCerts = CertGroup(CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, CSSM_CERTGROUP_DATA);
204	rootCerts.blobCerts() = &mRoots[0];
205	rootCerts.count() = (uint32)mRoots.size();
206}
207
208//
209// Load root (anchor) certificates from disk
210//
211void TrustStore::loadRootCertificates()
212{
213	StLock<Mutex> _(mMutex);
214
215	CFRef<CFArrayRef> anchors;
216	OSStatus ortn;
217
218	/*
219	 * Get the current set of all positively trusted anchors.
220	 */
221	ortn = SecTrustSettingsCopyUnrestrictedRoots(
222		true, true, true,		/* all domains */
223		anchors.take());
224	if(ortn) {
225		MacOSError::throwMe(ortn);
226	}
227
228	// how many data bytes do we need?
229	size_t size = 0;
230	CFIndex numCerts = CFArrayGetCount(anchors);
231	CSSM_RETURN crtn;
232	for(CFIndex dex=0; dex<numCerts; dex++) {
233		SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
234		CSSM_DATA certData;
235		crtn = SecCertificateGetData(certRef, &certData);
236		if(crtn) {
237			CssmError::throwMe(crtn);
238		}
239		size += certData.Length;
240	}
241	mRootBytes.length(size);
242
243	// fill CssmData vector while copying data bytes together
244	mRoots.clear();
245	uint8 *base = mRootBytes.data<uint8>();
246	for(CFIndex dex=0; dex<numCerts; dex++) {
247		SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
248		CSSM_DATA certData;
249		SecCertificateGetData(certRef, &certData);
250		memcpy(base, certData.Data, certData.Length);
251		mRoots.push_back(CssmData(base, certData.Length));
252		base += certData.Length;
253	}
254
255	secdebug("anchors", "%ld anchors loaded", (long)numCerts);
256
257	mRootsValid = true;			// ready to roll
258}
259
260} // end namespace KeychainCore
261} // end namespace Security
262