]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/TrustStore.cpp
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / TrustStore.cpp
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
35 namespace Security {
36 namespace KeychainCore {
37
38
39 //
40 // Make and break: trivial
41 //
42 TrustStore::TrustStore(Allocator &alloc)
43 : allocator(alloc), mRootsValid(false), mRootBytes(allocator), mMutex(Mutex::recursive)
44 {
45 }
46
47 TrustStore::~TrustStore()
48 { }
49
50 //
51 // Retrieve the trust setting for a (certificate, policy) pair.
52 //
53 SecTrustUserSetting 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 secinfo("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 secinfo("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 //
99 void 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 secinfo("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 secinfo("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 //
162 Item 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 #if 0
174 StLock<Mutex> _(mMutex);
175
176 try {
177 SecKeychainAttribute attrs[2];
178 CssmAutoData certIndex(Allocator::standard());
179 UserTrustItem::makeCertIndex(cert, certIndex);
180 attrs[0].tag = kSecTrustCertAttr;
181 attrs[0].length = (UInt32)certIndex.length();
182 attrs[0].data = certIndex.data();
183 const CssmOid &policyOid = policy->oid();
184 attrs[1].tag = kSecTrustPolicyAttr;
185 attrs[1].length = (UInt32)policyOid.length();
186 attrs[1].data = policyOid.data();
187 SecKeychainAttributeList attrList = { 2, attrs };
188 KCCursor cursor(keychainList, CSSM_DL_DB_RECORD_USER_TRUST, &attrList);
189 Item item;
190 if (cursor->next(item))
191 return item;
192 }
193 catch (const CommonError &error) {}
194
195 return ((ItemImpl*)NULL); // no trust schema, no records, no error
196 #endif
197 }
198
199 void TrustStore::getCssmRootCertificates(CertGroup &rootCerts)
200 {
201 StLock<Mutex> _(mMutex);
202
203 if (!mRootsValid)
204 loadRootCertificates();
205 rootCerts = CertGroup(CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, CSSM_CERTGROUP_DATA);
206 rootCerts.blobCerts() = &mRoots[0];
207 rootCerts.count() = (uint32)mRoots.size();
208 }
209
210 //
211 // Load root (anchor) certificates from disk
212 //
213 void TrustStore::loadRootCertificates()
214 {
215 StLock<Mutex> _(mMutex);
216
217 CFRef<CFArrayRef> anchors;
218 OSStatus ortn;
219
220 /*
221 * Get the current set of all positively trusted anchors.
222 */
223 ortn = SecTrustSettingsCopyUnrestrictedRoots(
224 true, true, true, /* all domains */
225 anchors.take());
226 if(ortn) {
227 MacOSError::throwMe(ortn);
228 }
229
230 // how many data bytes do we need?
231 size_t size = 0;
232 CFIndex numCerts = CFArrayGetCount(anchors);
233 CSSM_RETURN crtn;
234 for(CFIndex dex=0; dex<numCerts; dex++) {
235 SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
236 CSSM_DATA certData;
237 crtn = SecCertificateGetData(certRef, &certData);
238 if(crtn) {
239 CssmError::throwMe(crtn);
240 }
241 size += certData.Length;
242 }
243 mRootBytes.length(size);
244
245 // fill CssmData vector while copying data bytes together
246 mRoots.clear();
247 uint8 *base = mRootBytes.data<uint8>();
248 for(CFIndex dex=0; dex<numCerts; dex++) {
249 SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
250 CSSM_DATA certData;
251 SecCertificateGetData(certRef, &certData);
252 memcpy(base, certData.Data, certData.Length);
253 mRoots.push_back(CssmData(base, certData.Length));
254 base += certData.Length;
255 }
256
257 secinfo("anchors", "%ld anchors loaded", (long)numCerts);
258
259 mRootsValid = true; // ready to roll
260 }
261
262 } // end namespace KeychainCore
263 } // end namespace Security