X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_apple_csp/lib/FEEKeys.cpp diff --git a/libsecurity_apple_csp/lib/FEEKeys.cpp b/libsecurity_apple_csp/lib/FEEKeys.cpp new file mode 100644 index 00000000..90220ba0 --- /dev/null +++ b/libsecurity_apple_csp/lib/FEEKeys.cpp @@ -0,0 +1,454 @@ +/* + * 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. + */ + + +/* + * FEEKeys.cpp - FEE-related asymmetric key pair classes. + * + * Created 2/21/2001 by dmitch. + */ + +#ifdef CRYPTKIT_CSP_ENABLE + +#include "FEEKeys.h" +#include "FEECSPUtils.h" +#include "CryptKitSpace.h" +#include +#include +#include +#include "AppleCSPSession.h" +#include "AppleCSPUtils.h" +#include +#include + +#define feeKeyDebug(args...) secdebug("feeKey", ## args) + +/*** + *** FEE-style BinaryKey + ***/ + +/* constructor with optional existing feePubKey */ +CryptKit::FEEBinaryKey::FEEBinaryKey(feePubKey feeKey) + : mFeeKey(feeKey) +{ + if(mFeeKey == NULL) { + mFeeKey = feePubKeyAlloc(); + if(mFeeKey == NULL) { + CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); + } + } +} + +CryptKit::FEEBinaryKey::~FEEBinaryKey() +{ + if(mFeeKey) { + feePubKeyFree(mFeeKey); + mFeeKey = NULL; + } +} + +void CryptKit::FEEBinaryKey::generateKeyBlob( + Allocator &allocator, + CssmData &blob, + CSSM_KEYBLOB_FORMAT &format, + AppleCSPSession &session, + const CssmKey *paramKey, /* optional, unused here */ + CSSM_KEYATTR_FLAGS &attrFlags) /* IN/OUT */ +{ + unsigned char *keyBlob; + unsigned len; + feeReturn frtn = FR_Internal; + bool freeTheKey = false; + feePubKey keyToEncode = mFeeKey; + + assert(mFeeKey != NULL); + if((format == CSSM_KEYBLOB_RAW_FORMAT_DIGEST) && + (mKeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)) { + /* key digest calculation; special case for private keys: cook + * up the associated public key and encode that */ + keyToEncode = feePubKeyAlloc(); + if(keyToEncode == NULL) { + CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); + } + frtn = feePubKeyInitPubKeyFromPriv(mFeeKey, keyToEncode); + if(frtn) { + feePubKeyFree(keyToEncode); + throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv"); + } + freeTheKey = true; + } + + bool badFormat = false; + int isPrivate = feePubKeyIsPrivate(keyToEncode); + + switch(mKeyHeader.AlgorithmId) { + case CSSM_ALGID_FEE: + if(isPrivate) { + /* FEE private key */ + switch(format) { + case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: + format = CSSM_KEYBLOB_RAW_FORMAT_NONE; + /* and drop thru */ + case CSSM_KEYBLOB_RAW_FORMAT_NONE: + frtn = feePubKeyCreateDERPrivBlob(keyToEncode, &keyBlob, &len); + break; + case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: + frtn = feePubKeyCreatePrivBlob(keyToEncode, &keyBlob, &len); + break; + default: + badFormat = true; + break; + } + } + else { + /* FEE Public key */ + switch(format) { + case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: + format = CSSM_KEYBLOB_RAW_FORMAT_NONE; + /* and drop thru */ + case CSSM_KEYBLOB_RAW_FORMAT_NONE: + frtn = feePubKeyCreateDERPubBlob(keyToEncode, &keyBlob, &len); + break; + case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: + frtn = feePubKeyCreatePubBlob(keyToEncode, &keyBlob, &len); + break; + default: + badFormat = true; + break; + } + } + /* end of base ALGID_FEE */ + break; + + case CSSM_ALGID_ECDSA: + if(isPrivate) { + /* ECDSA/ECDH private key */ + switch(format) { + case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: + /* ECDSA private key: PKCS8 */ + frtn = feePubKeyCreatePKCS8Blob(keyToEncode, &keyBlob, &len); + break; + case CSSM_KEYBLOB_RAW_FORMAT_NONE: + /* set to default format, drop thru */ + format = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; + case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: + /* ECDSA private key, SEC1/OpenSSL format */ + frtn = feePubKeyCreateOpenSSLBlob(keyToEncode, &keyBlob, &len); + break; + case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: + format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; + /* and drop thru */ + case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: + /* raw private key bytes */ + frtn = feeCreateECDSAPrivBlob(keyToEncode, &keyBlob, &len); + break; + default: + badFormat = true; + break; + } + } + else { + /* + * ECDSA public key. + * Note there is no OpenSSL case here, that format is only generated for + * private keys. + */ + switch(format) { + case CSSM_KEYBLOB_RAW_FORMAT_NONE: + /* set to default format, drop thru */ + format = CSSM_KEYBLOB_RAW_FORMAT_X509; + case CSSM_KEYBLOB_RAW_FORMAT_X509: + /* ECDSA, public key, default: X509 */ + frtn = feePubKeyCreateX509Blob(keyToEncode, &keyBlob, &len); + break; + case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: + format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; + /* and drop thru */ + case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: + /* raw x|y string */ + frtn = feeCreateECDSAPubBlob(keyToEncode, &keyBlob, &len); + break; + default: + badFormat = true; + break; + } + } + /* end of case CSSM_ALGID_ECDSA */ + break; + default: + /* not reached */ + break; + } + + if(badFormat) { + CssmError::throwMe(isPrivate ? + CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT : + CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT); + } + if(frtn) { + throwCryptKit(frtn, "feePubKeyCreate*Blob"); + } + setUpCssmData(blob, len, allocator); + memmove(blob.data(), keyBlob, len); + blob.length(len); + ffree(keyBlob); + if(freeTheKey) { + /* free the temp pub key we created here */ + feePubKeyFree(keyToEncode); + } +} + +/*** + *** FEE-style AppleKeyPairGenContext + ***/ + +/* + * This one is specified in, and called from, CSPFullPluginSession. Our + * only job is to prepare two subclass-specific BinaryKeys and call up to + * AppleKeyPairGenContext. + */ +void CryptKit::FEEKeyPairGenContext::generate( + const Context &context, + CssmKey &pubKey, + CssmKey &privKey) +{ + FEEBinaryKey *pubBinKey = new FEEBinaryKey(); + FEEBinaryKey *privBinKey = new FEEBinaryKey(); + + try { + AppleKeyPairGenContext::generate(context, + session(), + pubKey, + pubBinKey, + privKey, + privBinKey); + } + catch (...) { + delete pubBinKey; + delete privBinKey; + throw; + } + +} + +// this one is specified in, and called from, AppleKeyPairGenContext +void CryptKit::FEEKeyPairGenContext::generate( + const Context &context, + BinaryKey &pubBinKey, + BinaryKey &privBinKey, + uint32 &keyBits) +{ + /* + * These casts throw exceptions if the keys are of the + * wrong classes, which would be a major bogon, since we created + * the keys in the above generate() function. + */ + FEEBinaryKey &fPubBinKey = + dynamic_cast(pubBinKey); + FEEBinaryKey &fPrivBinKey = + dynamic_cast(privBinKey); + + /* + * Two parameters from context. Key size in bits is required; + * seed is optional. If not present, we cook up random private data. + */ + keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH, + CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH); + CssmCryptoData *cseed = context.get(CSSM_ATTRIBUTE_SEED); + CssmData *seed; + bool haveSeed; + CssmAutoData aSeed(session()); // malloc on demand + if(cseed) { + /* caller specified seed */ + haveSeed = true; + seed = &cseed->param(); + } + else { + /* generate random seed */ + haveSeed = false; + unsigned keyBytes = ((keyBits + 7) / 8) + 1; + aSeed.malloc(keyBytes); + session().getRandomBytes(keyBytes, aSeed); + seed = &aSeed.get(); + } + + CSSM_ALGORITHMS algId = context.algorithm(); + + /* Curve and prime types - optional */ + feePrimeType primeType = FPT_Default; + uint32 uPrimeType = context.getInt(CSSM_ATTRIBUTE_FEE_PRIME_TYPE); + switch(uPrimeType) { + case CSSM_FEE_PRIME_TYPE_DEFAULT: + break; + case CSSM_FEE_PRIME_TYPE_MERSENNE: + primeType = FPT_Mersenne; + break; + case CSSM_FEE_PRIME_TYPE_FEE: + primeType = FPT_FEE; + break; + case CSSM_FEE_PRIME_TYPE_GENERAL: + primeType = FPT_General; + break; + default: + /* FIXME - maybe we should be more specific */ + CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS); + } + feeCurveType curveType = FCT_Default; + switch(algId) { + case CSSM_ALGID_ECDSA: + /* no options */ + curveType = FCT_ANSI; + break; + default: + { + uint32 uCurveType = context.getInt(CSSM_ATTRIBUTE_FEE_CURVE_TYPE); + switch(uCurveType) { + case CSSM_FEE_CURVE_TYPE_DEFAULT: + break; + case CSSM_FEE_CURVE_TYPE_MONTGOMERY: + curveType = FCT_Montgomery; + break; + case CSSM_FEE_CURVE_TYPE_WEIERSTRASS: + curveType = FCT_Weierstrass; + break; + case CSSM_FEE_CURVE_TYPE_ANSI_X9_62: + curveType = FCT_ANSI; + break; + default: + /* FIXME - maybe we should be more specific */ + CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS); + } + break; + } + } + feeReturn frtn = feePubKeyInitFromPrivDataKeyBits( + fPrivBinKey.feeKey(), + (unsigned char *)seed->data(), + seed->length(), + keyBits, + primeType, + curveType, + /* + * our random seed: trust it + * caller's seed: hash it + */ + haveSeed ? 1 : 0); + if(frtn) { + throwCryptKit(frtn, "feePubKeyInitFromPrivDataKeyBits"); + } + frtn = feePubKeyInitPubKeyFromPriv(fPrivBinKey.feeKey(), + fPubBinKey.feeKey()); + if(frtn) { + throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv"); + } +} + + +/*** + *** FEE-style CSPKeyInfoProvider. + ***/ +CryptKit::FEEKeyInfoProvider::FEEKeyInfoProvider( + const CssmKey &cssmKey, + AppleCSPSession &session) : + CSPKeyInfoProvider(cssmKey, session) +{ +} +CSPKeyInfoProvider *FEEKeyInfoProvider::provider( + const CssmKey &cssmKey, + AppleCSPSession &session) +{ + switch(cssmKey.algorithm()) { + case CSSM_ALGID_FEE: + case CSSM_ALGID_ECDSA: + break; + default: + return NULL; + } + switch(cssmKey.keyClass()) { + case CSSM_KEYCLASS_PUBLIC_KEY: + case CSSM_KEYCLASS_PRIVATE_KEY: + /* FIXME - verify proper CSSM_KEYBLOB_RAW_FORMAT_xx */ + break; + default: + return NULL; + } + /* OK, we'll handle this one */ + return new FEEKeyInfoProvider(cssmKey, session); +} + +/* Given a raw key, cook up a Binary key */ +void CryptKit::FEEKeyInfoProvider::CssmKeyToBinary( + CssmKey *paramKey, // optional, ignored + CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT + BinaryKey **binKey) +{ + *binKey = NULL; + feePubKey feeKey = NULL; + + /* first cook up a feePubKey, then drop that into a BinaryKey */ + feeKey = rawCssmKeyToFee(mKey); + FEEBinaryKey *feeBinKey = new FEEBinaryKey(feeKey); + *binKey = feeBinKey; +} + +/* + * Obtain key size in bits. + * Currently only raw public keys are dealt with (they're the ones + * which come from certs, the only current use for this function). + * Note that if we need to handle ref keys, we'll need a session ref... + */ +void CryptKit::FEEKeyInfoProvider::QueryKeySizeInBits( + CSSM_KEY_SIZE &keySize) +{ + feePubKey feeKey = NULL; + + if(mKey.blobType() != CSSM_KEYBLOB_RAW) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); + } + feeKey = rawCssmKeyToFee(mKey); + keySize.LogicalKeySizeInBits = feePubKeyBitsize(feeKey); + keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits; + feePubKeyFree(feeKey); +} + +/* + * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST + * passthrough. + */ +bool CryptKit::FEEKeyInfoProvider::getHashableBlob( + Allocator &allocator, + CssmData &blob) // blob to hash goes here +{ + /* + * The optimized case, a raw key in the "proper" format already. + * Currently this is: + * FEE public key in default/NONE form (which happens to be DER) + */ + assert(mKey.blobType() == CSSM_KEYBLOB_RAW); + if((mKey.algorithm() == CSSM_ALGID_FEE) && + (mKey.blobFormat() == CSSM_KEYBLOB_RAW_FORMAT_NONE) && + (mKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY)) { + const CssmData &keyBlob = CssmData::overlay(mKey.KeyData); + copyCssmData(keyBlob, blob, allocator); + return true; + } + + /* caller converts to binary and proceeds */ + return false; +} + +#endif /* CRYPTKIT_CSP_ENABLE */