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.
49 // @@@ This should really be a subclass of exception
53 feeException(feeReturn frtn
, const char *op
);
55 ~feeException() throw() {}
56 feeReturn
frtn() const throw() { return mFrtn
; }
57 static void throwMe(feeReturn frtn
, const char *op
= NULL
) __attribute__((noreturn
));
62 feeException::feeException(
68 dbgLog(("%s: %s\n", op
, feeReturnString(frtn
)));
72 void feeException::throwMe(feeReturn frtn
, const char *op
= NULL
) { throw feeException(frtn
, op
); }
75 * ASN1 encoding rules specify that an integer's sign is indicated by the MSB
76 * of the first (MS) content byte. For a non-negative number, if the MSB of
77 * the MS byte (of the unencoded number) is one, then the encoding starts with
78 * a byte of zeroes to indicate positive sign. For a negative number, the first
79 * nine bits can not be all 1 - if they are (in the undecoded number), leading
80 * bytes of 0xff are trimmed off until the first nine bits are something other
81 * than one. Also, the first nine bits of the encoded number can not all be
84 * CryptKit giants express their sign as part of the giantstruct.sign field.
85 * The giantDigit array (giantstruct.n[]) is stored l.s. digit first.
87 * These routines are independent of platform, endianness, and giatn digit size.
90 /* routines to guess maximum size of DER-encoded objects */
91 static unsigned feeSizeOfSnaccGiant(
94 unsigned rtn
= abs(g
->sign
) * GIANT_BYTES_PER_DIGIT
;
95 szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g
->sign
, rtn
+ 4));
99 static unsigned feeSizeofSnaccInt()
105 unsigned feeSizeOfDERSig(
109 unsigned rtn
= feeSizeOfSnaccGiant(g1
);
110 rtn
+= feeSizeOfSnaccGiant(g2
);
111 szprint(("feeSizeOfDERSig: size %d\n", rtn
+ 4));
115 static unsigned feeSizeofSnaccCurveParams(const curveParams
*cp
)
117 unsigned rtn
= 5 * feeSizeofSnaccInt(); // primeType, curveType, q, k, m
118 rtn
+= 10 * feeSizeOfSnaccGiant(cp
->basePrime
);
119 szprint(("feeSizeofSnaccCurveParams: size %d\n", rtn
));
123 static unsigned feeSizeOfSnaccPubKey(const curveParams
*cp
)
125 unsigned rtn
= 11; // version plus sequence overhead
126 rtn
+= feeSizeofSnaccCurveParams(cp
);
127 rtn
+= (3 * feeSizeOfSnaccGiant(cp
->basePrime
));
128 szprint(("feeSizeOfSnaccPubKey: size %d\n", rtn
));
132 static unsigned feeSizeOfSnaccPrivKey(const curveParams
*cp
)
134 unsigned rtn
= 11; // version plus sequence overhead
135 rtn
+= feeSizeofSnaccCurveParams(cp
);
136 rtn
+= feeSizeOfSnaccGiant(cp
->basePrime
);
137 szprint(("feeSizeOfSnaccPrivKey: size %d\n", rtn
));
141 /* perform 2's complement of byte array, expressed MS byte first */
142 static void twosComplement(
143 unsigned char *bytePtr
, // points to MS byte
146 unsigned char *outp
= bytePtr
+ numBytes
- 1;
147 unsigned char carry
= 1; // first time thru, carry = 1 to add one to 1's comp
148 for(unsigned byteDex
=0; byteDex
<numBytes
; byteDex
++) {
149 /* first complement, then add carry */
150 *outp
= ~*outp
+ carry
;
151 if(carry
&& (*outp
== 0)) {
163 * Convert a BigIntegerStr to a (mallocd) giant.
164 * Only known exception is a feeException.
166 static giant
bigIntStrToGiant(
167 BigIntegerStr
&bigInt
)
169 char *rawOcts
= bigInt
;
170 unsigned numBytes
= bigInt
.Len();
171 unsigned numGiantDigits
;
174 feeReturn frtn
= FR_Success
;
175 unsigned char *inp
= NULL
;
176 unsigned digitDex
; // index into g->giantDigit[]
178 /* handle degenerate case (value of zero) */
179 if((numBytes
== 0) || ((numBytes
== 1) && rawOcts
[0] == 0)) {
182 feeException::throwMe(FR_Memory
, "newGiant(1)");
184 int_to_giant(0, grtn
);
188 /* make a copy of raw octets if we have to do two's complement */
189 unsigned char *byteArray
= NULL
;
190 bool didMalloc
= false;
191 if(rawOcts
[0] & 0x80) {
194 byteArray
= (unsigned char *)fmalloc(numBytes
);
197 memmove(byteArray
+ 1, rawOcts
, numBytes
-1);
198 twosComplement(byteArray
, numBytes
);
203 byteArray
= (unsigned char *)foo
;
206 /* cook up a new giant */
207 numGiantDigits
= (numBytes
+ GIANT_BYTES_PER_DIGIT
- 1) /
208 GIANT_BYTES_PER_DIGIT
;
209 grtn
= newGiant(numGiantDigits
);
216 * Convert byteArray to array of giantDigits
217 * inp - raw input bytes, LSB last
218 * grtn->n[] - output array of giantDigits, LSD first
219 * Start at LS byte and LD digit
221 digitDex
= 0; // index into g->giantDigit[]
222 giantDigit thisDigit
;
223 inp
= byteArray
+ numBytes
- 1;
224 unsigned dex
; // total byte counter
225 unsigned byteDex
; // index into one giantDigit
227 for(dex
=0; dex
<numBytes
; ) { // increment dex inside
230 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
231 thisDigit
|= ((giantDigit
)(*inp
--) << shiftCount
);
233 if(++dex
== numBytes
) {
234 /* must be partial giantDigit */
238 CKASSERT(digitDex
< numGiantDigits
);
239 grtn
->n
[digitDex
++] = thisDigit
;
241 grtn
->sign
= (int)numGiantDigits
* sign
;
243 /* trim leading (MS) zeroes */
250 feeException::throwMe(frtn
, "bigIntStrToGiant");
256 * Convert a giant to an existing BigIntegerString.
257 * Only known exception is a feeException.
259 static void giantToBigIntStr(
261 BigIntegerStr
&bigInt
)
263 unsigned char doPrepend
= 0;
264 unsigned numGiantDigits
= abs(g
->sign
);
265 unsigned numBytes
= numGiantDigits
* GIANT_BYTES_PER_DIGIT
;
266 giantDigit msGiantBit
= 0;
268 /* special degenerate case */
273 msGiantBit
= g
->n
[numGiantDigits
- 1] >> (GIANT_BITS_PER_DIGIT
- 1);
276 /* prepend a byte of zero if necessary */
277 if((g
->sign
< 0) || // negative - to handle 2's complement
278 ((g
->sign
> 0) && msGiantBit
)) { // ensure MS byte is zero
283 unsigned char *rawBytes
= (unsigned char *)fmalloc(numBytes
);
284 if(rawBytes
== NULL
) {
285 feeException::throwMe(FR_Memory
, "giantToBigIntStr fmalloc(rawBytes)");
287 unsigned char *outp
= rawBytes
;
293 * Convert array of giantDigits to bytes.
294 * outp point to MS output byte.
296 int digitDex
; // index into g->giantDigit[]
297 unsigned byteDex
; // byte index into a giantDigit
298 for(digitDex
=numGiantDigits
-1; digitDex
>=0; digitDex
--) {
299 /* one loop per giantDigit, starting at MS end */
300 giantDigit thisDigit
= g
->n
[digitDex
];
301 unsigned char *bp
= outp
+ GIANT_BYTES_PER_DIGIT
- 1;
302 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
303 /* one loop per byte within the digit, starting at LS end */
304 *bp
-- = (unsigned char)(thisDigit
) & 0xff;
307 outp
+= GIANT_BYTES_PER_DIGIT
;
310 /* do two's complement for negative giants */
312 twosComplement(rawBytes
, numBytes
);
315 /* strip off redundant leading bits (nine zeroes or nine ones) */
317 unsigned char *endp
= outp
+ numBytes
- 1;
318 while((*outp
== 0) && // m.s. byte zero
319 (outp
< endp
) && // more bytes exist
320 (!(outp
[1] & 0x80))) { // 9th bit is 0
324 while((*outp
== 0xff) && // m.s. byte all ones
325 (outp
< endp
) && // more bytes exist
326 (outp
[1] & 0x80)) { // 9th bit is 1
331 /* rawBytes are the ASN-compliant contents */
332 bigInt
.ReSet(reinterpret_cast<const char *>(outp
), numBytes
);
336 /* curveParams : CryptKit <--> snacc */
337 /* Only known exception is a feeException */
338 static FEECurveParameters
*feeCurveParamsToSnacc(
339 const curveParams
*cp
)
341 #if PRINT_CURVE_PARAMS
342 printf("===encoding curveParams; cp:\n"); printCurveParams(cp
);
344 FEECurveParameters
*snaccCp
= NULL
;
346 snaccCp
= new FEECurveParameters();
348 switch(cp
->primeType
) {
350 val
= FEEPrimeType::pt_mersenne
;
353 val
= FEEPrimeType::pt_fee
;
356 val
= FEEPrimeType::pt_general
;
359 feeException::throwMe(FR_Internal
, "bad cp->primeType");
361 snaccCp
->primeType
.Set(val
);
362 switch(cp
->curveType
) {
364 val
= FEECurveType::ct_montgomery
;
366 case FCT_Weierstrass
:
367 val
= FEECurveType::ct_weierstrass
;
370 val
= FEECurveType::ct_general
;
373 feeException::throwMe(FR_Internal
, "bad cp->curveType");
375 snaccCp
->curveType
.Set(val
);
376 snaccCp
->q
.Set(cp
->q
);
377 snaccCp
->k
.Set(cp
->k
);
378 snaccCp
->m
.Set(cp
->m
);
379 giantToBigIntStr(cp
->a
, snaccCp
->a
);
380 giantToBigIntStr(cp
->b
, snaccCp
->bb
);
381 giantToBigIntStr(cp
->c
, snaccCp
->c
);
382 giantToBigIntStr(cp
->x1Plus
, snaccCp
->x1Plus
);
383 giantToBigIntStr(cp
->x1Minus
, snaccCp
->x1Minus
);
384 giantToBigIntStr(cp
->cOrderPlus
, snaccCp
->cOrderPlus
);
385 giantToBigIntStr(cp
->cOrderMinus
, snaccCp
->cOrderMinus
);
386 giantToBigIntStr(cp
->x1OrderPlus
, snaccCp
->x1OrderPlus
);
387 giantToBigIntStr(cp
->x1OrderMinus
, snaccCp
->x1OrderMinus
);
388 if(cp
->primeType
== FPT_General
) {
389 snaccCp
->basePrime
= new BigIntegerStr();
390 giantToBigIntStr(cp
->basePrime
, *snaccCp
->basePrime
);
393 catch(const feeException
&ferr
) {
399 feeException::throwMe(FR_Memory
, "feeCurveParamsToSnacc catchall"); // ???
404 static curveParams
*feeCurveParamsFromSnacc(
405 FEECurveParameters
&snaccCp
)
407 curveParams
*cp
= newCurveParams();
409 feeException::throwMe(FR_Memory
, "feeCurveParamsFromSnacc alloc cp");
411 AsnIntType val
= snaccCp
.primeType
;
413 case FEEPrimeType::pt_mersenne
:
414 cp
->primeType
= FPT_Mersenne
;
416 case FEEPrimeType::pt_fee
:
417 cp
->primeType
= FPT_FEE
;
419 case FEEPrimeType::pt_general
:
420 cp
->primeType
= FPT_General
;
423 feeException::throwMe(FR_BadPubKey
, "feeCurveParamsFromSnacc bad primeType");
425 val
= snaccCp
.curveType
;
427 case FEECurveType::ct_montgomery
:
428 cp
->curveType
= FCT_Montgomery
;
430 case FEECurveType::ct_weierstrass
:
431 cp
->curveType
= FCT_Weierstrass
;
433 case FEECurveType::ct_general
:
434 cp
->curveType
= FCT_General
;
437 feeException::throwMe(FR_BadPubKey
, "feeCurveParamsFromSnacc bad curveType");
442 cp
->a
= bigIntStrToGiant(snaccCp
.a
);
443 cp
->b
= bigIntStrToGiant(snaccCp
.bb
);
444 cp
->c
= bigIntStrToGiant(snaccCp
.c
);
445 cp
->x1Plus
= bigIntStrToGiant(snaccCp
.x1Plus
);
446 cp
->x1Minus
= bigIntStrToGiant(snaccCp
.x1Minus
);
447 cp
->cOrderPlus
= bigIntStrToGiant(snaccCp
.cOrderPlus
);
448 cp
->cOrderMinus
= bigIntStrToGiant(snaccCp
.cOrderMinus
);
449 cp
->x1OrderPlus
= bigIntStrToGiant(snaccCp
.x1OrderPlus
);
450 cp
->x1OrderMinus
= bigIntStrToGiant(snaccCp
.x1OrderMinus
);
451 if(snaccCp
.basePrime
!= NULL
) {
452 cp
->basePrime
= bigIntStrToGiant(*snaccCp
.basePrime
);
455 /* remaining fields inferred */
456 curveParamsInferFields(cp
);
457 allocRecipGiants(cp
);
458 #if PRINT_CURVE_PARAMS
459 printf("===decoding curveParams; cp:\n"); printCurveParams(cp
);
465 *** Public routines. These are usable from C code; they never throw.
469 * Encode/decode the two FEE signature types. We malloc returned data via
470 * fmalloc(); caller must free via ffree().
472 feeReturn
feeDEREncodeElGamalSignature(
475 unsigned char **encodedSig
, // fmallocd and RETURNED
476 unsigned *encodedSigLen
) // RETURNED
478 FEEElGamalSignature snaccSig
;
479 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
482 giantToBigIntStr(u
, snaccSig
.u
);
483 giantToBigIntStr(PmX
, snaccSig
.pmX
);
485 catch(const feeException
&ferr
) {
489 SC_encodeAsnObj(snaccSig
, oData
, feeSizeOfDERSig(u
, PmX
));
492 /* FIXME - bad sig? memory? */
493 return FR_BadSignatureFormat
;
495 *encodedSig
= (unsigned char *)fmalloc(oData
.length());
496 *encodedSigLen
= oData
.length();
497 memmove(*encodedSig
, oData
.get().Data
, oData
.length());
499 printf("feeEncodeElGamalSignature:\n");
500 printf(" u : "); printGiantHex(u
);
501 printf(" PmX : "); printGiantHex(PmX
);
502 printf(" u : "); snaccSig
.u
.Print(cout
); printf("\n");
503 printf(" PmX : "); snaccSig
.pmX
.Print(cout
); printf("\n");
508 feeReturn
feeDEREncodeECDSASignature(
511 unsigned char **encodedSig
, // fmallocd and RETURNED
512 unsigned *encodedSigLen
) // RETURNED
514 FEEECDSASignature snaccSig
;
515 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
518 giantToBigIntStr(c
, snaccSig
.c
);
519 giantToBigIntStr(d
, snaccSig
.d
);
521 catch(const feeException
&ferr
) {
525 SC_encodeAsnObj(snaccSig
, oData
, feeSizeOfDERSig(c
, d
));
528 /* FIXME - bad sig? memory? */
529 return FR_BadSignatureFormat
;
531 *encodedSig
= (unsigned char *)fmalloc(oData
.length());
532 *encodedSigLen
= oData
.length();
533 memmove(*encodedSig
, oData
.get().Data
, oData
.length());
535 printf("feeEncodeECDSASignature:\n");
536 printf(" c : "); printGiantHex(*c
);
537 printf(" d : "); printGiantHex(*d
);
538 printf(" c : "); snaccSig
.c
.Print(cout
); printf("\n");
539 printf(" d : "); snaccSig
.d
.Print(cout
); printf("\n");
544 feeReturn
feeDERDecodeElGamalSignature(
545 const unsigned char *encodedSig
,
546 unsigned encodedSigLen
,
547 giant
*u
, // newGiant'd and RETURNED
548 giant
*PmX
) // newGiant'd and RETURNED
550 FEEElGamalSignature snaccSig
;
551 CssmData
cData((void *)encodedSig
, encodedSigLen
);
553 SC_decodeAsnObj(cData
, snaccSig
);
556 return FR_BadSignatureFormat
;
559 *u
= bigIntStrToGiant(snaccSig
.u
);
560 *PmX
= bigIntStrToGiant(snaccSig
.pmX
);
562 catch(const feeException
&ferr
) {
566 /* FIXME - bad sig? memory? */
570 printf("feeDecodeElGamalSignature:\n");
571 printf(" u : "); printGiantHex(*u
);
572 printf(" PmX : "); printGiantHex(*PmX
);
573 printf(" u : "); snaccSig
.u
.Print(cout
); printf("\n");
574 printf(" PmX : "); snaccSig
.pmX
.Print(cout
); printf("\n");
579 feeReturn
feeDERDecodeECDSASignature(
580 const unsigned char *encodedSig
,
581 unsigned encodedSigLen
,
582 giant
*c
, // newGiant'd and RETURNED
583 giant
*d
) // newGiant'd and RETURNED
585 FEEECDSASignature snaccSig
;
586 CssmData
cData((void *)encodedSig
, encodedSigLen
);
588 SC_decodeAsnObj(cData
, snaccSig
);
591 return FR_BadSignatureFormat
;
594 *c
= bigIntStrToGiant(snaccSig
.c
);
595 *d
= bigIntStrToGiant(snaccSig
.d
);
597 catch(const feeException
&ferr
) {
601 /* FIXME - bad sig? memory? */
605 printf("feeDecodeECDSASignature:\n");
606 printf(" c : "); printGiantHex(*c
);
607 printf(" d : "); printGiantHex(*d
);
608 printf(" c : "); snaccSig
.c
.Print(cout
); printf("\n");
609 printf(" d : "); snaccSig
.d
.Print(cout
); printf("\n");
615 * Encode/decode the FEE private and public keys. We malloc returned data via
616 * falloc(); caller must free via ffree(). Public C functions which never throw.
618 feeReturn
feeDEREncodePublicKey(
620 const curveParams
*cp
,
623 giant plusY
, // may be NULL
624 unsigned char **keyBlob
, // fmallocd and RETURNED
625 unsigned *keyBlobLen
) // RETURNED
627 FEEPublicKey snaccKey
;
629 /* set up the SNACC object */
630 snaccKey
.version
.Set(version
);
632 snaccKey
.curveParams
= feeCurveParamsToSnacc(cp
);
633 giantToBigIntStr(plusX
, snaccKey
.plusX
);
634 giantToBigIntStr(minusX
, snaccKey
.minusX
);
636 snaccKey
.plusY
= new BigIntegerStr();
637 giantToBigIntStr(plusY
, *snaccKey
.plusY
);
640 catch(const feeException
&ferr
) {
644 /* encode the SNACC object */
645 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
648 SC_encodeAsnObj(snaccKey
, oData
, feeSizeOfSnaccPubKey(cp
));
654 *keyBlob
= (unsigned char *)fmalloc(oData
.length());
655 *keyBlobLen
= oData
.length();
656 memmove(*keyBlob
, oData
.get().Data
, oData
.length());
660 feeReturn
feeDEREncodePrivateKey(
662 const curveParams
*cp
,
663 const giant privData
,
664 unsigned char **keyBlob
, // fmallocd and RETURNED
665 unsigned *keyBlobLen
) // RETURNED
667 FEEPrivateKey snaccKey
;
669 /* set up the SNACC object */
670 snaccKey
.version
.Set(version
);
672 snaccKey
.curveParams
= feeCurveParamsToSnacc(cp
);
673 giantToBigIntStr(privData
, snaccKey
.privData
);
675 catch(const feeException
&ferr
) {
679 /* encode the SNACC object */
680 CssmAutoData
oData(CssmAllocator::standard(CssmAllocator::sensitive
));
683 SC_encodeAsnObj(snaccKey
, oData
, feeSizeOfSnaccPrivKey(cp
));
689 *keyBlob
= (unsigned char *)fmalloc(oData
.length());
690 *keyBlobLen
= oData
.length();
691 memmove(*keyBlob
, oData
.get().Data
, oData
.length());
695 feeReturn
feeDERDecodePublicKey(
696 const unsigned char *keyBlob
,
698 int *version
, // this and remainder RETURNED
702 giant
*plusY
) // may be NULL
704 FEEPublicKey snaccKey
;
705 CssmData
cData((unsigned char *)keyBlob
, (size_t)keyBlobLen
);
707 SC_decodeAsnObj(cData
, snaccKey
);
713 *version
= snaccKey
.version
;
714 *cp
= feeCurveParamsFromSnacc(*snaccKey
.curveParams
);
715 *plusX
= bigIntStrToGiant(snaccKey
.plusX
);
716 *minusX
= bigIntStrToGiant(snaccKey
.minusX
);
717 if(snaccKey
.plusY
!= NULL
) {
719 *plusY
= bigIntStrToGiant(*snaccKey
.plusY
);
722 *plusY
= newGiant(1);
723 int_to_giant(0, *plusY
);
726 catch(const feeException
&ferr
) {
730 /* FIXME - bad sig? memory? */
736 feeReturn
feeDERDecodePrivateKey(
737 const unsigned char *keyBlob
,
739 int *version
, // this and remainder RETURNED
741 giant
*privData
) // RETURNED
743 FEEPrivateKey snaccKey
;
744 CssmData
cData((unsigned char *)keyBlob
, (size_t)keyBlobLen
);
746 SC_decodeAsnObj(cData
, snaccKey
);
752 *version
= snaccKey
.version
;
753 *cp
= feeCurveParamsFromSnacc(*snaccKey
.curveParams
);
754 *privData
= bigIntStrToGiant(snaccKey
.privData
);
756 catch(const feeException
&ferr
) {
760 /* FIXME - bad sig? memory? */
766 #endif /* CRYPTKIT_CSP_ENABLE */