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.
28 #if CRYPTKIT_DER_ENABLE
30 #include <security_cryptkit/CryptKitDER.h>
31 #include <security_cryptkit/falloc.h>
32 #include <security_cryptkit/feeDebug.h>
33 #include <security_cryptkit/feeFunctions.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
, "giantToBigIntStr 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
);
483 feeReturn
feeDEREncodeECDSASignature(
486 unsigned char **encodedSig
, // fmallocd and RETURNED
487 unsigned *encodedSigLen
) // RETURNED
489 /* convert to FEEECDSASignatureASN1 */
490 FEEECDSASignatureASN1 asnSig
;
494 giantToCssmData(c
, asnSig
.c
, coder
);
495 giantToCssmData(d
, asnSig
.d
, coder
);
497 catch(const feeException
&ferr
) {
503 CSSM_DATA encBlob
; // mallocd by coder
504 perr
= coder
.encodeItem(&asnSig
, FEEECDSASignatureASN1Template
, encBlob
);
509 /* copy out to caller */
510 *encodedSig
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
511 *encodedSigLen
= (unsigned)encBlob
.Length
;
512 memmove(*encodedSig
, encBlob
.Data
, encBlob
.Length
);
515 printf("feeEncodeECDSASignature:\n");
516 printf(" c : "); printGiantHex(*c
);
517 printf(" d : "); printGiantHex(*d
);
523 feeReturn
feeDERDecodeElGamalSignature(
524 const unsigned char *encodedSig
,
525 size_t encodedSigLen
,
526 giant
*u
, // newGiant'd and RETURNED
527 giant
*PmX
) // newGiant'd and RETURNED
529 FEEElGamalSignatureASN1 asnSig
;
532 memset(&asnSig
, 0, sizeof(asnSig
));
533 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
534 FEEElGamalSignatureASN1Template
, &asnSig
);
536 return FR_BadSignatureFormat
;
540 *u
= cssmDataToGiant(asnSig
.u
);
541 *PmX
= cssmDataToGiant(asnSig
.pmX
);
543 catch(const feeException
&ferr
) {
547 /* FIXME - bad sig? memory? */
551 printf("feeDecodeElGamalSignature:\n");
552 printf(" u : "); printGiantHex(*u
);
553 printf(" PmX : "); printGiantHex(*PmX
);
558 feeReturn
feeDERDecodeECDSASignature(
559 const unsigned char *encodedSig
,
560 size_t encodedSigLen
,
561 giant
*c
, // newGiant'd and RETURNED
562 giant
*d
) // newGiant'd and RETURNED
564 FEEECDSASignatureASN1 asnSig
;
567 memset(&asnSig
, 0, sizeof(asnSig
));
568 PRErrorCode perr
= coder
.decode(encodedSig
, encodedSigLen
,
569 FEEECDSASignatureASN1Template
, &asnSig
);
571 return FR_BadSignatureFormat
;
575 *c
= cssmDataToGiant(asnSig
.c
);
576 *d
= cssmDataToGiant(asnSig
.d
);
578 catch(const feeException
&ferr
) {
582 /* FIXME - bad sig? memory? */
586 printf("feeDERDecodeECDSASignature:\n");
587 printf(" u : "); printGiantHex(*u
);
588 printf(" PmX : "); printGiantHex(*PmX
);
594 * Encode/decode the FEE private and public keys. We malloc returned data via
595 * falloc(); caller must free via ffree(). Public C functions which never throw.
597 feeReturn
feeDEREncodePublicKey(
599 const curveParams
*cp
,
602 giant plusY
, // may be NULL
603 unsigned char **keyBlob
, // fmallocd and RETURNED
604 unsigned *keyBlobLen
) // RETURNED
606 FEEPublicKeyASN1 asnKey
;
609 memset(&asnKey
, 0, sizeof(asnKey
));
610 intToCssmData(version
, asnKey
.version
, coder
);
613 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
614 giantToCssmData(plusX
, asnKey
.plusX
, coder
);
615 giantToCssmData(minusX
, asnKey
.minusX
, coder
);
617 giantToCssmData(plusY
, asnKey
.plusY
, coder
);
620 catch(const feeException
&ferr
) {
626 CSSM_DATA encBlob
; // mallocd by coder
627 perr
= coder
.encodeItem(&asnKey
, FEEPublicKeyASN1Template
, encBlob
);
633 *keyBlob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
634 *keyBlobLen
= (unsigned)encBlob
.Length
;
635 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
639 feeReturn
feeDEREncodePrivateKey(
641 const curveParams
*cp
,
642 const giant privData
,
643 unsigned char **keyBlob
, // fmallocd and RETURNED
644 unsigned *keyBlobLen
) // RETURNED
646 FEEPrivateKeyASN1 asnKey
;
649 memset(&asnKey
, 0, sizeof(asnKey
));
650 intToCssmData(version
, asnKey
.version
, coder
);
653 feeCurveParamsToASN1(cp
, asnKey
.curveParams
, coder
);
654 giantToCssmData(privData
, asnKey
.privData
, coder
);
656 catch(const feeException
&ferr
) {
662 CSSM_DATA encBlob
; // mallocd by coder
663 perr
= coder
.encodeItem(&asnKey
, FEEPrivateKeyASN1Template
, encBlob
);
669 *keyBlob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
670 *keyBlobLen
= (unsigned)encBlob
.Length
;
671 memmove(*keyBlob
, encBlob
.Data
, encBlob
.Length
);
675 feeReturn
feeDERDecodePublicKey(
676 const unsigned char *keyBlob
,
678 int *version
, // this and remainder RETURNED
682 giant
*plusY
) // may be NULL
684 FEEPublicKeyASN1 asnKey
;
687 memset(&asnKey
, 0, sizeof(asnKey
));
688 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
689 FEEPublicKeyASN1Template
, &asnKey
);
691 return FR_BadKeyBlob
;
695 *version
= cssmDataToInt(asnKey
.version
);
696 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
697 *plusX
= cssmDataToGiant(asnKey
.plusX
);
698 *minusX
= cssmDataToGiant(asnKey
.minusX
);
699 if(asnKey
.plusY
.Data
!= NULL
) {
701 *plusY
= cssmDataToGiant(asnKey
.plusY
);
704 *plusY
= newGiant(1);
705 int_to_giant(0, *plusY
);
708 catch(const feeException
&ferr
) {
712 /* FIXME - bad sig? memory? */
718 feeReturn
feeDERDecodePrivateKey(
719 const unsigned char *keyBlob
,
721 int *version
, // this and remainder RETURNED
723 giant
*privData
) // RETURNED
725 FEEPrivateKeyASN1 asnKey
;
728 memset(&asnKey
, 0, sizeof(asnKey
));
729 PRErrorCode perr
= coder
.decode(keyBlob
, keyBlobLen
,
730 FEEPrivateKeyASN1Template
, &asnKey
);
732 return FR_BadKeyBlob
;
736 *version
= cssmDataToInt(asnKey
.version
);
737 *cp
= feeCurveParamsFromAsn1(asnKey
.curveParams
);
738 *privData
= cssmDataToGiant(asnKey
.privData
);
740 catch(const feeException
&ferr
) {
744 /* FIXME - bad sig? memory? */
750 #pragma mark --- ECDSA support ---
752 /* convert between feeDepth and curve OIDs */
753 static const CSSM_OID
*depthToOid(
757 case FEE_DEPTH_secp192r1
:
758 return &CSSMOID_secp192r1
;
759 case FEE_DEPTH_secp256r1
:
760 return &CSSMOID_secp256r1
;
761 case FEE_DEPTH_secp384r1
:
762 return &CSSMOID_secp384r1
;
763 case FEE_DEPTH_secp521r1
:
764 return &CSSMOID_secp521r1
;
766 dbgLog(("depthToOid needs work\n"));
771 static feeReturn
curveOidToFeeDepth(
772 const CSSM_OID
*curveOid
,
773 feeDepth
*depth
) /* RETURNED */
775 if(nssCompareCssmData(curveOid
, &CSSMOID_secp192r1
)) {
776 *depth
= FEE_DEPTH_secp192r1
;
778 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp256r1
)) {
779 *depth
= FEE_DEPTH_secp256r1
;
781 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp384r1
)) {
782 *depth
= FEE_DEPTH_secp384r1
;
784 else if(nssCompareCssmData(curveOid
, &CSSMOID_secp521r1
)) {
785 *depth
= FEE_DEPTH_secp521r1
;
788 dbgLog(("curveOidToFeeDepth: unknown curve OID\n"));
789 return FR_BadKeyBlob
;
796 * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer
797 * depth from its algorith.parameter
799 static feeReturn
feeAlgIdToDepth(
800 const CSSM_X509_ALGORITHM_IDENTIFIER
*algId
,
803 const CSSM_OID
*oid
= &algId
->algorithm
;
804 /* FIXME what's the value here for a private key!? */
805 if(!nssCompareCssmData(oid
, &CSSMOID_ecPublicKey
)) {
806 dbgLog(("feeAlgIdToDepth: bad OID"));
807 return FR_BadKeyBlob
;
811 * AlgId.params is curve OID, still encoded since it's an ASN_ANY.
812 * First two bytes of encoded OID are (06, length)
814 const CSSM_DATA
*param
= &algId
->parameters
;
815 if((param
->Length
<= 2) || (param
->Data
[0] != BER_TAG_OID
)) {
816 dbgLog(("feeAlgIdToDepth: no curve params\n"));
817 return FR_BadKeyBlob
;
820 CSSM_OID decOid
= {param
->Length
-2, algId
->parameters
.Data
+2};
821 return curveOidToFeeDepth(&decOid
, depth
);
825 * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding.
827 static feeReturn
feeSetupAlgId(
830 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
)
832 algId
.algorithm
= CSSMOID_ecPublicKey
;
833 const CSSM_OID
*curveOid
= depthToOid(depth
);
834 if(curveOid
== NULL
) {
835 return FR_IllegalDepth
;
838 /* quick & dirty encode of the parameter OID; it's an ASN_ANY in the template */
839 coder
.allocItem(algId
.parameters
, curveOid
->Length
+ 2);
840 algId
.parameters
.Data
[0] = BER_TAG_OID
;
841 algId
.parameters
.Data
[1] = curveOid
->Length
;
842 memmove(algId
.parameters
.Data
+2, curveOid
->Data
, curveOid
->Length
);
846 #pragma mark --- ECDSA public key, X.509 format ---
849 * Encode/decode public key in X.509 format.
851 feeReturn
feeDEREncodeX509PublicKey(
852 const unsigned char *pubBlob
, /* x and y octet string */
855 unsigned char **x509Blob
, /* fmallocd and RETURNED */
856 unsigned *x509BlobLen
) /* RETURNED */
859 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo
;
861 memset(&nssPubKeyInfo
, 0, sizeof(nssPubKeyInfo
));
863 /* The x/y string, to be encoded in a bit string */
864 nssPubKeyInfo
.subjectPublicKey
.Data
= (uint8
*)pubBlob
;
865 nssPubKeyInfo
.subjectPublicKey
.Length
= pubBlobLen
* 8;
868 feeReturn frtn
= curveParamsDepth(cp
, &depth
);
870 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
874 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssPubKeyInfo
.algorithm
;
875 frtn
= feeSetupAlgId(depth
, coder
, algId
);
881 CSSM_DATA encBlob
; // mallocd by coder
882 PRErrorCode perr
= coder
.encodeItem(&nssPubKeyInfo
, kSecAsn1SubjectPublicKeyInfoTemplate
, encBlob
);
888 *x509Blob
= (unsigned char *)fmalloc((unsigned)encBlob
.Length
);
889 *x509BlobLen
= (unsigned)encBlob
.Length
;
890 memmove(*x509Blob
, encBlob
.Data
, encBlob
.Length
);
894 feeReturn
feeDERDecodeX509PublicKey(
895 const unsigned char *x509Blob
,
896 unsigned x509BlobLen
,
897 feeDepth
*depth
, /* RETURNED */
898 unsigned char **pubBlob
, /* x and y octet string RETURNED */
899 unsigned *pubBlobLen
) /* RETURNED */
902 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo
;
905 memset(&nssPubKeyInfo
, 0, sizeof(nssPubKeyInfo
));
906 perr
= coder
.decode(x509Blob
, x509BlobLen
, kSecAsn1SubjectPublicKeyInfoTemplate
,
909 dbgLog(("decode(SubjectPublicKeyInfo) error"));
910 return FR_BadKeyBlob
;
913 /* verify alg identifier & depth */
914 feeReturn frtn
= feeAlgIdToDepth(&nssPubKeyInfo
.algorithm
, depth
);
919 /* copy public key string - it's in bits here */
920 CSSM_DATA
*pubKey
= &nssPubKeyInfo
.subjectPublicKey
;
921 unsigned keyLen
=(unsigned) (pubKey
->Length
+ 7) / 8;
922 *pubBlob
= (unsigned char *)fmalloc(keyLen
);
923 if(*pubBlob
== NULL
) {
926 memmove(*pubBlob
, pubKey
->Data
, keyLen
);
927 *pubBlobLen
= keyLen
;
931 #pragma mark --- ECDSA keys, OpenSSL format ---
934 * Encode private, and decode private or public key, in unencrypted OpenSSL format.
936 feeReturn
feeDEREncodeOpenSSLPrivateKey(
937 const unsigned char *privBlob
, /* private data octet string */
938 unsigned privBlobLen
,
939 const unsigned char *pubBlob
, /* public key, optional */
942 unsigned char **openBlob
, /* fmallocd and RETURNED */
943 unsigned *openBlobLen
) /* RETURNED */
946 const CSSM_OID
*curveOid
;
949 NSS_ECDSA_PrivateKey ecdsaPrivKey
;
950 memset(&ecdsaPrivKey
, 0, sizeof(ecdsaPrivKey
));
952 ecdsaPrivKey
.version
.Data
= &vers
;
953 ecdsaPrivKey
.version
.Length
= 1;
954 ecdsaPrivKey
.privateKey
.Data
= (uint8
*)privBlob
;
955 ecdsaPrivKey
.privateKey
.Length
= privBlobLen
;
957 /* Params - ASN_ANY - actually the curve OID */
958 if(curveParamsDepth(cp
, &depth
)) {
959 dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth"));
960 return FR_BadKeyBlob
;
962 curveOid
= depthToOid(depth
);
963 if(curveOid
== NULL
) {
964 return FR_BadKeyBlob
;
967 /* quickie DER-encode of the curve OID */
969 coder
.allocItem(ecdsaPrivKey
.params
, curveOid
->Length
+ 2);
974 ecdsaPrivKey
.params
.Data
[0] = BER_TAG_OID
;
975 ecdsaPrivKey
.params
.Data
[1] = curveOid
->Length
;
976 memmove(ecdsaPrivKey
.params
.Data
+2, curveOid
->Data
, curveOid
->Length
);
978 /* public key - optional - bit string, length in bits */
980 ecdsaPrivKey
.pubKey
.Data
= (uint8
*)pubBlob
;
981 ecdsaPrivKey
.pubKey
.Length
= pubBlobLen
* 8;
984 CSSM_DATA encPriv
= {0, NULL
};
985 PRErrorCode perr
= coder
.encodeItem(&ecdsaPrivKey
, kSecAsn1ECDSAPrivateKeyInfoTemplate
, encPriv
);
991 *openBlob
= (unsigned char *)fmalloc((unsigned)encPriv
.Length
);
992 *openBlobLen
= (unsigned)encPriv
.Length
;
993 memmove(*openBlob
, encPriv
.Data
, encPriv
.Length
);
997 feeReturn
feeDERDecodeOpenSSLKey(
998 const unsigned char *osBlob
,
1000 feeDepth
*depth
, /* RETURNED */
1001 unsigned char **privBlob
, /* private data octet string RETURNED */
1002 unsigned *privBlobLen
, /* RETURNED */
1003 unsigned char **pubBlob
, /* public data octet string optionally RETURNED */
1004 unsigned *pubBlobLen
)
1007 NSS_ECDSA_PrivateKey ecdsaPrivKey
;
1008 memset(&ecdsaPrivKey
, 0, sizeof(ecdsaPrivKey
));
1009 if(coder
.decode(osBlob
, osBlobLen
,
1010 kSecAsn1ECDSAPrivateKeyInfoTemplate
, &ecdsaPrivKey
)) {
1011 dbgLog(("Error decoding openssl priv key\n"));
1012 return FR_BadKeyBlob
;
1015 unsigned keyLen
= (unsigned)ecdsaPrivKey
.privateKey
.Length
;
1017 dbgLog(("NULL priv key data in PKCS8\n"));
1019 *privBlob
= (unsigned char *)fmalloc(keyLen
);
1020 if(*privBlob
== NULL
) {
1023 *privBlobLen
= keyLen
;
1024 memmove(*privBlob
, ecdsaPrivKey
.privateKey
.Data
, keyLen
);
1026 /* curve OID --> depth */
1027 if(ecdsaPrivKey
.params
.Data
!= NULL
) {
1028 /* quickie decode */
1029 const CSSM_DATA
*param
= &ecdsaPrivKey
.params
;
1030 if((param
->Data
[0] != BER_TAG_OID
) || (param
->Length
<= 2)) {
1031 dbgLog(("feeDERDecodeOpenSSLKey: bad curve params\n"));
1032 return FR_BadKeyBlob
;
1034 CSSM_OID decOid
= {param
->Length
-2, param
->Data
+2};
1035 if(curveOidToFeeDepth(&decOid
, depth
)) {
1036 return FR_BadKeyBlob
;
1040 /* Public key, if it's there and caller wants it */
1041 if((ecdsaPrivKey
.pubKey
.Length
!= 0) && (pubBlob
!= NULL
)) {
1042 *pubBlobLen
= (unsigned)(ecdsaPrivKey
.pubKey
.Length
+ 7) / 8;
1043 *pubBlob
= (unsigned char *)fmalloc(*pubBlobLen
);
1044 memmove(*pubBlob
, ecdsaPrivKey
.pubKey
.Data
, *pubBlobLen
);
1049 #pragma mark --- ECDSA public key, PKCS8 format ---
1052 * Encode/decode private key in unencrypted PKCS8 format.
1054 feeReturn
feeDEREncodePKCS8PrivateKey(
1055 const unsigned char *privBlob
, /* private data octet string */
1056 unsigned privBlobLen
,
1057 const unsigned char *pubBlob
, /* public blob, optional */
1058 unsigned pubBlobLen
,
1060 unsigned char **pkcs8Blob
, /* fmallocd and RETURNED */
1061 unsigned *pkcs8BlobLen
) /* RETURNED */
1063 /* First encode a NSS_ECDSA_PrivateKey */
1064 unsigned char *encPriv
= NULL
;
1065 unsigned encPrivLen
= 0;
1066 feeReturn frtn
= feeDEREncodeOpenSSLPrivateKey(privBlob
, privBlobLen
,
1067 pubBlob
, pubBlobLen
, cp
, &encPriv
, &encPrivLen
);
1072 /* That encoding goes into NSS_PrivateKeyInfo.private key */
1074 NSS_PrivateKeyInfo nssPrivKeyInfo
;
1075 CSSM_X509_ALGORITHM_IDENTIFIER
&algId
= nssPrivKeyInfo
.algorithm
;
1076 memset(&nssPrivKeyInfo
, 0, sizeof(nssPrivKeyInfo
));
1077 nssPrivKeyInfo
.privateKey
.Data
= (uint8
*)encPriv
;
1078 nssPrivKeyInfo
.privateKey
.Length
= encPrivLen
;
1082 frtn
= curveParamsDepth(cp
, &depth
);
1084 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
1087 frtn
= feeSetupAlgId(depth
, coder
, algId
);
1092 nssPrivKeyInfo
.version
.Data
= &vers
;
1093 nssPrivKeyInfo
.version
.Length
= 1;
1096 CSSM_DATA encPrivInfo
; // mallocd by coder
1097 if(coder
.encodeItem(&nssPrivKeyInfo
, kSecAsn1PrivateKeyInfoTemplate
, encPrivInfo
)) {
1103 *pkcs8Blob
= (unsigned char *)fmalloc((unsigned)encPrivInfo
.Length
);
1104 *pkcs8BlobLen
= (unsigned)encPrivInfo
.Length
;
1105 memmove(*pkcs8Blob
, encPrivInfo
.Data
, encPrivInfo
.Length
);
1113 feeReturn
feeDERDecodePKCS8PrivateKey(
1114 const unsigned char *pkcs8Blob
,
1115 unsigned pkcs8BlobLen
,
1116 feeDepth
*depth
, /* RETURNED */
1117 unsigned char **privBlob
, /* private data octet string RETURNED */
1118 unsigned *privBlobLen
, /* RETURNED */
1119 unsigned char **pubBlob
, /* optionally returned, if it's there */
1120 unsigned *pubBlobLen
)
1122 NSS_PrivateKeyInfo nssPrivKeyInfo
;
1126 memset(&nssPrivKeyInfo
, 0, sizeof(nssPrivKeyInfo
));
1127 perr
= coder
.decode(pkcs8Blob
, pkcs8BlobLen
, kSecAsn1PrivateKeyInfoTemplate
, &nssPrivKeyInfo
);
1129 dbgLog(("Error decoding top level PKCS8\n"));
1130 return FR_BadKeyBlob
;
1133 /* verify alg identifier & depth */
1134 feeReturn frtn
= feeAlgIdToDepth(&nssPrivKeyInfo
.algorithm
, depth
);
1140 * nssPrivKeyInfo.privateKey is an octet string containing an encoded
1141 * NSS_ECDSA_PrivateKey.
1143 frtn
= feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo
.privateKey
.Data
,
1144 (unsigned)nssPrivKeyInfo
.privateKey
.Length
, depth
,
1145 privBlob
, privBlobLen
,
1146 pubBlob
, pubBlobLen
);
1151 #endif /* CRYPTKIT_DER_ENABLE */