TrustStore.cpp
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/SecTrustSettingsPriv.h> 34 35 namespace Security { 36 namespace KeychainCore { 37 38 39 // 40 // Make and break: trivial 41 // 42 TrustStore::TrustStore(Allocator &alloc) 43 : allocator(alloc), mRootsValid(false), mRootBytes(allocator), mMutex(Mutex::recursive) 44 { 45 } 46 47 TrustStore::~TrustStore() 48 { } 49 50 // 51 // Retrieve the trust setting for a (certificate, policy) pair. 52 // 53 SecTrustUserSetting 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 secinfo("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 secinfo("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 // 99 void 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 secinfo("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 secinfo("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 // 162 Item 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 #if 0 174 StLock<Mutex> _(mMutex); 175 176 try { 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); 189 Item item; 190 if (cursor->next(item)) 191 return item; 192 } 193 catch (const CommonError &error) {} 194 195 return ((ItemImpl*)NULL); // no trust schema, no records, no error 196 #endif 197 } 198 199 void TrustStore::getCssmRootCertificates(CertGroup &rootCerts) 200 { 201 StLock<Mutex> _(mMutex); 202 203 if (!mRootsValid) 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(); 208 } 209 210 // 211 // Load root (anchor) certificates from disk 212 // 213 void TrustStore::loadRootCertificates() 214 { 215 StLock<Mutex> _(mMutex); 216 217 CFRef<CFArrayRef> anchors; 218 OSStatus ortn; 219 220 /* 221 * Get the current set of all positively trusted anchors. 222 */ 223 ortn = SecTrustSettingsCopyUnrestrictedRoots( 224 true, true, true, /* all domains */ 225 anchors.take()); 226 if(ortn) { 227 MacOSError::throwMe(ortn); 228 } 229 230 // how many data bytes do we need? 231 size_t size = 0; 232 CFIndex numCerts = CFArrayGetCount(anchors); 233 CSSM_RETURN crtn; 234 for(CFIndex dex=0; dex<numCerts; dex++) { 235 SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex); 236 CSSM_DATA certData; 237 crtn = SecCertificateGetData(certRef, &certData); 238 if(crtn) { 239 CssmError::throwMe(crtn); 240 } 241 size += certData.Length; 242 } 243 mRootBytes.length(size); 244 245 // fill CssmData vector while copying data bytes together 246 mRoots.clear(); 247 uint8 *base = mRootBytes.data<uint8>(); 248 for(CFIndex dex=0; dex<numCerts; dex++) { 249 SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex); 250 CSSM_DATA certData; 251 SecCertificateGetData(certRef, &certData); 252 memcpy(base, certData.Data, certData.Length); 253 mRoots.push_back(CssmData(base, certData.Length)); 254 base += certData.Length; 255 } 256 257 secinfo("anchors", "%ld anchors loaded", (long)numCerts); 258 259 mRootsValid = true; // ready to roll 260 } 261 262 } // end namespace KeychainCore 263 } // end namespace Security