2 * Copyright (c) 2002-2004,2011-2014 Apple 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 // 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
);
173 StLock
<Mutex
> _(mMutex
);
176 SecKeychainAttribute attrs
[2];
177 CssmAutoData
certIndex(Allocator::standard());
178 UserTrustItem::makeCertIndex(cert
, certIndex
);
179 attrs
[0].tag
= kSecTrustCertAttr
;
180 attrs
[0].length
= (UInt32
)certIndex
.length();
181 attrs
[0].data
= certIndex
.data();
182 const CssmOid
&policyOid
= policy
->oid();
183 attrs
[1].tag
= kSecTrustPolicyAttr
;
184 attrs
[1].length
= (UInt32
)policyOid
.length();
185 attrs
[1].data
= policyOid
.data();
186 SecKeychainAttributeList attrList
= { 2, attrs
};
187 KCCursor
cursor(keychainList
, CSSM_DL_DB_RECORD_USER_TRUST
, &attrList
);
189 if (cursor
->next(item
))
192 catch (const CommonError
&error
) {}
194 return ((ItemImpl
*)NULL
); // no trust schema, no records, no error
197 void TrustStore::getCssmRootCertificates(CertGroup
&rootCerts
)
199 StLock
<Mutex
> _(mMutex
);
202 loadRootCertificates();
203 rootCerts
= CertGroup(CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
, CSSM_CERTGROUP_DATA
);
204 rootCerts
.blobCerts() = &mRoots
[0];
205 rootCerts
.count() = (uint32
)mRoots
.size();
209 // Load root (anchor) certificates from disk
211 void TrustStore::loadRootCertificates()
213 StLock
<Mutex
> _(mMutex
);
215 CFRef
<CFArrayRef
> anchors
;
219 * Get the current set of all positively trusted anchors.
221 ortn
= SecTrustSettingsCopyUnrestrictedRoots(
222 true, true, true, /* all domains */
225 MacOSError::throwMe(ortn
);
228 // how many data bytes do we need?
230 CFIndex numCerts
= CFArrayGetCount(anchors
);
232 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
233 SecCertificateRef certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(anchors
, dex
);
235 crtn
= SecCertificateGetData(certRef
, &certData
);
237 CssmError::throwMe(crtn
);
239 size
+= certData
.Length
;
241 mRootBytes
.length(size
);
243 // fill CssmData vector while copying data bytes together
245 uint8
*base
= mRootBytes
.data
<uint8
>();
246 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
247 SecCertificateRef certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(anchors
, dex
);
249 SecCertificateGetData(certRef
, &certData
);
250 memcpy(base
, certData
.Data
, certData
.Length
);
251 mRoots
.push_back(CssmData(base
, certData
.Length
));
252 base
+= certData
.Length
;
255 secdebug("anchors", "%ld anchors loaded", (long)numCerts
);
257 mRootsValid
= true; // ready to roll
260 } // end namespace KeychainCore
261 } // end namespace Security