1/*
2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20 * CryptKitDER.h - snacc-based routines to create and parse DER-encoded FEE
21 *				   keys and signatures
22 *
23 */
24
25#include "ckconfig.h"
26
27#if	CRYPTKIT_DER_ENABLE
28
29#include <security_cryptkit/CryptKitDER.h>
30#include <security_cryptkit/falloc.h>
31#include <security_cryptkit/feeDebug.h>
32#include <security_cryptkit/feeFunctions.h>
33#include "CryptKitAsn1.h"
34#include <security_asn1/SecNssCoder.h>
35#include <security_asn1/nssUtils.h>
36#include <Security/keyTemplates.h>
37#include <Security/oidsalg.h>
38#include <Security/oidsattr.h>
39
40#define PRINT_SIG_GIANTS		0
41#define PRINT_CURVE_PARAMS		0
42#define PRINT_SIZES				0
43#if		PRINT_SIZES
44#define szprint(s)				printf s
45#else
46#define szprint(s)
47#endif
48
49/*
50 * Trivial exception class associated with a feeReturn.
51 */
52class feeException
53{
54protected:
55	feeException(feeReturn frtn, const char *op);
56public:
57	~feeException() throw() {}
58	feeReturn frtn() const throw() { return mFrtn; }
59    static void throwMe(feeReturn frtn, const char *op = NULL) __attribute__((noreturn));
60private:
61	feeReturn mFrtn;
62};
63
64feeException::feeException(
65	feeReturn frtn,
66	const char *op)
67		: mFrtn(frtn)
68{
69	if(op) {
70		dbgLog(("%s: %s\n", op, feeReturnString(frtn)));
71	}
72}
73
74void feeException::throwMe(feeReturn frtn, const char *op /*= NULL*/) { throw feeException(frtn, op); }
75
76/*
77 * ASN1 encoding rules specify that an integer's sign is indicated by the MSB
78 * of the first (MS) content byte. For a non-negative number, if the MSB of
79 * the MS byte (of the unencoded number) is one, then the encoding starts with
80 * a byte of zeroes to indicate positive sign. For a negative number, the first
81 * nine bits can not be all 1 - if they are (in the undecoded number), leading
82 * bytes of 0xff are trimmed off until the first nine bits are something other
83 * than one. Also, the first nine bits of the encoded number can not all be
84 * zero.
85 *
86 * CryptKit giants express their sign as part of the giantstruct.sign field.
87 * The giantDigit array (giantstruct.n[]) is stored l.s. digit first.
88 *
89 * These routines are independent of platform, endianness, and giatn digit size.
90 */
91
92/* routines to guess maximum size of DER-encoded objects */
93static unsigned feeSizeOfSnaccGiant(
94	giant g)
95{
96	unsigned rtn = abs(g->sign) * GIANT_BYTES_PER_DIGIT;
97	szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g->sign, rtn + 4));
98	return rtn + 4;
99}
100
101/* PUBLIC... */
102unsigned feeSizeOfDERSig(
103	giant g1,
104	giant g2)
105{
106	unsigned rtn = feeSizeOfSnaccGiant(g1);
107	rtn += feeSizeOfSnaccGiant(g2);
108	szprint(("feeSizeOfDERSig: size %d\n", rtn + 4));
109	return rtn + 4;
110}
111
112/* perform 2's complement of byte array, expressed MS byte first */
113static void twosComplement(
114	unsigned char *bytePtr,		// points to MS byte
115	unsigned numBytes)
116{
117	unsigned char *outp = bytePtr + numBytes - 1;
118	unsigned char carry = 1;	// first time thru, carry = 1 to add one to 1's comp
119	for(unsigned byteDex=0; byteDex<numBytes; byteDex++) {
120		/* first complement, then add carry */
121		*outp = ~*outp + carry;
122		if(carry && (*outp == 0)) {
123			/* overflow/carry */
124			carry = 1;
125		}
126		else {
127			carry = 0;
128		}
129		outp--;
130	}
131}
132
133/*
134 * CSSM_DATA --> unsigned int
135 */
136static unsigned cssmDataToInt(
137	const CSSM_DATA &cdata)
138{
139	if((cdata.Length == 0) || (cdata.Data == NULL)) {
140		return 0;
141	}
142	unsigned len = (unsigned)cdata.Length;
143	if(len > sizeof(int)) {
144		feeException::throwMe(FR_BadKeyBlob, "cssmDataToInt");
145	}
146
147	unsigned rtn = 0;
148	uint8 *cp = cdata.Data;
149	for(unsigned i=0; i<len; i++) {
150		rtn = (rtn << 8) | *cp++;
151	}
152	return rtn;
153}
154
155/*
156 * unsigned int --> CSSM_DATA, mallocing from an SecNssCoder
157 */
158static void intToCssmData(
159	unsigned num,
160	CSSM_DATA &cdata,
161	SecNssCoder &coder)
162{
163	unsigned len = 0;
164
165	if(num < 0x100) {
166		len = 1;
167	}
168	else if(num < 0x10000) {
169		len = 2;
170	}
171	else if(num < 0x1000000) {
172		len = 3;
173	}
174	else {
175		len = 4;
176	}
177	cdata.Data = (uint8 *)coder.malloc(len);
178	cdata.Length = len;
179	uint8 *cp = &cdata.Data[len - 1];
180	for(unsigned i=0; i<len; i++) {
181		*cp-- = num & 0xff;
182		num >>= 8;
183	}
184}
185
186/*
187 * Convert a decoded ASN integer, as a CSSM_DATA, to a (mallocd) giant.
188 * Only known exception is a feeException.
189 */
190static giant cssmDataToGiant(
191	const CSSM_DATA 	&cdata)
192{
193	char *rawOcts = (char *)cdata.Data;
194	unsigned numBytes = (unsigned)cdata.Length;
195	unsigned numGiantDigits;
196	int sign = 1;
197	giant grtn;
198	feeReturn frtn = FR_Success;
199	unsigned char *inp = NULL;
200	unsigned digitDex;			// index into g->giantDigit[]
201
202	/* handle degenerate case (value of zero) */
203	if((numBytes == 0) || ((numBytes == 1) && rawOcts[0] == 0)) {
204		grtn = newGiant(1);
205		if(grtn == NULL) {
206			feeException::throwMe(FR_Memory, "newGiant(1)");
207		}
208		int_to_giant(0, grtn);
209		return grtn;
210	}
211
212	/* make a copy of raw octets if we have to do two's complement */
213	unsigned char *byteArray = NULL;
214	bool didMalloc = false;
215	if(rawOcts[0] & 0x80) {
216		sign = -1;
217		numBytes++;
218		byteArray = (unsigned char *)fmalloc(numBytes);
219		didMalloc = true;
220		byteArray[0] = 0xff;
221		memmove(byteArray + 1, rawOcts, numBytes-1);
222		twosComplement(byteArray, numBytes);
223	}
224	else {
225		/* no copy */
226		char *foo = rawOcts;
227		byteArray = (unsigned char *)foo;
228	}
229
230	/* cook up a new giant */
231	numGiantDigits = (numBytes + GIANT_BYTES_PER_DIGIT - 1) /
232			GIANT_BYTES_PER_DIGIT;
233	grtn = newGiant(numGiantDigits);
234	if(grtn == NULL) {
235		frtn = FR_Memory;
236		goto abort;
237	}
238
239	/*
240	 * Convert byteArray to array of giantDigits
241	 * inp - raw input bytes, LSB last
242	 * grtn->n[] - output array of giantDigits, LSD first
243	 * Start at LS byte and LD digit
244	 */
245	digitDex = 0;					// index into g->giantDigit[]
246	giantDigit thisDigit;
247	inp = byteArray + numBytes - 1;
248	unsigned dex;					// total byte counter
249	unsigned byteDex;				// index into one giantDigit
250	unsigned shiftCount;
251	for(dex=0; dex<numBytes; ) {	// increment dex inside
252		thisDigit = 0;
253		shiftCount = 0;
254		for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) {
255			thisDigit |= ((giantDigit)(*inp--) << shiftCount);
256			shiftCount += 8;
257			if(++dex == numBytes) {
258				/* must be partial giantDigit */
259				break;
260			}
261		}
262		CKASSERT(digitDex < numGiantDigits);
263		grtn->n[digitDex++] = thisDigit;
264	}
265	grtn->sign = (int)numGiantDigits * sign;
266
267	/* trim leading (MS) zeroes */
268	gtrimSign(grtn);
269abort:
270	if(didMalloc) {
271		ffree(byteArray);
272	}
273	if(frtn) {
274		feeException::throwMe(frtn, "bigIntStrToGiant");
275	}
276	return grtn;
277}
278
279/*
280 * Convert a giant to an CSSM_DATA, mallocing using specified coder.
281 * Only known exception is a feeException.
282 */
283 static void giantToCssmData(
284	giant 		g,
285	CSSM_DATA 	&cdata,
286	SecNssCoder	&coder)
287{
288	unsigned char doPrepend = 0;
289	unsigned numGiantDigits = abs(g->sign);
290	unsigned numBytes = numGiantDigits * GIANT_BYTES_PER_DIGIT;
291	giantDigit msGiantBit = 0;
292	if(isZero(g)) {
293		/* special degenerate case */
294		intToCssmData(0, cdata, coder);
295		return;
296	}
297	else {
298		msGiantBit = g->n[numGiantDigits - 1] >> (GIANT_BITS_PER_DIGIT - 1);
299	}
300
301	/* prepend a byte of zero if necessary */
302	if((g->sign < 0) ||					// negative - to handle 2's complement
303	   ((g->sign > 0) && msGiantBit)) {	// ensure MS byte is zero
304			doPrepend = 1;
305			numBytes++;
306	}
307
308	unsigned char *rawBytes = (unsigned char *)fmalloc(numBytes);
309	if(rawBytes == NULL) {
310		feeException::throwMe(FR_Memory, "giantToBigIntStr fmalloc(rawBytes)");
311	}
312	unsigned char *outp = rawBytes;
313	if(doPrepend) {
314		*outp++ = 0;
315	}
316
317	/*
318	 * Convert array of giantDigits to bytes.
319	 * outp point to MS output byte.
320	 */
321	int digitDex;			// index into g->giantDigit[]
322	unsigned byteDex;		// byte index into a giantDigit
323	for(digitDex=numGiantDigits-1; digitDex>=0; digitDex--) {
324		/* one loop per giantDigit, starting at MS end */
325		giantDigit thisDigit = g->n[digitDex];
326		unsigned char *bp = outp + GIANT_BYTES_PER_DIGIT - 1;
327		for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) {
328			/* one loop per byte within the digit, starting at LS end */
329			*bp-- = (unsigned char)(thisDigit) & 0xff;
330			thisDigit >>= 8;
331		}
332		outp += GIANT_BYTES_PER_DIGIT;
333	}
334
335	/* do two's complement for negative giants */
336	if(g->sign < 0) {
337		twosComplement(rawBytes, numBytes);
338	}
339
340	/* strip off redundant leading bits (nine zeroes or nine ones) */
341	outp = rawBytes;
342	unsigned char *endp = outp + numBytes - 1;
343	while((*outp == 0) &&			// m.s. byte zero
344	      (outp < endp) &&			// more bytes exist
345		  (!(outp[1] & 0x80))) {	// 9th bit is 0
346		outp++;
347		numBytes--;
348	}
349	while((*outp == 0xff) &&		// m.s. byte all ones
350	      (outp < endp) &&			// more bytes exist
351		  (outp[1] & 0x80)) {		// 9th bit is 1
352		outp++;
353		numBytes--;
354	}
355	cdata.Data = (uint8 *)coder.malloc(numBytes);
356	memmove(cdata.Data, outp, numBytes);
357	cdata.Length = numBytes;
358	ffree(rawBytes);
359	return;
360}
361
362/* curveParams : CryptKit <--> FEECurveParametersASN1 */
363/* Only known exception is a feeException */
364static void feeCurveParamsToASN1(
365	const curveParams *cp,
366	FEECurveParametersASN1 &asnCp,
367	SecNssCoder &coder)
368{
369	#if 	PRINT_CURVE_PARAMS
370	printf("===encoding curveParams; cp:\n"); printCurveParams(cp);
371	#endif
372	memset(&asnCp, 0, sizeof(asnCp));
373	try {
374		intToCssmData(cp->primeType, asnCp.primeType, coder);
375		intToCssmData(cp->curveType, asnCp.curveType, coder);
376		intToCssmData(cp->q, asnCp.q, coder);
377		intToCssmData(cp->k, asnCp.k, coder);
378		intToCssmData(cp->m, asnCp.m, coder);
379		giantToCssmData(cp->a, asnCp.a, coder);
380		giantToCssmData(cp->b, asnCp.b_, coder);
381		giantToCssmData(cp->c, asnCp.c, coder);
382		giantToCssmData(cp->x1Plus, asnCp.x1Plus, coder);
383		giantToCssmData(cp->x1Minus, asnCp.x1Minus, coder);
384		giantToCssmData(cp->cOrderPlus, asnCp.cOrderPlus, coder);
385		giantToCssmData(cp->cOrderMinus, asnCp.cOrderMinus, coder);
386		giantToCssmData(cp->x1OrderPlus, asnCp.x1OrderPlus, coder);
387		giantToCssmData(cp->x1OrderMinus, asnCp.x1OrderMinus, coder);
388		if(cp->primeType == FPT_General) {
389			giantToCssmData(cp->basePrime, asnCp.basePrime, coder);
390		}
391	}
392	catch(const feeException &ferr) {
393		throw;
394	}
395	catch(...) {
396		feeException::throwMe(FR_Memory, "feeCurveParamsToSnacc catchall");	// ???
397	}
398}
399
400static curveParams *feeCurveParamsFromAsn1(
401	const FEECurveParametersASN1 &asnCp)
402{
403	curveParams *cp = newCurveParams();
404	if(cp == NULL) {
405		feeException::throwMe(FR_Memory, "feeCurveParamsFromSnacc alloc cp");
406	}
407	cp->primeType = (feePrimeType)cssmDataToInt(asnCp.primeType);
408	cp->curveType = (feeCurveType)cssmDataToInt(asnCp.curveType);
409	cp->q 			   = cssmDataToInt(asnCp.q);
410	cp->k 			   = cssmDataToInt(asnCp.k);
411	cp->m 			   = cssmDataToInt(asnCp.m);
412	cp->a 			   = cssmDataToGiant(asnCp.a);
413	cp->b 			   = cssmDataToGiant(asnCp.b_);
414	cp->c              = cssmDataToGiant(asnCp.c);
415	cp->x1Plus         = cssmDataToGiant(asnCp.x1Plus);
416	cp->x1Minus        = cssmDataToGiant(asnCp.x1Minus);
417	cp->cOrderPlus     = cssmDataToGiant(asnCp.cOrderPlus);
418	cp->cOrderMinus    = cssmDataToGiant(asnCp.cOrderMinus);
419	cp->x1OrderPlus    = cssmDataToGiant(asnCp.x1OrderPlus);
420	cp->x1OrderMinus   = cssmDataToGiant(asnCp.x1OrderMinus);
421	if(asnCp.basePrime.Data != NULL) {
422		cp->basePrime  = cssmDataToGiant(asnCp.basePrime);
423	}
424
425	/* remaining fields inferred */
426	curveParamsInferFields(cp);
427	allocRecipGiants(cp);
428	#if 	PRINT_CURVE_PARAMS
429	printf("===decoding curveParams; cp:\n"); printCurveParams(cp);
430	#endif
431	return cp;
432}
433
434/***
435 *** Public routines. These are usable from C code; they never throw.
436 ***/
437
438/*
439 * Encode/decode the two FEE signature types. We malloc returned data via
440 * fmalloc(); caller must free via ffree().
441 */
442feeReturn feeDEREncodeElGamalSignature(
443	giant			u,
444	giant			PmX,
445	unsigned char	**encodedSig,		// fmallocd and RETURNED
446	unsigned		*encodedSigLen)		// RETURNED
447{
448	/* convert to FEEElGamalSignatureASN1 */
449	FEEElGamalSignatureASN1 asnSig;
450	SecNssCoder coder;
451
452	try {
453		giantToCssmData(u, asnSig.u, coder);
454		giantToCssmData(PmX, asnSig.pmX, coder);
455	}
456	catch(const feeException &ferr) {
457		return ferr.frtn();
458	}
459
460	/* DER encode */
461	PRErrorCode perr;
462	CSSM_DATA encBlob;			// mallocd by coder
463	perr = coder.encodeItem(&asnSig, FEEElGamalSignatureASN1Template, encBlob);
464	if(perr) {
465		return FR_Memory;
466	}
467
468	/* copy out  to caller */
469	*encodedSig = (unsigned char *)fmalloc((unsigned)encBlob.Length);
470	*encodedSigLen = (unsigned)encBlob.Length;
471	memmove(*encodedSig, encBlob.Data, encBlob.Length);
472
473	#if	PRINT_SIG_GIANTS
474	printf("feeEncodeElGamalSignature:\n");
475	printf("   u   : "); printGiantHex(u);
476	printf("   PmX : "); printGiantHex(PmX);
477	#endif
478
479	return FR_Success;
480}
481
482feeReturn feeDEREncodeECDSASignature(
483	giant			c,
484	giant			d,
485	unsigned char	**encodedSig,		// fmallocd and RETURNED
486	unsigned		*encodedSigLen)		// RETURNED
487{
488	/* convert to FEEECDSASignatureASN1 */
489	FEEECDSASignatureASN1 asnSig;
490	SecNssCoder coder;
491
492	try {
493		giantToCssmData(c, asnSig.c, coder);
494		giantToCssmData(d, asnSig.d, coder);
495	}
496	catch(const feeException &ferr) {
497		return ferr.frtn();
498	}
499
500	/* DER encode */
501	PRErrorCode perr;
502	CSSM_DATA encBlob;			// mallocd by coder
503	perr = coder.encodeItem(&asnSig, FEEECDSASignatureASN1Template, encBlob);
504	if(perr) {
505		return FR_Memory;
506	}
507
508	/* copy out  to caller */
509	*encodedSig = (unsigned char *)fmalloc((unsigned)encBlob.Length);
510	*encodedSigLen = (unsigned)encBlob.Length;
511	memmove(*encodedSig, encBlob.Data, encBlob.Length);
512
513	#if	PRINT_SIG_GIANTS
514	printf("feeEncodeECDSASignature:\n");
515	printf("   c   : "); printGiantHex(*c);
516	printf("   d   : "); printGiantHex(*d);
517	#endif
518	return FR_Success;
519
520}
521
522feeReturn feeDERDecodeElGamalSignature(
523	const unsigned char	*encodedSig,
524	size_t				encodedSigLen,
525	giant				*u,				// newGiant'd and RETURNED
526	giant				*PmX)			// newGiant'd and RETURNED
527{
528	FEEElGamalSignatureASN1 asnSig;
529	SecNssCoder coder;
530
531	memset(&asnSig, 0, sizeof(asnSig));
532	PRErrorCode perr = coder.decode(encodedSig, encodedSigLen,
533		FEEElGamalSignatureASN1Template, &asnSig);
534	if(perr) {
535		return FR_BadSignatureFormat;
536	}
537
538	try {
539		*u   = cssmDataToGiant(asnSig.u);
540		*PmX = cssmDataToGiant(asnSig.pmX);
541	}
542	catch(const feeException &ferr) {
543		return ferr.frtn();
544	}
545	catch(...) {
546		/* FIXME - bad sig? memory? */
547		return FR_Memory;
548	}
549	#if	PRINT_SIG_GIANTS
550	printf("feeDecodeElGamalSignature:\n");
551	printf("   u   : "); printGiantHex(*u);
552	printf("   PmX : "); printGiantHex(*PmX);
553	#endif
554	return FR_Success;
555}
556
557feeReturn feeDERDecodeECDSASignature(
558	const unsigned char	*encodedSig,
559	size_t				encodedSigLen,
560	giant				*c,				// newGiant'd and RETURNED
561	giant				*d)				// newGiant'd and RETURNED
562{
563	FEEECDSASignatureASN1 asnSig;
564	SecNssCoder coder;
565
566	memset(&asnSig, 0, sizeof(asnSig));
567	PRErrorCode perr = coder.decode(encodedSig, encodedSigLen,
568		FEEECDSASignatureASN1Template, &asnSig);
569	if(perr) {
570		return FR_BadSignatureFormat;
571	}
572
573	try {
574		*c = cssmDataToGiant(asnSig.c);
575		*d = cssmDataToGiant(asnSig.d);
576	}
577	catch(const feeException &ferr) {
578		return ferr.frtn();
579	}
580	catch(...) {
581		/* FIXME - bad sig? memory? */
582		return FR_Memory;
583	}
584	#if	PRINT_SIG_GIANTS
585	printf("feeDERDecodeECDSASignature:\n");
586	printf("   u   : "); printGiantHex(*u);
587	printf("   PmX : "); printGiantHex(*PmX);
588	#endif
589	return FR_Success;
590}
591
592/*
593 * Encode/decode the FEE private and public keys. We malloc returned data via
594 * falloc(); caller must free via ffree(). Public C functions which never throw.
595 */
596feeReturn feeDEREncodePublicKey(
597	int					version,
598	const curveParams	*cp,
599	giant				plusX,
600	giant				minusX,
601	giant				plusY,				// may be NULL
602	unsigned char		**keyBlob,			// fmallocd and RETURNED
603	unsigned			*keyBlobLen)		// RETURNED
604{
605	FEEPublicKeyASN1 asnKey;
606	SecNssCoder coder;
607
608	memset(&asnKey, 0, sizeof(asnKey));
609	intToCssmData(version, asnKey.version, coder);
610
611	try {
612		feeCurveParamsToASN1(cp, asnKey.curveParams, coder);
613		giantToCssmData(plusX, asnKey.plusX, coder);
614		giantToCssmData(minusX, asnKey.minusX, coder);
615		if(plusY != NULL) {
616			giantToCssmData(plusY, asnKey.plusY, coder);
617		}
618	}
619	catch(const feeException &ferr) {
620		return ferr.frtn();
621	}
622
623	/* DER encode */
624	PRErrorCode perr;
625	CSSM_DATA encBlob;			// mallocd by coder
626	perr = coder.encodeItem(&asnKey, FEEPublicKeyASN1Template, encBlob);
627	if(perr) {
628		return FR_Memory;
629	}
630
631	/* copy out */
632	*keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
633	*keyBlobLen = (unsigned)encBlob.Length;
634	memmove(*keyBlob, encBlob.Data, encBlob.Length);
635	return FR_Success;
636}
637
638feeReturn feeDEREncodePrivateKey(
639	int					version,
640	const curveParams	*cp,
641	const giant			privData,
642	unsigned char		**keyBlob,			// fmallocd and RETURNED
643	unsigned			*keyBlobLen)		// RETURNED
644{
645	FEEPrivateKeyASN1 asnKey;
646	SecNssCoder coder;
647
648	memset(&asnKey, 0, sizeof(asnKey));
649	intToCssmData(version, asnKey.version, coder);
650
651	try {
652		feeCurveParamsToASN1(cp, asnKey.curveParams, coder);
653		giantToCssmData(privData, asnKey.privData, coder);
654	}
655	catch(const feeException &ferr) {
656		return ferr.frtn();
657	}
658
659	/* DER encode */
660	PRErrorCode perr;
661	CSSM_DATA encBlob;			// mallocd by coder
662	perr = coder.encodeItem(&asnKey, FEEPrivateKeyASN1Template, encBlob);
663	if(perr) {
664		return FR_Memory;
665	}
666
667	/* copy out */
668	*keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
669	*keyBlobLen = (unsigned)encBlob.Length;
670	memmove(*keyBlob, encBlob.Data, encBlob.Length);
671	return FR_Success;
672}
673
674feeReturn feeDERDecodePublicKey(
675	const unsigned char	*keyBlob,
676	unsigned			keyBlobLen,
677	int					*version,			// this and remainder RETURNED
678	curveParams			**cp,
679	giant				*plusX,
680	giant				*minusX,
681	giant				*plusY)				// may be NULL
682{
683	FEEPublicKeyASN1 asnKey;
684	SecNssCoder coder;
685
686	memset(&asnKey, 0, sizeof(asnKey));
687	PRErrorCode perr = coder.decode(keyBlob, keyBlobLen,
688		FEEPublicKeyASN1Template, &asnKey);
689	if(perr) {
690		return FR_BadKeyBlob;
691	}
692
693	try {
694		*version = cssmDataToInt(asnKey.version);
695		*cp     = feeCurveParamsFromAsn1(asnKey.curveParams);
696		*plusX  = cssmDataToGiant(asnKey.plusX);
697		*minusX = cssmDataToGiant(asnKey.minusX);
698		if(asnKey.plusY.Data != NULL) {
699			/* optional */
700			*plusY = cssmDataToGiant(asnKey.plusY);
701		}
702		else {
703			*plusY = newGiant(1);
704			int_to_giant(0, *plusY);
705		}
706	}
707	catch(const feeException &ferr) {
708		return ferr.frtn();
709	}
710	catch(...) {
711		/* FIXME - bad sig? memory? */
712		return FR_Memory;
713	}
714	return FR_Success;
715}
716
717feeReturn feeDERDecodePrivateKey(
718	const unsigned char	*keyBlob,
719	unsigned			keyBlobLen,
720	int					*version,			// this and remainder RETURNED
721	curveParams			**cp,
722	giant				*privData)			// RETURNED
723{
724	FEEPrivateKeyASN1 asnKey;
725	SecNssCoder coder;
726
727	memset(&asnKey, 0, sizeof(asnKey));
728	PRErrorCode perr = coder.decode(keyBlob, keyBlobLen,
729		FEEPrivateKeyASN1Template, &asnKey);
730	if(perr) {
731		return FR_BadKeyBlob;
732	}
733
734	try {
735		*version = cssmDataToInt(asnKey.version);
736		*cp     = feeCurveParamsFromAsn1(asnKey.curveParams);
737		*privData  = cssmDataToGiant(asnKey.privData);
738	}
739	catch(const feeException &ferr) {
740		return ferr.frtn();
741	}
742	catch(...) {
743		/* FIXME - bad sig? memory? */
744		return FR_Memory;
745	}
746	return FR_Success;
747}
748
749#pragma mark --- ECDSA support ---
750
751/* convert between feeDepth and curve OIDs */
752static const CSSM_OID *depthToOid(
753	feeDepth depth)
754{
755	switch(depth) {
756		case FEE_DEPTH_secp192r1:
757			return &CSSMOID_secp192r1;
758		case FEE_DEPTH_secp256r1:
759			return &CSSMOID_secp256r1;
760		case FEE_DEPTH_secp384r1:
761			return &CSSMOID_secp384r1;
762		case FEE_DEPTH_secp521r1:
763			return &CSSMOID_secp521r1;
764		default:
765			dbgLog(("depthToOid needs work\n"));
766			return NULL;
767	}
768}
769
770static feeReturn curveOidToFeeDepth(
771	const CSSM_OID *curveOid,
772	feeDepth *depth)			/* RETURNED */
773{
774	if(nssCompareCssmData(curveOid, &CSSMOID_secp192r1)) {
775		*depth = FEE_DEPTH_secp192r1;
776	}
777	else if(nssCompareCssmData(curveOid, &CSSMOID_secp256r1)) {
778		*depth = FEE_DEPTH_secp256r1;
779	}
780	else if(nssCompareCssmData(curveOid, &CSSMOID_secp384r1)) {
781		*depth = FEE_DEPTH_secp384r1;
782	}
783	else if(nssCompareCssmData(curveOid, &CSSMOID_secp521r1)) {
784		*depth = FEE_DEPTH_secp521r1;
785	}
786	else {
787		dbgLog(("curveOidToFeeDepth: unknown curve OID\n"));
788		return FR_BadKeyBlob;
789	}
790	return FR_Success;
791}
792
793
794/*
795 * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer
796 * depth from its algorith.parameter
797 */
798static feeReturn feeAlgIdToDepth(
799	const CSSM_X509_ALGORITHM_IDENTIFIER *algId,
800	feeDepth *depth)
801{
802	const CSSM_OID *oid = &algId->algorithm;
803	/* FIXME what's the value here for a private key!? */
804	if(!nssCompareCssmData(oid, &CSSMOID_ecPublicKey)) {
805		dbgLog(("feeAlgIdToDepth: bad OID"));
806		return FR_BadKeyBlob;
807	}
808
809	/*
810	 * AlgId.params is curve OID, still encoded since it's an ASN_ANY.
811	 * First two bytes of encoded OID are (06, length)
812	 */
813	const CSSM_DATA *param = &algId->parameters;
814	if((param->Length <= 2) || (param->Data[0] != BER_TAG_OID)) {
815		dbgLog(("feeAlgIdToDepth: no curve params\n"));
816		return FR_BadKeyBlob;
817	}
818
819	CSSM_OID decOid = {param->Length-2, algId->parameters.Data+2};
820	return curveOidToFeeDepth(&decOid, depth);
821}
822
823/*
824 * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding.
825 */
826static feeReturn feeSetupAlgId(
827	feeDepth depth,
828	SecNssCoder &coder,
829	CSSM_X509_ALGORITHM_IDENTIFIER &algId)
830{
831	algId.algorithm = CSSMOID_ecPublicKey;
832	const CSSM_OID *curveOid = depthToOid(depth);
833	if(curveOid == NULL) {
834		return FR_IllegalDepth;
835	}
836
837	/* quick & dirty encode of the parameter OID; it's an ASN_ANY in the template */
838	coder.allocItem(algId.parameters, curveOid->Length + 2);
839	algId.parameters.Data[0] = BER_TAG_OID;
840	algId.parameters.Data[1] = curveOid->Length;
841	memmove(algId.parameters.Data+2, curveOid->Data, curveOid->Length);
842	return FR_Success;
843}
844
845#pragma mark --- ECDSA public key, X.509 format ---
846
847/*
848 * Encode/decode public key in X.509 format.
849 */
850feeReturn feeDEREncodeX509PublicKey(
851	const unsigned char	*pubBlob,		/* x and y octet string */
852	unsigned			pubBlobLen,
853	curveParams			*cp,
854	unsigned char		**x509Blob,		/* fmallocd and RETURNED */
855	unsigned			*x509BlobLen)	/* RETURNED */
856{
857	SecNssCoder coder;
858	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo;
859
860	memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo));
861
862	/* The x/y string, to be encoded in a bit string */
863	nssPubKeyInfo.subjectPublicKey.Data = (uint8 *)pubBlob;
864	nssPubKeyInfo.subjectPublicKey.Length = pubBlobLen * 8;
865
866	feeDepth depth;
867	feeReturn frtn = curveParamsDepth(cp, &depth);
868	if(frtn) {
869		dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
870		return frtn;
871	}
872
873	CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPubKeyInfo.algorithm;
874	frtn = feeSetupAlgId(depth, coder, algId);
875	if(frtn) {
876		return frtn;
877	}
878
879	/* DER encode */
880	CSSM_DATA encBlob;			// mallocd by coder
881	PRErrorCode perr = coder.encodeItem(&nssPubKeyInfo, kSecAsn1SubjectPublicKeyInfoTemplate, encBlob);
882	if(perr) {
883		return FR_Memory;
884	}
885
886	/* copy out */
887	*x509Blob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
888	*x509BlobLen = (unsigned)encBlob.Length;
889	memmove(*x509Blob, encBlob.Data, encBlob.Length);
890	return FR_Success;
891}
892
893feeReturn feeDERDecodeX509PublicKey(
894	const unsigned char	*x509Blob,
895	unsigned			x509BlobLen,
896	feeDepth			*depth,			/* RETURNED */
897	unsigned char		**pubBlob,		/* x and y octet string RETURNED */
898	unsigned			*pubBlobLen)	/* RETURNED */
899{
900	SecNssCoder coder;
901	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo;
902	PRErrorCode perr;
903
904	memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo));
905	perr = coder.decode(x509Blob, x509BlobLen, kSecAsn1SubjectPublicKeyInfoTemplate,
906		&nssPubKeyInfo);
907	if(perr) {
908		dbgLog(("decode(SubjectPublicKeyInfo) error"));
909		return FR_BadKeyBlob;
910	}
911
912	/* verify alg identifier & depth */
913	feeReturn frtn = feeAlgIdToDepth(&nssPubKeyInfo.algorithm, depth);
914	if(frtn) {
915		return frtn;
916	}
917
918	/* copy public key string - it's in bits here */
919	CSSM_DATA *pubKey = &nssPubKeyInfo.subjectPublicKey;
920	unsigned keyLen =(unsigned) (pubKey->Length + 7) / 8;
921	*pubBlob = (unsigned char *)fmalloc(keyLen);
922	if(*pubBlob == NULL) {
923		return FR_Memory;
924	}
925	memmove(*pubBlob, pubKey->Data, keyLen);
926	*pubBlobLen = keyLen;
927	return FR_Success;
928}
929
930#pragma mark --- ECDSA keys, OpenSSL format ---
931
932/*
933 * Encode private, and decode private or public key, in unencrypted OpenSSL format.
934 */
935feeReturn feeDEREncodeOpenSSLPrivateKey(
936	const unsigned char	*privBlob,		/* private data octet string */
937	unsigned			privBlobLen,
938	const unsigned char *pubBlob,		/* public key, optional */
939	unsigned			pubBlobLen,
940	curveParams			*cp,
941	unsigned char		**openBlob,		/* fmallocd and RETURNED */
942	unsigned			*openBlobLen)	/* RETURNED */
943{
944	feeDepth depth;
945	const CSSM_OID *curveOid;
946	SecNssCoder coder;
947
948	NSS_ECDSA_PrivateKey ecdsaPrivKey;
949	memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey));
950	uint8 vers = 1;
951	ecdsaPrivKey.version.Data = &vers;
952	ecdsaPrivKey.version.Length = 1;
953	ecdsaPrivKey.privateKey.Data = (uint8 *)privBlob;
954	ecdsaPrivKey.privateKey.Length = privBlobLen;
955
956	/* Params - ASN_ANY - actually the curve OID */
957	if(curveParamsDepth(cp, &depth)) {
958		dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth"));
959		return FR_BadKeyBlob;
960	}
961	curveOid = depthToOid(depth);
962	if(curveOid == NULL) {
963		return FR_BadKeyBlob;
964	}
965
966	/* quickie DER-encode of the curve OID */
967	try {
968		coder.allocItem(ecdsaPrivKey.params, curveOid->Length + 2);
969	}
970	catch(...) {
971		return FR_Memory;
972	}
973	ecdsaPrivKey.params.Data[0] = BER_TAG_OID;
974	ecdsaPrivKey.params.Data[1] = curveOid->Length;
975	memmove(ecdsaPrivKey.params.Data+2, curveOid->Data, curveOid->Length);
976
977	/* public key - optional - bit string, length in bits */
978	if(pubBlob) {
979		ecdsaPrivKey.pubKey.Data = (uint8 *)pubBlob;
980		ecdsaPrivKey.pubKey.Length = pubBlobLen * 8;
981	}
982
983	CSSM_DATA encPriv = {0, NULL};
984	PRErrorCode perr = coder.encodeItem(&ecdsaPrivKey, kSecAsn1ECDSAPrivateKeyInfoTemplate, encPriv);
985	if(perr) {
986		return FR_Memory;
987	}
988
989	/* copy out */
990	*openBlob = (unsigned char *)fmalloc((unsigned)encPriv.Length);
991	*openBlobLen = (unsigned)encPriv.Length;
992	memmove(*openBlob, encPriv.Data, encPriv.Length);
993	return FR_Success;
994}
995
996feeReturn feeDERDecodeOpenSSLKey(
997	const unsigned char	*osBlob,
998	unsigned			osBlobLen,
999	feeDepth			*depth,			/* RETURNED */
1000	unsigned char		**privBlob,		/* private data octet string RETURNED */
1001	unsigned			*privBlobLen,	/* RETURNED */
1002	unsigned char		**pubBlob,		/* public data octet string optionally RETURNED */
1003	unsigned			*pubBlobLen)
1004{
1005	SecNssCoder coder;
1006	NSS_ECDSA_PrivateKey ecdsaPrivKey;
1007	memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey));
1008	if(coder.decode(osBlob, osBlobLen,
1009			kSecAsn1ECDSAPrivateKeyInfoTemplate, &ecdsaPrivKey)) {
1010		dbgLog(("Error decoding openssl priv key\n"));
1011		return FR_BadKeyBlob;
1012	}
1013
1014	unsigned keyLen = (unsigned)ecdsaPrivKey.privateKey.Length;
1015	if(keyLen == 0) {
1016		dbgLog(("NULL priv key data in PKCS8\n"));
1017	}
1018	*privBlob = (unsigned char *)fmalloc(keyLen);
1019	if(*privBlob == NULL) {
1020		return FR_Memory;
1021	}
1022	*privBlobLen = keyLen;
1023	memmove(*privBlob, ecdsaPrivKey.privateKey.Data, keyLen);
1024
1025	/* curve OID --> depth */
1026	if(ecdsaPrivKey.params.Data != NULL) {
1027		/* quickie decode */
1028		const CSSM_DATA *param = &ecdsaPrivKey.params;
1029		if((param->Data[0] != BER_TAG_OID) || (param->Length <= 2)) {
1030			dbgLog(("feeDERDecodeOpenSSLKey: bad curve params\n"));
1031			return FR_BadKeyBlob;
1032		}
1033		CSSM_OID decOid = {param->Length-2, param->Data+2};
1034		if(curveOidToFeeDepth(&decOid, depth)) {
1035			return FR_BadKeyBlob;
1036		}
1037	}
1038
1039	/* Public key, if it's there and caller wants it */
1040	if((ecdsaPrivKey.pubKey.Length != 0) && (pubBlob != NULL)) {
1041		*pubBlobLen = (unsigned)(ecdsaPrivKey.pubKey.Length + 7) / 8;
1042		*pubBlob = (unsigned char *)fmalloc(*pubBlobLen);
1043		memmove(*pubBlob, ecdsaPrivKey.pubKey.Data, *pubBlobLen);
1044	}
1045	return FR_Success;
1046}
1047
1048#pragma mark --- ECDSA public key, PKCS8 format ---
1049
1050/*
1051 * Encode/decode private key in unencrypted PKCS8 format.
1052 */
1053feeReturn feeDEREncodePKCS8PrivateKey(
1054	const unsigned char	*privBlob,		/* private data octet string */
1055	unsigned			privBlobLen,
1056	const unsigned char	*pubBlob,		/* public blob, optional */
1057	unsigned			pubBlobLen,
1058	curveParams			*cp,
1059	unsigned char		**pkcs8Blob,	/* fmallocd and RETURNED */
1060	unsigned			*pkcs8BlobLen)	/* RETURNED */
1061{
1062	/* First encode a NSS_ECDSA_PrivateKey */
1063	unsigned char *encPriv = NULL;
1064	unsigned encPrivLen = 0;
1065	feeReturn frtn = feeDEREncodeOpenSSLPrivateKey(privBlob, privBlobLen,
1066		pubBlob, pubBlobLen, cp, &encPriv, &encPrivLen);
1067	if(frtn) {
1068		return frtn;
1069	}
1070
1071	/* That encoding goes into NSS_PrivateKeyInfo.private key */
1072	SecNssCoder coder;
1073	NSS_PrivateKeyInfo nssPrivKeyInfo;
1074	CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPrivKeyInfo.algorithm;
1075	memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo));
1076	nssPrivKeyInfo.privateKey.Data = (uint8 *)encPriv;
1077	nssPrivKeyInfo.privateKey.Length = encPrivLen;
1078	uint8 vers = 0;
1079
1080	feeDepth depth;
1081	frtn = curveParamsDepth(cp, &depth);
1082	if(frtn) {
1083		dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
1084		goto errOut;
1085	}
1086	frtn = feeSetupAlgId(depth, coder, algId);
1087	if(frtn) {
1088		goto errOut;
1089	}
1090
1091	nssPrivKeyInfo.version.Data = &vers;
1092	nssPrivKeyInfo.version.Length = 1;
1093
1094	/* DER encode */
1095	CSSM_DATA encPrivInfo;			// mallocd by coder
1096	if(coder.encodeItem(&nssPrivKeyInfo, kSecAsn1PrivateKeyInfoTemplate, encPrivInfo)) {
1097		frtn = FR_Memory;
1098		goto errOut;
1099	}
1100
1101	/* copy out */
1102	*pkcs8Blob = (unsigned char *)fmalloc((unsigned)encPrivInfo.Length);
1103	*pkcs8BlobLen = (unsigned)encPrivInfo.Length;
1104	memmove(*pkcs8Blob, encPrivInfo.Data, encPrivInfo.Length);
1105errOut:
1106	if(encPriv) {
1107		ffree(encPriv);
1108	}
1109	return frtn;
1110}
1111
1112feeReturn feeDERDecodePKCS8PrivateKey(
1113	const unsigned char	*pkcs8Blob,
1114	unsigned			pkcs8BlobLen,
1115	feeDepth			*depth,			/* RETURNED */
1116	unsigned char		**privBlob,		/* private data octet string RETURNED */
1117	unsigned			*privBlobLen,	/* RETURNED */
1118	unsigned char		**pubBlob,		/* optionally returned, if it's there */
1119	unsigned			*pubBlobLen)
1120{
1121	NSS_PrivateKeyInfo nssPrivKeyInfo;
1122	PRErrorCode perr;
1123	SecNssCoder coder;
1124
1125	memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo));
1126	perr = coder.decode(pkcs8Blob, pkcs8BlobLen, kSecAsn1PrivateKeyInfoTemplate, &nssPrivKeyInfo);
1127	if(perr) {
1128		dbgLog(("Error decoding top level PKCS8\n"));
1129		return FR_BadKeyBlob;
1130	}
1131
1132	/* verify alg identifier & depth */
1133	feeReturn frtn = feeAlgIdToDepth(&nssPrivKeyInfo.algorithm, depth);
1134	if(frtn) {
1135		return frtn;
1136	}
1137
1138	/*
1139	 * nssPrivKeyInfo.privateKey is an octet string containing an encoded
1140	 * NSS_ECDSA_PrivateKey.
1141	 */
1142	frtn = feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo.privateKey.Data,
1143		(unsigned)nssPrivKeyInfo.privateKey.Length, depth,
1144		privBlob, privBlobLen,
1145		pubBlob, pubBlobLen);
1146
1147	return frtn;
1148}
1149
1150#endif	/* CRYPTKIT_DER_ENABLE */
1151