X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_keychain/lib/TrustStore.cpp?ds=inline diff --git a/Security/libsecurity_keychain/lib/TrustStore.cpp b/Security/libsecurity_keychain/lib/TrustStore.cpp new file mode 100644 index 00000000..c703d431 --- /dev/null +++ b/Security/libsecurity_keychain/lib/TrustStore.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// +// TrustStore.h - Abstract interface to permanent user trust assignments +// +#include +#include +#include +#include +#include +#include +#include + +namespace Security { +namespace KeychainCore { + + +// +// Make and break: trivial +// +TrustStore::TrustStore(Allocator &alloc) + : allocator(alloc), mRootsValid(false), mRootBytes(allocator), mMutex(Mutex::recursive) +{ +} + +TrustStore::~TrustStore() +{ } + +// +// Retrieve the trust setting for a (certificate, policy) pair. +// +SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy, + StorageManager::KeychainList &keychainList) +{ + StLock _(mMutex); + + if (Item item = findItem(cert, policy, keychainList)) { + // Make sure that the certificate is available in some keychain, + // to provide a basis for editing the trust setting that we're returning. + if (cert->keychain() == NULL) { + if (cert->findInKeychain(keychainList) == NULL) { + Keychain defaultKeychain = Keychain::optional(NULL); + if (Keychain location = item->keychain()) { + try { + cert->copyTo(location); // add cert to the trust item's keychain + } catch (...) { + secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", + cert, location->name()); + try { + if (&*location != &*defaultKeychain) + cert->copyTo(defaultKeychain); // try the default (if it's not the same) + } catch (...) { + // unable to add the certificate + secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", + cert, defaultKeychain->name()); + } + } + } + } + } + CssmDataContainer data; + item->getData(data); + if (data.length() != sizeof(TrustData)) + MacOSError::throwMe(errSecInvalidTrustSetting); + TrustData &trust = *data.interpretedAs(); + if (trust.version != UserTrustItem::currentVersion) + MacOSError::throwMe(errSecInvalidTrustSetting); + return trust.trust; + } else { + return kSecTrustResultUnspecified; + } +} + + +// +// Set an individual trust element +// +void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust) +{ + StLock _(mMutex); + + TrustData trustData = { UserTrustItem::currentVersion, trust }; + Keychain defaultKeychain = Keychain::optional(NULL); + Keychain trustLocation = defaultKeychain; // default keychain, unless trust entry found + StorageManager::KeychainList searchList; + globals().storageManager.getSearchList(searchList); + + if (Item item = findItem(cert, policy, searchList)) { + // user has a trust setting in a keychain - modify that + trustLocation = item->keychain(); + if (trust == kSecTrustResultUnspecified) + item->keychain()->deleteItem(item); + else + item->modifyContent(NULL, sizeof(trustData), &trustData); + } else { + // no trust entry: make one + if (trust != kSecTrustResultUnspecified) { + Item item = new UserTrustItem(cert, policy, trustData); + if (Keychain location = cert->keychain()) { + try { + location->add(item); // try the cert's keychain first + trustLocation = location; + } catch (...) { + if (&*location != &*defaultKeychain) + defaultKeychain->add(item); // try the default (if it's not the same) + } + } else { + defaultKeychain->add(item); // raw cert - use default keychain + } + } + } + + // Make sure that the certificate is available in some keychain, + // to provide a basis for editing the trust setting that we're assigning. + if (cert->keychain() == NULL) { + if (cert->findInKeychain(searchList) == NULL) { + try { + cert->copyTo(trustLocation); // add cert to the trust item's keychain + } catch (...) { + secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", + cert, trustLocation->name()); + try { + if (&*trustLocation != &*defaultKeychain) + cert->copyTo(defaultKeychain); // try the default (if it's not the same) + } catch (...) { + // unable to add the certificate + secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"", + cert, defaultKeychain->name()); + } + } + } + } +} + + +// +// Search the user's configured keychains for a trust setting. +// If found, return it (as a TrustItem). Otherwise, return NULL. +// Note that this function throws if a "real" error is encountered. +// +Item TrustStore::findItem(Certificate *cert, Policy *policy, + StorageManager::KeychainList &keychainList) +{ + // As of OS X 10.5, user trust records are no longer stored in keychains. + // SecTrustSetUserTrust was replaced with SecTrustSettingsSetTrustSettings, + // which stores per-user trust in a separate root-owned file. This method, + // however, would continue to find old trust records created prior to 10.5. + // Since those are increasingly unlikely to exist (and cannot be edited), + // we no longer need or want to look for them anymore. + return ((ItemImpl*)NULL); + + StLock _(mMutex); + + try { + SecKeychainAttribute attrs[2]; + CssmAutoData certIndex(Allocator::standard()); + UserTrustItem::makeCertIndex(cert, certIndex); + attrs[0].tag = kSecTrustCertAttr; + attrs[0].length = (UInt32)certIndex.length(); + attrs[0].data = certIndex.data(); + const CssmOid &policyOid = policy->oid(); + attrs[1].tag = kSecTrustPolicyAttr; + attrs[1].length = (UInt32)policyOid.length(); + attrs[1].data = policyOid.data(); + SecKeychainAttributeList attrList = { 2, attrs }; + KCCursor cursor(keychainList, CSSM_DL_DB_RECORD_USER_TRUST, &attrList); + Item item; + if (cursor->next(item)) + return item; + } + catch (const CommonError &error) {} + + return ((ItemImpl*)NULL); // no trust schema, no records, no error +} + +void TrustStore::getCssmRootCertificates(CertGroup &rootCerts) +{ + StLock _(mMutex); + + if (!mRootsValid) + loadRootCertificates(); + rootCerts = CertGroup(CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, CSSM_CERTGROUP_DATA); + rootCerts.blobCerts() = &mRoots[0]; + rootCerts.count() = (uint32)mRoots.size(); +} + +// +// Load root (anchor) certificates from disk +// +void TrustStore::loadRootCertificates() +{ + StLock _(mMutex); + + CFRef anchors; + OSStatus ortn; + + /* + * Get the current set of all positively trusted anchors. + */ + ortn = SecTrustSettingsCopyUnrestrictedRoots( + true, true, true, /* all domains */ + anchors.take()); + if(ortn) { + MacOSError::throwMe(ortn); + } + + // how many data bytes do we need? + size_t size = 0; + CFIndex numCerts = CFArrayGetCount(anchors); + CSSM_RETURN crtn; + for(CFIndex dex=0; dex(); + for(CFIndex dex=0; dex