#include <security_cdsa_plugin/CSPsession.h>
#include <security_cdsa_plugin/cssmplugin.h>
#include <security_cdsa_utilities/cssmbridge.h>
typedef CSPFullPluginSession::CSPContext CSPContext;
CSPPluginSession::PluginContext::~PluginContext()
{ }
CSPFullPluginSession::AlgorithmFactory::~AlgorithmFactory()
{ }
CssmData CSPFullPluginSession::makeBuffer(size_t size, Allocator &alloc)
{
return CssmData(alloc.malloc(size), size);
}
inline size_t CSPFullPluginSession::totalBufferSize(const CssmData *data, uint32 count)
{
size_t size = 0;
for (uint32 n = 0; n < count; n++)
size += data[n].length();
return size;
}
bool CSPPluginSession::PluginContext::changed(const Context &context)
{
return false; }
CSPContext *CSPFullPluginSession::init(CSSM_CC_HANDLE ccHandle,
CSSM_CONTEXT_TYPE type,
const Context &context, bool encoding)
{
CSPContext *ctx = getContext<CSPContext>(ccHandle);
checkOperation(context.type(), type);
setupContext(ctx, context, encoding);
assert(ctx != NULL); ctx->mType = context.type();
ctx->mDirection = encoding;
setContext(ccHandle, ctx);
ctx->init(context, encoding);
return ctx;
}
CSPContext *CSPFullPluginSession::getStagedContext(CSSM_CC_HANDLE ccHandle,
CSSM_CONTEXT_TYPE type, bool encoding)
{
CSPContext *ctx = getContext<CSPContext>(ccHandle);
if (ctx == NULL)
CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT); checkOperation(ctx->type(), type);
if (ctx->encoding() != encoding)
CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
return ctx;
}
void CSPFullPluginSession::checkOperation(CSSM_CONTEXT_TYPE ctxType, CSSM_CONTEXT_TYPE opType)
{
switch (opType) {
case CSSM_ALGCLASS_NONE: return;
case CSSM_ALGCLASS_CRYPT: if (ctxType == CSSM_ALGCLASS_SYMMETRIC ||
ctxType == CSSM_ALGCLASS_ASYMMETRIC)
return;
default: if (ctxType == opType)
return;
}
CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
}
void CSPContext::init(const Context &context, bool encoding)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
void CSPContext::update(const CssmData &data)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
void CSPContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
void CSPContext::final(CssmData &out)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
void CSPContext::final(const CssmData &in)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
void CSPContext::generate(const Context &, CssmKey &pubKey, CssmKey &privKey)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
void CSPContext::generate(const Context &, uint32, CssmData ¶ms,
uint32 &attrCount, Context::Attr * &attrs)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
size_t CSPContext::inputSize(size_t outSize)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
size_t CSPContext::outputSize(bool final, size_t inSize)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
void CSPContext::minimumProgress(size_t &in, size_t &out)
{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
CSPFullPluginSession::CSPContext *CSPContext::clone(Allocator &)
{ CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); }
void CSPContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg)
{ CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); }
void CSPContext::update(const CssmData *in,
uint32 inCount, Writer &writer)
{
const CssmData *lastIn = in + inCount;
CssmData current;
for (;;) {
if (current.length() == 0) {
if (in == lastIn)
return; current = *in++;
continue; }
void *outP; size_t outSize;
writer.nextBlock(outP, outSize);
size_t inSize = inputSize(outSize);
if (inSize > current.length())
inSize = current.length(); if (inSize > 0) {
update(current.data(), inSize, outP, outSize);
current.use(inSize);
writer.use(outSize);
} else {
size_t minOutput;
minimumProgress(inSize, minOutput);
assert(minOutput > outSize); char splitBuffer[128];
assert(minOutput <= sizeof(splitBuffer)); outSize = sizeof(splitBuffer);
if (current.length() < inSize)
inSize = current.length(); update(current.data(), inSize, splitBuffer, outSize);
assert(inSize > 0); writer.put(splitBuffer, outSize); current.use(inSize);
}
}
}
void CSPContext::final(CssmData &out, Allocator &alloc)
{
size_t needed = outputSize(true, 0);
if (out) {
if (out.length() < needed)
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
} else {
out = makeBuffer(needed, alloc);
}
final(out);
}
void CSPContext::final(Writer &writer, Allocator &alloc)
{
if (size_t needed = outputSize(true, 0)) {
writer.allocate(needed, alloc);
void *addr; size_t size;
writer.nextBlock(addr, size); if (needed <= size) { CssmData chunk(addr, size);
final(chunk);
writer.use(chunk.length());
} else { char splitBuffer[128];
assert(needed <= sizeof(splitBuffer));
CssmData chunk(splitBuffer, sizeof(splitBuffer));
final(chunk);
writer.put(chunk.data(), chunk.length());
}
}
}
CSPPluginSession::PluginContext *
CSPPluginSession::contextCreate(CSSM_CC_HANDLE, const Context &)
{
return NULL; }
void CSPPluginSession::contextUpdate(CSSM_CC_HANDLE ccHandle,
const Context &context, PluginContext * &ctx)
{
if (ctx && !ctx->changed(context)) {
delete ctx;
ctx = NULL;
}
}
void CSPPluginSession::contextDelete(CSSM_CC_HANDLE, const Context &, PluginContext *)
{
}
void CSPPluginSession::EventNotify(CSSM_CONTEXT_EVENT event,
CSSM_CC_HANDLE ccHandle, const Context &context)
{
switch (event) {
case CSSM_CONTEXT_EVENT_CREATE:
if (PluginContext *ctx = contextCreate(ccHandle, context)) {
StLock<Mutex> _(contextMapLock);
assert(contextMap[ccHandle] == NULL); contextMap[ccHandle] = ctx;
}
break;
case CSSM_CONTEXT_EVENT_UPDATE:
{
StLock<Mutex> _(contextMapLock);
contextUpdate(ccHandle, context, contextMap[ccHandle]);
}
break;
case CSSM_CONTEXT_EVENT_DELETE:
{
StLock<Mutex> _(contextMapLock);
if (PluginContext *ctx = contextMap[ccHandle]) {
contextDelete(ccHandle, context, ctx);
delete ctx;
}
contextMap.erase(ccHandle);
}
break;
default:
CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
}
void CSPFullPluginSession::getKeySize(const CssmKey &key, CSSM_KEY_SIZE &size)
{ unimplemented(); }
void CSPFullPluginSession::EncryptData(CSSM_CC_HANDLE ccHandle,
const Context &context,
const CssmData clearBufs[],
uint32 clearBufCount,
CssmData cipherBufs[],
uint32 cipherBufCount,
CSSM_SIZE &bytesEncrypted,
CssmData &remData,
CSSM_PRIVILEGE privilege)
{
Writer writer(cipherBufs, cipherBufCount, &remData);
CSPContext *ctx = init(ccHandle, CSSM_ALGCLASS_CRYPT, context, true);
size_t outNeeded = ctx->outputSize(true, totalBufferSize(clearBufs, clearBufCount));
writer.allocate(outNeeded, *this);
ctx->update(clearBufs, clearBufCount, writer);
ctx->final(writer, *this);
bytesEncrypted = writer.close();
}
void CSPFullPluginSession::EncryptDataInit(CSSM_CC_HANDLE ccHandle,
const Context &context,
CSSM_PRIVILEGE Privilege)
{
init(ccHandle, CSSM_ALGCLASS_CRYPT, context, true);
}
void CSPFullPluginSession::EncryptDataUpdate(CSSM_CC_HANDLE ccHandle,
const CssmData clearBufs[],
uint32 clearBufCount,
CssmData cipherBufs[],
uint32 cipherBufCount,
CSSM_SIZE &bytesEncrypted)
{
CSPContext *alg = getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, true);
Writer writer(cipherBufs, cipherBufCount);
size_t outNeeded = alg->outputSize(false, totalBufferSize(clearBufs, clearBufCount));
writer.allocate(outNeeded, *this);
alg->update(clearBufs, clearBufCount, writer);
bytesEncrypted = writer.close();
}
void CSPFullPluginSession::EncryptDataFinal(CSSM_CC_HANDLE ccHandle,
CssmData &remData)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, true)->final(remData, *this);
}
void CSPFullPluginSession::DecryptData(CSSM_CC_HANDLE ccHandle,
const Context &context,
const CssmData cipherBufs[],
uint32 cipherBufCount,
CssmData clearBufs[],
uint32 clearBufCount,
CSSM_SIZE &bytesDecrypted,
CssmData &remData,
CSSM_PRIVILEGE privilege)
{
Writer writer(clearBufs, clearBufCount, &remData);
CSPContext *ctx = init(ccHandle, CSSM_ALGCLASS_CRYPT, context, false);
size_t outNeeded = ctx->outputSize(true, totalBufferSize(cipherBufs, cipherBufCount));
writer.allocate(outNeeded, *this);
ctx->update(cipherBufs, cipherBufCount, writer);
ctx->final(writer, *this);
bytesDecrypted = writer.close();
}
void CSPFullPluginSession::DecryptDataInit(CSSM_CC_HANDLE ccHandle,
const Context &context,
CSSM_PRIVILEGE Privilege)
{
init(ccHandle, CSSM_ALGCLASS_CRYPT, context, false);
}
void CSPFullPluginSession::DecryptDataUpdate(CSSM_CC_HANDLE ccHandle,
const CssmData cipherBufs[],
uint32 cipherBufCount,
CssmData clearBufs[],
uint32 clearBufCount,
CSSM_SIZE &bytesDecrypted)
{
CSPContext *ctx = getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, false);
Writer writer(clearBufs, clearBufCount);
size_t outNeeded = ctx->outputSize(false, totalBufferSize(cipherBufs, cipherBufCount));
writer.allocate(outNeeded, *this);
ctx->update(cipherBufs, cipherBufCount, writer);
bytesDecrypted = writer.close();
}
void CSPFullPluginSession::DecryptDataFinal(CSSM_CC_HANDLE ccHandle,
CssmData &remData)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, false)->final(remData, *this);
}
void CSPFullPluginSession::QuerySize(CSSM_CC_HANDLE ccHandle,
const Context &context,
CSSM_BOOL encrypt,
uint32 querySizeCount,
QuerySizeData *dataBlock)
{
if (querySizeCount == 0)
return; CSPContext *ctx = getContext<CSPContext>(ccHandle); if (ctx == NULL) ctx = init(ccHandle, context.type(), context, encrypt);
for (uint32 n = 0; n < querySizeCount; n++) {
dataBlock[n].SizeOutputBlock =
(uint32)ctx->outputSize(n == querySizeCount-1, dataBlock[n].inputSize());
}
}
void CSPFullPluginSession::WrapKey(CSSM_CC_HANDLE CCHandle,
const Context &Context,
const AccessCredentials &AccessCred,
const CssmKey &Key,
const CssmData *DescriptiveData,
CssmKey &WrappedKey,
CSSM_PRIVILEGE Privilege)
{
unimplemented();
}
void CSPFullPluginSession::UnwrapKey(CSSM_CC_HANDLE CCHandle,
const Context &Context,
const CssmKey *PublicKey,
const CssmKey &WrappedKey,
uint32 KeyUsage,
uint32 KeyAttr,
const CssmData *KeyLabel,
const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
CssmKey &UnwrappedKey,
CssmData &DescriptiveData,
CSSM_PRIVILEGE Privilege)
{
unimplemented();
}
void CSPFullPluginSession::DeriveKey(CSSM_CC_HANDLE CCHandle,
const Context &Context,
CssmData &Param,
uint32 KeyUsage,
uint32 KeyAttr,
const CssmData *KeyLabel,
const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
CssmKey &DerivedKey)
{
unimplemented();
}
void CSPFullPluginSession::GenerateMac(CSSM_CC_HANDLE ccHandle,
const Context &context,
const CssmData dataBufs[],
uint32 dataBufCount,
CssmData &mac)
{
GenerateMacInit(ccHandle, context);
GenerateMacUpdate(ccHandle, dataBufs, dataBufCount);
GenerateMacFinal(ccHandle, mac);
}
void CSPFullPluginSession::GenerateMacInit(CSSM_CC_HANDLE ccHandle,
const Context &context)
{
init(ccHandle, CSSM_ALGCLASS_MAC, context, true);
}
void CSPFullPluginSession::GenerateMacUpdate(CSSM_CC_HANDLE ccHandle,
const CssmData dataBufs[],
uint32 dataBufCount)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, true)->update(dataBufs, dataBufCount);
}
void CSPFullPluginSession::GenerateMacFinal(CSSM_CC_HANDLE ccHandle,
CssmData &mac)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, true)->final(mac, *this);
}
void CSPFullPluginSession::VerifyMac(CSSM_CC_HANDLE ccHandle,
const Context &context,
const CssmData dataBufs[],
uint32 dataBufCount,
const CssmData &mac)
{
VerifyMacInit(ccHandle, context);
VerifyMacUpdate(ccHandle, dataBufs, dataBufCount);
VerifyMacFinal(ccHandle, mac);
}
void CSPFullPluginSession::VerifyMacInit(CSSM_CC_HANDLE ccHandle,
const Context &context)
{
init(ccHandle, CSSM_ALGCLASS_MAC, context, false);
}
void CSPFullPluginSession::VerifyMacUpdate(CSSM_CC_HANDLE ccHandle,
const CssmData dataBufs[],
uint32 dataBufCount)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, false)->update(dataBufs, dataBufCount);
}
void CSPFullPluginSession::VerifyMacFinal(CSSM_CC_HANDLE ccHandle,
const CssmData &mac)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, false)->final(mac);
}
void CSPFullPluginSession::SignData(CSSM_CC_HANDLE ccHandle,
const Context &context,
const CssmData dataBufs[],
uint32 dataBufCount,
CSSM_ALGORITHMS digestAlgorithm,
CssmData &Signature)
{
SignDataInit(ccHandle, context);
if(digestAlgorithm != CSSM_ALGID_NONE) {
getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE,
true)->setDigestAlgorithm(digestAlgorithm);
}
SignDataUpdate(ccHandle, dataBufs, dataBufCount);
SignDataFinal(ccHandle, Signature);
}
void CSPFullPluginSession::SignDataInit(CSSM_CC_HANDLE ccHandle,
const Context &context)
{
init(ccHandle, CSSM_ALGCLASS_SIGNATURE, context, true);
}
void CSPFullPluginSession::SignDataUpdate(CSSM_CC_HANDLE ccHandle,
const CssmData dataBufs[],
uint32 dataBufCount)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, true)->update(dataBufs, dataBufCount);
}
void CSPFullPluginSession::SignDataFinal(CSSM_CC_HANDLE ccHandle,
CssmData &signature)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, true)->final(signature, *this);
}
void CSPFullPluginSession::VerifyData(CSSM_CC_HANDLE ccHandle,
const Context &context,
const CssmData dataBufs[],
uint32 dataBufCount,
CSSM_ALGORITHMS digestAlgorithm,
const CssmData &Signature)
{
VerifyDataInit(ccHandle, context);
if(digestAlgorithm != CSSM_ALGID_NONE) {
getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE,
false)->setDigestAlgorithm(digestAlgorithm);
}
VerifyDataUpdate(ccHandle, dataBufs, dataBufCount);
VerifyDataFinal(ccHandle, Signature);
}
void CSPFullPluginSession::VerifyDataInit(CSSM_CC_HANDLE ccHandle, const Context &context)
{
init(ccHandle, CSSM_ALGCLASS_SIGNATURE, context, false);
}
void CSPFullPluginSession::VerifyDataUpdate(CSSM_CC_HANDLE ccHandle,
const CssmData dataBufs[],
uint32 dataBufCount)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, false)->update(dataBufs, dataBufCount);
}
void CSPFullPluginSession::VerifyDataFinal(CSSM_CC_HANDLE ccHandle,
const CssmData &signature)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, false)->final(signature);
}
void CSPFullPluginSession::DigestData(CSSM_CC_HANDLE ccHandle,
const Context &context,
const CssmData dataBufs[],
uint32 DataBufCount,
CssmData &Digest)
{
DigestDataInit(ccHandle, context);
DigestDataUpdate(ccHandle, dataBufs, DataBufCount);
DigestDataFinal(ccHandle, Digest);
}
void CSPFullPluginSession::DigestDataInit(CSSM_CC_HANDLE ccHandle, const Context &context)
{
init(ccHandle, CSSM_ALGCLASS_DIGEST, context);
}
void CSPFullPluginSession::DigestDataUpdate(CSSM_CC_HANDLE ccHandle,
const CssmData dataBufs[],
uint32 dataBufCount)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->update(dataBufs, dataBufCount);
}
void CSPFullPluginSession::DigestDataFinal(CSSM_CC_HANDLE ccHandle,
CssmData &digest)
{
getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->final(digest, *this);
}
void CSPFullPluginSession::DigestDataClone(CSSM_CC_HANDLE ccHandle,
CSSM_CC_HANDLE clonedCCHandle)
{
CSPContext *cloned = getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->clone(*this);
cloned->mDirection = true;
cloned->mType = CSSM_ALGCLASS_DIGEST;
setContext(clonedCCHandle, cloned);
}
void CSPFullPluginSession::GenerateKey(CSSM_CC_HANDLE ccHandle,
const Context &context,
uint32 keyUsage,
uint32 keyAttr,
const CssmData *keyLabel,
const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
CssmKey &key,
CSSM_PRIVILEGE privilege)
{
CSPContext *alg = init(ccHandle, CSSM_ALGCLASS_KEYGEN, context);
setKey(key, context, CSSM_KEYCLASS_SESSION_KEY, keyAttr, keyUsage);
CssmKey blank; alg->generate(context, key, blank);
}
class ContextMinder
{
private:
CSSM_CC_HANDLE mHandle;
public:
ContextMinder(CSSM_CC_HANDLE ccHandle) : mHandle(ccHandle) {}
~ContextMinder() {CSSM_DeleteContext(mHandle);}
};
void CSPFullPluginSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle,
const Context &context,
uint32 publicKeyUsage,
uint32 publicKeyAttr,
const CssmData *publicKeyLabel,
CssmKey &publicKey,
uint32 privateKeyUsage,
uint32 privateKeyAttr,
const CssmData *privateKeyLabel,
const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
CssmKey &privateKey,
CSSM_PRIVILEGE privilege)
{
CSPContext *alg = init(ccHandle, CSSM_ALGCLASS_KEYGEN, context);
setKey(publicKey, context, CSSM_KEYCLASS_PUBLIC_KEY, publicKeyAttr, publicKeyUsage);
setKey(privateKey, context, CSSM_KEYCLASS_PRIVATE_KEY, privateKeyAttr, privateKeyUsage);
alg->generate(context, publicKey, privateKey);
bool encryptPublic = publicKeyUsage & CSSM_KEYUSE_ENCRYPT;
bool encryptPrivate = privateKeyUsage & CSSM_KEYUSE_ENCRYPT;
if (!(encryptPublic || encryptPrivate))
{
return ;
}
CSSM_CSP_HANDLE moduleHandle = handle();
CSSM_CC_HANDLE encryptHandle;
CSSM_ACCESS_CREDENTIALS nullCreds;
memset(&nullCreds, 0, sizeof(nullCreds));
CSSM_KEY_PTR encryptingKey, decryptingKey;
if (encryptPublic)
{
encryptingKey = &publicKey;
decryptingKey = &privateKey;
}
else
{
encryptingKey = &privateKey;
decryptingKey = &publicKey;
}
unsigned bytesInKey = encryptingKey->KeyHeader.LogicalKeySizeInBits / 8;
u_int8_t *buffer = (u_int8_t*)malloc(bytesInKey);
if (buffer == NULL) {
CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
}
unsigned i;
for (i = 0; i < bytesInKey; ++i)
{
buffer[i] = i;
}
CSSM_DATA clearBuf = {bytesInKey, buffer};
CSSM_DATA cipherBuf; CSSM_SIZE bytesEncrypted;
CSSM_DATA remData = {0, NULL};
CSSM_DATA decryptedBuf = {bytesInKey, buffer};
CSSM_RETURN result = CSSM_CSP_CreateAsymmetricContext(moduleHandle, encryptingKey->KeyHeader.AlgorithmId, &nullCreds, encryptingKey, CSSM_PADDING_NONE, &encryptHandle);
if (result != CSSM_OK)
{
free(buffer);
CssmError::throwMe(result);
}
ContextMinder encryptMinder(encryptHandle);
CSSM_QUERY_SIZE_DATA qsData;
qsData.SizeInputBlock = bytesInKey;
result = CSSM_QuerySize(encryptHandle, CSSM_TRUE, 1, &qsData);
if (result == CSSMERR_CSP_INVALID_ALGORITHM)
{
free(buffer);
return;
}
uint8 cipherBuffer[qsData.SizeOutputBlock];
cipherBuf.Length = qsData.SizeOutputBlock;
cipherBuf.Data = cipherBuffer;
result = CSSM_EncryptData(encryptHandle, &clearBuf, 1, &cipherBuf, 1, &bytesEncrypted, &remData);
if (result != CSSM_OK)
{
free(buffer);
CssmError::throwMe(result);
}
if (memcmp(cipherBuf.Data, clearBuf.Data, clearBuf.Length) == 0)
{
abort();
}
if (remData.Data != NULL)
{
free(remData.Data);
}
CSSM_CC_HANDLE decryptHandle;
result = CSSM_CSP_CreateAsymmetricContext(moduleHandle, encryptingKey->KeyHeader.AlgorithmId, &nullCreds, decryptingKey, CSSM_PADDING_NONE, &decryptHandle);
ContextMinder decryptMinder(decryptHandle);
if (result != CSSM_OK)
{
free(buffer);
CssmError::throwMe(result);
}
result = CSSM_DecryptData(decryptHandle, &cipherBuf, 1, &decryptedBuf, 1, &bytesEncrypted, &remData);
if (result != CSSM_OK)
{
free(buffer);
CssmError::throwMe(result);
}
for (i = 0; i < bytesInKey; ++i)
{
if (decryptedBuf.Data[i] != (i & 0xFF))
{
abort();
}
}
if (remData.Data != NULL)
{
free(remData.Data);
}
free(buffer);
}
void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
CssmKey &PrivateKey)
{
unimplemented();
}
void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle,
const Context *context,
const CssmKey *key,
CSSM_KEY_SIZE &keySize)
{
if (context) {
getKeySize(context->get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY),
keySize);
} else {
getKeySize(CssmKey::required(key), keySize);
}
}
void CSPFullPluginSession::FreeKey(const AccessCredentials *AccessCred,
CssmKey &key,
CSSM_BOOL Delete)
{
free(key.data());
}
void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
const Context &context,
CssmData &randomNumber)
{
init(ccHandle, CSSM_ALGCLASS_RANDOMGEN, context)->final(randomNumber, *this);
}
void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle,
const Context &context,
uint32 paramBits,
CssmData ¶m,
uint32 &attrCount,
CSSM_CONTEXT_ATTRIBUTE_PTR &attrs)
{
Context::Attr *attrList;
init(ccHandle, CSSM_ALGCLASS_NONE, context)->generate(context, paramBits,
param, attrCount, attrList);
attrs = attrList;
}
void CSPFullPluginSession::Login(const AccessCredentials &AccessCred,
const CssmData *LoginName,
const void *Reserved)
{
if (Reserved != NULL)
CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME);
}
void CSPFullPluginSession::Logout()
{
if (!loggedIn(false))
CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN);
}
void CSPFullPluginSession::VerifyDevice(const CssmData &DeviceCert)
{
CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
}
void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
{
memset(&statistics, 0, sizeof(statistics));
statistics.UserAuthenticated = loggedIn();
}
void CSPFullPluginSession::RetrieveCounter(CssmData &Counter)
{
unimplemented();
}
void CSPFullPluginSession::RetrieveUniqueId(CssmData &UniqueID)
{
unimplemented();
}
void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
{
unimplemented();
}
void CSPFullPluginSession::GetKeyOwner(const CssmKey &Key,
CSSM_ACL_OWNER_PROTOTYPE &Owner)
{
unimplemented();
}
void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
const CssmKey &Key,
const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
{
unimplemented();
}
void CSPFullPluginSession::GetKeyAcl(const CssmKey &Key,
const CSSM_STRING *SelectionTag,
uint32 &NumberOfAclInfos,
CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
{
unimplemented();
}
void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
const CSSM_ACL_EDIT &AclEdit,
const CssmKey &Key)
{
unimplemented();
}
void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
{
unimplemented();
}
void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
{
unimplemented();
}
void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
uint32 &NumberOfAclInfos,
CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
{
unimplemented();
}
void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
const CSSM_ACL_EDIT &AclEdit)
{
unimplemented();
}
void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle,
const Context &Context,
uint32 PassThroughId,
const void *InData,
void **OutData)
{
unimplemented();
}
KeyPool::KeyPool()
{
}
KeyPool::~KeyPool()
{
StLock<Mutex> _(mKeyMapLock);
KeyMap::iterator end = mKeyMap.end();
for (KeyMap::iterator it = mKeyMap.begin(); it != end; ++it)
{
try
{
it->second->deactivate();
}
catch(...) {}
delete it->second;
}
mKeyMap.clear();
}
void
KeyPool::add(ReferencedKey &referencedKey)
{
StLock<Mutex> _(mKeyMapLock);
bool inserted;
inserted = mKeyMap.insert(KeyMap::value_type(referencedKey.keyReference(), &referencedKey)).second;
assert(inserted);
secinfo("SecAccessReference", "added a referenced key %p for key reference %ld", &referencedKey, referencedKey.keyReference());
}
ReferencedKey &
KeyPool::findKey(const CSSM_KEY &key) const
{
return findKeyReference(ReferencedKey::keyReference(key));
}
ReferencedKey &
KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference) const
{
StLock<Mutex> _(mKeyMapLock);
KeyMap::const_iterator it = mKeyMap.find(keyReference);
if (it == mKeyMap.end())
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
secinfo("SecAccessReference", "found a referenced key %p for key reference %ld [%ld]", it->second, keyReference, it->second->keyReference());
return *it->second;
}
void
KeyPool::erase(ReferencedKey &referencedKey)
{
erase(referencedKey.keyReference());
}
ReferencedKey &
KeyPool::erase(ReferencedKey::KeyReference keyReference)
{
StLock<Mutex> _(mKeyMapLock);
KeyMap::iterator it = mKeyMap.find(keyReference);
if (it == mKeyMap.end())
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
ReferencedKey &referencedKey = *it->second;
mKeyMap.erase(it);
return referencedKey;
}
void
KeyPool::freeKey(Allocator &allocator, CSSM_KEY &ioKey)
{
delete &erase(ReferencedKey::freeReferenceKey(allocator, ioKey));
}
ReferencedKey::ReferencedKey(KeyPool &keyPool) : mKeyPool(&keyPool)
{
mKeyPool->add(*this);
}
ReferencedKey::~ReferencedKey()
{
if (isActive())
mKeyPool->erase(*this);
}
ReferencedKey::KeyReference
ReferencedKey::keyReference()
{
return reinterpret_cast<ReferencedKey::KeyReference>(this);
}
void
ReferencedKey::makeReferenceKey(Allocator &allocator, KeyReference keyReference, CSSM_KEY &key)
{
key.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE;
key.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER;
key.KeyData.Length = sizeof(KeyReference);
key.KeyData.Data = allocator.alloc<uint8>(sizeof(KeyReference));
uint8 *cp = key.KeyData.Data;
for (int i = sizeof(KeyReference); --i >= 0;)
{
cp[i] = keyReference & 0xff;
keyReference = keyReference >> 8;
}
}
ReferencedKey::KeyReference
ReferencedKey::keyReference(const CSSM_KEY &key)
{
if (key.KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE
|| key.KeyHeader.Format != CSSM_KEYBLOB_REF_FORMAT_INTEGER
|| key.KeyData.Length != sizeof(KeyReference)
|| key.KeyData.Data == NULL)
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
const uint8 *cp = key.KeyData.Data;
KeyReference keyReference = 0;
for (uint32 i = 0; i < sizeof(KeyReference); ++i)
keyReference = (keyReference << 8) + cp[i];
return keyReference;
}
ReferencedKey::KeyReference
ReferencedKey::freeReferenceKey(Allocator &allocator, CSSM_KEY &key)
{
KeyReference aKeyReference = keyReference(key);
allocator.free(key.KeyData.Data);
key.KeyData.Data = NULL;
key.KeyData.Length = 0;
return aKeyReference;
}