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 "CryptKitAsn1.h"
34 #include <security_asn1/SecNssCoder.h>
35 #include <security_asn1/nssUtils.h>
36 #include <Security/keyTemplates.h>
37 #include <Security/oidsalg.h>
38 #include <Security/oidsattr.h>
40 #define PRINT_SIG_GIANTS 0
41 #define PRINT_CURVE_PARAMS 0
44 #define szprint(s) printf s
50 * Trivial exception class associated with a feeReturn.
55 feeException(feeReturn frtn
, const char *op
);
57 ~feeException() throw() {}
58 feeReturn
frtn() const throw() { return mFrtn
; }
59 static void throwMe(feeReturn frtn
, const char *op
= NULL
) __attribute__((noreturn
));
64 feeException::feeException(
70 dbgLog(("%s: %s\n", op
, feeReturnString(frtn
)));
74 void feeException::throwMe(feeReturn frtn
, const char *op
/*= NULL*/) { throw feeException(frtn
, op
); }
77 * ASN1 encoding rules specify that an integer's sign is indicated by the MSB
78 * of the first (MS) content byte. For a non-negative number, if the MSB of
79 * the MS byte (of the unencoded number) is one, then the encoding starts with
80 * a byte of zeroes to indicate positive sign. For a negative number, the first
81 * nine bits can not be all 1 - if they are (in the undecoded number), leading
82 * bytes of 0xff are trimmed off until the first nine bits are something other
83 * than one. Also, the first nine bits of the encoded number can not all be
86 * CryptKit giants express their sign as part of the giantstruct.sign field.
87 * The giantDigit array (giantstruct.n[]) is stored l.s. digit first.
89 * These routines are independent of platform, endianness, and giatn digit size.
92 /* routines to guess maximum size of DER-encoded objects */
93 static unsigned feeSizeOfSnaccGiant(
96 unsigned rtn
= abs(g
->sign
) * GIANT_BYTES_PER_DIGIT
;
97 szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g
->sign
, rtn
+ 4));
102 unsigned feeSizeOfDERSig(
106 unsigned rtn
= feeSizeOfSnaccGiant(g1
);
107 rtn
+= feeSizeOfSnaccGiant(g2
);
108 szprint(("feeSizeOfDERSig: size %d\n", rtn
+ 4));
112 /* perform 2's complement of byte array, expressed MS byte first */
113 static void twosComplement(
114 unsigned char *bytePtr
, // points to MS byte
117 unsigned char *outp
= bytePtr
+ numBytes
- 1;
118 unsigned char carry
= 1; // first time thru, carry = 1 to add one to 1's comp
119 for(unsigned byteDex
=0; byteDex
<numBytes
; byteDex
++) {
120 /* first complement, then add carry */
121 *outp
= ~*outp
+ carry
;
122 if(carry
&& (*outp
== 0)) {
134 * CSSM_DATA --> unsigned int
136 static unsigned cssmDataToInt(
137 const CSSM_DATA
&cdata
)
139 if((cdata
.Length
== 0) || (cdata
.Data
== NULL
)) {
142 unsigned len
= (unsigned)cdata
.Length
;
143 if(len
> sizeof(int)) {
144 feeException::throwMe(FR_BadKeyBlob
, "cssmDataToInt");
148 uint8
*cp
= cdata
.Data
;
149 for(unsigned i
=0; i
<len
; i
++) {
150 rtn
= (rtn
<< 8) | *cp
++;
156 * unsigned int --> CSSM_DATA, mallocing from an SecNssCoder
158 static void intToCssmData(
168 else if(num
< 0x10000) {
171 else if(num
< 0x1000000) {
177 cdata
.Data
= (uint8
*)coder
.malloc(len
);
179 uint8
*cp
= &cdata
.Data
[len
- 1];
180 for(unsigned i
=0; i
<len
; i
++) {
187 * Convert a decoded ASN integer, as a CSSM_DATA, to a (mallocd) giant.
188 * Only known exception is a feeException.
190 static giant
cssmDataToGiant(
191 const CSSM_DATA
&cdata
)
193 char *rawOcts
= (char *)cdata
.Data
;
194 unsigned numBytes
= (unsigned)cdata
.Length
;
195 unsigned numGiantDigits
;
198 feeReturn frtn
= FR_Success
;
199 unsigned char *inp
= NULL
;
200 unsigned digitDex
; // index into g->giantDigit[]
202 /* handle degenerate case (value of zero) */
203 if((numBytes
== 0) || ((numBytes
== 1) && rawOcts
[0] == 0)) {
206 feeException::throwMe(FR_Memory
, "newGiant(1)");
208 int_to_giant(0, grtn
);
212 /* make a copy of raw octets if we have to do two's complement */
213 unsigned char *byteArray
= NULL
;
214 bool didMalloc
= false;
215 if(rawOcts
[0] & 0x80) {
218 byteArray
= (unsigned char *)fmalloc(numBytes
);
221 memmove(byteArray
+ 1, rawOcts
, numBytes
-1);
222 twosComplement(byteArray
, numBytes
);
227 byteArray
= (unsigned char *)foo
;
230 /* cook up a new giant */
231 numGiantDigits
= (numBytes
+ GIANT_BYTES_PER_DIGIT
- 1) /
232 GIANT_BYTES_PER_DIGIT
;
233 grtn
= newGiant(numGiantDigits
);
240 * Convert byteArray to array of giantDigits
241 * inp - raw input bytes, LSB last
242 * grtn->n[] - output array of giantDigits, LSD first
243 * Start at LS byte and LD digit
245 digitDex
= 0; // index into g->giantDigit[]
246 giantDigit thisDigit
;
247 inp
= byteArray
+ numBytes
- 1;
248 unsigned dex
; // total byte counter
249 unsigned byteDex
; // index into one giantDigit
251 for(dex
=0; dex
<numBytes
; ) { // increment dex inside
254 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
255 thisDigit
|= ((giantDigit
)(*inp
--) << shiftCount
);
257 if(++dex
== numBytes
) {
258 /* must be partial giantDigit */
262 CKASSERT(digitDex
< numGiantDigits
);
263 grtn
->n
[digitDex
++] = thisDigit
;
265 grtn
->sign
= (int)numGiantDigits
* sign
;
267 /* trim leading (MS) zeroes */
274 feeException::throwMe(frtn
, "bigIntStrToGiant");
280 * Convert a giant to an CSSM_DATA, mallocing using specified coder.
281 * Only known exception is a feeException.
283 static void giantToCssmData(
288 unsigned char doPrepend
= 0;
289 unsigned numGiantDigits
= abs(g
->sign
);
290 unsigned numBytes
= numGiantDigits
* GIANT_BYTES_PER_DIGIT
;
291 giantDigit msGiantBit
= 0;
293 /* special degenerate case */
294 intToCssmData(0, cdata
, coder
);
298 msGiantBit
= g
->n
[numGiantDigits
- 1] >> (GIANT_BITS_PER_DIGIT
- 1);
301 /* prepend a byte of zero if necessary */
302 if((g
->sign
< 0) || // negative - to handle 2's complement
303 ((g
->sign
> 0) && msGiantBit
)) { // ensure MS byte is zero
308 unsigned char *rawBytes
= (unsigned char *)fmalloc(numBytes
);
309 if(rawBytes
== NULL
) {
310 feeException::throwMe(FR_Memory
, "giantToBigIntStr fmalloc(rawBytes)");
312 unsigned char *outp
= rawBytes
;
318 * Convert array of giantDigits to bytes.
319 * outp point to MS output byte.
321 int digitDex
; // index into g->giantDigit[]
322 unsigned byteDex
; // byte index into a giantDigit
323 for(digitDex
=numGiantDigits
-1; digitDex
>=0; digitDex
--) {
324 /* one loop per giantDigit, starting at MS end */
325 giantDigit thisDigit
= g
->n
[digitDex
];
326 unsigned char *bp
= outp
+ GIANT_BYTES_PER_DIGIT
- 1;
327 for(byteDex
=0; byteDex
<GIANT_BYTES_PER_DIGIT
; byteDex
++) {
328 /* one loop per byte within the digit, starting at LS end */
329 *bp
-- = (unsigned char)(thisDigit
) & 0xff;
332 outp
+= GIANT_BYTES_PER_DIGIT
;
335 /* do two's complement for negative giants */
337 twosComplement(rawBytes
, numBytes
);
340 /* strip off redundant leading bits (nine zeroes or nine ones) */
342 unsigned char *endp
= outp
+ numBytes
- 1;
343 while((*outp
== 0) && // m.s. byte zero
344 (outp
< endp
) && // more bytes exist
345 (!(outp
[1] & 0x80))) { // 9th bit is 0
349 while((*outp
== 0xff) && // m.s. byte all ones
350 (outp
< endp
) && // more bytes exist
351 (outp
[1] & 0x80)) { // 9th bit is 1
355 cdata
.Data
= (uint8
*)coder
.malloc(numBytes
);
356 memmove(cdata
.Data
, outp
, numBytes
);
357 cdata
.Length
= numBytes
;
362 /* curveParams : CryptKit <--> FEECurveParametersASN1 */
363 /* Only known exception is a feeException */
364 static void feeCurveParamsToASN1(
365 const curveParams
*cp
,
366 FEECurveParametersASN1
&asnCp
,
369 #if PRINT_CURVE_PARAMS
370 printf("===encoding curveParams; cp:\n"); printCurveParams(cp
);
372 memset(&asnCp
, 0, sizeof(asnCp
));
374 intToCssmData(cp
->primeType
, asnCp
.primeType
, coder
);
375 intToCssmData(cp
->curveType
, asnCp
.curveType
, coder
);
376 intToCssmData(cp
->q
, asnCp
.q
, coder
);
377 intToCssmData(cp
->k
, asnCp
.k
, coder
);
378 intToCssmData(cp
->m
, asnCp
.m
, coder
);
379 giantToCssmData(cp
->a
, asnCp
.a
, coder
);
380 giantToCssmData(cp
->b
, asnCp
.b_
, coder
);
381 giantToCssmData(cp
->c
, asnCp
.c
, coder
);
382 giantToCssmData(cp
->x1Plus
, asnCp
.x1Plus
, coder
);
383 giantToCssmData(cp
->x1Minus
, asnCp
.x1Minus
, coder
);
384 giantToCssmData(cp
->cOrderPlus
, asnCp
.cOrderPlus
, coder
);
385 giantToCssmData(cp
->cOrderMinus
, asnCp
.cOrderMinus
, coder
);
386 giantToCssmData(cp
->x1OrderPlus
, asnCp
.x1OrderPlus
, coder
);
387 giantToCssmData(cp
->x1OrderMinus
, asnCp
.x1OrderMinus
, coder
);
388 if(cp
->primeType
== FPT_General
) {
389 giantToCssmData(cp
->basePrime
, asnCp
.basePrime
, coder
);
392 catch(const feeException
&ferr
) {
396 feeException::throwMe(FR_Memory
, "feeCurveParamsToSnacc catchall"); // ???
400 static curveParams
*feeCurveParamsFromAsn1(
401 const FEECurveParametersASN1
&asnCp
)
403 curveParams
*cp
= newCurveParams();
405 feeException::throwMe(FR_Memory
, "feeCurveParamsFromSnacc alloc cp");
407 cp
->primeType
= (feePrimeType
)cssmDataToInt(asnCp
.primeType
);
408 cp
->curveType
= (feeCurveType
)cssmDataToInt(asnCp
.curveType
);
409 cp
->q
= cssmDataToInt(asnCp
.q
);
410 cp
->k
= cssmDataToInt(asnCp
.k
);
411 cp
->m
= cssmDataToInt(asnCp
.m
);
412 cp
->a
= cssmDataToGiant(asnCp
.a
);
413 cp
->b
= cssmDataToGiant(asnCp
.b_
);
414 cp
->c
= cssmDataToGiant(asnCp
.c
);
415 cp
->x1Plus
= cssmDataToGiant(asnCp
.x1Plus
);
416 cp
->x1Minus
= cssmDataToGiant(asnCp
.x1Minus
);
417 cp
->cOrderPlus
= cssmDataToGiant(asnCp
.cOrderPlus
);
418 cp
->cOrderMinus
= cssmDataToGiant(asnCp
.cOrderMinus
);
419 cp
->x1OrderPlus
= cssmDataToGiant(asnCp
.x1OrderPlus
);
420 cp
->x1OrderMinus
= cssmDataToGiant(asnCp
.x1OrderMinus
);
421 if(asnCp
.basePrime
.Data
!= NULL
) {
422 cp
->basePrime
= cssmDataToGiant(asnCp
.basePrime
);
425 /* remaining fields inferred */
426 curveParamsInferFields(cp
);
427 allocRecipGiants(cp
);
428 #if PRINT_CURVE_PARAMS
429 printf("===decoding curveParams; cp:\n"); printCurveParams(cp
);
435 *** Public routines. These are usable from C code; they never throw.
439 * Encode/decode the two FEE signature types. We malloc returned data via
440 * fmalloc(); caller must free via ffree().
442 feeReturn
feeDEREncodeElGamalSignature(
445 unsigned char **encodedSig
, // fmallocd and RETURNED
446 unsigned *encodedSigLen
) // RETURNED
448 /* convert to FEEElGamalSignatureASN1 */
449 FEEElGamalSignatureASN1 asnSig
;
453 giantToCssmData(u
, asnSig
.u
, coder
);
454 giantToCssmData(PmX
, asnSig
.pmX
, coder
);
456 catch(const feeException
&ferr
) {
462 CSSM_DATA encBlob
; // mallocd by coder
463 perr
= coder
.encodeItem(&asnSig
, FEEElGamalSignatureASN1Template
, encBlob
);
468 /* copy out to caller */
469 *encodedSig
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
470 *encodedSigLen
= (unsigned)encBlob
.Length
;
471 memmove(*encodedSig
, encBlob
.Data
, encBlob
.Length
);
474 printf("feeEncodeElGamalSignature:\n");
475 printf(" u : "); printGiantHex(u
);
476 printf(" PmX : "); printGiantHex(PmX
);
482 feeReturn
feeDEREncodeECDSASignature(
485 unsigned char **encodedSig
, // fmallocd and RETURNED
486 unsigned *encodedSigLen
) // RETURNED
488 /* convert to FEEECDSASignatureASN1 */
489 FEEECDSASignatureASN1 asnSig
;
493 giantToCssmData(c
, asnSig
.c
, coder
);
494 giantToCssmData(d
, asnSig
.d
, coder
);
496 catch(const feeException
&ferr
) {
502 CSSM_DATA encBlob
; // mallocd by coder
503 perr
= coder
.encodeItem(&asnSig
, FEEECDSASignatureASN1Template
, encBlob
);
508 /* copy out to caller */
509 *encodedSig
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
510 *encodedSigLen
= (unsigned)encBlob
.Length
;
511 memmove(*encodedSig
, encBlob
.Data
, encBlob
.Length
);
514 printf("feeEncodeECDSASignature:\n");
515 printf(" c : "); printGiantHex(*c
);
516 printf(" d : "); printGiantHex(*d
);
522 feeReturn
feeDERDecodeElGamalSignature(
523 const unsigned char *encodedSig
,
524 size_t encodedSigLen
,
525 giant
*u
, // newGiant'd and RETURNED
526 giant
*PmX
) // newGiant'd and RETURNED
528 FEEElGamalSignatureASN1 asnSig
;
531 memset(&asnSig
, 0, sizeof(asnSig
));
532 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
533 FEEElGamalSignatureASN1Template
, &asnSig
);
535 return FR_BadSignatureFormat
;
539 *u
= cssmDataToGiant(asnSig
.u
);
540 *PmX
= cssmDataToGiant(asnSig
.pmX
);
542 catch(const feeException
&ferr
) {
546 /* FIXME - bad sig? memory? */
550 printf("feeDecodeElGamalSignature:\n");
551 printf(" u : "); printGiantHex(*u
);
552 printf(" PmX : "); printGiantHex(*PmX
);
557 feeReturn
feeDERDecodeECDSASignature(
558 const unsigned char *encodedSig
,
559 size_t encodedSigLen
,
560 giant
*c
, // newGiant'd and RETURNED
561 giant
*d
) // newGiant'd and RETURNED
563 FEEECDSASignatureASN1 asnSig
;
566 memset(&asnSig
, 0, sizeof(asnSig
));
567 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
568 FEEECDSASignatureASN1Template
, &asnSig
);
570 return FR_BadSignatureFormat
;
574 *c
= cssmDataToGiant(asnSig
.c
);
575 *d
= cssmDataToGiant(asnSig
.d
);
577 catch(const feeException
&ferr
) {
581 /* FIXME - bad sig? memory? */
585 printf("feeDERDecodeECDSASignature:\n");
586 printf(" u : "); printGiantHex(*u
);
587 printf(" PmX : "); printGiantHex(*PmX
);
593 * Encode/decode the FEE private and public keys. We malloc returned data via
594 * falloc(); caller must free via ffree(). Public C functions which never throw.
596 feeReturn
feeDEREncodePublicKey(
598 const curveParams
*cp
,
601 giant plusY
, // may be NULL
602 unsigned char **keyBlob
, // fmallocd and RETURNED
603 unsigned *keyBlobLen
) // RETURNED
605 FEEPublicKeyASN1 asnKey
;
608 memset(&asnKey
, 0, sizeof(asnKey
));
609 intToCssmData(version
, asnKey
.version
, coder
);
612 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
613 giantToCssmData(plusX
, asnKey
.plusX
, coder
);
614 giantToCssmData(minusX
, asnKey
.minusX
, coder
);
616 giantToCssmData(plusY
, asnKey
.plusY
, coder
);
619 catch(const feeException
&ferr
) {
625 CSSM_DATA encBlob
; // mallocd by coder
626 perr
= coder
.encodeItem(&asnKey
, FEEPublicKeyASN1Template
, encBlob
);
632 *keyBlob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
633 *keyBlobLen
= (unsigned)encBlob
.Length
;
634 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
638 feeReturn
feeDEREncodePrivateKey(
640 const curveParams
*cp
,
641 const giant privData
,
642 unsigned char **keyBlob
, // fmallocd and RETURNED
643 unsigned *keyBlobLen
) // RETURNED
645 FEEPrivateKeyASN1 asnKey
;
648 memset(&asnKey
, 0, sizeof(asnKey
));
649 intToCssmData(version
, asnKey
.version
, coder
);
652 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
653 giantToCssmData(privData
, asnKey
.privData
, coder
);
655 catch(const feeException
&ferr
) {
661 CSSM_DATA encBlob
; // mallocd by coder
662 perr
= coder
.encodeItem(&asnKey
, FEEPrivateKeyASN1Template
, encBlob
);
668 *keyBlob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
669 *keyBlobLen
= (unsigned)encBlob
.Length
;
670 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
674 feeReturn
feeDERDecodePublicKey(
675 const unsigned char *keyBlob
,
677 int *version
, // this and remainder RETURNED
681 giant
*plusY
) // may be NULL
683 FEEPublicKeyASN1 asnKey
;
686 memset(&asnKey
, 0, sizeof(asnKey
));
687 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
688 FEEPublicKeyASN1Template
, &asnKey
);
690 return FR_BadKeyBlob
;
694 *version
= cssmDataToInt(asnKey
.version
);
695 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
696 *plusX
= cssmDataToGiant(asnKey
.plusX
);
697 *minusX
= cssmDataToGiant(asnKey
.minusX
);
698 if(asnKey
.plusY
.Data
!= NULL
) {
700 *plusY
= cssmDataToGiant(asnKey
.plusY
);
703 *plusY
= newGiant(1);
704 int_to_giant(0, *plusY
);
707 catch(const feeException
&ferr
) {
711 /* FIXME - bad sig? memory? */
717 feeReturn
feeDERDecodePrivateKey(
718 const unsigned char *keyBlob
,
720 int *version
, // this and remainder RETURNED
722 giant
*privData
) // RETURNED
724 FEEPrivateKeyASN1 asnKey
;
727 memset(&asnKey
, 0, sizeof(asnKey
));
728 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
729 FEEPrivateKeyASN1Template
, &asnKey
);
731 return FR_BadKeyBlob
;
735 *version
= cssmDataToInt(asnKey
.version
);
736 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
737 *privData
= cssmDataToGiant(asnKey
.privData
);
739 catch(const feeException
&ferr
) {
743 /* FIXME - bad sig? memory? */
749 #pragma mark --- ECDSA support ---
751 /* convert between feeDepth and curve OIDs */
752 static const CSSM_OID
*depthToOid(
756 case FEE_DEPTH_secp192r1
:
757 return &CSSMOID_secp192r1
;
758 case FEE_DEPTH_secp256r1
:
759 return &CSSMOID_secp256r1
;
760 case FEE_DEPTH_secp384r1
:
761 return &CSSMOID_secp384r1
;
762 case FEE_DEPTH_secp521r1
:
763 return &CSSMOID_secp521r1
;
765 dbgLog(("depthToOid needs work\n"));
770 static feeReturn
curveOidToFeeDepth(
771 const CSSM_OID
*curveOid
,
772 feeDepth
*depth
) /* RETURNED */
774 if(nssCompareCssmData(curveOid
, &CSSMOID_secp192r1
)) {
775 *depth
= FEE_DEPTH_secp192r1
;
777 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp256r1
)) {
778 *depth
= FEE_DEPTH_secp256r1
;
780 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp384r1
)) {
781 *depth
= FEE_DEPTH_secp384r1
;
783 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp521r1
)) {
784 *depth
= FEE_DEPTH_secp521r1
;
787 dbgLog(("curveOidToFeeDepth: unknown curve OID\n"));
788 return FR_BadKeyBlob
;
795 * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer
796 * depth from its algorith.parameter
798 static feeReturn
feeAlgIdToDepth(
799 const CSSM_X509_ALGORITHM_IDENTIFIER
*algId
,
802 const CSSM_OID
*oid
= &algId
->algorithm
;
803 /* FIXME what's the value here for a private key!? */
804 if(!nssCompareCssmData(oid
, &CSSMOID_ecPublicKey
)) {
805 dbgLog(("feeAlgIdToDepth: bad OID"));
806 return FR_BadKeyBlob
;
810 * AlgId.params is curve OID, still encoded since it's an ASN_ANY.
811 * First two bytes of encoded OID are (06, length)
813 const CSSM_DATA
*param
= &algId
->parameters
;
814 if((param
->Length
<= 2) || (param
->Data
[0] != BER_TAG_OID
)) {
815 dbgLog(("feeAlgIdToDepth: no curve params\n"));
816 return FR_BadKeyBlob
;
819 CSSM_OID decOid
= {param
->Length
-2, algId
->parameters
.Data
+2};
820 return curveOidToFeeDepth(&decOid
, depth
);
824 * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding.
826 static feeReturn
feeSetupAlgId(
829 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
)
831 algId
.algorithm
= CSSMOID_ecPublicKey
;
832 const CSSM_OID
*curveOid
= depthToOid(depth
);
833 if(curveOid
== NULL
) {
834 return FR_IllegalDepth
;
837 /* quick & dirty encode of the parameter OID; it's an ASN_ANY in the template */
838 coder
.allocItem(algId
.parameters
, curveOid
->Length
+ 2);
839 algId
.parameters
.Data
[0] = BER_TAG_OID
;
840 algId
.parameters
.Data
[1] = curveOid
->Length
;
841 memmove(algId
.parameters
.Data
+2, curveOid
->Data
, curveOid
->Length
);
845 #pragma mark --- ECDSA public key, X.509 format ---
848 * Encode/decode public key in X.509 format.
850 feeReturn
feeDEREncodeX509PublicKey(
851 const unsigned char *pubBlob
, /* x and y octet string */
854 unsigned char **x509Blob
, /* fmallocd and RETURNED */
855 unsigned *x509BlobLen
) /* RETURNED */
858 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo
;
860 memset(&nssPubKeyInfo
, 0, sizeof(nssPubKeyInfo
));
862 /* The x/y string, to be encoded in a bit string */
863 nssPubKeyInfo
.subjectPublicKey
.Data
= (uint8
*)pubBlob
;
864 nssPubKeyInfo
.subjectPublicKey
.Length
= pubBlobLen
* 8;
867 feeReturn frtn
= curveParamsDepth(cp
, &depth
);
869 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
873 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssPubKeyInfo
.algorithm
;
874 frtn
= feeSetupAlgId(depth
, coder
, algId
);
880 CSSM_DATA encBlob
; // mallocd by coder
881 PRErrorCode perr
= coder
.encodeItem(&nssPubKeyInfo
, kSecAsn1SubjectPublicKeyInfoTemplate
, encBlob
);
887 *x509Blob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
888 *x509BlobLen
= (unsigned)encBlob
.Length
;
889 memmove(*x509Blob
, encBlob
.Data
, encBlob
.Length
);
893 feeReturn
feeDERDecodeX509PublicKey(
894 const unsigned char *x509Blob
,
895 unsigned x509BlobLen
,
896 feeDepth
*depth
, /* RETURNED */
897 unsigned char **pubBlob
, /* x and y octet string RETURNED */
898 unsigned *pubBlobLen
) /* RETURNED */
901 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo
;
904 memset(&nssPubKeyInfo
, 0, sizeof(nssPubKeyInfo
));
905 perr
= coder
.decode(x509Blob
, x509BlobLen
, kSecAsn1SubjectPublicKeyInfoTemplate
,
908 dbgLog(("decode(SubjectPublicKeyInfo) error"));
909 return FR_BadKeyBlob
;
912 /* verify alg identifier & depth */
913 feeReturn frtn
= feeAlgIdToDepth(&nssPubKeyInfo
.algorithm
, depth
);
918 /* copy public key string - it's in bits here */
919 CSSM_DATA
*pubKey
= &nssPubKeyInfo
.subjectPublicKey
;
920 unsigned keyLen
=(unsigned) (pubKey
->Length
+ 7) / 8;
921 *pubBlob
= (unsigned char *)fmalloc(keyLen
);
922 if(*pubBlob
== NULL
) {
925 memmove(*pubBlob
, pubKey
->Data
, keyLen
);
926 *pubBlobLen
= keyLen
;
930 #pragma mark --- ECDSA keys, OpenSSL format ---
933 * Encode private, and decode private or public key, in unencrypted OpenSSL format.
935 feeReturn
feeDEREncodeOpenSSLPrivateKey(
936 const unsigned char *privBlob
, /* private data octet string */
937 unsigned privBlobLen
,
938 const unsigned char *pubBlob
, /* public key, optional */
941 unsigned char **openBlob
, /* fmallocd and RETURNED */
942 unsigned *openBlobLen
) /* RETURNED */
945 const CSSM_OID
*curveOid
;
948 NSS_ECDSA_PrivateKey ecdsaPrivKey
;
949 memset(&ecdsaPrivKey
, 0, sizeof(ecdsaPrivKey
));
951 ecdsaPrivKey
.version
.Data
= &vers
;
952 ecdsaPrivKey
.version
.Length
= 1;
953 ecdsaPrivKey
.privateKey
.Data
= (uint8
*)privBlob
;
954 ecdsaPrivKey
.privateKey
.Length
= privBlobLen
;
956 /* Params - ASN_ANY - actually the curve OID */
957 if(curveParamsDepth(cp
, &depth
)) {
958 dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth"));
959 return FR_BadKeyBlob
;
961 curveOid
= depthToOid(depth
);
962 if(curveOid
== NULL
) {
963 return FR_BadKeyBlob
;
966 /* quickie DER-encode of the curve OID */
968 coder
.allocItem(ecdsaPrivKey
.params
, curveOid
->Length
+ 2);
973 ecdsaPrivKey
.params
.Data
[0] = BER_TAG_OID
;
974 ecdsaPrivKey
.params
.Data
[1] = curveOid
->Length
;
975 memmove(ecdsaPrivKey
.params
.Data
+2, curveOid
->Data
, curveOid
->Length
);
977 /* public key - optional - bit string, length in bits */
979 ecdsaPrivKey
.pubKey
.Data
= (uint8
*)pubBlob
;
980 ecdsaPrivKey
.pubKey
.Length
= pubBlobLen
* 8;
983 CSSM_DATA encPriv
= {0, NULL
};
984 PRErrorCode perr
= coder
.encodeItem(&ecdsaPrivKey
, kSecAsn1ECDSAPrivateKeyInfoTemplate
, encPriv
);
990 *openBlob
= (unsigned char *)fmalloc((unsigned)encPriv
.Length
);
991 *openBlobLen
= (unsigned)encPriv
.Length
;
992 memmove(*openBlob
, encPriv
.Data
, encPriv
.Length
);
996 feeReturn
feeDERDecodeOpenSSLKey(
997 const unsigned char *osBlob
,
999 feeDepth
*depth
, /* RETURNED */
1000 unsigned char **privBlob
, /* private data octet string RETURNED */
1001 unsigned *privBlobLen
, /* RETURNED */
1002 unsigned char **pubBlob
, /* public data octet string optionally RETURNED */
1003 unsigned *pubBlobLen
)
1006 NSS_ECDSA_PrivateKey ecdsaPrivKey
;
1007 memset(&ecdsaPrivKey
, 0, sizeof(ecdsaPrivKey
));
1008 if(coder
.decode(osBlob
, osBlobLen
,
1009 kSecAsn1ECDSAPrivateKeyInfoTemplate
, &ecdsaPrivKey
)) {
1010 dbgLog(("Error decoding openssl priv key\n"));
1011 return FR_BadKeyBlob
;
1014 unsigned keyLen
= (unsigned)ecdsaPrivKey
.privateKey
.Length
;
1016 dbgLog(("NULL priv key data in PKCS8\n"));
1018 *privBlob
= (unsigned char *)fmalloc(keyLen
);
1019 if(*privBlob
== NULL
) {
1022 *privBlobLen
= keyLen
;
1023 memmove(*privBlob
, ecdsaPrivKey
.privateKey
.Data
, keyLen
);
1025 /* curve OID --> depth */
1026 if(ecdsaPrivKey
.params
.Data
!= NULL
) {
1027 /* quickie decode */
1028 const CSSM_DATA
*param
= &ecdsaPrivKey
.params
;
1029 if((param
->Data
[0] != BER_TAG_OID
) || (param
->Length
<= 2)) {
1030 dbgLog(("feeDERDecodeOpenSSLKey: bad curve params\n"));
1031 return FR_BadKeyBlob
;
1033 CSSM_OID decOid
= {param
->Length
-2, param
->Data
+2};
1034 if(curveOidToFeeDepth(&decOid
, depth
)) {
1035 return FR_BadKeyBlob
;
1039 /* Public key, if it's there and caller wants it */
1040 if((ecdsaPrivKey
.pubKey
.Length
!= 0) && (pubBlob
!= NULL
)) {
1041 *pubBlobLen
= (unsigned)(ecdsaPrivKey
.pubKey
.Length
+ 7) / 8;
1042 *pubBlob
= (unsigned char *)fmalloc(*pubBlobLen
);
1043 memmove(*pubBlob
, ecdsaPrivKey
.pubKey
.Data
, *pubBlobLen
);
1048 #pragma mark --- ECDSA public key, PKCS8 format ---
1051 * Encode/decode private key in unencrypted PKCS8 format.
1053 feeReturn
feeDEREncodePKCS8PrivateKey(
1054 const unsigned char *privBlob
, /* private data octet string */
1055 unsigned privBlobLen
,
1056 const unsigned char *pubBlob
, /* public blob, optional */
1057 unsigned pubBlobLen
,
1059 unsigned char **pkcs8Blob
, /* fmallocd and RETURNED */
1060 unsigned *pkcs8BlobLen
) /* RETURNED */
1062 /* First encode a NSS_ECDSA_PrivateKey */
1063 unsigned char *encPriv
= NULL
;
1064 unsigned encPrivLen
= 0;
1065 feeReturn frtn
= feeDEREncodeOpenSSLPrivateKey(privBlob
, privBlobLen
,
1066 pubBlob
, pubBlobLen
, cp
, &encPriv
, &encPrivLen
);
1071 /* That encoding goes into NSS_PrivateKeyInfo.private key */
1073 NSS_PrivateKeyInfo nssPrivKeyInfo
;
1074 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssPrivKeyInfo
.algorithm
;
1075 memset(&nssPrivKeyInfo
, 0, sizeof(nssPrivKeyInfo
));
1076 nssPrivKeyInfo
.privateKey
.Data
= (uint8
*)encPriv
;
1077 nssPrivKeyInfo
.privateKey
.Length
= encPrivLen
;
1081 frtn
= curveParamsDepth(cp
, &depth
);
1083 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
1086 frtn
= feeSetupAlgId(depth
, coder
, algId
);
1091 nssPrivKeyInfo
.version
.Data
= &vers
;
1092 nssPrivKeyInfo
.version
.Length
= 1;
1095 CSSM_DATA encPrivInfo
; // mallocd by coder
1096 if(coder
.encodeItem(&nssPrivKeyInfo
, kSecAsn1PrivateKeyInfoTemplate
, encPrivInfo
)) {
1102 *pkcs8Blob
= (unsigned char *)fmalloc((unsigned)encPrivInfo
.Length
);
1103 *pkcs8BlobLen
= (unsigned)encPrivInfo
.Length
;
1104 memmove(*pkcs8Blob
, encPrivInfo
.Data
, encPrivInfo
.Length
);
1112 feeReturn
feeDERDecodePKCS8PrivateKey(
1113 const unsigned char *pkcs8Blob
,
1114 unsigned pkcs8BlobLen
,
1115 feeDepth
*depth
, /* RETURNED */
1116 unsigned char **privBlob
, /* private data octet string RETURNED */
1117 unsigned *privBlobLen
, /* RETURNED */
1118 unsigned char **pubBlob
, /* optionally returned, if it's there */
1119 unsigned *pubBlobLen
)
1121 NSS_PrivateKeyInfo nssPrivKeyInfo
;
1125 memset(&nssPrivKeyInfo
, 0, sizeof(nssPrivKeyInfo
));
1126 perr
= coder
.decode(pkcs8Blob
, pkcs8BlobLen
, kSecAsn1PrivateKeyInfoTemplate
, &nssPrivKeyInfo
);
1128 dbgLog(("Error decoding top level PKCS8\n"));
1129 return FR_BadKeyBlob
;
1132 /* verify alg identifier & depth */
1133 feeReturn frtn
= feeAlgIdToDepth(&nssPrivKeyInfo
.algorithm
, depth
);
1139 * nssPrivKeyInfo.privateKey is an octet string containing an encoded
1140 * NSS_ECDSA_PrivateKey.
1142 frtn
= feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo
.privateKey
.Data
,
1143 (unsigned)nssPrivKeyInfo
.privateKey
.Length
, depth
,
1144 privBlob
, privBlobLen
,
1145 pubBlob
, pubBlobLen
);
1150 #endif /* CRYPTKIT_DER_ENABLE */