#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()), mDigest(Server::csp().allocator())
{
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;
secdebug("SSkey", "%p (handle 0x%lx) created from blob version %lx",
this, handle(), blob->version());
}
Key::Key(Database *db, const CssmKey &newKey, uint32 moreAttributes,
const AclEntryPrototype *owner)
: SecurityServerAcl(keyAcl, CssmAllocator::standard()), mDigest(Server::csp().allocator())
{
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 && !owner->subject().empty())
cssmSetInitial(*owner); else
cssmSetInitial(new AnyAclSubject()); secdebug("SSkey", "%p (handle 0x%lx) created from key alg=%ld use=0x%lx attr=0x%lx db=%p",
this, handle(), mKey.header().algorithm(), mKey.header().usage(), mAttributes, db);
}
void Key::setup(const CssmKey &newKey, uint32 moreAttributes)
{
mKey = CssmClient::Key(Server::csp(), newKey, false);
CssmKey::Header &header = mKey->header();
header = newKey.header();
mAttributes = (header.attributes() & ~forcedAttributes) | 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) == forcedAttributes);
}
Key::~Key()
{
CssmAllocator::standard().free(mBlob);
secdebug("SSkey", "%p destroyed", this);
}
Key::KeySpec::KeySpec(uint32 usage, uint32 attrs)
: CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes)
{
if (attrs & generatedAttributes)
CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
}
Key::KeySpec::KeySpec(uint32 usage, uint32 attrs, const CssmData &label)
: CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes, label)
{
if (attrs & generatedAttributes)
CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
}
CssmClient::Key Key::keyValue()
{
decode();
return mKey;
}
void Key::decode()
{
if (!mValidKey) {
assert(mDatabase); assert(mValidBlob);
void *publicAcl, *privateAcl;
CssmKey key;
database()->decodeKey(mBlob, key, publicAcl, privateAcl);
mKey = CssmClient::Key(Server::csp(), key);
importBlob(publicAcl, privateAcl);
CssmAllocator::standard().free(privateAcl);
mAttributes = mKey.header().attributes() & managedAttributes;
mKey.header().clearAttribute(managedAttributes);
mKey.header().setAttribute(forcedAttributes);
mValidKey = true;
}
}
void Key::returnKey(Handle &h, CssmKey::Header &hdr)
{
h = handle();
if (mValidKey) {
hdr = mKey.header();
} else {
assert(mValidBlob);
hdr = mBlob->header;
n2hi(hdr); }
hdr.clearAttribute(forcedAttributes);
hdr.setAttribute(mAttributes);
}
const CssmData &Key::canonicalDigest()
{
if (!mDigest) {
CssmClient::PassThrough ctx(Server::csp());
ctx.key(keyValue());
CssmData *digest = NULL;
ctx(CSSM_APPLECSP_KEYDIGEST, (const void *)NULL, &digest);
assert(digest);
mDigest.set(*digest); Server::csp().allocator().free(digest); }
return mDigest.get();
}
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.clearAttribute(forcedAttributes);
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::changedAcl()
{
mValidBlob = false;
}
const Database *Key::relatedDatabase() const
{ return database(); }