+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2011,2014 Apple 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.
- */
-
-#ifdef BSAFE_CSP_ENABLE
-
-
-//
-// bsafeContext.cpp - implementation of class BSafe::BSafeContext
-// and some of its subclasses
-//
-
-#include "bsafecspi.h"
-#include "bsafePKCS1.h"
-#include <bkey.h>
-#include <balg.h>
-#include <algobj.h>
-#include "cspdebugging.h"
-
-#define DATA(cData) POINTER(cData.data()), cData.length()
-
-A_SURRENDER_CTX * const BSafe::BSafeContext::bsSurrender = NULL;
-
-
-//
-// Construct an algorithm object
-//
-BSafe::BSafeContext::BSafeContext(AppleCSPSession &session)
- : AppleCSPContext(session)
-{
- bsAlgorithm = NULL;
- bsKey = NULL;
- bsBinKey = NULL;
- bsRandom = NULL;
- initialized = false;
- opStarted = false;
-#ifdef SAFER
- inUpdate = NULL;
- inOutUpdate = NULL;
- inFinal = NULL;
- outFinal = NULL;
- outFinalR = NULL;
-#endif //SAFER
-}
-
-BSafe::BSafeContext::~BSafeContext()
-{
- reset();
-}
-
-void BSafe::BSafeContext::reset()
-{
- B_DestroyAlgorithmObject(&bsAlgorithm);
- B_DestroyAlgorithmObject(&bsRandom);
- destroyBsKey();
-}
-
-/*
- * Clear key state. We only destroy bsKey if we don't have a
- * BinaryKey.
- */
-void BSafe::BSafeContext::destroyBsKey()
-{
- if(bsBinKey == NULL) {
- B_DestroyKeyObject(&bsKey);
- }
- else {
- // bsKey gets destroyed when bsBinKey gets deleted
- bsBinKey = NULL;
- bsKey = NULL;
- }
-}
-
-void BSafe::check(int status, bool isKeyOp)
-{
- if(status == 0) {
- return;
- }
- dprintf1("BSAFE Error %d\n", status);
- switch (status) {
- case BE_ALLOC:
- throw std::bad_alloc();
- case BE_SIGNATURE:
- CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
- case BE_OUTPUT_LEN:
- CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
- case BE_INPUT_LEN:
- CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
- case BE_EXPONENT_EVEN:
- case BE_EXPONENT_LEN:
- case BE_EXPONENT_ONE:
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
- case BE_DATA:
- case BE_INPUT_DATA:
- if(isKeyOp) {
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
- }
- else {
- CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
- }
- case BE_MODULUS_LEN:
- case BE_OVER_32K:
- case BE_INPUT_COUNT:
- case BE_CANCEL:
- //@@@ later...
- default:
- //@@@ translate BSafe errors intelligently
- CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
- }
-}
-
-
-void BSafe::BSafeContext::setAlgorithm(
- B_INFO_TYPE bAlgType,
- const void *info)
-{
- B_DestroyAlgorithmObject(&bsAlgorithm); // clear any old BSafe algorithm
- check(B_CreateAlgorithmObject(&bsAlgorithm));
- check(B_SetAlgorithmInfo(bsAlgorithm, bAlgType, POINTER(info)));
-}
-
-/* safely create bsKey */
-void BSafe::BSafeContext::createBsKey()
-{
- /* reset to initial key state - some keys can't be reused */
- destroyBsKey();
- check(B_CreateKeyObject(&bsKey));
-}
-
-/* form of *info varies per bKeyInfo */
-void BSafe::BSafeContext::setKeyAtom(
- B_INFO_TYPE bKeyInfo,
- const void *info)
-{
- /* debug only */
- if((bKeyInfo == KI_RSAPublicBER) || (bKeyInfo == KI_RSAPublic)) {
- printf("Aargh! Unhandled KI_RSAPublic!\n");
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
- }
- assert(bKeyInfo != KI_RSAPublicBER); // handled elsewhere for now
- assert(bKeyInfo != KI_RSAPublic); // handled elsewhere for now
- createBsKey();
- check(B_SetKeyInfo(bsKey, bKeyInfo, POINTER(info)), true);
-}
-
-//
-// Set outSize for RSA keys.
-//
-void BSafe::BSafeContext::setRsaOutSize(
- bool isPubKey)
-{
- assert(bsKey != NULL);
-
- A_RSA_KEY *keyInfo;
- if(isPubKey) {
- keyInfo = getKey<A_RSA_KEY>(bsKey, KI_RSAPublic);
- }
- else {
- keyInfo = getKey<A_RSA_KEY>(bsKey, KI_RSAPrivate);
- }
- mOutSize = (B_IntegerBits(keyInfo->modulus.data,
- keyInfo->modulus.len) + 7) / 8;
-}
-
-//
-// Handle various forms of reference key. Symmetric
-// keys are stored as SymmetricBinaryKey, with raw key bytes
-// in keyData. Our asymmetric keys are stored as BSafeBinaryKeys,
-// with an embedded ready-to-use B_KEY_OBJ.
-//
-void BSafe::BSafeContext::setRefKey(CssmKey &key)
-{
- bool isPubKey = false;
-
- switch(key.keyClass()) {
- case CSSM_KEYCLASS_SESSION_KEY:
- {
- assert(key.blobFormat() ==
- CSSM_KEYBLOB_REF_FORMAT_INTEGER);
-
- BinaryKey &binKey = session().lookupRefKey(key);
- // fails if this is not a SymmetricBinaryKey
- SymmetricBinaryKey *symBinKey =
- dynamic_cast<SymmetricBinaryKey *>(&binKey);
- if(symBinKey == NULL) {
- errorLog0("BSafe::setRefKey(1): wrong BinaryKey subclass\n");
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
- }
- setKeyFromCssmData(KI_Item, symBinKey->mKeyData);
- return;
- }
- case CSSM_KEYCLASS_PUBLIC_KEY:
- isPubKey = true; // and fall thru
- case CSSM_KEYCLASS_PRIVATE_KEY:
- {
- BinaryKey &binKey = session().lookupRefKey(key);
- destroyBsKey();
- bsBinKey = dynamic_cast<BSafeBinaryKey *>(&binKey);
- /* this cast failing means that this is some other
- * kind of binary key */
- if(bsBinKey == NULL) {
- errorLog0("BSafe::setRefKey(2): wrong BinaryKey subclass\n");
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
- }
- assert(bsBinKey->bsKey() != NULL);
- bsKey = bsBinKey->bsKey();
- if(key.algorithm() == CSSM_ALGID_RSA) {
- setRsaOutSize(isPubKey);
- }
- return;
- }
- default:
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
- }
-}
-
-void BSafe::BSafeContext::setKeyFromContext(
- const Context &context,
- bool required)
-{
- CssmKey &key =
- context.get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
-
- switch(key.blobType()) {
- case CSSM_KEYBLOB_REFERENCE:
- setRefKey(key);
- return;
- case CSSM_KEYBLOB_RAW:
- break; // to main routine
- default:
- CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
- }
-
- bool isPubKey;
- switch (key.keyClass()) {
- case CSSM_KEYCLASS_SESSION_KEY:
- /* symmetric, one format supported for all algs */
- switch (key.blobFormat()) {
- case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
- setKeyFromCssmKey(KI_Item, key);
- return;
- default:
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
- }
- case CSSM_KEYCLASS_PUBLIC_KEY:
- isPubKey = true;
- break;
- case CSSM_KEYCLASS_PRIVATE_KEY:
- isPubKey = false;
- break;
- default:
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
- }
-
- /* We know it's an asymmetric key; get some info */
- B_INFO_TYPE infoType;
- CSSM_KEYBLOB_FORMAT expectedFormat;
-
- if(!bsafeAlgToInfoType(key.algorithm(),
- isPubKey,
- infoType,
- expectedFormat)) {
- /* unknown alg! */
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
- }
-
- /*
- * Correct format?
- * NOTE: if we end up supporting multiple incoming key formats, they'll
- * have to be handled here.
- */
- if(expectedFormat != key.blobFormat()) {
- errorLog1("setKeyFromContext: invalid blob format (%d)\n",
- (int)key.blobFormat());
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
- }
-
- /*
- * Most formats can be handled directly by BSAFE. Handle the special cases
- * requiring additional processing here.
- */
- switch(expectedFormat) {
- case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
- /* RSA public keys */
- createBsKey();
- BS_setKeyPkcs1(CssmData::overlay(key.KeyData), bsKey);
- break;
- default:
- setKeyFromCssmKey(infoType, key);
- break;
- }
-
- /*
- * One more thing - set mOutSize for RSA keys
- */
- if(key.algorithm() == CSSM_ALGID_RSA) {
- setRsaOutSize(isPubKey);
- }
-}
-
-#define BSAFE_RANDSIZE 32
-
-void BSafe::BSafeContext::setRandom()
-{
- if (bsRandom == NULL) {
- check(B_CreateAlgorithmObject(&bsRandom));
- check(B_SetAlgorithmInfo(bsRandom, AI_X962Random_V0, NULL_PTR));
- check(B_RandomInit(bsRandom, chooser(), bsSurrender));
- uint8 seed[BSAFE_RANDSIZE];
- session().getRandomBytes(BSAFE_RANDSIZE, seed);
- check(B_RandomUpdate(bsRandom, seed, sizeof(seed), bsSurrender));
- }
-}
-
-
-//
-// Operational methods of BSafeContext
-//
-void BSafe::BSafeContext::init(const Context &, bool)
-{
- // some algorithms don't need init(), because all is done in the context constructor
-}
-
-// update for input-only block/stream algorithms
-void BSafe::BSafeContext::update(const CssmData &data)
-{
- opStarted = true;
- check(inUpdate(bsAlgorithm, POINTER(data.data()), data.length(), bsSurrender));
-}
-
-// update for input/output block/stream algorithms
-void BSafe::BSafeContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize)
-{
- unsigned int length;
- opStarted = true;
- check(inOutUpdate(bsAlgorithm, POINTER(outp), &length, outSize,
- POINTER(inp), inSize, bsRandom, bsSurrender));
- // always eat all input (inSize unchanged)
- outSize = length;
-
- // let the algorithm manager track I/O sizes, if needed
- trackUpdate(inSize, outSize);
-}
-
-// output-generating final call
-void BSafe::BSafeContext::final(CssmData &out)
-{
- unsigned int length;
- if (outFinal) {
- check(outFinal(bsAlgorithm,
- POINTER(out.data()),
- &length,
- out.length(),
- bsSurrender));
- }
- else {
- check(outFinalR(bsAlgorithm,
- POINTER(out.data()),
- &length,
- out.length(),
- bsRandom,
- bsSurrender));
- }
- out.length(length);
- initialized = false;
-}
-
-// verifying final call (takes additional input)
-void BSafe::BSafeContext::final(const CssmData &in)
-{
- int status;
-
- /* note sig verify errors can show up as lots of BSAFE statuses;
- * munge them all into the appropriate error */
- if (inFinal) {
- status = inFinal(bsAlgorithm,
- POINTER(in.data()),
- in.length(),
- bsSurrender);
- }
- else {
- status = inFinalR(bsAlgorithm,
- POINTER(in.data()),
- in.length(),
- bsRandom,
- bsSurrender);
- }
- if(status != 0) {
- if((mType == CSSM_ALGCLASS_SIGNATURE) && (mDirection == false)) {
- /* yep, sig verify error */
- CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
- }
- /* other error, use standard trap */
- check(status);
- }
- initialized = false;
-}
-
-size_t BSafe::BSafeContext::outputSize(bool final, size_t inSize)
-{
- // this default implementation only makes sense for single-output end-loaded algorithms
- return final ? mOutSize : 0;
-}
-
-void BSafe::BSafeContext::trackUpdate(size_t, size_t)
-{ /* do nothing */ }
-
-//
-// Common features of CipherContexts.
-//
-void BSafe::CipherContext::cipherInit()
-{
- // set handlers
- if (encoding) {
- inOutUpdate = B_EncryptUpdate;
- outFinalR = B_EncryptFinal;
- } else {
- inOutUpdate = B_DecryptUpdate;
- outFinalR = B_DecryptFinal;
- }
- outFinal = NULL;
-
- // init the algorithm
- check((encoding ? B_EncryptInit : B_DecryptInit)
- (bsAlgorithm, bsKey, chooser(), bsSurrender));
-
- // buffers start empty
- pending = 0;
-
- // state is now valid
- initialized = true;
- opStarted = false;
-}
-#endif /* BSAFE_CSP_ENABLE */
-