1/* Copyright (c) 1998,2011-2012,2014 Apple Inc.  All Rights Reserved.
2 *
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
7 * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
10 *
11 * feePublicKey.c - Portable FEE public key object.
12 *
13 * Revision History
14 * ----------------
15 * 11/27/98	dmitch
16 *	Added ECDSA_VERIFY_ONLY dependencies.
17 * 10/06/98	ap
18 *	Changed to compile with C++.
19 *  9 Sep 98 at NeXT
20 * 	Major changes for IEEE P1363 compliance.
21 * 23 Mar 98 at Apple
22 *	Added blob support.
23 * 21 Jan 98 at Apple
24 * 	Fixed feePubKeyBitsize bitlen bug for PT_GENERAL case.
25 * 05 Jan 98 at Apple
26 *	ECDSA now uses SHA-1 hash. Imcompatible with old ECDSA signatures.
27 * 17 Jul 97 at Apple
28 *	Added ECDSA signature routines.
29 * 12 Jun 97 at Apple
30 *	Added feePubKeyInitGiants()
31 *	Deleted obsolete code
32 *	Changes for lesserX1OrderJustify (was curveOrderJustify)
33 * 31 Mar 97 at Apple
34 *	Fixed leak in feePubKeyCreateKeyString()
35 * 15 Jan 97 at NeXT
36 *	PUBLIC_KEY_STRING_VERSION = 3; broke compatibility with all older
37 *		versions.
38 *	Cleaned up which_curve/index code to use CURVE_MINUS/CURVE_PLUS.
39 * 12 Dec 96 at NeXT
40 *	Added initFromEnc64KeyStr().
41 * 20 Aug 96 at NeXT
42 *	Ported to C.
43 *  ???? 1994	Blaine Garst at NeXT
44 *	Created.
45 */
46
47#include "ckconfig.h"
48#include "feePublicKey.h"
49#include "feePublicKeyPrivate.h"
50#include "ckutilities.h"
51#include "giantIntegers.h"
52#include "elliptic.h"
53#include "curveParams.h"
54#include "falloc.h"
55#include "feeTypes.h"
56#include "feeDebug.h"
57#include "feeHash.h"
58#include "ckSHA1.h"
59#include "feeDigitalSignature.h"
60#include "feeECDSA.h"
61#include "platform.h"
62#include "enc64.h"
63#include "feeDES.h"
64#include "byteRep.h"
65#if	CRYPTKIT_DER_ENABLE
66#include "CryptKitDER.h"
67#endif
68#include <stdio.h>
69
70/*
71 * 11/27/98 dmitch: The ECDSA_VERIFY_ONLY symbol, when #defined, disables all
72 * of the code in this module except that which is necessary for ECDSA
73 * siggnature verification.
74 */
75
76#ifndef	NULL
77#define NULL ((void *)0)
78#endif	// NULL
79
80/*
81 * Magic number for a portable key blobs. Must be in sync with static
82 * final PUBLIC_KEY_STRING_MAGIC in JavaFee/PublicKey.java.
83 */
84#define PUBLIC_KEY_BLOB_MAGIC_PUB  		0xfeeddeef
85#define PUBLIC_KEY_BLOB_MAGIC_PRIV  	0xfeeddeed
86#define PUBLIC_KEY_BLOB_VERSION  		6
87#define PUBLIC_KEY_BLOB_MINVERSION		6
88
89#if	CRYPTKIT_DER_ENABLE
90#define PUBLIC_DER_KEY_BLOB_VERSION		1
91#endif
92
93/*
94 * Private data. All "instance" routines are passed a feePubKey (actually
95 * a void *) which is actually a pointer to one of these.
96 */
97typedef struct {
98	key			plus;
99	key			minus;		// not needed for ECDSA
100	curveParams	*cp;		// common params shared by minus, plus
101	giant		privGiant;	// private key
102} pubKeyInst;
103
104static feeReturn feeGenPrivate(pubKeyInst *pkinst,
105	const unsigned char *passwd,
106	unsigned passwdLen,
107	char hashPasswd);
108static pubKeyInst *pubKeyInstAlloc(void);
109static void pubKeyInstFree(pubKeyInst *pkinst);
110#if		GIANTS_VIA_STACK
111static void feePubKeyInitGiants(void);
112#endif
113static feeReturn createKeyBlob(pubKeyInst *pkinst,
114	int isPrivate,			// 0 : public   1 : private
115	unsigned char **keyBlob,	// mallocd and RETURNED
116	unsigned *keyBlobLen);		// RETURNED
117static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
118	unsigned char *keyBlob,
119	unsigned keyBlobLen);
120
121#pragma mark --- General public API function ---
122
123/*
124 * Obatin a newly allocated feePubKey.
125 */
126feePubKey feePubKeyAlloc(void)
127{
128	pubKeyInst *pkinst = pubKeyInstAlloc();
129
130	#if		GIANTS_VIA_STACK
131	feePubKeyInitGiants();
132	#endif
133	return pkinst;
134}
135
136void feePubKeyFree(feePubKey pubKey)
137{
138	pubKeyInstFree((pubKeyInst*) pubKey);
139}
140
141#ifndef	ECDSA_VERIFY_ONLY
142/*
143 * Init feePubKey from private key data.
144 */
145feeReturn feePubKeyInitFromPrivDataKeyBits(feePubKey pubKey,
146	const unsigned char *privData,
147	unsigned privDataLen,
148	unsigned keyBits,			/* key size in bits */
149	feePrimeType primeType,		/* FPT_Fefault means "best one" */
150	feeCurveType curveType,		/* FCT_Default means "best one" */
151	char hashPrivData)
152{
153	feeReturn frtn;
154	feeDepth depth;
155
156	frtn = feeKeyBitsToDepth(keyBits, primeType, curveType, &depth);
157	if(frtn) {
158		return frtn;
159	}
160	return feePubKeyInitFromPrivDataDepth(pubKey,
161		privData,
162		privDataLen,
163		depth,
164		hashPrivData);
165}
166
167feeReturn feePubKeyInitFromPrivDataDepth(feePubKey pubKey,
168	const unsigned char *privData,
169	unsigned privDataLen,
170	feeDepth depth,
171	char hashPrivData)
172{
173	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
174	feeReturn  frtn;
175
176	#if	ENGINE_127_BITS
177	if(depth != FEE_DEPTH_127_1) {
178		dbgLog(("Illegal Depth\n"));
179		return FR_IllegalDepth;
180	}
181	#endif	// ENGINE_127_BITS
182	if(depth > FEE_DEPTH_MAX) {
183		dbgLog(("Illegal Depth\n"));
184		return FR_IllegalDepth;
185	}
186
187	pkinst->cp = curveParamsForDepth(depth);
188	pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
189	if(pkinst->cp->x1Minus != NULL) {
190		pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
191	}
192	/* else only usable for ECDSA */
193
194	frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData);
195	if(frtn) {
196		return frtn;
197	}
198	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
199	if(pkinst->cp->x1Minus != NULL) {
200		set_priv_key_giant(pkinst->minus, pkinst->privGiant);
201	}
202	return FR_Success;
203}
204
205#endif	/* ECDSA_VERIFY_ONLY */
206
207/*
208 * Init feePubKey from curve parameters matching existing oldKey.
209 */
210feeReturn feePubKeyInitFromKey(feePubKey pubKey,
211	const unsigned char *privData,
212	unsigned privDataLen,
213	feePubKey oldKey,
214	char hashPrivData)
215{
216	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
217	pubKeyInst *oldInst = (pubKeyInst *) oldKey;
218	feeReturn  frtn;
219
220	if(oldKey == NULL) {
221		dbgLog(("NULL existing key\n"));
222		return FR_BadPubKey;
223	}
224
225	pkinst->cp = curveParamsCopy(oldInst->cp);
226	if(pkinst->cp->x1Minus != NULL) {
227		pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
228		if(pkinst->minus == NULL) {
229			goto abort;
230		}
231	}
232	/* else this curve only usable for ECDSA */
233
234	pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
235	if(pkinst->plus == NULL) {
236		goto abort;
237	}
238	frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData);
239	if(frtn) {
240		return frtn;
241	}
242	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
243	if(pkinst->cp->x1Minus != NULL) {
244		set_priv_key_giant(pkinst->minus, pkinst->privGiant);
245	}
246	return FR_Success;
247
248abort:
249	dbgLog(("Bad Existing Public Key\n"));
250	return FR_BadPubKey;
251}
252
253/***
254 *** Public KeyString support.
255 ***/
256/*
257 * Init feePubKey from a public key string.
258 *
259 * See ByteRep.doc for info on the format of the public key string and blobs;
260 * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT.
261 */
262feeReturn feePubKeyInitFromKeyString(feePubKey pubKey,
263	const char *keyStr,
264	unsigned keyStrLen)
265{
266	unsigned char 	*blob = NULL;
267	unsigned		blobLen;
268	feeReturn		frtn;
269
270	blob = dec64((unsigned char *)keyStr, keyStrLen, &blobLen);
271	if(blob == NULL) {
272		dbgLog(("Bad Public Key String (not enc64)\n"));
273		return FR_BadPubKeyString;
274	}
275	frtn = feePubKeyInitFromKeyBlob(pubKey, blob, blobLen);
276	ffree(blob);
277	return frtn;
278}
279
280/*
281 * Create a public key in the form of a null-terminated C string.
282 * This string contains an encoded version of all of our ivars except for
283 * privGiant.
284 *
285 * See ByteRep.doc for info on the format of the public key string and blobs;
286 * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT.
287 */
288feeReturn feePubKeyCreateKeyString(feePubKey pubKey,
289	char **pubKeyString,		/* RETURNED */
290	unsigned *pubKeyStringLen)	/* RETURNED */
291{
292	unsigned char 	*blob;
293	unsigned 	blobLen;
294	feeReturn 	frtn;
295	pubKeyInst 	*pkinst = (pubKeyInst *)pubKey;
296
297	/* get binary pub blob, encode the blob, free the blob */
298	frtn = createKeyBlob(pkinst,
299		0,		// isPrivate
300		&blob,
301		&blobLen);
302	if(frtn) {
303		return frtn;
304	}
305
306	*pubKeyString = (char *)enc64(blob, blobLen, pubKeyStringLen);
307	ffree(blob);
308	return FR_Success;
309}
310
311/***
312 *** Native key blob support.
313 ***/
314
315#ifndef	ECDSA_VERIFY_ONLY
316
317/*
318 * Obtain portable public and private key blobs from a key.
319 */
320feeReturn feePubKeyCreatePubBlob(feePubKey pubKey,
321	unsigned char **keyBlob,	// mallocd and RETURNED
322	unsigned *keyBlobLen)		// RETURNED
323{
324	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
325
326	return createKeyBlob(pkinst,
327		0,
328		keyBlob,
329		keyBlobLen);
330}
331
332feeReturn feePubKeyCreatePrivBlob(feePubKey pubKey,
333	unsigned char **keyBlob,	// mallocd and RETURNED
334	unsigned *keyBlobLen)		// RETURNED
335{
336	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
337
338	if(pkinst->privGiant == NULL) {
339		return FR_IncompatibleKey;
340	}
341	return createKeyBlob(pkinst,
342		1,
343		keyBlob,
344		keyBlobLen);
345}
346
347/*
348 * Given private-capable privKey, initialize pubKey to be its corresponding
349 * public key.
350 */
351feeReturn feePubKeyInitPubKeyFromPriv(feePubKey privKey,
352	feePubKey pubKey)
353{
354	pubKeyInst *privInst = (pubKeyInst *)privKey;
355	pubKeyInst *pubInst  = (pubKeyInst *)pubKey;
356
357	if((privInst == NULL) || (pubInst == NULL)) {
358		return FR_BadPubKey;
359	}
360	if(privInst->privGiant == NULL) {
361		return FR_IncompatibleKey;
362	}
363	pubInst->cp = curveParamsCopy(privInst->cp);
364	if(pubInst == NULL) {
365		return FR_Memory;
366	}
367	pubInst->plus   = new_public_with_key(privInst->plus,  pubInst->cp);
368	if(pubInst->plus == NULL) {
369		return FR_Memory;
370	}
371	if(pubInst->cp->x1Minus != NULL) {
372		pubInst->minus  = new_public_with_key(privInst->minus, pubInst->cp);
373		if(pubInst->minus == NULL) {
374			return FR_Memory;
375		}
376	}
377	return FR_Success;
378}
379
380#endif	/* ECDSA_VERIFY_ONLY */
381
382/*
383 * Returns non-zero if two keys are equivalent.
384 */
385int feePubKeyIsEqual(feePubKey key1, feePubKey key2)
386{
387	pubKeyInst *pkinst1 = (pubKeyInst *) key1;
388	pubKeyInst *pkinst2 = (pubKeyInst *) key2;
389
390	if ((pkinst1 == NULL) || (pkinst2 == NULL)) {
391		return 0;
392	}
393	if((pkinst1->minus != NULL) && (pkinst2->minus != NULL)) {
394		if(key_equal(pkinst1->minus, pkinst2->minus) == 0) {
395			return 0;
396		}
397	}
398	if(key_equal(pkinst1->plus, pkinst2->plus) == 0) {
399		return 0;
400	}
401	return 1;
402}
403
404/*
405 * Returns non-zero if key is private-capable (i.e., capable of signing
406 * and decrypting).
407 */
408int feePubKeyIsPrivate(feePubKey key)
409{
410	pubKeyInst *myPkinst = (pubKeyInst *)key;
411
412	return ((myPkinst->privGiant != NULL) ? 1 : 0);
413}
414
415#ifndef	ECDSA_VERIFY_ONLY
416
417#if	CRYPTKIT_KEY_EXCHANGE
418
419feeReturn feePubKeyCreatePad(feePubKey myKey,
420	feePubKey theirKey,
421	unsigned char **padData,	/* RETURNED */
422	unsigned *padDataLen)		/* RETURNED padData length in bytes */
423{
424	pubKeyInst *myPkinst = (pubKeyInst *) myKey;
425	pubKeyInst *theirPkinst = (pubKeyInst *) theirKey;
426	giant pad;
427	unsigned char *result;
428    	unsigned padLen;
429	key pkey;
430
431	/*
432	 * Do some compatibility checking (myKey, theirKey) here...?
433	 */
434	if(DEFAULT_CURVE == CURVE_PLUS) {
435		pkey = theirPkinst->plus;
436	}
437	else {
438		pkey = theirPkinst->minus;
439	}
440	pad = make_pad(myPkinst->privGiant, pkey);
441	result = mem_from_giant(pad, &padLen);
442	freeGiant(pad);
443
444	/*
445	 * Ensure we have a the minimum necessary for DES. A bit of a hack,
446	 * to be sure.
447	 */
448	if(padLen >= FEE_DES_MIN_STATE_SIZE) {
449		*padData = result;
450		*padDataLen = padLen;
451	}
452	else {
453		*padData = (unsigned char*) fmalloc(FEE_DES_MIN_STATE_SIZE);
454		*padDataLen = FEE_DES_MIN_STATE_SIZE;
455		bzero(*padData, FEE_DES_MIN_STATE_SIZE);
456		bcopy(result, *padData, padLen);
457		ffree(result);
458	}
459	return FR_Success;
460}
461
462#endif	/* CRYPTKIT_KEY_EXCHANGE */
463
464#if	CRYPTKIT_HIGH_LEVEL_SIG
465
466#warning HLS
467/*
468 * Generate digital signature, ElGamal style.
469 */
470feeReturn feePubKeyCreateSignature(feePubKey pubKey,
471	const unsigned char *data,
472	unsigned dataLen,
473	unsigned char **signature,	/* fmalloc'd and RETURNED */
474	unsigned *signatureLen)		/* RETURNED */
475{
476	pubKeyInst	*pkinst = (pubKeyInst *) pubKey;
477	feeHash 	hash;
478	feeSig 		sig;
479	unsigned char 	*Pm = NULL;
480	unsigned 	PmLen;
481	feeReturn	frtn;
482
483	if(pkinst->privGiant == NULL) {
484		dbgLog(("feePubKeyCreateSignature: Attempt to Sign without"
485			" private data\n"));
486		return FR_BadPubKey;
487	}
488	hash = feeHashAlloc();
489	sig = feeSigNewWithKey(pubKey, NULL, NULL);
490	if(sig == NULL) {
491		/*
492		 * Shouldn't happen, but...
493		 */
494		feeHashFree(hash);
495		return FR_BadPubKey;
496	}
497
498	/*
499	 * Get Pm to salt hash object
500	 */
501	Pm = feeSigPm(sig, &PmLen);
502	feeHashAddData(hash, Pm, PmLen);
503
504	/*
505	 * Now hash the data proper, then sign the hash
506	 */
507	feeHashAddData(hash, data, dataLen);
508	frtn = feeSigSign(sig,
509		feeHashDigest(hash),
510		feeHashDigestLen(),
511		pubKey);
512	if(frtn == FR_Success) {
513		frtn = feeSigData(sig, signature, signatureLen);
514	}
515	feeHashFree(hash);
516	feeSigFree(sig);
517	ffree(Pm);
518	return frtn;
519}
520
521/*
522 * Verify digital signature, ElGamal style. If the signature is ECDSA,
523 * we'll use that format for compatibility.
524 */
525feeReturn feePubKeyVerifySignature(feePubKey pubKey,
526	const unsigned char *data,
527	unsigned dataLen,
528	const unsigned char *signature,
529	unsigned signatureLen)
530{
531	feeHash 		hash;
532	feeSig 			sig;
533	unsigned char 	*Pm = NULL;
534	unsigned 		PmLen;
535	feeReturn		frtn;
536
537	hash = feeHashAlloc();
538	frtn = feeSigParse(signature, signatureLen, &sig);
539	if(frtn) {
540		feeHashFree(hash);
541		#if CRYPTKIT_ECDSA_ENABLE
542		if(frtn == FR_WrongSignatureType) {
543			return feePubKeyVerifyECDSASignature(pubKey,
544				data,
545				dataLen,
546				signature,
547				signatureLen);
548		}
549		#endif	/* CRYPTKIT_ECDSA_ENABLE */
550		return frtn;
551	}
552
553	/*
554	 * Get PM as salt; eat salt, then hash data
555	 */
556	Pm = feeSigPm(sig, &PmLen);
557	feeHashAddData(hash, Pm, PmLen);
558	feeHashAddData(hash, data, dataLen);
559	frtn = feeSigVerify(sig,
560		feeHashDigest(hash),
561		feeHashDigestLen(),
562		pubKey);
563
564	feeHashFree(hash);
565	feeSigFree(sig);
566	ffree(Pm);
567	return frtn;
568}
569
570#pragma mark --- ECDSA signature: high level routines ---
571
572#if	CRYPTKIT_ECDSA_ENABLE
573/*
574 * Generate digital signature, ECDSA style.
575 */
576feeReturn feePubKeyCreateECDSASignature(feePubKey pubKey,
577	const unsigned char *data,
578	unsigned dataLen,
579	unsigned char **signature,	/* fmalloc'd and RETURNED */
580	unsigned *signatureLen)		/* RETURNED */
581{
582	pubKeyInst	*pkinst = (pubKeyInst *) pubKey;
583	sha1Obj 	sha1;
584	feeReturn	frtn;
585
586	if(pkinst->privGiant == NULL) {
587		dbgLog(("feePubKeyCreateECDSASignature: Attempt to Sign "
588			"without private data\n"));
589		return FR_BadPubKey;
590	}
591	sha1 = sha1Alloc();
592	sha1AddData(sha1, data, dataLen);
593	frtn = feeECDSASign(pubKey,
594		sha1Digest(sha1),
595		sha1DigestLen(),
596		NULL,			// randFcn
597		NULL,
598		signature,
599		signatureLen);
600	sha1Free(sha1);
601	return frtn;
602}
603#endif	/* CRYPTKIT_ECDSA_ENABLE */
604#endif  /* CRYPTKIT_HIGH_LEVEL_SIG */
605#endif	/* ECDSA_VERIFY_ONLY */
606
607#if	CRYPTKIT_HIGH_LEVEL_SIG
608
609#if	CRYPTKIT_ECDSA_ENABLE
610
611/*
612 * Verify digital signature, ECDSA style.
613 */
614feeReturn feePubKeyVerifyECDSASignature(feePubKey pubKey,
615	const unsigned char *data,
616	unsigned dataLen,
617	const unsigned char *signature,
618	unsigned signatureLen)
619{
620	sha1Obj 	sha1;
621	feeReturn	frtn;
622
623	sha1 = sha1Alloc();
624	sha1AddData(sha1, data, dataLen);
625	frtn = feeECDSAVerify(signature,
626		signatureLen,
627		sha1Digest(sha1),
628		sha1DigestLen(),
629		pubKey);
630	sha1Free(sha1);
631	return frtn;
632}
633
634#endif	/* CRYPTKIT_ECDSA_ENABLE */
635
636#endif	/* CRYPTKIT_HIGH_LEVEL_SIG */
637
638#pragma mark --- ECDH ---
639
640/*
641 * Diffie-Hellman. Public key is specified either as a feePubKey or
642 * a ANSI X9.62 format public key string (0x04 | x | y). In either case
643 * the caller must ensure that the two keys are on the same curve.
644 * Output data is fmalloc'd here; caller must free. Output data is
645 * exactly the size of the curve's modulus in bytes.
646 */
647feeReturn feePubKeyECDH(
648	feePubKey privKey,
649	/* one of the following two is non-NULL */
650	feePubKey pubKey,
651	const unsigned char *pubKeyStr,
652	unsigned pubKeyStrLen,
653	/* output fmallocd and RETURNED here */
654	unsigned char **output,
655	unsigned *outputLen)
656{
657	feePubKey theirPub = pubKey;
658	feeReturn frtn = FR_Success;
659	pubKeyInst *privInst = (pubKeyInst *) privKey;
660
661	if(privInst->privGiant == NULL) {
662		dbgLog(("feePubKeyECDH: privKey not a private key\n"));
663		return FR_IncompatibleKey;
664	}
665
666	if(theirPub == NULL) {
667		if(pubKeyStr == NULL) {
668			return FR_IllegalArg;
669		}
670
671		/* Cook up a public key with the same curveParams as the private key */
672		feeDepth depth;
673		frtn = curveParamsDepth(privInst->cp, &depth);
674		if(frtn) {
675			return frtn;
676		}
677		theirPub = feePubKeyAlloc();
678		if(theirPub == NULL) {
679			return FR_Memory;
680		}
681		frtn = feePubKeyInitFromECDSAPubBlob(theirPub, pubKeyStr, pubKeyStrLen, depth);
682		if(frtn) {
683			goto errOut;
684		}
685	}
686
687	pubKeyInst *pubInst = (pubKeyInst *) theirPub;
688
689	giant outputGiant = make_pad(privInst->privGiant, pubInst->plus);
690	if(outputGiant == NULL) {
691		dbgLog(("feePubKeyECDH: make_pad error\n"));
692		frtn = FR_Internal;
693	}
694	else {
695		*outputLen = (privInst->cp->q + 7) / 8;
696		*output = (unsigned char *)fmalloc(*outputLen);
697		if(*output == NULL) {
698			frtn = FR_Memory;
699			goto errOut;
700		}
701		serializeGiant(outputGiant, *output, *outputLen);
702		freeGiant(outputGiant);
703	}
704errOut:
705	if((pubKey == NULL) && (theirPub != NULL)) {
706		feePubKeyFree(theirPub);
707	}
708	return frtn;
709}
710
711#pragma mark --- feePubKey data accessors ---
712
713unsigned feePubKeyBitsize(feePubKey pubKey)
714{
715	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
716	switch(pkinst->cp->primeType) {
717		case FPT_General:	/* cp->q is here for just this purpose */
718		case FPT_Mersenne:
719			return pkinst->cp->q;
720		case FPT_FEE:		/* could be larger or smaller than 2^q-1 */
721		default:
722			return bitlen(pkinst->cp->basePrime);
723	}
724	/* NOT REACHED */
725	return 0;
726}
727
728/*
729 * Accessor routines.
730 */
731/* private only...*/
732key feePubKeyPlusCurve(feePubKey pubKey)
733{
734	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
735
736	return pkinst->plus;
737}
738
739key feePubKeyMinusCurve(feePubKey pubKey)
740{
741	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
742
743	return pkinst->minus;
744}
745
746curveParams *feePubKeyCurveParams(feePubKey pubKey)
747{
748	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
749
750	return pkinst->cp;
751}
752
753giant feePubKeyPrivData(feePubKey pubKey)
754{
755	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
756
757	return pkinst->privGiant;
758}
759
760const char *feePubKeyAlgorithmName(void)
761{
762	return "Elliptic Curve - FEE by Apple Computer";
763}
764
765#pragma mark --- Private functions ---
766
767/*
768 * alloc, free pubKeyInst
769 */
770static pubKeyInst *pubKeyInstAlloc(void)
771{
772	pubKeyInst *pkinst = (pubKeyInst *) fmalloc(sizeof(pubKeyInst));
773
774	bzero(pkinst, sizeof(pubKeyInst));
775	return pkinst;
776}
777
778static void pubKeyInstFree(pubKeyInst *pkinst)
779{
780	if(pkinst->minus) {
781		free_key(pkinst->minus);
782	}
783	if(pkinst->plus) {
784		free_key(pkinst->plus);
785	}
786	if(pkinst->cp) {
787		freeCurveParams(pkinst->cp);
788	}
789	if(pkinst->privGiant) {
790		/*
791		 * Zero out the private data...
792		 */
793		clearGiant(pkinst->privGiant);
794		freeGiant(pkinst->privGiant);
795	}
796	ffree(pkinst);
797}
798
799#ifndef	ECDSA_VERIFY_ONLY
800
801/*
802 * Create a pubKeyInst.privGiant given a password of
803 * arbitrary length.
804 * Currently, the only error is "private data too short" (FR_IllegalArg).
805 */
806
807#define NO_PRIV_MUNGE		0	/* skip this step */
808
809static feeReturn feeGenPrivate(pubKeyInst *pkinst,
810	const unsigned char *passwd,
811	unsigned passwdLen,
812	char hashPasswd)
813{
814	unsigned 		privLen;			// desired size of pkinst->privData
815	feeHash 		*hash = NULL;		// a malloc'd array
816	unsigned		digestLen;			// size of MD5 digest
817	unsigned 		dataSize;			// min(privLen, passwdLen)
818	unsigned		numDigests = 0;
819	unsigned		i;
820	unsigned char	*cp;
821	unsigned		toMove;				// for this digest
822	unsigned		moved;				// total digested
823	unsigned char	*digest = NULL;
824	unsigned char	*privData = NULL;	// temp, before modg(curveOrder)
825	giant			corder;				// lesser of two curve orders
826
827	/*
828	 * generate privData which is just larger than the smaller
829	 * curve order.
830	 * We'll take the result mod the curve order when we're done.
831	 * Note we do *not* have to free corder - it's a pointer to a giant
832	 * in pkinst->cp.
833	 */
834	corder = lesserX1Order(pkinst->cp);
835	CKASSERT(!isZero(corder));
836	privLen = (bitlen(corder) / 8) + 1;
837
838	if(!hashPasswd) {
839		/*
840		 * Caller trusts the incoming entropy. Verify it's big enough and proceed.
841		 */
842		if(passwdLen < privLen) {
843			return FR_ShortPrivData;
844		}
845		privLen = passwdLen;
846		privData = (unsigned char *)passwd;
847		goto finishUp;
848	}
849	if(passwdLen < 2) {
850		return FR_IllegalArg;
851	}
852
853
854	/*
855	 * Calculate how many MD5 digests we'll generate.
856	 */
857	if(privLen > passwdLen) {
858		dataSize = passwdLen;
859	}
860	else {
861		dataSize = privLen;
862	}
863	digestLen = feeHashDigestLen();
864	numDigests = (dataSize + digestLen - 1) / digestLen;
865
866	hash = (void**) fmalloc(numDigests * sizeof(feeHash));
867	for(i=0; i<numDigests; i++) {
868		hash[i] = feeHashAlloc();
869	}
870
871	/*
872	 * fill digests with passwd data, digestLen (or resid length)
873	 * at a time. If (passwdLen > privLen), last digest will hash all
874	 * remaining passwd data.
875	 */
876	cp = (unsigned char *)passwd;
877	moved = 0;
878	for(i=0; i<numDigests; i++) {
879		if(i == (numDigests - 1)) {		    // last digest
880		    toMove = passwdLen - moved;
881		}
882		else {
883		    toMove = digestLen;
884		}
885		feeHashAddData(hash[i], cp, toMove);
886		cp += toMove;
887		moved += toMove;
888	}
889
890	/*
891	 * copy digests to privData, up to privLen bytes. Pad with
892	 * additional copies of digests if necessary.
893	 */
894	privData = (unsigned char*) fmalloc(privLen);
895	cp = privData;
896	moved = 0;
897	i = 0;			// digest number
898	for(moved=0; moved<privLen; ) {
899		if((moved + digestLen) > privLen) {
900		   toMove = privLen - moved;
901		}
902		else {
903		   toMove = digestLen;
904		}
905		digest = feeHashDigest(hash[i++]);
906		bcopy(digest, cp, toMove);
907		cp += toMove;
908		moved += toMove;
909		if(i == numDigests) {
910		    i = 0;		// wrap to 0, start padding
911		}
912	}
913
914finishUp:
915	/*
916	 * Convert to giant, justify result to within [2, lesserX1Order]
917	 */
918	pkinst->privGiant = giant_with_data(privData, privLen);
919
920	#if	FEE_DEBUG
921	if(isZero(pkinst->privGiant)) {
922		printf("feeGenPrivate: privData = 0!\n");
923	}
924	#endif	// FEE_DEBUG
925
926	lesserX1OrderJustify(pkinst->privGiant, pkinst->cp);
927	if(hashPasswd) {
928		memset(privData, 0, privLen);
929		ffree(privData);
930		for(i=0; i<numDigests; i++) {
931			feeHashFree(hash[i]);
932		}
933		ffree(hash);
934	}
935	return FR_Success;
936}
937
938#endif	/* ECDSA_VERIFY_ONLY */
939
940#if	FEE_DEBUG
941
942void printPubKey(feePubKey pubKey)
943{
944	pubKeyInst *pkinst = pubKey;
945
946	printf("\ncurveParams:\n");
947	printCurveParams(pkinst->cp);
948	printf("plus:\n");
949	printKey(pkinst->plus);
950	printf("minus:\n");
951	printKey(pkinst->minus);
952	if(pkinst->privGiant != NULL) {
953	    printf("privGiant : ");
954	    printGiant(pkinst->privGiant);
955	}
956}
957
958#else	// FEE_DEBUG
959void printPubKey(feePubKey pubKey) {}
960#endif	// FEE_DEBUG
961
962/*
963 * Prime the curveParams and giants modules for quick allocs of giants.
964 */
965#if		GIANTS_VIA_STACK
966
967static int giantsInitd = 0;
968
969static void feePubKeyInitGiants(void)
970{
971	if(giantsInitd) {
972		return;
973	}
974	curveParamsInitGiants();
975	giantsInitd = 1;
976}
977#endif
978
979#pragma mark --- Native (custom) key blob formatting ---
980
981/*
982 * Exported key blob support. New, 23 Mar 1998.
983 *
984 * Convert to public or private key blob.
985 */
986
987#ifndef	ECDSA_VERIFY_ONLY
988
989/***
990 *** Common native blob support
991 ***/
992static feeReturn createKeyBlob(pubKeyInst *pkinst,
993	int 			isPrivate,		// 0 : public   1 : private
994	unsigned char 	**keyBlob,		// mallocd and RETURNED
995	unsigned 		*keyBlobLen)	// RETURNED
996{
997	unsigned char 	*s;		// running ptr into *origS
998	unsigned		sLen;
999	int				magic;
1000
1001	/* common blob elements */
1002	sLen = (4 * sizeof(int)) +		// magic, version, minVersion,
1003									// spare
1004	    lengthOfByteRepCurveParams(pkinst->cp);
1005	if(isPrivate) {
1006	    /* private only */
1007	    sLen += lengthOfByteRepGiant(pkinst->privGiant);
1008	    magic = PUBLIC_KEY_BLOB_MAGIC_PRIV;
1009	}
1010	else {
1011	    /* public only */
1012	    sLen += (lengthOfByteRepKey(pkinst->plus) +
1013		     lengthOfByteRepKey(pkinst->minus));
1014	    magic = PUBLIC_KEY_BLOB_MAGIC_PUB;
1015	}
1016	*keyBlob = s = (unsigned char*) fmalloc(sLen);
1017	s += intToByteRep(magic, s);
1018	s += intToByteRep(PUBLIC_KEY_BLOB_VERSION, s);
1019	s += intToByteRep(PUBLIC_KEY_BLOB_MINVERSION, s);
1020	s += intToByteRep(0, s);			// spare
1021	s += curveParamsToByteRep(pkinst->cp, s);
1022	if(isPrivate) {
1023	    s += giantToByteRep(pkinst->privGiant, s);
1024	}
1025	else {
1026	    /* keyToByteRep writes y for plus curve only */
1027	    s += keyToByteRep(pkinst->plus, s);
1028		if(pkinst->minus != NULL) {
1029			s += keyToByteRep(pkinst->minus, s);
1030		}
1031		else {
1032			/* TBD */
1033			dbgLog(("work needed here for blobs with no minus key\n"));
1034		}
1035	}
1036	*keyBlobLen = sLen;
1037	return FR_Success;
1038}
1039
1040#endif	/* ECDSA_VERIFY_ONLY */
1041
1042/*
1043 * Init an empty feePubKey from a native blob (non-DER format).
1044 */
1045static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
1046	unsigned char *keyBlob,
1047	unsigned keyBlobLen)
1048{
1049	pubKeyInst		*pkinst = (pubKeyInst *) pubKey;
1050	unsigned char	*s;		// running pointer
1051	unsigned		sLen;		// bytes remaining in *s
1052	int				magic;
1053	unsigned		len;		// for length of individual components
1054	int 			minVersion;
1055	int				version;
1056	int				isPrivate;
1057
1058	s = keyBlob;
1059	sLen = keyBlobLen;
1060	if(sLen < (4 * sizeof(int))) {	// magic, version, minVersion, spare
1061		/*
1062		 * Too short for all the ints we need
1063		 */
1064		dbgLog(("feePublicKey: key blob (1)\n"));
1065		return FR_BadKeyBlob;
1066	}
1067
1068	magic = byteRepToInt(s);
1069	s += sizeof(int);
1070	sLen -= sizeof(int);
1071	switch(magic) {
1072	    case PUBLIC_KEY_BLOB_MAGIC_PUB:
1073	    	isPrivate = 0;
1074		break;
1075	    case PUBLIC_KEY_BLOB_MAGIC_PRIV:
1076	    	isPrivate = 1;
1077		break;
1078	    default:
1079		dbgLog(("feePublicKey: Bad Public Key Magic Number\n"));
1080		return FR_BadKeyBlob;
1081	}
1082
1083	/*
1084	 * Switch on this for version-specific cases
1085	 */
1086	version = byteRepToInt(s);
1087	s += sizeof(int);
1088	sLen -= sizeof(int);
1089
1090	minVersion = byteRepToInt(s);
1091	s += sizeof(int);
1092	sLen -= sizeof(int);
1093	if(minVersion > PUBLIC_KEY_BLOB_VERSION) {
1094		/*
1095		 * old code, newer key blob - can't parse
1096		 */
1097		dbgLog(("feePublicKey: Incompatible Public Key (1)\n"));
1098		return FR_BadKeyBlob;
1099	}
1100
1101	s += sizeof(int);			// skip spare
1102	sLen -= sizeof(int);
1103
1104	pkinst->cp = byteRepToCurveParams(s, sLen, &len);
1105	if(pkinst->cp == NULL) {
1106		dbgLog(("feePublicKey: Bad Key Blob(2)\n"));
1107		return FR_BadKeyBlob;
1108	}
1109	s += len;
1110	sLen -= len;
1111
1112	/*
1113	 * Private key blob: privGiant.
1114	 * Public Key blob:  plusX, minusX, plusY.
1115	 */
1116	if(isPrivate) {
1117		pkinst->privGiant = byteRepToGiant(s, sLen, &len);
1118		if(pkinst->privGiant == NULL) {
1119			dbgLog(("feePublicKey: Bad Key Blob(3)\n"));
1120			return FR_BadKeyBlob;
1121		}
1122		s += len;
1123		sLen -= len;
1124	}
1125	else {
1126		/* this writes x and y */
1127		pkinst->plus = byteRepToKey(s,
1128			sLen,
1129			CURVE_PLUS,		// twist
1130			pkinst->cp,
1131			&len);
1132		if(pkinst->plus == NULL) {
1133			dbgLog(("feePublicKey: Bad Key Blob(4)\n"));
1134			return FR_BadKeyBlob;
1135		}
1136		s += len;
1137		sLen -= len;
1138
1139		/* this only writes x */
1140		pkinst->minus = byteRepToKey(s,
1141			sLen,
1142			CURVE_MINUS,		// twist
1143			pkinst->cp,
1144			&len);
1145		if(pkinst->minus == NULL) {
1146			dbgLog(("feePublicKey: Bad Key Blob(5)\n"));
1147			return FR_BadKeyBlob;
1148		}
1149		s += len;
1150		sLen -= len;
1151	}
1152
1153	/*
1154	 * One more thing: cook up public plusX and minusX for private key
1155	 * blob case.
1156	 */
1157	if(isPrivate) {
1158		pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
1159		pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
1160		set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1161		set_priv_key_giant(pkinst->minus, pkinst->privGiant);
1162	}
1163	return FR_Success;
1164
1165}
1166
1167feeReturn feePubKeyInitFromPubBlob(feePubKey pubKey,
1168	unsigned char *keyBlob,
1169	unsigned keyBlobLen)
1170{
1171	return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
1172}
1173
1174#ifndef	ECDSA_VERIFY_ONLY
1175
1176feeReturn feePubKeyInitFromPrivBlob(feePubKey pubKey,
1177	unsigned char *keyBlob,
1178	unsigned keyBlobLen)
1179{
1180	return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
1181}
1182
1183#endif	/* ECDSA_VERIFY_ONLY */
1184
1185#if	CRYPTKIT_DER_ENABLE
1186#ifndef	ECDSA_VERIFY_ONLY
1187
1188/*
1189 * DER format support.
1190 * Obtain portable public and private DER-encoded key blobs from a key.
1191 */
1192feeReturn feePubKeyCreateDERPubBlob(feePubKey pubKey,
1193	unsigned char **keyBlob,	// mallocd and RETURNED
1194	unsigned *keyBlobLen)		// RETURNED
1195{
1196	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1197
1198	if(pkinst == NULL) {
1199		return FR_BadPubKey;
1200	}
1201	if(pkinst->minus == NULL) {
1202		/* Only ECDSA key formats supported */
1203		return FR_IncompatibleKey;
1204	}
1205	return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION,
1206		pkinst->cp,
1207		pkinst->plus->x,
1208		pkinst->minus->x,
1209		isZero(pkinst->plus->y) ? NULL : pkinst->plus->y,
1210		keyBlob,
1211		keyBlobLen);
1212}
1213
1214feeReturn feePubKeyCreateDERPrivBlob(feePubKey pubKey,
1215	unsigned char **keyBlob,	// mallocd and RETURNED
1216	unsigned *keyBlobLen)		// RETURNED
1217{
1218	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1219
1220	if(pkinst == NULL) {
1221		return FR_BadPubKey;
1222	}
1223	if(pkinst->privGiant == NULL) {
1224		return FR_IncompatibleKey;
1225	}
1226	if(pkinst->minus == NULL) {
1227		/* Only ECDSA key formats supported */
1228		return FR_IncompatibleKey;
1229	}
1230	return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION,
1231		pkinst->cp,
1232		pkinst->privGiant,
1233		keyBlob,
1234		keyBlobLen);
1235}
1236
1237#endif	/* ECDSA_VERIFY_ONLY */
1238
1239/*
1240 * Init an empty feePubKey from a DER-encoded blob, public and private key versions.
1241 */
1242feeReturn feePubKeyInitFromDERPubBlob(feePubKey pubKey,
1243	unsigned char *keyBlob,
1244	size_t keyBlobLen)
1245{
1246	pubKeyInst	*pkinst = (pubKeyInst *) pubKey;
1247	feeReturn	frtn;
1248	int			version;
1249
1250	if(pkinst == NULL) {
1251		return FR_BadPubKey;
1252	}
1253
1254	/* kind of messy, maybe we should clean this up. But new_public() does too
1255	 * much - e.g., it allocates the x and y which we really don't want */
1256	 memset(pkinst, 0, sizeof(pubKeyInst));
1257	 pkinst->plus = (key) fmalloc(sizeof(keystruct));
1258	 pkinst->minus = (key) fmalloc(sizeof(keystruct));
1259	 if((pkinst->plus == NULL) || (pkinst->minus == NULL)) {
1260		return FR_Memory;
1261	 }
1262	 memset(pkinst->plus, 0, sizeof(keystruct));
1263	 memset(pkinst->minus, 0, sizeof(keystruct));
1264	 pkinst->cp = NULL;
1265	 pkinst->privGiant = NULL;
1266	 pkinst->plus->twist  = CURVE_PLUS;
1267	 pkinst->minus->twist = CURVE_MINUS;
1268	 frtn = feeDERDecodePublicKey(keyBlob,
1269		(unsigned)keyBlobLen,
1270		&version,			// currently unused
1271		&pkinst->cp,
1272		&pkinst->plus->x,
1273		&pkinst->minus->x,
1274		&pkinst->plus->y);
1275	if(frtn) {
1276		return frtn;
1277	}
1278	/* minus curve, y is not used */
1279	pkinst->minus->y = newGiant(1);
1280	int_to_giant(0, pkinst->minus->y);
1281	pkinst->plus->cp = pkinst->minus->cp = pkinst->cp;
1282	return FR_Success;
1283}
1284
1285#ifndef	ECDSA_VERIFY_ONLY
1286
1287feeReturn feePubKeyInitFromDERPrivBlob(feePubKey pubKey,
1288	unsigned char *keyBlob,
1289	size_t keyBlobLen)
1290{
1291	pubKeyInst	*pkinst = (pubKeyInst *) pubKey;
1292	int			version;
1293	feeReturn	frtn;
1294
1295	if(pkinst == NULL) {
1296		return FR_BadPubKey;
1297	}
1298	memset(pkinst, 0, sizeof(pubKeyInst));
1299	frtn = feeDERDecodePrivateKey(keyBlob,
1300		(unsigned)keyBlobLen,
1301		&version,		// currently unused
1302		&pkinst->cp,
1303		&pkinst->privGiant);
1304	if(frtn) {
1305		return frtn;
1306	}
1307
1308	/* since this blob only had the private data, infer the remaining fields */
1309	pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
1310	pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
1311	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1312	set_priv_key_giant(pkinst->minus, pkinst->privGiant);
1313	return FR_Success;
1314}
1315
1316#endif	/* ECDSA_VERIFY_ONLY */
1317
1318#pragma mark --- X509 (public) and PKCS8 (private) key formatting ---
1319
1320feeReturn feePubKeyCreateX509Blob(
1321	feePubKey pubKey,			// public key
1322	unsigned char **keyBlob,	// mallocd and RETURNED
1323	unsigned *keyBlobLen)		// RETURNED
1324{
1325	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1326	unsigned char *xyStr = NULL;
1327	unsigned xyStrLen = 0;
1328	feeReturn frtn = feeCreateECDSAPubBlob(pubKey, &xyStr, &xyStrLen);
1329	if(frtn) {
1330		return frtn;
1331	}
1332	frtn = feeDEREncodeX509PublicKey(xyStr, xyStrLen, pkinst->cp, keyBlob, keyBlobLen);
1333	ffree(xyStr);
1334	return frtn;
1335}
1336
1337feeReturn feePubKeyCreatePKCS8Blob(
1338	feePubKey pubKey,			// private key
1339	unsigned char **keyBlob,	// mallocd and RETURNED
1340	unsigned *keyBlobLen)		// RETURNED
1341{
1342	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1343	unsigned char *privStr = NULL;
1344	unsigned privStrLen = 0;
1345	feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1346	if(frtn) {
1347		return frtn;
1348	}
1349	unsigned char *pubStr = NULL;
1350	unsigned pubStrLen = 0;
1351	frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1352	if(frtn) {
1353		goto errOut;
1354	}
1355	frtn = feeDEREncodePKCS8PrivateKey(privStr, privStrLen,
1356		pubStr, pubStrLen,
1357		pkinst->cp, keyBlob, keyBlobLen);
1358errOut:
1359	if(privStr) {
1360		ffree(privStr);
1361	}
1362	if(pubStr) {
1363		ffree(pubStr);
1364	}
1365	return frtn;
1366}
1367
1368feeReturn feePubKeyInitFromX509Blob(
1369	feePubKey pubKey,			// public key
1370	unsigned char *keyBlob,
1371	size_t keyBlobLen)
1372{
1373	feeDepth depth;
1374	unsigned char *xyStr = NULL;
1375	unsigned xyStrLen = 0;
1376
1377	/* obtain x/y and depth from X509 encoding */
1378	feeReturn frtn = feeDERDecodeX509PublicKey(keyBlob, (unsigned)keyBlobLen, &depth,
1379		&xyStr, &xyStrLen);
1380	if(frtn) {
1381		return frtn;
1382	}
1383
1384	frtn = feePubKeyInitFromECDSAPubBlob(pubKey, xyStr, xyStrLen, depth);
1385	ffree(xyStr);
1386	return frtn;
1387}
1388
1389
1390feeReturn feePubKeyInitFromPKCS8Blob(
1391	feePubKey pubKey,			// private key
1392	unsigned char *keyBlob,
1393	size_t keyBlobLen)
1394{
1395	feeDepth depth;
1396	unsigned char *privStr = NULL;
1397	unsigned privStrLen = 0;
1398
1399	/* obtain x/y and depth from PKCS8 encoding */
1400	/* For now we ignore the possible public key string */
1401	feeReturn frtn = feeDERDecodePKCS8PrivateKey(keyBlob, (unsigned)keyBlobLen, &depth,
1402		&privStr, &privStrLen, NULL, NULL);
1403	if(frtn) {
1404		return frtn;
1405	}
1406
1407	frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1408	ffree(privStr);
1409	return frtn;
1410}
1411
1412#pragma mark --- OpenSSL key formatting ---
1413
1414/*
1415 * The native OpenSSL ECDSA key format contains both the private and public
1416 * components in one blob. This throws a bit of a monkey wrench into the API
1417 * here, as we only have one encoder - which requires a private key - and one
1418 * decoder, which can result in the decoding of either a public or a private
1419 * key.
1420 */
1421feeReturn feePubKeyCreateOpenSSLBlob(
1422	feePubKey pubKey,			// private key
1423	unsigned char **keyBlob,	// mallocd and RETURNED
1424	unsigned *keyBlobLen)		// RETURNED
1425{
1426	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1427	unsigned char *privStr = NULL;
1428	unsigned privStrLen = 0;
1429	feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1430	if(frtn) {
1431		return frtn;
1432	}
1433	unsigned char *pubStr = NULL;
1434	unsigned pubStrLen = 0;
1435	frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1436	if(frtn) {
1437		goto errOut;
1438	}
1439	frtn = feeDEREncodeOpenSSLPrivateKey(privStr, privStrLen,
1440		pubStr, pubStrLen,
1441		pkinst->cp, keyBlob, keyBlobLen);
1442errOut:
1443	if(privStr) {
1444		ffree(privStr);
1445	}
1446	if(pubStr) {
1447		ffree(pubStr);
1448	}
1449	return frtn;
1450}
1451
1452feeReturn feePubKeyInitFromOpenSSLBlob(
1453	feePubKey pubKey,			// private or public key
1454	int pubOnly,
1455	unsigned char *keyBlob,
1456	size_t keyBlobLen)
1457{
1458	feeDepth depth;
1459	unsigned char *privStr = NULL;
1460	unsigned privStrLen = 0;
1461	unsigned char *pubStr = NULL;
1462	unsigned pubStrLen = 0;
1463
1464	/* obtain x/y, public bit string, and depth from PKCS8 encoding */
1465	feeReturn frtn = feeDERDecodeOpenSSLKey(keyBlob, (unsigned)keyBlobLen, &depth,
1466		&privStr, &privStrLen, &pubStr, &pubStrLen);
1467	if(frtn) {
1468		return frtn;
1469	}
1470
1471	if(pubOnly) {
1472		frtn = feePubKeyInitFromECDSAPubBlob(pubKey, pubStr, pubStrLen, depth);
1473	}
1474	else {
1475		frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1476	}
1477	if(privStr) {
1478		ffree(privStr);
1479	}
1480	if(pubStr) {
1481		ffree(pubStr);
1482	}
1483	return frtn;
1484}
1485
1486#endif	/* CRYPTKIT_DER_ENABLE */
1487
1488/*
1489 * ANSI X9.62/Certicom key support.
1490 * Public key is 04 || x || y
1491 * Private key is privData per Certicom SEC1 C.4.
1492 */
1493feeReturn feeCreateECDSAPubBlob(feePubKey pubKey,
1494	unsigned char **keyBlob,
1495	unsigned *keyBlobLen)
1496{
1497	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1498	if(pkinst == NULL) {
1499		return FR_BadPubKey;
1500	}
1501
1502	unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1503	unsigned blobSize = 1 + (2 * giantBytes);
1504	unsigned char *blob = fmalloc(blobSize);
1505	if(blob == NULL) {
1506		return FR_Memory;
1507	}
1508	*blob = 0x04;
1509	serializeGiant(pkinst->plus->x, blob+1, giantBytes);
1510	serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes);
1511	*keyBlob = blob;
1512	*keyBlobLen = blobSize;
1513	return FR_Success;
1514}
1515
1516feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey,
1517	unsigned char **keyBlob,
1518	unsigned *keyBlobLen)
1519{
1520	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1521	if(pkinst == NULL) {
1522		return FR_BadPubKey;
1523	}
1524	if(pkinst->privGiant == NULL) {
1525		return FR_IncompatibleKey;
1526	}
1527
1528	/*
1529	 * Return the raw private key bytes padded with zeroes in
1530	 * the m.s. end to fill exactly one prime-size byte array.
1531	 */
1532	unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1533	unsigned char *blob = fmalloc(giantBytes);
1534	if(blob == NULL) {
1535		return FR_Memory;
1536	}
1537	serializeGiant(pkinst->privGiant, blob, giantBytes);
1538	*keyBlob = blob;
1539	*keyBlobLen = giantBytes;
1540	return FR_Success;
1541}
1542
1543/* Caller determines depth from other sources (e.g. AlgId.Params) */
1544feeReturn feePubKeyInitFromECDSAPubBlob(feePubKey pubKey,
1545	const unsigned char *keyBlob,
1546	unsigned keyBlobLen,
1547	feeDepth depth)
1548{
1549	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1550	if(pkinst == NULL) {
1551		return FR_BadPubKey;
1552	}
1553	curveParams *cp = curveParamsForDepth(depth);
1554	if(cp == NULL) {
1555		return FR_IllegalDepth;
1556	}
1557	unsigned giantBytes = (cp->q + 7) / 8;
1558	unsigned blobSize = 1 + (2 * giantBytes);
1559	if(keyBlobLen != blobSize) {
1560		dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blobLen\n"));
1561		return FR_BadKeyBlob;
1562	}
1563	if(*keyBlob != 0x04) {
1564		dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n"));
1565		return FR_BadKeyBlob;
1566	}
1567
1568	pkinst->cp = cp;
1569	pkinst->plus = new_public(cp, CURVE_PLUS);
1570	deserializeGiant(keyBlob+1, pkinst->plus->x, giantBytes);
1571	deserializeGiant(keyBlob+1+giantBytes, pkinst->plus->y, giantBytes);
1572	return FR_Success;
1573}
1574
1575feeReturn feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey,
1576	const unsigned char *keyBlob,
1577	unsigned keyBlobLen,
1578	feeDepth depth)
1579{
1580	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1581	if(pkinst == NULL) {
1582		return FR_BadPubKey;
1583	}
1584	curveParams *cp = curveParamsForDepth(depth);
1585	if(cp == NULL) {
1586		return FR_IllegalDepth;
1587	}
1588	unsigned giantDigits = cp->basePrime->sign;
1589	unsigned giantBytes = (cp->q + 7) / 8;
1590
1591	/*
1592	 * The specified private key can be one byte smaller than the modulus */
1593	if((keyBlobLen > giantBytes) || (keyBlobLen < (giantBytes - 1))) {
1594		dbgLog(("feePubKeyInitFromECDSAPrivBlob: bad blobLen\n"));
1595		return FR_BadKeyBlob;
1596	}
1597
1598	pkinst->cp = cp;
1599
1600	/* cook up a new private giant */
1601	pkinst->privGiant = newGiant(giantDigits);
1602	if(pkinst->privGiant == NULL) {
1603		return FR_Memory;
1604	}
1605	deserializeGiant(keyBlob, pkinst->privGiant, keyBlobLen);
1606
1607	/* since this blob only had the private data, infer the remaining fields */
1608	pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
1609	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1610	return FR_Success;
1611}
1612
1613