1/* 2 * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24// 25// TrustStore.h - Abstract interface to permanent user trust assignments 26// 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> 34 35namespace Security { 36namespace KeychainCore { 37 38 39// 40// Make and break: trivial 41// 42TrustStore::TrustStore(Allocator &alloc) 43 : allocator(alloc), mRootsValid(false), mRootBytes(allocator), mMutex(Mutex::recursive) 44{ 45} 46 47TrustStore::~TrustStore() 48{ } 49 50// 51// Retrieve the trust setting for a (certificate, policy) pair. 52// 53SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy, 54 StorageManager::KeychainList &keychainList) 55{ 56 StLock<Mutex> _(mMutex); 57 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()) { 65 try { 66 cert->copyTo(location); // add cert to the trust item's keychain 67 } catch (...) { 68 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", 69 cert, location->name()); 70 try { 71 if (&*location != &*defaultKeychain) 72 cert->copyTo(defaultKeychain); // try the default (if it's not the same) 73 } catch (...) { 74 // unable to add the certificate 75 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", 76 cert, defaultKeychain->name()); 77 } 78 } 79 } 80 } 81 } 82 CssmDataContainer data; 83 item->getData(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); 89 return trust.trust; 90 } else { 91 return kSecTrustResultUnspecified; 92 } 93} 94 95 96// 97// Set an individual trust element 98// 99void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust) 100{ 101 StLock<Mutex> _(mMutex); 102 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); 108 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); 114 else 115 item->modifyContent(NULL, sizeof(trustData), &trustData); 116 } else { 117 // no trust entry: make one 118 if (trust != kSecTrustResultUnspecified) { 119 Item item = new UserTrustItem(cert, policy, trustData); 120 if (Keychain location = cert->keychain()) { 121 try { 122 location->add(item); // try the cert's keychain first 123 trustLocation = location; 124 } catch (...) { 125 if (&*location != &*defaultKeychain) 126 defaultKeychain->add(item); // try the default (if it's not the same) 127 } 128 } else { 129 defaultKeychain->add(item); // raw cert - use default keychain 130 } 131 } 132 } 133 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) { 138 try { 139 cert->copyTo(trustLocation); // add cert to the trust item's keychain 140 } catch (...) { 141 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", 142 cert, trustLocation->name()); 143 try { 144 if (&*trustLocation != &*defaultKeychain) 145 cert->copyTo(defaultKeychain); // try the default (if it's not the same) 146 } catch (...) { 147 // unable to add the certificate 148 secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", 149 cert, defaultKeychain->name()); 150 } 151 } 152 } 153 } 154} 155 156 157// 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. 161// 162Item TrustStore::findItem(Certificate *cert, Policy *policy, 163 StorageManager::KeychainList &keychainList) 164{ 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); 172 173 StLock<Mutex> _(mMutex); 174 175 try { 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); 188 Item item; 189 if (cursor->next(item)) 190 return item; 191 } 192 catch (const CommonError &error) {} 193 194 return ((ItemImpl*)NULL); // no trust schema, no records, no error 195} 196 197void TrustStore::getCssmRootCertificates(CertGroup &rootCerts) 198{ 199 StLock<Mutex> _(mMutex); 200 201 if (!mRootsValid) 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(); 206} 207 208// 209// Load root (anchor) certificates from disk 210// 211void TrustStore::loadRootCertificates() 212{ 213 StLock<Mutex> _(mMutex); 214 215 CFRef<CFArrayRef> anchors; 216 OSStatus ortn; 217 218 /* 219 * Get the current set of all positively trusted anchors. 220 */ 221 ortn = SecTrustSettingsCopyUnrestrictedRoots( 222 true, true, true, /* all domains */ 223 anchors.take()); 224 if(ortn) { 225 MacOSError::throwMe(ortn); 226 } 227 228 // how many data bytes do we need? 229 size_t size = 0; 230 CFIndex numCerts = CFArrayGetCount(anchors); 231 CSSM_RETURN crtn; 232 for(CFIndex dex=0; dex<numCerts; dex++) { 233 SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex); 234 CSSM_DATA certData; 235 crtn = SecCertificateGetData(certRef, &certData); 236 if(crtn) { 237 CssmError::throwMe(crtn); 238 } 239 size += certData.Length; 240 } 241 mRootBytes.length(size); 242 243 // fill CssmData vector while copying data bytes together 244 mRoots.clear(); 245 uint8 *base = mRootBytes.data<uint8>(); 246 for(CFIndex dex=0; dex<numCerts; dex++) { 247 SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex); 248 CSSM_DATA certData; 249 SecCertificateGetData(certRef, &certData); 250 memcpy(base, certData.Data, certData.Length); 251 mRoots.push_back(CssmData(base, certData.Length)); 252 base += certData.Length; 253 } 254 255 secdebug("anchors", "%ld anchors loaded", (long)numCerts); 256 257 mRootsValid = true; // ready to roll 258} 259 260} // end namespace KeychainCore 261} // end namespace Security 262