#include "SSKey.h"
#include "SSCSPSession.h"
#include "SSCSPDLSession.h"
#include "SSDatabase.h"
#include "SSDLSession.h"
#include <security_cdsa_utilities/KeySchema.h>
#include <security_cdsa_plugin/cssmplugin.h>
using namespace CssmClient;
using namespace SecurityServer;
SSKey::SSKey(SSCSPSession &session, KeyHandle keyHandle, CssmKey &ioKey,
SSDatabase &inSSDatabase, uint32 inKeyAttr,
const CssmData *inKeyLabel)
: ReferencedKey(session.mSSCSPDLSession),
mAllocator(session), mKeyHandle(keyHandle),
mClientSession(session.clientSession())
{
CssmKey::Header &header = ioKey.header();
if (inKeyAttr & CSSM_KEYATTR_PERMANENT)
{
if (!inSSDatabase)
CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE);
CssmDataContainer blob(mAllocator);
clientSession().encodeKey(keyHandle, blob);
assert(header.HeaderVersion == CSSM_KEYHEADER_VERSION);
switch (header.KeyClass)
{
case CSSM_KEYCLASS_PUBLIC_KEY:
mRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
break;
case CSSM_KEYCLASS_PRIVATE_KEY:
mRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
break;
case CSSM_KEYCLASS_SESSION_KEY:
mRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
CssmData label;
if (inKeyLabel)
label = *inKeyLabel;
CssmData none;
CssmGuidData creatorGuid(header.CspId);
CssmDateData startDate(header.StartDate);
CssmDateData endDate(header.EndDate);
DbAttributes attributes(inSSDatabase);
attributes.recordType(mRecordType);
attributes.add(KeySchema::KeyClass, mRecordType);
attributes.add(KeySchema::PrintName, label);
attributes.add(KeySchema::Alias, none);
attributes.add(KeySchema::Permanent,
header.attribute(CSSM_KEYATTR_PERMANENT));
attributes.add(KeySchema::Private,
header.attribute(CSSM_KEYATTR_PRIVATE));
attributes.add(KeySchema::Modifiable,
header.attribute(CSSM_KEYATTR_MODIFIABLE));
attributes.add(KeySchema::Label, label);
attributes.add(KeySchema::ApplicationTag, none);
attributes.add(KeySchema::KeyCreator, creatorGuid);
attributes.add(KeySchema::KeyType, header.AlgorithmId);
attributes.add(KeySchema::KeySizeInBits, header.LogicalKeySizeInBits);
attributes.add(KeySchema::EffectiveKeySize, header.LogicalKeySizeInBits);
attributes.add(KeySchema::StartDate, startDate);
attributes.add(KeySchema::EndDate, endDate);
attributes.add(KeySchema::Sensitive,
header.attribute(CSSM_KEYATTR_SENSITIVE));
attributes.add(KeySchema::AlwaysSensitive,
header.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE));
attributes.add(KeySchema::Extractable,
header.attribute(CSSM_KEYATTR_EXTRACTABLE));
attributes.add(KeySchema::NeverExtractable,
header.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE));
attributes.add(KeySchema::Encrypt,
header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_ENCRYPT));
attributes.add(KeySchema::Decrypt,
header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DECRYPT));
attributes.add(KeySchema::Derive,
header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DERIVE));
attributes.add(KeySchema::Sign,
header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_SIGN));
attributes.add(KeySchema::Verify,
header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_VERIFY));
attributes.add(KeySchema::SignRecover,
header.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_SIGN_RECOVER));
attributes.add(KeySchema::VerifyRecover,
header.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_VERIFY_RECOVER));
attributes.add(KeySchema::Wrap,
header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_WRAP));
attributes.add(KeySchema::Unwrap,
header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_UNWRAP));
mUniqueId = inSSDatabase->insert(mRecordType, &attributes, &blob,
true);
}
header.cspGuid(session.plugin.myGuid()); makeReferenceKey(mAllocator, keyReference(), ioKey);
}
SSKey::SSKey(SSDLSession &session, CssmKey &ioKey, SSDatabase &inSSDatabase,
const SSUniqueRecord &uniqueId, CSSM_DB_RECORDTYPE recordType,
CssmData &keyBlob)
: ReferencedKey(session.mSSCSPDLSession),
mAllocator(session.allocator()), mKeyHandle(noKey), mUniqueId(uniqueId),
mRecordType(recordType),
mClientSession(session.clientSession())
{
CssmKey::Header &header = ioKey.header();
memset(&header, 0, sizeof(header));
if (!mUniqueId || !mUniqueId->database())
CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
header.HeaderVersion = CSSM_KEYHEADER_VERSION;
switch (mRecordType)
{
case CSSM_DL_DB_RECORD_PUBLIC_KEY:
header.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
break;
case CSSM_DL_DB_RECORD_PRIVATE_KEY:
header.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
break;
case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
header.KeyClass = CSSM_KEYCLASS_SESSION_KEY;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
DbAttributes attributes(mUniqueId->database());
attributes.recordType(mRecordType);
attributes.add(KeySchema::KeyClass); attributes.add(KeySchema::Permanent); attributes.add(KeySchema::Private); attributes.add(KeySchema::Modifiable); attributes.add(KeySchema::KeyCreator); attributes.add(KeySchema::KeyType); attributes.add(KeySchema::KeySizeInBits); attributes.add(KeySchema::StartDate); attributes.add(KeySchema::EndDate); attributes.add(KeySchema::Sensitive); attributes.add(KeySchema::AlwaysSensitive); attributes.add(KeySchema::Extractable); attributes.add(KeySchema::NeverExtractable); attributes.add(KeySchema::Encrypt); attributes.add(KeySchema::Decrypt); attributes.add(KeySchema::Derive); attributes.add(KeySchema::Sign); attributes.add(KeySchema::Verify); attributes.add(KeySchema::SignRecover); attributes.add(KeySchema::VerifyRecover); attributes.add(KeySchema::Wrap); attributes.add(KeySchema::Unwrap);
mUniqueId->get(&attributes, NULL);
if (mRecordType != uint32(attributes[0]))
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
header.AlgorithmId = attributes[5]; header.LogicalKeySizeInBits = attributes[6];
if (attributes[1]) header.setAttribute(CSSM_KEYATTR_PERMANENT);
if (attributes[2]) header.setAttribute(CSSM_KEYATTR_PRIVATE);
if (attributes[3]) header.setAttribute(CSSM_KEYATTR_MODIFIABLE);
if (attributes[9]) header.setAttribute(CSSM_KEYATTR_SENSITIVE);
if (attributes[11]) header.setAttribute(CSSM_KEYATTR_EXTRACTABLE);
if (attributes[10]) header.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE);
if (attributes[12]) header.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE);
if (attributes[13]) header.usage(CSSM_KEYUSE_ENCRYPT);
if (attributes[14]) header.usage(CSSM_KEYUSE_DECRYPT);
if (attributes[15]) header.usage(CSSM_KEYUSE_DERIVE);
if (attributes[16]) header.usage(CSSM_KEYUSE_SIGN);
if (attributes[17]) header.usage(CSSM_KEYUSE_VERIFY);
if (attributes[18]) header.usage(CSSM_KEYUSE_SIGN_RECOVER);
if (attributes[19]) header.usage(CSSM_KEYUSE_VERIFY_RECOVER);
if (attributes[20]) header.usage(CSSM_KEYUSE_WRAP);
if (attributes[21]) header.usage(CSSM_KEYUSE_UNWRAP);
if (header.usage() == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_DERIVE | CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER
| CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP))
header.usage(CSSM_KEYUSE_ANY);
if (!attributes[7].size() || !attributes[8].size())
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
header.StartDate = attributes[7].at<CSSM_DATE>(0);
header.EndDate = attributes[8].at<CSSM_DATE>(0);
makeReferenceKey(mAllocator, keyReference(), ioKey);
header.cspGuid(session.plugin.myGuid()); }
SSKey::~SSKey()
{
if (mKeyHandle != noKey)
clientSession().releaseKey(mKeyHandle);
}
void
SSKey::free(const AccessCredentials *accessCred, CssmKey &ioKey,
CSSM_BOOL deleteKey)
{
freeReferenceKey(mAllocator, ioKey);
if (deleteKey)
{
if (!mUniqueId || !mUniqueId->database())
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
mUniqueId->deleteRecord();
}
if (mKeyHandle != noKey)
{
clientSession().releaseKey(mKeyHandle);
mKeyHandle = noKey;
}
}
SecurityServer::ClientSession &
SSKey::clientSession()
{
return mClientSession;
}
KeyHandle SSKey::optionalKeyHandle() const
{
return mKeyHandle;
}
KeyHandle
SSKey::keyHandle()
{
if (mKeyHandle == noKey)
{
if (!mUniqueId || !mUniqueId->database())
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
CssmDataContainer blob(mAllocator);
mUniqueId->get(NULL, &blob);
CssmKey::Header dummyHeader; mKeyHandle =
clientSession().decodeKey(mUniqueId->database().dbHandle(), blob,
dummyHeader);
}
return mKeyHandle;
}
void
SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE &owner, Allocator &allocator)
{
clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner),
allocator);
}
void
SSKey::changeOwner(const AccessCredentials &accessCred,
const AclOwnerPrototype &newOwner)
{
clientSession().changeKeyOwner(keyHandle(), accessCred, newOwner);
didChangeAcl();
}
void
SSKey::getAcl(const char *selectionTag, uint32 &numberOfAclInfos,
AclEntryInfo *&aclInfos, Allocator &allocator)
{
clientSession().getKeyAcl(keyHandle(), selectionTag, numberOfAclInfos,
aclInfos, allocator);
}
void
SSKey::changeAcl(const AccessCredentials &accessCred, const AclEdit &aclEdit)
{
clientSession().changeKeyAcl(keyHandle(), accessCred, aclEdit);
didChangeAcl();
}
void
SSKey::didChangeAcl()
{
if (mUniqueId == true)
{
secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", (unsigned long)mKeyHandle);
CssmDataContainer keyBlob(mAllocator);
clientSession().encodeKey(keyHandle(), keyBlob);
mUniqueId->modify(mRecordType, NULL, &keyBlob, CSSM_DB_MODIFY_ATTRIBUTE_NONE);
}
else
{
secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", (unsigned long)mKeyHandle);
}
}