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 <CryptKit/CryptKitDER.h>
29 #include <CryptKit/falloc.h>
30 #include <CryptKit/feeDebug.h>
31 #include <CryptKit/feeFunctions.h>
32 #include "CryptKitAsn1.h"
33 #include <SecurityNssAsn1/SecNssCoder.h>
36 #define PRINT_SIG_GIANTS 0
37 #define PRINT_CURVE_PARAMS 0
40 #define szprint(s) printf s
46 * Trivial exception class associated with a feeReturn.
51 feeException(feeReturn frtn
, const char *op
);
53 ~feeException() throw() {}
54 feeReturn
frtn() const throw() { return mFrtn
; }
55 static void throwMe(feeReturn frtn
, const char *op
= NULL
) __attribute__((noreturn
));
60 feeException::feeException(
66 dbgLog(("%s: %s\n", op
, feeReturnString(frtn
)));
70 void feeException::throwMe(feeReturn frtn
, const char *op
/*= NULL*/) { throw feeException(frtn
, op
); }
73 * ASN1 encoding rules specify that an integer's sign is indicated by the MSB
74 * of the first (MS) content byte. For a non-negative number, if the MSB of
75 * the MS byte (of the unencoded number) is one, then the encoding starts with
76 * a byte of zeroes to indicate positive sign. For a negative number, the first
77 * nine bits can not be all 1 - if they are (in the undecoded number), leading
78 * bytes of 0xff are trimmed off until the first nine bits are something other
79 * than one. Also, the first nine bits of the encoded number can not all be
82 * CryptKit giants express their sign as part of the giantstruct.sign field.
83 * The giantDigit array (giantstruct.n[]) is stored l.s. digit first.
85 * These routines are independent of platform, endianness, and giatn digit size.
88 /* routines to guess maximum size of DER-encoded objects */
89 static unsigned feeSizeOfSnaccGiant(
92 unsigned rtn
= abs(g
->sign
) * GIANT_BYTES_PER_DIGIT
;
93 szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g
->sign
, rtn
+ 4));
98 unsigned feeSizeOfDERSig(
102 unsigned rtn
= feeSizeOfSnaccGiant(g1
);
103 rtn
+= feeSizeOfSnaccGiant(g2
);
104 szprint(("feeSizeOfDERSig: size %d\n", rtn
+ 4));
108 /* perform 2's complement of byte array, expressed MS byte first */
109 static void twosComplement(
110 unsigned char *bytePtr
, // points to MS byte
113 unsigned char *outp
= bytePtr
+ numBytes
- 1;
114 unsigned char carry
= 1; // first time thru, carry = 1 to add one to 1's comp
115 for(unsigned byteDex
=0; byteDex
<numBytes
; byteDex
++) {
116 /* first complement, then add carry */
117 *outp
= ~*outp
+ carry
;
118 if(carry
&& (*outp
== 0)) {
130 * CSSM_DATA --> unsigned int
132 static unsigned cssmDataToInt(
133 const CSSM_DATA
&cdata
)
135 if((cdata
.Length
== 0) || (cdata
.Data
== NULL
)) {
138 unsigned len
= (unsigned)cdata
.Length
;
139 if(len
> sizeof(int)) {
140 feeException::throwMe(FR_BadKeyBlob
, "cssmDataToInt");
144 uint8
*cp
= cdata
.Data
;
145 for(unsigned i
=0; i
<len
; i
++) {
146 rtn
= (rtn
<< 8) | *cp
++;
152 * unsigned int --> CSSM_DATA, mallocing from an SecNssCoder
154 static void intToCssmData(
164 else if(num
< 0x10000) {
167 else if(num
< 0x1000000) {
173 cdata
.Data
= (uint8
*)coder
.malloc(len
);
175 uint8
*cp
= &cdata
.Data
[len
- 1];
176 for(unsigned i
=0; i
<len
; i
++) {
183 * Convert a decoded ASN integer, as a CSSM_DATA, to a (mallocd) giant.
184 * Only known exception is a feeException.
186 static giant
cssmDataToGiant(
187 const CSSM_DATA
&cdata
)
189 char *rawOcts
= (char *)cdata
.Data
;
190 unsigned numBytes
= cdata
.Length
;
191 unsigned numGiantDigits
;
194 feeReturn frtn
= FR_Success
;
195 unsigned char *inp
= NULL
;
196 unsigned digitDex
; // index into g->giantDigit[]
198 /* handle degenerate case (value of zero) */
199 if((numBytes
== 0) || ((numBytes
== 1) && rawOcts
[0] == 0)) {
202 feeException::throwMe(FR_Memory
, "newGiant(1)");
204 int_to_giant(0, grtn
);
208 /* make a copy of raw octets if we have to do two's complement */
209 unsigned char *byteArray
= NULL
;
210 bool didMalloc
= false;
211 if(rawOcts
[0] & 0x80) {
214 byteArray
= (unsigned char *)fmalloc(numBytes
);
217 memmove(byteArray
+ 1, rawOcts
, numBytes
-1);
218 twosComplement(byteArray
, numBytes
);
223 byteArray
= (unsigned char *)foo
;
226 /* cook up a new giant */
227 numGiantDigits
= (numBytes
+ GIANT_BYTES_PER_DIGIT
- 1) /
228 GIANT_BYTES_PER_DIGIT
;
229 grtn
= newGiant(numGiantDigits
);
236 * Convert byteArray to array of giantDigits
237 * inp - raw input bytes, LSB last
238 * grtn->n[] - output array of giantDigits, LSD first
239 * Start at LS byte and LD digit
241 digitDex
= 0; // index into g->giantDigit[]
242 giantDigit thisDigit
;
243 inp
= byteArray
+ numBytes
- 1;
244 unsigned dex
; // total byte counter
245 unsigned byteDex
; // index into one giantDigit
247 for(dex
=0; dex
<numBytes
; ) { // increment dex inside
250 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
251 thisDigit
|= ((giantDigit
)(*inp
--) << shiftCount
);
253 if(++dex
== numBytes
) {
254 /* must be partial giantDigit */
258 CKASSERT(digitDex
< numGiantDigits
);
259 grtn
->n
[digitDex
++] = thisDigit
;
261 grtn
->sign
= (int)numGiantDigits
* sign
;
263 /* trim leading (MS) zeroes */
270 feeException::throwMe(frtn
, "bigIntStrToGiant");
276 * Convert a giant to an CSSM_DATA, mallocing using specified coder.
277 * Only known exception is a feeException.
279 static void giantToCssmData(
284 unsigned char doPrepend
= 0;
285 unsigned numGiantDigits
= abs(g
->sign
);
286 unsigned numBytes
= numGiantDigits
* GIANT_BYTES_PER_DIGIT
;
287 giantDigit msGiantBit
= 0;
289 /* special degenerate case */
290 intToCssmData(0, cdata
, coder
);
294 msGiantBit
= g
->n
[numGiantDigits
- 1] >> (GIANT_BITS_PER_DIGIT
- 1);
297 /* prepend a byte of zero if necessary */
298 if((g
->sign
< 0) || // negative - to handle 2's complement
299 ((g
->sign
> 0) && msGiantBit
)) { // ensure MS byte is zero
304 unsigned char *rawBytes
= (unsigned char *)fmalloc(numBytes
);
305 if(rawBytes
== NULL
) {
306 feeException::throwMe(FR_Memory
, "giantToBigIntStr fmalloc(rawBytes)");
308 unsigned char *outp
= rawBytes
;
314 * Convert array of giantDigits to bytes.
315 * outp point to MS output byte.
317 int digitDex
; // index into g->giantDigit[]
318 unsigned byteDex
; // byte index into a giantDigit
319 for(digitDex
=numGiantDigits
-1; digitDex
>=0; digitDex
--) {
320 /* one loop per giantDigit, starting at MS end */
321 giantDigit thisDigit
= g
->n
[digitDex
];
322 unsigned char *bp
= outp
+ GIANT_BYTES_PER_DIGIT
- 1;
323 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
324 /* one loop per byte within the digit, starting at LS end */
325 *bp
-- = (unsigned char)(thisDigit
) & 0xff;
328 outp
+= GIANT_BYTES_PER_DIGIT
;
331 /* do two's complement for negative giants */
333 twosComplement(rawBytes
, numBytes
);
336 /* strip off redundant leading bits (nine zeroes or nine ones) */
338 unsigned char *endp
= outp
+ numBytes
- 1;
339 while((*outp
== 0) && // m.s. byte zero
340 (outp
< endp
) && // more bytes exist
341 (!(outp
[1] & 0x80))) { // 9th bit is 0
345 while((*outp
== 0xff) && // m.s. byte all ones
346 (outp
< endp
) && // more bytes exist
347 (outp
[1] & 0x80)) { // 9th bit is 1
351 cdata
.Data
= (uint8
*)coder
.malloc(numBytes
);
352 memmove(cdata
.Data
, outp
, numBytes
);
353 cdata
.Length
= numBytes
;
358 /* curveParams : CryptKit <--> FEECurveParametersASN1 */
359 /* Only known exception is a feeException */
360 static void feeCurveParamsToASN1(
361 const curveParams
*cp
,
362 FEECurveParametersASN1
&asnCp
,
365 #if PRINT_CURVE_PARAMS
366 printf("===encoding curveParams; cp:\n"); printCurveParams(cp
);
368 memset(&asnCp
, 0, sizeof(asnCp
));
370 intToCssmData(cp
->primeType
, asnCp
.primeType
, coder
);
371 intToCssmData(cp
->curveType
, asnCp
.curveType
, coder
);
372 intToCssmData(cp
->q
, asnCp
.q
, coder
);
373 intToCssmData(cp
->k
, asnCp
.k
, coder
);
374 intToCssmData(cp
->m
, asnCp
.m
, coder
);
375 giantToCssmData(cp
->a
, asnCp
.a
, coder
);
376 giantToCssmData(cp
->b
, asnCp
.b_
, coder
);
377 giantToCssmData(cp
->c
, asnCp
.c
, coder
);
378 giantToCssmData(cp
->x1Plus
, asnCp
.x1Plus
, coder
);
379 giantToCssmData(cp
->x1Minus
, asnCp
.x1Minus
, coder
);
380 giantToCssmData(cp
->cOrderPlus
, asnCp
.cOrderPlus
, coder
);
381 giantToCssmData(cp
->cOrderMinus
, asnCp
.cOrderMinus
, coder
);
382 giantToCssmData(cp
->x1OrderPlus
, asnCp
.x1OrderPlus
, coder
);
383 giantToCssmData(cp
->x1OrderMinus
, asnCp
.x1OrderMinus
, coder
);
384 if(cp
->primeType
== FPT_General
) {
385 giantToCssmData(cp
->basePrime
, asnCp
.basePrime
, coder
);
388 catch(const feeException
&ferr
) {
392 feeException::throwMe(FR_Memory
, "feeCurveParamsToSnacc catchall"); // ???
396 static curveParams
*feeCurveParamsFromAsn1(
397 const FEECurveParametersASN1
&asnCp
)
399 curveParams
*cp
= newCurveParams();
401 feeException::throwMe(FR_Memory
, "feeCurveParamsFromSnacc alloc cp");
403 cp
->primeType
= (feePrimeType
)cssmDataToInt(asnCp
.primeType
);
404 cp
->curveType
= (feeCurveType
)cssmDataToInt(asnCp
.curveType
);
405 cp
->q
= cssmDataToInt(asnCp
.q
);
406 cp
->k
= cssmDataToInt(asnCp
.k
);
407 cp
->m
= cssmDataToInt(asnCp
.m
);
408 cp
->a
= cssmDataToGiant(asnCp
.a
);
409 cp
->b
= cssmDataToGiant(asnCp
.b_
);
410 cp
->c
= cssmDataToGiant(asnCp
.c
);
411 cp
->x1Plus
= cssmDataToGiant(asnCp
.x1Plus
);
412 cp
->x1Minus
= cssmDataToGiant(asnCp
.x1Minus
);
413 cp
->cOrderPlus
= cssmDataToGiant(asnCp
.cOrderPlus
);
414 cp
->cOrderMinus
= cssmDataToGiant(asnCp
.cOrderMinus
);
415 cp
->x1OrderPlus
= cssmDataToGiant(asnCp
.x1OrderPlus
);
416 cp
->x1OrderMinus
= cssmDataToGiant(asnCp
.x1OrderMinus
);
417 if(asnCp
.basePrime
.Data
!= NULL
) {
418 cp
->basePrime
= cssmDataToGiant(asnCp
.basePrime
);
421 /* remaining fields inferred */
422 curveParamsInferFields(cp
);
423 allocRecipGiants(cp
);
424 #if PRINT_CURVE_PARAMS
425 printf("===decoding curveParams; cp:\n"); printCurveParams(cp
);
431 *** Public routines. These are usable from C code; they never throw.
435 * Encode/decode the two FEE signature types. We malloc returned data via
436 * fmalloc(); caller must free via ffree().
438 feeReturn
feeDEREncodeElGamalSignature(
441 unsigned char **encodedSig
, // fmallocd and RETURNED
442 unsigned *encodedSigLen
) // RETURNED
444 /* convert to FEEElGamalSignatureASN1 */
445 FEEElGamalSignatureASN1 asnSig
;
449 giantToCssmData(u
, asnSig
.u
, coder
);
450 giantToCssmData(PmX
, asnSig
.pmX
, coder
);
452 catch(const feeException
&ferr
) {
458 CSSM_DATA encBlob
; // mallocd by coder
459 perr
= coder
.encodeItem(&asnSig
, FEEElGamalSignatureASN1Template
, encBlob
);
464 /* copy out to caller */
465 *encodedSig
= (unsigned char *)fmalloc(encBlob
.Length
);
466 *encodedSigLen
= encBlob
.Length
;
467 memmove(*encodedSig
, encBlob
.Data
, encBlob
.Length
);
470 printf("feeEncodeElGamalSignature:\n");
471 printf(" u : "); printGiantHex(u
);
472 printf(" PmX : "); printGiantHex(PmX
);
478 feeReturn
feeDEREncodeECDSASignature(
481 unsigned char **encodedSig
, // fmallocd and RETURNED
482 unsigned *encodedSigLen
) // RETURNED
484 /* convert to FEEECDSASignatureASN1 */
485 FEEECDSASignatureASN1 asnSig
;
489 giantToCssmData(c
, asnSig
.c
, coder
);
490 giantToCssmData(d
, asnSig
.d
, coder
);
492 catch(const feeException
&ferr
) {
498 CSSM_DATA encBlob
; // mallocd by coder
499 perr
= coder
.encodeItem(&asnSig
, FEEECDSASignatureASN1Template
, encBlob
);
504 /* copy out to caller */
505 *encodedSig
= (unsigned char *)fmalloc(encBlob
.Length
);
506 *encodedSigLen
= encBlob
.Length
;
507 memmove(*encodedSig
, encBlob
.Data
, encBlob
.Length
);
510 printf("feeEncodeECDSASignature:\n");
511 printf(" c : "); printGiantHex(*c
);
512 printf(" d : "); printGiantHex(*d
);
518 feeReturn
feeDERDecodeElGamalSignature(
519 const unsigned char *encodedSig
,
520 unsigned encodedSigLen
,
521 giant
*u
, // newGiant'd and RETURNED
522 giant
*PmX
) // newGiant'd and RETURNED
524 FEEElGamalSignatureASN1 asnSig
;
527 memset(&asnSig
, 0, sizeof(asnSig
));
528 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
529 FEEElGamalSignatureASN1Template
, &asnSig
);
531 return FR_BadSignatureFormat
;
535 *u
= cssmDataToGiant(asnSig
.u
);
536 *PmX
= cssmDataToGiant(asnSig
.pmX
);
538 catch(const feeException
&ferr
) {
542 /* FIXME - bad sig? memory? */
546 printf("feeDecodeElGamalSignature:\n");
547 printf(" u : "); printGiantHex(*u
);
548 printf(" PmX : "); printGiantHex(*PmX
);
553 feeReturn
feeDERDecodeECDSASignature(
554 const unsigned char *encodedSig
,
555 unsigned encodedSigLen
,
556 giant
*c
, // newGiant'd and RETURNED
557 giant
*d
) // newGiant'd and RETURNED
559 FEEECDSASignatureASN1 asnSig
;
562 memset(&asnSig
, 0, sizeof(asnSig
));
563 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
564 FEEECDSASignatureASN1Template
, &asnSig
);
566 return FR_BadSignatureFormat
;
570 *c
= cssmDataToGiant(asnSig
.c
);
571 *d
= cssmDataToGiant(asnSig
.d
);
573 catch(const feeException
&ferr
) {
577 /* FIXME - bad sig? memory? */
581 printf("feeDERDecodeECDSASignature:\n");
582 printf(" u : "); printGiantHex(*u
);
583 printf(" PmX : "); printGiantHex(*PmX
);
589 * Encode/decode the FEE private and public keys. We malloc returned data via
590 * falloc(); caller must free via ffree(). Public C functions which never throw.
592 feeReturn
feeDEREncodePublicKey(
594 const curveParams
*cp
,
597 giant plusY
, // may be NULL
598 unsigned char **keyBlob
, // fmallocd and RETURNED
599 unsigned *keyBlobLen
) // RETURNED
601 FEEPublicKeyASN1 asnKey
;
604 memset(&asnKey
, 0, sizeof(asnKey
));
605 intToCssmData(version
, asnKey
.version
, coder
);
608 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
609 giantToCssmData(plusX
, asnKey
.plusX
, coder
);
610 giantToCssmData(minusX
, asnKey
.minusX
, coder
);
612 giantToCssmData(plusY
, asnKey
.plusY
, coder
);
615 catch(const feeException
&ferr
) {
621 CSSM_DATA encBlob
; // mallocd by coder
622 perr
= coder
.encodeItem(&asnKey
, FEEPublicKeyASN1Template
, encBlob
);
628 *keyBlob
= (unsigned char *)fmalloc(encBlob
.Length
);
629 *keyBlobLen
= encBlob
.Length
;
630 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
634 feeReturn
feeDEREncodePrivateKey(
636 const curveParams
*cp
,
637 const giant privData
,
638 unsigned char **keyBlob
, // fmallocd and RETURNED
639 unsigned *keyBlobLen
) // RETURNED
641 FEEPrivateKeyASN1 asnKey
;
644 memset(&asnKey
, 0, sizeof(asnKey
));
645 intToCssmData(version
, asnKey
.version
, coder
);
648 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
649 giantToCssmData(privData
, asnKey
.privData
, coder
);
651 catch(const feeException
&ferr
) {
657 CSSM_DATA encBlob
; // mallocd by coder
658 perr
= coder
.encodeItem(&asnKey
, FEEPrivateKeyASN1Template
, encBlob
);
664 *keyBlob
= (unsigned char *)fmalloc(encBlob
.Length
);
665 *keyBlobLen
= encBlob
.Length
;
666 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
670 feeReturn
feeDERDecodePublicKey(
671 const unsigned char *keyBlob
,
673 int *version
, // this and remainder RETURNED
677 giant
*plusY
) // may be NULL
679 FEEPublicKeyASN1 asnKey
;
682 memset(&asnKey
, 0, sizeof(asnKey
));
683 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
684 FEEPublicKeyASN1Template
, &asnKey
);
686 return FR_BadKeyBlob
;
690 *version
= cssmDataToInt(asnKey
.version
);
691 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
692 *plusX
= cssmDataToGiant(asnKey
.plusX
);
693 *minusX
= cssmDataToGiant(asnKey
.minusX
);
694 if(asnKey
.plusY
.Data
!= NULL
) {
696 *plusY
= cssmDataToGiant(asnKey
.plusY
);
699 *plusY
= newGiant(1);
700 int_to_giant(0, *plusY
);
703 catch(const feeException
&ferr
) {
707 /* FIXME - bad sig? memory? */
713 feeReturn
feeDERDecodePrivateKey(
714 const unsigned char *keyBlob
,
716 int *version
, // this and remainder RETURNED
718 giant
*privData
) // RETURNED
720 FEEPrivateKeyASN1 asnKey
;
723 memset(&asnKey
, 0, sizeof(asnKey
));
724 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
725 FEEPrivateKeyASN1Template
, &asnKey
);
727 return FR_BadKeyBlob
;
731 *version
= cssmDataToInt(asnKey
.version
);
732 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
733 *privData
= cssmDataToGiant(asnKey
.privData
);
735 catch(const feeException
&ferr
) {
739 /* FIXME - bad sig? memory? */
745 #endif /* CRYPTKIT_CSP_ENABLE */