X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_keychain/lib/TrustItem.cpp?ds=inline diff --git a/Security/libsecurity_keychain/lib/TrustItem.cpp b/Security/libsecurity_keychain/lib/TrustItem.cpp new file mode 100644 index 00000000..4c2e3632 --- /dev/null +++ b/Security/libsecurity_keychain/lib/TrustItem.cpp @@ -0,0 +1,192 @@ +/* + * 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 + + +namespace Security { +namespace KeychainCore { + + +// +// Construct a UserTrustItem from attributes and initial content +// +UserTrustItem::UserTrustItem(Certificate *cert, Policy *policy, const TrustData &trustData) : + ItemImpl(CSSM_DL_DB_RECORD_USER_TRUST, + reinterpret_cast(NULL), + UInt32(sizeof(trustData)), + reinterpret_cast(&trustData)), + mCertificate(cert), mPolicy(policy) +{ + secdebug("usertrust", "%p create(%p,%p) = %d", + this, cert, policy, SecTrustUserSetting(trustData.trust)); +} + + +// +// Destroy it +// +UserTrustItem::~UserTrustItem() +{ + secdebug("usertrust", "%p destroyed", this); +} + + +// +// Retrieve the trust value from a UserTrustItem +// +UserTrustItem::TrustData UserTrustItem::trust() +{ + StLock_(mMutex); + CssmDataContainer data; + getData(data); + if (data.length() != sizeof(TrustData)) + MacOSError::throwMe(errSecInvalidTrustSetting); + return *data.interpretedAs(); +} + + +// +// Add item to keychain +// +PrimaryKey UserTrustItem::add(Keychain &keychain) +{ + StLock_(mMutex); + // If we already have a Keychain we can't be added. + if (mKeychain) + MacOSError::throwMe(errSecDuplicateItem); + + populateAttributes(); + + CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType(); + + Db db(keychain->database()); + // add the item to the (regular) db + try + { + mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get()); + secdebug("usertrust", "%p inserted", this); + } + catch (const CssmError &e) + { + if (e.osStatus() != CSSMERR_DL_INVALID_RECORDTYPE) + throw; + + // Create the trust relation and try again. + secdebug("usertrust", "adding schema relation for user trusts"); + db->createRelation(CSSM_DL_DB_RECORD_USER_TRUST, "CSSM_DL_DB_RECORD_USER_TRUST", + Schema::UserTrustSchemaAttributeCount, + Schema::UserTrustSchemaAttributeList, + Schema::UserTrustSchemaIndexCount, + Schema::UserTrustSchemaIndexList); + keychain->keychainSchema()->didCreateRelation( + CSSM_DL_DB_RECORD_USER_TRUST, + "CSSM_DL_DB_RECORD_USER_TRUST", + Schema::UserTrustSchemaAttributeCount, + Schema::UserTrustSchemaAttributeList, + Schema::UserTrustSchemaIndexCount, + Schema::UserTrustSchemaIndexList); + + mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get()); + secdebug("usertrust", "%p inserted now", this); + } + + mPrimaryKey = keychain->makePrimaryKey(recordType, mUniqueId); + mKeychain = keychain; + return mPrimaryKey; +} + + +void UserTrustItem::populateAttributes() +{ + StLock_(mMutex); + CssmAutoData encodedIndex(Allocator::standard()); + makeCertIndex(mCertificate, encodedIndex); + const CssmOid &policyOid = mPolicy->oid(); + + mDbAttributes->add(Schema::attributeInfo(kSecTrustCertAttr), encodedIndex.get()); + mDbAttributes->add(Schema::attributeInfo(kSecTrustPolicyAttr), policyOid); +} + + +// +// An ad-hoc hold-and-destroy accessor for a single-valued certificate field +// +class CertField { +public: + CertField(Certificate *cert, const CSSM_OID &inField) + : certificate(cert), field(inField) + { mData = certificate->copyFirstFieldValue(field); } + + ~CertField() { certificate->releaseFieldValue(field, mData); } + + Certificate * const certificate; + const CSSM_OID &field; + + operator bool () const { return mData && mData->Data; } + CssmData &data() const { return CssmData::overlay(*mData); } + +private: + CSSM_DATA_PTR mData; +}; + + +// +// Construct a trust item index. +// This is an ASN.1 sequence of issuer and serial number. +// +struct IssuerAndSN { + CSSM_DATA issuer; + CSSM_DATA serial; +}; + +static const SecAsn1Template issuerAndSNTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(IssuerAndSN) }, + { SEC_ASN1_OCTET_STRING, offsetof(IssuerAndSN, issuer) }, + { SEC_ASN1_OCTET_STRING, offsetof(IssuerAndSN, serial) }, + { 0 } +}; + +void UserTrustItem::makeCertIndex(Certificate *cert, CssmOwnedData &encodedIndex) +{ + CertField issuer(cert, CSSMOID_X509V1IssuerName); + CertField serial(cert, CSSMOID_X509V1SerialNumber); + IssuerAndSN index; + index.issuer = issuer.data(); + index.serial = serial.data(); + if (SecNssEncodeItemOdata(&index, issuerAndSNTemplate, encodedIndex)) + CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); +} + + +} // end namespace KeychainCore +} // end namespace Security