X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_apple_csp/lib/FEEAsymmetricContext.cpp diff --git a/libsecurity_apple_csp/lib/FEEAsymmetricContext.cpp b/libsecurity_apple_csp/lib/FEEAsymmetricContext.cpp deleted file mode 100644 index 3556c887..00000000 --- a/libsecurity_apple_csp/lib/FEEAsymmetricContext.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* - * 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. - */ - - -/* - * FEEAsymmetricContext.cpp - CSPContexts for FEE asymmetric encryption - * - * Created March 8 2001 by dmitch. - */ - -#ifdef CRYPTKIT_CSP_ENABLE - -#include "FEEAsymmetricContext.h" -#include "FEECSPUtils.h" -#include -#include - -/* validate context for FEED and FEEDExp - no unexpected attributes allowed */ -static void validateFeedContext( - const Context &context) -{ - /* Note we cannot distinguish between zero and "not there" */ - uint32 blockSize = context.getInt(CSSM_ATTRIBUTE_BLOCK_SIZE); - if(blockSize != 0) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_BLOCK_SIZE); - } - CSSM_ENCRYPT_MODE cssmMode = context.getInt(CSSM_ATTRIBUTE_MODE); - if(cssmMode != 0) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE); - } - #if 0 - /* we allow this for CMS wrapping */ - CssmData *iv = context.get(CSSM_ATTRIBUTE_INIT_VECTOR); - if(iv != NULL) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR); - } - #endif - CSSM_PADDING padding = context.getInt(CSSM_ATTRIBUTE_PADDING); - if(padding != 0) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING); - } -} - -/*** - *** FEED - 1:1 FEED - encrypt n bytes of plaintext, get (roughly) n bytes - *** of ciphertext. Ciphertext is smaller than with FEED, but this is slower. - ***/ -CryptKit::FEEDContext::~FEEDContext() -{ - if(mFeeFeed) { - feeFEEDFree(mFeeFeed); - mFeeFeed = NULL; - } - if(mPrivKey && mAllocdPrivKey) { - feePubKeyFree(mPrivKey); - } - if(mPubKey && mAllocdPubKey) { - feePubKeyFree(mPubKey); - } - mPrivKey = NULL; - mPubKey = NULL; - mInitFlag = false; -} - -// called by CSPFullPluginSession; reusable -void CryptKit::FEEDContext::init( - const Context &context, - bool encoding) -{ - if(mInitFlag && !opStarted()) { - /* reusing - e.g. query followed by encrypt */ - return; - } - - /* - * Fetch FEE keys from context. This is an unusual algorithm - it requires - * two keys, one public and one private. The public key MUST be stored in - * the context with attribute type CSSM_ATTRIBUTE_PUBLIC_KEY, and the private - * key with CSSM_ATTRIBUTE_KEY. - * - * For now, we require CSSM_KEYUSE_ANY for FEE keys used for this algorithm. - * Otherwise we'd have to allow both KEYUSE_ENCRYPT and KEYUSE_DECRYPT for - * both keys, and that would require some algorithm-specific hack in - * cspValidateKeyUsageBits() which I really don't want to do. - */ - if(mPrivKey == NULL) { - assert(!opStarted()); - mPrivKey = contextToFeeKey(context, - session(), - CSSM_ATTRIBUTE_KEY, - CSSM_KEYCLASS_PRIVATE_KEY, - CSSM_KEYUSE_ANY, - mAllocdPrivKey); - } - else { - assert(opStarted()); - } - if(mPubKey == NULL) { - assert(!opStarted()); - mPubKey = contextToFeeKey(context, - session(), - CSSM_ATTRIBUTE_PUBLIC_KEY, - CSSM_KEYCLASS_PUBLIC_KEY, - CSSM_KEYUSE_ANY, - mAllocdPubKey); - } - else { - assert(opStarted()); - } - - /* validate context - no other attributes allowed */ - validateFeedContext(context); - - if(mFeeFeed != NULL) { - /* not reusable */ - assert(opStarted()); - feeFEEDFree(mFeeFeed); - mFeeFeed = NULL; - } - - /* OK, looks good. Cook up a feeFEED object. */ - mFeeFeed = feeFEEDNewWithPubKey(mPrivKey, - mPubKey, - encoding ? 1 : 0, - feeRandCallback, - &session()); - if(mFeeFeed == NULL) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY); - } - - /* finally, have BlockCryptor set up its stuff. */ - unsigned plainBlockSize = feeFEEDPlainBlockSize(mFeeFeed); - unsigned cipherBlockSize = feeFEEDCipherBlockSize(mFeeFeed); - setup(encoding ? plainBlockSize : cipherBlockSize, // blockSizeIn - encoding ? cipherBlockSize : plainBlockSize, // blockSizeOut - false, // pkcsPad - true, // needsFinal - BCM_ECB, - NULL); // IV - mInitFlag = true; -} - -// called by BlockCryptor -void CryptKit::FEEDContext::encryptBlock( - const void *plainText, // length implied (one block) - size_t plainTextLen, - void *cipherText, - size_t &cipherTextLen, // in/out, throws on overflow - bool final) -{ - feeReturn frtn; - unsigned actMoved; - - assert(mFeeFeed != NULL); - frtn = feeFEEDEncryptBlock(mFeeFeed, - (unsigned char *)plainText, - (unsigned int)plainTextLen, - (unsigned char *)cipherText, - &actMoved, - final ? 1 : 0); - if(frtn) { - throwCryptKit(frtn, "feeFEEDEncryptBlock"); - } - if(actMoved > cipherTextLen) { - /* Overflow already occurred! */ - CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); - } - cipherTextLen = actMoved; -} - -void CryptKit::FEEDContext::decryptBlock( - const void *cipherText, // length implied (one cipher block) - size_t cipherTextLen, - void *plainText, - size_t &plainTextLen, // in/out, throws on overflow - bool final) -{ - feeReturn frtn; - unsigned actMoved; - - assert(mFeeFeed != NULL); - frtn = feeFEEDDecryptBlock(mFeeFeed, - (unsigned char *)cipherText, - (unsigned int)inBlockSize(), - (unsigned char *)plainText, - &actMoved, - final ? 1 : 0); - if(frtn) { - throwCryptKit(frtn, "feeFEEDDecryptBlock"); - } - if(actMoved > plainTextLen) { - /* Overflow already occurred! */ - CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); - } - plainTextLen = actMoved; -} - -/* - * Additional query size support, necessary because we don't conform to - * BlockCryptor's standard one-to-one block scheme - */ - -#define BUFFER_DEBUG 0 -#if BUFFER_DEBUG -#define bprintf(s) printf s -#else -#define bprintf(s) -#endif - -size_t CryptKit::FEEDContext::inputSize( - size_t outSize) // input for given output size -{ - /* - * We've been assured that this is NOT called for the final() op... - */ - unsigned inSize; - if(encoding()) { - inSize = feeFEEDPlainTextSize(mFeeFeed, (unsigned int)outSize, 0); - } - else { - inSize = feeFEEDCipherTextSize(mFeeFeed, (unsigned int)outSize, 0); - } - - /* account for possible pending buffered input */ - if(inSize >= inBufSize()) { - inSize -= inBufSize(); - } - - /* round up to next block size, then lop off one...anything from - * blockSize*n to (blockSize*n)-1 has same effect */ - unsigned inBlocks = (unsigned int)((inSize + inBlockSize()) / inBlockSize()); - inSize = (unsigned int)(inBlocks * inBlockSize()) - 1; - bprintf(("--- FEEDContext::inputSize inSize 0x%x outSize 0x%x\n", - inSize, outSize)); - return inSize; -} - -size_t CryptKit::FEEDContext::outputSize( - bool final, - size_t inSize) // output for given input size -{ - size_t rtn; - if(encoding()) { - rtn = feeFEEDCipherTextSize(mFeeFeed, (unsigned int)(inSize + inBufSize()), final ? 1 : 0); - } - else { - rtn = feeFEEDPlainTextSize(mFeeFeed, (unsigned int)(inSize + inBufSize()), final ? 1 : 0); - } - bprintf(("--- FEEDContext::outputSize inSize 0x%x outSize 0x%x final %d\n", - inSize, rtn, final)); - return rtn; -} - -void CryptKit::FEEDContext::minimumProgress( - size_t &in, - size_t &out) // minimum progress chunks -{ - if(encoding()) { - /* - * -- in := one block plaintext - * -- out := current cipher size for one block plaintext - */ - in = inBlockSize(); - out = feeFEEDCipherBufSize(mFeeFeed, 0); - } - else { - /* - * -- in := current cipher size for one block plaintext - * -- out := one block plaintext - */ - in = feeFEEDCipherBufSize(mFeeFeed, 0); - out = outBlockSize(); - } - - /* - * Either case - input adjusted for pending. Note inBufSize can be up to one - * input block size, leaving the temp result zero here.... - */ - assert(in >= inBufSize()); - in -= inBufSize(); - - /* if it is zero, bump it up so caller can make something happen */ - if(in == 0) { - in++; - } - bprintf(("--- FEEDContext::minProgres inSize 0x%x outSize 0x%x\n", - in, out)); -} - -/*** - *** FEEDExp - 2:1 FEED - encrypt n bytes of plaintext, get (roughly) 2n bytes - *** of ciphertext. Ciphertext is larger than with FEED, but this is faster. - ***/ -CryptKit::FEEDExpContext::~FEEDExpContext() -{ - if(mFeeFeedExp) { - feeFEEDExpFree(mFeeFeedExp); - mFeeFeedExp = NULL; - } - if(mFeeKey && mAllocdFeeKey) { - feePubKeyFree(mFeeKey); - } - mFeeKey = NULL; - mInitFlag = false; -} - -// called by CSPFullPluginSession; reusable -void CryptKit::FEEDExpContext::init( - const Context &context, - bool encoding) -{ - if(mInitFlag && !opStarted()) { - /* reusing - e.g. query followed by encrypt */ - return; - } - - /* fetch FEE key from context */ - CSSM_KEYCLASS keyClass; - CSSM_KEYUSE keyUse; - - if(encoding) { - /* encrypting to public key */ - keyClass = CSSM_KEYCLASS_PUBLIC_KEY; - keyUse = CSSM_KEYUSE_ENCRYPT; - } - else { - /* decrypting with private key */ - keyClass = CSSM_KEYCLASS_PRIVATE_KEY; - keyUse = CSSM_KEYUSE_DECRYPT; - } - if(mFeeKey == NULL) { - assert(!opStarted()); - mFeeKey = contextToFeeKey(context, - session(), - CSSM_ATTRIBUTE_KEY, - keyClass, - keyUse, - mAllocdFeeKey); - } - else { - assert(opStarted()); - } - - /* validate context - no other attributes allowed */ - validateFeedContext(context); - - /* OK, looks good. Cook up a feeFEEDExp object. */ - if(mFeeFeedExp != NULL) { - /* not reusable */ - assert(opStarted()); - feeFEEDExpFree(mFeeFeedExp); - mFeeFeedExp = NULL; - } - mFeeFeedExp = feeFEEDExpNewWithPubKey(mFeeKey, - feeRandCallback, - &session()); - if(mFeeFeedExp == NULL) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY); - } - - /* finally, have BlockCryptor set up its stuff. */ - unsigned plainBlockSize = feeFEEDExpPlainBlockSize(mFeeFeedExp); - unsigned cipherBlockSize = feeFEEDExpCipherBlockSize(mFeeFeedExp); - setup(encoding ? plainBlockSize : cipherBlockSize, // blockSizeIn - encoding ? cipherBlockSize : plainBlockSize, // blockSizeOut - false, // pkcs5Pad - true, // needsFinal - BCM_ECB, - NULL); // IV - mInitFlag = true; -} - -// called by BlockCryptor -void CryptKit::FEEDExpContext::encryptBlock( - const void *plainText, // length implied (one block) - size_t plainTextLen, - void *cipherText, - size_t &cipherTextLen, // in/out, throws on overflow - bool final) -{ - feeReturn frtn; - unsigned actMoved; - - assert(mFeeFeedExp != NULL); - frtn = feeFEEDExpEncryptBlock(mFeeFeedExp, - (unsigned char *)plainText, - (unsigned int)plainTextLen, - (unsigned char *)cipherText, - &actMoved, - final ? 1 : 0); - if(frtn) { - throwCryptKit(frtn, "feeFEEDExpEncryptBlock"); - } - if(actMoved > cipherTextLen) { - /* Overflow already occurred! */ - CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); - } - cipherTextLen = actMoved; -} - -void CryptKit::FEEDExpContext::decryptBlock( - const void *cipherText, // length implied (one cipher block) - size_t cipherTextLen, - void *plainText, - size_t &plainTextLen, // in/out, throws on overflow - bool final) -{ - feeReturn frtn; - unsigned actMoved; - - assert(mFeeFeedExp != NULL); - frtn = feeFEEDExpDecryptBlock(mFeeFeedExp, - (unsigned char *)cipherText, - (unsigned int)inBlockSize(), - (unsigned char *)plainText, - &actMoved, - final ? 1 : 0); - if(frtn) { - throwCryptKit(frtn, "feeFEEDExpDecryptBlock"); - } - if(actMoved > plainTextLen) { - /* Overflow already occurred! */ - CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); - } - plainTextLen = actMoved; -} - -/* convert uint32 to big-endian 4 bytes */ -static void int32ToBytes( - uint32_t i, - unsigned char *b) -{ - for(int dex=3; dex>=0; dex--) { - b[dex] = i; - i >>= 8; - } -} - -/* - * X9.63 key derivation with optional SharedInfo passed as - * context attribute CSSM_ATTRIBUTE_SALT. - */ -static feeReturn ecdhKdf( - const Context &context, - const unsigned char *Z, /* shared secret, i.e., output of ECDH */ - unsigned ZLen, - CSSM_DATA *K) /* output RETURNED in K->Data, length K->Length bytes */ -{ - /* SharedInfo via salt, from context, optional */ - const unsigned char *sharedInfo = NULL; - CSSM_SIZE sharedInfoLen = 0; - - CssmData *salt = context.get(CSSM_ATTRIBUTE_SALT); - if(salt != NULL) { - sharedInfo = (const unsigned char *)salt->Data; - sharedInfoLen = salt->Length; - } - - unsigned char *outp = K->Data; - CSSM_SIZE bytesToGo = K->Length; - CC_SHA1_CTX sha1; - uint32_t counter = 1; - uint8 counterBytes[4]; - unsigned char digOut[CC_SHA1_DIGEST_LENGTH]; - - do { - /* K[i] = Hash(Z || Counter || SharedInfo) */ - CC_SHA1_Init(&sha1); - CC_SHA1_Update(&sha1, Z, ZLen); - int32ToBytes(counter, counterBytes); - CC_SHA1_Update(&sha1, counterBytes, 4); - if(sharedInfoLen) { - CC_SHA1_Update(&sha1, sharedInfo, (CC_LONG)sharedInfoLen); - } - CC_SHA1_Final(digOut, &sha1); - - /* digest --> output */ - unsigned toMove = CC_SHA1_DIGEST_LENGTH; - if(toMove > bytesToGo) { - toMove = (unsigned int)bytesToGo; - } - memmove(outp, digOut, toMove); - - counter++; - outp += toMove; - bytesToGo -= toMove; - - } while(bytesToGo); - - return FR_Success; -} - -/* - * Elliptic curve Diffie-Hellman key exchange. The public key is - * specified in one of two ways - a raw X9.62 format public key - * string in Param, or a CSSM_KEY in the Context. - * Requested size, in keyData->Length, must be the same size as - * the keys' modulus. Data is returned in keyData->Data, which is - * allocated by the caller. - * Optionally performs X9.63 key derivation if algId == - * CSSM_ALGID_ECDH_X963_KDF, with the optional SharedInfo passed - * as optional context attribute CSSM_ATTRIBUTE_SALT. - */ -void CryptKit::DeriveKey_ECDH ( - const Context &context, - CSSM_ALGORITHMS algId, - const CssmData &Param, // other's public key. may be empty - CSSM_DATA *keyData, // mallocd by caller - // we fill in keyData->Length bytes - AppleCSPSession &session) -{ - bool mallocdPrivKey; - size_t privSize; - - /* private ECDH key from context - required */ - feePubKey privKey = contextToFeeKey(context, session, CSSM_ATTRIBUTE_KEY, - CSSM_KEYCLASS_PRIVATE_KEY, CSSM_KEYUSE_DERIVE, mallocdPrivKey); - if(privKey == NULL) { - CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY); - } - privSize = (feePubKeyBitsize(privKey) + 7) / 8; - if((algId == CSSM_ALGID_ECDH) & (privSize != keyData->Length)) { - /* exact match required here */ - CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); - } - - /* - * Public key ("their" key) can come from two places: - * -- in the context as a CSSM_ATTRIBUTE_PUBLIC_KEY. This is how - * public keys in X509 format must be used in this function. - * -- in the incoming Param, the raw unformatted (ANSI X9.62) form - */ - bool mallocdPubKey = false; - feePubKey pubKey = NULL; - if(Param.Data == NULL) { - /* this throws if no key present */ - pubKey = contextToFeeKey(context, session, CSSM_ATTRIBUTE_PUBLIC_KEY, - CSSM_KEYCLASS_PUBLIC_KEY, CSSM_KEYUSE_DERIVE, mallocdPubKey); - } - if((pubKey == NULL) && (Param.Data == NULL)) { - errorLog0("DeriveKey_ECDH: no pub_key\n"); - CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); - } - unsigned char *output = NULL; - unsigned outputLen = 0; - feeReturn frtn = feePubKeyECDH(privKey, pubKey, - (const unsigned char *)Param.Data, (unsigned)Param.Length, - &output, &outputLen); - if(frtn) { - goto errOut; - } - switch(algId) { - case CSSM_ALGID_ECDH: - /* - * Raw ECDH - requested length must match the generated size - * exactly. If so, return the result unmodified. - */ - if(outputLen != keyData->Length) { - errorLog0("DeriveKey_ECDH: length mismatch\n"); - frtn = FR_Internal; - break; - } - memmove(keyData->Data, output, outputLen); - break; - case CSSM_ALGID_ECDH_X963_KDF: - /* Further processing... */ - frtn = ecdhKdf(context, output, outputLen, keyData); - break; - default: - /* shouldn't be here */ - frtn = FR_Internal; - break; - } - -errOut: - if(mallocdPrivKey) { - feePubKeyFree(privKey); - } - if(mallocdPubKey) { - feePubKeyFree(pubKey); - } - if(output != NULL) { - ffree(output); - } - if(frtn) { - throwCryptKit(frtn, NULL); - } -} - -#endif /* CRYPTKIT_CSP_ENABLE */