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