#include <security_keychain/TrustItem.h>
#include <security_cdsa_utilities/Schema.h>
#include <security_keychain/SecCFTypes.h>
#include <security_asn1/secasn1.h>
#include <security_asn1/SecNssCoder.h>
#include <Security/oidscert.h>
namespace Security {
namespace KeychainCore {
UserTrustItem::UserTrustItem(Certificate *cert, Policy *policy, const TrustData &trustData) :
ItemImpl(CSSM_DL_DB_RECORD_USER_TRUST,
reinterpret_cast<SecKeychainAttributeList *>(NULL),
UInt32(sizeof(trustData)),
reinterpret_cast<const void *>(&trustData)),
mCertificate(cert), mPolicy(policy)
{
secdebug("usertrust", "%p create(%p,%p) = %d",
this, cert, policy, SecTrustUserSetting(trustData.trust));
}
UserTrustItem::~UserTrustItem()
{
secdebug("usertrust", "%p destroyed", this);
}
UserTrustItem::TrustData UserTrustItem::trust()
{
StLock<Mutex>_(mMutex);
CssmDataContainer data;
getData(data);
if (data.length() != sizeof(TrustData))
MacOSError::throwMe(errSecInvalidTrustSetting);
return *data.interpretedAs<TrustData>();
}
PrimaryKey UserTrustItem::add(Keychain &keychain)
{
StLock<Mutex>_(mMutex);
if (mKeychain)
MacOSError::throwMe(errSecDuplicateItem);
populateAttributes();
CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
Db db(keychain->database());
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;
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<Mutex>_(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);
}
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;
};
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);
}
} }