]> git.saurik.com Git - apple/security.git/blame - Keychain/TrustStore.cpp
Security-163.tar.gz
[apple/security.git] / Keychain / TrustStore.cpp
CommitLineData
29654253
A
1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18//
19// TrustStore.h - Abstract interface to permanent user trust assignments
20//
21#include <Security/TrustStore.h>
22#include <Security/Globals.h>
23#include <Security/Certificate.h>
df0e469f 24#include <Security/KCCursor.h>
29654253
A
25#include <Security/SecCFTypes.h>
26#include <Security/schema.h>
27
28
29namespace Security {
30namespace KeychainCore {
31
32
33//
34// Make and break: trivial
35//
36TrustStore::TrustStore(CssmAllocator &alloc)
37 : allocator(alloc), mRootsValid(false), mRootBytes(allocator)
38{
39}
40
41TrustStore::~TrustStore()
42{ }
43
44
45//
46// Retrieve the trust setting for a (certificate, policy) pair.
47//
48SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy)
49{
50 if (Item item = findItem(cert, policy)) {
51 CssmDataContainer data;
52 item->getData(data);
53 if (data.length() != sizeof(TrustData))
54 MacOSError::throwMe(errSecInvalidTrustSetting);
55 TrustData &trust = *data.interpretedAs<TrustData>();
56 if (trust.version != UserTrustItem::currentVersion)
57 MacOSError::throwMe(errSecInvalidTrustSetting);
58 return trust.trust;
59 } else {
60 return kSecTrustResultUnspecified;
61 }
62}
63
64
65//
66// Set an individual trust element
67//
68void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust)
69{
70 TrustData trustData = { UserTrustItem::currentVersion, trust };
71 if (Item item = findItem(cert, policy)) {
72 // user has a trust setting in a keychain - modify that
df0e469f
A
73 if (trust == kSecTrustResultUnspecified)
74 item->keychain()->deleteItem(item);
75 else
76 item->modifyContent(NULL, sizeof(trustData), &trustData);
29654253
A
77 } else {
78 // no trust entry: make one
df0e469f
A
79 if (trust != kSecTrustResultUnspecified) {
80 Item item = new UserTrustItem(cert, policy, trustData);
81 if (Keychain location = cert->keychain())
82 location->add(item); // in the cert's keychain
83 else
84 Keychain::optional(NULL)->add(item); // in the default keychain
85 }
29654253
A
86 }
87}
88
89
90//
91// Search the user's configured keychains for a trust setting.
92// If found, return it (as a TrustItem). Otherwise, return NULL.
93// Note that this function throws if a "real" error is encountered.
94//
95Item TrustStore::findItem(Certificate *cert, Policy *policy)
96{
97 try {
98 SecKeychainAttribute attrs[2];
df0e469f
A
99 CssmAutoData certIndex(CssmAllocator::standard());
100 UserTrustItem::makeCertIndex(cert, certIndex);
29654253 101 attrs[0].tag = kSecTrustCertAttr;
df0e469f
A
102 attrs[0].length = certIndex.length();
103 attrs[0].data = certIndex.data();
29654253
A
104 const CssmOid &policyOid = policy->oid();
105 attrs[1].tag = kSecTrustPolicyAttr;
106 attrs[1].length = policyOid.length();
107 attrs[1].data = policyOid.data();
108 SecKeychainAttributeList attrList = { 2, attrs };
109 KCCursor cursor = globals().storageManager.createCursor(CSSM_DL_DB_RECORD_USER_TRUST, &attrList);
110 Item item;
111 if (cursor->next(item))
112 return item;
113 else
114 return NULL;
df0e469f 115 } catch (const CssmCommonError &error) {
29654253
A
116 if (error.cssmError() == CSSMERR_DL_INVALID_RECORDTYPE)
117 return NULL; // no trust schema, no records, no error
118 throw;
119 }
120}
121
122
123//
124// Return the root certificate list.
125// This list is cached.
126//
127CFArrayRef TrustStore::copyRootCertificates()
128{
129 if (!mRootsValid) {
130 loadRootCertificates();
131 mCFRoots = NULL;
132 }
133 if (!mCFRoots) {
134 uint32 count = mRoots.size();
df0e469f 135 secdebug("anchors", "building %ld CF-style anchor certificates", count);
29654253
A
136 vector<SecCertificateRef> roots(count);
137 for (uint32 n = 0; n < count; n++) {
df0e469f 138 SecPointer<Certificate> cert = new Certificate(mRoots[n],
29654253 139 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER);
df0e469f 140 roots[n] = cert->handle();
29654253
A
141 }
142 mCFRoots = CFArrayCreate(NULL, (const void **)&roots[0], count,
143 &kCFTypeArrayCallBacks);
144 for (uint32 n = 0; n < count; n++)
145 CFRelease(roots[n]); // undo CFArray's retain
146 }
147 CFRetain(mCFRoots);
148 return mCFRoots;
149}
150
151void TrustStore::getCssmRootCertificates(CertGroup &rootCerts)
152{
153 if (!mRootsValid)
154 loadRootCertificates();
155 rootCerts = CertGroup(CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, CSSM_CERTGROUP_DATA);
156 rootCerts.blobCerts() = &mRoots[0];
157 rootCerts.count() = mRoots.size();
158}
159
160void TrustStore::refreshRootCertificates()
161{
162 if (mRootsValid) {
df0e469f 163 secdebug("anchors", "clearing %ld cached anchor certificates", mRoots.size());
29654253
A
164
165 // throw out the CF version
166 if (mCFRoots) {
167 CFRelease(mCFRoots);
168 mCFRoots = NULL;
169 }
170
171 // release cert memory
172 mRootBytes.reset();
173 mRoots.clear();
174
175 // all pristine again
176 mRootsValid = false;
177 }
178}
179
180
181//
182// Load root (anchor) certificates from disk
183//
184void TrustStore::loadRootCertificates()
185{
186 using namespace CssmClient;
187 using namespace KeychainCore::Schema;
188
189 // release previous cached data (if any)
190 refreshRootCertificates();
191
192 static const char anchorLibrary[] = "/System/Library/Keychains/X509Anchors";
193
194 // open anchor database and formulate query (x509v3 certs)
df0e469f 195 secdebug("anchors", "Loading anchors from %s", anchorLibrary);
29654253
A
196 DL dl(gGuidAppleFileDL);
197 Db db(dl, anchorLibrary);
198 DbCursor search(db);
199 search->recordType(CSSM_DL_DB_RECORD_X509_CERTIFICATE);
200 search->conjunctive(CSSM_DB_OR);
201#if 0 // if we ever need to support v1/v2 certificates...
202 search->add(CSSM_DB_EQUAL, kX509CertificateCertType, UInt32(CSSM_CERT_X_509v1));
203 search->add(CSSM_DB_EQUAL, kX509CertificateCertType, UInt32(CSSM_CERT_X_509v2));
204 search->add(CSSM_DB_EQUAL, kX509CertificateCertType, UInt32(CSSM_CERT_X_509v3));
205#endif
206
207 // collect certificate data
208 typedef list<CssmDataContainer> ContainerList;
209 ContainerList::iterator last;
210 ContainerList certs;
211 for (;;) {
212 DbUniqueRecord id;
df0e469f 213 last = certs.insert(certs.end(), CssmDataContainer());
29654253
A
214 if (!search->next(NULL, &*last, id))
215 break;
216 }
217
218 // how many data bytes do we need?
219 size_t size = 0;
220 for (ContainerList::const_iterator it = certs.begin(); it != last; it++)
221 size += it->length();
222 mRootBytes.length(size);
223
224 // fill CssmData vector while copying data bytes together
225 mRoots.clear();
226 uint8 *base = mRootBytes.data<uint8>();
227 for (ContainerList::const_iterator it = certs.begin(); it != last; it++) {
228 memcpy(base, it->data(), it->length());
229 mRoots.push_back(CssmData(base, it->length()));
230 base += it->length();
231 }
df0e469f 232 secdebug("anchors", "%ld anchors loaded", mRoots.size());
29654253
A
233
234 mRootsValid = true; // ready to roll
235}
236
237
238} // end namespace KeychainCore
239} // end namespace Security