2 * Copyright (c) 2000-2001,2011-2012,2014 Apple 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
27 #if CRYPTKIT_DER_ENABLE
29 #include <security_cryptkit/CryptKitDER.h>
30 #include <security_cryptkit/falloc.h>
31 #include <security_cryptkit/feeDebug.h>
32 #include <security_cryptkit/feeFunctions.h>
33 #include <security_cryptkit/ckutilities.h>
34 #include "CryptKitAsn1.h"
35 #include <security_asn1/SecNssCoder.h>
36 #include <security_asn1/nssUtils.h>
37 #include <Security/keyTemplates.h>
38 #include <Security/oidsalg.h>
39 #include <Security/oidsattr.h>
41 #define PRINT_SIG_GIANTS 0
42 #define PRINT_CURVE_PARAMS 0
45 #define szprint(s) printf s
51 * Trivial exception class associated with a feeReturn.
56 feeException(feeReturn frtn
, const char *op
);
58 ~feeException() throw() {}
59 feeReturn
frtn() const throw() { return mFrtn
; }
60 static void throwMe(feeReturn frtn
, const char *op
= NULL
) __attribute__((noreturn
));
65 feeException::feeException(
71 dbgLog(("%s: %s\n", op
, feeReturnString(frtn
)));
75 void feeException::throwMe(feeReturn frtn
, const char *op
/*= NULL*/) { throw feeException(frtn
, op
); }
78 * ASN1 encoding rules specify that an integer's sign is indicated by the MSB
79 * of the first (MS) content byte. For a non-negative number, if the MSB of
80 * the MS byte (of the unencoded number) is one, then the encoding starts with
81 * a byte of zeroes to indicate positive sign. For a negative number, the first
82 * nine bits can not be all 1 - if they are (in the undecoded number), leading
83 * bytes of 0xff are trimmed off until the first nine bits are something other
84 * than one. Also, the first nine bits of the encoded number can not all be
87 * CryptKit giants express their sign as part of the giantstruct.sign field.
88 * The giantDigit array (giantstruct.n[]) is stored l.s. digit first.
90 * These routines are independent of platform, endianness, and giatn digit size.
93 /* routines to guess maximum size of DER-encoded objects */
94 static unsigned feeSizeOfSnaccGiant(
97 unsigned rtn
= abs(g
->sign
) * GIANT_BYTES_PER_DIGIT
;
98 szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g
->sign
, rtn
+ 4));
103 unsigned feeSizeOfDERSig(
107 unsigned rtn
= feeSizeOfSnaccGiant(g1
);
108 rtn
+= feeSizeOfSnaccGiant(g2
);
109 szprint(("feeSizeOfDERSig: size %d\n", rtn
+ 4));
113 /* perform 2's complement of byte array, expressed MS byte first */
114 static void twosComplement(
115 unsigned char *bytePtr
, // points to MS byte
118 unsigned char *outp
= bytePtr
+ numBytes
- 1;
119 unsigned char carry
= 1; // first time thru, carry = 1 to add one to 1's comp
120 for(unsigned byteDex
=0; byteDex
<numBytes
; byteDex
++) {
121 /* first complement, then add carry */
122 *outp
= ~*outp
+ carry
;
123 if(carry
&& (*outp
== 0)) {
135 * CSSM_DATA --> unsigned int
137 static unsigned cssmDataToInt(
138 const CSSM_DATA
&cdata
)
140 if((cdata
.Length
== 0) || (cdata
.Data
== NULL
)) {
143 unsigned len
= (unsigned)cdata
.Length
;
144 if(len
> sizeof(int)) {
145 feeException::throwMe(FR_BadKeyBlob
, "cssmDataToInt");
149 uint8
*cp
= cdata
.Data
;
150 for(unsigned i
=0; i
<len
; i
++) {
151 rtn
= (rtn
<< 8) | *cp
++;
157 * unsigned int --> CSSM_DATA, mallocing from an SecNssCoder
159 static void intToCssmData(
169 else if(num
< 0x10000) {
172 else if(num
< 0x1000000) {
178 cdata
.Data
= (uint8
*)coder
.malloc(len
);
180 uint8
*cp
= &cdata
.Data
[len
- 1];
181 for(unsigned i
=0; i
<len
; i
++) {
188 * Convert a decoded ASN integer, as a CSSM_DATA, to a (mallocd) giant.
189 * Only known exception is a feeException.
191 static giant
cssmDataToGiant(
192 const CSSM_DATA
&cdata
)
194 char *rawOcts
= (char *)cdata
.Data
;
195 unsigned numBytes
= (unsigned)cdata
.Length
;
196 unsigned numGiantDigits
;
199 feeReturn frtn
= FR_Success
;
200 unsigned char *inp
= NULL
;
201 unsigned digitDex
; // index into g->giantDigit[]
203 /* handle degenerate case (value of zero) */
204 if((numBytes
== 0) || ((numBytes
== 1) && rawOcts
[0] == 0)) {
207 feeException::throwMe(FR_Memory
, "newGiant(1)");
209 int_to_giant(0, grtn
);
213 /* make a copy of raw octets if we have to do two's complement */
214 unsigned char *byteArray
= NULL
;
215 bool didMalloc
= false;
216 if(rawOcts
[0] & 0x80) {
219 byteArray
= (unsigned char *)fmalloc(numBytes
);
222 memmove(byteArray
+ 1, rawOcts
, numBytes
-1);
223 twosComplement(byteArray
, numBytes
);
228 byteArray
= (unsigned char *)foo
;
231 /* cook up a new giant */
232 numGiantDigits
= (numBytes
+ GIANT_BYTES_PER_DIGIT
- 1) /
233 GIANT_BYTES_PER_DIGIT
;
234 grtn
= newGiant(numGiantDigits
);
241 * Convert byteArray to array of giantDigits
242 * inp - raw input bytes, LSB last
243 * grtn->n[] - output array of giantDigits, LSD first
244 * Start at LS byte and LD digit
246 digitDex
= 0; // index into g->giantDigit[]
247 giantDigit thisDigit
;
248 inp
= byteArray
+ numBytes
- 1;
249 unsigned dex
; // total byte counter
250 unsigned byteDex
; // index into one giantDigit
252 for(dex
=0; dex
<numBytes
; ) { // increment dex inside
255 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
256 thisDigit
|= ((giantDigit
)(*inp
--) << shiftCount
);
258 if(++dex
== numBytes
) {
259 /* must be partial giantDigit */
263 CKASSERT(digitDex
< numGiantDigits
);
264 grtn
->n
[digitDex
++] = thisDigit
;
266 grtn
->sign
= (int)numGiantDigits
* sign
;
268 /* trim leading (MS) zeroes */
275 feeException::throwMe(frtn
, "bigIntStrToGiant");
281 * Convert a giant to an CSSM_DATA, mallocing using specified coder.
282 * Only known exception is a feeException.
284 static void giantToCssmData(
289 unsigned char doPrepend
= 0;
290 unsigned numGiantDigits
= abs(g
->sign
);
291 unsigned numBytes
= numGiantDigits
* GIANT_BYTES_PER_DIGIT
;
292 giantDigit msGiantBit
= 0;
294 /* special degenerate case */
295 intToCssmData(0, cdata
, coder
);
299 msGiantBit
= g
->n
[numGiantDigits
- 1] >> (GIANT_BITS_PER_DIGIT
- 1);
302 /* prepend a byte of zero if necessary */
303 if((g
->sign
< 0) || // negative - to handle 2's complement
304 ((g
->sign
> 0) && msGiantBit
)) { // ensure MS byte is zero
309 unsigned char *rawBytes
= (unsigned char *)fmalloc(numBytes
);
310 if(rawBytes
== NULL
) {
311 feeException::throwMe(FR_Memory
, "giantToCssmData fmalloc(rawBytes)");
313 unsigned char *outp
= rawBytes
;
319 * Convert array of giantDigits to bytes.
320 * outp point to MS output byte.
322 int digitDex
; // index into g->giantDigit[]
323 unsigned byteDex
; // byte index into a giantDigit
324 for(digitDex
=numGiantDigits
-1; digitDex
>=0; digitDex
--) {
325 /* one loop per giantDigit, starting at MS end */
326 giantDigit thisDigit
= g
->n
[digitDex
];
327 unsigned char *bp
= outp
+ GIANT_BYTES_PER_DIGIT
- 1;
328 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
329 /* one loop per byte within the digit, starting at LS end */
330 *bp
-- = (unsigned char)(thisDigit
) & 0xff;
333 outp
+= GIANT_BYTES_PER_DIGIT
;
336 /* do two's complement for negative giants */
338 twosComplement(rawBytes
, numBytes
);
341 /* strip off redundant leading bits (nine zeroes or nine ones) */
343 unsigned char *endp
= outp
+ numBytes
- 1;
344 while((*outp
== 0) && // m.s. byte zero
345 (outp
< endp
) && // more bytes exist
346 (!(outp
[1] & 0x80))) { // 9th bit is 0
350 while((*outp
== 0xff) && // m.s. byte all ones
351 (outp
< endp
) && // more bytes exist
352 (outp
[1] & 0x80)) { // 9th bit is 1
356 cdata
.Data
= (uint8
*)coder
.malloc(numBytes
);
357 memmove(cdata
.Data
, outp
, numBytes
);
358 cdata
.Length
= numBytes
;
363 /* curveParams : CryptKit <--> FEECurveParametersASN1 */
364 /* Only known exception is a feeException */
365 static void feeCurveParamsToASN1(
366 const curveParams
*cp
,
367 FEECurveParametersASN1
&asnCp
,
370 #if PRINT_CURVE_PARAMS
371 printf("===encoding curveParams; cp:\n"); printCurveParams(cp
);
373 memset(&asnCp
, 0, sizeof(asnCp
));
375 intToCssmData(cp
->primeType
, asnCp
.primeType
, coder
);
376 intToCssmData(cp
->curveType
, asnCp
.curveType
, coder
);
377 intToCssmData(cp
->q
, asnCp
.q
, coder
);
378 intToCssmData(cp
->k
, asnCp
.k
, coder
);
379 intToCssmData(cp
->m
, asnCp
.m
, coder
);
380 giantToCssmData(cp
->a
, asnCp
.a
, coder
);
381 giantToCssmData(cp
->b
, asnCp
.b_
, coder
);
382 giantToCssmData(cp
->c
, asnCp
.c
, coder
);
383 giantToCssmData(cp
->x1Plus
, asnCp
.x1Plus
, coder
);
384 giantToCssmData(cp
->x1Minus
, asnCp
.x1Minus
, coder
);
385 giantToCssmData(cp
->cOrderPlus
, asnCp
.cOrderPlus
, coder
);
386 giantToCssmData(cp
->cOrderMinus
, asnCp
.cOrderMinus
, coder
);
387 giantToCssmData(cp
->x1OrderPlus
, asnCp
.x1OrderPlus
, coder
);
388 giantToCssmData(cp
->x1OrderMinus
, asnCp
.x1OrderMinus
, coder
);
389 if(cp
->primeType
== FPT_General
) {
390 giantToCssmData(cp
->basePrime
, asnCp
.basePrime
, coder
);
393 catch(const feeException
&ferr
) {
397 feeException::throwMe(FR_Memory
, "feeCurveParamsToSnacc catchall"); // ???
401 static curveParams
*feeCurveParamsFromAsn1(
402 const FEECurveParametersASN1
&asnCp
)
404 curveParams
*cp
= newCurveParams();
406 feeException::throwMe(FR_Memory
, "feeCurveParamsFromSnacc alloc cp");
408 cp
->primeType
= (feePrimeType
)cssmDataToInt(asnCp
.primeType
);
409 cp
->curveType
= (feeCurveType
)cssmDataToInt(asnCp
.curveType
);
410 cp
->q
= cssmDataToInt(asnCp
.q
);
411 cp
->k
= cssmDataToInt(asnCp
.k
);
412 cp
->m
= cssmDataToInt(asnCp
.m
);
413 cp
->a
= cssmDataToGiant(asnCp
.a
);
414 cp
->b
= cssmDataToGiant(asnCp
.b_
);
415 cp
->c
= cssmDataToGiant(asnCp
.c
);
416 cp
->x1Plus
= cssmDataToGiant(asnCp
.x1Plus
);
417 cp
->x1Minus
= cssmDataToGiant(asnCp
.x1Minus
);
418 cp
->cOrderPlus
= cssmDataToGiant(asnCp
.cOrderPlus
);
419 cp
->cOrderMinus
= cssmDataToGiant(asnCp
.cOrderMinus
);
420 cp
->x1OrderPlus
= cssmDataToGiant(asnCp
.x1OrderPlus
);
421 cp
->x1OrderMinus
= cssmDataToGiant(asnCp
.x1OrderMinus
);
422 if(asnCp
.basePrime
.Data
!= NULL
) {
423 cp
->basePrime
= cssmDataToGiant(asnCp
.basePrime
);
426 /* remaining fields inferred */
427 curveParamsInferFields(cp
);
428 allocRecipGiants(cp
);
429 #if PRINT_CURVE_PARAMS
430 printf("===decoding curveParams; cp:\n"); printCurveParams(cp
);
436 *** Public routines. These are usable from C code; they never throw.
440 * Encode/decode the two FEE signature types. We malloc returned data via
441 * fmalloc(); caller must free via ffree().
443 feeReturn
feeDEREncodeElGamalSignature(
446 unsigned char **encodedSig
, // fmallocd and RETURNED
447 unsigned *encodedSigLen
) // RETURNED
449 /* convert to FEEElGamalSignatureASN1 */
450 FEEElGamalSignatureASN1 asnSig
;
454 giantToCssmData(u
, asnSig
.u
, coder
);
455 giantToCssmData(PmX
, asnSig
.pmX
, coder
);
457 catch(const feeException
&ferr
) {
463 CSSM_DATA encBlob
; // mallocd by coder
464 perr
= coder
.encodeItem(&asnSig
, FEEElGamalSignatureASN1Template
, encBlob
);
469 /* copy out to caller */
470 *encodedSig
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
471 *encodedSigLen
= (unsigned)encBlob
.Length
;
472 memmove(*encodedSig
, encBlob
.Data
, encBlob
.Length
);
475 printf("feeEncodeElGamalSignature:\n");
476 printf(" u : "); printGiantHex(u
);
477 printf(" PmX : "); printGiantHex(PmX
);
484 * Encode a DER formatted ECDSA signature
486 feeReturn
feeDEREncodeECDSASignature(
489 unsigned char **encodedSig
, // fmallocd and RETURNED
490 unsigned *encodedSigLen
) // RETURNED
492 /* convert to FEEECDSASignatureASN1 */
493 FEEECDSASignatureASN1 asnSig
;
497 giantToCssmData(c
, asnSig
.c
, coder
);
498 giantToCssmData(d
, asnSig
.d
, coder
);
500 catch(const feeException
&ferr
) {
506 CSSM_DATA encBlob
; // mallocd by coder
507 perr
= coder
.encodeItem(&asnSig
, FEEECDSASignatureASN1Template
, encBlob
);
512 /* copy out to caller */
513 *encodedSig
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
514 *encodedSigLen
= (unsigned)encBlob
.Length
;
515 memmove(*encodedSig
, encBlob
.Data
, encBlob
.Length
);
518 printf("feeDEREncodeECDSASignature:\n");
519 printf(" c : "); printGiantHex(c
);
520 printf(" d : "); printGiantHex(d
);
527 static void printHex(
528 const unsigned char *buf
,
532 bool doEllipsis
= false;
538 for(dex
=0; dex
<len
; dex
++) {
539 printf("%02X ", *buf
++);
548 * Encode a RAW formatted ECDSA signature
550 feeReturn
feeRAWEncodeECDSASignature(unsigned groupBytesLen
,
553 unsigned char **encodedSig
, // fmallocd and RETURNED
554 unsigned *encodedSigLen
) // RETURNED
556 /* copy out to caller */
557 *encodedSig
= (unsigned char *)fmalloc(2*groupBytesLen
);
558 *encodedSigLen
= (unsigned)2*groupBytesLen
;
560 /* convert to FEEECDSASignatureASN1 */
562 serializeGiant(c
, *encodedSig
, groupBytesLen
);
563 serializeGiant(d
, *encodedSig
+groupBytesLen
, groupBytesLen
);
565 catch(const feeException
&ferr
) {
570 printf("feeRAWEncodeECDSASignature:\n");
571 printf(" c : "); printGiantHex(c
);
572 printf(" d : "); printGiantHex(d
);
573 printf(" sig : "); printHex(*encodedSig
,*encodedSigLen
,512);
579 feeReturn
feeDERDecodeElGamalSignature(
580 const unsigned char *encodedSig
,
581 size_t encodedSigLen
,
582 giant
*u
, // newGiant'd and RETURNED
583 giant
*PmX
) // newGiant'd and RETURNED
585 FEEElGamalSignatureASN1 asnSig
;
588 memset(&asnSig
, 0, sizeof(asnSig
));
589 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
590 FEEElGamalSignatureASN1Template
, &asnSig
);
592 return FR_BadSignatureFormat
;
596 *u
= cssmDataToGiant(asnSig
.u
);
597 *PmX
= cssmDataToGiant(asnSig
.pmX
);
599 catch(const feeException
&ferr
) {
603 /* FIXME - bad sig? memory? */
607 printf("feeDecodeElGamalSignature:\n");
608 printf(" u : "); printGiantHex(*u
);
609 printf(" PmX : "); printGiantHex(*PmX
);
615 * Decode a DER formatted ECDSA signature
617 feeReturn
feeDERDecodeECDSASignature(
618 const unsigned char *encodedSig
,
619 size_t encodedSigLen
,
620 giant
*c
, // newGiant'd and RETURNED
621 giant
*d
) // newGiant'd and RETURNED
623 FEEECDSASignatureASN1 asnSig
;
626 memset(&asnSig
, 0, sizeof(asnSig
));
627 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
628 FEEECDSASignatureASN1Template
, &asnSig
);
630 return FR_BadSignatureFormat
;
634 *c
= cssmDataToGiant(asnSig
.c
);
635 *d
= cssmDataToGiant(asnSig
.d
);
637 catch(const feeException
&ferr
) {
641 /* FIXME - bad sig? memory? */
645 printf("feeDERDecodeECDSASignature:\n");
646 printf(" c : "); printGiantHex(*c
);
647 printf(" d : "); printGiantHex(*d
);
653 * Decode a RAW formatted ECDSA signature
655 feeReturn
feeRAWDecodeECDSASignature(unsigned groupBytesLen
,
656 const unsigned char *encodedSig
,
657 size_t encodedSigLen
,
658 giant
*c
, // newGiant'd and RETURNED
659 giant
*d
) // newGiant'd and RETURNED
663 if (((encodedSigLen
& 1) == 1) || (groupBytesLen
!= (encodedSigLen
>>1))) {
664 return FR_BadSignatureFormat
;
668 *c
= giant_with_data((uint8_t*)encodedSig
,(int)groupBytesLen
);
669 *d
= giant_with_data((uint8_t*)encodedSig
+groupBytesLen
, (int)groupBytesLen
);
671 catch(const feeException
&ferr
) {
675 /* FIXME - bad sig? memory? */
679 printf("feeRAWDecodeECDSASignature:\n");
680 printf(" c : "); printGiantHex(*c
);
681 printf(" d : "); printGiantHex(*d
);
687 * Encode/decode the FEE private and public keys. We malloc returned data via
688 * falloc(); caller must free via ffree(). Public C functions which never throw.
690 feeReturn
feeDEREncodePublicKey(
692 const curveParams
*cp
,
695 giant plusY
, // may be NULL
696 unsigned char **keyBlob
, // fmallocd and RETURNED
697 unsigned *keyBlobLen
) // RETURNED
699 FEEPublicKeyASN1 asnKey
;
702 memset(&asnKey
, 0, sizeof(asnKey
));
703 intToCssmData(version
, asnKey
.version
, coder
);
706 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
707 giantToCssmData(plusX
, asnKey
.plusX
, coder
);
708 giantToCssmData(minusX
, asnKey
.minusX
, coder
);
710 giantToCssmData(plusY
, asnKey
.plusY
, coder
);
713 catch(const feeException
&ferr
) {
719 CSSM_DATA encBlob
; // mallocd by coder
720 perr
= coder
.encodeItem(&asnKey
, FEEPublicKeyASN1Template
, encBlob
);
726 *keyBlob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
727 *keyBlobLen
= (unsigned)encBlob
.Length
;
728 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
732 feeReturn
feeDEREncodePrivateKey(
734 const curveParams
*cp
,
735 const giant privData
,
736 unsigned char **keyBlob
, // fmallocd and RETURNED
737 unsigned *keyBlobLen
) // RETURNED
739 FEEPrivateKeyASN1 asnKey
;
742 memset(&asnKey
, 0, sizeof(asnKey
));
743 intToCssmData(version
, asnKey
.version
, coder
);
746 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
747 giantToCssmData(privData
, asnKey
.privData
, coder
);
749 catch(const feeException
&ferr
) {
755 CSSM_DATA encBlob
; // mallocd by coder
756 perr
= coder
.encodeItem(&asnKey
, FEEPrivateKeyASN1Template
, encBlob
);
762 *keyBlob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
763 *keyBlobLen
= (unsigned)encBlob
.Length
;
764 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
768 feeReturn
feeDERDecodePublicKey(
769 const unsigned char *keyBlob
,
771 int *version
, // this and remainder RETURNED
775 giant
*plusY
) // may be NULL
777 FEEPublicKeyASN1 asnKey
;
780 memset(&asnKey
, 0, sizeof(asnKey
));
781 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
782 FEEPublicKeyASN1Template
, &asnKey
);
784 return FR_BadKeyBlob
;
788 *version
= cssmDataToInt(asnKey
.version
);
789 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
790 *plusX
= cssmDataToGiant(asnKey
.plusX
);
791 *minusX
= cssmDataToGiant(asnKey
.minusX
);
792 if(asnKey
.plusY
.Data
!= NULL
) {
794 *plusY
= cssmDataToGiant(asnKey
.plusY
);
797 *plusY
= newGiant(1);
798 int_to_giant(0, *plusY
);
801 catch(const feeException
&ferr
) {
805 /* FIXME - bad sig? memory? */
811 feeReturn
feeDERDecodePrivateKey(
812 const unsigned char *keyBlob
,
814 int *version
, // this and remainder RETURNED
816 giant
*privData
) // RETURNED
818 FEEPrivateKeyASN1 asnKey
;
821 memset(&asnKey
, 0, sizeof(asnKey
));
822 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
823 FEEPrivateKeyASN1Template
, &asnKey
);
825 return FR_BadKeyBlob
;
829 *version
= cssmDataToInt(asnKey
.version
);
830 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
831 *privData
= cssmDataToGiant(asnKey
.privData
);
833 catch(const feeException
&ferr
) {
837 /* FIXME - bad sig? memory? */
843 #pragma mark --- ECDSA support ---
845 /* convert between feeDepth and curve OIDs */
846 static const CSSM_OID
*depthToOid(
850 case FEE_DEPTH_secp192r1
:
851 return &CSSMOID_secp192r1
;
852 case FEE_DEPTH_secp256r1
:
853 return &CSSMOID_secp256r1
;
854 case FEE_DEPTH_secp384r1
:
855 return &CSSMOID_secp384r1
;
856 case FEE_DEPTH_secp521r1
:
857 return &CSSMOID_secp521r1
;
859 dbgLog(("depthToOid needs work\n"));
864 static feeReturn
curveOidToFeeDepth(
865 const CSSM_OID
*curveOid
,
866 feeDepth
*depth
) /* RETURNED */
868 if(nssCompareCssmData(curveOid
, &CSSMOID_secp192r1
)) {
869 *depth
= FEE_DEPTH_secp192r1
;
871 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp256r1
)) {
872 *depth
= FEE_DEPTH_secp256r1
;
874 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp384r1
)) {
875 *depth
= FEE_DEPTH_secp384r1
;
877 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp521r1
)) {
878 *depth
= FEE_DEPTH_secp521r1
;
881 dbgLog(("curveOidToFeeDepth: unknown curve OID\n"));
882 return FR_BadKeyBlob
;
889 * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer
890 * depth from its algorith.parameter
892 static feeReturn
feeAlgIdToDepth(
893 const CSSM_X509_ALGORITHM_IDENTIFIER
*algId
,
896 const CSSM_OID
*oid
= &algId
->algorithm
;
897 /* FIXME what's the value here for a private key!? */
898 if(!nssCompareCssmData(oid
, &CSSMOID_ecPublicKey
)) {
899 dbgLog(("feeAlgIdToDepth: bad OID"));
900 return FR_BadKeyBlob
;
904 * AlgId.params is curve OID, still encoded since it's an ASN_ANY.
905 * First two bytes of encoded OID are (06, length)
907 const CSSM_DATA
*param
= &algId
->parameters
;
908 if((param
->Length
<= 2) || (param
->Data
[0] != BER_TAG_OID
)) {
909 dbgLog(("feeAlgIdToDepth: no curve params\n"));
910 return FR_BadKeyBlob
;
913 CSSM_OID decOid
= {param
->Length
-2, algId
->parameters
.Data
+2};
914 return curveOidToFeeDepth(&decOid
, depth
);
918 * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding.
920 static feeReturn
feeSetupAlgId(
923 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
)
925 algId
.algorithm
= CSSMOID_ecPublicKey
;
926 const CSSM_OID
*curveOid
= depthToOid(depth
);
927 if(curveOid
== NULL
) {
928 return FR_IllegalDepth
;
931 /* quick & dirty encode of the parameter OID; it's an ASN_ANY in the template */
932 coder
.allocItem(algId
.parameters
, curveOid
->Length
+ 2);
933 algId
.parameters
.Data
[0] = BER_TAG_OID
;
934 algId
.parameters
.Data
[1] = curveOid
->Length
;
935 memmove(algId
.parameters
.Data
+2, curveOid
->Data
, curveOid
->Length
);
939 #pragma mark --- ECDSA public key, X.509 format ---
942 * Encode/decode public key in X.509 format.
944 feeReturn
feeDEREncodeX509PublicKey(
945 const unsigned char *pubBlob
, /* x and y octet string */
948 unsigned char **x509Blob
, /* fmallocd and RETURNED */
949 unsigned *x509BlobLen
) /* RETURNED */
952 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo
;
954 memset(&nssPubKeyInfo
, 0, sizeof(nssPubKeyInfo
));
956 /* The x/y string, to be encoded in a bit string */
957 nssPubKeyInfo
.subjectPublicKey
.Data
= (uint8
*)pubBlob
;
958 nssPubKeyInfo
.subjectPublicKey
.Length
= pubBlobLen
* 8;
961 feeReturn frtn
= curveParamsDepth(cp
, &depth
);
963 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
967 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssPubKeyInfo
.algorithm
;
968 frtn
= feeSetupAlgId(depth
, coder
, algId
);
974 CSSM_DATA encBlob
; // mallocd by coder
975 PRErrorCode perr
= coder
.encodeItem(&nssPubKeyInfo
, kSecAsn1SubjectPublicKeyInfoTemplate
, encBlob
);
981 *x509Blob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
982 *x509BlobLen
= (unsigned)encBlob
.Length
;
983 memmove(*x509Blob
, encBlob
.Data
, encBlob
.Length
);
987 feeReturn
feeDERDecodeX509PublicKey(
988 const unsigned char *x509Blob
,
989 unsigned x509BlobLen
,
990 feeDepth
*depth
, /* RETURNED */
991 unsigned char **pubBlob
, /* x and y octet string RETURNED */
992 unsigned *pubBlobLen
) /* RETURNED */
995 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo
;
998 memset(&nssPubKeyInfo
, 0, sizeof(nssPubKeyInfo
));
999 perr
= coder
.decode(x509Blob
, x509BlobLen
, kSecAsn1SubjectPublicKeyInfoTemplate
,
1002 dbgLog(("decode(SubjectPublicKeyInfo) error"));
1003 return FR_BadKeyBlob
;
1006 /* verify alg identifier & depth */
1007 feeReturn frtn
= feeAlgIdToDepth(&nssPubKeyInfo
.algorithm
, depth
);
1012 /* copy public key string - it's in bits here */
1013 CSSM_DATA
*pubKey
= &nssPubKeyInfo
.subjectPublicKey
;
1014 unsigned keyLen
=(unsigned) (pubKey
->Length
+ 7) / 8;
1015 *pubBlob
= (unsigned char *)fmalloc(keyLen
);
1016 if(*pubBlob
== NULL
) {
1019 memmove(*pubBlob
, pubKey
->Data
, keyLen
);
1020 *pubBlobLen
= keyLen
;
1024 #pragma mark --- ECDSA keys, OpenSSL format ---
1027 * Encode private, and decode private or public key, in unencrypted OpenSSL format.
1029 feeReturn
feeDEREncodeOpenSSLPrivateKey(
1030 const unsigned char *privBlob
, /* private data octet string */
1031 unsigned privBlobLen
,
1032 const unsigned char *pubBlob
, /* public key, optional */
1033 unsigned pubBlobLen
,
1035 unsigned char **openBlob
, /* fmallocd and RETURNED */
1036 unsigned *openBlobLen
) /* RETURNED */
1039 const CSSM_OID
*curveOid
;
1042 NSS_ECDSA_PrivateKey ecdsaPrivKey
;
1043 memset(&ecdsaPrivKey
, 0, sizeof(ecdsaPrivKey
));
1045 ecdsaPrivKey
.version
.Data
= &vers
;
1046 ecdsaPrivKey
.version
.Length
= 1;
1047 ecdsaPrivKey
.privateKey
.Data
= (uint8
*)privBlob
;
1048 ecdsaPrivKey
.privateKey
.Length
= privBlobLen
;
1050 /* Params - ASN_ANY - actually the curve OID */
1051 if(curveParamsDepth(cp
, &depth
)) {
1052 dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth"));
1053 return FR_BadKeyBlob
;
1055 curveOid
= depthToOid(depth
);
1056 if(curveOid
== NULL
) {
1057 return FR_BadKeyBlob
;
1060 /* quickie DER-encode of the curve OID */
1062 coder
.allocItem(ecdsaPrivKey
.params
, curveOid
->Length
+ 2);
1067 ecdsaPrivKey
.params
.Data
[0] = BER_TAG_OID
;
1068 ecdsaPrivKey
.params
.Data
[1] = curveOid
->Length
;
1069 memmove(ecdsaPrivKey
.params
.Data
+2, curveOid
->Data
, curveOid
->Length
);
1071 /* public key - optional - bit string, length in bits */
1073 ecdsaPrivKey
.pubKey
.Data
= (uint8
*)pubBlob
;
1074 ecdsaPrivKey
.pubKey
.Length
= pubBlobLen
* 8;
1077 CSSM_DATA encPriv
= {0, NULL
};
1078 PRErrorCode perr
= coder
.encodeItem(&ecdsaPrivKey
, kSecAsn1ECDSAPrivateKeyInfoTemplate
, encPriv
);
1084 *openBlob
= (unsigned char *)fmalloc((unsigned)encPriv
.Length
);
1085 *openBlobLen
= (unsigned)encPriv
.Length
;
1086 memmove(*openBlob
, encPriv
.Data
, encPriv
.Length
);
1090 feeReturn
feeDERDecodeOpenSSLKey(
1091 const unsigned char *osBlob
,
1093 feeDepth
*depth
, /* RETURNED */
1094 unsigned char **privBlob
, /* private data octet string RETURNED */
1095 unsigned *privBlobLen
, /* RETURNED */
1096 unsigned char **pubBlob
, /* public data octet string optionally RETURNED */
1097 unsigned *pubBlobLen
)
1100 NSS_ECDSA_PrivateKey ecdsaPrivKey
;
1101 memset(&ecdsaPrivKey
, 0, sizeof(ecdsaPrivKey
));
1102 if(coder
.decode(osBlob
, osBlobLen
,
1103 kSecAsn1ECDSAPrivateKeyInfoTemplate
, &ecdsaPrivKey
)) {
1104 dbgLog(("Error decoding openssl priv key\n"));
1105 return FR_BadKeyBlob
;
1108 unsigned keyLen
= (unsigned)ecdsaPrivKey
.privateKey
.Length
;
1110 dbgLog(("NULL priv key data in PKCS8\n"));
1112 *privBlob
= (unsigned char *)fmalloc(keyLen
);
1113 if(*privBlob
== NULL
) {
1116 *privBlobLen
= keyLen
;
1117 memmove(*privBlob
, ecdsaPrivKey
.privateKey
.Data
, keyLen
);
1119 /* curve OID --> depth */
1120 if(ecdsaPrivKey
.params
.Data
!= NULL
) {
1121 /* quickie decode */
1122 const CSSM_DATA
*param
= &ecdsaPrivKey
.params
;
1123 if((param
->Data
[0] != BER_TAG_OID
) || (param
->Length
<= 2)) {
1124 dbgLog(("feeDERDecodeOpenSSLKey: bad curve params\n"));
1125 return FR_BadKeyBlob
;
1127 CSSM_OID decOid
= {param
->Length
-2, param
->Data
+2};
1128 if(curveOidToFeeDepth(&decOid
, depth
)) {
1129 return FR_BadKeyBlob
;
1133 /* Public key, if it's there and caller wants it */
1134 if((ecdsaPrivKey
.pubKey
.Length
!= 0) && (pubBlob
!= NULL
)) {
1135 *pubBlobLen
= (unsigned)(ecdsaPrivKey
.pubKey
.Length
+ 7) / 8;
1136 *pubBlob
= (unsigned char *)fmalloc(*pubBlobLen
);
1137 memmove(*pubBlob
, ecdsaPrivKey
.pubKey
.Data
, *pubBlobLen
);
1142 #pragma mark --- ECDSA public key, PKCS8 format ---
1145 * Encode/decode private key in unencrypted PKCS8 format.
1147 feeReturn
feeDEREncodePKCS8PrivateKey(
1148 const unsigned char *privBlob
, /* private data octet string */
1149 unsigned privBlobLen
,
1150 const unsigned char *pubBlob
, /* public blob, optional */
1151 unsigned pubBlobLen
,
1153 unsigned char **pkcs8Blob
, /* fmallocd and RETURNED */
1154 unsigned *pkcs8BlobLen
) /* RETURNED */
1156 /* First encode a NSS_ECDSA_PrivateKey */
1157 unsigned char *encPriv
= NULL
;
1158 unsigned encPrivLen
= 0;
1159 feeReturn frtn
= feeDEREncodeOpenSSLPrivateKey(privBlob
, privBlobLen
,
1160 pubBlob
, pubBlobLen
, cp
, &encPriv
, &encPrivLen
);
1165 /* That encoding goes into NSS_PrivateKeyInfo.private key */
1167 NSS_PrivateKeyInfo nssPrivKeyInfo
;
1168 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssPrivKeyInfo
.algorithm
;
1169 memset(&nssPrivKeyInfo
, 0, sizeof(nssPrivKeyInfo
));
1170 nssPrivKeyInfo
.privateKey
.Data
= (uint8
*)encPriv
;
1171 nssPrivKeyInfo
.privateKey
.Length
= encPrivLen
;
1175 frtn
= curveParamsDepth(cp
, &depth
);
1177 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
1180 frtn
= feeSetupAlgId(depth
, coder
, algId
);
1185 nssPrivKeyInfo
.version
.Data
= &vers
;
1186 nssPrivKeyInfo
.version
.Length
= 1;
1189 CSSM_DATA encPrivInfo
; // mallocd by coder
1190 if(coder
.encodeItem(&nssPrivKeyInfo
, kSecAsn1PrivateKeyInfoTemplate
, encPrivInfo
)) {
1196 *pkcs8Blob
= (unsigned char *)fmalloc((unsigned)encPrivInfo
.Length
);
1197 *pkcs8BlobLen
= (unsigned)encPrivInfo
.Length
;
1198 memmove(*pkcs8Blob
, encPrivInfo
.Data
, encPrivInfo
.Length
);
1206 feeReturn
feeDERDecodePKCS8PrivateKey(
1207 const unsigned char *pkcs8Blob
,
1208 unsigned pkcs8BlobLen
,
1209 feeDepth
*depth
, /* RETURNED */
1210 unsigned char **privBlob
, /* private data octet string RETURNED */
1211 unsigned *privBlobLen
, /* RETURNED */
1212 unsigned char **pubBlob
, /* optionally returned, if it's there */
1213 unsigned *pubBlobLen
)
1215 NSS_PrivateKeyInfo nssPrivKeyInfo
;
1219 memset(&nssPrivKeyInfo
, 0, sizeof(nssPrivKeyInfo
));
1220 perr
= coder
.decode(pkcs8Blob
, pkcs8BlobLen
, kSecAsn1PrivateKeyInfoTemplate
, &nssPrivKeyInfo
);
1222 dbgLog(("Error decoding top level PKCS8\n"));
1223 return FR_BadKeyBlob
;
1226 /* verify alg identifier & depth */
1227 feeReturn frtn
= feeAlgIdToDepth(&nssPrivKeyInfo
.algorithm
, depth
);
1233 * nssPrivKeyInfo.privateKey is an octet string containing an encoded
1234 * NSS_ECDSA_PrivateKey.
1236 frtn
= feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo
.privateKey
.Data
,
1237 (unsigned)nssPrivKeyInfo
.privateKey
.Length
, depth
,
1238 privBlob
, privBlobLen
,
1239 pubBlob
, pubBlobLen
);
1244 #endif /* CRYPTKIT_DER_ENABLE */