X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_apple_csp/lib/bsafeKeyGen.cpp diff --git a/libsecurity_apple_csp/lib/bsafeKeyGen.cpp b/libsecurity_apple_csp/lib/bsafeKeyGen.cpp new file mode 100644 index 00000000..8e76232d --- /dev/null +++ b/libsecurity_apple_csp/lib/bsafeKeyGen.cpp @@ -0,0 +1,461 @@ +/* + * 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. + */ + +#ifdef BSAFE_CSP_ENABLE + + +// +// bsafeKeyGen.cpp - key generation routines +// +#include "bsafecspi.h" +#include "bsafePKCS1.h" +#include "cspdebugging.h" + +/* + * Stateless, private function to map a CSSM alg and pub/priv state + * to B_INFO_TYPE and format. Returns true on success, false on + * "I don't understand this algorithm". + */ +bool BSafe::bsafeAlgToInfoType( + CSSM_ALGORITHMS alg, + bool isPublic, + B_INFO_TYPE &infoType, // RETURNED + CSSM_KEYBLOB_FORMAT &format) // RETURNED +{ + switch(alg) { + case CSSM_ALGID_RSA: + if(isPublic) { + infoType = RSA_PUB_KEYINFO_TYPE; + format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; + } + else { + infoType = RSA_PRIV_KEYINFO_TYPE; + format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; + } + return true; + case CSSM_ALGID_DSA: + format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186; + if(isPublic) { + infoType = DSA_PUB_KEYINFO_TYPE; + } + else { + infoType = DSA_PRIV_KEYINFO_TYPE; + } + return true; + default: + return false; + } +} + + +BSafe::BSafeBinaryKey::BSafeBinaryKey( + bool isPub, + uint32 Alg) + : mIsPublic(isPub), + mAlg(Alg) +{ + BSafe::check(B_CreateKeyObject(&mBsKey), true); +} + +BSafe::BSafeBinaryKey::~BSafeBinaryKey() +{ + B_DestroyKeyObject(&mBsKey); +} + +void BSafe::BSafeBinaryKey::generateKeyBlob( + Allocator &allocator, + CssmData &blob, + CSSM_KEYBLOB_FORMAT &format, // input val ignored for now + AppleCSPSession &session, + const CssmKey *paramKey, // optional, unused here + CSSM_KEYATTR_FLAGS &attrFlags) // IN/OUT +{ + assert(mBsKey != NULL); + + B_INFO_TYPE bsType; + if(!bsafeAlgToInfoType(mAlg, mIsPublic, bsType, format)) { + CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); + } + if(format == CSSM_KEYBLOB_RAW_FORMAT_PKCS1) { + /* special case, encode the PKCS1 format blob */ + CssmRemoteData rData( + Allocator::standard(Allocator::sensitive), blob); + BS_GetKeyPkcs1(mBsKey, rData); + rData.release(); + } + else { + BSafeItem *info; + BSafe::check( + B_GetKeyInfo((POINTER *)&info, mBsKey, bsType), true); + blob = info->copy(allocator); + } +} + +// +// This is called from CSPFullPluginSession +// +void BSafe::BSafeKeyPairGenContext::generate( + const Context &context, + CssmKey &pubKey, + CssmKey &privKey) +{ + BSafeBinaryKey *pubBinKey = new BSafeBinaryKey(true, + context.algorithm()); + BSafeBinaryKey *privBinKey = new BSafeBinaryKey(false, + context.algorithm()); + + try { + AppleKeyPairGenContext::generate(context, + session(), + pubKey, + pubBinKey, + privKey, + privBinKey); + } + catch (...) { + delete pubBinKey; + delete privBinKey; + throw; + } +} + +// +// Called from AppleKeyPairGenContext +// +void BSafe::BSafeKeyPairGenContext::generate( + const Context &context, + BinaryKey &pubBinKey, // valid on successful return + BinaryKey &privBinKey, // ditto + uint32 &keySize) // ditto +{ + /* these casts throw exceptions if the keys are of the + * wrong classes, which is a major bogon, since we created + * the keys in the above generate() function */ + BSafeBinaryKey &bsPubBinKey = + dynamic_cast(pubBinKey); + BSafeBinaryKey &bsPrivBinKey = + dynamic_cast(privBinKey); + + if (!initialized) { + setupAlgorithm(context, keySize); + check(B_GenerateInit(bsAlgorithm, chooser(), bsSurrender), true); + initialized = true; + } + + setRandom(); + check(B_GenerateKeypair(bsAlgorithm, + bsPubBinKey.bsKey(), + bsPrivBinKey.bsKey(), + bsRandom, + bsSurrender), true); +} + +void BSafe::BSafeKeyPairGenContext::setupAlgorithm( + const Context &context, + uint32 &keySize) +{ + switch(context.algorithm()) { + case CSSM_ALGID_RSA: + { + A_RSA_KEY_GEN_PARAMS genParams; + keySize = genParams.modulusBits = + context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH, + CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH); + if (CssmData *params = + context.get(CSSM_ATTRIBUTE_ALG_PARAMS)) { + genParams.publicExponent = BSafeItem(*params); + } else { + static unsigned char exponent[] = { 1, 0, 1 }; + genParams.publicExponent = BSafeItem(exponent, sizeof(exponent)); + } + /* + * For test purposes, we avoid the 'strong' key generate + * algorithm if a CSSM_ALGMODE_CUSTOM mode atrtribute + * is present in the context. This is not published and + * not supported in the real world. + */ + uint32 mode = context.getInt(CSSM_ATTRIBUTE_MODE); + if(mode == CSSM_ALGMODE_CUSTOM) { + setAlgorithm(AI_RSAKeyGen, &genParams); + } + else { + setAlgorithm(AI_RSAStrongKeyGen, &genParams); + } + } + break; + case CSSM_ALGID_DSA: + { + A_DSA_PARAMS genParams; + genParams.prime = + BSafeItem(context.get( + CSSM_ATTRIBUTE_PRIME, + CSSMERR_CSP_MISSING_ATTR_ALG_PARAMS)); + genParams.subPrime = + BSafeItem(context.get( + CSSM_ATTRIBUTE_SUBPRIME, + CSSMERR_CSP_MISSING_ATTR_ALG_PARAMS)); + genParams.base = + BSafeItem(context.get( + CSSM_ATTRIBUTE_BASE, + CSSMERR_CSP_MISSING_ATTR_ALG_PARAMS)); + setAlgorithm(AI_DSAKeyGen, &genParams); + keySize = B_IntegerBits(genParams.prime.data, genParams.prime.len); + } + break; + default: + CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); + } +} + +// +// DSA Parameter Generation +// +void BSafe::BSafeKeyPairGenContext::generate( + const Context &context, + uint32 bitSize, + CssmData ¶ms, + uint32 &attrCount, + Context::Attr * &attrs) +{ + assert(context.algorithm() == CSSM_ALGID_DSA); + + B_ALGORITHM_OBJ genAlg = NULL; + B_ALGORITHM_OBJ result = NULL; + + try { + check(B_CreateAlgorithmObject(&genAlg)); + + B_DSA_PARAM_GEN_PARAMS genParams; + genParams.primeBits = bitSize; + check(B_SetAlgorithmInfo(genAlg, AI_DSAParamGen, POINTER(&genParams))); + setRandom(); + check(B_GenerateInit(genAlg, chooser(), bsSurrender), true); + check(B_CreateAlgorithmObject(&result)); + check(B_GenerateParameters(genAlg, result, bsRandom, bsSurrender)); + + // get parameters out of algorithm object + A_DSA_PARAMS *kParams = NULL; + check(B_GetAlgorithmInfo((POINTER *)&kParams, result, AI_DSAKeyGen), true); + + // shred them into context attribute form + attrs = normAllocator->alloc(3); + attrs[0] = Context::Attr(CSSM_ATTRIBUTE_PRIME, + *BSafeItem(kParams->prime).copyp(*normAllocator)); + attrs[1] = Context::Attr(CSSM_ATTRIBUTE_SUBPRIME, + *BSafeItem(kParams->subPrime).copyp(*normAllocator)); + attrs[2] = Context::Attr(CSSM_ATTRIBUTE_BASE, + *BSafeItem(kParams->base).copyp(*normAllocator)); + attrCount = 3; + + // clean up + B_DestroyAlgorithmObject(&result); + B_DestroyAlgorithmObject(&genAlg); + } catch (...) { + // clean up + B_DestroyAlgorithmObject(&result); + B_DestroyAlgorithmObject(&genAlg); + throw; + } +} + +/* + * CSPKeyInfoProvider for asymmetric BSAFE keys. + */ +BSafe::BSafeKeyInfoProvider::BSafeKeyInfoProvider( + const CssmKey &cssmKey, + AppleCSPSession &session) : + CSPKeyInfoProvider(cssmKey, session) +{ +} + +CSPKeyInfoProvider *BSafe::BSafeKeyInfoProvider::provider( + const CssmKey &cssmKey, + AppleCSPSession &session) +{ + switch(cssmKey.keyClass()) { + case CSSM_KEYCLASS_PUBLIC_KEY: + case CSSM_KEYCLASS_PRIVATE_KEY: + break; + default: + return NULL; + } + switch(mKey.algorithm()) { + case CSSM_ALGID_RSA: + case CSSM_ALGID_DSA: + break; + default: + return NULL; + } + /* OK, we'll handle this one */ + return new BSafeKeyInfoProvider(cssmKey, session); +} + +/* cook up a Binary key */ +void BSafe::BSafeKeyInfoProvider::CssmKeyToBinary( + CssmKey *paramKey, // optional, ignored + CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT + BinaryKey **binKey) +{ + *binKey = NULL; + + const CSSM_KEYHEADER *hdr = &mKey.KeyHeader; + assert(hdr->BlobType == CSSM_KEYBLOB_RAW); + + B_INFO_TYPE bsType; + CSSM_KEYBLOB_FORMAT format; + bool isPub; + + switch(hdr->KeyClass) { + case CSSM_KEYCLASS_PUBLIC_KEY: + isPub = true; + break; + case CSSM_KEYCLASS_PRIVATE_KEY: + isPub = false; + break; + default: + // someone else's key + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); + } + if(!bsafeAlgToInfoType(hdr->AlgorithmId, isPub, bsType, format)) { + // someone else's key + CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); + } + if(hdr->Format != format) { + dprintf0("BSafe::cssmKeyToBinary: format mismatch\n"); + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); + } + + BSafeBinaryKey *bsBinKey = new BSafeBinaryKey(isPub, + hdr->AlgorithmId); + + // set up key material as appropriate + if(format == CSSM_KEYBLOB_RAW_FORMAT_PKCS1) { + /* special case, decode the PKCS1 format blob */ + BS_setKeyPkcs1(mKey, bsBinKey->bsKey()); + } + else { + /* normal case, use key blob as is */ + BSafeItem item(mKey.KeyData); + BSafe::check( + B_SetKeyInfo(bsBinKey->bsKey(), bsType, POINTER(&item)), true); + } + *binKey = bsBinKey; +} + +/* + * Obtain key size in bits. + */ +void BSafe::BSafeKeyInfoProvider::QueryKeySizeInBits( + CSSM_KEY_SIZE &keySize) +{ + if(mKey.blobType() != CSSM_KEYBLOB_RAW) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); + } + + /* cook up BSAFE key */ + B_KEY_OBJ bKey; + A_RSA_KEY *rsaKeyInfo = NULL; + A_DSA_PUBLIC_KEY *dsaPubKeyInfo = NULL; + A_DSA_PRIVATE_KEY *dsaPrivKeyInfo = NULL; + ITEM *sizeItem = NULL; + BSafe::check(B_CreateKeyObject(&bKey), true); + B_INFO_TYPE infoType; + + switch(mKey.algorithm()) { + case CSSM_ALGID_RSA: + switch(mKey.keyClass()) { + case CSSM_KEYCLASS_PUBLIC_KEY: + if(mKey.blobFormat() != + CSSM_KEYBLOB_RAW_FORMAT_PKCS1) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); + } + + /* convert from PKCS1 blob to raw key */ + BS_setKeyPkcs1(mKey, bKey); + infoType = KI_RSAPublic; + /* break to common RSA code */ + break; + case CSSM_KEYCLASS_PRIVATE_KEY: + { + if(mKey.blobFormat() != + CSSM_KEYBLOB_RAW_FORMAT_PKCS8) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); + } + + /* convert from PKCS8 blob to raw key */ + BSafeItem item(mKey.KeyData); + BSafe::check( + B_SetKeyInfo(bKey, KI_PKCS_RSAPrivateBER, + POINTER(&item)), true); + infoType = KI_RSAPrivate; + break; + } + default: + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); + } + rsaKeyInfo = getKey(bKey, infoType); + sizeItem = &rsaKeyInfo->modulus; + break; + + case CSSM_ALGID_DSA: + /* untested as of 9/11/00 */ + if(mKey.blobFormat() != + CSSM_KEYBLOB_RAW_FORMAT_FIPS186) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); + } + switch(mKey.keyClass()) { + case CSSM_KEYCLASS_PUBLIC_KEY: + { + BSafeItem item(mKey.KeyData); + BSafe::check(B_SetKeyInfo(bKey, + DSA_PUB_KEYINFO_TYPE, + (POINTER)&item), true); + + /* get the key bits */ + dsaPubKeyInfo = getKey(bKey, + KI_DSAPublic); + sizeItem = &dsaPubKeyInfo->params.prime; + break; + } + case CSSM_KEYCLASS_PRIVATE_KEY: + { + BSafeItem item(mKey.KeyData); + BSafe::check(B_SetKeyInfo(bKey, + DSA_PRIV_KEYINFO_TYPE, + (POINTER)&item), true); + + /* get the key bits */ + dsaPrivKeyInfo = getKey(bKey, + KI_DSAPrivate); + sizeItem = &dsaPrivKeyInfo->params.prime; + break; + } + default: + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); + } + break; + default: + CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); + } + uint32 iSize = B_IntegerBits(sizeItem->data, sizeItem->len); + keySize.LogicalKeySizeInBits = iSize; + keySize.EffectiveKeySizeInBits = iSize; + B_DestroyKeyObject(&bKey); +} + +#endif /* BSAFE_CSP_ENABLE */ +