/ OSX / libsecurity_cryptkit / lib / feePublicKey.c
feePublicKey.c
   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 "byteRep.h"
  64  #include "CryptKitDER.h"
  65  #include <stdio.h>
  66  
  67  /*
  68   * 11/27/98 dmitch: The ECDSA_VERIFY_ONLY symbol, when #defined, disables all
  69   * of the code in this module except that which is necessary for ECDSA
  70   * siggnature verification.
  71   */
  72   
  73  #ifndef	NULL
  74  #define NULL ((void *)0)
  75  #endif	// NULL
  76  
  77  /*
  78   * Magic number for a portable key blobs. Must be in sync with static
  79   * final PUBLIC_KEY_STRING_MAGIC in JavaFee/PublicKey.java.
  80   */
  81  #define PUBLIC_KEY_BLOB_MAGIC_PUB  		0xfeeddeef
  82  #define PUBLIC_KEY_BLOB_MAGIC_PRIV  	0xfeeddeed
  83  #define PUBLIC_KEY_BLOB_VERSION  		6
  84  #define PUBLIC_KEY_BLOB_MINVERSION		6
  85  
  86  #define PUBLIC_DER_KEY_BLOB_VERSION		1
  87  
  88  /*
  89   * Private data. All "instance" routines are passed a feePubKey (actually
  90   * a void *) which is actually a pointer to one of these.
  91   */
  92  typedef struct {
  93  	key			plus;
  94  	key			minus;		// not needed for ECDSA
  95  	curveParams	*cp;		// common params shared by minus, plus
  96  	giant		privGiant;	// private key
  97  } pubKeyInst;
  98  
  99  static feeReturn feeGenPrivate(pubKeyInst *pkinst,
 100  	const unsigned char *passwd,
 101  	unsigned passwdLen,
 102  	char hashPasswd);
 103  static pubKeyInst *pubKeyInstAlloc(void);
 104  static void pubKeyInstFree(pubKeyInst *pkinst);
 105  
 106  static feeReturn createKeyBlob(pubKeyInst *pkinst,
 107  	int isPrivate,			// 0 : public   1 : private
 108  	unsigned char **keyBlob,	// mallocd and RETURNED
 109  	unsigned *keyBlobLen);		// RETURNED
 110  static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
 111  	unsigned char *keyBlob,
 112  	unsigned keyBlobLen);
 113  
 114  #pragma mark --- General public API function ---
 115  
 116  /*
 117   * Obatin a newly allocated feePubKey.
 118   */
 119  feePubKey feePubKeyAlloc(void)
 120  {
 121  	pubKeyInst *pkinst = pubKeyInstAlloc();
 122  
 123  	
 124  	return pkinst;
 125  }
 126  
 127  void feePubKeyFree(feePubKey pubKey)
 128  {
 129  	pubKeyInstFree((pubKeyInst*) pubKey);
 130  }
 131  
 132  #ifndef	ECDSA_VERIFY_ONLY
 133  /*
 134   * Init feePubKey from private key data.
 135   */
 136  feeReturn feePubKeyInitFromPrivDataKeyBits(feePubKey pubKey,
 137  	const unsigned char *privData,
 138  	unsigned privDataLen,
 139  	unsigned keyBits,			/* key size in bits */
 140  	feePrimeType primeType,		/* FPT_Fefault means "best one" */
 141  	feeCurveType curveType,		/* FCT_Default means "best one" */
 142  	char hashPrivData)
 143  {
 144  	feeReturn frtn;
 145  	feeDepth depth;
 146  	
 147  	frtn = feeKeyBitsToDepth(keyBits, primeType, curveType, &depth);
 148  	if(frtn) {
 149  		return frtn;
 150  	}
 151  	return feePubKeyInitFromPrivDataDepth(pubKey,
 152  		privData, 
 153  		privDataLen,
 154  		depth,
 155  		hashPrivData);
 156  }
 157  
 158  feeReturn feePubKeyInitFromPrivDataDepth(feePubKey pubKey,
 159  	const unsigned char *privData,
 160  	unsigned privDataLen,
 161  	feeDepth depth,
 162  	char hashPrivData)
 163  {
 164  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
 165  	feeReturn  frtn;
 166  
 167  	if(depth > FEE_DEPTH_MAX) {
 168  		dbgLog(("Illegal Depth\n"));
 169  		return FR_IllegalDepth;
 170  	}
 171  
 172  	pkinst->cp = curveParamsForDepth(depth);
 173  	pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
 174  	if(pkinst->cp->x1Minus != NULL) {
 175  		pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
 176  	}
 177  	/* else only usable for ECDSA */
 178  	
 179  	frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData);
 180  	if(frtn) {
 181  		return frtn;
 182  	}
 183  	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
 184  	if(pkinst->cp->x1Minus != NULL) {
 185  		set_priv_key_giant(pkinst->minus, pkinst->privGiant);
 186  	}
 187  	return FR_Success;
 188  }
 189  
 190  #endif	/* ECDSA_VERIFY_ONLY */
 191  
 192  /*
 193   * Init feePubKey from curve parameters matching existing oldKey.
 194   */
 195  feeReturn feePubKeyInitFromKey(feePubKey pubKey,
 196  	const unsigned char *privData,
 197  	unsigned privDataLen,
 198  	feePubKey oldKey,
 199  	char hashPrivData)
 200  {
 201  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
 202  	pubKeyInst *oldInst = (pubKeyInst *) oldKey;
 203  	feeReturn  frtn;
 204  
 205  	if(oldKey == NULL) {
 206  		dbgLog(("NULL existing key\n"));
 207  		return FR_BadPubKey;
 208  	}
 209  
 210  	pkinst->cp = curveParamsCopy(oldInst->cp);
 211  	if(pkinst->cp->x1Minus != NULL) {
 212  		pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
 213  		if(pkinst->minus == NULL) {
 214  			goto abort;
 215  		}
 216  	}
 217  	/* else this curve only usable for ECDSA */
 218  	
 219  	pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
 220  	if(pkinst->plus == NULL) {
 221  		goto abort;
 222  	}
 223  	frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData);
 224  	if(frtn) {
 225  		return frtn;
 226  	}
 227  	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
 228  	if(pkinst->cp->x1Minus != NULL) {
 229  		set_priv_key_giant(pkinst->minus, pkinst->privGiant);
 230  	}
 231  	return FR_Success;
 232  
 233  abort:
 234  	dbgLog(("Bad Existing Public Key\n"));
 235  	return FR_BadPubKey;
 236  }
 237  
 238  /***
 239   *** Public KeyString support. 
 240   ***/
 241  /*
 242   * Init feePubKey from a public key string.
 243   *
 244   * See ByteRep.doc for info on the format of the public key string and blobs;
 245   * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT.
 246   */
 247  feeReturn feePubKeyInitFromKeyString(feePubKey pubKey,
 248  	const char *keyStr,
 249  	unsigned keyStrLen)
 250  {
 251  	unsigned char 	*blob = NULL;
 252  	unsigned		blobLen;
 253  	feeReturn		frtn;
 254  
 255  	blob = dec64((unsigned char *)keyStr, keyStrLen, &blobLen);
 256  	if(blob == NULL) {
 257  		dbgLog(("Bad Public Key String (not enc64)\n"));
 258  		return FR_BadPubKeyString;
 259  	}
 260  	frtn = feePubKeyInitFromKeyBlob(pubKey, blob, blobLen);
 261  	ffree(blob);
 262  	return frtn;
 263  }
 264  
 265  /*
 266   * Create a public key in the form of a null-terminated C string.
 267   * This string contains an encoded version of all of our ivars except for
 268   * privGiant.
 269   *
 270   * See ByteRep.doc for info on the format of the public key string and blobs;
 271   * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT.
 272   */
 273  feeReturn feePubKeyCreateKeyString(feePubKey pubKey,
 274  	char **pubKeyString,		/* RETURNED */
 275  	unsigned *pubKeyStringLen)	/* RETURNED */
 276  {
 277  	unsigned char 	*blob;
 278  	unsigned 	blobLen;
 279  	feeReturn 	frtn;
 280  	pubKeyInst 	*pkinst = (pubKeyInst *)pubKey;
 281  
 282  	/* get binary pub blob, encode the blob, free the blob */
 283  	frtn = createKeyBlob(pkinst,
 284  		0,		// isPrivate
 285  		&blob,
 286  		&blobLen);
 287  	if(frtn) {
 288  		return frtn;
 289  	}
 290  
 291  	*pubKeyString = (char *)enc64(blob, blobLen, pubKeyStringLen);
 292  	ffree(blob);
 293  	return FR_Success;
 294  }
 295  
 296  /*** 
 297   *** Native key blob support.
 298   ***/
 299   
 300  #ifndef	ECDSA_VERIFY_ONLY
 301  
 302  /*
 303   * Obtain portable public and private key blobs from a key.
 304   */
 305  feeReturn feePubKeyCreatePubBlob(feePubKey pubKey,
 306  	unsigned char **keyBlob,	// mallocd and RETURNED
 307  	unsigned *keyBlobLen)		// RETURNED
 308  {
 309  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
 310  
 311  	return createKeyBlob(pkinst,
 312  		0,
 313  		keyBlob,
 314  		keyBlobLen);
 315  }
 316  
 317  feeReturn feePubKeyCreatePrivBlob(feePubKey pubKey,
 318  	unsigned char **keyBlob,	// mallocd and RETURNED
 319  	unsigned *keyBlobLen)		// RETURNED
 320  {
 321  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
 322  
 323  	if(pkinst->privGiant == NULL) {
 324  		return FR_IncompatibleKey;
 325  	}
 326  	return createKeyBlob(pkinst,
 327  		1,
 328  		keyBlob,
 329  		keyBlobLen);
 330  }
 331  
 332  /* 
 333   * Given private-capable privKey, initialize pubKey to be its corresponding 
 334   * public key.
 335   */
 336  feeReturn feePubKeyInitPubKeyFromPriv(feePubKey privKey,
 337  	feePubKey pubKey)
 338  {
 339  	pubKeyInst *privInst = (pubKeyInst *)privKey;
 340  	pubKeyInst *pubInst  = (pubKeyInst *)pubKey;
 341  
 342  	if((privInst == NULL) || (pubInst == NULL)) {
 343  		return FR_BadPubKey;
 344  	}
 345  	if(privInst->privGiant == NULL) {
 346  		return FR_IncompatibleKey;
 347  	}
 348  	pubInst->cp = curveParamsCopy(privInst->cp);
 349  	if(pubInst == NULL) {
 350  		return FR_Memory;
 351  	}
 352  	pubInst->plus   = new_public_with_key(privInst->plus,  pubInst->cp);
 353  	if(pubInst->plus == NULL) {
 354  		return FR_Memory;
 355  	} 
 356  	if(pubInst->cp->x1Minus != NULL) {
 357  		pubInst->minus  = new_public_with_key(privInst->minus, pubInst->cp);
 358  		if(pubInst->minus == NULL) {
 359  			return FR_Memory;
 360  		} 
 361  	}
 362  	return FR_Success;
 363  }
 364  
 365  #endif	/* ECDSA_VERIFY_ONLY */
 366  
 367  /*
 368   * Returns non-zero if two keys are equivalent.
 369   */
 370  int feePubKeyIsEqual(feePubKey key1, feePubKey key2)
 371  {
 372  	pubKeyInst *pkinst1 = (pubKeyInst *) key1;
 373  	pubKeyInst *pkinst2 = (pubKeyInst *) key2;
 374  
 375  	if ((pkinst1 == NULL) || (pkinst2 == NULL)) {
 376  		return 0;
 377  	}
 378  	if((pkinst1->minus != NULL) && (pkinst2->minus != NULL)) {
 379  		if(key_equal(pkinst1->minus, pkinst2->minus) == 0) {
 380  			return 0;
 381  		}
 382  	}
 383  	if(key_equal(pkinst1->plus, pkinst2->plus) == 0) {
 384  		return 0;
 385  	}
 386  	return 1;
 387  }
 388  
 389  /*
 390   * Returns non-zero if key is private-capable (i.e., capable of signing
 391   * and decrypting).
 392   */
 393  int feePubKeyIsPrivate(feePubKey key)
 394  {
 395  	pubKeyInst *myPkinst = (pubKeyInst *)key;
 396  
 397  	return ((myPkinst->privGiant != NULL) ? 1 : 0);
 398  }
 399  
 400  #pragma mark --- ECDH ---
 401  
 402  /* 
 403   * Diffie-Hellman. Public key is specified either as a feePubKey or 
 404   * a ANSI X9.62 format public key string (0x04 | x | y). In either case
 405   * the caller must ensure that the two keys are on the same curve. 
 406   * Output data is fmalloc'd here; caller must free. Output data is 
 407   * exactly the size of the curve's modulus in bytes. 
 408   */
 409  feeReturn feePubKeyECDH(
 410  	feePubKey privKey,
 411  	/* one of the following two is non-NULL */
 412  	feePubKey pubKey,
 413  	const unsigned char *pubKeyStr,
 414  	unsigned pubKeyStrLen,
 415  	/* output fmallocd and RETURNED here */
 416  	unsigned char **output,
 417  	unsigned *outputLen)
 418  {
 419  	feePubKey theirPub = pubKey;
 420  	feeReturn frtn = FR_Success;
 421  	pubKeyInst *privInst = (pubKeyInst *) privKey;
 422  	
 423  	if(privInst->privGiant == NULL) {
 424  		dbgLog(("feePubKeyECDH: privKey not a private key\n"));
 425  		return FR_IncompatibleKey;
 426  	}
 427  	
 428  	if(theirPub == NULL) {
 429  		if(pubKeyStr == NULL) {
 430  			return FR_IllegalArg;
 431  		}
 432  		
 433  		/* Cook up a public key with the same curveParams as the private key */
 434  		feeDepth depth;
 435  		frtn = curveParamsDepth(privInst->cp, &depth);
 436  		if(frtn) {
 437  			return frtn;
 438  		}
 439  		theirPub = feePubKeyAlloc();
 440  		if(theirPub == NULL) {
 441  			return FR_Memory;
 442  		}
 443  		frtn = feePubKeyInitFromECDSAPubBlob(theirPub, pubKeyStr, pubKeyStrLen, depth);
 444  		if(frtn) {
 445  			goto errOut;
 446  		}
 447  	}
 448  	
 449  	pubKeyInst *pubInst = (pubKeyInst *) theirPub;
 450  	
 451  	giant outputGiant = make_pad(privInst->privGiant, pubInst->plus);
 452  	if(outputGiant == NULL) {
 453  		dbgLog(("feePubKeyECDH: make_pad error\n"));
 454  		frtn = FR_Internal;
 455  	}
 456  	else {
 457  		*outputLen = (privInst->cp->q + 7) / 8;
 458  		*output = (unsigned char *)fmalloc(*outputLen);
 459  		if(*output == NULL) {
 460  			frtn = FR_Memory;
 461  			goto errOut;
 462  		}
 463  		serializeGiant(outputGiant, *output, *outputLen);
 464  		freeGiant(outputGiant);
 465  	}
 466  errOut:
 467  	if((pubKey == NULL) && (theirPub != NULL)) {
 468  		feePubKeyFree(theirPub);
 469  	}
 470  	return frtn;
 471  }
 472  
 473  #pragma mark --- feePubKey data accessors ---
 474  
 475  unsigned feePubKeyBitsize(feePubKey pubKey)
 476  {
 477  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
 478  	switch(pkinst->cp->primeType) {
 479  		case FPT_General:	/* cp->q is here for just this purpose */
 480  		case FPT_Mersenne:
 481  			return pkinst->cp->q;
 482  		case FPT_FEE:		/* could be larger or smaller than 2^q-1 */
 483  		default:
 484  			return bitlen(pkinst->cp->basePrime);	
 485  	}
 486  }
 487  
 488  /*
 489   * Accessor routines.
 490   */
 491  /* private only...*/
 492  key feePubKeyPlusCurve(feePubKey pubKey)
 493  {
 494  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
 495  
 496  	return pkinst->plus;
 497  }
 498  
 499  key feePubKeyMinusCurve(feePubKey pubKey)
 500  {
 501  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
 502  
 503  	return pkinst->minus;
 504  }
 505  
 506  curveParams *feePubKeyCurveParams(feePubKey pubKey)
 507  {
 508  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
 509  
 510  	return pkinst->cp;
 511  }
 512  
 513  giant feePubKeyPrivData(feePubKey pubKey)
 514  {
 515  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
 516  
 517  	return pkinst->privGiant;
 518  }
 519  
 520  const char *feePubKeyAlgorithmName(void)
 521  {
 522  	return "Elliptic Curve - FEE by Apple Computer";
 523  }
 524  
 525  #pragma mark --- Private functions ---
 526  
 527  /*
 528   * alloc, free pubKeyInst
 529   */
 530  static pubKeyInst *pubKeyInstAlloc(void)
 531  {
 532  	pubKeyInst *pkinst = (pubKeyInst *) fmalloc(sizeof(pubKeyInst));
 533  
 534  	bzero(pkinst, sizeof(pubKeyInst));
 535  	return pkinst;
 536  }
 537  
 538  static void pubKeyInstFree(pubKeyInst *pkinst)
 539  {
 540  	if(pkinst->minus) {
 541  		free_key(pkinst->minus);
 542  	}
 543  	if(pkinst->plus) {
 544  		free_key(pkinst->plus);
 545  	}
 546  	if(pkinst->cp) {
 547  		freeCurveParams(pkinst->cp);
 548  	}
 549  	if(pkinst->privGiant) {
 550  		/*
 551  		 * Zero out the private data...
 552  		 */
 553  		clearGiant(pkinst->privGiant);
 554  		freeGiant(pkinst->privGiant);
 555  	}
 556  	ffree(pkinst);
 557  }
 558  
 559  #ifndef	ECDSA_VERIFY_ONLY
 560  
 561  /*
 562   * Create a pubKeyInst.privGiant given a password of
 563   * arbitrary length.
 564   * Currently, the only error is "private data too short" (FR_IllegalArg).
 565   */
 566  
 567  #define NO_PRIV_MUNGE		0	/* skip this step */
 568  
 569  static feeReturn feeGenPrivate(pubKeyInst *pkinst,
 570  	const unsigned char *passwd,
 571  	unsigned passwdLen,
 572  	char hashPasswd)
 573  {
 574  	unsigned 		privLen;			// desired size of pkinst->privData
 575  	feeHash 		*hash = NULL;		// a malloc'd array
 576  	unsigned		digestLen;			// size of MD5 digest
 577  	unsigned 		dataSize;			// min(privLen, passwdLen)
 578  	unsigned		numDigests = 0;
 579  	unsigned		i;
 580  	unsigned char	*cp;
 581  	unsigned		toMove;				// for this digest
 582  	unsigned		moved;				// total digested
 583  	unsigned char	*digest = NULL;
 584  	unsigned char	*privData = NULL;	// temp, before modg(curveOrder)
 585  	giant			corder;				// lesser of two curve orders
 586  	
 587  	/*
 588  	 * generate privData which is just larger than the smaller
 589  	 * curve order.
 590  	 * We'll take the result mod the curve order when we're done.
 591  	 * Note we do *not* have to free corder - it's a pointer to a giant
 592  	 * in pkinst->cp.
 593  	 */
 594  	corder = lesserX1Order(pkinst->cp);
 595  	CKASSERT(!isZero(corder));
 596  	privLen = (bitlen(corder) / 8) + 1;
 597  
 598  	if(!hashPasswd) {
 599  		/* 
 600  		 * Caller trusts the incoming entropy. Verify it's big enough and proceed. 
 601  		 */
 602  		if(passwdLen < privLen) {
 603  			return FR_ShortPrivData;
 604  		}
 605  		privLen = passwdLen;
 606  		privData = (unsigned char *)passwd;
 607  		goto finishUp;
 608  	}
 609  	if(passwdLen < 2) {
 610  		return FR_IllegalArg;
 611  	}
 612  
 613  
 614  	/*
 615  	 * Calculate how many MD5 digests we'll generate.
 616  	 */
 617  	if(privLen > passwdLen) {
 618  		dataSize = passwdLen;
 619  	}
 620  	else {
 621  		dataSize = privLen;
 622  	}
 623  	digestLen = feeHashDigestLen();
 624  	numDigests = (dataSize + digestLen - 1) / digestLen;
 625  
 626  	hash = (void**) fmalloc(numDigests * sizeof(feeHash));
 627  	for(i=0; i<numDigests; i++) {
 628  		hash[i] = feeHashAlloc();
 629  	}
 630  
 631  	/*
 632  	 * fill digests with passwd data, digestLen (or resid length)
 633  	 * at a time. If (passwdLen > privLen), last digest will hash all
 634  	 * remaining passwd data.
 635  	 */
 636  	cp = (unsigned char *)passwd;
 637  	moved = 0;
 638  	for(i=0; i<numDigests; i++) {
 639  		if(i == (numDigests - 1)) {		    // last digest
 640  		    toMove = passwdLen - moved;
 641  		}
 642  		else {
 643  		    toMove = digestLen;
 644  		}
 645  		feeHashAddData(hash[i], cp, toMove);
 646  		cp += toMove;
 647  		moved += toMove;
 648  	}
 649  
 650  	/*
 651  	 * copy digests to privData, up to privLen bytes. Pad with
 652  	 * additional copies of digests if necessary.
 653  	 */
 654  	privData = (unsigned char*) fmalloc(privLen);
 655  	cp = privData;
 656  	moved = 0;
 657  	i = 0;			// digest number
 658  	for(moved=0; moved<privLen; ) {
 659  		if((moved + digestLen) > privLen) {
 660  		   toMove = privLen - moved;
 661  		}
 662  		else {
 663  		   toMove = digestLen;
 664  		}
 665  		digest = feeHashDigest(hash[i++]);
 666  		bcopy(digest, cp, toMove);
 667  		cp += toMove;
 668  		moved += toMove;
 669  		if(i == numDigests) {
 670  		    i = 0;		// wrap to 0, start padding
 671  		}
 672  	}
 673  	
 674  finishUp:
 675  	/*
 676  	 * Convert to giant, justify result to within [2, lesserX1Order]
 677  	 */
 678  	pkinst->privGiant = giant_with_data(privData, privLen);
 679  
 680  	#if	FEE_DEBUG
 681  	if(isZero(pkinst->privGiant)) {
 682  		printf("feeGenPrivate: privData = 0!\n");
 683  	}
 684  	#endif	// FEE_DEBUG
 685  
 686  	lesserX1OrderJustify(pkinst->privGiant, pkinst->cp);
 687  	if(hashPasswd) {
 688  		memset(privData, 0, privLen);
 689  		ffree(privData);
 690  		for(i=0; i<numDigests; i++) {
 691  			feeHashFree(hash[i]);
 692  		}
 693  		ffree(hash);
 694  	}
 695  	return FR_Success;
 696  }
 697  
 698  #endif	/* ECDSA_VERIFY_ONLY */
 699  
 700  #if	FEE_DEBUG
 701  
 702  void printPubKey(feePubKey pubKey)
 703  {
 704  	pubKeyInst *pkinst = pubKey;
 705  
 706  	printf("\ncurveParams:\n");
 707  	printCurveParams(pkinst->cp);
 708  	printf("plus:\n");
 709  	printKey(pkinst->plus);
 710  	printf("minus:\n");
 711  	printKey(pkinst->minus);
 712  	if(pkinst->privGiant != NULL) {
 713  	    printf("privGiant : ");
 714  	    printGiant(pkinst->privGiant);
 715  	}
 716  }
 717  
 718  #else	// FEE_DEBUG
 719  void printPubKey(feePubKey pubKey) {}
 720  #endif	// FEE_DEBUG
 721  
 722  
 723  #pragma mark --- Native (custom) key blob formatting ---
 724  
 725  /*
 726   * Exported key blob support. New, 23 Mar 1998.
 727   *
 728   * Convert to public or private key blob.
 729   */
 730  
 731  #ifndef	ECDSA_VERIFY_ONLY
 732  
 733  /***
 734   *** Common native blob support 
 735   ***/
 736  static feeReturn createKeyBlob(pubKeyInst *pkinst,
 737  	int 			isPrivate,		// 0 : public   1 : private
 738  	unsigned char 	**keyBlob,		// mallocd and RETURNED
 739  	unsigned 		*keyBlobLen)	// RETURNED
 740  {
 741  	unsigned char 	*s;		// running ptr into *origS
 742  	unsigned		sLen;
 743  	int				magic;
 744  
 745  	/* common blob elements */
 746  	sLen = (4 * sizeof(int)) +		// magic, version, minVersion,
 747  									// spare
 748  	    lengthOfByteRepCurveParams(pkinst->cp);
 749  	if(isPrivate) {
 750  	    /* private only */
 751  	    sLen += lengthOfByteRepGiant(pkinst->privGiant);
 752  	    magic = PUBLIC_KEY_BLOB_MAGIC_PRIV;
 753  	}
 754  	else {
 755  	    /* public only */
 756  	    sLen += (lengthOfByteRepKey(pkinst->plus) +
 757  		     lengthOfByteRepKey(pkinst->minus));
 758  	    magic = PUBLIC_KEY_BLOB_MAGIC_PUB;
 759  	}
 760  	*keyBlob = s = (unsigned char*) fmalloc(sLen);
 761  	s += intToByteRep(magic, s);
 762  	s += intToByteRep(PUBLIC_KEY_BLOB_VERSION, s);
 763  	s += intToByteRep(PUBLIC_KEY_BLOB_MINVERSION, s);
 764  	s += intToByteRep(0, s);			// spare
 765  	s += curveParamsToByteRep(pkinst->cp, s);
 766  	if(isPrivate) {
 767  	    s += giantToByteRep(pkinst->privGiant, s);
 768  	}
 769  	else {
 770  	    /* keyToByteRep writes y for plus curve only */
 771  	    s += keyToByteRep(pkinst->plus, s);
 772  		if(pkinst->minus != NULL) {
 773  			s += keyToByteRep(pkinst->minus, s);
 774  		}
 775  		else {
 776  			/* TBD */
 777  			dbgLog(("work needed here for blobs with no minus key\n"));
 778  		}
 779  	}
 780  	*keyBlobLen = sLen;
 781  	return FR_Success;
 782  }
 783  
 784  #endif	/* ECDSA_VERIFY_ONLY */
 785  
 786  /*
 787   * Init an empty feePubKey from a native blob (non-DER format).
 788   */
 789  static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
 790  	unsigned char *keyBlob,
 791  	unsigned keyBlobLen)
 792  {
 793  	pubKeyInst		*pkinst = (pubKeyInst *) pubKey;
 794  	unsigned char	*s;		// running pointer
 795  	unsigned		sLen;		// bytes remaining in *s
 796  	int				magic;
 797  	unsigned		len;		// for length of individual components
 798  	int 			minVersion;
 799  	int				version;
 800  	int				isPrivate;
 801  
 802  	s = keyBlob;
 803  	sLen = keyBlobLen;
 804  	if(sLen < (4 * sizeof(int))) {	// magic, version, minVersion, spare
 805  		/*
 806  		 * Too short for all the ints we need
 807  		 */
 808  		dbgLog(("feePublicKey: key blob (1)\n"));
 809  		return FR_BadKeyBlob;
 810  	}
 811  
 812  	magic = byteRepToInt(s);
 813  	s += sizeof(int);
 814  	sLen -= sizeof(int);
 815  	switch(magic) {
 816  	    case PUBLIC_KEY_BLOB_MAGIC_PUB:
 817  	    	isPrivate = 0;
 818  		break;
 819  	    case PUBLIC_KEY_BLOB_MAGIC_PRIV:
 820  	    	isPrivate = 1;
 821  		break;
 822  	    default:
 823  		dbgLog(("feePublicKey: Bad Public Key Magic Number\n"));
 824  		return FR_BadKeyBlob;
 825  	}
 826  
 827  	/*
 828  	 * Switch on this for version-specific cases
 829  	 */
 830  	version = byteRepToInt(s);
 831  	s += sizeof(int);
 832  	sLen -= sizeof(int);
 833  
 834  	minVersion = byteRepToInt(s);
 835  	s += sizeof(int);
 836  	sLen -= sizeof(int);
 837  	if(minVersion > PUBLIC_KEY_BLOB_VERSION) {
 838  		/*
 839  		 * old code, newer key blob - can't parse
 840  		 */
 841  		dbgLog(("feePublicKey: Incompatible Public Key (1)\n"));
 842  		return FR_BadKeyBlob;
 843  	}
 844  
 845  	s += sizeof(int);			// skip spare
 846  	sLen -= sizeof(int);
 847  
 848  	pkinst->cp = byteRepToCurveParams(s, sLen, &len);
 849  	if(pkinst->cp == NULL) {
 850  		dbgLog(("feePublicKey: Bad Key Blob(2)\n"));
 851  		return FR_BadKeyBlob;
 852  	}
 853  	s += len;
 854  	sLen -= len;
 855  
 856  	/*
 857  	 * Private key blob: privGiant.
 858  	 * Public Key blob:  plusX, minusX, plusY.
 859  	 */
 860  	if(isPrivate) {
 861  		pkinst->privGiant = byteRepToGiant(s, sLen, &len);
 862  		if(pkinst->privGiant == NULL) {
 863  			dbgLog(("feePublicKey: Bad Key Blob(3)\n"));
 864  			return FR_BadKeyBlob;
 865  		}
 866  		s += len;
 867  		sLen -= len;
 868  	}
 869  	else {
 870  		/* this writes x and y */
 871  		pkinst->plus = byteRepToKey(s,
 872  			sLen,
 873  			CURVE_PLUS,		// twist
 874  			pkinst->cp,
 875  			&len);
 876  		if(pkinst->plus == NULL) {
 877  			dbgLog(("feePublicKey: Bad Key Blob(4)\n"));
 878  			return FR_BadKeyBlob;
 879  		}
 880  		s += len;
 881  		sLen -= len;
 882  
 883  		/* this only writes x */
 884  		pkinst->minus = byteRepToKey(s,
 885  			sLen,
 886  			CURVE_MINUS,		// twist
 887  			pkinst->cp,
 888  			&len);
 889  		if(pkinst->minus == NULL) {
 890  			dbgLog(("feePublicKey: Bad Key Blob(5)\n"));
 891  			return FR_BadKeyBlob;
 892  		}
 893  		s += len;
 894  		sLen -= len;
 895  	}
 896  
 897  	/*
 898  	 * One more thing: cook up public plusX and minusX for private key
 899  	 * blob case.
 900  	 */
 901  	if(isPrivate) {
 902  		pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
 903  		pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
 904  		set_priv_key_giant(pkinst->plus, pkinst->privGiant);
 905  		set_priv_key_giant(pkinst->minus, pkinst->privGiant);
 906  	}
 907  	return FR_Success;
 908  
 909  }
 910  
 911  feeReturn feePubKeyInitFromPubBlob(feePubKey pubKey,
 912  	unsigned char *keyBlob,
 913  	unsigned keyBlobLen)
 914  {
 915  	return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
 916  }
 917  
 918  #ifndef	ECDSA_VERIFY_ONLY
 919  
 920  feeReturn feePubKeyInitFromPrivBlob(feePubKey pubKey,
 921  	unsigned char *keyBlob,
 922  	unsigned keyBlobLen)
 923  {
 924  	return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);	
 925  }
 926  
 927  #endif	/* ECDSA_VERIFY_ONLY */
 928  
 929  #ifndef	ECDSA_VERIFY_ONLY
 930  
 931  /* 
 932   * DER format support. 
 933   * Obtain portable public and private DER-encoded key blobs from a key.
 934   */
 935  feeReturn feePubKeyCreateDERPubBlob(feePubKey pubKey,
 936  	unsigned char **keyBlob,	// mallocd and RETURNED
 937  	unsigned *keyBlobLen)		// RETURNED
 938  {
 939  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
 940  
 941  	if(pkinst == NULL) {
 942  		return FR_BadPubKey;
 943  	}
 944  	if(pkinst->minus == NULL) {
 945  		/* Only ECDSA key formats supported */
 946  		return FR_IncompatibleKey;
 947  	}
 948  	return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION,
 949  		pkinst->cp,
 950  		pkinst->plus->x,
 951  		pkinst->minus->x,
 952  		isZero(pkinst->plus->y) ? NULL : pkinst->plus->y, 
 953  		keyBlob,
 954  		keyBlobLen);
 955  }
 956  
 957  feeReturn feePubKeyCreateDERPrivBlob(feePubKey pubKey,
 958  	unsigned char **keyBlob,	// mallocd and RETURNED
 959  	unsigned *keyBlobLen)		// RETURNED
 960  {
 961  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
 962  
 963  	if(pkinst == NULL) {
 964  		return FR_BadPubKey;
 965  	}
 966  	if(pkinst->privGiant == NULL) {
 967  		return FR_IncompatibleKey;
 968  	}
 969  	if(pkinst->minus == NULL) {
 970  		/* Only ECDSA key formats supported */
 971  		return FR_IncompatibleKey;
 972  	}
 973  	return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION,
 974  		pkinst->cp,
 975  		pkinst->privGiant,
 976  		keyBlob,
 977  		keyBlobLen);
 978  }
 979  
 980  #endif	/* ECDSA_VERIFY_ONLY */
 981  
 982  /*
 983   * Init an empty feePubKey from a DER-encoded blob, public and private key versions. 
 984   */
 985  feeReturn feePubKeyInitFromDERPubBlob(feePubKey pubKey,
 986  	unsigned char *keyBlob,
 987  	size_t keyBlobLen)
 988  {
 989  	pubKeyInst	*pkinst = (pubKeyInst *) pubKey;
 990  	feeReturn	frtn;
 991  	int			version;
 992  	
 993  	if(pkinst == NULL) {
 994  		return FR_BadPubKey;
 995  	}
 996  	
 997  	/* kind of messy, maybe we should clean this up. But new_public() does too
 998  	 * much - e.g., it allocates the x and y which we really don't want */
 999  	 memset(pkinst, 0, sizeof(pubKeyInst));
1000  	 pkinst->plus = (key) fmalloc(sizeof(keystruct));
1001  	 pkinst->minus = (key) fmalloc(sizeof(keystruct));
1002  	 if((pkinst->plus == NULL) || (pkinst->minus == NULL)) {
1003  		return FR_Memory;
1004  	 }
1005  	 memset(pkinst->plus, 0, sizeof(keystruct));
1006  	 memset(pkinst->minus, 0, sizeof(keystruct));
1007  	 pkinst->cp = NULL;
1008  	 pkinst->privGiant = NULL;
1009  	 pkinst->plus->twist  = CURVE_PLUS;
1010  	 pkinst->minus->twist = CURVE_MINUS;
1011  	 frtn = feeDERDecodePublicKey(keyBlob, 
1012  		(unsigned)keyBlobLen,
1013  		&version,			// currently unused
1014  		&pkinst->cp,
1015  		&pkinst->plus->x,
1016  		&pkinst->minus->x,
1017  		&pkinst->plus->y);
1018  	if(frtn) {
1019  		return frtn;
1020  	}
1021  	/* minus curve, y is not used */
1022  	pkinst->minus->y = newGiant(1);
1023  	int_to_giant(0, pkinst->minus->y);
1024  	pkinst->plus->cp = pkinst->minus->cp = pkinst->cp;
1025  	return FR_Success;
1026  }
1027  
1028  #ifndef	ECDSA_VERIFY_ONLY
1029  
1030  feeReturn feePubKeyInitFromDERPrivBlob(feePubKey pubKey,
1031  	unsigned char *keyBlob,
1032  	size_t keyBlobLen)
1033  {
1034  	pubKeyInst	*pkinst = (pubKeyInst *) pubKey;
1035  	int			version;
1036  	feeReturn	frtn;
1037  	
1038  	if(pkinst == NULL) {
1039  		return FR_BadPubKey;
1040  	}
1041  	memset(pkinst, 0, sizeof(pubKeyInst));
1042  	frtn = feeDERDecodePrivateKey(keyBlob, 
1043  		(unsigned)keyBlobLen,
1044  		&version,		// currently unused
1045  		&pkinst->cp,
1046  		&pkinst->privGiant);
1047  	if(frtn) {
1048  		return frtn;
1049  	}
1050  	
1051  	/* since this blob only had the private data, infer the remaining fields */
1052  	pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
1053  	pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
1054  	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1055  	set_priv_key_giant(pkinst->minus, pkinst->privGiant);
1056  	return FR_Success;
1057  }
1058  
1059  #endif	/* ECDSA_VERIFY_ONLY */
1060  
1061  #pragma mark --- X509 (public) and PKCS8 (private) key formatting ---
1062  
1063  feeReturn feePubKeyCreateX509Blob(
1064  	feePubKey pubKey,			// public key
1065  	unsigned char **keyBlob,	// mallocd and RETURNED
1066  	unsigned *keyBlobLen)		// RETURNED
1067  {
1068  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1069  	unsigned char *xyStr = NULL;
1070  	unsigned xyStrLen = 0;
1071  	feeReturn frtn = feeCreateECDSAPubBlob(pubKey, &xyStr, &xyStrLen);
1072  	if(frtn) {
1073  		return frtn;
1074  	}
1075  	frtn = feeDEREncodeX509PublicKey(xyStr, xyStrLen, pkinst->cp, keyBlob, keyBlobLen);
1076  	ffree(xyStr);
1077  	return frtn;
1078  }
1079  
1080  feeReturn feePubKeyCreatePKCS8Blob(
1081  	feePubKey pubKey,			// private key
1082  	unsigned char **keyBlob,	// mallocd and RETURNED
1083  	unsigned *keyBlobLen)		// RETURNED
1084  {
1085  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1086  	unsigned char *privStr = NULL;
1087  	unsigned privStrLen = 0;
1088  	feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1089  	if(frtn) {
1090  		return frtn;
1091  	}
1092  	unsigned char *pubStr = NULL;
1093  	unsigned pubStrLen = 0;
1094  	frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1095  	if(frtn) {
1096  		goto errOut;
1097  	}
1098  	frtn = feeDEREncodePKCS8PrivateKey(privStr, privStrLen, 
1099  		pubStr, pubStrLen,
1100  		pkinst->cp, keyBlob, keyBlobLen);
1101  errOut:
1102  	if(privStr) {
1103  		ffree(privStr);
1104  	}
1105  	if(pubStr) {
1106  		ffree(pubStr);
1107  	}
1108  	return frtn;
1109  }
1110  
1111  feeReturn feePubKeyInitFromX509Blob(
1112  	feePubKey pubKey,			// public key 
1113  	unsigned char *keyBlob,
1114  	size_t keyBlobLen)
1115  {
1116  	feeDepth depth;
1117  	unsigned char *xyStr = NULL;
1118  	unsigned xyStrLen = 0;
1119  	
1120  	/* obtain x/y and depth from X509 encoding */
1121  	feeReturn frtn = feeDERDecodeX509PublicKey(keyBlob, (unsigned)keyBlobLen, &depth,
1122  		&xyStr, &xyStrLen);
1123  	if(frtn) {
1124  		return frtn;
1125  	}
1126  	
1127  	frtn = feePubKeyInitFromECDSAPubBlob(pubKey, xyStr, xyStrLen, depth);
1128  	ffree(xyStr);
1129  	return frtn;
1130  }
1131  
1132  
1133  feeReturn feePubKeyInitFromPKCS8Blob(
1134  	feePubKey pubKey,			// private key 
1135  	unsigned char *keyBlob,
1136  	size_t keyBlobLen)
1137  {
1138  	feeDepth depth;
1139  	unsigned char *privStr = NULL;
1140  	unsigned privStrLen = 0;
1141  	
1142  	/* obtain x/y and depth from PKCS8 encoding */
1143  	/* For now we ignore the possible public key string */
1144  	feeReturn frtn = feeDERDecodePKCS8PrivateKey(keyBlob, (unsigned)keyBlobLen, &depth,
1145  		&privStr, &privStrLen, NULL, NULL);
1146  	if(frtn) {
1147  		return frtn;
1148  	}
1149  	
1150  	frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1151  	ffree(privStr);
1152  	return frtn;
1153  }
1154  
1155  #pragma mark --- OpenSSL key formatting ---
1156  
1157  /*
1158   * The native OpenSSL ECDSA key format contains both the private and public
1159   * components in one blob. This throws a bit of a monkey wrench into the API
1160   * here, as we only have one encoder - which requires a private key - and one
1161   * decoder, which can result in the decoding of either a public or a private
1162   * key.
1163   */
1164  feeReturn feePubKeyCreateOpenSSLBlob(
1165  	feePubKey pubKey,			// private key
1166  	unsigned char **keyBlob,	// mallocd and RETURNED
1167  	unsigned *keyBlobLen)		// RETURNED
1168  {
1169  	pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1170  	unsigned char *privStr = NULL;
1171  	unsigned privStrLen = 0;
1172  	feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1173  	if(frtn) {
1174  		return frtn;
1175  	}
1176  	unsigned char *pubStr = NULL;
1177  	unsigned pubStrLen = 0;
1178  	frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1179  	if(frtn) {
1180  		goto errOut;
1181  	}
1182  	frtn = feeDEREncodeOpenSSLPrivateKey(privStr, privStrLen, 
1183  		pubStr, pubStrLen,
1184  		pkinst->cp, keyBlob, keyBlobLen);
1185  errOut:
1186  	if(privStr) {
1187  		ffree(privStr);
1188  	}
1189  	if(pubStr) {
1190  		ffree(pubStr);
1191  	}
1192  	return frtn;
1193  }
1194  
1195  feeReturn feePubKeyInitFromOpenSSLBlob(
1196  	feePubKey pubKey,			// private or public key 
1197  	int pubOnly,
1198  	unsigned char *keyBlob,
1199  	size_t keyBlobLen)
1200  {
1201  	feeDepth depth;
1202  	unsigned char *privStr = NULL;
1203  	unsigned privStrLen = 0;
1204  	unsigned char *pubStr = NULL;
1205  	unsigned pubStrLen = 0;
1206  	
1207  	/* obtain x/y, public bit string, and depth from PKCS8 encoding */
1208  	feeReturn frtn = feeDERDecodeOpenSSLKey(keyBlob, (unsigned)keyBlobLen, &depth,
1209  		&privStr, &privStrLen, &pubStr, &pubStrLen);
1210  	if(frtn) {
1211  		return frtn;
1212  	}
1213  	
1214  	if(pubOnly) {
1215  		frtn = feePubKeyInitFromECDSAPubBlob(pubKey, pubStr, pubStrLen, depth);
1216  	}
1217  	else {
1218  		frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1219  	}
1220  	if(privStr) {
1221  		ffree(privStr);
1222  	}
1223  	if(pubStr) {
1224  		ffree(pubStr);
1225  	}
1226  	return frtn;
1227  }
1228  
1229  /*
1230   * ANSI X9.62/Certicom key support.
1231   * Public key is 04 || x || y
1232   * Private key is privData per Certicom SEC1 C.4.
1233   */
1234  feeReturn feeCreateECDSAPubBlob(feePubKey pubKey,
1235  	unsigned char **keyBlob,
1236  	unsigned *keyBlobLen)
1237  {
1238  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1239  	if(pkinst == NULL) {
1240  		return FR_BadPubKey;
1241  	}
1242  	
1243  	unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1244  	unsigned blobSize = 1 + (2 * giantBytes);
1245  	unsigned char *blob = fmalloc(blobSize);
1246  	if(blob == NULL) {
1247  		return FR_Memory;
1248  	}
1249  	*blob = 0x04;
1250  	serializeGiant(pkinst->plus->x, blob+1, giantBytes);
1251  	serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes);
1252  	*keyBlob = blob;
1253  	*keyBlobLen = blobSize;
1254  	return FR_Success;
1255  }
1256  
1257  feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey,
1258  	unsigned char **keyBlob,
1259  	unsigned *keyBlobLen)
1260  {
1261  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1262  	if(pkinst == NULL) {
1263  		return FR_BadPubKey;
1264  	}
1265  	if(pkinst->privGiant == NULL) {
1266  		return FR_IncompatibleKey;
1267  	}
1268  
1269  	/* 
1270  	 * Return the raw private key bytes padded with zeroes in
1271  	 * the m.s. end to fill exactly one prime-size byte array.
1272  	 */
1273  	unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1274  	unsigned char *blob = fmalloc(giantBytes);
1275  	if(blob == NULL) {
1276  		return FR_Memory;
1277  	}
1278  	serializeGiant(pkinst->privGiant, blob, giantBytes);
1279  	*keyBlob = blob;
1280  	*keyBlobLen = giantBytes;
1281  	return FR_Success;
1282  }
1283  
1284  /* Caller determines depth from other sources (e.g. AlgId.Params) */
1285  feeReturn feePubKeyInitFromECDSAPubBlob(feePubKey pubKey,
1286  	const unsigned char *keyBlob,
1287  	unsigned keyBlobLen,
1288  	feeDepth depth)
1289  {
1290  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1291  	if(pkinst == NULL) {
1292  		return FR_BadPubKey;
1293  	}
1294  	curveParams *cp = curveParamsForDepth(depth);
1295  	if(cp == NULL) {
1296  		return FR_IllegalDepth;
1297  	}
1298  	unsigned giantBytes = (cp->q + 7) / 8;
1299  	unsigned blobSize = 1 + (2 * giantBytes);
1300  	if(keyBlobLen != blobSize) {
1301  		dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blobLen\n"));
1302  		return FR_BadKeyBlob;
1303  	}
1304  	if(*keyBlob != 0x04) {
1305  		dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n"));
1306  		return FR_BadKeyBlob;
1307  	}
1308  	
1309  	pkinst->cp = cp;
1310  	pkinst->plus = new_public(cp, CURVE_PLUS);
1311  	deserializeGiant(keyBlob+1, pkinst->plus->x, giantBytes);
1312  	deserializeGiant(keyBlob+1+giantBytes, pkinst->plus->y, giantBytes);
1313  	return FR_Success;
1314  }
1315  
1316  feeReturn feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey,
1317  	const unsigned char *keyBlob,
1318  	unsigned keyBlobLen,
1319  	feeDepth depth)
1320  {
1321  	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1322  	if(pkinst == NULL) {
1323  		return FR_BadPubKey;
1324  	}
1325  	curveParams *cp = curveParamsForDepth(depth);
1326  	if(cp == NULL) {
1327  		return FR_IllegalDepth;
1328  	}
1329  	unsigned giantDigits = cp->basePrime->sign;
1330  	unsigned giantBytes = (cp->q + 7) / 8;
1331  
1332  	/* 
1333  	 * The specified private key can be one byte smaller than the modulus */
1334  	if((keyBlobLen > giantBytes) || (keyBlobLen < (giantBytes - 1))) {
1335  		dbgLog(("feePubKeyInitFromECDSAPrivBlob: bad blobLen\n"));
1336  		return FR_BadKeyBlob;
1337  	}
1338  	
1339  	pkinst->cp = cp;
1340  	
1341  	/* cook up a new private giant */
1342  	pkinst->privGiant = newGiant(giantDigits);
1343  	if(pkinst->privGiant == NULL) {
1344  		return FR_Memory;
1345  	}
1346  	deserializeGiant(keyBlob, pkinst->privGiant, keyBlobLen);
1347  
1348  	/* since this blob only had the private data, infer the remaining fields */
1349  	pkinst->plus  = new_public(pkinst->cp, CURVE_PLUS);
1350  	set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1351  	return FR_Success;
1352  }
1353