X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_cryptkit/lib/feePublicKey.c diff --git a/Security/libsecurity_cryptkit/lib/feePublicKey.c b/Security/libsecurity_cryptkit/lib/feePublicKey.c deleted file mode 100644 index 3105723a..00000000 --- a/Security/libsecurity_cryptkit/lib/feePublicKey.c +++ /dev/null @@ -1,1612 +0,0 @@ -/* Copyright (c) 1998,2011-2012,2014 Apple Inc. All Rights Reserved. - * - * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT - * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE - * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE - * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE, - * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL - * EXPOSE YOU TO LIABILITY. - *************************************************************************** - * - * feePublicKey.c - Portable FEE public key object. - * - * Revision History - * ---------------- - * 11/27/98 dmitch - * Added ECDSA_VERIFY_ONLY dependencies. - * 10/06/98 ap - * Changed to compile with C++. - * 9 Sep 98 at NeXT - * Major changes for IEEE P1363 compliance. - * 23 Mar 98 at Apple - * Added blob support. - * 21 Jan 98 at Apple - * Fixed feePubKeyBitsize bitlen bug for PT_GENERAL case. - * 05 Jan 98 at Apple - * ECDSA now uses SHA-1 hash. Imcompatible with old ECDSA signatures. - * 17 Jul 97 at Apple - * Added ECDSA signature routines. - * 12 Jun 97 at Apple - * Added feePubKeyInitGiants() - * Deleted obsolete code - * Changes for lesserX1OrderJustify (was curveOrderJustify) - * 31 Mar 97 at Apple - * Fixed leak in feePubKeyCreateKeyString() - * 15 Jan 97 at NeXT - * PUBLIC_KEY_STRING_VERSION = 3; broke compatibility with all older - * versions. - * Cleaned up which_curve/index code to use CURVE_MINUS/CURVE_PLUS. - * 12 Dec 96 at NeXT - * Added initFromEnc64KeyStr(). - * 20 Aug 96 at NeXT - * Ported to C. - * ???? 1994 Blaine Garst at NeXT - * Created. - */ - -#include "ckconfig.h" -#include "feePublicKey.h" -#include "feePublicKeyPrivate.h" -#include "ckutilities.h" -#include "giantIntegers.h" -#include "elliptic.h" -#include "curveParams.h" -#include "falloc.h" -#include "feeTypes.h" -#include "feeDebug.h" -#include "feeHash.h" -#include "ckSHA1.h" -#include "feeDigitalSignature.h" -#include "feeECDSA.h" -#include "platform.h" -#include "enc64.h" -#include "feeDES.h" -#include "byteRep.h" -#if CRYPTKIT_DER_ENABLE -#include "CryptKitDER.h" -#endif -#include - -/* - * 11/27/98 dmitch: The ECDSA_VERIFY_ONLY symbol, when #defined, disables all - * of the code in this module except that which is necessary for ECDSA - * siggnature verification. - */ - -#ifndef NULL -#define NULL ((void *)0) -#endif // NULL - -/* - * Magic number for a portable key blobs. Must be in sync with static - * final PUBLIC_KEY_STRING_MAGIC in JavaFee/PublicKey.java. - */ -#define PUBLIC_KEY_BLOB_MAGIC_PUB 0xfeeddeef -#define PUBLIC_KEY_BLOB_MAGIC_PRIV 0xfeeddeed -#define PUBLIC_KEY_BLOB_VERSION 6 -#define PUBLIC_KEY_BLOB_MINVERSION 6 - -#if CRYPTKIT_DER_ENABLE -#define PUBLIC_DER_KEY_BLOB_VERSION 1 -#endif - -/* - * Private data. All "instance" routines are passed a feePubKey (actually - * a void *) which is actually a pointer to one of these. - */ -typedef struct { - key plus; - key minus; // not needed for ECDSA - curveParams *cp; // common params shared by minus, plus - giant privGiant; // private key -} pubKeyInst; - -static feeReturn feeGenPrivate(pubKeyInst *pkinst, - const unsigned char *passwd, - unsigned passwdLen, - char hashPasswd); -static pubKeyInst *pubKeyInstAlloc(void); -static void pubKeyInstFree(pubKeyInst *pkinst); -#if GIANTS_VIA_STACK -static void feePubKeyInitGiants(void); -#endif -static feeReturn createKeyBlob(pubKeyInst *pkinst, - int isPrivate, // 0 : public 1 : private - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen); // RETURNED -static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey, - unsigned char *keyBlob, - unsigned keyBlobLen); - -#pragma mark --- General public API function --- - -/* - * Obatin a newly allocated feePubKey. - */ -feePubKey feePubKeyAlloc(void) -{ - pubKeyInst *pkinst = pubKeyInstAlloc(); - - #if GIANTS_VIA_STACK - feePubKeyInitGiants(); - #endif - return pkinst; -} - -void feePubKeyFree(feePubKey pubKey) -{ - pubKeyInstFree((pubKeyInst*) pubKey); -} - -#ifndef ECDSA_VERIFY_ONLY -/* - * Init feePubKey from private key data. - */ -feeReturn feePubKeyInitFromPrivDataKeyBits(feePubKey pubKey, - const unsigned char *privData, - unsigned privDataLen, - unsigned keyBits, /* key size in bits */ - feePrimeType primeType, /* FPT_Fefault means "best one" */ - feeCurveType curveType, /* FCT_Default means "best one" */ - char hashPrivData) -{ - feeReturn frtn; - feeDepth depth; - - frtn = feeKeyBitsToDepth(keyBits, primeType, curveType, &depth); - if(frtn) { - return frtn; - } - return feePubKeyInitFromPrivDataDepth(pubKey, - privData, - privDataLen, - depth, - hashPrivData); -} - -feeReturn feePubKeyInitFromPrivDataDepth(feePubKey pubKey, - const unsigned char *privData, - unsigned privDataLen, - feeDepth depth, - char hashPrivData) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - feeReturn frtn; - - #if ENGINE_127_BITS - if(depth != FEE_DEPTH_127_1) { - dbgLog(("Illegal Depth\n")); - return FR_IllegalDepth; - } - #endif // ENGINE_127_BITS - if(depth > FEE_DEPTH_MAX) { - dbgLog(("Illegal Depth\n")); - return FR_IllegalDepth; - } - - pkinst->cp = curveParamsForDepth(depth); - pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); - if(pkinst->cp->x1Minus != NULL) { - pkinst->minus = new_public(pkinst->cp, CURVE_MINUS); - } - /* else only usable for ECDSA */ - - frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData); - if(frtn) { - return frtn; - } - set_priv_key_giant(pkinst->plus, pkinst->privGiant); - if(pkinst->cp->x1Minus != NULL) { - set_priv_key_giant(pkinst->minus, pkinst->privGiant); - } - return FR_Success; -} - -#endif /* ECDSA_VERIFY_ONLY */ - -/* - * Init feePubKey from curve parameters matching existing oldKey. - */ -feeReturn feePubKeyInitFromKey(feePubKey pubKey, - const unsigned char *privData, - unsigned privDataLen, - feePubKey oldKey, - char hashPrivData) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - pubKeyInst *oldInst = (pubKeyInst *) oldKey; - feeReturn frtn; - - if(oldKey == NULL) { - dbgLog(("NULL existing key\n")); - return FR_BadPubKey; - } - - pkinst->cp = curveParamsCopy(oldInst->cp); - if(pkinst->cp->x1Minus != NULL) { - pkinst->minus = new_public(pkinst->cp, CURVE_MINUS); - if(pkinst->minus == NULL) { - goto abort; - } - } - /* else this curve only usable for ECDSA */ - - pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); - if(pkinst->plus == NULL) { - goto abort; - } - frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData); - if(frtn) { - return frtn; - } - set_priv_key_giant(pkinst->plus, pkinst->privGiant); - if(pkinst->cp->x1Minus != NULL) { - set_priv_key_giant(pkinst->minus, pkinst->privGiant); - } - return FR_Success; - -abort: - dbgLog(("Bad Existing Public Key\n")); - return FR_BadPubKey; -} - -/*** - *** Public KeyString support. - ***/ -/* - * Init feePubKey from a public key string. - * - * See ByteRep.doc for info on the format of the public key string and blobs; - * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT. - */ -feeReturn feePubKeyInitFromKeyString(feePubKey pubKey, - const char *keyStr, - unsigned keyStrLen) -{ - unsigned char *blob = NULL; - unsigned blobLen; - feeReturn frtn; - - blob = dec64((unsigned char *)keyStr, keyStrLen, &blobLen); - if(blob == NULL) { - dbgLog(("Bad Public Key String (not enc64)\n")); - return FR_BadPubKeyString; - } - frtn = feePubKeyInitFromKeyBlob(pubKey, blob, blobLen); - ffree(blob); - return frtn; -} - -/* - * Create a public key in the form of a null-terminated C string. - * This string contains an encoded version of all of our ivars except for - * privGiant. - * - * See ByteRep.doc for info on the format of the public key string and blobs; - * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT. - */ -feeReturn feePubKeyCreateKeyString(feePubKey pubKey, - char **pubKeyString, /* RETURNED */ - unsigned *pubKeyStringLen) /* RETURNED */ -{ - unsigned char *blob; - unsigned blobLen; - feeReturn frtn; - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - - /* get binary pub blob, encode the blob, free the blob */ - frtn = createKeyBlob(pkinst, - 0, // isPrivate - &blob, - &blobLen); - if(frtn) { - return frtn; - } - - *pubKeyString = (char *)enc64(blob, blobLen, pubKeyStringLen); - ffree(blob); - return FR_Success; -} - -/*** - *** Native key blob support. - ***/ - -#ifndef ECDSA_VERIFY_ONLY - -/* - * Obtain portable public and private key blobs from a key. - */ -feeReturn feePubKeyCreatePubBlob(feePubKey pubKey, - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - - return createKeyBlob(pkinst, - 0, - keyBlob, - keyBlobLen); -} - -feeReturn feePubKeyCreatePrivBlob(feePubKey pubKey, - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - - if(pkinst->privGiant == NULL) { - return FR_IncompatibleKey; - } - return createKeyBlob(pkinst, - 1, - keyBlob, - keyBlobLen); -} - -/* - * Given private-capable privKey, initialize pubKey to be its corresponding - * public key. - */ -feeReturn feePubKeyInitPubKeyFromPriv(feePubKey privKey, - feePubKey pubKey) -{ - pubKeyInst *privInst = (pubKeyInst *)privKey; - pubKeyInst *pubInst = (pubKeyInst *)pubKey; - - if((privInst == NULL) || (pubInst == NULL)) { - return FR_BadPubKey; - } - if(privInst->privGiant == NULL) { - return FR_IncompatibleKey; - } - pubInst->cp = curveParamsCopy(privInst->cp); - if(pubInst == NULL) { - return FR_Memory; - } - pubInst->plus = new_public_with_key(privInst->plus, pubInst->cp); - if(pubInst->plus == NULL) { - return FR_Memory; - } - if(pubInst->cp->x1Minus != NULL) { - pubInst->minus = new_public_with_key(privInst->minus, pubInst->cp); - if(pubInst->minus == NULL) { - return FR_Memory; - } - } - return FR_Success; -} - -#endif /* ECDSA_VERIFY_ONLY */ - -/* - * Returns non-zero if two keys are equivalent. - */ -int feePubKeyIsEqual(feePubKey key1, feePubKey key2) -{ - pubKeyInst *pkinst1 = (pubKeyInst *) key1; - pubKeyInst *pkinst2 = (pubKeyInst *) key2; - - if ((pkinst1 == NULL) || (pkinst2 == NULL)) { - return 0; - } - if((pkinst1->minus != NULL) && (pkinst2->minus != NULL)) { - if(key_equal(pkinst1->minus, pkinst2->minus) == 0) { - return 0; - } - } - if(key_equal(pkinst1->plus, pkinst2->plus) == 0) { - return 0; - } - return 1; -} - -/* - * Returns non-zero if key is private-capable (i.e., capable of signing - * and decrypting). - */ -int feePubKeyIsPrivate(feePubKey key) -{ - pubKeyInst *myPkinst = (pubKeyInst *)key; - - return ((myPkinst->privGiant != NULL) ? 1 : 0); -} - -#ifndef ECDSA_VERIFY_ONLY - -#if CRYPTKIT_KEY_EXCHANGE - -feeReturn feePubKeyCreatePad(feePubKey myKey, - feePubKey theirKey, - unsigned char **padData, /* RETURNED */ - unsigned *padDataLen) /* RETURNED padData length in bytes */ -{ - pubKeyInst *myPkinst = (pubKeyInst *) myKey; - pubKeyInst *theirPkinst = (pubKeyInst *) theirKey; - giant pad; - unsigned char *result; - unsigned padLen; - key pkey; - - /* - * Do some compatibility checking (myKey, theirKey) here...? - */ - if(DEFAULT_CURVE == CURVE_PLUS) { - pkey = theirPkinst->plus; - } - else { - pkey = theirPkinst->minus; - } - pad = make_pad(myPkinst->privGiant, pkey); - result = mem_from_giant(pad, &padLen); - freeGiant(pad); - - /* - * Ensure we have a the minimum necessary for DES. A bit of a hack, - * to be sure. - */ - if(padLen >= FEE_DES_MIN_STATE_SIZE) { - *padData = result; - *padDataLen = padLen; - } - else { - *padData = (unsigned char*) fmalloc(FEE_DES_MIN_STATE_SIZE); - *padDataLen = FEE_DES_MIN_STATE_SIZE; - bzero(*padData, FEE_DES_MIN_STATE_SIZE); - bcopy(result, *padData, padLen); - ffree(result); - } - return FR_Success; -} - -#endif /* CRYPTKIT_KEY_EXCHANGE */ - -#if CRYPTKIT_HIGH_LEVEL_SIG - -#warning HLS -/* - * Generate digital signature, ElGamal style. - */ -feeReturn feePubKeyCreateSignature(feePubKey pubKey, - const unsigned char *data, - unsigned dataLen, - unsigned char **signature, /* fmalloc'd and RETURNED */ - unsigned *signatureLen) /* RETURNED */ -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - feeHash hash; - feeSig sig; - unsigned char *Pm = NULL; - unsigned PmLen; - feeReturn frtn; - - if(pkinst->privGiant == NULL) { - dbgLog(("feePubKeyCreateSignature: Attempt to Sign without" - " private data\n")); - return FR_BadPubKey; - } - hash = feeHashAlloc(); - sig = feeSigNewWithKey(pubKey, NULL, NULL); - if(sig == NULL) { - /* - * Shouldn't happen, but... - */ - feeHashFree(hash); - return FR_BadPubKey; - } - - /* - * Get Pm to salt hash object - */ - Pm = feeSigPm(sig, &PmLen); - feeHashAddData(hash, Pm, PmLen); - - /* - * Now hash the data proper, then sign the hash - */ - feeHashAddData(hash, data, dataLen); - frtn = feeSigSign(sig, - feeHashDigest(hash), - feeHashDigestLen(), - pubKey); - if(frtn == FR_Success) { - frtn = feeSigData(sig, signature, signatureLen); - } - feeHashFree(hash); - feeSigFree(sig); - ffree(Pm); - return frtn; -} - -/* - * Verify digital signature, ElGamal style. If the signature is ECDSA, - * we'll use that format for compatibility. - */ -feeReturn feePubKeyVerifySignature(feePubKey pubKey, - const unsigned char *data, - unsigned dataLen, - const unsigned char *signature, - unsigned signatureLen) -{ - feeHash hash; - feeSig sig; - unsigned char *Pm = NULL; - unsigned PmLen; - feeReturn frtn; - - hash = feeHashAlloc(); - frtn = feeSigParse(signature, signatureLen, &sig); - if(frtn) { - feeHashFree(hash); - #if CRYPTKIT_ECDSA_ENABLE - if(frtn == FR_WrongSignatureType) { - return feePubKeyVerifyECDSASignature(pubKey, - data, - dataLen, - signature, - signatureLen); - } - #endif /* CRYPTKIT_ECDSA_ENABLE */ - return frtn; - } - - /* - * Get PM as salt; eat salt, then hash data - */ - Pm = feeSigPm(sig, &PmLen); - feeHashAddData(hash, Pm, PmLen); - feeHashAddData(hash, data, dataLen); - frtn = feeSigVerify(sig, - feeHashDigest(hash), - feeHashDigestLen(), - pubKey); - - feeHashFree(hash); - feeSigFree(sig); - ffree(Pm); - return frtn; -} - -#pragma mark --- ECDSA signature: high level routines --- - -#if CRYPTKIT_ECDSA_ENABLE -/* - * Generate digital signature, ECDSA style. - */ -feeReturn feePubKeyCreateECDSASignature(feePubKey pubKey, - const unsigned char *data, - unsigned dataLen, - unsigned char **signature, /* fmalloc'd and RETURNED */ - unsigned *signatureLen) /* RETURNED */ -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - sha1Obj sha1; - feeReturn frtn; - - if(pkinst->privGiant == NULL) { - dbgLog(("feePubKeyCreateECDSASignature: Attempt to Sign " - "without private data\n")); - return FR_BadPubKey; - } - sha1 = sha1Alloc(); - sha1AddData(sha1, data, dataLen); - frtn = feeECDSASign(pubKey, - sha1Digest(sha1), - sha1DigestLen(), - NULL, // randFcn - NULL, - signature, - signatureLen); - sha1Free(sha1); - return frtn; -} -#endif /* CRYPTKIT_ECDSA_ENABLE */ -#endif /* CRYPTKIT_HIGH_LEVEL_SIG */ -#endif /* ECDSA_VERIFY_ONLY */ - -#if CRYPTKIT_HIGH_LEVEL_SIG - -#if CRYPTKIT_ECDSA_ENABLE - -/* - * Verify digital signature, ECDSA style. - */ -feeReturn feePubKeyVerifyECDSASignature(feePubKey pubKey, - const unsigned char *data, - unsigned dataLen, - const unsigned char *signature, - unsigned signatureLen) -{ - sha1Obj sha1; - feeReturn frtn; - - sha1 = sha1Alloc(); - sha1AddData(sha1, data, dataLen); - frtn = feeECDSAVerify(signature, - signatureLen, - sha1Digest(sha1), - sha1DigestLen(), - pubKey); - sha1Free(sha1); - return frtn; -} - -#endif /* CRYPTKIT_ECDSA_ENABLE */ - -#endif /* CRYPTKIT_HIGH_LEVEL_SIG */ - -#pragma mark --- ECDH --- - -/* - * Diffie-Hellman. Public key is specified either as a feePubKey or - * a ANSI X9.62 format public key string (0x04 | x | y). In either case - * the caller must ensure that the two keys are on the same curve. - * Output data is fmalloc'd here; caller must free. Output data is - * exactly the size of the curve's modulus in bytes. - */ -feeReturn feePubKeyECDH( - feePubKey privKey, - /* one of the following two is non-NULL */ - feePubKey pubKey, - const unsigned char *pubKeyStr, - unsigned pubKeyStrLen, - /* output fmallocd and RETURNED here */ - unsigned char **output, - unsigned *outputLen) -{ - feePubKey theirPub = pubKey; - feeReturn frtn = FR_Success; - pubKeyInst *privInst = (pubKeyInst *) privKey; - - if(privInst->privGiant == NULL) { - dbgLog(("feePubKeyECDH: privKey not a private key\n")); - return FR_IncompatibleKey; - } - - if(theirPub == NULL) { - if(pubKeyStr == NULL) { - return FR_IllegalArg; - } - - /* Cook up a public key with the same curveParams as the private key */ - feeDepth depth; - frtn = curveParamsDepth(privInst->cp, &depth); - if(frtn) { - return frtn; - } - theirPub = feePubKeyAlloc(); - if(theirPub == NULL) { - return FR_Memory; - } - frtn = feePubKeyInitFromECDSAPubBlob(theirPub, pubKeyStr, pubKeyStrLen, depth); - if(frtn) { - goto errOut; - } - } - - pubKeyInst *pubInst = (pubKeyInst *) theirPub; - - giant outputGiant = make_pad(privInst->privGiant, pubInst->plus); - if(outputGiant == NULL) { - dbgLog(("feePubKeyECDH: make_pad error\n")); - frtn = FR_Internal; - } - else { - *outputLen = (privInst->cp->q + 7) / 8; - *output = (unsigned char *)fmalloc(*outputLen); - if(*output == NULL) { - frtn = FR_Memory; - goto errOut; - } - serializeGiant(outputGiant, *output, *outputLen); - freeGiant(outputGiant); - } -errOut: - if((pubKey == NULL) && (theirPub != NULL)) { - feePubKeyFree(theirPub); - } - return frtn; -} - -#pragma mark --- feePubKey data accessors --- - -unsigned feePubKeyBitsize(feePubKey pubKey) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - switch(pkinst->cp->primeType) { - case FPT_General: /* cp->q is here for just this purpose */ - case FPT_Mersenne: - return pkinst->cp->q; - case FPT_FEE: /* could be larger or smaller than 2^q-1 */ - default: - return bitlen(pkinst->cp->basePrime); - } - /* NOT REACHED */ - return 0; -} - -/* - * Accessor routines. - */ -/* private only...*/ -key feePubKeyPlusCurve(feePubKey pubKey) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - - return pkinst->plus; -} - -key feePubKeyMinusCurve(feePubKey pubKey) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - - return pkinst->minus; -} - -curveParams *feePubKeyCurveParams(feePubKey pubKey) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - - return pkinst->cp; -} - -giant feePubKeyPrivData(feePubKey pubKey) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - - return pkinst->privGiant; -} - -const char *feePubKeyAlgorithmName(void) -{ - return "Elliptic Curve - FEE by Apple Computer"; -} - -#pragma mark --- Private functions --- - -/* - * alloc, free pubKeyInst - */ -static pubKeyInst *pubKeyInstAlloc(void) -{ - pubKeyInst *pkinst = (pubKeyInst *) fmalloc(sizeof(pubKeyInst)); - - bzero(pkinst, sizeof(pubKeyInst)); - return pkinst; -} - -static void pubKeyInstFree(pubKeyInst *pkinst) -{ - if(pkinst->minus) { - free_key(pkinst->minus); - } - if(pkinst->plus) { - free_key(pkinst->plus); - } - if(pkinst->cp) { - freeCurveParams(pkinst->cp); - } - if(pkinst->privGiant) { - /* - * Zero out the private data... - */ - clearGiant(pkinst->privGiant); - freeGiant(pkinst->privGiant); - } - ffree(pkinst); -} - -#ifndef ECDSA_VERIFY_ONLY - -/* - * Create a pubKeyInst.privGiant given a password of - * arbitrary length. - * Currently, the only error is "private data too short" (FR_IllegalArg). - */ - -#define NO_PRIV_MUNGE 0 /* skip this step */ - -static feeReturn feeGenPrivate(pubKeyInst *pkinst, - const unsigned char *passwd, - unsigned passwdLen, - char hashPasswd) -{ - unsigned privLen; // desired size of pkinst->privData - feeHash *hash = NULL; // a malloc'd array - unsigned digestLen; // size of MD5 digest - unsigned dataSize; // min(privLen, passwdLen) - unsigned numDigests = 0; - unsigned i; - unsigned char *cp; - unsigned toMove; // for this digest - unsigned moved; // total digested - unsigned char *digest = NULL; - unsigned char *privData = NULL; // temp, before modg(curveOrder) - giant corder; // lesser of two curve orders - - /* - * generate privData which is just larger than the smaller - * curve order. - * We'll take the result mod the curve order when we're done. - * Note we do *not* have to free corder - it's a pointer to a giant - * in pkinst->cp. - */ - corder = lesserX1Order(pkinst->cp); - CKASSERT(!isZero(corder)); - privLen = (bitlen(corder) / 8) + 1; - - if(!hashPasswd) { - /* - * Caller trusts the incoming entropy. Verify it's big enough and proceed. - */ - if(passwdLen < privLen) { - return FR_ShortPrivData; - } - privLen = passwdLen; - privData = (unsigned char *)passwd; - goto finishUp; - } - if(passwdLen < 2) { - return FR_IllegalArg; - } - - - /* - * Calculate how many MD5 digests we'll generate. - */ - if(privLen > passwdLen) { - dataSize = passwdLen; - } - else { - dataSize = privLen; - } - digestLen = feeHashDigestLen(); - numDigests = (dataSize + digestLen - 1) / digestLen; - - hash = (void**) fmalloc(numDigests * sizeof(feeHash)); - for(i=0; i privLen), last digest will hash all - * remaining passwd data. - */ - cp = (unsigned char *)passwd; - moved = 0; - for(i=0; i privLen) { - toMove = privLen - moved; - } - else { - toMove = digestLen; - } - digest = feeHashDigest(hash[i++]); - bcopy(digest, cp, toMove); - cp += toMove; - moved += toMove; - if(i == numDigests) { - i = 0; // wrap to 0, start padding - } - } - -finishUp: - /* - * Convert to giant, justify result to within [2, lesserX1Order] - */ - pkinst->privGiant = giant_with_data(privData, privLen); - - #if FEE_DEBUG - if(isZero(pkinst->privGiant)) { - printf("feeGenPrivate: privData = 0!\n"); - } - #endif // FEE_DEBUG - - lesserX1OrderJustify(pkinst->privGiant, pkinst->cp); - if(hashPasswd) { - memset(privData, 0, privLen); - ffree(privData); - for(i=0; icp); - printf("plus:\n"); - printKey(pkinst->plus); - printf("minus:\n"); - printKey(pkinst->minus); - if(pkinst->privGiant != NULL) { - printf("privGiant : "); - printGiant(pkinst->privGiant); - } -} - -#else // FEE_DEBUG -void printPubKey(feePubKey pubKey) {} -#endif // FEE_DEBUG - -/* - * Prime the curveParams and giants modules for quick allocs of giants. - */ -#if GIANTS_VIA_STACK - -static int giantsInitd = 0; - -static void feePubKeyInitGiants(void) -{ - if(giantsInitd) { - return; - } - curveParamsInitGiants(); - giantsInitd = 1; -} -#endif - -#pragma mark --- Native (custom) key blob formatting --- - -/* - * Exported key blob support. New, 23 Mar 1998. - * - * Convert to public or private key blob. - */ - -#ifndef ECDSA_VERIFY_ONLY - -/*** - *** Common native blob support - ***/ -static feeReturn createKeyBlob(pubKeyInst *pkinst, - int isPrivate, // 0 : public 1 : private - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - unsigned char *s; // running ptr into *origS - unsigned sLen; - int magic; - - /* common blob elements */ - sLen = (4 * sizeof(int)) + // magic, version, minVersion, - // spare - lengthOfByteRepCurveParams(pkinst->cp); - if(isPrivate) { - /* private only */ - sLen += lengthOfByteRepGiant(pkinst->privGiant); - magic = PUBLIC_KEY_BLOB_MAGIC_PRIV; - } - else { - /* public only */ - sLen += (lengthOfByteRepKey(pkinst->plus) + - lengthOfByteRepKey(pkinst->minus)); - magic = PUBLIC_KEY_BLOB_MAGIC_PUB; - } - *keyBlob = s = (unsigned char*) fmalloc(sLen); - s += intToByteRep(magic, s); - s += intToByteRep(PUBLIC_KEY_BLOB_VERSION, s); - s += intToByteRep(PUBLIC_KEY_BLOB_MINVERSION, s); - s += intToByteRep(0, s); // spare - s += curveParamsToByteRep(pkinst->cp, s); - if(isPrivate) { - s += giantToByteRep(pkinst->privGiant, s); - } - else { - /* keyToByteRep writes y for plus curve only */ - s += keyToByteRep(pkinst->plus, s); - if(pkinst->minus != NULL) { - s += keyToByteRep(pkinst->minus, s); - } - else { - /* TBD */ - dbgLog(("work needed here for blobs with no minus key\n")); - } - } - *keyBlobLen = sLen; - return FR_Success; -} - -#endif /* ECDSA_VERIFY_ONLY */ - -/* - * Init an empty feePubKey from a native blob (non-DER format). - */ -static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey, - unsigned char *keyBlob, - unsigned keyBlobLen) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - unsigned char *s; // running pointer - unsigned sLen; // bytes remaining in *s - int magic; - unsigned len; // for length of individual components - int minVersion; - int version; - int isPrivate; - - s = keyBlob; - sLen = keyBlobLen; - if(sLen < (4 * sizeof(int))) { // magic, version, minVersion, spare - /* - * Too short for all the ints we need - */ - dbgLog(("feePublicKey: key blob (1)\n")); - return FR_BadKeyBlob; - } - - magic = byteRepToInt(s); - s += sizeof(int); - sLen -= sizeof(int); - switch(magic) { - case PUBLIC_KEY_BLOB_MAGIC_PUB: - isPrivate = 0; - break; - case PUBLIC_KEY_BLOB_MAGIC_PRIV: - isPrivate = 1; - break; - default: - dbgLog(("feePublicKey: Bad Public Key Magic Number\n")); - return FR_BadKeyBlob; - } - - /* - * Switch on this for version-specific cases - */ - version = byteRepToInt(s); - s += sizeof(int); - sLen -= sizeof(int); - - minVersion = byteRepToInt(s); - s += sizeof(int); - sLen -= sizeof(int); - if(minVersion > PUBLIC_KEY_BLOB_VERSION) { - /* - * old code, newer key blob - can't parse - */ - dbgLog(("feePublicKey: Incompatible Public Key (1)\n")); - return FR_BadKeyBlob; - } - - s += sizeof(int); // skip spare - sLen -= sizeof(int); - - pkinst->cp = byteRepToCurveParams(s, sLen, &len); - if(pkinst->cp == NULL) { - dbgLog(("feePublicKey: Bad Key Blob(2)\n")); - return FR_BadKeyBlob; - } - s += len; - sLen -= len; - - /* - * Private key blob: privGiant. - * Public Key blob: plusX, minusX, plusY. - */ - if(isPrivate) { - pkinst->privGiant = byteRepToGiant(s, sLen, &len); - if(pkinst->privGiant == NULL) { - dbgLog(("feePublicKey: Bad Key Blob(3)\n")); - return FR_BadKeyBlob; - } - s += len; - sLen -= len; - } - else { - /* this writes x and y */ - pkinst->plus = byteRepToKey(s, - sLen, - CURVE_PLUS, // twist - pkinst->cp, - &len); - if(pkinst->plus == NULL) { - dbgLog(("feePublicKey: Bad Key Blob(4)\n")); - return FR_BadKeyBlob; - } - s += len; - sLen -= len; - - /* this only writes x */ - pkinst->minus = byteRepToKey(s, - sLen, - CURVE_MINUS, // twist - pkinst->cp, - &len); - if(pkinst->minus == NULL) { - dbgLog(("feePublicKey: Bad Key Blob(5)\n")); - return FR_BadKeyBlob; - } - s += len; - sLen -= len; - } - - /* - * One more thing: cook up public plusX and minusX for private key - * blob case. - */ - if(isPrivate) { - pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); - pkinst->minus = new_public(pkinst->cp, CURVE_MINUS); - set_priv_key_giant(pkinst->plus, pkinst->privGiant); - set_priv_key_giant(pkinst->minus, pkinst->privGiant); - } - return FR_Success; - -} - -feeReturn feePubKeyInitFromPubBlob(feePubKey pubKey, - unsigned char *keyBlob, - unsigned keyBlobLen) -{ - return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen); -} - -#ifndef ECDSA_VERIFY_ONLY - -feeReturn feePubKeyInitFromPrivBlob(feePubKey pubKey, - unsigned char *keyBlob, - unsigned keyBlobLen) -{ - return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen); -} - -#endif /* ECDSA_VERIFY_ONLY */ - -#if CRYPTKIT_DER_ENABLE -#ifndef ECDSA_VERIFY_ONLY - -/* - * DER format support. - * Obtain portable public and private DER-encoded key blobs from a key. - */ -feeReturn feePubKeyCreateDERPubBlob(feePubKey pubKey, - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - - if(pkinst == NULL) { - return FR_BadPubKey; - } - if(pkinst->minus == NULL) { - /* Only ECDSA key formats supported */ - return FR_IncompatibleKey; - } - return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION, - pkinst->cp, - pkinst->plus->x, - pkinst->minus->x, - isZero(pkinst->plus->y) ? NULL : pkinst->plus->y, - keyBlob, - keyBlobLen); -} - -feeReturn feePubKeyCreateDERPrivBlob(feePubKey pubKey, - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - - if(pkinst == NULL) { - return FR_BadPubKey; - } - if(pkinst->privGiant == NULL) { - return FR_IncompatibleKey; - } - if(pkinst->minus == NULL) { - /* Only ECDSA key formats supported */ - return FR_IncompatibleKey; - } - return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION, - pkinst->cp, - pkinst->privGiant, - keyBlob, - keyBlobLen); -} - -#endif /* ECDSA_VERIFY_ONLY */ - -/* - * Init an empty feePubKey from a DER-encoded blob, public and private key versions. - */ -feeReturn feePubKeyInitFromDERPubBlob(feePubKey pubKey, - unsigned char *keyBlob, - size_t keyBlobLen) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - feeReturn frtn; - int version; - - if(pkinst == NULL) { - return FR_BadPubKey; - } - - /* kind of messy, maybe we should clean this up. But new_public() does too - * much - e.g., it allocates the x and y which we really don't want */ - memset(pkinst, 0, sizeof(pubKeyInst)); - pkinst->plus = (key) fmalloc(sizeof(keystruct)); - pkinst->minus = (key) fmalloc(sizeof(keystruct)); - if((pkinst->plus == NULL) || (pkinst->minus == NULL)) { - return FR_Memory; - } - memset(pkinst->plus, 0, sizeof(keystruct)); - memset(pkinst->minus, 0, sizeof(keystruct)); - pkinst->cp = NULL; - pkinst->privGiant = NULL; - pkinst->plus->twist = CURVE_PLUS; - pkinst->minus->twist = CURVE_MINUS; - frtn = feeDERDecodePublicKey(keyBlob, - (unsigned)keyBlobLen, - &version, // currently unused - &pkinst->cp, - &pkinst->plus->x, - &pkinst->minus->x, - &pkinst->plus->y); - if(frtn) { - return frtn; - } - /* minus curve, y is not used */ - pkinst->minus->y = newGiant(1); - int_to_giant(0, pkinst->minus->y); - pkinst->plus->cp = pkinst->minus->cp = pkinst->cp; - return FR_Success; -} - -#ifndef ECDSA_VERIFY_ONLY - -feeReturn feePubKeyInitFromDERPrivBlob(feePubKey pubKey, - unsigned char *keyBlob, - size_t keyBlobLen) -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - int version; - feeReturn frtn; - - if(pkinst == NULL) { - return FR_BadPubKey; - } - memset(pkinst, 0, sizeof(pubKeyInst)); - frtn = feeDERDecodePrivateKey(keyBlob, - (unsigned)keyBlobLen, - &version, // currently unused - &pkinst->cp, - &pkinst->privGiant); - if(frtn) { - return frtn; - } - - /* since this blob only had the private data, infer the remaining fields */ - pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); - pkinst->minus = new_public(pkinst->cp, CURVE_MINUS); - set_priv_key_giant(pkinst->plus, pkinst->privGiant); - set_priv_key_giant(pkinst->minus, pkinst->privGiant); - return FR_Success; -} - -#endif /* ECDSA_VERIFY_ONLY */ - -#pragma mark --- X509 (public) and PKCS8 (private) key formatting --- - -feeReturn feePubKeyCreateX509Blob( - feePubKey pubKey, // public key - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - unsigned char *xyStr = NULL; - unsigned xyStrLen = 0; - feeReturn frtn = feeCreateECDSAPubBlob(pubKey, &xyStr, &xyStrLen); - if(frtn) { - return frtn; - } - frtn = feeDEREncodeX509PublicKey(xyStr, xyStrLen, pkinst->cp, keyBlob, keyBlobLen); - ffree(xyStr); - return frtn; -} - -feeReturn feePubKeyCreatePKCS8Blob( - feePubKey pubKey, // private key - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - unsigned char *privStr = NULL; - unsigned privStrLen = 0; - feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen); - if(frtn) { - return frtn; - } - unsigned char *pubStr = NULL; - unsigned pubStrLen = 0; - frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen); - if(frtn) { - goto errOut; - } - frtn = feeDEREncodePKCS8PrivateKey(privStr, privStrLen, - pubStr, pubStrLen, - pkinst->cp, keyBlob, keyBlobLen); -errOut: - if(privStr) { - ffree(privStr); - } - if(pubStr) { - ffree(pubStr); - } - return frtn; -} - -feeReturn feePubKeyInitFromX509Blob( - feePubKey pubKey, // public key - unsigned char *keyBlob, - size_t keyBlobLen) -{ - feeDepth depth; - unsigned char *xyStr = NULL; - unsigned xyStrLen = 0; - - /* obtain x/y and depth from X509 encoding */ - feeReturn frtn = feeDERDecodeX509PublicKey(keyBlob, (unsigned)keyBlobLen, &depth, - &xyStr, &xyStrLen); - if(frtn) { - return frtn; - } - - frtn = feePubKeyInitFromECDSAPubBlob(pubKey, xyStr, xyStrLen, depth); - ffree(xyStr); - return frtn; -} - - -feeReturn feePubKeyInitFromPKCS8Blob( - feePubKey pubKey, // private key - unsigned char *keyBlob, - size_t keyBlobLen) -{ - feeDepth depth; - unsigned char *privStr = NULL; - unsigned privStrLen = 0; - - /* obtain x/y and depth from PKCS8 encoding */ - /* For now we ignore the possible public key string */ - feeReturn frtn = feeDERDecodePKCS8PrivateKey(keyBlob, (unsigned)keyBlobLen, &depth, - &privStr, &privStrLen, NULL, NULL); - if(frtn) { - return frtn; - } - - frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth); - ffree(privStr); - return frtn; -} - -#pragma mark --- OpenSSL key formatting --- - -/* - * The native OpenSSL ECDSA key format contains both the private and public - * components in one blob. This throws a bit of a monkey wrench into the API - * here, as we only have one encoder - which requires a private key - and one - * decoder, which can result in the decoding of either a public or a private - * key. - */ -feeReturn feePubKeyCreateOpenSSLBlob( - feePubKey pubKey, // private key - unsigned char **keyBlob, // mallocd and RETURNED - unsigned *keyBlobLen) // RETURNED -{ - pubKeyInst *pkinst = (pubKeyInst *) pubKey; - unsigned char *privStr = NULL; - unsigned privStrLen = 0; - feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen); - if(frtn) { - return frtn; - } - unsigned char *pubStr = NULL; - unsigned pubStrLen = 0; - frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen); - if(frtn) { - goto errOut; - } - frtn = feeDEREncodeOpenSSLPrivateKey(privStr, privStrLen, - pubStr, pubStrLen, - pkinst->cp, keyBlob, keyBlobLen); -errOut: - if(privStr) { - ffree(privStr); - } - if(pubStr) { - ffree(pubStr); - } - return frtn; -} - -feeReturn feePubKeyInitFromOpenSSLBlob( - feePubKey pubKey, // private or public key - int pubOnly, - unsigned char *keyBlob, - size_t keyBlobLen) -{ - feeDepth depth; - unsigned char *privStr = NULL; - unsigned privStrLen = 0; - unsigned char *pubStr = NULL; - unsigned pubStrLen = 0; - - /* obtain x/y, public bit string, and depth from PKCS8 encoding */ - feeReturn frtn = feeDERDecodeOpenSSLKey(keyBlob, (unsigned)keyBlobLen, &depth, - &privStr, &privStrLen, &pubStr, &pubStrLen); - if(frtn) { - return frtn; - } - - if(pubOnly) { - frtn = feePubKeyInitFromECDSAPubBlob(pubKey, pubStr, pubStrLen, depth); - } - else { - frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth); - } - if(privStr) { - ffree(privStr); - } - if(pubStr) { - ffree(pubStr); - } - return frtn; -} - -#endif /* CRYPTKIT_DER_ENABLE */ - -/* - * ANSI X9.62/Certicom key support. - * Public key is 04 || x || y - * Private key is privData per Certicom SEC1 C.4. - */ -feeReturn feeCreateECDSAPubBlob(feePubKey pubKey, - unsigned char **keyBlob, - unsigned *keyBlobLen) -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - if(pkinst == NULL) { - return FR_BadPubKey; - } - - unsigned giantBytes = (pkinst->cp->q + 7) / 8; - unsigned blobSize = 1 + (2 * giantBytes); - unsigned char *blob = fmalloc(blobSize); - if(blob == NULL) { - return FR_Memory; - } - *blob = 0x04; - serializeGiant(pkinst->plus->x, blob+1, giantBytes); - serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes); - *keyBlob = blob; - *keyBlobLen = blobSize; - return FR_Success; -} - -feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey, - unsigned char **keyBlob, - unsigned *keyBlobLen) -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - if(pkinst == NULL) { - return FR_BadPubKey; - } - if(pkinst->privGiant == NULL) { - return FR_IncompatibleKey; - } - - /* - * Return the raw private key bytes padded with zeroes in - * the m.s. end to fill exactly one prime-size byte array. - */ - unsigned giantBytes = (pkinst->cp->q + 7) / 8; - unsigned char *blob = fmalloc(giantBytes); - if(blob == NULL) { - return FR_Memory; - } - serializeGiant(pkinst->privGiant, blob, giantBytes); - *keyBlob = blob; - *keyBlobLen = giantBytes; - return FR_Success; -} - -/* Caller determines depth from other sources (e.g. AlgId.Params) */ -feeReturn feePubKeyInitFromECDSAPubBlob(feePubKey pubKey, - const unsigned char *keyBlob, - unsigned keyBlobLen, - feeDepth depth) -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - if(pkinst == NULL) { - return FR_BadPubKey; - } - curveParams *cp = curveParamsForDepth(depth); - if(cp == NULL) { - return FR_IllegalDepth; - } - unsigned giantBytes = (cp->q + 7) / 8; - unsigned blobSize = 1 + (2 * giantBytes); - if(keyBlobLen != blobSize) { - dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blobLen\n")); - return FR_BadKeyBlob; - } - if(*keyBlob != 0x04) { - dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n")); - return FR_BadKeyBlob; - } - - pkinst->cp = cp; - pkinst->plus = new_public(cp, CURVE_PLUS); - deserializeGiant(keyBlob+1, pkinst->plus->x, giantBytes); - deserializeGiant(keyBlob+1+giantBytes, pkinst->plus->y, giantBytes); - return FR_Success; -} - -feeReturn feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey, - const unsigned char *keyBlob, - unsigned keyBlobLen, - feeDepth depth) -{ - pubKeyInst *pkinst = (pubKeyInst *)pubKey; - if(pkinst == NULL) { - return FR_BadPubKey; - } - curveParams *cp = curveParamsForDepth(depth); - if(cp == NULL) { - return FR_IllegalDepth; - } - unsigned giantDigits = cp->basePrime->sign; - unsigned giantBytes = (cp->q + 7) / 8; - - /* - * The specified private key can be one byte smaller than the modulus */ - if((keyBlobLen > giantBytes) || (keyBlobLen < (giantBytes - 1))) { - dbgLog(("feePubKeyInitFromECDSAPrivBlob: bad blobLen\n")); - return FR_BadKeyBlob; - } - - pkinst->cp = cp; - - /* cook up a new private giant */ - pkinst->privGiant = newGiant(giantDigits); - if(pkinst->privGiant == NULL) { - return FR_Memory; - } - deserializeGiant(keyBlob, pkinst->privGiant, keyBlobLen); - - /* since this blob only had the private data, infer the remaining fields */ - pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); - set_priv_key_giant(pkinst->plus, pkinst->privGiant); - return FR_Success; -} -