2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
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
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.
19 // TrustStore.h - Abstract interface to permanent user trust assignments
21 #include <Security/TrustStore.h>
22 #include <Security/Globals.h>
23 #include <Security/Certificate.h>
24 #include <Security/KCCursor.h>
25 #include <Security/SecCFTypes.h>
26 #include <Security/schema.h>
30 namespace KeychainCore
{
34 // Make and break: trivial
36 TrustStore::TrustStore(CssmAllocator
&alloc
)
37 : allocator(alloc
), mRootsValid(false), mRootBytes(allocator
)
41 TrustStore::~TrustStore()
46 // Retrieve the trust setting for a (certificate, policy) pair.
48 SecTrustUserSetting
TrustStore::find(Certificate
*cert
, Policy
*policy
)
50 if (Item item
= findItem(cert
, policy
)) {
51 CssmDataContainer 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
);
60 return kSecTrustResultUnspecified
;
66 // Set an individual trust element
68 void TrustStore::assign(Certificate
*cert
, Policy
*policy
, SecTrustUserSetting trust
)
70 TrustData trustData
= { UserTrustItem::currentVersion
, trust
};
71 if (Item item
= findItem(cert
, policy
)) {
72 // user has a trust setting in a keychain - modify that
73 if (trust
== kSecTrustResultUnspecified
)
74 item
->keychain()->deleteItem(item
);
76 item
->modifyContent(NULL
, sizeof(trustData
), &trustData
);
78 // no trust entry: make one
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
84 Keychain::optional(NULL
)->add(item
); // in the default keychain
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.
95 Item
TrustStore::findItem(Certificate
*cert
, Policy
*policy
)
98 SecKeychainAttribute attrs
[2];
99 CssmAutoData
certIndex(CssmAllocator::standard());
100 UserTrustItem::makeCertIndex(cert
, certIndex
);
101 attrs
[0].tag
= kSecTrustCertAttr
;
102 attrs
[0].length
= certIndex
.length();
103 attrs
[0].data
= certIndex
.data();
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
);
111 if (cursor
->next(item
))
115 } catch (const CssmCommonError
&error
) {
116 if (error
.cssmError() == CSSMERR_DL_INVALID_RECORDTYPE
)
117 return NULL
; // no trust schema, no records, no error
124 // Return the root certificate list.
125 // This list is cached.
127 CFArrayRef
TrustStore::copyRootCertificates()
130 loadRootCertificates();
134 uint32 count
= mRoots
.size();
135 secdebug("anchors", "building %ld CF-style anchor certificates", count
);
136 vector
<SecCertificateRef
> roots(count
);
137 for (uint32 n
= 0; n
< count
; n
++) {
138 SecPointer
<Certificate
> cert
= new Certificate(mRoots
[n
],
139 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
);
140 roots
[n
] = cert
->handle();
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
151 void TrustStore::getCssmRootCertificates(CertGroup
&rootCerts
)
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();
160 void TrustStore::refreshRootCertificates()
163 secdebug("anchors", "clearing %ld cached anchor certificates", mRoots
.size());
165 // throw out the CF version
171 // release cert memory
175 // all pristine again
182 // Load root (anchor) certificates from disk
184 void TrustStore::loadRootCertificates()
186 using namespace CssmClient
;
187 using namespace KeychainCore::Schema
;
189 // release previous cached data (if any)
190 refreshRootCertificates();
192 static const char anchorLibrary
[] = "/System/Library/Keychains/X509Anchors";
194 // open anchor database and formulate query (x509v3 certs)
195 secdebug("anchors", "Loading anchors from %s", anchorLibrary
);
196 DL
dl(gGuidAppleFileDL
);
197 Db
db(dl
, anchorLibrary
);
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
));
207 // collect certificate data
208 typedef list
<CssmDataContainer
> ContainerList
;
209 ContainerList::iterator last
;
213 last
= certs
.insert(certs
.end(), CssmDataContainer());
214 if (!search
->next(NULL
, &*last
, id
))
218 // how many data bytes do we need?
220 for (ContainerList::const_iterator it
= certs
.begin(); it
!= last
; it
++)
221 size
+= it
->length();
222 mRootBytes
.length(size
);
224 // fill CssmData vector while copying data bytes together
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();
232 secdebug("anchors", "%ld anchors loaded", mRoots
.size());
234 mRootsValid
= true; // ready to roll
238 } // end namespace KeychainCore
239 } // end namespace Security