-/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-//
-// CSPsession - Plugin framework for CSP plugin modules
-//
-#include <security_cdsa_plugin/CSPsession.h>
-#include <security_cdsa_plugin/cssmplugin.h>
-#include <security_cdsa_utilities/cssmbridge.h>
-
-
-typedef CSPFullPluginSession::CSPContext CSPContext;
-
-
-//
-// PluginContext construction
-//
-CSPPluginSession::PluginContext::~PluginContext()
-{ /* virtual */ }
-
-CSPFullPluginSession::AlgorithmFactory::~AlgorithmFactory()
-{ /* virtual */ }
-
-
-//
-// Internal utilities
-//
-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;
-}
-
-
-//
-// Notify a context that its underlying CSSM context has (well, may have) changed.
-// The default reaction is to ask the frame to delete the context and start over.
-//
-bool CSPPluginSession::PluginContext::changed(const Context &context)
-{
- return false; // delete me, please
-}
-
-
-//
-// The Session's init() function calls your setupContext() method to prepare
-// it for action, then calls the context's init() method.
-//
-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);
-
- // ask the implementation to set up an internal context
- setupContext(ctx, context, encoding);
- assert(ctx != NULL); // must have context now (@@@ throw INTERNAL_ERROR instead?)
- ctx->mType = context.type();
- ctx->mDirection = encoding;
- setContext(ccHandle, ctx);
-
- // initialize the context and return it
- ctx->init(context, encoding);
- return ctx;
-}
-
-
-//
-// Retrieve a context for a staged operation in progress.
-//
-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); //@@@ better diagnostic?
- checkOperation(ctx->type(), type);
- if (ctx->encoding() != encoding)
- CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
- return ctx;
-}
-
-
-//
-// The Session's checkState() function is called for subsequent staged operations
-// (update/final) to verify that the user didn't screw up the sequencing.
-//
-void CSPFullPluginSession::checkOperation(CSSM_CONTEXT_TYPE ctxType, CSSM_CONTEXT_TYPE opType)
-{
- switch (opType) {
- case CSSM_ALGCLASS_NONE: // no check
- return;
- case CSSM_ALGCLASS_CRYPT: // symmetric or asymmetric encryption
- if (ctxType == CSSM_ALGCLASS_SYMMETRIC ||
- ctxType == CSSM_ALGCLASS_ASYMMETRIC)
- return;
- default: // plain match
- if (ctxType == opType)
- return;
- }
- CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
-}
-
-
-//
-// The default implementations of the primary context operations throw internal
-// errors. You must implement any of these that are actually called by the
-// operations involved. The others, of course, can be left alone.
-//
-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; // all done
- current = *in++;
- continue; // Just in case next block is zero length too.
- }
- // match up current input and output buffers
- void *outP; size_t outSize;
- writer.nextBlock(outP, outSize);
- size_t inSize = inputSize(outSize);
- if (inSize > current.length())
- inSize = current.length(); // cap to remaining input buffer
- if (inSize > 0) {
- // we can stuff into the current output buffer - do it
- update(current.data(), inSize, outP, outSize);
- current.use(inSize);
- writer.use(outSize);
- } else {
- // We have remaining output buffer space, but not enough
- // for the algorithm to make progress with it. We must proceed with
- // a bounce buffer and split it manually into this and the next buffer(s).
- size_t minOutput;
- minimumProgress(inSize, minOutput);
- assert(minOutput > outSize); // PluginContext consistency (not fatal)
- char splitBuffer[128];
- assert(minOutput <= sizeof(splitBuffer)); // @@@ static buffer for now
- outSize = sizeof(splitBuffer);
- if (current.length() < inSize)
- inSize = current.length(); // cap to data remaining in input buffer
- update(current.data(), inSize, splitBuffer, outSize);
- assert(inSize > 0); // progress made
- writer.put(splitBuffer, outSize); // stuff into buffer, the hard way
- 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)) {
- // need to generate additional output
- writer.allocate(needed, alloc); // belt + suspender
-
- void *addr; size_t size;
- writer.nextBlock(addr, size); // next single block available
- if (needed <= size) { // rest fits into one block
- CssmData chunk(addr, size);
- final(chunk);
- writer.use(chunk.length());
- } else { // need to split it up
- char splitBuffer[128];
- assert(needed <= sizeof(splitBuffer));
- CssmData chunk(splitBuffer, sizeof(splitBuffer));
- final(chunk);
- writer.put(chunk.data(), chunk.length());
- }
- }
-}
-
-
-//
-// Default context response functions
-//
-CSPPluginSession::PluginContext *
-CSPPluginSession::contextCreate(CSSM_CC_HANDLE, const Context &)
-{
- return NULL; // request no local context
-}
-
-void CSPPluginSession::contextUpdate(CSSM_CC_HANDLE ccHandle,
- const Context &context, PluginContext * &ctx)
-{
- // call update notifier in context object
- if (ctx && !ctx->changed(context)) {
- // context requested that it be removed
- delete ctx;
- ctx = NULL;
- }
-}
-
-void CSPPluginSession::contextDelete(CSSM_CC_HANDLE, const Context &, PluginContext *)
-{
- // do nothing (you can't prohibit deletion here)
-}
-
-
-//
-// Default event notification handler.
-// This default handler calls the virtual context* methods to dispose of context actions.
-//
-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); // check context re-creation
- contextMap[ccHandle] = ctx;
- }
- break;
- case CSSM_CONTEXT_EVENT_UPDATE:
- // note that the handler can change the map entry (even to NULL, if desired)
- {
- 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); // unexpected event code
- }
-}
-
-
-//
-// Defaults for methods you *should* implement.
-// If you don't, they'll throw UNIMPLEMENTED.
-//
-void CSPFullPluginSession::getKeySize(const CssmKey &key, CSSM_KEY_SIZE &size)
-{ unimplemented(); }
-
-
-//
-// Encryption and decryption
-//
-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; // nothing ventured, nothing gained
- CSPContext *ctx = getContext<CSPContext>(ccHandle); // existing context?
- if (ctx == NULL) // force internal context creation (as best we can)
- ctx = init(ccHandle, context.type(), context, encrypt);
- // If QuerySizeCount > 1, we assume this inquires about a staged
- // operation, and the LAST item gets the 'final' treatment.
- //@@@ Intel revised algspec says "use the staged flag" -- TBD
- for (uint32 n = 0; n < querySizeCount; n++) {
- // the outputSize() call might throw CSSMERR_CSP_QUERY_SIZE_UNKNOWN
- dataBlock[n].SizeOutputBlock =
- (uint32)ctx->outputSize(n == querySizeCount-1, dataBlock[n].inputSize());
- }
- //@@@ if we forced a context creation, should we discard it now?
-}
-
-
-//
-// Key wrapping and unwrapping.
-//
-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();
-}
-
-
-//
-// Message Authentication Codes.
-// Almost like signatures (signatures with symmetric keys), though the
-// underlying implementation may be somewhat different.
-//
-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);
-}
-
-
-//
-// Signatures
-//
-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);
-}
-
-
-//
-// Digesting
-//
-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);
-}
-
-
-//
-// Key generation, Derivation, and inquiry
-//
-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; // dummy 2nd key (not used)
- 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);
-
- //@@@ handle labels
- //@@@ handle reference keys
-
- bool encryptPublic = publicKeyUsage & CSSM_KEYUSE_ENCRYPT;
- bool encryptPrivate = privateKeyUsage & CSSM_KEYUSE_ENCRYPT;
-
- if (!(encryptPublic || encryptPrivate))
- {
- return ;
- }
-
- // time to do the FIPS required test!
- 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;
- }
-
- // make data to be encrypted
- unsigned bytesInKey = encryptingKey->KeyHeader.LogicalKeySizeInBits / 8;
- u_int8_t buffer[bytesInKey];
- unsigned i;
-
- for (i = 0; i < bytesInKey; ++i)
- {
- buffer[i] = i;
- }
-
- CSSM_DATA clearBuf = {bytesInKey, buffer};
- CSSM_DATA cipherBuf; // have the CSP allocate the resulting memory
- 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)
- {
- CssmError::throwMe(result);
- }
-
- ContextMinder encryptMinder(encryptHandle); // auto throw away if we error out
-
- CSSM_QUERY_SIZE_DATA qsData;
- qsData.SizeInputBlock = bytesInKey;
- result = CSSM_QuerySize(encryptHandle, CSSM_TRUE, 1, &qsData);
- if (result == CSSMERR_CSP_INVALID_ALGORITHM)
- {
- return;
- }
-
- uint8 cipherBuffer[qsData.SizeOutputBlock];
- cipherBuf.Length = qsData.SizeOutputBlock;
- cipherBuf.Data = cipherBuffer;
-
- // do the encryption
- result = CSSM_EncryptData(encryptHandle, &clearBuf, 1, &cipherBuf, 1, &bytesEncrypted, &remData);
- if (result != CSSM_OK)
- {
- CssmError::throwMe(result);
- }
-
- // check the result
- if (memcmp(cipherBuf.Data, clearBuf.Data, clearBuf.Length) == 0)
- {
- // we have a match, that's not good news...
- abort();
- }
-
- // clean up
- if (remData.Data != NULL)
- {
- free(remData.Data);
- }
-
- // make a context to perform the decryption
- 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)
- {
- CssmError::throwMe(result);
- }
-
- result = CSSM_DecryptData(decryptHandle, &cipherBuf, 1, &decryptedBuf, 1, &bytesEncrypted, &remData);
- if (result != CSSM_OK)
- {
- CssmError::throwMe(result);
- }
-
- // check the results
- for (i = 0; i < bytesInKey; ++i)
- {
- if (decryptedBuf.Data[i] != (i & 0xFF))
- {
- // bad news
- abort();
- }
- }
-
- if (remData.Data != NULL)
- {
- free(remData.Data);
- }
-}
-
-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);
- }
-}
-
-
-//
-// Free a key object.
-//
-void CSPFullPluginSession::FreeKey(const AccessCredentials *AccessCred,
- CssmKey &key,
- CSSM_BOOL Delete)
-{
- free(key.data());
-}
-
-
-//
-// Random number and parameter generation
-//
-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;
-}
-
-
-//
-// Login/Logout and token operational maintainance.
-// These mean little without support by the actual implementation, but we can help...
-// @@@ Should this be in CSP[non-Full]PluginSession?
-//
-void CSPFullPluginSession::Login(const AccessCredentials &AccessCred,
- const CssmData *LoginName,
- const void *Reserved)
-{
- if (Reserved != NULL)
- CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
-
- // default implementation refuses to log in
- //@@@ should hand it to implementation virtual defaulting to this
- 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();
- //@@@ collect device flags - capability matrix setup?
- //@@@ collect token limitation parameters (static) - capability matrix setup?
- //@@@ collect token statistics (dynamic) - dynamic accounting call-downs?
-}
-
-
-//
-// Utterly miscellaneous, rarely used, strange functions
-//
-void CSPFullPluginSession::RetrieveCounter(CssmData &Counter)
-{
- unimplemented();
-}
-
-void CSPFullPluginSession::RetrieveUniqueId(CssmData &UniqueID)
-{
- unimplemented();
-}
-
-void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
-{
- unimplemented();
-}
-
-
-//
-// ACL retrieval and change operations
-//
-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();
-}
-
-
-
-//
-// Passthroughs (by default, unimplemented)
-//
-void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle,
- const Context &Context,
- uint32 PassThroughId,
- const void *InData,
- void **OutData)
-{
- unimplemented();
-}
-
-
-//
-// KeyPool -- ReferencedKey management functionality
-//
-KeyPool::KeyPool()
-{
-}
-
-KeyPool::~KeyPool()
-{
- StLock<Mutex> _(mKeyMapLock);
- // Delete every ReferencedKey in the pool, but be careful to deactivate them first
- // to keep them from calling erase (which would cause deadlock since we already hold 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;
- // Since add is only called from the constructor of ReferencedKey we should
- // never add a key that is already in mKeyMap
- assert(inserted);
-}
-
-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);
-
- 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;
-}
-
-// Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
-void
-KeyPool::freeKey(Allocator &allocator, CSSM_KEY &ioKey)
-{
- delete &erase(ReferencedKey::freeReferenceKey(allocator, ioKey));
-}
-
-//
-// ReferencedKey class
-//
-ReferencedKey::ReferencedKey(KeyPool &keyPool) : mKeyPool(&keyPool)
-{
- mKeyPool->add(*this);
-}
-
-ReferencedKey::~ReferencedKey()
-{
- if (isActive())
- mKeyPool->erase(*this);
-}
-
-ReferencedKey::KeyReference
-ReferencedKey::keyReference()
-{
- // @@@ Possibly check isActive() and return an invalid reference if it is not set.
- return reinterpret_cast<ReferencedKey::KeyReference>(this);
-}
-
-//
-// Making, retrieving and freeing Key references of CssmKeys
-//
-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;
-}