]> git.saurik.com Git - apple/security.git/blob - libsecurity_cryptkit/lib/feePublicKey.c
Security-55471.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 #warning HLS
467 /*
468 * Generate digital signature, ElGamal style.
469 */
470 feeReturn feePubKeyCreateSignature(feePubKey pubKey,
471 const unsigned char *data,
472 unsigned dataLen,
473 unsigned char **signature, /* fmalloc'd and RETURNED */
474 unsigned *signatureLen) /* RETURNED */
475 {
476 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
477 feeHash hash;
478 feeSig sig;
479 unsigned char *Pm = NULL;
480 unsigned PmLen;
481 feeReturn frtn;
482
483 if(pkinst->privGiant == NULL) {
484 dbgLog(("feePubKeyCreateSignature: Attempt to Sign without"
485 " private data\n"));
486 return FR_BadPubKey;
487 }
488 hash = feeHashAlloc();
489 sig = feeSigNewWithKey(pubKey, NULL, NULL);
490 if(sig == NULL) {
491 /*
492 * Shouldn't happen, but...
493 */
494 feeHashFree(hash);
495 return FR_BadPubKey;
496 }
497
498 /*
499 * Get Pm to salt hash object
500 */
501 Pm = feeSigPm(sig, &PmLen);
502 feeHashAddData(hash, Pm, PmLen);
503
504 /*
505 * Now hash the data proper, then sign the hash
506 */
507 feeHashAddData(hash, data, dataLen);
508 frtn = feeSigSign(sig,
509 feeHashDigest(hash),
510 feeHashDigestLen(),
511 pubKey);
512 if(frtn == FR_Success) {
513 frtn = feeSigData(sig, signature, signatureLen);
514 }
515 feeHashFree(hash);
516 feeSigFree(sig);
517 ffree(Pm);
518 return frtn;
519 }
520
521 /*
522 * Verify digital signature, ElGamal style. If the signature is ECDSA,
523 * we'll use that format for compatibility.
524 */
525 feeReturn feePubKeyVerifySignature(feePubKey pubKey,
526 const unsigned char *data,
527 unsigned dataLen,
528 const unsigned char *signature,
529 unsigned signatureLen)
530 {
531 feeHash hash;
532 feeSig sig;
533 unsigned char *Pm = NULL;
534 unsigned PmLen;
535 feeReturn frtn;
536
537 hash = feeHashAlloc();
538 frtn = feeSigParse(signature, signatureLen, &sig);
539 if(frtn) {
540 feeHashFree(hash);
541 #if CRYPTKIT_ECDSA_ENABLE
542 if(frtn == FR_WrongSignatureType) {
543 return feePubKeyVerifyECDSASignature(pubKey,
544 data,
545 dataLen,
546 signature,
547 signatureLen);
548 }
549 #endif /* CRYPTKIT_ECDSA_ENABLE */
550 return frtn;
551 }
552
553 /*
554 * Get PM as salt; eat salt, then hash data
555 */
556 Pm = feeSigPm(sig, &PmLen);
557 feeHashAddData(hash, Pm, PmLen);
558 feeHashAddData(hash, data, dataLen);
559 frtn = feeSigVerify(sig,
560 feeHashDigest(hash),
561 feeHashDigestLen(),
562 pubKey);
563
564 feeHashFree(hash);
565 feeSigFree(sig);
566 ffree(Pm);
567 return frtn;
568 }
569
570 #pragma mark --- ECDSA signature: high level routines ---
571
572 #if CRYPTKIT_ECDSA_ENABLE
573 /*
574 * Generate digital signature, ECDSA style.
575 */
576 feeReturn feePubKeyCreateECDSASignature(feePubKey pubKey,
577 const unsigned char *data,
578 unsigned dataLen,
579 unsigned char **signature, /* fmalloc'd and RETURNED */
580 unsigned *signatureLen) /* RETURNED */
581 {
582 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
583 sha1Obj sha1;
584 feeReturn frtn;
585
586 if(pkinst->privGiant == NULL) {
587 dbgLog(("feePubKeyCreateECDSASignature: Attempt to Sign "
588 "without private data\n"));
589 return FR_BadPubKey;
590 }
591 sha1 = sha1Alloc();
592 sha1AddData(sha1, data, dataLen);
593 frtn = feeECDSASign(pubKey,
594 sha1Digest(sha1),
595 sha1DigestLen(),
596 NULL, // randFcn
597 NULL,
598 signature,
599 signatureLen);
600 sha1Free(sha1);
601 return frtn;
602 }
603 #endif /* CRYPTKIT_ECDSA_ENABLE */
604 #endif /* CRYPTKIT_HIGH_LEVEL_SIG */
605 #endif /* ECDSA_VERIFY_ONLY */
606
607 #if CRYPTKIT_HIGH_LEVEL_SIG
608
609 #if CRYPTKIT_ECDSA_ENABLE
610
611 /*
612 * Verify digital signature, ECDSA style.
613 */
614 feeReturn feePubKeyVerifyECDSASignature(feePubKey pubKey,
615 const unsigned char *data,
616 unsigned dataLen,
617 const unsigned char *signature,
618 unsigned signatureLen)
619 {
620 sha1Obj sha1;
621 feeReturn frtn;
622
623 sha1 = sha1Alloc();
624 sha1AddData(sha1, data, dataLen);
625 frtn = feeECDSAVerify(signature,
626 signatureLen,
627 sha1Digest(sha1),
628 sha1DigestLen(),
629 pubKey);
630 sha1Free(sha1);
631 return frtn;
632 }
633
634 #endif /* CRYPTKIT_ECDSA_ENABLE */
635
636 #endif /* CRYPTKIT_HIGH_LEVEL_SIG */
637
638 #pragma mark --- ECDH ---
639
640 /*
641 * Diffie-Hellman. Public key is specified either as a feePubKey or
642 * a ANSI X9.62 format public key string (0x04 | x | y). In either case
643 * the caller must ensure that the two keys are on the same curve.
644 * Output data is fmalloc'd here; caller must free. Output data is
645 * exactly the size of the curve's modulus in bytes.
646 */
647 feeReturn feePubKeyECDH(
648 feePubKey privKey,
649 /* one of the following two is non-NULL */
650 feePubKey pubKey,
651 const unsigned char *pubKeyStr,
652 unsigned pubKeyStrLen,
653 /* output fmallocd and RETURNED here */
654 unsigned char **output,
655 unsigned *outputLen)
656 {
657 feePubKey theirPub = pubKey;
658 feeReturn frtn = FR_Success;
659 pubKeyInst *privInst = (pubKeyInst *) privKey;
660
661 if(privInst->privGiant == NULL) {
662 dbgLog(("feePubKeyECDH: privKey not a private key\n"));
663 return FR_IncompatibleKey;
664 }
665
666 if(theirPub == NULL) {
667 if(pubKeyStr == NULL) {
668 return FR_IllegalArg;
669 }
670
671 /* Cook up a public key with the same curveParams as the private key */
672 feeDepth depth;
673 frtn = curveParamsDepth(privInst->cp, &depth);
674 if(frtn) {
675 return frtn;
676 }
677 theirPub = feePubKeyAlloc();
678 if(theirPub == NULL) {
679 return FR_Memory;
680 }
681 frtn = feePubKeyInitFromECDSAPubBlob(theirPub, pubKeyStr, pubKeyStrLen, depth);
682 if(frtn) {
683 goto errOut;
684 }
685 }
686
687 pubKeyInst *pubInst = (pubKeyInst *) theirPub;
688
689 giant outputGiant = make_pad(privInst->privGiant, pubInst->plus);
690 if(outputGiant == NULL) {
691 dbgLog(("feePubKeyECDH: make_pad error\n"));
692 frtn = FR_Internal;
693 }
694 else {
695 *outputLen = (privInst->cp->q + 7) / 8;
696 *output = (unsigned char *)fmalloc(*outputLen);
697 if(*output == NULL) {
698 frtn = FR_Memory;
699 goto errOut;
700 }
701 serializeGiant(outputGiant, *output, *outputLen);
702 freeGiant(outputGiant);
703 }
704 errOut:
705 if((pubKey == NULL) && (theirPub != NULL)) {
706 feePubKeyFree(theirPub);
707 }
708 return frtn;
709 }
710
711 #pragma mark --- feePubKey data accessors ---
712
713 unsigned feePubKeyBitsize(feePubKey pubKey)
714 {
715 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
716 switch(pkinst->cp->primeType) {
717 case FPT_General: /* cp->q is here for just this purpose */
718 case FPT_Mersenne:
719 return pkinst->cp->q;
720 case FPT_FEE: /* could be larger or smaller than 2^q-1 */
721 default:
722 return bitlen(pkinst->cp->basePrime);
723 }
724 /* NOT REACHED */
725 return 0;
726 }
727
728 /*
729 * Accessor routines.
730 */
731 /* private only...*/
732 key feePubKeyPlusCurve(feePubKey pubKey)
733 {
734 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
735
736 return pkinst->plus;
737 }
738
739 key feePubKeyMinusCurve(feePubKey pubKey)
740 {
741 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
742
743 return pkinst->minus;
744 }
745
746 curveParams *feePubKeyCurveParams(feePubKey pubKey)
747 {
748 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
749
750 return pkinst->cp;
751 }
752
753 giant feePubKeyPrivData(feePubKey pubKey)
754 {
755 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
756
757 return pkinst->privGiant;
758 }
759
760 const char *feePubKeyAlgorithmName(void)
761 {
762 return "Elliptic Curve - FEE by Apple Computer";
763 }
764
765 #pragma mark --- Private functions ---
766
767 /*
768 * alloc, free pubKeyInst
769 */
770 static pubKeyInst *pubKeyInstAlloc(void)
771 {
772 pubKeyInst *pkinst = (pubKeyInst *) fmalloc(sizeof(pubKeyInst));
773
774 bzero(pkinst, sizeof(pubKeyInst));
775 return pkinst;
776 }
777
778 static void pubKeyInstFree(pubKeyInst *pkinst)
779 {
780 if(pkinst->minus) {
781 free_key(pkinst->minus);
782 }
783 if(pkinst->plus) {
784 free_key(pkinst->plus);
785 }
786 if(pkinst->cp) {
787 freeCurveParams(pkinst->cp);
788 }
789 if(pkinst->privGiant) {
790 /*
791 * Zero out the private data...
792 */
793 clearGiant(pkinst->privGiant);
794 freeGiant(pkinst->privGiant);
795 }
796 ffree(pkinst);
797 }
798
799 #ifndef ECDSA_VERIFY_ONLY
800
801 /*
802 * Create a pubKeyInst.privGiant given a password of
803 * arbitrary length.
804 * Currently, the only error is "private data too short" (FR_IllegalArg).
805 */
806
807 #define NO_PRIV_MUNGE 0 /* skip this step */
808
809 static feeReturn feeGenPrivate(pubKeyInst *pkinst,
810 const unsigned char *passwd,
811 unsigned passwdLen,
812 char hashPasswd)
813 {
814 unsigned privLen; // desired size of pkinst->privData
815 feeHash *hash = NULL; // a malloc'd array
816 unsigned digestLen; // size of MD5 digest
817 unsigned dataSize; // min(privLen, passwdLen)
818 unsigned numDigests = 0;
819 unsigned i;
820 unsigned char *cp;
821 unsigned toMove; // for this digest
822 unsigned moved; // total digested
823 unsigned char *digest = NULL;
824 unsigned char *privData = NULL; // temp, before modg(curveOrder)
825 giant corder; // lesser of two curve orders
826
827 /*
828 * generate privData which is just larger than the smaller
829 * curve order.
830 * We'll take the result mod the curve order when we're done.
831 * Note we do *not* have to free corder - it's a pointer to a giant
832 * in pkinst->cp.
833 */
834 corder = lesserX1Order(pkinst->cp);
835 CKASSERT(!isZero(corder));
836 privLen = (bitlen(corder) / 8) + 1;
837
838 if(!hashPasswd) {
839 /*
840 * Caller trusts the incoming entropy. Verify it's big enough and proceed.
841 */
842 if(passwdLen < privLen) {
843 return FR_ShortPrivData;
844 }
845 privLen = passwdLen;
846 privData = (unsigned char *)passwd;
847 goto finishUp;
848 }
849 if(passwdLen < 2) {
850 return FR_IllegalArg;
851 }
852
853
854 /*
855 * Calculate how many MD5 digests we'll generate.
856 */
857 if(privLen > passwdLen) {
858 dataSize = passwdLen;
859 }
860 else {
861 dataSize = privLen;
862 }
863 digestLen = feeHashDigestLen();
864 numDigests = (dataSize + digestLen - 1) / digestLen;
865
866 hash = (void**) fmalloc(numDigests * sizeof(feeHash));
867 for(i=0; i<numDigests; i++) {
868 hash[i] = feeHashAlloc();
869 }
870
871 /*
872 * fill digests with passwd data, digestLen (or resid length)
873 * at a time. If (passwdLen > privLen), last digest will hash all
874 * remaining passwd data.
875 */
876 cp = (unsigned char *)passwd;
877 moved = 0;
878 for(i=0; i<numDigests; i++) {
879 if(i == (numDigests - 1)) { // last digest
880 toMove = passwdLen - moved;
881 }
882 else {
883 toMove = digestLen;
884 }
885 feeHashAddData(hash[i], cp, toMove);
886 cp += toMove;
887 moved += toMove;
888 }
889
890 /*
891 * copy digests to privData, up to privLen bytes. Pad with
892 * additional copies of digests if necessary.
893 */
894 privData = (unsigned char*) fmalloc(privLen);
895 cp = privData;
896 moved = 0;
897 i = 0; // digest number
898 for(moved=0; moved<privLen; ) {
899 if((moved + digestLen) > privLen) {
900 toMove = privLen - moved;
901 }
902 else {
903 toMove = digestLen;
904 }
905 digest = feeHashDigest(hash[i++]);
906 bcopy(digest, cp, toMove);
907 cp += toMove;
908 moved += toMove;
909 if(i == numDigests) {
910 i = 0; // wrap to 0, start padding
911 }
912 }
913
914 finishUp:
915 /*
916 * Convert to giant, justify result to within [2, lesserX1Order]
917 */
918 pkinst->privGiant = giant_with_data(privData, privLen);
919
920 #if FEE_DEBUG
921 if(isZero(pkinst->privGiant)) {
922 printf("feeGenPrivate: privData = 0!\n");
923 }
924 #endif // FEE_DEBUG
925
926 lesserX1OrderJustify(pkinst->privGiant, pkinst->cp);
927 if(hashPasswd) {
928 memset(privData, 0, privLen);
929 ffree(privData);
930 for(i=0; i<numDigests; i++) {
931 feeHashFree(hash[i]);
932 }
933 ffree(hash);
934 }
935 return FR_Success;
936 }
937
938 #endif /* ECDSA_VERIFY_ONLY */
939
940 #if FEE_DEBUG
941
942 void printPubKey(feePubKey pubKey)
943 {
944 pubKeyInst *pkinst = pubKey;
945
946 printf("\ncurveParams:\n");
947 printCurveParams(pkinst->cp);
948 printf("plus:\n");
949 printKey(pkinst->plus);
950 printf("minus:\n");
951 printKey(pkinst->minus);
952 if(pkinst->privGiant != NULL) {
953 printf("privGiant : ");
954 printGiant(pkinst->privGiant);
955 }
956 }
957
958 #else // FEE_DEBUG
959 void printPubKey(feePubKey pubKey) {}
960 #endif // FEE_DEBUG
961
962 /*
963 * Prime the curveParams and giants modules for quick allocs of giants.
964 */
965 #if GIANTS_VIA_STACK
966
967 static int giantsInitd = 0;
968
969 static void feePubKeyInitGiants(void)
970 {
971 if(giantsInitd) {
972 return;
973 }
974 curveParamsInitGiants();
975 giantsInitd = 1;
976 }
977 #endif
978
979 #pragma mark --- Native (custom) key blob formatting ---
980
981 /*
982 * Exported key blob support. New, 23 Mar 1998.
983 *
984 * Convert to public or private key blob.
985 */
986
987 #ifndef ECDSA_VERIFY_ONLY
988
989 /***
990 *** Common native blob support
991 ***/
992 static feeReturn createKeyBlob(pubKeyInst *pkinst,
993 int isPrivate, // 0 : public 1 : private
994 unsigned char **keyBlob, // mallocd and RETURNED
995 unsigned *keyBlobLen) // RETURNED
996 {
997 unsigned char *s; // running ptr into *origS
998 unsigned sLen;
999 int magic;
1000
1001 /* common blob elements */
1002 sLen = (4 * sizeof(int)) + // magic, version, minVersion,
1003 // spare
1004 lengthOfByteRepCurveParams(pkinst->cp);
1005 if(isPrivate) {
1006 /* private only */
1007 sLen += lengthOfByteRepGiant(pkinst->privGiant);
1008 magic = PUBLIC_KEY_BLOB_MAGIC_PRIV;
1009 }
1010 else {
1011 /* public only */
1012 sLen += (lengthOfByteRepKey(pkinst->plus) +
1013 lengthOfByteRepKey(pkinst->minus));
1014 magic = PUBLIC_KEY_BLOB_MAGIC_PUB;
1015 }
1016 *keyBlob = s = (unsigned char*) fmalloc(sLen);
1017 s += intToByteRep(magic, s);
1018 s += intToByteRep(PUBLIC_KEY_BLOB_VERSION, s);
1019 s += intToByteRep(PUBLIC_KEY_BLOB_MINVERSION, s);
1020 s += intToByteRep(0, s); // spare
1021 s += curveParamsToByteRep(pkinst->cp, s);
1022 if(isPrivate) {
1023 s += giantToByteRep(pkinst->privGiant, s);
1024 }
1025 else {
1026 /* keyToByteRep writes y for plus curve only */
1027 s += keyToByteRep(pkinst->plus, s);
1028 if(pkinst->minus != NULL) {
1029 s += keyToByteRep(pkinst->minus, s);
1030 }
1031 else {
1032 /* TBD */
1033 dbgLog(("work needed here for blobs with no minus key\n"));
1034 }
1035 }
1036 *keyBlobLen = sLen;
1037 return FR_Success;
1038 }
1039
1040 #endif /* ECDSA_VERIFY_ONLY */
1041
1042 /*
1043 * Init an empty feePubKey from a native blob (non-DER format).
1044 */
1045 static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
1046 unsigned char *keyBlob,
1047 unsigned keyBlobLen)
1048 {
1049 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1050 unsigned char *s; // running pointer
1051 unsigned sLen; // bytes remaining in *s
1052 int magic;
1053 unsigned len; // for length of individual components
1054 int minVersion;
1055 int version;
1056 int isPrivate;
1057
1058 s = keyBlob;
1059 sLen = keyBlobLen;
1060 if(sLen < (4 * sizeof(int))) { // magic, version, minVersion, spare
1061 /*
1062 * Too short for all the ints we need
1063 */
1064 dbgLog(("feePublicKey: key blob (1)\n"));
1065 return FR_BadKeyBlob;
1066 }
1067
1068 magic = byteRepToInt(s);
1069 s += sizeof(int);
1070 sLen -= sizeof(int);
1071 switch(magic) {
1072 case PUBLIC_KEY_BLOB_MAGIC_PUB:
1073 isPrivate = 0;
1074 break;
1075 case PUBLIC_KEY_BLOB_MAGIC_PRIV:
1076 isPrivate = 1;
1077 break;
1078 default:
1079 dbgLog(("feePublicKey: Bad Public Key Magic Number\n"));
1080 return FR_BadKeyBlob;
1081 }
1082
1083 /*
1084 * Switch on this for version-specific cases
1085 */
1086 version = byteRepToInt(s);
1087 s += sizeof(int);
1088 sLen -= sizeof(int);
1089
1090 minVersion = byteRepToInt(s);
1091 s += sizeof(int);
1092 sLen -= sizeof(int);
1093 if(minVersion > PUBLIC_KEY_BLOB_VERSION) {
1094 /*
1095 * old code, newer key blob - can't parse
1096 */
1097 dbgLog(("feePublicKey: Incompatible Public Key (1)\n"));
1098 return FR_BadKeyBlob;
1099 }
1100
1101 s += sizeof(int); // skip spare
1102 sLen -= sizeof(int);
1103
1104 pkinst->cp = byteRepToCurveParams(s, sLen, &len);
1105 if(pkinst->cp == NULL) {
1106 dbgLog(("feePublicKey: Bad Key Blob(2)\n"));
1107 return FR_BadKeyBlob;
1108 }
1109 s += len;
1110 sLen -= len;
1111
1112 /*
1113 * Private key blob: privGiant.
1114 * Public Key blob: plusX, minusX, plusY.
1115 */
1116 if(isPrivate) {
1117 pkinst->privGiant = byteRepToGiant(s, sLen, &len);
1118 if(pkinst->privGiant == NULL) {
1119 dbgLog(("feePublicKey: Bad Key Blob(3)\n"));
1120 return FR_BadKeyBlob;
1121 }
1122 s += len;
1123 sLen -= len;
1124 }
1125 else {
1126 /* this writes x and y */
1127 pkinst->plus = byteRepToKey(s,
1128 sLen,
1129 CURVE_PLUS, // twist
1130 pkinst->cp,
1131 &len);
1132 if(pkinst->plus == NULL) {
1133 dbgLog(("feePublicKey: Bad Key Blob(4)\n"));
1134 return FR_BadKeyBlob;
1135 }
1136 s += len;
1137 sLen -= len;
1138
1139 /* this only writes x */
1140 pkinst->minus = byteRepToKey(s,
1141 sLen,
1142 CURVE_MINUS, // twist
1143 pkinst->cp,
1144 &len);
1145 if(pkinst->minus == NULL) {
1146 dbgLog(("feePublicKey: Bad Key Blob(5)\n"));
1147 return FR_BadKeyBlob;
1148 }
1149 s += len;
1150 sLen -= len;
1151 }
1152
1153 /*
1154 * One more thing: cook up public plusX and minusX for private key
1155 * blob case.
1156 */
1157 if(isPrivate) {
1158 pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
1159 pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
1160 set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1161 set_priv_key_giant(pkinst->minus, pkinst->privGiant);
1162 }
1163 return FR_Success;
1164
1165 }
1166
1167 feeReturn feePubKeyInitFromPubBlob(feePubKey pubKey,
1168 unsigned char *keyBlob,
1169 unsigned keyBlobLen)
1170 {
1171 return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
1172 }
1173
1174 #ifndef ECDSA_VERIFY_ONLY
1175
1176 feeReturn feePubKeyInitFromPrivBlob(feePubKey pubKey,
1177 unsigned char *keyBlob,
1178 unsigned keyBlobLen)
1179 {
1180 return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
1181 }
1182
1183 #endif /* ECDSA_VERIFY_ONLY */
1184
1185 #if CRYPTKIT_DER_ENABLE
1186 #ifndef ECDSA_VERIFY_ONLY
1187
1188 /*
1189 * DER format support.
1190 * Obtain portable public and private DER-encoded key blobs from a key.
1191 */
1192 feeReturn feePubKeyCreateDERPubBlob(feePubKey pubKey,
1193 unsigned char **keyBlob, // mallocd and RETURNED
1194 unsigned *keyBlobLen) // RETURNED
1195 {
1196 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1197
1198 if(pkinst == NULL) {
1199 return FR_BadPubKey;
1200 }
1201 if(pkinst->minus == NULL) {
1202 /* Only ECDSA key formats supported */
1203 return FR_IncompatibleKey;
1204 }
1205 return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION,
1206 pkinst->cp,
1207 pkinst->plus->x,
1208 pkinst->minus->x,
1209 isZero(pkinst->plus->y) ? NULL : pkinst->plus->y,
1210 keyBlob,
1211 keyBlobLen);
1212 }
1213
1214 feeReturn feePubKeyCreateDERPrivBlob(feePubKey pubKey,
1215 unsigned char **keyBlob, // mallocd and RETURNED
1216 unsigned *keyBlobLen) // RETURNED
1217 {
1218 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1219
1220 if(pkinst == NULL) {
1221 return FR_BadPubKey;
1222 }
1223 if(pkinst->privGiant == NULL) {
1224 return FR_IncompatibleKey;
1225 }
1226 if(pkinst->minus == NULL) {
1227 /* Only ECDSA key formats supported */
1228 return FR_IncompatibleKey;
1229 }
1230 return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION,
1231 pkinst->cp,
1232 pkinst->privGiant,
1233 keyBlob,
1234 keyBlobLen);
1235 }
1236
1237 #endif /* ECDSA_VERIFY_ONLY */
1238
1239 /*
1240 * Init an empty feePubKey from a DER-encoded blob, public and private key versions.
1241 */
1242 feeReturn feePubKeyInitFromDERPubBlob(feePubKey pubKey,
1243 unsigned char *keyBlob,
1244 size_t keyBlobLen)
1245 {
1246 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1247 feeReturn frtn;
1248 int version;
1249
1250 if(pkinst == NULL) {
1251 return FR_BadPubKey;
1252 }
1253
1254 /* kind of messy, maybe we should clean this up. But new_public() does too
1255 * much - e.g., it allocates the x and y which we really don't want */
1256 memset(pkinst, 0, sizeof(pubKeyInst));
1257 pkinst->plus = (key) fmalloc(sizeof(keystruct));
1258 pkinst->minus = (key) fmalloc(sizeof(keystruct));
1259 if((pkinst->plus == NULL) || (pkinst->minus == NULL)) {
1260 return FR_Memory;
1261 }
1262 memset(pkinst->plus, 0, sizeof(keystruct));
1263 memset(pkinst->minus, 0, sizeof(keystruct));
1264 pkinst->cp = NULL;
1265 pkinst->privGiant = NULL;
1266 pkinst->plus->twist = CURVE_PLUS;
1267 pkinst->minus->twist = CURVE_MINUS;
1268 frtn = feeDERDecodePublicKey(keyBlob,
1269 (unsigned)keyBlobLen,
1270 &version, // currently unused
1271 &pkinst->cp,
1272 &pkinst->plus->x,
1273 &pkinst->minus->x,
1274 &pkinst->plus->y);
1275 if(frtn) {
1276 return frtn;
1277 }
1278 /* minus curve, y is not used */
1279 pkinst->minus->y = newGiant(1);
1280 int_to_giant(0, pkinst->minus->y);
1281 pkinst->plus->cp = pkinst->minus->cp = pkinst->cp;
1282 return FR_Success;
1283 }
1284
1285 #ifndef ECDSA_VERIFY_ONLY
1286
1287 feeReturn feePubKeyInitFromDERPrivBlob(feePubKey pubKey,
1288 unsigned char *keyBlob,
1289 size_t keyBlobLen)
1290 {
1291 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1292 int version;
1293 feeReturn frtn;
1294
1295 if(pkinst == NULL) {
1296 return FR_BadPubKey;
1297 }
1298 memset(pkinst, 0, sizeof(pubKeyInst));
1299 frtn = feeDERDecodePrivateKey(keyBlob,
1300 (unsigned)keyBlobLen,
1301 &version, // currently unused
1302 &pkinst->cp,
1303 &pkinst->privGiant);
1304 if(frtn) {
1305 return frtn;
1306 }
1307
1308 /* since this blob only had the private data, infer the remaining fields */
1309 pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
1310 pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
1311 set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1312 set_priv_key_giant(pkinst->minus, pkinst->privGiant);
1313 return FR_Success;
1314 }
1315
1316 #endif /* ECDSA_VERIFY_ONLY */
1317
1318 #pragma mark --- X509 (public) and PKCS8 (private) key formatting ---
1319
1320 feeReturn feePubKeyCreateX509Blob(
1321 feePubKey pubKey, // public key
1322 unsigned char **keyBlob, // mallocd and RETURNED
1323 unsigned *keyBlobLen) // RETURNED
1324 {
1325 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1326 unsigned char *xyStr = NULL;
1327 unsigned xyStrLen = 0;
1328 feeReturn frtn = feeCreateECDSAPubBlob(pubKey, &xyStr, &xyStrLen);
1329 if(frtn) {
1330 return frtn;
1331 }
1332 frtn = feeDEREncodeX509PublicKey(xyStr, xyStrLen, pkinst->cp, keyBlob, keyBlobLen);
1333 ffree(xyStr);
1334 return frtn;
1335 }
1336
1337 feeReturn feePubKeyCreatePKCS8Blob(
1338 feePubKey pubKey, // private key
1339 unsigned char **keyBlob, // mallocd and RETURNED
1340 unsigned *keyBlobLen) // RETURNED
1341 {
1342 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1343 unsigned char *privStr = NULL;
1344 unsigned privStrLen = 0;
1345 feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1346 if(frtn) {
1347 return frtn;
1348 }
1349 unsigned char *pubStr = NULL;
1350 unsigned pubStrLen = 0;
1351 frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1352 if(frtn) {
1353 goto errOut;
1354 }
1355 frtn = feeDEREncodePKCS8PrivateKey(privStr, privStrLen,
1356 pubStr, pubStrLen,
1357 pkinst->cp, keyBlob, keyBlobLen);
1358 errOut:
1359 if(privStr) {
1360 ffree(privStr);
1361 }
1362 if(pubStr) {
1363 ffree(pubStr);
1364 }
1365 return frtn;
1366 }
1367
1368 feeReturn feePubKeyInitFromX509Blob(
1369 feePubKey pubKey, // public key
1370 unsigned char *keyBlob,
1371 size_t keyBlobLen)
1372 {
1373 feeDepth depth;
1374 unsigned char *xyStr = NULL;
1375 unsigned xyStrLen = 0;
1376
1377 /* obtain x/y and depth from X509 encoding */
1378 feeReturn frtn = feeDERDecodeX509PublicKey(keyBlob, (unsigned)keyBlobLen, &depth,
1379 &xyStr, &xyStrLen);
1380 if(frtn) {
1381 return frtn;
1382 }
1383
1384 frtn = feePubKeyInitFromECDSAPubBlob(pubKey, xyStr, xyStrLen, depth);
1385 ffree(xyStr);
1386 return frtn;
1387 }
1388
1389
1390 feeReturn feePubKeyInitFromPKCS8Blob(
1391 feePubKey pubKey, // private key
1392 unsigned char *keyBlob,
1393 size_t keyBlobLen)
1394 {
1395 feeDepth depth;
1396 unsigned char *privStr = NULL;
1397 unsigned privStrLen = 0;
1398
1399 /* obtain x/y and depth from PKCS8 encoding */
1400 /* For now we ignore the possible public key string */
1401 feeReturn frtn = feeDERDecodePKCS8PrivateKey(keyBlob, (unsigned)keyBlobLen, &depth,
1402 &privStr, &privStrLen, NULL, NULL);
1403 if(frtn) {
1404 return frtn;
1405 }
1406
1407 frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1408 ffree(privStr);
1409 return frtn;
1410 }
1411
1412 #pragma mark --- OpenSSL key formatting ---
1413
1414 /*
1415 * The native OpenSSL ECDSA key format contains both the private and public
1416 * components in one blob. This throws a bit of a monkey wrench into the API
1417 * here, as we only have one encoder - which requires a private key - and one
1418 * decoder, which can result in the decoding of either a public or a private
1419 * key.
1420 */
1421 feeReturn feePubKeyCreateOpenSSLBlob(
1422 feePubKey pubKey, // private key
1423 unsigned char **keyBlob, // mallocd and RETURNED
1424 unsigned *keyBlobLen) // RETURNED
1425 {
1426 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1427 unsigned char *privStr = NULL;
1428 unsigned privStrLen = 0;
1429 feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1430 if(frtn) {
1431 return frtn;
1432 }
1433 unsigned char *pubStr = NULL;
1434 unsigned pubStrLen = 0;
1435 frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1436 if(frtn) {
1437 goto errOut;
1438 }
1439 frtn = feeDEREncodeOpenSSLPrivateKey(privStr, privStrLen,
1440 pubStr, pubStrLen,
1441 pkinst->cp, keyBlob, keyBlobLen);
1442 errOut:
1443 if(privStr) {
1444 ffree(privStr);
1445 }
1446 if(pubStr) {
1447 ffree(pubStr);
1448 }
1449 return frtn;
1450 }
1451
1452 feeReturn feePubKeyInitFromOpenSSLBlob(
1453 feePubKey pubKey, // private or public key
1454 int pubOnly,
1455 unsigned char *keyBlob,
1456 size_t keyBlobLen)
1457 {
1458 feeDepth depth;
1459 unsigned char *privStr = NULL;
1460 unsigned privStrLen = 0;
1461 unsigned char *pubStr = NULL;
1462 unsigned pubStrLen = 0;
1463
1464 /* obtain x/y, public bit string, and depth from PKCS8 encoding */
1465 feeReturn frtn = feeDERDecodeOpenSSLKey(keyBlob, (unsigned)keyBlobLen, &depth,
1466 &privStr, &privStrLen, &pubStr, &pubStrLen);
1467 if(frtn) {
1468 return frtn;
1469 }
1470
1471 if(pubOnly) {
1472 frtn = feePubKeyInitFromECDSAPubBlob(pubKey, pubStr, pubStrLen, depth);
1473 }
1474 else {
1475 frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1476 }
1477 if(privStr) {
1478 ffree(privStr);
1479 }
1480 if(pubStr) {
1481 ffree(pubStr);
1482 }
1483 return frtn;
1484 }
1485
1486 #endif /* CRYPTKIT_DER_ENABLE */
1487
1488 /*
1489 * ANSI X9.62/Certicom key support.
1490 * Public key is 04 || x || y
1491 * Private key is privData per Certicom SEC1 C.4.
1492 */
1493 feeReturn feeCreateECDSAPubBlob(feePubKey pubKey,
1494 unsigned char **keyBlob,
1495 unsigned *keyBlobLen)
1496 {
1497 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1498 if(pkinst == NULL) {
1499 return FR_BadPubKey;
1500 }
1501
1502 unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1503 unsigned blobSize = 1 + (2 * giantBytes);
1504 unsigned char *blob = fmalloc(blobSize);
1505 if(blob == NULL) {
1506 return FR_Memory;
1507 }
1508 *blob = 0x04;
1509 serializeGiant(pkinst->plus->x, blob+1, giantBytes);
1510 serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes);
1511 *keyBlob = blob;
1512 *keyBlobLen = blobSize;
1513 return FR_Success;
1514 }
1515
1516 feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey,
1517 unsigned char **keyBlob,
1518 unsigned *keyBlobLen)
1519 {
1520 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1521 if(pkinst == NULL) {
1522 return FR_BadPubKey;
1523 }
1524 if(pkinst->privGiant == NULL) {
1525 return FR_IncompatibleKey;
1526 }
1527
1528 /*
1529 * Return the raw private key bytes padded with zeroes in
1530 * the m.s. end to fill exactly one prime-size byte array.
1531 */
1532 unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1533 unsigned char *blob = fmalloc(giantBytes);
1534 if(blob == NULL) {
1535 return FR_Memory;
1536 }
1537 serializeGiant(pkinst->privGiant, blob, giantBytes);
1538 *keyBlob = blob;
1539 *keyBlobLen = giantBytes;
1540 return FR_Success;
1541 }
1542
1543 /* Caller determines depth from other sources (e.g. AlgId.Params) */
1544 feeReturn feePubKeyInitFromECDSAPubBlob(feePubKey pubKey,
1545 const unsigned char *keyBlob,
1546 unsigned keyBlobLen,
1547 feeDepth depth)
1548 {
1549 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1550 if(pkinst == NULL) {
1551 return FR_BadPubKey;
1552 }
1553 curveParams *cp = curveParamsForDepth(depth);
1554 if(cp == NULL) {
1555 return FR_IllegalDepth;
1556 }
1557 unsigned giantBytes = (cp->q + 7) / 8;
1558 unsigned blobSize = 1 + (2 * giantBytes);
1559 if(keyBlobLen != blobSize) {
1560 dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blobLen\n"));
1561 return FR_BadKeyBlob;
1562 }
1563 if(*keyBlob != 0x04) {
1564 dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n"));
1565 return FR_BadKeyBlob;
1566 }
1567
1568 pkinst->cp = cp;
1569 pkinst->plus = new_public(cp, CURVE_PLUS);
1570 deserializeGiant(keyBlob+1, pkinst->plus->x, giantBytes);
1571 deserializeGiant(keyBlob+1+giantBytes, pkinst->plus->y, giantBytes);
1572 return FR_Success;
1573 }
1574
1575 feeReturn feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey,
1576 const unsigned char *keyBlob,
1577 unsigned keyBlobLen,
1578 feeDepth depth)
1579 {
1580 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1581 if(pkinst == NULL) {
1582 return FR_BadPubKey;
1583 }
1584 curveParams *cp = curveParamsForDepth(depth);
1585 if(cp == NULL) {
1586 return FR_IllegalDepth;
1587 }
1588 unsigned giantDigits = cp->basePrime->sign;
1589 unsigned giantBytes = (cp->q + 7) / 8;
1590
1591 /*
1592 * The specified private key can be one byte smaller than the modulus */
1593 if((keyBlobLen > giantBytes) || (keyBlobLen < (giantBytes - 1))) {
1594 dbgLog(("feePubKeyInitFromECDSAPrivBlob: bad blobLen\n"));
1595 return FR_BadKeyBlob;
1596 }
1597
1598 pkinst->cp = cp;
1599
1600 /* cook up a new private giant */
1601 pkinst->privGiant = newGiant(giantDigits);
1602 if(pkinst->privGiant == NULL) {
1603 return FR_Memory;
1604 }
1605 deserializeGiant(keyBlob, pkinst->privGiant, keyBlobLen);
1606
1607 /* since this blob only had the private data, infer the remaining fields */
1608 pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
1609 set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1610 return FR_Success;
1611 }
1612