1 /* Copyright (c) 1998,2011-2012,2014 Apple Inc. All Rights Reserved.
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 ***************************************************************************
11 * feePublicKey.c - Portable FEE public key object.
16 * Added ECDSA_VERIFY_ONLY dependencies.
18 * Changed to compile with C++.
20 * Major changes for IEEE P1363 compliance.
24 * Fixed feePubKeyBitsize bitlen bug for PT_GENERAL case.
26 * ECDSA now uses SHA-1 hash. Imcompatible with old ECDSA signatures.
28 * Added ECDSA signature routines.
30 * Added feePubKeyInitGiants()
31 * Deleted obsolete code
32 * Changes for lesserX1OrderJustify (was curveOrderJustify)
34 * Fixed leak in feePubKeyCreateKeyString()
36 * PUBLIC_KEY_STRING_VERSION = 3; broke compatibility with all older
38 * Cleaned up which_curve/index code to use CURVE_MINUS/CURVE_PLUS.
40 * Added initFromEnc64KeyStr().
43 * ???? 1994 Blaine Garst at NeXT
48 #include "feePublicKey.h"
49 #include "feePublicKeyPrivate.h"
50 #include "ckutilities.h"
51 #include "giantIntegers.h"
53 #include "curveParams.h"
59 #include "feeDigitalSignature.h"
64 #include "CryptKitDER.h"
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.
74 #define NULL ((void *)0)
78 * Magic number for a portable key blobs. Must be in sync with static
79 * final PUBLIC_KEY_STRING_MAGIC in JavaFee/PublicKey.java.
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
86 #define PUBLIC_DER_KEY_BLOB_VERSION 1
89 * Private data. All "instance" routines are passed a feePubKey (actually
90 * a void *) which is actually a pointer to one of these.
94 key minus
; // not needed for ECDSA
95 curveParams
*cp
; // common params shared by minus, plus
96 giant privGiant
; // private key
99 static feeReturn
feeGenPrivate(pubKeyInst
*pkinst
,
100 const unsigned char *passwd
,
103 static pubKeyInst
*pubKeyInstAlloc(void);
104 static void pubKeyInstFree(pubKeyInst
*pkinst
);
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
);
114 #pragma mark --- General public API function ---
117 * Obatin a newly allocated feePubKey.
119 feePubKey
feePubKeyAlloc(void)
121 pubKeyInst
*pkinst
= pubKeyInstAlloc();
127 void feePubKeyFree(feePubKey pubKey
)
129 pubKeyInstFree((pubKeyInst
*) pubKey
);
132 #ifndef ECDSA_VERIFY_ONLY
134 * Init feePubKey from private key data.
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" */
147 frtn
= feeKeyBitsToDepth(keyBits
, primeType
, curveType
, &depth
);
151 return feePubKeyInitFromPrivDataDepth(pubKey
,
158 feeReturn
feePubKeyInitFromPrivDataDepth(feePubKey pubKey
,
159 const unsigned char *privData
,
160 unsigned privDataLen
,
164 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
167 if(depth
> FEE_DEPTH_MAX
) {
168 dbgLog(("Illegal Depth\n"));
169 return FR_IllegalDepth
;
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
);
177 /* else only usable for ECDSA */
179 frtn
= feeGenPrivate(pkinst
, privData
, privDataLen
, hashPrivData
);
183 set_priv_key_giant(pkinst
->plus
, pkinst
->privGiant
);
184 if(pkinst
->cp
->x1Minus
!= NULL
) {
185 set_priv_key_giant(pkinst
->minus
, pkinst
->privGiant
);
190 #endif /* ECDSA_VERIFY_ONLY */
193 * Init feePubKey from curve parameters matching existing oldKey.
195 feeReturn
feePubKeyInitFromKey(feePubKey pubKey
,
196 const unsigned char *privData
,
197 unsigned privDataLen
,
201 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
202 pubKeyInst
*oldInst
= (pubKeyInst
*) oldKey
;
206 dbgLog(("NULL existing key\n"));
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
) {
217 /* else this curve only usable for ECDSA */
219 pkinst
->plus
= new_public(pkinst
->cp
, CURVE_PLUS
);
220 if(pkinst
->plus
== NULL
) {
223 frtn
= feeGenPrivate(pkinst
, privData
, privDataLen
, hashPrivData
);
227 set_priv_key_giant(pkinst
->plus
, pkinst
->privGiant
);
228 if(pkinst
->cp
->x1Minus
!= NULL
) {
229 set_priv_key_giant(pkinst
->minus
, pkinst
->privGiant
);
234 dbgLog(("Bad Existing Public Key\n"));
239 *** Public KeyString support.
242 * Init feePubKey from a public key string.
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.
247 feeReturn
feePubKeyInitFromKeyString(feePubKey pubKey
,
251 unsigned char *blob
= NULL
;
255 blob
= dec64((unsigned char *)keyStr
, keyStrLen
, &blobLen
);
257 dbgLog(("Bad Public Key String (not enc64)\n"));
258 return FR_BadPubKeyString
;
260 frtn
= feePubKeyInitFromKeyBlob(pubKey
, blob
, blobLen
);
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
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.
273 feeReturn
feePubKeyCreateKeyString(feePubKey pubKey
,
274 char **pubKeyString
, /* RETURNED */
275 unsigned *pubKeyStringLen
) /* RETURNED */
280 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
282 /* get binary pub blob, encode the blob, free the blob */
283 frtn
= createKeyBlob(pkinst
,
291 *pubKeyString
= (char *)enc64(blob
, blobLen
, pubKeyStringLen
);
297 *** Native key blob support.
300 #ifndef ECDSA_VERIFY_ONLY
303 * Obtain portable public and private key blobs from a key.
305 feeReturn
feePubKeyCreatePubBlob(feePubKey pubKey
,
306 unsigned char **keyBlob
, // mallocd and RETURNED
307 unsigned *keyBlobLen
) // RETURNED
309 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
311 return createKeyBlob(pkinst
,
317 feeReturn
feePubKeyCreatePrivBlob(feePubKey pubKey
,
318 unsigned char **keyBlob
, // mallocd and RETURNED
319 unsigned *keyBlobLen
) // RETURNED
321 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
323 if(pkinst
->privGiant
== NULL
) {
324 return FR_IncompatibleKey
;
326 return createKeyBlob(pkinst
,
333 * Given private-capable privKey, initialize pubKey to be its corresponding
336 feeReturn
feePubKeyInitPubKeyFromPriv(feePubKey privKey
,
339 pubKeyInst
*privInst
= (pubKeyInst
*)privKey
;
340 pubKeyInst
*pubInst
= (pubKeyInst
*)pubKey
;
342 if((privInst
== NULL
) || (pubInst
== NULL
)) {
345 if(privInst
->privGiant
== NULL
) {
346 return FR_IncompatibleKey
;
348 pubInst
->cp
= curveParamsCopy(privInst
->cp
);
349 if(pubInst
== NULL
) {
352 pubInst
->plus
= new_public_with_key(privInst
->plus
, pubInst
->cp
);
353 if(pubInst
->plus
== NULL
) {
356 if(pubInst
->cp
->x1Minus
!= NULL
) {
357 pubInst
->minus
= new_public_with_key(privInst
->minus
, pubInst
->cp
);
358 if(pubInst
->minus
== NULL
) {
365 #endif /* ECDSA_VERIFY_ONLY */
368 * Returns non-zero if two keys are equivalent.
370 int feePubKeyIsEqual(feePubKey key1
, feePubKey key2
)
372 pubKeyInst
*pkinst1
= (pubKeyInst
*) key1
;
373 pubKeyInst
*pkinst2
= (pubKeyInst
*) key2
;
375 if ((pkinst1
== NULL
) || (pkinst2
== NULL
)) {
378 if((pkinst1
->minus
!= NULL
) && (pkinst2
->minus
!= NULL
)) {
379 if(key_equal(pkinst1
->minus
, pkinst2
->minus
) == 0) {
383 if(key_equal(pkinst1
->plus
, pkinst2
->plus
) == 0) {
390 * Returns non-zero if key is private-capable (i.e., capable of signing
393 int feePubKeyIsPrivate(feePubKey key
)
395 pubKeyInst
*myPkinst
= (pubKeyInst
*)key
;
397 return ((myPkinst
->privGiant
!= NULL
) ? 1 : 0);
400 #pragma mark --- ECDH ---
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.
409 feeReturn
feePubKeyECDH(
411 /* one of the following two is non-NULL */
413 const unsigned char *pubKeyStr
,
414 unsigned pubKeyStrLen
,
415 /* output fmallocd and RETURNED here */
416 unsigned char **output
,
419 feePubKey theirPub
= pubKey
;
420 feeReturn frtn
= FR_Success
;
421 pubKeyInst
*privInst
= (pubKeyInst
*) privKey
;
423 if(privInst
->privGiant
== NULL
) {
424 dbgLog(("feePubKeyECDH: privKey not a private key\n"));
425 return FR_IncompatibleKey
;
428 if(theirPub
== NULL
) {
429 if(pubKeyStr
== NULL
) {
430 return FR_IllegalArg
;
433 /* Cook up a public key with the same curveParams as the private key */
435 frtn
= curveParamsDepth(privInst
->cp
, &depth
);
439 theirPub
= feePubKeyAlloc();
440 if(theirPub
== NULL
) {
443 frtn
= feePubKeyInitFromECDSAPubBlob(theirPub
, pubKeyStr
, pubKeyStrLen
, depth
);
449 pubKeyInst
*pubInst
= (pubKeyInst
*) theirPub
;
451 giant outputGiant
= make_pad(privInst
->privGiant
, pubInst
->plus
);
452 if(outputGiant
== NULL
) {
453 dbgLog(("feePubKeyECDH: make_pad error\n"));
457 *outputLen
= (privInst
->cp
->q
+ 7) / 8;
458 *output
= (unsigned char *)fmalloc(*outputLen
);
459 if(*output
== NULL
) {
463 serializeGiant(outputGiant
, *output
, *outputLen
);
464 freeGiant(outputGiant
);
467 if((pubKey
== NULL
) && (theirPub
!= NULL
)) {
468 feePubKeyFree(theirPub
);
473 #pragma mark --- feePubKey data accessors ---
475 unsigned feePubKeyBitsize(feePubKey pubKey
)
477 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
478 switch(pkinst
->cp
->primeType
) {
479 case FPT_General
: /* cp->q is here for just this purpose */
481 return pkinst
->cp
->q
;
482 case FPT_FEE
: /* could be larger or smaller than 2^q-1 */
484 return bitlen(pkinst
->cp
->basePrime
);
492 key
feePubKeyPlusCurve(feePubKey pubKey
)
494 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
499 key
feePubKeyMinusCurve(feePubKey pubKey
)
501 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
503 return pkinst
->minus
;
506 curveParams
*feePubKeyCurveParams(feePubKey pubKey
)
508 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
513 giant
feePubKeyPrivData(feePubKey pubKey
)
515 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
517 return pkinst
->privGiant
;
520 const char *feePubKeyAlgorithmName(void)
522 return "Elliptic Curve - FEE by Apple Computer";
525 #pragma mark --- Private functions ---
528 * alloc, free pubKeyInst
530 static pubKeyInst
*pubKeyInstAlloc(void)
532 pubKeyInst
*pkinst
= (pubKeyInst
*) fmalloc(sizeof(pubKeyInst
));
534 bzero(pkinst
, sizeof(pubKeyInst
));
538 static void pubKeyInstFree(pubKeyInst
*pkinst
)
541 free_key(pkinst
->minus
);
544 free_key(pkinst
->plus
);
547 freeCurveParams(pkinst
->cp
);
549 if(pkinst
->privGiant
) {
551 * Zero out the private data...
553 clearGiant(pkinst
->privGiant
);
554 freeGiant(pkinst
->privGiant
);
559 #ifndef ECDSA_VERIFY_ONLY
562 * Create a pubKeyInst.privGiant given a password of
564 * Currently, the only error is "private data too short" (FR_IllegalArg).
567 #define NO_PRIV_MUNGE 0 /* skip this step */
569 static feeReturn
feeGenPrivate(pubKeyInst
*pkinst
,
570 const unsigned char *passwd
,
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;
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
588 * generate privData which is just larger than the smaller
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
594 corder
= lesserX1Order(pkinst
->cp
);
595 CKASSERT(!isZero(corder
));
596 privLen
= (bitlen(corder
) / 8) + 1;
600 * Caller trusts the incoming entropy. Verify it's big enough and proceed.
602 if(passwdLen
< privLen
) {
603 return FR_ShortPrivData
;
606 privData
= (unsigned char *)passwd
;
610 return FR_IllegalArg
;
615 * Calculate how many MD5 digests we'll generate.
617 if(privLen
> passwdLen
) {
618 dataSize
= passwdLen
;
623 digestLen
= feeHashDigestLen();
624 numDigests
= (dataSize
+ digestLen
- 1) / digestLen
;
626 hash
= (void**) fmalloc(numDigests
* sizeof(feeHash
));
627 for(i
=0; i
<numDigests
; i
++) {
628 hash
[i
] = feeHashAlloc();
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.
636 cp
= (unsigned char *)passwd
;
638 for(i
=0; i
<numDigests
; i
++) {
639 if(i
== (numDigests
- 1)) { // last digest
640 toMove
= passwdLen
- moved
;
645 feeHashAddData(hash
[i
], cp
, toMove
);
651 * copy digests to privData, up to privLen bytes. Pad with
652 * additional copies of digests if necessary.
654 privData
= (unsigned char*) fmalloc(privLen
);
657 i
= 0; // digest number
658 for(moved
=0; moved
<privLen
; ) {
659 if((moved
+ digestLen
) > privLen
) {
660 toMove
= privLen
- moved
;
665 digest
= feeHashDigest(hash
[i
++]);
666 bcopy(digest
, cp
, toMove
);
669 if(i
== numDigests
) {
670 i
= 0; // wrap to 0, start padding
676 * Convert to giant, justify result to within [2, lesserX1Order]
678 pkinst
->privGiant
= giant_with_data(privData
, privLen
);
681 if(isZero(pkinst
->privGiant
)) {
682 printf("feeGenPrivate: privData = 0!\n");
686 lesserX1OrderJustify(pkinst
->privGiant
, pkinst
->cp
);
688 memset(privData
, 0, privLen
);
690 for(i
=0; i
<numDigests
; i
++) {
691 feeHashFree(hash
[i
]);
698 #endif /* ECDSA_VERIFY_ONLY */
702 void printPubKey(feePubKey pubKey
)
704 pubKeyInst
*pkinst
= pubKey
;
706 printf("\ncurveParams:\n");
707 printCurveParams(pkinst
->cp
);
709 printKey(pkinst
->plus
);
711 printKey(pkinst
->minus
);
712 if(pkinst
->privGiant
!= NULL
) {
713 printf("privGiant : ");
714 printGiant(pkinst
->privGiant
);
719 void printPubKey(feePubKey pubKey
) {}
723 #pragma mark --- Native (custom) key blob formatting ---
726 * Exported key blob support. New, 23 Mar 1998.
728 * Convert to public or private key blob.
731 #ifndef ECDSA_VERIFY_ONLY
734 *** Common native blob support
736 static feeReturn
createKeyBlob(pubKeyInst
*pkinst
,
737 int isPrivate
, // 0 : public 1 : private
738 unsigned char **keyBlob
, // mallocd and RETURNED
739 unsigned *keyBlobLen
) // RETURNED
741 unsigned char *s
; // running ptr into *origS
745 /* common blob elements */
746 sLen
= (4 * sizeof(int)) + // magic, version, minVersion,
748 lengthOfByteRepCurveParams(pkinst
->cp
);
751 sLen
+= lengthOfByteRepGiant(pkinst
->privGiant
);
752 magic
= PUBLIC_KEY_BLOB_MAGIC_PRIV
;
756 sLen
+= (lengthOfByteRepKey(pkinst
->plus
) +
757 lengthOfByteRepKey(pkinst
->minus
));
758 magic
= PUBLIC_KEY_BLOB_MAGIC_PUB
;
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
);
767 s
+= giantToByteRep(pkinst
->privGiant
, s
);
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
);
777 dbgLog(("work needed here for blobs with no minus key\n"));
784 #endif /* ECDSA_VERIFY_ONLY */
787 * Init an empty feePubKey from a native blob (non-DER format).
789 static feeReturn
feePubKeyInitFromKeyBlob(feePubKey pubKey
,
790 unsigned char *keyBlob
,
793 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
794 unsigned char *s
; // running pointer
795 unsigned sLen
; // bytes remaining in *s
797 unsigned len
; // for length of individual components
804 if(sLen
< (4 * sizeof(int))) { // magic, version, minVersion, spare
806 * Too short for all the ints we need
808 dbgLog(("feePublicKey: key blob (1)\n"));
809 return FR_BadKeyBlob
;
812 magic
= byteRepToInt(s
);
816 case PUBLIC_KEY_BLOB_MAGIC_PUB
:
819 case PUBLIC_KEY_BLOB_MAGIC_PRIV
:
823 dbgLog(("feePublicKey: Bad Public Key Magic Number\n"));
824 return FR_BadKeyBlob
;
828 * Switch on this for version-specific cases
830 version
= byteRepToInt(s
);
834 minVersion
= byteRepToInt(s
);
837 if(minVersion
> PUBLIC_KEY_BLOB_VERSION
) {
839 * old code, newer key blob - can't parse
841 dbgLog(("feePublicKey: Incompatible Public Key (1)\n"));
842 return FR_BadKeyBlob
;
845 s
+= sizeof(int); // skip spare
848 pkinst
->cp
= byteRepToCurveParams(s
, sLen
, &len
);
849 if(pkinst
->cp
== NULL
) {
850 dbgLog(("feePublicKey: Bad Key Blob(2)\n"));
851 return FR_BadKeyBlob
;
857 * Private key blob: privGiant.
858 * Public Key blob: plusX, minusX, plusY.
861 pkinst
->privGiant
= byteRepToGiant(s
, sLen
, &len
);
862 if(pkinst
->privGiant
== NULL
) {
863 dbgLog(("feePublicKey: Bad Key Blob(3)\n"));
864 return FR_BadKeyBlob
;
870 /* this writes x and y */
871 pkinst
->plus
= byteRepToKey(s
,
876 if(pkinst
->plus
== NULL
) {
877 dbgLog(("feePublicKey: Bad Key Blob(4)\n"));
878 return FR_BadKeyBlob
;
883 /* this only writes x */
884 pkinst
->minus
= byteRepToKey(s
,
886 CURVE_MINUS
, // twist
889 if(pkinst
->minus
== NULL
) {
890 dbgLog(("feePublicKey: Bad Key Blob(5)\n"));
891 return FR_BadKeyBlob
;
898 * One more thing: cook up public plusX and minusX for private key
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
);
911 feeReturn
feePubKeyInitFromPubBlob(feePubKey pubKey
,
912 unsigned char *keyBlob
,
915 return feePubKeyInitFromKeyBlob(pubKey
, keyBlob
, keyBlobLen
);
918 #ifndef ECDSA_VERIFY_ONLY
920 feeReturn
feePubKeyInitFromPrivBlob(feePubKey pubKey
,
921 unsigned char *keyBlob
,
924 return feePubKeyInitFromKeyBlob(pubKey
, keyBlob
, keyBlobLen
);
927 #endif /* ECDSA_VERIFY_ONLY */
929 #ifndef ECDSA_VERIFY_ONLY
932 * DER format support.
933 * Obtain portable public and private DER-encoded key blobs from a key.
935 feeReturn
feePubKeyCreateDERPubBlob(feePubKey pubKey
,
936 unsigned char **keyBlob
, // mallocd and RETURNED
937 unsigned *keyBlobLen
) // RETURNED
939 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
944 if(pkinst
->minus
== NULL
) {
945 /* Only ECDSA key formats supported */
946 return FR_IncompatibleKey
;
948 return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION
,
952 isZero(pkinst
->plus
->y
) ? NULL
: pkinst
->plus
->y
,
957 feeReturn
feePubKeyCreateDERPrivBlob(feePubKey pubKey
,
958 unsigned char **keyBlob
, // mallocd and RETURNED
959 unsigned *keyBlobLen
) // RETURNED
961 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
966 if(pkinst
->privGiant
== NULL
) {
967 return FR_IncompatibleKey
;
969 if(pkinst
->minus
== NULL
) {
970 /* Only ECDSA key formats supported */
971 return FR_IncompatibleKey
;
973 return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION
,
980 #endif /* ECDSA_VERIFY_ONLY */
983 * Init an empty feePubKey from a DER-encoded blob, public and private key versions.
985 feeReturn
feePubKeyInitFromDERPubBlob(feePubKey pubKey
,
986 unsigned char *keyBlob
,
989 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
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
)) {
1005 memset(pkinst
->plus
, 0, sizeof(keystruct
));
1006 memset(pkinst
->minus
, 0, sizeof(keystruct
));
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
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
;
1028 #ifndef ECDSA_VERIFY_ONLY
1030 feeReturn
feePubKeyInitFromDERPrivBlob(feePubKey pubKey
,
1031 unsigned char *keyBlob
,
1034 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1038 if(pkinst
== NULL
) {
1039 return FR_BadPubKey
;
1041 memset(pkinst
, 0, sizeof(pubKeyInst
));
1042 frtn
= feeDERDecodePrivateKey(keyBlob
,
1043 (unsigned)keyBlobLen
,
1044 &version
, // currently unused
1046 &pkinst
->privGiant
);
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
);
1059 #endif /* ECDSA_VERIFY_ONLY */
1061 #pragma mark --- X509 (public) and PKCS8 (private) key formatting ---
1063 feeReturn
feePubKeyCreateX509Blob(
1064 feePubKey pubKey
, // public key
1065 unsigned char **keyBlob
, // mallocd and RETURNED
1066 unsigned *keyBlobLen
) // RETURNED
1068 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1069 unsigned char *xyStr
= NULL
;
1070 unsigned xyStrLen
= 0;
1071 feeReturn frtn
= feeCreateECDSAPubBlob(pubKey
, &xyStr
, &xyStrLen
);
1075 frtn
= feeDEREncodeX509PublicKey(xyStr
, xyStrLen
, pkinst
->cp
, keyBlob
, keyBlobLen
);
1080 feeReturn
feePubKeyCreatePKCS8Blob(
1081 feePubKey pubKey
, // private key
1082 unsigned char **keyBlob
, // mallocd and RETURNED
1083 unsigned *keyBlobLen
) // RETURNED
1085 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1086 unsigned char *privStr
= NULL
;
1087 unsigned privStrLen
= 0;
1088 feeReturn frtn
= feeCreateECDSAPrivBlob(pubKey
, &privStr
, &privStrLen
);
1092 unsigned char *pubStr
= NULL
;
1093 unsigned pubStrLen
= 0;
1094 frtn
= feeCreateECDSAPubBlob(pubKey
, &pubStr
, &pubStrLen
);
1098 frtn
= feeDEREncodePKCS8PrivateKey(privStr
, privStrLen
,
1100 pkinst
->cp
, keyBlob
, keyBlobLen
);
1111 feeReturn
feePubKeyInitFromX509Blob(
1112 feePubKey pubKey
, // public key
1113 unsigned char *keyBlob
,
1117 unsigned char *xyStr
= NULL
;
1118 unsigned xyStrLen
= 0;
1120 /* obtain x/y and depth from X509 encoding */
1121 feeReturn frtn
= feeDERDecodeX509PublicKey(keyBlob
, (unsigned)keyBlobLen
, &depth
,
1127 frtn
= feePubKeyInitFromECDSAPubBlob(pubKey
, xyStr
, xyStrLen
, depth
);
1133 feeReturn
feePubKeyInitFromPKCS8Blob(
1134 feePubKey pubKey
, // private key
1135 unsigned char *keyBlob
,
1139 unsigned char *privStr
= NULL
;
1140 unsigned privStrLen
= 0;
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
);
1150 frtn
= feePubKeyInitFromECDSAPrivBlob(pubKey
, privStr
, privStrLen
, depth
);
1155 #pragma mark --- OpenSSL key formatting ---
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
1164 feeReturn
feePubKeyCreateOpenSSLBlob(
1165 feePubKey pubKey
, // private key
1166 unsigned char **keyBlob
, // mallocd and RETURNED
1167 unsigned *keyBlobLen
) // RETURNED
1169 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1170 unsigned char *privStr
= NULL
;
1171 unsigned privStrLen
= 0;
1172 feeReturn frtn
= feeCreateECDSAPrivBlob(pubKey
, &privStr
, &privStrLen
);
1176 unsigned char *pubStr
= NULL
;
1177 unsigned pubStrLen
= 0;
1178 frtn
= feeCreateECDSAPubBlob(pubKey
, &pubStr
, &pubStrLen
);
1182 frtn
= feeDEREncodeOpenSSLPrivateKey(privStr
, privStrLen
,
1184 pkinst
->cp
, keyBlob
, keyBlobLen
);
1195 feeReturn
feePubKeyInitFromOpenSSLBlob(
1196 feePubKey pubKey
, // private or public key
1198 unsigned char *keyBlob
,
1202 unsigned char *privStr
= NULL
;
1203 unsigned privStrLen
= 0;
1204 unsigned char *pubStr
= NULL
;
1205 unsigned pubStrLen
= 0;
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
);
1215 frtn
= feePubKeyInitFromECDSAPubBlob(pubKey
, pubStr
, pubStrLen
, depth
);
1218 frtn
= feePubKeyInitFromECDSAPrivBlob(pubKey
, privStr
, privStrLen
, depth
);
1230 * ANSI X9.62/Certicom key support.
1231 * Public key is 04 || x || y
1232 * Private key is privData per Certicom SEC1 C.4.
1234 feeReturn
feeCreateECDSAPubBlob(feePubKey pubKey
,
1235 unsigned char **keyBlob
,
1236 unsigned *keyBlobLen
)
1238 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1239 if(pkinst
== NULL
) {
1240 return FR_BadPubKey
;
1243 unsigned giantBytes
= (pkinst
->cp
->q
+ 7) / 8;
1244 unsigned blobSize
= 1 + (2 * giantBytes
);
1245 unsigned char *blob
= fmalloc(blobSize
);
1250 serializeGiant(pkinst
->plus
->x
, blob
+1, giantBytes
);
1251 serializeGiant(pkinst
->plus
->y
, blob
+1+giantBytes
, giantBytes
);
1253 *keyBlobLen
= blobSize
;
1257 feeReturn
feeCreateECDSAPrivBlob(feePubKey pubKey
,
1258 unsigned char **keyBlob
,
1259 unsigned *keyBlobLen
)
1261 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1262 if(pkinst
== NULL
) {
1263 return FR_BadPubKey
;
1265 if(pkinst
->privGiant
== NULL
) {
1266 return FR_IncompatibleKey
;
1270 * Return the raw private key bytes padded with zeroes in
1271 * the m.s. end to fill exactly one prime-size byte array.
1273 unsigned giantBytes
= (pkinst
->cp
->q
+ 7) / 8;
1274 unsigned char *blob
= fmalloc(giantBytes
);
1278 serializeGiant(pkinst
->privGiant
, blob
, giantBytes
);
1280 *keyBlobLen
= giantBytes
;
1284 /* Caller determines depth from other sources (e.g. AlgId.Params) */
1285 feeReturn
feePubKeyInitFromECDSAPubBlob(feePubKey pubKey
,
1286 const unsigned char *keyBlob
,
1287 unsigned keyBlobLen
,
1290 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1291 if(pkinst
== NULL
) {
1292 return FR_BadPubKey
;
1294 curveParams
*cp
= curveParamsForDepth(depth
);
1296 return FR_IllegalDepth
;
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
;
1304 if(*keyBlob
!= 0x04) {
1305 dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n"));
1306 return FR_BadKeyBlob
;
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
);
1316 feeReturn
feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey
,
1317 const unsigned char *keyBlob
,
1318 unsigned keyBlobLen
,
1321 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1322 if(pkinst
== NULL
) {
1323 return FR_BadPubKey
;
1325 curveParams
*cp
= curveParamsForDepth(depth
);
1327 return FR_IllegalDepth
;
1329 unsigned giantDigits
= cp
->basePrime
->sign
;
1330 unsigned giantBytes
= (cp
->q
+ 7) / 8;
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
;
1341 /* cook up a new private giant */
1342 pkinst
->privGiant
= newGiant(giantDigits
);
1343 if(pkinst
->privGiant
== NULL
) {
1346 deserializeGiant(keyBlob
, pkinst
->privGiant
, keyBlobLen
);
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
);