#include "key.h"
#include "server.h"
#include "xdatabase.h"
#include <Security/acl_any.h>
Key::Key(Database &db, const KeyBlob *blob)
: SecurityServerAcl(keyAcl, CssmAllocator::standard())
{
assert(blob);
blob->validate(CSSMERR_APPLEDL_INVALID_KEY_BLOB);
switch (blob->version) {
#if defined(COMPAT_OSX_10_0)
case blob->version_MacOS_10_0:
break;
#endif
case blob->version_MacOS_10_1:
break;
default:
CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_KEY_BLOB);
}
mDatabase = &db;
mBlob = blob->copy(CssmAllocator::standard());
mAttributes = 0;
mValidBlob = true;
mValidKey = false;
mValidUID = false;
debug("SSkey", "%p created from blob version %lx", this, blob->version);
}
Key::Key(Database *db, const CssmKey &newKey, uint32 moreAttributes,
const AclEntryPrototype *owner)
: SecurityServerAcl(keyAcl, CssmAllocator::standard())
{
if (moreAttributes & CSSM_KEYATTR_PERMANENT) {
if (!db)
CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE);
} else {
db = NULL;
}
mDatabase = db;
mValidKey = true;
mBlob = NULL;
mValidBlob = false;
mValidUID = false;
setup(newKey, moreAttributes);
if (owner)
cssmSetInitial(*owner);
else
cssmSetInitial(new AnyAclSubject());
debug("SSkey", "%p created from key alg=%ld use=0x%lx attr=0x%lx",
this, mKey.algorithm(), mKey.usage(), mAttributes);
}
void Key::setup(const CssmKey &newKey, uint32 moreAttributes)
{
CssmKey::Header &header = mKey.header();
header = newKey.header();
mAttributes = header.attributes() | moreAttributes;
if (!(mAttributes & CSSM_KEYATTR_EXTRACTABLE))
mAttributes |= CSSM_KEYATTR_NEVER_EXTRACTABLE;
if (mAttributes & CSSM_KEYATTR_SENSITIVE)
mAttributes |= CSSM_KEYATTR_ALWAYS_SENSITIVE;
assert(!(header.attributes() & managedAttributes));
mKey.KeyData = CssmData(memcpy(malloc(newKey.length()), newKey.data(), newKey.length()), newKey.length());
}
Key::~Key()
{
CssmAllocator::standard().free(mBlob);
if (mValidKey)
Server::csp()->freeKey(mKey);
debug("SSkey", "%p destroyed", this);
}
CssmKey &Key::keyValue()
{
decode();
return mKey;
}
void Key::decode()
{
if (!mValidKey) {
assert(mDatabase); assert(mValidBlob);
void *publicAcl, *privateAcl;
database()->decodeKey(mBlob, mKey, publicAcl, privateAcl);
importBlob(publicAcl, privateAcl);
CssmAllocator::standard().free(privateAcl);
mAttributes = mKey.attributes() & managedAttributes;
mKey.clearAttribute(managedAttributes);
mValidKey = true;
}
}
CssmKey::Header &Key::keyHeader()
{
if (mValidKey) {
return mKey.header();
} else {
assert(mValidBlob);
return mBlob->header;
}
}
void Key::returnKey(Handle &h, CssmKey::Header &hdr)
{
h = handle();
hdr = keyHeader();
hdr.setAttribute(mAttributes);
}
KeyBlob *Key::blob()
{
if (mDatabase == NULL) CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
if (!mValidBlob) {
assert(mValidKey);
CssmData pubAcl, privAcl;
exportBlob(pubAcl, privAcl);
CssmKey externalKey = mKey;
externalKey.setAttribute(mAttributes);
KeyBlob *newBlob = database()->encodeKey(externalKey, pubAcl, privAcl);
CssmAllocator::standard().free(mBlob);
mBlob = newBlob;
mValidBlob = true;
database()->allocator.free(pubAcl);
database()->allocator.free(privAcl);
}
return mBlob;
}
KeyUID &Key::uid()
{
if (!mValidUID) {
memset(&mUID, 0, sizeof(mUID));
mValidUID = true;
}
return mUID;
}
void Key::instantiateAcl()
{
decode();
}
void Key::noticeAclChange()
{
mValidBlob = false;
}
const Database *Key::relatedDatabase() const
{ return database(); }