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