#include "Schema.h"
#include "Attribute.h"
#include "MetaRecord.h"
#include "MetaAttribute.h"
#include <Security/SecKey.h>
#include <Security/SecCertificate.h>
#include <Security/SecKeychainItem.h>
#include <Security/SecKeychainItemPriv.h>
#include <Security/cssmapple.h>
namespace Tokend
{
#pragma mark ---------------- Schema --------------
Schema::Schema() :
mTrueCoder(true),
mFalseCoder(false),
mCertEncodingBERCoder(CSSM_CERT_ENCODING(CSSM_CERT_ENCODING_BER)),
mSdCSPDLGuidCoder(gGuidAppleSdCSPDL),
mPublicKeyClassCoder(CSSM_KEYCLASS(CSSM_KEYCLASS_PUBLIC_KEY)),
mPrivateKeyClassCoder(CSSM_KEYCLASS(CSSM_KEYCLASS_PRIVATE_KEY)),
mSessionKeyClassCoder(CSSM_KEYCLASS(CSSM_KEYCLASS_SESSION_KEY))
{
}
Schema::~Schema()
{
try
{
for_each_map_delete(mRelationMap.begin(), mRelationMap.end());
}
catch(...) {}
}
void Schema::create()
{
std::string
an_RelationID("RelationID"),
an_RelationName("RelationName"),
an_AttributeID("AttributeID"),
an_AttributeNameFormat("AttributeNameFormat"),
an_AttributeName("AttributeName"),
an_AttributeNameID("AttributeNameID"),
an_AttributeFormat("AttributeFormat"),
an_IndexID("IndexID"),
an_IndexType("IndexType"),
an_IndexedDataLocation("IndexedDataLocation");
MetaRecord *mrio = new MetaRecord(CSSM_DL_DB_SCHEMA_INFO);
io_rid = mrio->createAttribute(an_RelationID,
kAF_UINT32).attributeIndex();
io_rn = mrio->createAttribute(an_RelationName,
kAF_STRING).attributeIndex();
mInfo = createRelation(mrio);
MetaRecord *mras = new MetaRecord(CSSM_DL_DB_SCHEMA_ATTRIBUTES);
as_rid = mras->createAttribute(an_RelationID,
kAF_UINT32).attributeIndex();
as_aid = mras->createAttribute(an_AttributeID,
kAF_UINT32).attributeIndex();
as_anf = mras->createAttribute(an_AttributeNameFormat,
kAF_UINT32).attributeIndex();
as_an = mras->createAttribute(an_AttributeName,
kAF_STRING).attributeIndex();
as_anid= mras->createAttribute(an_AttributeNameID,
kAF_BLOB ).attributeIndex();
as_af = mras->createAttribute(an_AttributeFormat,
kAF_UINT32).attributeIndex();
mAttributes = createRelation(mras);
MetaRecord *mrix = new MetaRecord(CSSM_DL_DB_SCHEMA_INDEXES);
ix_rid = mrix->createAttribute(an_RelationID,
kAF_UINT32).attributeIndex();
ix_iid = mrix->createAttribute(an_IndexID,
kAF_UINT32).attributeIndex();
ix_aid = mrix->createAttribute(an_AttributeID,
kAF_UINT32).attributeIndex();
ix_it = mrix->createAttribute(an_IndexType,
kAF_UINT32).attributeIndex();
ix_idl = mrix->createAttribute(an_IndexedDataLocation,
kAF_UINT32).attributeIndex();
mIndices = createRelation(mrix);
#ifdef ADD_SCHEMA_PARSING_MODULE
std::string
an_ModuleID("ModuleID"),
an_AddinVersion("AddinVersion"),
an_SSID("SSID"),
an_SubserviceType("SubserviceType");
MetaRecord *mr_parsing = new MetaRecord(CSSM_DL_DB_SCHEMA_PARSING_MODULE);
mr_parsing->createAttribute(an_AttributeID, kAF_UINT32);
mr_parsing->createAttribute(an_ModuleID, kAF_BLOB );
mr_parsing->createAttribute(an_AddinVersion, kAF_STRING);
mr_parsing->createAttribute(an_SSID, kAF_UINT32);
mr_parsing->createAttribute(an_SubserviceType, kAF_UINT32);
createRelation(mr_parsing);
#endif
#ifdef REGISTER_SCHEMA_RELATIONS
registerRelation("CSSM_DL_DB_SCHEMA_INFO", CSSM_DL_DB_SCHEMA_INFO)
registerAttribute(CSSM_DL_DB_SCHEMA_INFO, &an_RelationID, 0,
kAF_UINT32, true);
registerAttribute(CSSM_DL_DB_SCHEMA_INFO, &an_RelationName, 1,
kAF_UINT32, false);
registerRelation("CSSM_DL_DB_SCHEMA_ATTRIBUTES",
CSSM_DL_DB_SCHEMA_ATTRIBUTES)
registerAttribute(CSSM_DL_DB_SCHEMA_ATTRIBUTES, &an_RelationID, 0,
kAF_UINT32, true);
registerAttribute(CSSM_DL_DB_SCHEMA_ATTRIBUTES, &an_AttributeID, 2,
kAF_UINT32, true);
registerAttribute(CSSM_DL_DB_SCHEMA_ATTRIBUTES, &an_AttributeNameFormat, 3,
kAF_UINT32, false);
registerAttribute(CSSM_DL_DB_SCHEMA_ATTRIBUTES, &an_AttributeName, 4,
kAF_STRING, false);
registerAttribute(CSSM_DL_DB_SCHEMA_ATTRIBUTES, &an_AttributeNameId, 5,
kAF_BLOB, false);
registerAttribute(CSSM_DL_DB_SCHEMA_ATTRIBUTES, &an_AttributeFormat, 6,
kAF_UINT32, false);
registerRelation("CSSM_DL_DB_SCHEMA_INDEXES", CSSM_DL_DB_SCHEMA_INDEXES)
registerAttribute(CSSM_DL_DB_SCHEMA_INDEXES, &an_RelationID, 0,
kAF_UINT32, true);
registerAttribute(CSSM_DL_DB_SCHEMA_INDEXES, &an_IndexID, 1,
kAF_UINT32, true);
registerAttribute(CSSM_DL_DB_SCHEMA_INDEXES, &an_AttributeID, 2,
kAF_UINT32, true);
registerAttribute(CSSM_DL_DB_SCHEMA_INDEXES, &an_IndexType, 3,
kAF_UINT32, false);
registerAttribute(CSSM_DL_DB_SCHEMA_INDEXES, &an_IndexedDataLocation, 4,
kAF_UINT32, false);
#endif
}
Relation *Schema::createStandardRelation(RelationId relationId)
{
std::string relationName;
switch (relationId)
{
case CSSM_DL_DB_RECORD_PRIVATE_KEY:
relationName = "CSSM_DL_DB_RECORD_PRIVATE_KEY"; break;
case CSSM_DL_DB_RECORD_PUBLIC_KEY:
relationName = "CSSM_DL_DB_RECORD_PUBLIC_KEY"; break;
case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
relationName = "CSSM_DL_DB_RECORD_SYMMETRIC_KEY"; break;
case CSSM_DL_DB_RECORD_X509_CERTIFICATE:
relationName = "CSSM_DL_DB_RECORD_X509_CERTIFICATE"; break;
case CSSM_DL_DB_RECORD_GENERIC:
relationName = "CSSM_DL_DB_RECORD_GENERIC"; break;
default: CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
}
Relation *rt = createRelation(relationName, relationId);
std::string
an_CertType = "CertType",
an_CertEncoding = "CertEncoding",
an_PrintName = "PrintName",
an_Alias = "Alias",
an_Subject = "Subject",
an_Issuer = "Issuer",
an_SerialNumber = "SerialNumber",
an_SubjectKeyIdentifier = "SubjectKeyIdentifier",
an_PublicKeyHash = "PublicKeyHash",
an_KeyClass = "KeyClass",
an_Permanent = "Permanent",
an_Private = "Private",
an_Modifiable = "Modifiable",
an_Label = "Label",
an_ApplicationTag = "ApplicationTag",
an_KeyCreator = "KeyCreator",
an_KeyType = "KeyType",
an_KeySizeInBits = "KeySizeInBits",
an_EffectiveKeySize = "EffectiveKeySize",
an_StartDate = "StartDate",
an_EndDate = "EndDate",
an_Sensitive = "Sensitive",
an_AlwaysSensitive = "AlwaysSensitive",
an_Extractable = "Extractable",
an_NeverExtractable = "NeverExtractable",
an_Encrypt = "Encrypt",
an_Decrypt = "Decrypt",
an_Derive = "Derive",
an_Sign = "Sign",
an_Verify = "Verify",
an_SignRecover = "SignRecover",
an_VerifyRecover = "VerifyRecover",
an_Wrap = "Wrap",
an_Unwrap = "Unwrap";
switch (relationId)
{
case CSSM_DL_DB_RECORD_GENERIC:
createAttribute(*rt, &an_PrintName, kSecLabelItemAttr, kAF_BLOB, false)
.attributeCoder(&mDescriptionCoder);
createAttribute(*rt, &an_Alias, kSecAliasItemAttr, kAF_BLOB, false)
.attributeCoder(&mZeroCoder);
rt->metaRecord().attributeCoderForData(&mDataAttributeCoder);
break;
case CSSM_DL_DB_RECORD_X509_CERTIFICATE:
createAttribute(*rt, &an_CertType, kSecCertTypeItemAttr,
kAF_UINT32, true).attributeCoder(&mCertificateCoder);
createAttribute(*rt, &an_CertEncoding, kSecCertEncodingItemAttr,
kAF_UINT32, false).attributeCoder(&mCertEncodingBERCoder);
createAttribute(*rt, &an_PrintName, kSecLabelItemAttr,
kAF_BLOB, false).attributeCoder(&mCertificateCoder);
createAttribute(*rt, &an_Alias, kSecAliasItemAttr,
kAF_BLOB, false).attributeCoder(&mCertificateCoder);
createAttribute(*rt, &an_Subject, kSecSubjectItemAttr,
kAF_BLOB, false).attributeCoder(&mCertificateCoder);
createAttribute(*rt, &an_Issuer, kSecIssuerItemAttr,
kAF_BLOB, true).attributeCoder(&mCertificateCoder);
createAttribute(*rt, &an_SerialNumber, kSecSerialNumberItemAttr,
kAF_BLOB, true).attributeCoder(&mCertificateCoder);
createAttribute(*rt, &an_SubjectKeyIdentifier,
kSecSubjectKeyIdentifierItemAttr,
kAF_BLOB, false).attributeCoder(&mCertificateCoder);
createAttribute(*rt, &an_PublicKeyHash, kSecPublicKeyHashItemAttr,
kAF_BLOB, false).attributeCoder(&mCertificateCoder);
rt->metaRecord().attributeCoderForData(&mDataAttributeCoder);
mPublicKeyHashCoder.setCertificateMetaAttribute(&(rt->metaRecord()
.metaAttribute(kSecPublicKeyHashItemAttr)));
break;
case CSSM_DL_DB_RECORD_PUBLIC_KEY:
case CSSM_DL_DB_RECORD_PRIVATE_KEY:
case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
rt->metaRecord().attributeCoderForData(&mKeyDataCoder);
createAttribute(*rt, &an_KeyClass, kSecKeyKeyClass,
kAF_UINT32, false).attributeCoder(
relationId == CSSM_DL_DB_RECORD_PUBLIC_KEY
? &mPublicKeyClassCoder
: relationId == CSSM_DL_DB_RECORD_PRIVATE_KEY
? &mPrivateKeyClassCoder
: &mSessionKeyClassCoder);
createAttribute(*rt, &an_PrintName, kSecKeyPrintName,
kAF_BLOB, false).attributeCoder(&mZeroCoder);
createAttribute(*rt, &an_Alias, kSecKeyAlias,
kAF_BLOB, false).attributeCoder(&mZeroCoder);
createAttribute(*rt, &an_Permanent, kSecKeyPermanent,
kAF_UINT32, false).attributeCoder(&mTrueCoder);
createAttribute(*rt, &an_Private, kSecKeyPrivate,
kAF_UINT32, false).attributeCoder(
relationId == CSSM_DL_DB_RECORD_PUBLIC_KEY
? &mFalseCoder : &mTrueCoder);
createAttribute(*rt, &an_Modifiable, kSecKeyModifiable,
kAF_UINT32, false).attributeCoder(&mFalseCoder);
createAttribute(*rt, &an_Label, kSecKeyLabel,
kAF_BLOB, true).attributeCoder(
relationId == CSSM_DL_DB_RECORD_PRIVATE_KEY
? &mPublicKeyHashCoder : NULL);
createAttribute(*rt, &an_ApplicationTag, kSecKeyApplicationTag,
kAF_BLOB, true).attributeCoder(&mZeroCoder);
createAttribute(*rt, &an_KeyCreator, kSecKeyKeyCreator,
kAF_BLOB, true).attributeCoder(&mSdCSPDLGuidCoder);
createAttribute(*rt, &an_KeyType, kSecKeyKeyType, kAF_UINT32, true);
createAttribute(*rt, &an_KeySizeInBits, kSecKeyKeySizeInBits,
kAF_UINT32, true);
createAttribute(*rt, &an_EffectiveKeySize, kSecKeyEffectiveKeySize,
kAF_UINT32, true);
createAttribute(*rt, &an_StartDate, kSecKeyStartDate,
kAF_TIME_DATE, true).attributeCoder(&mZeroCoder);
createAttribute(*rt, &an_EndDate, kSecKeyEndDate,
kAF_TIME_DATE, true).attributeCoder(&mZeroCoder);
createAttribute(*rt, &an_Sensitive, kSecKeySensitive,
kAF_UINT32, false).attributeCoder(
relationId == CSSM_DL_DB_RECORD_PUBLIC_KEY
? &mFalseCoder : &mTrueCoder);
createAttribute(*rt, &an_AlwaysSensitive, kSecKeyAlwaysSensitive,
kAF_UINT32, false).attributeCoder(&mFalseCoder);
createAttribute(*rt, &an_Extractable, kSecKeyExtractable,
kAF_UINT32, false).attributeCoder(&mFalseCoder);
createAttribute(*rt, &an_NeverExtractable, kSecKeyNeverExtractable,
kAF_UINT32, false).attributeCoder(&mFalseCoder);
createAttribute(*rt, &an_Encrypt, kSecKeyEncrypt, kAF_UINT32, false);
createAttribute(*rt, &an_Decrypt, kSecKeyDecrypt, kAF_UINT32, false);
createAttribute(*rt, &an_Derive, kSecKeyDerive, kAF_UINT32, false);
createAttribute(*rt, &an_Sign, kSecKeySign, kAF_UINT32, false);
createAttribute(*rt, &an_Verify, kSecKeyVerify, kAF_UINT32, false);
createAttribute(*rt, &an_SignRecover, kSecKeySignRecover,
kAF_UINT32, false);
createAttribute(*rt, &an_VerifyRecover, kSecKeyVerifyRecover,
kAF_UINT32, false);
createAttribute(*rt, &an_Wrap, kSecKeyWrap, kAF_UINT32, false);
createAttribute(*rt, &an_Unwrap, kSecKeyUnwrap, kAF_UINT32, false);
if (relationId == CSSM_DL_DB_RECORD_PUBLIC_KEY)
mPublicKeyHashCoder.setPublicKeyMetaAttribute(&(rt->metaRecord()
.metaAttribute(kSecKeyLabel)));
break;
}
return rt;
}
Relation *Schema::createRelation(MetaRecord *metaRecord)
{
auto_ptr<Relation> aRelation(new Relation(metaRecord));
if (!mRelationMap.insert(RelationMap::value_type(metaRecord->relationId(),
aRelation.get())).second)
{
CssmError::throwMe(CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA);
}
return aRelation.release();
}
Relation *Schema::createRelation(const std::string &relationName,
RelationId relationId)
{
MetaRecord *mr = new MetaRecord(relationId);
Relation *rt = createRelation(mr);
registerRelation(relationName, relationId);
return rt;
}
MetaAttribute &Schema::createAttribute(Relation &relation,
const std::string *name, uint32 attributeId,
CSSM_DB_ATTRIBUTE_FORMAT attributeFormat, bool isIndex)
{
MetaRecord &mr = relation.metaRecord();
registerAttribute(mr.relationId(), name, attributeId, attributeFormat,
isIndex);
return mr.createAttribute(name, NULL, attributeId, attributeFormat);
}
void Schema::registerRelation(const std::string &relationName,
RelationId relationId)
{
RefPointer<Record> record = new Record();
record->attributeAtIndex(io_rid, new Attribute(relationId));
record->attributeAtIndex(io_rn, new Attribute(relationName));
mInfo->insertRecord(record);
}
void Schema::registerAttribute(RelationId relationId, const std::string *name,
uint32 attributeId, CSSM_DB_ATTRIBUTE_FORMAT attributeFormat, bool isIndex)
{
CSSM_DB_ATTRIBUTE_NAME_FORMAT nameFormat = name
? CSSM_DB_ATTRIBUTE_NAME_AS_STRING : CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
RefPointer<Record> rc_attribute = new Record();
rc_attribute->attributeAtIndex(as_rid, new Attribute(relationId));
rc_attribute->attributeAtIndex(as_aid, new Attribute(attributeId));
rc_attribute->attributeAtIndex(as_anf, new Attribute(nameFormat));
rc_attribute->attributeAtIndex(as_an, name
? new Attribute(*name) : new Attribute()); rc_attribute->attributeAtIndex(as_anid, new Attribute()); rc_attribute->attributeAtIndex(as_af, new Attribute(attributeFormat));
mAttributes->insertRecord(rc_attribute);
if (isIndex)
{
RefPointer<Record> rc_index = new Record();
rc_index->attributeAtIndex(ix_rid, new Attribute(relationId));
rc_index->attributeAtIndex(ix_iid, new Attribute(uint32(0)));
rc_index->attributeAtIndex(ix_aid, new Attribute(attributeId));
rc_index->attributeAtIndex(ix_it, new Attribute(uint32(CSSM_DB_INDEX_UNIQUE)));
rc_index->attributeAtIndex(ix_idl, new Attribute(uint32(CSSM_DB_INDEX_ON_UNKNOWN)));
mIndices->insertRecord(rc_index);
}
}
#pragma mark ---------------- Utility methods --------------
const Relation &Schema::findRelation(RelationId inRelationId) const
{
RelationMap::const_iterator it = mRelationMap.find(inRelationId);
if (it == mRelationMap.end())
CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
return *it->second;
}
Relation &Schema::findRelation(RelationId inRelationId)
{
RelationMap::iterator it = mRelationMap.find(inRelationId);
if (it == mRelationMap.end())
CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
return *it->second;
}
MetaRecord &Schema::findMetaRecord(RelationId inRelationId)
{
return findRelation(inRelationId).metaRecord();
}
}