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  
  28 #include <security_cryptkit/CryptKitDER.h> 
  29 #include <security_cryptkit/falloc.h> 
  30 #include <security_cryptkit/feeDebug.h> 
  31 #include <security_cryptkit/feeFunctions.h> 
  32 #include <security_cryptkit/ckutilities.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> 
  39 #include <Security/x509defs.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() _NOEXCEPT 
{} 
  59         feeReturn 
frtn() const _NOEXCEPT 
{ 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
);