]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/feePublicKey.c
Security-58286.51.6.tar.gz
[apple/security.git] / OSX / libsecurity_cryptkit / lib / 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 "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 }
725
726 /*
727 * Accessor routines.
728 */
729 /* private only...*/
730 key feePubKeyPlusCurve(feePubKey pubKey)
731 {
732 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
733
734 return pkinst->plus;
735 }
736
737 key feePubKeyMinusCurve(feePubKey pubKey)
738 {
739 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
740
741 return pkinst->minus;
742 }
743
744 curveParams *feePubKeyCurveParams(feePubKey pubKey)
745 {
746 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
747
748 return pkinst->cp;
749 }
750
751 giant feePubKeyPrivData(feePubKey pubKey)
752 {
753 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
754
755 return pkinst->privGiant;
756 }
757
758 const char *feePubKeyAlgorithmName(void)
759 {
760 return "Elliptic Curve - FEE by Apple Computer";
761 }
762
763 #pragma mark --- Private functions ---
764
765 /*
766 * alloc, free pubKeyInst
767 */
768 static pubKeyInst *pubKeyInstAlloc(void)
769 {
770 pubKeyInst *pkinst = (pubKeyInst *) fmalloc(sizeof(pubKeyInst));
771
772 bzero(pkinst, sizeof(pubKeyInst));
773 return pkinst;
774 }
775
776 static void pubKeyInstFree(pubKeyInst *pkinst)
777 {
778 if(pkinst->minus) {
779 free_key(pkinst->minus);
780 }
781 if(pkinst->plus) {
782 free_key(pkinst->plus);
783 }
784 if(pkinst->cp) {
785 freeCurveParams(pkinst->cp);
786 }
787 if(pkinst->privGiant) {
788 /*
789 * Zero out the private data...
790 */
791 clearGiant(pkinst->privGiant);
792 freeGiant(pkinst->privGiant);
793 }
794 ffree(pkinst);
795 }
796
797 #ifndef ECDSA_VERIFY_ONLY
798
799 /*
800 * Create a pubKeyInst.privGiant given a password of
801 * arbitrary length.
802 * Currently, the only error is "private data too short" (FR_IllegalArg).
803 */
804
805 #define NO_PRIV_MUNGE 0 /* skip this step */
806
807 static feeReturn feeGenPrivate(pubKeyInst *pkinst,
808 const unsigned char *passwd,
809 unsigned passwdLen,
810 char hashPasswd)
811 {
812 unsigned privLen; // desired size of pkinst->privData
813 feeHash *hash = NULL; // a malloc'd array
814 unsigned digestLen; // size of MD5 digest
815 unsigned dataSize; // min(privLen, passwdLen)
816 unsigned numDigests = 0;
817 unsigned i;
818 unsigned char *cp;
819 unsigned toMove; // for this digest
820 unsigned moved; // total digested
821 unsigned char *digest = NULL;
822 unsigned char *privData = NULL; // temp, before modg(curveOrder)
823 giant corder; // lesser of two curve orders
824
825 /*
826 * generate privData which is just larger than the smaller
827 * curve order.
828 * We'll take the result mod the curve order when we're done.
829 * Note we do *not* have to free corder - it's a pointer to a giant
830 * in pkinst->cp.
831 */
832 corder = lesserX1Order(pkinst->cp);
833 CKASSERT(!isZero(corder));
834 privLen = (bitlen(corder) / 8) + 1;
835
836 if(!hashPasswd) {
837 /*
838 * Caller trusts the incoming entropy. Verify it's big enough and proceed.
839 */
840 if(passwdLen < privLen) {
841 return FR_ShortPrivData;
842 }
843 privLen = passwdLen;
844 privData = (unsigned char *)passwd;
845 goto finishUp;
846 }
847 if(passwdLen < 2) {
848 return FR_IllegalArg;
849 }
850
851
852 /*
853 * Calculate how many MD5 digests we'll generate.
854 */
855 if(privLen > passwdLen) {
856 dataSize = passwdLen;
857 }
858 else {
859 dataSize = privLen;
860 }
861 digestLen = feeHashDigestLen();
862 numDigests = (dataSize + digestLen - 1) / digestLen;
863
864 hash = (void**) fmalloc(numDigests * sizeof(feeHash));
865 for(i=0; i<numDigests; i++) {
866 hash[i] = feeHashAlloc();
867 }
868
869 /*
870 * fill digests with passwd data, digestLen (or resid length)
871 * at a time. If (passwdLen > privLen), last digest will hash all
872 * remaining passwd data.
873 */
874 cp = (unsigned char *)passwd;
875 moved = 0;
876 for(i=0; i<numDigests; i++) {
877 if(i == (numDigests - 1)) { // last digest
878 toMove = passwdLen - moved;
879 }
880 else {
881 toMove = digestLen;
882 }
883 feeHashAddData(hash[i], cp, toMove);
884 cp += toMove;
885 moved += toMove;
886 }
887
888 /*
889 * copy digests to privData, up to privLen bytes. Pad with
890 * additional copies of digests if necessary.
891 */
892 privData = (unsigned char*) fmalloc(privLen);
893 cp = privData;
894 moved = 0;
895 i = 0; // digest number
896 for(moved=0; moved<privLen; ) {
897 if((moved + digestLen) > privLen) {
898 toMove = privLen - moved;
899 }
900 else {
901 toMove = digestLen;
902 }
903 digest = feeHashDigest(hash[i++]);
904 bcopy(digest, cp, toMove);
905 cp += toMove;
906 moved += toMove;
907 if(i == numDigests) {
908 i = 0; // wrap to 0, start padding
909 }
910 }
911
912 finishUp:
913 /*
914 * Convert to giant, justify result to within [2, lesserX1Order]
915 */
916 pkinst->privGiant = giant_with_data(privData, privLen);
917
918 #if FEE_DEBUG
919 if(isZero(pkinst->privGiant)) {
920 printf("feeGenPrivate: privData = 0!\n");
921 }
922 #endif // FEE_DEBUG
923
924 lesserX1OrderJustify(pkinst->privGiant, pkinst->cp);
925 if(hashPasswd) {
926 memset(privData, 0, privLen);
927 ffree(privData);
928 for(i=0; i<numDigests; i++) {
929 feeHashFree(hash[i]);
930 }
931 ffree(hash);
932 }
933 return FR_Success;
934 }
935
936 #endif /* ECDSA_VERIFY_ONLY */
937
938 #if FEE_DEBUG
939
940 void printPubKey(feePubKey pubKey)
941 {
942 pubKeyInst *pkinst = pubKey;
943
944 printf("\ncurveParams:\n");
945 printCurveParams(pkinst->cp);
946 printf("plus:\n");
947 printKey(pkinst->plus);
948 printf("minus:\n");
949 printKey(pkinst->minus);
950 if(pkinst->privGiant != NULL) {
951 printf("privGiant : ");
952 printGiant(pkinst->privGiant);
953 }
954 }
955
956 #else // FEE_DEBUG
957 void printPubKey(feePubKey pubKey) {}
958 #endif // FEE_DEBUG
959
960 /*
961 * Prime the curveParams and giants modules for quick allocs of giants.
962 */
963 #if GIANTS_VIA_STACK
964
965 static int giantsInitd = 0;
966
967 static void feePubKeyInitGiants(void)
968 {
969 if(giantsInitd) {
970 return;
971 }
972 curveParamsInitGiants();
973 giantsInitd = 1;
974 }
975 #endif
976
977 #pragma mark --- Native (custom) key blob formatting ---
978
979 /*
980 * Exported key blob support. New, 23 Mar 1998.
981 *
982 * Convert to public or private key blob.
983 */
984
985 #ifndef ECDSA_VERIFY_ONLY
986
987 /***
988 *** Common native blob support
989 ***/
990 static feeReturn createKeyBlob(pubKeyInst *pkinst,
991 int isPrivate, // 0 : public 1 : private
992 unsigned char **keyBlob, // mallocd and RETURNED
993 unsigned *keyBlobLen) // RETURNED
994 {
995 unsigned char *s; // running ptr into *origS
996 unsigned sLen;
997 int magic;
998
999 /* common blob elements */
1000 sLen = (4 * sizeof(int)) + // magic, version, minVersion,
1001 // spare
1002 lengthOfByteRepCurveParams(pkinst->cp);
1003 if(isPrivate) {
1004 /* private only */
1005 sLen += lengthOfByteRepGiant(pkinst->privGiant);
1006 magic = PUBLIC_KEY_BLOB_MAGIC_PRIV;
1007 }
1008 else {
1009 /* public only */
1010 sLen += (lengthOfByteRepKey(pkinst->plus) +
1011 lengthOfByteRepKey(pkinst->minus));
1012 magic = PUBLIC_KEY_BLOB_MAGIC_PUB;
1013 }
1014 *keyBlob = s = (unsigned char*) fmalloc(sLen);
1015 s += intToByteRep(magic, s);
1016 s += intToByteRep(PUBLIC_KEY_BLOB_VERSION, s);
1017 s += intToByteRep(PUBLIC_KEY_BLOB_MINVERSION, s);
1018 s += intToByteRep(0, s); // spare
1019 s += curveParamsToByteRep(pkinst->cp, s);
1020 if(isPrivate) {
1021 s += giantToByteRep(pkinst->privGiant, s);
1022 }
1023 else {
1024 /* keyToByteRep writes y for plus curve only */
1025 s += keyToByteRep(pkinst->plus, s);
1026 if(pkinst->minus != NULL) {
1027 s += keyToByteRep(pkinst->minus, s);
1028 }
1029 else {
1030 /* TBD */
1031 dbgLog(("work needed here for blobs with no minus key\n"));
1032 }
1033 }
1034 *keyBlobLen = sLen;
1035 return FR_Success;
1036 }
1037
1038 #endif /* ECDSA_VERIFY_ONLY */
1039
1040 /*
1041 * Init an empty feePubKey from a native blob (non-DER format).
1042 */
1043 static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
1044 unsigned char *keyBlob,
1045 unsigned keyBlobLen)
1046 {
1047 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1048 unsigned char *s; // running pointer
1049 unsigned sLen; // bytes remaining in *s
1050 int magic;
1051 unsigned len; // for length of individual components
1052 int minVersion;
1053 int version;
1054 int isPrivate;
1055
1056 s = keyBlob;
1057 sLen = keyBlobLen;
1058 if(sLen < (4 * sizeof(int))) { // magic, version, minVersion, spare
1059 /*
1060 * Too short for all the ints we need
1061 */
1062 dbgLog(("feePublicKey: key blob (1)\n"));
1063 return FR_BadKeyBlob;
1064 }
1065
1066 magic = byteRepToInt(s);
1067 s += sizeof(int);
1068 sLen -= sizeof(int);
1069 switch(magic) {
1070 case PUBLIC_KEY_BLOB_MAGIC_PUB:
1071 isPrivate = 0;
1072 break;
1073 case PUBLIC_KEY_BLOB_MAGIC_PRIV:
1074 isPrivate = 1;
1075 break;
1076 default:
1077 dbgLog(("feePublicKey: Bad Public Key Magic Number\n"));
1078 return FR_BadKeyBlob;
1079 }
1080
1081 /*
1082 * Switch on this for version-specific cases
1083 */
1084 version = byteRepToInt(s);
1085 s += sizeof(int);
1086 sLen -= sizeof(int);
1087
1088 minVersion = byteRepToInt(s);
1089 s += sizeof(int);
1090 sLen -= sizeof(int);
1091 if(minVersion > PUBLIC_KEY_BLOB_VERSION) {
1092 /*
1093 * old code, newer key blob - can't parse
1094 */
1095 dbgLog(("feePublicKey: Incompatible Public Key (1)\n"));
1096 return FR_BadKeyBlob;
1097 }
1098
1099 s += sizeof(int); // skip spare
1100 sLen -= sizeof(int);
1101
1102 pkinst->cp = byteRepToCurveParams(s, sLen, &len);
1103 if(pkinst->cp == NULL) {
1104 dbgLog(("feePublicKey: Bad Key Blob(2)\n"));
1105 return FR_BadKeyBlob;
1106 }
1107 s += len;
1108 sLen -= len;
1109
1110 /*
1111 * Private key blob: privGiant.
1112 * Public Key blob: plusX, minusX, plusY.
1113 */
1114 if(isPrivate) {
1115 pkinst->privGiant = byteRepToGiant(s, sLen, &len);
1116 if(pkinst->privGiant == NULL) {
1117 dbgLog(("feePublicKey: Bad Key Blob(3)\n"));
1118 return FR_BadKeyBlob;
1119 }
1120 s += len;
1121 sLen -= len;
1122 }
1123 else {
1124 /* this writes x and y */
1125 pkinst->plus = byteRepToKey(s,
1126 sLen,
1127 CURVE_PLUS, // twist
1128 pkinst->cp,
1129 &len);
1130 if(pkinst->plus == NULL) {
1131 dbgLog(("feePublicKey: Bad Key Blob(4)\n"));
1132 return FR_BadKeyBlob;
1133 }
1134 s += len;
1135 sLen -= len;
1136
1137 /* this only writes x */
1138 pkinst->minus = byteRepToKey(s,
1139 sLen,
1140 CURVE_MINUS, // twist
1141 pkinst->cp,
1142 &len);
1143 if(pkinst->minus == NULL) {
1144 dbgLog(("feePublicKey: Bad Key Blob(5)\n"));
1145 return FR_BadKeyBlob;
1146 }
1147 s += len;
1148 sLen -= len;
1149 }
1150
1151 /*
1152 * One more thing: cook up public plusX and minusX for private key
1153 * blob case.
1154 */
1155 if(isPrivate) {
1156 pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
1157 pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
1158 set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1159 set_priv_key_giant(pkinst->minus, pkinst->privGiant);
1160 }
1161 return FR_Success;
1162
1163 }
1164
1165 feeReturn feePubKeyInitFromPubBlob(feePubKey pubKey,
1166 unsigned char *keyBlob,
1167 unsigned keyBlobLen)
1168 {
1169 return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
1170 }
1171
1172 #ifndef ECDSA_VERIFY_ONLY
1173
1174 feeReturn feePubKeyInitFromPrivBlob(feePubKey pubKey,
1175 unsigned char *keyBlob,
1176 unsigned keyBlobLen)
1177 {
1178 return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
1179 }
1180
1181 #endif /* ECDSA_VERIFY_ONLY */
1182
1183 #if CRYPTKIT_DER_ENABLE
1184 #ifndef ECDSA_VERIFY_ONLY
1185
1186 /*
1187 * DER format support.
1188 * Obtain portable public and private DER-encoded key blobs from a key.
1189 */
1190 feeReturn feePubKeyCreateDERPubBlob(feePubKey pubKey,
1191 unsigned char **keyBlob, // mallocd and RETURNED
1192 unsigned *keyBlobLen) // RETURNED
1193 {
1194 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1195
1196 if(pkinst == NULL) {
1197 return FR_BadPubKey;
1198 }
1199 if(pkinst->minus == NULL) {
1200 /* Only ECDSA key formats supported */
1201 return FR_IncompatibleKey;
1202 }
1203 return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION,
1204 pkinst->cp,
1205 pkinst->plus->x,
1206 pkinst->minus->x,
1207 isZero(pkinst->plus->y) ? NULL : pkinst->plus->y,
1208 keyBlob,
1209 keyBlobLen);
1210 }
1211
1212 feeReturn feePubKeyCreateDERPrivBlob(feePubKey pubKey,
1213 unsigned char **keyBlob, // mallocd and RETURNED
1214 unsigned *keyBlobLen) // RETURNED
1215 {
1216 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1217
1218 if(pkinst == NULL) {
1219 return FR_BadPubKey;
1220 }
1221 if(pkinst->privGiant == NULL) {
1222 return FR_IncompatibleKey;
1223 }
1224 if(pkinst->minus == NULL) {
1225 /* Only ECDSA key formats supported */
1226 return FR_IncompatibleKey;
1227 }
1228 return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION,
1229 pkinst->cp,
1230 pkinst->privGiant,
1231 keyBlob,
1232 keyBlobLen);
1233 }
1234
1235 #endif /* ECDSA_VERIFY_ONLY */
1236
1237 /*
1238 * Init an empty feePubKey from a DER-encoded blob, public and private key versions.
1239 */
1240 feeReturn feePubKeyInitFromDERPubBlob(feePubKey pubKey,
1241 unsigned char *keyBlob,
1242 size_t keyBlobLen)
1243 {
1244 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1245 feeReturn frtn;
1246 int version;
1247
1248 if(pkinst == NULL) {
1249 return FR_BadPubKey;
1250 }
1251
1252 /* kind of messy, maybe we should clean this up. But new_public() does too
1253 * much - e.g., it allocates the x and y which we really don't want */
1254 memset(pkinst, 0, sizeof(pubKeyInst));
1255 pkinst->plus = (key) fmalloc(sizeof(keystruct));
1256 pkinst->minus = (key) fmalloc(sizeof(keystruct));
1257 if((pkinst->plus == NULL) || (pkinst->minus == NULL)) {
1258 return FR_Memory;
1259 }
1260 memset(pkinst->plus, 0, sizeof(keystruct));
1261 memset(pkinst->minus, 0, sizeof(keystruct));
1262 pkinst->cp = NULL;
1263 pkinst->privGiant = NULL;
1264 pkinst->plus->twist = CURVE_PLUS;
1265 pkinst->minus->twist = CURVE_MINUS;
1266 frtn = feeDERDecodePublicKey(keyBlob,
1267 (unsigned)keyBlobLen,
1268 &version, // currently unused
1269 &pkinst->cp,
1270 &pkinst->plus->x,
1271 &pkinst->minus->x,
1272 &pkinst->plus->y);
1273 if(frtn) {
1274 return frtn;
1275 }
1276 /* minus curve, y is not used */
1277 pkinst->minus->y = newGiant(1);
1278 int_to_giant(0, pkinst->minus->y);
1279 pkinst->plus->cp = pkinst->minus->cp = pkinst->cp;
1280 return FR_Success;
1281 }
1282
1283 #ifndef ECDSA_VERIFY_ONLY
1284
1285 feeReturn feePubKeyInitFromDERPrivBlob(feePubKey pubKey,
1286 unsigned char *keyBlob,
1287 size_t keyBlobLen)
1288 {
1289 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1290 int version;
1291 feeReturn frtn;
1292
1293 if(pkinst == NULL) {
1294 return FR_BadPubKey;
1295 }
1296 memset(pkinst, 0, sizeof(pubKeyInst));
1297 frtn = feeDERDecodePrivateKey(keyBlob,
1298 (unsigned)keyBlobLen,
1299 &version, // currently unused
1300 &pkinst->cp,
1301 &pkinst->privGiant);
1302 if(frtn) {
1303 return frtn;
1304 }
1305
1306 /* since this blob only had the private data, infer the remaining fields */
1307 pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
1308 pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
1309 set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1310 set_priv_key_giant(pkinst->minus, pkinst->privGiant);
1311 return FR_Success;
1312 }
1313
1314 #endif /* ECDSA_VERIFY_ONLY */
1315
1316 #pragma mark --- X509 (public) and PKCS8 (private) key formatting ---
1317
1318 feeReturn feePubKeyCreateX509Blob(
1319 feePubKey pubKey, // public key
1320 unsigned char **keyBlob, // mallocd and RETURNED
1321 unsigned *keyBlobLen) // RETURNED
1322 {
1323 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1324 unsigned char *xyStr = NULL;
1325 unsigned xyStrLen = 0;
1326 feeReturn frtn = feeCreateECDSAPubBlob(pubKey, &xyStr, &xyStrLen);
1327 if(frtn) {
1328 return frtn;
1329 }
1330 frtn = feeDEREncodeX509PublicKey(xyStr, xyStrLen, pkinst->cp, keyBlob, keyBlobLen);
1331 ffree(xyStr);
1332 return frtn;
1333 }
1334
1335 feeReturn feePubKeyCreatePKCS8Blob(
1336 feePubKey pubKey, // private key
1337 unsigned char **keyBlob, // mallocd and RETURNED
1338 unsigned *keyBlobLen) // RETURNED
1339 {
1340 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1341 unsigned char *privStr = NULL;
1342 unsigned privStrLen = 0;
1343 feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1344 if(frtn) {
1345 return frtn;
1346 }
1347 unsigned char *pubStr = NULL;
1348 unsigned pubStrLen = 0;
1349 frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1350 if(frtn) {
1351 goto errOut;
1352 }
1353 frtn = feeDEREncodePKCS8PrivateKey(privStr, privStrLen,
1354 pubStr, pubStrLen,
1355 pkinst->cp, keyBlob, keyBlobLen);
1356 errOut:
1357 if(privStr) {
1358 ffree(privStr);
1359 }
1360 if(pubStr) {
1361 ffree(pubStr);
1362 }
1363 return frtn;
1364 }
1365
1366 feeReturn feePubKeyInitFromX509Blob(
1367 feePubKey pubKey, // public key
1368 unsigned char *keyBlob,
1369 size_t keyBlobLen)
1370 {
1371 feeDepth depth;
1372 unsigned char *xyStr = NULL;
1373 unsigned xyStrLen = 0;
1374
1375 /* obtain x/y and depth from X509 encoding */
1376 feeReturn frtn = feeDERDecodeX509PublicKey(keyBlob, (unsigned)keyBlobLen, &depth,
1377 &xyStr, &xyStrLen);
1378 if(frtn) {
1379 return frtn;
1380 }
1381
1382 frtn = feePubKeyInitFromECDSAPubBlob(pubKey, xyStr, xyStrLen, depth);
1383 ffree(xyStr);
1384 return frtn;
1385 }
1386
1387
1388 feeReturn feePubKeyInitFromPKCS8Blob(
1389 feePubKey pubKey, // private key
1390 unsigned char *keyBlob,
1391 size_t keyBlobLen)
1392 {
1393 feeDepth depth;
1394 unsigned char *privStr = NULL;
1395 unsigned privStrLen = 0;
1396
1397 /* obtain x/y and depth from PKCS8 encoding */
1398 /* For now we ignore the possible public key string */
1399 feeReturn frtn = feeDERDecodePKCS8PrivateKey(keyBlob, (unsigned)keyBlobLen, &depth,
1400 &privStr, &privStrLen, NULL, NULL);
1401 if(frtn) {
1402 return frtn;
1403 }
1404
1405 frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1406 ffree(privStr);
1407 return frtn;
1408 }
1409
1410 #pragma mark --- OpenSSL key formatting ---
1411
1412 /*
1413 * The native OpenSSL ECDSA key format contains both the private and public
1414 * components in one blob. This throws a bit of a monkey wrench into the API
1415 * here, as we only have one encoder - which requires a private key - and one
1416 * decoder, which can result in the decoding of either a public or a private
1417 * key.
1418 */
1419 feeReturn feePubKeyCreateOpenSSLBlob(
1420 feePubKey pubKey, // private key
1421 unsigned char **keyBlob, // mallocd and RETURNED
1422 unsigned *keyBlobLen) // RETURNED
1423 {
1424 pubKeyInst *pkinst = (pubKeyInst *) pubKey;
1425 unsigned char *privStr = NULL;
1426 unsigned privStrLen = 0;
1427 feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
1428 if(frtn) {
1429 return frtn;
1430 }
1431 unsigned char *pubStr = NULL;
1432 unsigned pubStrLen = 0;
1433 frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
1434 if(frtn) {
1435 goto errOut;
1436 }
1437 frtn = feeDEREncodeOpenSSLPrivateKey(privStr, privStrLen,
1438 pubStr, pubStrLen,
1439 pkinst->cp, keyBlob, keyBlobLen);
1440 errOut:
1441 if(privStr) {
1442 ffree(privStr);
1443 }
1444 if(pubStr) {
1445 ffree(pubStr);
1446 }
1447 return frtn;
1448 }
1449
1450 feeReturn feePubKeyInitFromOpenSSLBlob(
1451 feePubKey pubKey, // private or public key
1452 int pubOnly,
1453 unsigned char *keyBlob,
1454 size_t keyBlobLen)
1455 {
1456 feeDepth depth;
1457 unsigned char *privStr = NULL;
1458 unsigned privStrLen = 0;
1459 unsigned char *pubStr = NULL;
1460 unsigned pubStrLen = 0;
1461
1462 /* obtain x/y, public bit string, and depth from PKCS8 encoding */
1463 feeReturn frtn = feeDERDecodeOpenSSLKey(keyBlob, (unsigned)keyBlobLen, &depth,
1464 &privStr, &privStrLen, &pubStr, &pubStrLen);
1465 if(frtn) {
1466 return frtn;
1467 }
1468
1469 if(pubOnly) {
1470 frtn = feePubKeyInitFromECDSAPubBlob(pubKey, pubStr, pubStrLen, depth);
1471 }
1472 else {
1473 frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
1474 }
1475 if(privStr) {
1476 ffree(privStr);
1477 }
1478 if(pubStr) {
1479 ffree(pubStr);
1480 }
1481 return frtn;
1482 }
1483
1484 #endif /* CRYPTKIT_DER_ENABLE */
1485
1486 /*
1487 * ANSI X9.62/Certicom key support.
1488 * Public key is 04 || x || y
1489 * Private key is privData per Certicom SEC1 C.4.
1490 */
1491 feeReturn feeCreateECDSAPubBlob(feePubKey pubKey,
1492 unsigned char **keyBlob,
1493 unsigned *keyBlobLen)
1494 {
1495 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1496 if(pkinst == NULL) {
1497 return FR_BadPubKey;
1498 }
1499
1500 unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1501 unsigned blobSize = 1 + (2 * giantBytes);
1502 unsigned char *blob = fmalloc(blobSize);
1503 if(blob == NULL) {
1504 return FR_Memory;
1505 }
1506 *blob = 0x04;
1507 serializeGiant(pkinst->plus->x, blob+1, giantBytes);
1508 serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes);
1509 *keyBlob = blob;
1510 *keyBlobLen = blobSize;
1511 return FR_Success;
1512 }
1513
1514 feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey,
1515 unsigned char **keyBlob,
1516 unsigned *keyBlobLen)
1517 {
1518 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1519 if(pkinst == NULL) {
1520 return FR_BadPubKey;
1521 }
1522 if(pkinst->privGiant == NULL) {
1523 return FR_IncompatibleKey;
1524 }
1525
1526 /*
1527 * Return the raw private key bytes padded with zeroes in
1528 * the m.s. end to fill exactly one prime-size byte array.
1529 */
1530 unsigned giantBytes = (pkinst->cp->q + 7) / 8;
1531 unsigned char *blob = fmalloc(giantBytes);
1532 if(blob == NULL) {
1533 return FR_Memory;
1534 }
1535 serializeGiant(pkinst->privGiant, blob, giantBytes);
1536 *keyBlob = blob;
1537 *keyBlobLen = giantBytes;
1538 return FR_Success;
1539 }
1540
1541 /* Caller determines depth from other sources (e.g. AlgId.Params) */
1542 feeReturn feePubKeyInitFromECDSAPubBlob(feePubKey pubKey,
1543 const unsigned char *keyBlob,
1544 unsigned keyBlobLen,
1545 feeDepth depth)
1546 {
1547 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1548 if(pkinst == NULL) {
1549 return FR_BadPubKey;
1550 }
1551 curveParams *cp = curveParamsForDepth(depth);
1552 if(cp == NULL) {
1553 return FR_IllegalDepth;
1554 }
1555 unsigned giantBytes = (cp->q + 7) / 8;
1556 unsigned blobSize = 1 + (2 * giantBytes);
1557 if(keyBlobLen != blobSize) {
1558 dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blobLen\n"));
1559 return FR_BadKeyBlob;
1560 }
1561 if(*keyBlob != 0x04) {
1562 dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n"));
1563 return FR_BadKeyBlob;
1564 }
1565
1566 pkinst->cp = cp;
1567 pkinst->plus = new_public(cp, CURVE_PLUS);
1568 deserializeGiant(keyBlob+1, pkinst->plus->x, giantBytes);
1569 deserializeGiant(keyBlob+1+giantBytes, pkinst->plus->y, giantBytes);
1570 return FR_Success;
1571 }
1572
1573 feeReturn feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey,
1574 const unsigned char *keyBlob,
1575 unsigned keyBlobLen,
1576 feeDepth depth)
1577 {
1578 pubKeyInst *pkinst = (pubKeyInst *)pubKey;
1579 if(pkinst == NULL) {
1580 return FR_BadPubKey;
1581 }
1582 curveParams *cp = curveParamsForDepth(depth);
1583 if(cp == NULL) {
1584 return FR_IllegalDepth;
1585 }
1586 unsigned giantDigits = cp->basePrime->sign;
1587 unsigned giantBytes = (cp->q + 7) / 8;
1588
1589 /*
1590 * The specified private key can be one byte smaller than the modulus */
1591 if((keyBlobLen > giantBytes) || (keyBlobLen < (giantBytes - 1))) {
1592 dbgLog(("feePubKeyInitFromECDSAPrivBlob: bad blobLen\n"));
1593 return FR_BadKeyBlob;
1594 }
1595
1596 pkinst->cp = cp;
1597
1598 /* cook up a new private giant */
1599 pkinst->privGiant = newGiant(giantDigits);
1600 if(pkinst->privGiant == NULL) {
1601 return FR_Memory;
1602 }
1603 deserializeGiant(keyBlob, pkinst->privGiant, keyBlobLen);
1604
1605 /* since this blob only had the private data, infer the remaining fields */
1606 pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
1607 set_priv_key_giant(pkinst->plus, pkinst->privGiant);
1608 return FR_Success;
1609 }
1610