2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 * CryptKitDER.h - snacc-based routines to create and parse DER-encoded FEE
23 * Created 3/12/2001 by dmitch.
26 #ifdef CRYPTKIT_CSP_ENABLE
28 #include <Security/asn-incl.h>
29 #include <Security/sm_vdatypes.h>
30 #include <CryptKit/CryptKitDER.h>
31 #include <CryptKit/falloc.h>
32 #include <CryptKit/feeDebug.h>
33 #include <CryptKit/feeFunctions.h>
34 #include <Security/cdsaUtils.h>
35 #include <Security/appleoids.h>
37 #define PRINT_SIG_GIANTS 0
38 #define PRINT_CURVE_PARAMS 0
41 #define szprint(s) printf s
47 * Trivial exception class associated with a feeReturn.
52 feeException(feeReturn frtn
, const char *op
);
55 feeReturn
frtn() { return mFrtn
; }
56 static void throwMe(feeReturn frtn
, const char *op
= NULL
) __attribute__((noreturn
));
61 feeException::feeException(
67 dbgLog(("%s: %s\n", op
, feeReturnString(frtn
)));
71 void feeException::throwMe(feeReturn frtn
, const char *op
= NULL
) { throw feeException(frtn
, op
); }
74 * ASN1 encoding rules specify that an integer's sign is indicated by the MSB
75 * of the first (MS) content byte. For a non-negative number, if the MSB of
76 * the MS byte (of the unencoded number) is one, then the encoding starts with
77 * a byte of zeroes to indicate positive sign. For a negative number, the first
78 * nine bits can not be all 1 - if they are (in the undecoded number), leading
79 * bytes of 0xff are trimmed off until the first nine bits are something other
80 * than one. Also, the first nine bits of the encoded number can not all be
83 * CryptKit giants express their sign as part of the giantstruct.sign field.
84 * The giantDigit array (giantstruct.n[]) is stored l.s. digit first.
86 * These routines are independent of platform, endianness, and giatn digit size.
89 /* routines to guess maximum size of DER-encoded objects */
90 static unsigned feeSizeOfSnaccGiant(
93 unsigned rtn
= abs(g
->sign
) * GIANT_BYTES_PER_DIGIT
;
94 szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g
->sign
, rtn
+ 4));
98 static unsigned feeSizeofSnaccInt()
104 unsigned feeSizeOfDERSig(
108 unsigned rtn
= feeSizeOfSnaccGiant(g1
);
109 rtn
+= feeSizeOfSnaccGiant(g2
);
110 szprint(("feeSizeOfDERSig: size %d\n", rtn
+ 4));
114 static unsigned feeSizeofSnaccCurveParams(const curveParams
*cp
)
116 unsigned rtn
= 5 * feeSizeofSnaccInt(); // primeType, curveType, q, k, m
117 rtn
+= 10 * feeSizeOfSnaccGiant(cp
->basePrime
);
118 szprint(("feeSizeofSnaccCurveParams: size %d\n", rtn
));
122 static unsigned feeSizeOfSnaccPubKey(const curveParams
*cp
)
124 unsigned rtn
= 11; // version plus sequence overhead
125 rtn
+= feeSizeofSnaccCurveParams(cp
);
126 rtn
+= (3 * feeSizeOfSnaccGiant(cp
->basePrime
));
127 szprint(("feeSizeOfSnaccPubKey: size %d\n", rtn
));
131 static unsigned feeSizeOfSnaccPrivKey(const curveParams
*cp
)
133 unsigned rtn
= 11; // version plus sequence overhead
134 rtn
+= feeSizeofSnaccCurveParams(cp
);
135 rtn
+= feeSizeOfSnaccGiant(cp
->basePrime
);
136 szprint(("feeSizeOfSnaccPrivKey: size %d\n", rtn
));
140 /* perform 2's complement of byte array, expressed MS byte first */
141 static void twosComplement(
142 unsigned char *bytePtr
, // points to MS byte
145 unsigned char *outp
= bytePtr
+ numBytes
- 1;
146 unsigned char carry
= 1; // first time thru, carry = 1 to add one to 1's comp
147 for(unsigned byteDex
=0; byteDex
<numBytes
; byteDex
++) {
148 /* first complement, then add carry */
149 *outp
= ~*outp
+ carry
;
150 if(carry
&& (*outp
== 0)) {
162 * Convert a BigIntegerStr to a (mallocd) giant.
163 * Only known exception is a feeException.
165 static giant
bigIntStrToGiant(
166 BigIntegerStr
&bigInt
)
168 char *rawOcts
= bigInt
;
169 unsigned numBytes
= bigInt
.Len();
170 unsigned numGiantDigits
;
173 feeReturn frtn
= FR_Success
;
174 unsigned char *inp
= NULL
;
175 unsigned digitDex
; // index into g->giantDigit[]
177 /* handle degenerate case (value of zero) */
178 if((numBytes
== 0) || ((numBytes
== 1) && rawOcts
[0] == 0)) {
181 feeException::throwMe(FR_Memory
, "newGiant(1)");
183 int_to_giant(0, grtn
);
187 /* make a copy of raw octets if we have to do two's complement */
188 unsigned char *byteArray
= NULL
;
189 bool didMalloc
= false;
190 if(rawOcts
[0] & 0x80) {
193 byteArray
= (unsigned char *)fmalloc(numBytes
);
196 memmove(byteArray
+ 1, rawOcts
, numBytes
-1);
197 twosComplement(byteArray
, numBytes
);
202 byteArray
= (unsigned char *)foo
;
205 /* cook up a new giant */
206 numGiantDigits
= (numBytes
+ GIANT_BYTES_PER_DIGIT
- 1) /
207 GIANT_BYTES_PER_DIGIT
;
208 grtn
= newGiant(numGiantDigits
);
215 * Convert byteArray to array of giantDigits
216 * inp - raw input bytes, LSB last
217 * grtn->n[] - output array of giantDigits, LSD first
218 * Start at LS byte and LD digit
220 digitDex
= 0; // index into g->giantDigit[]
221 giantDigit thisDigit
;
222 inp
= byteArray
+ numBytes
- 1;
223 unsigned dex
; // total byte counter
224 unsigned byteDex
; // index into one giantDigit
226 for(dex
=0; dex
<numBytes
; ) { // increment dex inside
229 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
230 thisDigit
|= ((giantDigit
)(*inp
--) << shiftCount
);
232 if(++dex
== numBytes
) {
233 /* must be partial giantDigit */
237 CKASSERT(digitDex
< numGiantDigits
);
238 grtn
->n
[digitDex
++] = thisDigit
;
240 grtn
->sign
= (int)numGiantDigits
* sign
;
242 /* trim leading (MS) zeroes */
249 feeException::throwMe(frtn
, "bigIntStrToGiant");
255 * Convert a giant to an existing BigIntegerString.
256 * Only known exception is a feeException.
258 static void giantToBigIntStr(
260 BigIntegerStr
&bigInt
)
262 unsigned char doPrepend
= 0;
263 unsigned numGiantDigits
= abs(g
->sign
);
264 unsigned numBytes
= numGiantDigits
* GIANT_BYTES_PER_DIGIT
;
265 giantDigit msGiantBit
= 0;
267 /* special degenerate case */
272 msGiantBit
= g
->n
[numGiantDigits
- 1] >> (GIANT_BITS_PER_DIGIT
- 1);
275 /* prepend a byte of zero if necessary */
276 if((g
->sign
< 0) || // negative - to handle 2's complement
277 ((g
->sign
> 0) && msGiantBit
)) { // ensure MS byte is zero
282 unsigned char *rawBytes
= (unsigned char *)fmalloc(numBytes
);
283 if(rawBytes
== NULL
) {
284 feeException::throwMe(FR_Memory
, "giantToBigIntStr fmalloc(rawBytes)");
286 unsigned char *outp
= rawBytes
;
292 * Convert array of giantDigits to bytes.
293 * outp point to MS output byte.
295 int digitDex
; // index into g->giantDigit[]
296 unsigned byteDex
; // byte index into a giantDigit
297 for(digitDex
=numGiantDigits
-1; digitDex
>=0; digitDex
--) {
298 /* one loop per giantDigit, starting at MS end */
299 giantDigit thisDigit
= g
->n
[digitDex
];
300 unsigned char *bp
= outp
+ GIANT_BYTES_PER_DIGIT
- 1;
301 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
302 /* one loop per byte within the digit, starting at LS end */
303 *bp
-- = (unsigned char)(thisDigit
) & 0xff;
306 outp
+= GIANT_BYTES_PER_DIGIT
;
309 /* do two's complement for negative giants */
311 twosComplement(rawBytes
, numBytes
);
314 /* strip off redundant leading bits (nine zeroes or nine ones) */
316 unsigned char *endp
= outp
+ numBytes
- 1;
317 while((*outp
== 0) && // m.s. byte zero
318 (outp
< endp
) && // more bytes exist
319 (!(outp
[1] & 0x80))) { // 9th bit is 0
323 while((*outp
== 0xff) && // m.s. byte all ones
324 (outp
< endp
) && // more bytes exist
325 (outp
[1] & 0x80)) { // 9th bit is 1
330 /* rawBytes are the ASN-compliant contents */
331 bigInt
.ReSet(reinterpret_cast<const char *>(outp
), numBytes
);
335 /* curveParams : CryptKit <--> snacc */
336 /* Only known exception is a feeException */
337 static FEECurveParameters
*feeCurveParamsToSnacc(
338 const curveParams
*cp
)
340 #if PRINT_CURVE_PARAMS
341 printf("===encoding curveParams; cp:\n"); printCurveParams(cp
);
343 FEECurveParameters
*snaccCp
= NULL
;
345 snaccCp
= new FEECurveParameters();
347 switch(cp
->primeType
) {
349 val
= FEEPrimeType::pt_mersenne
;
352 val
= FEEPrimeType::pt_fee
;
355 val
= FEEPrimeType::pt_general
;
358 feeException::throwMe(FR_Internal
, "bad cp->primeType");
360 snaccCp
->primeType
.Set(val
);
361 switch(cp
->curveType
) {
363 val
= FEECurveType::ct_montgomery
;
365 case FCT_Weierstrass
:
366 val
= FEECurveType::ct_weierstrass
;
369 val
= FEECurveType::ct_general
;
372 feeException::throwMe(FR_Internal
, "bad cp->curveType");
374 snaccCp
->curveType
.Set(val
);
375 snaccCp
->q
.Set(cp
->q
);
376 snaccCp
->k
.Set(cp
->k
);
377 snaccCp
->m
.Set(cp
->m
);
378 giantToBigIntStr(cp
->a
, snaccCp
->a
);
379 giantToBigIntStr(cp
->b
, snaccCp
->bb
);
380 giantToBigIntStr(cp
->c
, snaccCp
->c
);
381 giantToBigIntStr(cp
->x1Plus
, snaccCp
->x1Plus
);
382 giantToBigIntStr(cp
->x1Minus
, snaccCp
->x1Minus
);
383 giantToBigIntStr(cp
->cOrderPlus
, snaccCp
->cOrderPlus
);
384 giantToBigIntStr(cp
->cOrderMinus
, snaccCp
->cOrderMinus
);
385 giantToBigIntStr(cp
->x1OrderPlus
, snaccCp
->x1OrderPlus
);
386 giantToBigIntStr(cp
->x1OrderMinus
, snaccCp
->x1OrderMinus
);
387 if(cp
->primeType
== FPT_General
) {
388 snaccCp
->basePrime
= new BigIntegerStr();
389 giantToBigIntStr(cp
->basePrime
, *snaccCp
->basePrime
);
392 catch(feeException ferr
) {
398 feeException::throwMe(FR_Memory
, "feeCurveParamsToSnacc catchall"); // ???
403 static curveParams
*feeCurveParamsFromSnacc(
404 FEECurveParameters
&snaccCp
)
406 curveParams
*cp
= newCurveParams();
408 feeException::throwMe(FR_Memory
, "feeCurveParamsFromSnacc alloc cp");
410 AsnIntType val
= snaccCp
.primeType
;
412 case FEEPrimeType::pt_mersenne
:
413 cp
->primeType
= FPT_Mersenne
;
415 case FEEPrimeType::pt_fee
:
416 cp
->primeType
= FPT_FEE
;
418 case FEEPrimeType::pt_general
:
419 cp
->primeType
= FPT_General
;
422 feeException::throwMe(FR_BadPubKey
, "feeCurveParamsFromSnacc bad primeType");
424 val
= snaccCp
.curveType
;
426 case FEECurveType::ct_montgomery
:
427 cp
->curveType
= FCT_Montgomery
;
429 case FEECurveType::ct_weierstrass
:
430 cp
->curveType
= FCT_Weierstrass
;
432 case FEECurveType::ct_general
:
433 cp
->curveType
= FCT_General
;
436 feeException::throwMe(FR_BadPubKey
, "feeCurveParamsFromSnacc bad curveType");
441 cp
->a
= bigIntStrToGiant(snaccCp
.a
);
442 cp
->b
= bigIntStrToGiant(snaccCp
.bb
);
443 cp
->c
= bigIntStrToGiant(snaccCp
.c
);
444 cp
->x1Plus
= bigIntStrToGiant(snaccCp
.x1Plus
);
445 cp
->x1Minus
= bigIntStrToGiant(snaccCp
.x1Minus
);
446 cp
->cOrderPlus
= bigIntStrToGiant(snaccCp
.cOrderPlus
);
447 cp
->cOrderMinus
= bigIntStrToGiant(snaccCp
.cOrderMinus
);
448 cp
->x1OrderPlus
= bigIntStrToGiant(snaccCp
.x1OrderPlus
);
449 cp
->x1OrderMinus
= bigIntStrToGiant(snaccCp
.x1OrderMinus
);
450 if(snaccCp
.basePrime
!= NULL
) {
451 cp
->basePrime
= bigIntStrToGiant(*snaccCp
.basePrime
);
454 /* remaining fields inferred */
455 curveParamsInferFields(cp
);
456 allocRecipGiants(cp
);
457 #if PRINT_CURVE_PARAMS
458 printf("===decoding curveParams; cp:\n"); printCurveParams(cp
);
464 *** Public routines. These are usable from C code; they never throw.
468 * Encode/decode the two FEE signature types. We malloc returned data via
469 * fmalloc(); caller must free via ffree().
471 feeReturn
feeDEREncodeElGamalSignature(
474 unsigned char **encodedSig
, // fmallocd and RETURNED
475 unsigned *encodedSigLen
) // RETURNED
477 FEEElGamalSignature snaccSig
;
478 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
481 giantToBigIntStr(u
, snaccSig
.u
);
482 giantToBigIntStr(PmX
, snaccSig
.pmX
);
484 catch(feeException ferr
) {
488 SC_encodeAsnObj(snaccSig
, oData
, feeSizeOfDERSig(u
, PmX
));
491 /* FIXME - bad sig? memory? */
492 return FR_BadSignatureFormat
;
494 *encodedSig
= (unsigned char *)fmalloc(oData
.length());
495 *encodedSigLen
= oData
.length();
496 memmove(*encodedSig
, oData
.get().Data
, oData
.length());
498 printf("feeEncodeElGamalSignature:\n");
499 printf(" u : "); printGiantHex(u
);
500 printf(" PmX : "); printGiantHex(PmX
);
501 printf(" u : "); snaccSig
.u
.Print(cout
); printf("\n");
502 printf(" PmX : "); snaccSig
.pmX
.Print(cout
); printf("\n");
507 feeReturn
feeDEREncodeECDSASignature(
510 unsigned char **encodedSig
, // fmallocd and RETURNED
511 unsigned *encodedSigLen
) // RETURNED
513 FEEECDSASignature snaccSig
;
514 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
517 giantToBigIntStr(c
, snaccSig
.c
);
518 giantToBigIntStr(d
, snaccSig
.d
);
520 catch(feeException ferr
) {
524 SC_encodeAsnObj(snaccSig
, oData
, feeSizeOfDERSig(c
, d
));
527 /* FIXME - bad sig? memory? */
528 return FR_BadSignatureFormat
;
530 *encodedSig
= (unsigned char *)fmalloc(oData
.length());
531 *encodedSigLen
= oData
.length();
532 memmove(*encodedSig
, oData
.get().Data
, oData
.length());
534 printf("feeEncodeECDSASignature:\n");
535 printf(" c : "); printGiantHex(*c
);
536 printf(" d : "); printGiantHex(*d
);
537 printf(" c : "); snaccSig
.c
.Print(cout
); printf("\n");
538 printf(" d : "); snaccSig
.d
.Print(cout
); printf("\n");
543 feeReturn
feeDERDecodeElGamalSignature(
544 const unsigned char *encodedSig
,
545 unsigned encodedSigLen
,
546 giant
*u
, // newGiant'd and RETURNED
547 giant
*PmX
) // newGiant'd and RETURNED
549 FEEElGamalSignature snaccSig
;
550 CssmData
cData((void *)encodedSig
, encodedSigLen
);
552 SC_decodeAsnObj(cData
, snaccSig
);
555 return FR_BadSignatureFormat
;
558 *u
= bigIntStrToGiant(snaccSig
.u
);
559 *PmX
= bigIntStrToGiant(snaccSig
.pmX
);
561 catch(feeException ferr
) {
565 /* FIXME - bad sig? memory? */
569 printf("feeDecodeElGamalSignature:\n");
570 printf(" u : "); printGiantHex(*u
);
571 printf(" PmX : "); printGiantHex(*PmX
);
572 printf(" u : "); snaccSig
.u
.Print(cout
); printf("\n");
573 printf(" PmX : "); snaccSig
.pmX
.Print(cout
); printf("\n");
578 feeReturn
feeDERDecodeECDSASignature(
579 const unsigned char *encodedSig
,
580 unsigned encodedSigLen
,
581 giant
*c
, // newGiant'd and RETURNED
582 giant
*d
) // newGiant'd and RETURNED
584 FEEECDSASignature snaccSig
;
585 CssmData
cData((void *)encodedSig
, encodedSigLen
);
587 SC_decodeAsnObj(cData
, snaccSig
);
590 return FR_BadSignatureFormat
;
593 *c
= bigIntStrToGiant(snaccSig
.c
);
594 *d
= bigIntStrToGiant(snaccSig
.d
);
596 catch(feeException ferr
) {
600 /* FIXME - bad sig? memory? */
604 printf("feeDecodeECDSASignature:\n");
605 printf(" c : "); printGiantHex(*c
);
606 printf(" d : "); printGiantHex(*d
);
607 printf(" c : "); snaccSig
.c
.Print(cout
); printf("\n");
608 printf(" d : "); snaccSig
.d
.Print(cout
); printf("\n");
614 * Encode/decode the FEE private and public keys. We malloc returned data via
615 * falloc(); caller must free via ffree(). Public C functions which never throw.
617 feeReturn
feeDEREncodePublicKey(
619 const curveParams
*cp
,
622 giant plusY
, // may be NULL
623 unsigned char **keyBlob
, // fmallocd and RETURNED
624 unsigned *keyBlobLen
) // RETURNED
626 FEEPublicKey snaccKey
;
628 /* set up the SNACC object */
629 snaccKey
.version
.Set(version
);
631 snaccKey
.curveParams
= feeCurveParamsToSnacc(cp
);
632 giantToBigIntStr(plusX
, snaccKey
.plusX
);
633 giantToBigIntStr(minusX
, snaccKey
.minusX
);
635 snaccKey
.plusY
= new BigIntegerStr();
636 giantToBigIntStr(plusY
, *snaccKey
.plusY
);
639 catch(feeException ferr
) {
643 /* encode the SNACC object */
644 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
647 SC_encodeAsnObj(snaccKey
, oData
, feeSizeOfSnaccPubKey(cp
));
653 *keyBlob
= (unsigned char *)fmalloc(oData
.length());
654 *keyBlobLen
= oData
.length();
655 memmove(*keyBlob
, oData
.get().Data
, oData
.length());
659 feeReturn
feeDEREncodePrivateKey(
661 const curveParams
*cp
,
662 const giant privData
,
663 unsigned char **keyBlob
, // fmallocd and RETURNED
664 unsigned *keyBlobLen
) // RETURNED
666 FEEPrivateKey snaccKey
;
668 /* set up the SNACC object */
669 snaccKey
.version
.Set(version
);
671 snaccKey
.curveParams
= feeCurveParamsToSnacc(cp
);
672 giantToBigIntStr(privData
, snaccKey
.privData
);
674 catch(feeException ferr
) {
678 /* encode the SNACC object */
679 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
682 SC_encodeAsnObj(snaccKey
, oData
, feeSizeOfSnaccPrivKey(cp
));
688 *keyBlob
= (unsigned char *)fmalloc(oData
.length());
689 *keyBlobLen
= oData
.length();
690 memmove(*keyBlob
, oData
.get().Data
, oData
.length());
694 feeReturn
feeDERDecodePublicKey(
695 const unsigned char *keyBlob
,
697 int *version
, // this and remainder RETURNED
701 giant
*plusY
) // may be NULL
703 FEEPublicKey snaccKey
;
704 CssmData
cData((unsigned char *)keyBlob
, (size_t)keyBlobLen
);
706 SC_decodeAsnObj(cData
, snaccKey
);
712 *version
= snaccKey
.version
;
713 *cp
= feeCurveParamsFromSnacc(*snaccKey
.curveParams
);
714 *plusX
= bigIntStrToGiant(snaccKey
.plusX
);
715 *minusX
= bigIntStrToGiant(snaccKey
.minusX
);
716 if(snaccKey
.plusY
!= NULL
) {
718 *plusY
= bigIntStrToGiant(*snaccKey
.plusY
);
721 *plusY
= newGiant(1);
722 int_to_giant(0, *plusY
);
725 catch(feeException ferr
) {
729 /* FIXME - bad sig? memory? */
735 feeReturn
feeDERDecodePrivateKey(
736 const unsigned char *keyBlob
,
738 int *version
, // this and remainder RETURNED
740 giant
*privData
) // RETURNED
742 FEEPrivateKey snaccKey
;
743 CssmData
cData((unsigned char *)keyBlob
, (size_t)keyBlobLen
);
745 SC_decodeAsnObj(cData
, snaccKey
);
751 *version
= snaccKey
.version
;
752 *cp
= feeCurveParamsFromSnacc(*snaccKey
.curveParams
);
753 *privData
= bigIntStrToGiant(snaccKey
.privData
);
755 catch(feeException ferr
) {
759 /* FIXME - bad sig? memory? */
765 #endif /* CRYPTKIT_CSP_ENABLE */