+++ /dev/null
-/*
- * 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.
- */
-
-
-//
-// AppleCSP.cpp - top-level plugin and session implementation
-//
-#include "AppleCSP.h"
-#include "AppleCSPSession.h"
-#include "AppleCSPUtils.h"
-#include <stdio.h>
-#include "cspdebugging.h"
-#include <security_cdsa_plugin/CSPsession.h>
-#include <security_utilities/alloc.h>
-#ifdef BSAFE_CSP_ENABLE
-#include "bsafecsp.h"
-#include "bsafecspi.h"
-#endif
-#ifdef CRYPTKIT_CSP_ENABLE
-#include "cryptkitcsp.h"
-#include "FEEKeys.h"
-#endif
-#include <miscAlgFactory.h>
-#ifdef ASC_CSP_ENABLE
-#include "ascFactory.h"
-#endif
-#include <RSA_DSA_csp.h>
-#include <RSA_DSA_keys.h>
-#include <DH_csp.h>
-#include <DH_keys.h>
-
-#include "YarrowConnection.h"
-
-//
-// Make and break the plugin object
-//
-AppleCSPPlugin::AppleCSPPlugin() :
- normAllocator(Allocator::standard(Allocator::normal)),
- privAllocator(Allocator::standard(Allocator::sensitive)),
- #ifdef BSAFE_CSP_ENABLE
- bSafe4Factory(new BSafeFactory(&normAllocator, &privAllocator)),
- #endif
- #ifdef CRYPTKIT_CSP_ENABLE
- cryptKitFactory(new CryptKitFactory(&normAllocator, &privAllocator)),
- #endif
- miscAlgFactory(new MiscAlgFactory(&normAllocator, &privAllocator)),
- #ifdef ASC_CSP_ENABLE
- ascAlgFactory(new AscAlgFactory(&normAllocator, &privAllocator)),
- #endif
- rsaDsaAlgFactory(new RSA_DSA_Factory(&normAllocator, &privAllocator)),
- dhAlgFactory(new DH_Factory(&normAllocator, &privAllocator))
-{
- // misc. once-per-address-space cruft...
-}
-
-AppleCSPPlugin::~AppleCSPPlugin()
-{
- #ifdef BSAFE_CSP_ENABLE
- delete bSafe4Factory;
- #endif
- #ifdef CRYPTKIT_CSP_ENABLE
- delete cryptKitFactory;
- #endif
- delete miscAlgFactory;
- #ifdef ASC_CSP_ENABLE
- delete ascAlgFactory;
- #endif
- delete rsaDsaAlgFactory;
- delete dhAlgFactory;
-}
-
-
-//
-// Create a new plugin session, our way
-//
-PluginSession *AppleCSPPlugin::makeSession(
- CSSM_MODULE_HANDLE handle,
- const CSSM_VERSION &version,
- uint32 subserviceId,
- CSSM_SERVICE_TYPE subserviceType,
- CSSM_ATTACH_FLAGS attachFlags,
- const CSSM_UPCALLS &upcalls)
-{
- switch (subserviceType) {
- case CSSM_SERVICE_CSP:
- return new AppleCSPSession(handle,
- *this,
- version,
- subserviceId,
- subserviceType,
- attachFlags,
- upcalls);
- default:
- CssmError::throwMe(CSSMERR_CSSM_INVALID_SERVICE_MASK);
- return 0; // placebo
- }
-}
-
-
-//
-// Session constructor
-//
-AppleCSPSession::AppleCSPSession(
- CSSM_MODULE_HANDLE handle,
- AppleCSPPlugin &plug,
- const CSSM_VERSION &version,
- uint32 subserviceId,
- CSSM_SERVICE_TYPE subserviceType,
- CSSM_ATTACH_FLAGS attachFlags,
- const CSSM_UPCALLS &upcalls)
- : CSPFullPluginSession(handle,
- plug,
- version,
- subserviceId,
- subserviceType,
- attachFlags,
- upcalls),
- #ifdef BSAFE_CSP_ENABLE
- bSafe4Factory(*(dynamic_cast<BSafeFactory *>(plug.bSafe4Factory))),
- #endif
- #ifdef CRYPTKIT_CSP_ENABLE
- cryptKitFactory(*(dynamic_cast<CryptKitFactory *>(plug.cryptKitFactory))),
- #endif
- miscAlgFactory(*(dynamic_cast<MiscAlgFactory *>(plug.miscAlgFactory))),
- #ifdef ASC_CSP_ENABLE
- ascAlgFactory(*(dynamic_cast<AscAlgFactory *>(plug.ascAlgFactory))),
- #endif
- rsaDsaAlgFactory(*(dynamic_cast<RSA_DSA_Factory *>(plug.rsaDsaAlgFactory))),
- dhAlgFactory(*(dynamic_cast<DH_Factory *>(plug.dhAlgFactory))),
- normAllocator(*this),
- privAllocator(plug.privAlloc())
-{
- // anything?
-}
-
-AppleCSPSession::~AppleCSPSession()
-{
- // anything?
-}
-
-//
-// Called at (CSSM) context create time. This is ignored; we do a full
-// context setup later, at setupContext time.
-//
-CSPFullPluginSession::CSPContext *
-AppleCSPSession::contextCreate(
- CSSM_CC_HANDLE handle,
- const Context &context)
-{
- return NULL;
-}
-
-//
-// Called by CSPFullPluginSession when an op is actually commencing.
-// Context can safely assumed to be fully formed and stable for the
-// duration of the op; thus we wait until now to set up our
-// CSPContext as appropriate to the op.
-//
-void AppleCSPSession::setupContext(
- CSPContext * &cspCtx,
- const Context &context,
- bool encoding)
-{
- /*
- * Note we leave the decision as to whether it's OK to
- * reuse a context to the individual factories.
- */
- #ifdef BSAFE_CSP_ENABLE
- /* Give BSAFE the firsrt shot if it's present */
- if (bSafe4Factory.setup(*this, cspCtx, context)) {
- CASSERT(cspCtx != NULL);
- return;
- }
- #endif
- if (rsaDsaAlgFactory.setup(*this, cspCtx, context)) {
- CASSERT(cspCtx != NULL);
- return;
- }
- if (miscAlgFactory.setup(*this, cspCtx, context)) {
- CASSERT(cspCtx != NULL);
- return;
- }
- if (dhAlgFactory.setup(*this, cspCtx, context)) {
- CASSERT(cspCtx != NULL);
- return;
- }
- #ifdef CRYPTKIT_CSP_ENABLE
- if (cryptKitFactory.setup(*this, cspCtx, context)) {
- CASSERT(cspCtx != NULL);
- return;
- }
- #endif
- #ifdef ASC_CSP_ENABLE
- if (ascAlgFactory.setup(*this, cspCtx, context)) {
- CASSERT(cspCtx != NULL);
- return;
- }
- #endif
- if(setup(cspCtx, context)) {
- CASSERT(cspCtx != NULL);
- return;
- }
- dprintf0("AppleCSPSession::setupContext: invalid algorithm\n");
- CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
-}
-
-/*
- * Used for generating crypto contexts at this level.
- * Analogous to AlgorithmFactory.setup().
- */
-bool AppleCSPSession::setup(
- CSPFullPluginSession::CSPContext * &cspCtx,
- const Context &context)
-{
- if (cspCtx) {
- return false; // not ours or already set
- }
-
- switch(context.type()) {
- case CSSM_ALGCLASS_RANDOMGEN:
- switch (context.algorithm()) {
- case CSSM_ALGID_APPLE_YARROW:
- cspCtx = new YarrowContext(*this);
- return true;
- /* other random algs here */
- default:
- return false;
- }
- /* other contexts here */
- default:
- return false;
- }
- /* NOT REACHED */
- return false;
-
-}
-
-//
-// Context for CSSM_ALGID_APPLE_YARROW.
-//
-YarrowContext::YarrowContext(AppleCSPSession &session)
- : AppleCSPContext(session)
-{
- // nothing for now
-}
-
-YarrowContext::~YarrowContext()
-{
- // nothing for now
-}
-
-//
-// Only job here is to snag the length and process the optional seed argument
-//
-void YarrowContext::init(
- const Context &context,
- bool encoding)
-{
- /* stash requested length for use later in outputSize() */
- outSize = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE,
- CSSMERR_CSP_INVALID_ATTR_OUTPUT_SIZE);
-
- /* optional seed */
- CssmCryptoData *cseed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED);
- if(cseed == NULL) {
- /* we're done */
- return;
- }
- CssmData seed = (*cseed)();
- if((seed.Length == 0) ||
- (seed.Data == NULL)) {
- CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED);
- }
- session().addEntropy((size_t)seed.Length, seed.Data);
-}
-
-void YarrowContext::final(
- CssmData &out)
-{
- session().getRandomBytes((size_t)out.Length, out.Data);
-}
-
-/***
- *** Binary Key support.
- ***/
-
-// Given a CSSM_DATA, extract its KeyRef.
-static KeyRef CssmDataToKeyRef(
- const CSSM_DATA &data)
-{
- if(data.Length != sizeof(KeyRef)) {
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
- }
-
- uint8 *cp = data.Data + sizeof(KeyRef) - 1;
- KeyRef keyRef = 0;
- for(unsigned dex=0; dex<sizeof(KeyRef); dex++) {
- keyRef <<= 8;
- keyRef |= *cp--;
- }
- return keyRef;
-}
-
-// Place a KeyRef into a CSSM_DATA, mallocing if necessary.
-static void keyRefToCssmData(
- KeyRef keyRef,
- CSSM_DATA &data,
- Allocator &allocator)
-{
- if(data.Length > sizeof(keyRef)) {
- /* don't leave old raw key material lying around */
- memset(data.Data + sizeof(keyRef), 0, data.Length - sizeof(keyRef));
- }
- else if(data.Length < sizeof(keyRef)) {
- /* not enough space for even a keyRef, force realloc */
- allocator.free(data.Data);
- data.Data = NULL;
- data.Length = 0;
- }
- setUpData(data, sizeof(keyRef), allocator);
-
- uint8 *cp = data.Data;
- for(unsigned i=0; i<sizeof(keyRef); i++) {
- *cp++ = keyRef & 0xff;
- keyRef >>= 8;
- }
-}
-
-// Look up a BinaryKey by its KeyRef. Returns NULL if not
-// found. refKeyMapLock held on entry and exit.
-BinaryKey *AppleCSPSession::lookupKeyRef(
- KeyRef keyRef)
-{
- const BinaryKey *binKey;
-
- // use safe version, don't create new entry if this key
- // isn't there
- keyMap::iterator it = refKeyMap.find(keyRef);
- if(it == refKeyMap.end()) {
- return NULL;
- }
- binKey = it->second;
- assert(binKey == reinterpret_cast<const BinaryKey *>(keyRef));
- assert(binKey->mKeyRef == keyRef);
- return const_cast<BinaryKey *>(binKey);
-}
-
-// add a BinaryKey to our refKeyMap. Sets up cssmKey
-// as appropriate.
-void AppleCSPSession::addRefKey(
- BinaryKey &binKey,
- CssmKey &cssmKey)
-{
- // for now, KeyRef is just the address of the BinaryKey
- KeyRef keyRef = reinterpret_cast<KeyRef>(&binKey);
-
- binKey.mKeyRef = keyRef;
- binKey.mKeyHeader = CssmKey::Header::overlay(cssmKey.KeyHeader);
- {
- StLock<Mutex> _(refKeyMapLock);
- assert(lookupKeyRef(keyRef) == NULL);
- refKeyMap[keyRef] = &binKey;
- }
- cssmKey.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE;
- cssmKey.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER;
- keyRefToCssmData(keyRef, cssmKey.KeyData, normAllocator);
- secdebug("freeKey", "CSP addRefKey key %p keyData %p keyRef %p",
- &cssmKey, cssmKey.KeyData.Data, &binKey);
-}
-
-// Given a CssmKey in reference form, obtain the associated
-// BinaryKey. Throws CSSMERR_CSP_INVALID_KEY_REFERENCE if
-// key not found in session key map.
-BinaryKey & AppleCSPSession::lookupRefKey(
- const CssmKey &cssmKey)
-{
- KeyRef keyRef;
- BinaryKey *binKey;
-
- keyRef = CssmDataToKeyRef(cssmKey.KeyData);
- {
- StLock<Mutex> _(refKeyMapLock);
- binKey = lookupKeyRef(keyRef);
- }
- if(binKey == NULL) {
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
- }
- assert(Guid::overlay(binKey->mKeyHeader.CspId) == plugin.myGuid());
-
- /*
- * Verify sensitive fields have not changed between when the BinaryKey was
- * created/stored and when the caller passed in the ref key.
- * Some fields were changed by addRefKey, so make a local copy....
- */
- CSSM_KEYHEADER localHdr = cssmKey.KeyHeader;
- localHdr.BlobType = binKey->mKeyHeader.BlobType;
- localHdr.Format = binKey->mKeyHeader.Format;
- if(memcmp(&localHdr, &binKey->mKeyHeader, sizeof(CSSM_KEYHEADER))) {
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
- }
- return (*binKey);
-}
-
-// CSPFullPluginSession declares & implements this.
-// Note that we ignore the delete argument; since we don't
-// store anything, freeing is the same as deleting.
-void AppleCSPSession::FreeKey(
- const AccessCredentials *AccessCred,
- CssmKey &KeyPtr,
- CSSM_BOOL Delete)
-{
-
- if((KeyPtr.blobType() == CSSM_KEYBLOB_REFERENCE) &&
- (KeyPtr.cspGuid() == plugin.myGuid())) {
- // it's a ref key we generated - delete associated BinaryKey
- KeyRef keyRef = CssmDataToKeyRef(KeyPtr.KeyData);
- {
- StLock<Mutex> _(refKeyMapLock);
- BinaryKey *binKey = lookupKeyRef(keyRef);
- if(binKey != NULL) {
- secdebug("freeKey", "CSP FreeKey key %p keyData %p binKey %p",
- &KeyPtr, KeyPtr.KeyData.Data, binKey);
- try {
- refKeyMap.erase(keyRef);
- delete binKey;
- }
- catch (...) {
- errorLog0("Error deleting/erasing known "
- "ref key\n");
- }
- }
- else {
- secdebug("freeKey", "CSP freeKey unknown key");
- }
- }
- }
- CSPFullPluginSession::FreeKey(AccessCred, KeyPtr, Delete);
-}
-
-/* Passthrough, used for key digest */
-void AppleCSPSession::PassThrough(
- CSSM_CC_HANDLE CCHandle,
- const Context &Context,
- uint32 PassThroughId,
- const void *InData,
- void **OutData)
-{
- *OutData = NULL;
-
- /* validate context */
- if(Context.type() != CSSM_ALGCLASS_NONE) {
- CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
- }
-
- switch(PassThroughId) {
- case CSSM_APPLECSP_KEYDIGEST:
- {
- CssmKey &key = Context.get<CssmKey>(
- CSSM_ATTRIBUTE_KEY,
- CSSMERR_CSP_MISSING_ATTR_KEY);
-
- /* validate key as best we can */
- switch(key.keyClass()) {
- case CSSM_KEYCLASS_PUBLIC_KEY:
- case CSSM_KEYCLASS_PRIVATE_KEY:
- case CSSM_KEYCLASS_SESSION_KEY:
- break;
- default:
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
- }
-
- /*
- * Ref key: obtain binary, ask it for blob
- * Raw key: get info provider, ask it for the blob. This
- * allows for an optimized path which avoids
- * converting to a BinaryKey.
- */
- CssmData blobToHash;
- switch(key.blobType()) {
- case CSSM_KEYBLOB_RAW:
- {
- CSPKeyInfoProvider *provider = infoProvider(key);
- bool converted =
- provider->getHashableBlob(privAllocator, blobToHash);
- if(converted) {
- /* took optimized case; proceed */
- delete provider;
- break;
- }
-
- /* convert to BinaryKey and ask it to do the work */
- BinaryKey *binKey;
- CSSM_KEYATTR_FLAGS flags = 0; // not used
- provider->CssmKeyToBinary(NULL, // no paramKey
- flags,
- &binKey);
- binKey->mKeyHeader =
- CssmKey::Header::overlay(key.KeyHeader);
- CSSM_KEYBLOB_FORMAT rawFormat;
- rawFormat = CSSM_KEYBLOB_RAW_FORMAT_DIGEST;
- CSSM_KEYATTR_FLAGS attrFlags = 0;
- binKey->generateKeyBlob(privAllocator,
- blobToHash,
- rawFormat,
- *this,
- NULL,
- attrFlags);
- delete binKey;
- delete provider;
- break;
- }
- case CSSM_KEYBLOB_REFERENCE:
- {
- BinaryKey &binKey = lookupRefKey(key);
- CSSM_KEYBLOB_FORMAT rawFormat;
- rawFormat = CSSM_KEYBLOB_RAW_FORMAT_DIGEST;
- CSSM_KEYATTR_FLAGS attrFlags = 0;
- binKey.generateKeyBlob(privAllocator,
- blobToHash,
- rawFormat,
- *this,
- NULL,
- attrFlags);
- }
- break;
- default:
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
- }
-
- /* obtain sha1 hash of blobToHash */
-
- CSSM_DATA_PTR outHash = NULL;
- try {
- outHash =
- (CSSM_DATA_PTR)normAllocator.malloc(sizeof(CSSM_DATA));
- outHash->Data =
- (uint8 *)normAllocator.malloc(SHA1_DIGEST_SIZE);
- outHash->Length = SHA1_DIGEST_SIZE;
- }
- catch(...) {
- freeCssmData(blobToHash, privAllocator);
- throw;
- }
- cspGenSha1Hash(blobToHash.data(), blobToHash.length(),
- outHash->Data);
- freeCssmData(blobToHash, privAllocator);
- *OutData = outHash;
- return;
- }
- default:
- CssmError::throwMe(CSSMERR_CSP_INVALID_PASSTHROUGH_ID);
- }
- /* NOT REACHED */
-}
-
-/*
- * CSPSession version of QueryKeySizeInBits.
- */
-void AppleCSPSession::getKeySize(const CssmKey &key,
- CSSM_KEY_SIZE &size)
-{
- CSPKeyInfoProvider *provider = infoProvider(key);
- try {
- provider->QueryKeySizeInBits(size);
- }
- catch(...) {
- /* don't leak this on error */
- delete provider;
- throw;
- }
- delete provider;
-}
-
-void AppleCSPSession::getRandomBytes(size_t length, uint8 *cp)
-{
- try {
- cspGetRandomBytes(cp, (unsigned)length);
- }
- catch(...) {
- errorLog0("CSP: YarrowClient failure\n");
- }
-}
-
-void AppleCSPSession::addEntropy(size_t length, const uint8 *cp)
-{
- try {
- cspAddEntropy(cp, (unsigned)length);
- }
- catch(...) {
- #if CSP_ALLOW_FEE_RNG
- return;
- #else
- throw;
- #endif
- }
-}
-
-/***
- *** CSPKeyInfoProvider support.
- ***/
-
-/*
- * Find a CSPKeyInfoProvider subclass for the specified key.
- */
-CSPKeyInfoProvider *AppleCSPSession::infoProvider(
- const CssmKey &key)
-{
- CSPKeyInfoProvider *provider = NULL;
-
- #ifdef BSAFE_CSP_ENABLE
- /* Give BSAFE first shot, if it's here */
- provider = BSafe::BSafeKeyInfoProvider::provider(key, *this);
- if(provider != NULL) {
- return provider;
- }
- #endif
-
- provider = RSAKeyInfoProvider::provider(key, *this);
- if(provider != NULL) {
- return provider;
- }
-
- provider = SymmetricKeyInfoProvider::provider(key, *this);
- if(provider != NULL) {
- return provider;
- }
-
- #ifdef CRYPTKIT_CSP_ENABLE
- provider = CryptKit::FEEKeyInfoProvider::provider(key, *this);
- if(provider != NULL) {
- return provider;
- }
- #endif
-
- provider = DSAKeyInfoProvider::provider(key, *this);
- if(provider != NULL) {
- return provider;
- }
-
- provider = DHKeyInfoProvider::provider(key, *this);
- if(provider != NULL) {
- return provider;
- }
-
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
-}
-