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