#include <security_keychain/TrustStore.h>
#include <security_keychain/Globals.h>
#include <security_keychain/Certificate.h>
#include <security_keychain/KCCursor.h>
#include <security_keychain/SecCFTypes.h>
#include <security_cdsa_utilities/Schema.h>
#include <security_keychain/SecTrustSettingsPriv.h>
namespace Security {
namespace KeychainCore {
TrustStore::TrustStore(Allocator &alloc)
: allocator(alloc), mRootsValid(false), mRootBytes(allocator), mMutex(Mutex::recursive)
{
}
TrustStore::~TrustStore()
{ }
SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy,
StorageManager::KeychainList &keychainList)
{
StLock<Mutex> _(mMutex);
if (Item item = findItem(cert, policy, keychainList)) {
if (cert->keychain() == NULL) {
if (cert->findInKeychain(keychainList) == NULL) {
Keychain defaultKeychain = Keychain::optional(NULL);
if (Keychain location = item->keychain()) {
try {
cert->copyTo(location); } catch (...) {
secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
cert, location->name());
try {
if (&*location != &*defaultKeychain)
cert->copyTo(defaultKeychain); } catch (...) {
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<TrustData>();
if (trust.version != UserTrustItem::currentVersion)
MacOSError::throwMe(errSecInvalidTrustSetting);
return trust.trust;
} else {
return kSecTrustResultUnspecified;
}
}
void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust)
{
StLock<Mutex> _(mMutex);
TrustData trustData = { UserTrustItem::currentVersion, trust };
Keychain defaultKeychain = Keychain::optional(NULL);
Keychain trustLocation = defaultKeychain; StorageManager::KeychainList searchList;
globals().storageManager.getSearchList(searchList);
if (Item item = findItem(cert, policy, searchList)) {
trustLocation = item->keychain();
if (trust == kSecTrustResultUnspecified)
item->keychain()->deleteItem(item);
else
item->modifyContent(NULL, sizeof(trustData), &trustData);
} else {
if (trust != kSecTrustResultUnspecified) {
Item item = new UserTrustItem(cert, policy, trustData);
if (Keychain location = cert->keychain()) {
try {
location->add(item); trustLocation = location;
} catch (...) {
if (&*location != &*defaultKeychain)
defaultKeychain->add(item); }
} else {
defaultKeychain->add(item); }
}
}
if (cert->keychain() == NULL) {
if (cert->findInKeychain(searchList) == NULL) {
try {
cert->copyTo(trustLocation); } catch (...) {
secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
cert, trustLocation->name());
try {
if (&*trustLocation != &*defaultKeychain)
cert->copyTo(defaultKeychain); } catch (...) {
secdebug("trusteval", "failed to add certificate %p to keychain \"%s\"",
cert, defaultKeychain->name());
}
}
}
}
}
Item TrustStore::findItem(Certificate *cert, Policy *policy,
StorageManager::KeychainList &keychainList)
{
return ((ItemImpl*)NULL);
StLock<Mutex> _(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); }
void TrustStore::getCssmRootCertificates(CertGroup &rootCerts)
{
StLock<Mutex> _(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();
}
void TrustStore::loadRootCertificates()
{
StLock<Mutex> _(mMutex);
CFRef<CFArrayRef> anchors;
OSStatus ortn;
ortn = SecTrustSettingsCopyUnrestrictedRoots(
true, true, true,
anchors.take());
if(ortn) {
MacOSError::throwMe(ortn);
}
size_t size = 0;
CFIndex numCerts = CFArrayGetCount(anchors);
CSSM_RETURN crtn;
for(CFIndex dex=0; dex<numCerts; dex++) {
SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
CSSM_DATA certData;
crtn = SecCertificateGetData(certRef, &certData);
if(crtn) {
CssmError::throwMe(crtn);
}
size += certData.Length;
}
mRootBytes.length(size);
mRoots.clear();
uint8 *base = mRootBytes.data<uint8>();
for(CFIndex dex=0; dex<numCerts; dex++) {
SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
CSSM_DATA certData;
SecCertificateGetData(certRef, &certData);
memcpy(base, certData.Data, certData.Length);
mRoots.push_back(CssmData(base, certData.Length));
base += certData.Length;
}
secdebug("anchors", "%ld anchors loaded", (long)numCerts);
mRootsValid = true; }
} }