2 * Copyright (c) 2002-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // TrustStore.h - Abstract interface to permanent user trust assignments
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>
36 namespace KeychainCore
{
40 // Make and break: trivial
42 TrustStore::TrustStore(Allocator
&alloc
)
43 : allocator(alloc
), mRootsValid(false), mRootBytes(allocator
), mMutex(Mutex::recursive
)
47 TrustStore::~TrustStore()
51 // Retrieve the trust setting for a (certificate, policy) pair.
53 SecTrustUserSetting
TrustStore::find(Certificate
*cert
, Policy
*policy
,
54 StorageManager::KeychainList
&keychainList
)
56 StLock
<Mutex
> _(mMutex
);
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()) {
66 cert
->copyTo(location
); // add cert to the trust item's keychain
68 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
69 cert
, location
->name());
71 if (&*location
!= &*defaultKeychain
)
72 cert
->copyTo(defaultKeychain
); // try the default (if it's not the same)
74 // unable to add the certificate
75 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
76 cert
, defaultKeychain
->name());
82 CssmDataContainer 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
);
91 return kSecTrustResultUnspecified
;
97 // Set an individual trust element
99 void TrustStore::assign(Certificate
*cert
, Policy
*policy
, SecTrustUserSetting trust
)
101 StLock
<Mutex
> _(mMutex
);
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
);
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
);
115 item
->modifyContent(NULL
, sizeof(trustData
), &trustData
);
117 // no trust entry: make one
118 if (trust
!= kSecTrustResultUnspecified
) {
119 Item item
= new UserTrustItem(cert
, policy
, trustData
);
120 if (Keychain location
= cert
->keychain()) {
122 location
->add(item
); // try the cert's keychain first
123 trustLocation
= location
;
125 if (&*location
!= &*defaultKeychain
)
126 defaultKeychain
->add(item
); // try the default (if it's not the same)
129 defaultKeychain
->add(item
); // raw cert - use default keychain
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
) {
139 cert
->copyTo(trustLocation
); // add cert to the trust item's keychain
141 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
142 cert
, trustLocation
->name());
144 if (&*trustLocation
!= &*defaultKeychain
)
145 cert
->copyTo(defaultKeychain
); // try the default (if it's not the same)
147 // unable to add the certificate
148 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
149 cert
, defaultKeychain
->name());
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.
162 Item
TrustStore::findItem(Certificate
*cert
, Policy
*policy
,
163 StorageManager::KeychainList
&keychainList
)
165 StLock
<Mutex
> _(mMutex
);
168 SecKeychainAttribute attrs
[2];
169 CssmAutoData
certIndex(Allocator::standard());
170 UserTrustItem::makeCertIndex(cert
, certIndex
);
171 attrs
[0].tag
= kSecTrustCertAttr
;
172 attrs
[0].length
= certIndex
.length();
173 attrs
[0].data
= certIndex
.data();
174 const CssmOid
&policyOid
= policy
->oid();
175 attrs
[1].tag
= kSecTrustPolicyAttr
;
176 attrs
[1].length
= policyOid
.length();
177 attrs
[1].data
= policyOid
.data();
178 SecKeychainAttributeList attrList
= { 2, attrs
};
179 KCCursor
cursor(keychainList
, CSSM_DL_DB_RECORD_USER_TRUST
, &attrList
);
181 if (cursor
->next(item
))
185 } catch (const CommonError
&error
) {
186 return NULL
; // no trust schema, no records, no error
190 void TrustStore::getCssmRootCertificates(CertGroup
&rootCerts
)
192 StLock
<Mutex
> _(mMutex
);
195 loadRootCertificates();
196 rootCerts
= CertGroup(CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
, CSSM_CERTGROUP_DATA
);
197 rootCerts
.blobCerts() = &mRoots
[0];
198 rootCerts
.count() = mRoots
.size();
202 // Load root (anchor) certificates from disk
204 void TrustStore::loadRootCertificates()
206 StLock
<Mutex
> _(mMutex
);
208 CFRef
<CFArrayRef
> anchors
;
212 * Get the current set of all positively trusted anchors.
214 ortn
= SecTrustSettingsCopyUnrestrictedRoots(
215 true, true, true, /* all domains */
218 MacOSError::throwMe(ortn
);
221 // how many data bytes do we need?
223 CFIndex numCerts
= CFArrayGetCount(anchors
);
225 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
226 SecCertificateRef certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(anchors
, dex
);
228 crtn
= SecCertificateGetData(certRef
, &certData
);
230 CssmError::throwMe(crtn
);
232 size
+= certData
.Length
;
234 mRootBytes
.length(size
);
236 // fill CssmData vector while copying data bytes together
238 uint8
*base
= mRootBytes
.data
<uint8
>();
239 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
240 SecCertificateRef certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(anchors
, dex
);
242 SecCertificateGetData(certRef
, &certData
);
243 memcpy(base
, certData
.Data
, certData
.Length
);
244 mRoots
.push_back(CssmData(base
, certData
.Length
));
245 base
+= certData
.Length
;
248 secdebug("anchors", "%ld anchors loaded", (long)numCerts
);
250 mRootsValid
= true; // ready to roll
253 } // end namespace KeychainCore
254 } // end namespace Security