/* * 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( CssmAllocator &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( CssmAllocator::standard(CssmAllocator::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 */