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"
65 #if CRYPTKIT_DER_ENABLE
66 #include "CryptKitDER.h"
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.
77 #define NULL ((void *)0)
81 * Magic number for a portable key blobs. Must be in sync with static
82 * final PUBLIC_KEY_STRING_MAGIC in JavaFee/PublicKey.java.
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
89 #if CRYPTKIT_DER_ENABLE
90 #define PUBLIC_DER_KEY_BLOB_VERSION 1
94 * Private data. All "instance" routines are passed a feePubKey (actually
95 * a void *) which is actually a pointer to one of these.
99 key minus
; // not needed for ECDSA
100 curveParams
*cp
; // common params shared by minus, plus
101 giant privGiant
; // private key
104 static feeReturn
feeGenPrivate(pubKeyInst
*pkinst
,
105 const unsigned char *passwd
,
108 static pubKeyInst
*pubKeyInstAlloc(void);
109 static void pubKeyInstFree(pubKeyInst
*pkinst
);
111 static void feePubKeyInitGiants(void);
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
);
121 #pragma mark --- General public API function ---
124 * Obatin a newly allocated feePubKey.
126 feePubKey
feePubKeyAlloc(void)
128 pubKeyInst
*pkinst
= pubKeyInstAlloc();
131 feePubKeyInitGiants();
136 void feePubKeyFree(feePubKey pubKey
)
138 pubKeyInstFree((pubKeyInst
*) pubKey
);
141 #ifndef ECDSA_VERIFY_ONLY
143 * Init feePubKey from private key data.
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" */
156 frtn
= feeKeyBitsToDepth(keyBits
, primeType
, curveType
, &depth
);
160 return feePubKeyInitFromPrivDataDepth(pubKey
,
167 feeReturn
feePubKeyInitFromPrivDataDepth(feePubKey pubKey
,
168 const unsigned char *privData
,
169 unsigned privDataLen
,
173 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
177 if(depth
!= FEE_DEPTH_127_1
) {
178 dbgLog(("Illegal Depth\n"));
179 return FR_IllegalDepth
;
181 #endif // ENGINE_127_BITS
182 if(depth
> FEE_DEPTH_MAX
) {
183 dbgLog(("Illegal Depth\n"));
184 return FR_IllegalDepth
;
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
);
192 /* else only usable for ECDSA */
194 frtn
= feeGenPrivate(pkinst
, privData
, privDataLen
, hashPrivData
);
198 set_priv_key_giant(pkinst
->plus
, pkinst
->privGiant
);
199 if(pkinst
->cp
->x1Minus
!= NULL
) {
200 set_priv_key_giant(pkinst
->minus
, pkinst
->privGiant
);
205 #endif /* ECDSA_VERIFY_ONLY */
208 * Init feePubKey from curve parameters matching existing oldKey.
210 feeReturn
feePubKeyInitFromKey(feePubKey pubKey
,
211 const unsigned char *privData
,
212 unsigned privDataLen
,
216 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
217 pubKeyInst
*oldInst
= (pubKeyInst
*) oldKey
;
221 dbgLog(("NULL existing key\n"));
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
) {
232 /* else this curve only usable for ECDSA */
234 pkinst
->plus
= new_public(pkinst
->cp
, CURVE_PLUS
);
235 if(pkinst
->plus
== NULL
) {
238 frtn
= feeGenPrivate(pkinst
, privData
, privDataLen
, hashPrivData
);
242 set_priv_key_giant(pkinst
->plus
, pkinst
->privGiant
);
243 if(pkinst
->cp
->x1Minus
!= NULL
) {
244 set_priv_key_giant(pkinst
->minus
, pkinst
->privGiant
);
249 dbgLog(("Bad Existing Public Key\n"));
254 *** Public KeyString support.
257 * Init feePubKey from a public key string.
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.
262 feeReturn
feePubKeyInitFromKeyString(feePubKey pubKey
,
266 unsigned char *blob
= NULL
;
270 blob
= dec64((unsigned char *)keyStr
, keyStrLen
, &blobLen
);
272 dbgLog(("Bad Public Key String (not enc64)\n"));
273 return FR_BadPubKeyString
;
275 frtn
= feePubKeyInitFromKeyBlob(pubKey
, blob
, blobLen
);
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
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.
288 feeReturn
feePubKeyCreateKeyString(feePubKey pubKey
,
289 char **pubKeyString
, /* RETURNED */
290 unsigned *pubKeyStringLen
) /* RETURNED */
295 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
297 /* get binary pub blob, encode the blob, free the blob */
298 frtn
= createKeyBlob(pkinst
,
306 *pubKeyString
= (char *)enc64(blob
, blobLen
, pubKeyStringLen
);
312 *** Native key blob support.
315 #ifndef ECDSA_VERIFY_ONLY
318 * Obtain portable public and private key blobs from a key.
320 feeReturn
feePubKeyCreatePubBlob(feePubKey pubKey
,
321 unsigned char **keyBlob
, // mallocd and RETURNED
322 unsigned *keyBlobLen
) // RETURNED
324 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
326 return createKeyBlob(pkinst
,
332 feeReturn
feePubKeyCreatePrivBlob(feePubKey pubKey
,
333 unsigned char **keyBlob
, // mallocd and RETURNED
334 unsigned *keyBlobLen
) // RETURNED
336 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
338 if(pkinst
->privGiant
== NULL
) {
339 return FR_IncompatibleKey
;
341 return createKeyBlob(pkinst
,
348 * Given private-capable privKey, initialize pubKey to be its corresponding
351 feeReturn
feePubKeyInitPubKeyFromPriv(feePubKey privKey
,
354 pubKeyInst
*privInst
= (pubKeyInst
*)privKey
;
355 pubKeyInst
*pubInst
= (pubKeyInst
*)pubKey
;
357 if((privInst
== NULL
) || (pubInst
== NULL
)) {
360 if(privInst
->privGiant
== NULL
) {
361 return FR_IncompatibleKey
;
363 pubInst
->cp
= curveParamsCopy(privInst
->cp
);
364 if(pubInst
== NULL
) {
367 pubInst
->plus
= new_public_with_key(privInst
->plus
, pubInst
->cp
);
368 if(pubInst
->plus
== NULL
) {
371 if(pubInst
->cp
->x1Minus
!= NULL
) {
372 pubInst
->minus
= new_public_with_key(privInst
->minus
, pubInst
->cp
);
373 if(pubInst
->minus
== NULL
) {
380 #endif /* ECDSA_VERIFY_ONLY */
383 * Returns non-zero if two keys are equivalent.
385 int feePubKeyIsEqual(feePubKey key1
, feePubKey key2
)
387 pubKeyInst
*pkinst1
= (pubKeyInst
*) key1
;
388 pubKeyInst
*pkinst2
= (pubKeyInst
*) key2
;
390 if ((pkinst1
== NULL
) || (pkinst2
== NULL
)) {
393 if((pkinst1
->minus
!= NULL
) && (pkinst2
->minus
!= NULL
)) {
394 if(key_equal(pkinst1
->minus
, pkinst2
->minus
) == 0) {
398 if(key_equal(pkinst1
->plus
, pkinst2
->plus
) == 0) {
405 * Returns non-zero if key is private-capable (i.e., capable of signing
408 int feePubKeyIsPrivate(feePubKey key
)
410 pubKeyInst
*myPkinst
= (pubKeyInst
*)key
;
412 return ((myPkinst
->privGiant
!= NULL
) ? 1 : 0);
415 #ifndef ECDSA_VERIFY_ONLY
417 #if CRYPTKIT_KEY_EXCHANGE
419 feeReturn
feePubKeyCreatePad(feePubKey myKey
,
421 unsigned char **padData
, /* RETURNED */
422 unsigned *padDataLen
) /* RETURNED padData length in bytes */
424 pubKeyInst
*myPkinst
= (pubKeyInst
*) myKey
;
425 pubKeyInst
*theirPkinst
= (pubKeyInst
*) theirKey
;
427 unsigned char *result
;
432 * Do some compatibility checking (myKey, theirKey) here...?
434 if(DEFAULT_CURVE
== CURVE_PLUS
) {
435 pkey
= theirPkinst
->plus
;
438 pkey
= theirPkinst
->minus
;
440 pad
= make_pad(myPkinst
->privGiant
, pkey
);
441 result
= mem_from_giant(pad
, &padLen
);
445 * Ensure we have a the minimum necessary for DES. A bit of a hack,
448 if(padLen
>= FEE_DES_MIN_STATE_SIZE
) {
450 *padDataLen
= padLen
;
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
);
462 #endif /* CRYPTKIT_KEY_EXCHANGE */
464 #if CRYPTKIT_HIGH_LEVEL_SIG
468 * Generate digital signature, ElGamal style.
470 feeReturn
feePubKeyCreateSignature(feePubKey pubKey
,
471 const unsigned char *data
,
473 unsigned char **signature
, /* fmalloc'd and RETURNED */
474 unsigned *signatureLen
) /* RETURNED */
476 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
479 unsigned char *Pm
= NULL
;
483 if(pkinst
->privGiant
== NULL
) {
484 dbgLog(("feePubKeyCreateSignature: Attempt to Sign without"
488 hash
= feeHashAlloc();
489 sig
= feeSigNewWithKey(pubKey
, NULL
, NULL
);
492 * Shouldn't happen, but...
499 * Get Pm to salt hash object
501 Pm
= feeSigPm(sig
, &PmLen
);
502 feeHashAddData(hash
, Pm
, PmLen
);
505 * Now hash the data proper, then sign the hash
507 feeHashAddData(hash
, data
, dataLen
);
508 frtn
= feeSigSign(sig
,
512 if(frtn
== FR_Success
) {
513 frtn
= feeSigData(sig
, signature
, signatureLen
);
522 * Verify digital signature, ElGamal style. If the signature is ECDSA,
523 * we'll use that format for compatibility.
525 feeReturn
feePubKeyVerifySignature(feePubKey pubKey
,
526 const unsigned char *data
,
528 const unsigned char *signature
,
529 unsigned signatureLen
)
533 unsigned char *Pm
= NULL
;
537 hash
= feeHashAlloc();
538 frtn
= feeSigParse(signature
, signatureLen
, &sig
);
541 #if CRYPTKIT_ECDSA_ENABLE
542 if(frtn
== FR_WrongSignatureType
) {
543 return feePubKeyVerifyECDSASignature(pubKey
,
549 #endif /* CRYPTKIT_ECDSA_ENABLE */
554 * Get PM as salt; eat salt, then hash data
556 Pm
= feeSigPm(sig
, &PmLen
);
557 feeHashAddData(hash
, Pm
, PmLen
);
558 feeHashAddData(hash
, data
, dataLen
);
559 frtn
= feeSigVerify(sig
,
570 #pragma mark --- ECDSA signature: high level routines ---
572 #if CRYPTKIT_ECDSA_ENABLE
574 * Generate digital signature, ECDSA style.
576 feeReturn
feePubKeyCreateECDSASignature(feePubKey pubKey
,
577 const unsigned char *data
,
579 unsigned char **signature
, /* fmalloc'd and RETURNED */
580 unsigned *signatureLen
) /* RETURNED */
582 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
586 if(pkinst
->privGiant
== NULL
) {
587 dbgLog(("feePubKeyCreateECDSASignature: Attempt to Sign "
588 "without private data\n"));
592 sha1AddData(sha1
, data
, dataLen
);
593 frtn
= feeECDSASign(pubKey
,
603 #endif /* CRYPTKIT_ECDSA_ENABLE */
604 #endif /* CRYPTKIT_HIGH_LEVEL_SIG */
605 #endif /* ECDSA_VERIFY_ONLY */
607 #if CRYPTKIT_HIGH_LEVEL_SIG
609 #if CRYPTKIT_ECDSA_ENABLE
612 * Verify digital signature, ECDSA style.
614 feeReturn
feePubKeyVerifyECDSASignature(feePubKey pubKey
,
615 const unsigned char *data
,
617 const unsigned char *signature
,
618 unsigned signatureLen
)
624 sha1AddData(sha1
, data
, dataLen
);
625 frtn
= feeECDSAVerify(signature
,
634 #endif /* CRYPTKIT_ECDSA_ENABLE */
636 #endif /* CRYPTKIT_HIGH_LEVEL_SIG */
638 #pragma mark --- ECDH ---
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.
647 feeReturn
feePubKeyECDH(
649 /* one of the following two is non-NULL */
651 const unsigned char *pubKeyStr
,
652 unsigned pubKeyStrLen
,
653 /* output fmallocd and RETURNED here */
654 unsigned char **output
,
657 feePubKey theirPub
= pubKey
;
658 feeReturn frtn
= FR_Success
;
659 pubKeyInst
*privInst
= (pubKeyInst
*) privKey
;
661 if(privInst
->privGiant
== NULL
) {
662 dbgLog(("feePubKeyECDH: privKey not a private key\n"));
663 return FR_IncompatibleKey
;
666 if(theirPub
== NULL
) {
667 if(pubKeyStr
== NULL
) {
668 return FR_IllegalArg
;
671 /* Cook up a public key with the same curveParams as the private key */
673 frtn
= curveParamsDepth(privInst
->cp
, &depth
);
677 theirPub
= feePubKeyAlloc();
678 if(theirPub
== NULL
) {
681 frtn
= feePubKeyInitFromECDSAPubBlob(theirPub
, pubKeyStr
, pubKeyStrLen
, depth
);
687 pubKeyInst
*pubInst
= (pubKeyInst
*) theirPub
;
689 giant outputGiant
= make_pad(privInst
->privGiant
, pubInst
->plus
);
690 if(outputGiant
== NULL
) {
691 dbgLog(("feePubKeyECDH: make_pad error\n"));
695 *outputLen
= (privInst
->cp
->q
+ 7) / 8;
696 *output
= (unsigned char *)fmalloc(*outputLen
);
697 if(*output
== NULL
) {
701 serializeGiant(outputGiant
, *output
, *outputLen
);
702 freeGiant(outputGiant
);
705 if((pubKey
== NULL
) && (theirPub
!= NULL
)) {
706 feePubKeyFree(theirPub
);
711 #pragma mark --- feePubKey data accessors ---
713 unsigned feePubKeyBitsize(feePubKey pubKey
)
715 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
716 switch(pkinst
->cp
->primeType
) {
717 case FPT_General
: /* cp->q is here for just this purpose */
719 return pkinst
->cp
->q
;
720 case FPT_FEE
: /* could be larger or smaller than 2^q-1 */
722 return bitlen(pkinst
->cp
->basePrime
);
730 key
feePubKeyPlusCurve(feePubKey pubKey
)
732 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
737 key
feePubKeyMinusCurve(feePubKey pubKey
)
739 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
741 return pkinst
->minus
;
744 curveParams
*feePubKeyCurveParams(feePubKey pubKey
)
746 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
751 giant
feePubKeyPrivData(feePubKey pubKey
)
753 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
755 return pkinst
->privGiant
;
758 const char *feePubKeyAlgorithmName(void)
760 return "Elliptic Curve - FEE by Apple Computer";
763 #pragma mark --- Private functions ---
766 * alloc, free pubKeyInst
768 static pubKeyInst
*pubKeyInstAlloc(void)
770 pubKeyInst
*pkinst
= (pubKeyInst
*) fmalloc(sizeof(pubKeyInst
));
772 bzero(pkinst
, sizeof(pubKeyInst
));
776 static void pubKeyInstFree(pubKeyInst
*pkinst
)
779 free_key(pkinst
->minus
);
782 free_key(pkinst
->plus
);
785 freeCurveParams(pkinst
->cp
);
787 if(pkinst
->privGiant
) {
789 * Zero out the private data...
791 clearGiant(pkinst
->privGiant
);
792 freeGiant(pkinst
->privGiant
);
797 #ifndef ECDSA_VERIFY_ONLY
800 * Create a pubKeyInst.privGiant given a password of
802 * Currently, the only error is "private data too short" (FR_IllegalArg).
805 #define NO_PRIV_MUNGE 0 /* skip this step */
807 static feeReturn
feeGenPrivate(pubKeyInst
*pkinst
,
808 const unsigned char *passwd
,
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;
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
826 * generate privData which is just larger than the smaller
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
832 corder
= lesserX1Order(pkinst
->cp
);
833 CKASSERT(!isZero(corder
));
834 privLen
= (bitlen(corder
) / 8) + 1;
838 * Caller trusts the incoming entropy. Verify it's big enough and proceed.
840 if(passwdLen
< privLen
) {
841 return FR_ShortPrivData
;
844 privData
= (unsigned char *)passwd
;
848 return FR_IllegalArg
;
853 * Calculate how many MD5 digests we'll generate.
855 if(privLen
> passwdLen
) {
856 dataSize
= passwdLen
;
861 digestLen
= feeHashDigestLen();
862 numDigests
= (dataSize
+ digestLen
- 1) / digestLen
;
864 hash
= (void**) fmalloc(numDigests
* sizeof(feeHash
));
865 for(i
=0; i
<numDigests
; i
++) {
866 hash
[i
] = feeHashAlloc();
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.
874 cp
= (unsigned char *)passwd
;
876 for(i
=0; i
<numDigests
; i
++) {
877 if(i
== (numDigests
- 1)) { // last digest
878 toMove
= passwdLen
- moved
;
883 feeHashAddData(hash
[i
], cp
, toMove
);
889 * copy digests to privData, up to privLen bytes. Pad with
890 * additional copies of digests if necessary.
892 privData
= (unsigned char*) fmalloc(privLen
);
895 i
= 0; // digest number
896 for(moved
=0; moved
<privLen
; ) {
897 if((moved
+ digestLen
) > privLen
) {
898 toMove
= privLen
- moved
;
903 digest
= feeHashDigest(hash
[i
++]);
904 bcopy(digest
, cp
, toMove
);
907 if(i
== numDigests
) {
908 i
= 0; // wrap to 0, start padding
914 * Convert to giant, justify result to within [2, lesserX1Order]
916 pkinst
->privGiant
= giant_with_data(privData
, privLen
);
919 if(isZero(pkinst
->privGiant
)) {
920 printf("feeGenPrivate: privData = 0!\n");
924 lesserX1OrderJustify(pkinst
->privGiant
, pkinst
->cp
);
926 memset(privData
, 0, privLen
);
928 for(i
=0; i
<numDigests
; i
++) {
929 feeHashFree(hash
[i
]);
936 #endif /* ECDSA_VERIFY_ONLY */
940 void printPubKey(feePubKey pubKey
)
942 pubKeyInst
*pkinst
= pubKey
;
944 printf("\ncurveParams:\n");
945 printCurveParams(pkinst
->cp
);
947 printKey(pkinst
->plus
);
949 printKey(pkinst
->minus
);
950 if(pkinst
->privGiant
!= NULL
) {
951 printf("privGiant : ");
952 printGiant(pkinst
->privGiant
);
957 void printPubKey(feePubKey pubKey
) {}
961 * Prime the curveParams and giants modules for quick allocs of giants.
965 static int giantsInitd
= 0;
967 static void feePubKeyInitGiants(void)
972 curveParamsInitGiants();
977 #pragma mark --- Native (custom) key blob formatting ---
980 * Exported key blob support. New, 23 Mar 1998.
982 * Convert to public or private key blob.
985 #ifndef ECDSA_VERIFY_ONLY
988 *** Common native blob support
990 static feeReturn
createKeyBlob(pubKeyInst
*pkinst
,
991 int isPrivate
, // 0 : public 1 : private
992 unsigned char **keyBlob
, // mallocd and RETURNED
993 unsigned *keyBlobLen
) // RETURNED
995 unsigned char *s
; // running ptr into *origS
999 /* common blob elements */
1000 sLen
= (4 * sizeof(int)) + // magic, version, minVersion,
1002 lengthOfByteRepCurveParams(pkinst
->cp
);
1005 sLen
+= lengthOfByteRepGiant(pkinst
->privGiant
);
1006 magic
= PUBLIC_KEY_BLOB_MAGIC_PRIV
;
1010 sLen
+= (lengthOfByteRepKey(pkinst
->plus
) +
1011 lengthOfByteRepKey(pkinst
->minus
));
1012 magic
= PUBLIC_KEY_BLOB_MAGIC_PUB
;
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
);
1021 s
+= giantToByteRep(pkinst
->privGiant
, s
);
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
);
1031 dbgLog(("work needed here for blobs with no minus key\n"));
1038 #endif /* ECDSA_VERIFY_ONLY */
1041 * Init an empty feePubKey from a native blob (non-DER format).
1043 static feeReturn
feePubKeyInitFromKeyBlob(feePubKey pubKey
,
1044 unsigned char *keyBlob
,
1045 unsigned keyBlobLen
)
1047 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1048 unsigned char *s
; // running pointer
1049 unsigned sLen
; // bytes remaining in *s
1051 unsigned len
; // for length of individual components
1058 if(sLen
< (4 * sizeof(int))) { // magic, version, minVersion, spare
1060 * Too short for all the ints we need
1062 dbgLog(("feePublicKey: key blob (1)\n"));
1063 return FR_BadKeyBlob
;
1066 magic
= byteRepToInt(s
);
1068 sLen
-= sizeof(int);
1070 case PUBLIC_KEY_BLOB_MAGIC_PUB
:
1073 case PUBLIC_KEY_BLOB_MAGIC_PRIV
:
1077 dbgLog(("feePublicKey: Bad Public Key Magic Number\n"));
1078 return FR_BadKeyBlob
;
1082 * Switch on this for version-specific cases
1084 version
= byteRepToInt(s
);
1086 sLen
-= sizeof(int);
1088 minVersion
= byteRepToInt(s
);
1090 sLen
-= sizeof(int);
1091 if(minVersion
> PUBLIC_KEY_BLOB_VERSION
) {
1093 * old code, newer key blob - can't parse
1095 dbgLog(("feePublicKey: Incompatible Public Key (1)\n"));
1096 return FR_BadKeyBlob
;
1099 s
+= sizeof(int); // skip spare
1100 sLen
-= sizeof(int);
1102 pkinst
->cp
= byteRepToCurveParams(s
, sLen
, &len
);
1103 if(pkinst
->cp
== NULL
) {
1104 dbgLog(("feePublicKey: Bad Key Blob(2)\n"));
1105 return FR_BadKeyBlob
;
1111 * Private key blob: privGiant.
1112 * Public Key blob: plusX, minusX, plusY.
1115 pkinst
->privGiant
= byteRepToGiant(s
, sLen
, &len
);
1116 if(pkinst
->privGiant
== NULL
) {
1117 dbgLog(("feePublicKey: Bad Key Blob(3)\n"));
1118 return FR_BadKeyBlob
;
1124 /* this writes x and y */
1125 pkinst
->plus
= byteRepToKey(s
,
1127 CURVE_PLUS
, // twist
1130 if(pkinst
->plus
== NULL
) {
1131 dbgLog(("feePublicKey: Bad Key Blob(4)\n"));
1132 return FR_BadKeyBlob
;
1137 /* this only writes x */
1138 pkinst
->minus
= byteRepToKey(s
,
1140 CURVE_MINUS
, // twist
1143 if(pkinst
->minus
== NULL
) {
1144 dbgLog(("feePublicKey: Bad Key Blob(5)\n"));
1145 return FR_BadKeyBlob
;
1152 * One more thing: cook up public plusX and minusX for private key
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
);
1165 feeReturn
feePubKeyInitFromPubBlob(feePubKey pubKey
,
1166 unsigned char *keyBlob
,
1167 unsigned keyBlobLen
)
1169 return feePubKeyInitFromKeyBlob(pubKey
, keyBlob
, keyBlobLen
);
1172 #ifndef ECDSA_VERIFY_ONLY
1174 feeReturn
feePubKeyInitFromPrivBlob(feePubKey pubKey
,
1175 unsigned char *keyBlob
,
1176 unsigned keyBlobLen
)
1178 return feePubKeyInitFromKeyBlob(pubKey
, keyBlob
, keyBlobLen
);
1181 #endif /* ECDSA_VERIFY_ONLY */
1183 #if CRYPTKIT_DER_ENABLE
1184 #ifndef ECDSA_VERIFY_ONLY
1187 * DER format support.
1188 * Obtain portable public and private DER-encoded key blobs from a key.
1190 feeReturn
feePubKeyCreateDERPubBlob(feePubKey pubKey
,
1191 unsigned char **keyBlob
, // mallocd and RETURNED
1192 unsigned *keyBlobLen
) // RETURNED
1194 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1196 if(pkinst
== NULL
) {
1197 return FR_BadPubKey
;
1199 if(pkinst
->minus
== NULL
) {
1200 /* Only ECDSA key formats supported */
1201 return FR_IncompatibleKey
;
1203 return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION
,
1207 isZero(pkinst
->plus
->y
) ? NULL
: pkinst
->plus
->y
,
1212 feeReturn
feePubKeyCreateDERPrivBlob(feePubKey pubKey
,
1213 unsigned char **keyBlob
, // mallocd and RETURNED
1214 unsigned *keyBlobLen
) // RETURNED
1216 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1218 if(pkinst
== NULL
) {
1219 return FR_BadPubKey
;
1221 if(pkinst
->privGiant
== NULL
) {
1222 return FR_IncompatibleKey
;
1224 if(pkinst
->minus
== NULL
) {
1225 /* Only ECDSA key formats supported */
1226 return FR_IncompatibleKey
;
1228 return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION
,
1235 #endif /* ECDSA_VERIFY_ONLY */
1238 * Init an empty feePubKey from a DER-encoded blob, public and private key versions.
1240 feeReturn
feePubKeyInitFromDERPubBlob(feePubKey pubKey
,
1241 unsigned char *keyBlob
,
1244 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1248 if(pkinst
== NULL
) {
1249 return FR_BadPubKey
;
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
)) {
1260 memset(pkinst
->plus
, 0, sizeof(keystruct
));
1261 memset(pkinst
->minus
, 0, sizeof(keystruct
));
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
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
;
1283 #ifndef ECDSA_VERIFY_ONLY
1285 feeReturn
feePubKeyInitFromDERPrivBlob(feePubKey pubKey
,
1286 unsigned char *keyBlob
,
1289 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1293 if(pkinst
== NULL
) {
1294 return FR_BadPubKey
;
1296 memset(pkinst
, 0, sizeof(pubKeyInst
));
1297 frtn
= feeDERDecodePrivateKey(keyBlob
,
1298 (unsigned)keyBlobLen
,
1299 &version
, // currently unused
1301 &pkinst
->privGiant
);
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
);
1314 #endif /* ECDSA_VERIFY_ONLY */
1316 #pragma mark --- X509 (public) and PKCS8 (private) key formatting ---
1318 feeReturn
feePubKeyCreateX509Blob(
1319 feePubKey pubKey
, // public key
1320 unsigned char **keyBlob
, // mallocd and RETURNED
1321 unsigned *keyBlobLen
) // RETURNED
1323 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1324 unsigned char *xyStr
= NULL
;
1325 unsigned xyStrLen
= 0;
1326 feeReturn frtn
= feeCreateECDSAPubBlob(pubKey
, &xyStr
, &xyStrLen
);
1330 frtn
= feeDEREncodeX509PublicKey(xyStr
, xyStrLen
, pkinst
->cp
, keyBlob
, keyBlobLen
);
1335 feeReturn
feePubKeyCreatePKCS8Blob(
1336 feePubKey pubKey
, // private key
1337 unsigned char **keyBlob
, // mallocd and RETURNED
1338 unsigned *keyBlobLen
) // RETURNED
1340 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1341 unsigned char *privStr
= NULL
;
1342 unsigned privStrLen
= 0;
1343 feeReturn frtn
= feeCreateECDSAPrivBlob(pubKey
, &privStr
, &privStrLen
);
1347 unsigned char *pubStr
= NULL
;
1348 unsigned pubStrLen
= 0;
1349 frtn
= feeCreateECDSAPubBlob(pubKey
, &pubStr
, &pubStrLen
);
1353 frtn
= feeDEREncodePKCS8PrivateKey(privStr
, privStrLen
,
1355 pkinst
->cp
, keyBlob
, keyBlobLen
);
1366 feeReturn
feePubKeyInitFromX509Blob(
1367 feePubKey pubKey
, // public key
1368 unsigned char *keyBlob
,
1372 unsigned char *xyStr
= NULL
;
1373 unsigned xyStrLen
= 0;
1375 /* obtain x/y and depth from X509 encoding */
1376 feeReturn frtn
= feeDERDecodeX509PublicKey(keyBlob
, (unsigned)keyBlobLen
, &depth
,
1382 frtn
= feePubKeyInitFromECDSAPubBlob(pubKey
, xyStr
, xyStrLen
, depth
);
1388 feeReturn
feePubKeyInitFromPKCS8Blob(
1389 feePubKey pubKey
, // private key
1390 unsigned char *keyBlob
,
1394 unsigned char *privStr
= NULL
;
1395 unsigned privStrLen
= 0;
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
);
1405 frtn
= feePubKeyInitFromECDSAPrivBlob(pubKey
, privStr
, privStrLen
, depth
);
1410 #pragma mark --- OpenSSL key formatting ---
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
1419 feeReturn
feePubKeyCreateOpenSSLBlob(
1420 feePubKey pubKey
, // private key
1421 unsigned char **keyBlob
, // mallocd and RETURNED
1422 unsigned *keyBlobLen
) // RETURNED
1424 pubKeyInst
*pkinst
= (pubKeyInst
*) pubKey
;
1425 unsigned char *privStr
= NULL
;
1426 unsigned privStrLen
= 0;
1427 feeReturn frtn
= feeCreateECDSAPrivBlob(pubKey
, &privStr
, &privStrLen
);
1431 unsigned char *pubStr
= NULL
;
1432 unsigned pubStrLen
= 0;
1433 frtn
= feeCreateECDSAPubBlob(pubKey
, &pubStr
, &pubStrLen
);
1437 frtn
= feeDEREncodeOpenSSLPrivateKey(privStr
, privStrLen
,
1439 pkinst
->cp
, keyBlob
, keyBlobLen
);
1450 feeReturn
feePubKeyInitFromOpenSSLBlob(
1451 feePubKey pubKey
, // private or public key
1453 unsigned char *keyBlob
,
1457 unsigned char *privStr
= NULL
;
1458 unsigned privStrLen
= 0;
1459 unsigned char *pubStr
= NULL
;
1460 unsigned pubStrLen
= 0;
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
);
1470 frtn
= feePubKeyInitFromECDSAPubBlob(pubKey
, pubStr
, pubStrLen
, depth
);
1473 frtn
= feePubKeyInitFromECDSAPrivBlob(pubKey
, privStr
, privStrLen
, depth
);
1484 #endif /* CRYPTKIT_DER_ENABLE */
1487 * ANSI X9.62/Certicom key support.
1488 * Public key is 04 || x || y
1489 * Private key is privData per Certicom SEC1 C.4.
1491 feeReturn
feeCreateECDSAPubBlob(feePubKey pubKey
,
1492 unsigned char **keyBlob
,
1493 unsigned *keyBlobLen
)
1495 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1496 if(pkinst
== NULL
) {
1497 return FR_BadPubKey
;
1500 unsigned giantBytes
= (pkinst
->cp
->q
+ 7) / 8;
1501 unsigned blobSize
= 1 + (2 * giantBytes
);
1502 unsigned char *blob
= fmalloc(blobSize
);
1507 serializeGiant(pkinst
->plus
->x
, blob
+1, giantBytes
);
1508 serializeGiant(pkinst
->plus
->y
, blob
+1+giantBytes
, giantBytes
);
1510 *keyBlobLen
= blobSize
;
1514 feeReturn
feeCreateECDSAPrivBlob(feePubKey pubKey
,
1515 unsigned char **keyBlob
,
1516 unsigned *keyBlobLen
)
1518 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1519 if(pkinst
== NULL
) {
1520 return FR_BadPubKey
;
1522 if(pkinst
->privGiant
== NULL
) {
1523 return FR_IncompatibleKey
;
1527 * Return the raw private key bytes padded with zeroes in
1528 * the m.s. end to fill exactly one prime-size byte array.
1530 unsigned giantBytes
= (pkinst
->cp
->q
+ 7) / 8;
1531 unsigned char *blob
= fmalloc(giantBytes
);
1535 serializeGiant(pkinst
->privGiant
, blob
, giantBytes
);
1537 *keyBlobLen
= giantBytes
;
1541 /* Caller determines depth from other sources (e.g. AlgId.Params) */
1542 feeReturn
feePubKeyInitFromECDSAPubBlob(feePubKey pubKey
,
1543 const unsigned char *keyBlob
,
1544 unsigned keyBlobLen
,
1547 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1548 if(pkinst
== NULL
) {
1549 return FR_BadPubKey
;
1551 curveParams
*cp
= curveParamsForDepth(depth
);
1553 return FR_IllegalDepth
;
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
;
1561 if(*keyBlob
!= 0x04) {
1562 dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n"));
1563 return FR_BadKeyBlob
;
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
);
1573 feeReturn
feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey
,
1574 const unsigned char *keyBlob
,
1575 unsigned keyBlobLen
,
1578 pubKeyInst
*pkinst
= (pubKeyInst
*)pubKey
;
1579 if(pkinst
== NULL
) {
1580 return FR_BadPubKey
;
1582 curveParams
*cp
= curveParamsForDepth(depth
);
1584 return FR_IllegalDepth
;
1586 unsigned giantDigits
= cp
->basePrime
->sign
;
1587 unsigned giantBytes
= (cp
->q
+ 7) / 8;
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
;
1598 /* cook up a new private giant */
1599 pkinst
->privGiant
= newGiant(giantDigits
);
1600 if(pkinst
->privGiant
== NULL
) {
1603 deserializeGiant(keyBlob
, pkinst
->privGiant
, keyBlobLen
);
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
);