#include "kckey.h"
#include "server.h"
#include "database.h"
#include <security_cdsa_utilities/acl_any.h>
#include <security_cdsa_utilities/cssmendian.h>
KeychainKey::KeychainKey(Database &db, const KeyBlob *blob)
: LocalKey(db, n2h(blob->header.attributes()))
{
assert(blob);
blob->validate(CSSMERR_APPLEDL_INVALID_KEY_BLOB);
switch (blob->version()) {
#if defined(COMPAT_OSX_10_0)
case KeyBlob::version_MacOS_10_0:
break;
#endif
case KeyBlob::version_MacOS_10_1:
break;
case KeyBlob::version_partition:
break;
default:
CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_KEY_BLOB);
}
mBlob = blob->copy(Allocator::standard());
mValidBlob = true;
db.addReference(*this);
secdebug("SSkey", "%p (handle %#x) created from blob version %x",
this, handle(), blob->version());
}
KeychainKey::KeychainKey(Database &db, const CssmKey &newKey, uint32 moreAttributes,
const AclEntryPrototype *owner)
: LocalKey(db, newKey, moreAttributes)
{
assert(moreAttributes & CSSM_KEYATTR_PERMANENT);
setOwner(owner);
mBlob = NULL;
mValidBlob = false;
db.addReference(*this);
}
KeychainKey::~KeychainKey()
{
Allocator::standard().free(mBlob);
secdebug("SSkey", "%p destroyed", this);
}
KeychainDatabase &KeychainKey::database() const
{
return referent<KeychainDatabase>();
}
void KeychainKey::getKey()
{
decode();
}
void KeychainKey::getHeader(CssmKey::Header &hdr)
{
assert(mValidBlob);
hdr = mBlob->header;
n2hi(hdr); }
void KeychainKey::decode()
{
if (!mValidKey) {
assert(mValidBlob);
void *publicAcl, *privateAcl;
CssmKey key;
database().decodeKey(mBlob, key, publicAcl, privateAcl);
mKey = CssmClient::Key(Server::csp(), key);
acl().importBlob(publicAcl, privateAcl);
Allocator::standard().free(privateAcl);
mAttributes = mKey.header().attributes() & managedAttributes;
mKey.header().clearAttribute(managedAttributes);
mKey.header().setAttribute(forcedAttributes);
mValidKey = true;
}
}
KeyBlob *KeychainKey::blob()
{
if (!mValidBlob) {
assert(mValidKey);
CssmData pubAcl, privAcl;
acl().exportBlob(pubAcl, privAcl);
CssmKey externalKey = mKey;
externalKey.clearAttribute(forcedAttributes);
externalKey.setAttribute(mAttributes);
KeyBlob *newBlob = database().encodeKey(externalKey, pubAcl, privAcl);
Allocator::standard().free(mBlob);
mBlob = newBlob;
mValidBlob = true;
acl().allocator.free(pubAcl);
acl().allocator.free(privAcl);
}
return mBlob;
}
void KeychainKey::invalidateBlob()
{
mValidBlob = false;
}
void KeychainKey::instantiateAcl()
{
StLock<Mutex> _(*this);
decode();
}
void KeychainKey::changedAcl()
{
invalidateBlob();
}
void KeychainKey::validate(AclAuthorization auth, const AccessCredentials *cred,
Database *relatedDatabase)
{
if(!mBlob->isClearText()) {
if (KeychainDatabase *db = dynamic_cast<KeychainDatabase *>(relatedDatabase))
db->unlockDb();
}
SecurityServerAcl::validate(auth, cred, relatedDatabase);
database().activity(); }
AclKind KeychainKey::aclKind() const
{
return keyAcl;
}
Database *KeychainKey::relatedDatabase()
{
return &database();
}
SecurityServerAcl &KeychainKey::acl()
{
return *this;
}