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/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 secinfo("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 secinfo("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 secinfo("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 secinfo("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
);
174 StLock
<Mutex
> _(mMutex
);
177 SecKeychainAttribute attrs
[2];
178 CssmAutoData
certIndex(Allocator::standard());
179 UserTrustItem::makeCertIndex(cert
, certIndex
);
180 attrs
[0].tag
= kSecTrustCertAttr
;
181 attrs
[0].length
= (UInt32
)certIndex
.length();
182 attrs
[0].data
= certIndex
.data();
183 const CssmOid
&policyOid
= policy
->oid();
184 attrs
[1].tag
= kSecTrustPolicyAttr
;
185 attrs
[1].length
= (UInt32
)policyOid
.length();
186 attrs
[1].data
= policyOid
.data();
187 SecKeychainAttributeList attrList
= { 2, attrs
};
188 KCCursor
cursor(keychainList
, CSSM_DL_DB_RECORD_USER_TRUST
, &attrList
);
190 if (cursor
->next(item
))
193 catch (const CommonError
&error
) {}
195 return ((ItemImpl
*)NULL
); // no trust schema, no records, no error
199 void TrustStore::getCssmRootCertificates(CertGroup
&rootCerts
)
201 StLock
<Mutex
> _(mMutex
);
204 loadRootCertificates();
205 rootCerts
= CertGroup(CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
, CSSM_CERTGROUP_DATA
);
206 rootCerts
.blobCerts() = &mRoots
[0];
207 rootCerts
.count() = (uint32
)mRoots
.size();
211 // Load root (anchor) certificates from disk
213 void TrustStore::loadRootCertificates()
215 StLock
<Mutex
> _(mMutex
);
217 CFRef
<CFArrayRef
> anchors
;
221 * Get the current set of all positively trusted anchors.
223 ortn
= SecTrustSettingsCopyUnrestrictedRoots(
224 true, true, true, /* all domains */
227 MacOSError::throwMe(ortn
);
230 // how many data bytes do we need?
232 CFIndex numCerts
= CFArrayGetCount(anchors
);
234 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
235 SecCertificateRef certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(anchors
, dex
);
237 crtn
= SecCertificateGetData(certRef
, &certData
);
239 CssmError::throwMe(crtn
);
241 size
+= certData
.Length
;
243 mRootBytes
.length(size
);
245 // fill CssmData vector while copying data bytes together
247 uint8
*base
= mRootBytes
.data
<uint8
>();
248 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
249 SecCertificateRef certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(anchors
, dex
);
251 SecCertificateGetData(certRef
, &certData
);
252 memcpy(base
, certData
.Data
, certData
.Length
);
253 mRoots
.push_back(CssmData(base
, certData
.Length
));
254 base
+= certData
.Length
;
257 secinfo("anchors", "%ld anchors loaded", (long)numCerts
);
259 mRootsValid
= true; // ready to roll
262 } // end namespace KeychainCore
263 } // end namespace Security