]> git.saurik.com Git - apple/security.git/blame - Keychain/TrustStore.cpp
Security-54.1.9.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>
24#include <Security/SecCFTypes.h>
25#include <Security/schema.h>
26
27
28namespace Security {
29namespace KeychainCore {
30
31
32//
33// Make and break: trivial
34//
35TrustStore::TrustStore(CssmAllocator &alloc)
36 : allocator(alloc), mRootsValid(false), mRootBytes(allocator)
37{
38}
39
40TrustStore::~TrustStore()
41{ }
42
43
44//
45// Retrieve the trust setting for a (certificate, policy) pair.
46//
47SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy)
48{
49 if (Item item = findItem(cert, policy)) {
50 CssmDataContainer data;
51 item->getData(data);
52 if (data.length() != sizeof(TrustData))
53 MacOSError::throwMe(errSecInvalidTrustSetting);
54 TrustData &trust = *data.interpretedAs<TrustData>();
55 if (trust.version != UserTrustItem::currentVersion)
56 MacOSError::throwMe(errSecInvalidTrustSetting);
57 return trust.trust;
58 } else {
59 return kSecTrustResultUnspecified;
60 }
61}
62
63
64//
65// Set an individual trust element
66//
67void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust)
68{
69 TrustData trustData = { UserTrustItem::currentVersion, trust };
70 if (Item item = findItem(cert, policy)) {
71 // user has a trust setting in a keychain - modify that
72 item->modifyContent(NULL, sizeof(trustData), &trustData);
73 } else {
74 // no trust entry: make one
75 Item item = new UserTrustItem(cert, policy, trustData);
76 if (Keychain location = cert->keychain())
77 location->add(item); // in the cert's keychain
78 else
79 Keychain::optional(NULL)->add(item); // in the default keychain
80 }
81}
82
83
84//
85// Search the user's configured keychains for a trust setting.
86// If found, return it (as a TrustItem). Otherwise, return NULL.
87// Note that this function throws if a "real" error is encountered.
88//
89Item TrustStore::findItem(Certificate *cert, Policy *policy)
90{
91 try {
92 SecKeychainAttribute attrs[2];
93 const CssmData &data = cert->data();
94 attrs[0].tag = kSecTrustCertAttr;
95 attrs[0].length = data.length();
96 attrs[0].data = data.data();
97 const CssmOid &policyOid = policy->oid();
98 attrs[1].tag = kSecTrustPolicyAttr;
99 attrs[1].length = policyOid.length();
100 attrs[1].data = policyOid.data();
101 SecKeychainAttributeList attrList = { 2, attrs };
102 KCCursor cursor = globals().storageManager.createCursor(CSSM_DL_DB_RECORD_USER_TRUST, &attrList);
103 Item item;
104 if (cursor->next(item))
105 return item;
106 else
107 return NULL;
108 } catch (const CssmError &error) {
109 if (error.cssmError() == CSSMERR_DL_INVALID_RECORDTYPE)
110 return NULL; // no trust schema, no records, no error
111 throw;
112 }
113}
114
115
116//
117// Return the root certificate list.
118// This list is cached.
119//
120CFArrayRef TrustStore::copyRootCertificates()
121{
122 if (!mRootsValid) {
123 loadRootCertificates();
124 mCFRoots = NULL;
125 }
126 if (!mCFRoots) {
127 uint32 count = mRoots.size();
128 debug("anchors", "building %ld CF-style anchor certificates", count);
129 vector<SecCertificateRef> roots(count);
130 for (uint32 n = 0; n < count; n++) {
131 RefPointer<Certificate> cert = new Certificate(mRoots[n],
132 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER);
133 roots[n] = gTypes().certificate.handle(*cert);
134 }
135 mCFRoots = CFArrayCreate(NULL, (const void **)&roots[0], count,
136 &kCFTypeArrayCallBacks);
137 for (uint32 n = 0; n < count; n++)
138 CFRelease(roots[n]); // undo CFArray's retain
139 }
140 CFRetain(mCFRoots);
141 return mCFRoots;
142}
143
144void TrustStore::getCssmRootCertificates(CertGroup &rootCerts)
145{
146 if (!mRootsValid)
147 loadRootCertificates();
148 rootCerts = CertGroup(CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, CSSM_CERTGROUP_DATA);
149 rootCerts.blobCerts() = &mRoots[0];
150 rootCerts.count() = mRoots.size();
151}
152
153void TrustStore::refreshRootCertificates()
154{
155 if (mRootsValid) {
156 debug("anchors", "clearing %ld cached anchor certificates", mRoots.size());
157
158 // throw out the CF version
159 if (mCFRoots) {
160 CFRelease(mCFRoots);
161 mCFRoots = NULL;
162 }
163
164 // release cert memory
165 mRootBytes.reset();
166 mRoots.clear();
167
168 // all pristine again
169 mRootsValid = false;
170 }
171}
172
173
174//
175// Load root (anchor) certificates from disk
176//
177void TrustStore::loadRootCertificates()
178{
179 using namespace CssmClient;
180 using namespace KeychainCore::Schema;
181
182 // release previous cached data (if any)
183 refreshRootCertificates();
184
185 static const char anchorLibrary[] = "/System/Library/Keychains/X509Anchors";
186
187 // open anchor database and formulate query (x509v3 certs)
188 debug("anchors", "Loading anchors from %s", anchorLibrary);
189 DL dl(gGuidAppleFileDL);
190 Db db(dl, anchorLibrary);
191 DbCursor search(db);
192 search->recordType(CSSM_DL_DB_RECORD_X509_CERTIFICATE);
193 search->conjunctive(CSSM_DB_OR);
194#if 0 // if we ever need to support v1/v2 certificates...
195 search->add(CSSM_DB_EQUAL, kX509CertificateCertType, UInt32(CSSM_CERT_X_509v1));
196 search->add(CSSM_DB_EQUAL, kX509CertificateCertType, UInt32(CSSM_CERT_X_509v2));
197 search->add(CSSM_DB_EQUAL, kX509CertificateCertType, UInt32(CSSM_CERT_X_509v3));
198#endif
199
200 // collect certificate data
201 typedef list<CssmDataContainer> ContainerList;
202 ContainerList::iterator last;
203 ContainerList certs;
204 for (;;) {
205 DbUniqueRecord id;
206 last = certs.insert(certs.end());
207 if (!search->next(NULL, &*last, id))
208 break;
209 }
210
211 // how many data bytes do we need?
212 size_t size = 0;
213 for (ContainerList::const_iterator it = certs.begin(); it != last; it++)
214 size += it->length();
215 mRootBytes.length(size);
216
217 // fill CssmData vector while copying data bytes together
218 mRoots.clear();
219 uint8 *base = mRootBytes.data<uint8>();
220 for (ContainerList::const_iterator it = certs.begin(); it != last; it++) {
221 memcpy(base, it->data(), it->length());
222 mRoots.push_back(CssmData(base, it->length()));
223 base += it->length();
224 }
225 debug("anchors", "%ld anchors loaded", mRoots.size());
226
227 mRootsValid = true; // ready to roll
228}
229
230
231} // end namespace KeychainCore
232} // end namespace Security