CryptKitDER.cpp
1 /* 2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 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 8 * using this file. 9 * 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. 16 */ 17 18 19 /* 20 * CryptKitDER.h - snacc-based routines to create and parse DER-encoded FEE 21 * keys and signatures 22 * 23 */ 24 25 #include "ckconfig.h" 26 27 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> 40 41 #define PRINT_SIG_GIANTS 0 42 #define PRINT_CURVE_PARAMS 0 43 #define PRINT_SIZES 0 44 #if PRINT_SIZES 45 #define szprint(s) printf s 46 #else 47 #define szprint(s) 48 #endif 49 50 /* 51 * Trivial exception class associated with a feeReturn. 52 */ 53 class feeException 54 { 55 protected: 56 feeException(feeReturn frtn, const char *op); 57 public: 58 ~feeException() _NOEXCEPT {} 59 feeReturn frtn() const _NOEXCEPT { return mFrtn; } 60 static void throwMe(feeReturn frtn, const char *op = NULL) __attribute__((noreturn)); 61 private: 62 feeReturn mFrtn; 63 }; 64 65 feeException::feeException( 66 feeReturn frtn, 67 const char *op) 68 : mFrtn(frtn) 69 { 70 if(op) { 71 dbgLog(("%s: %s\n", op, feeReturnString(frtn))); 72 } 73 } 74 75 void feeException::throwMe(feeReturn frtn, const char *op /*= NULL*/) { throw feeException(frtn, op); } 76 77 /* 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 85 * zero. 86 * 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. 89 * 90 * These routines are independent of platform, endianness, and giatn digit size. 91 */ 92 93 /* routines to guess maximum size of DER-encoded objects */ 94 static unsigned feeSizeOfSnaccGiant( 95 giant g) 96 { 97 unsigned rtn = abs(g->sign) * GIANT_BYTES_PER_DIGIT; 98 szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g->sign, rtn + 4)); 99 return rtn + 4; 100 } 101 102 /* PUBLIC... */ 103 unsigned feeSizeOfDERSig( 104 giant g1, 105 giant g2) 106 { 107 unsigned rtn = feeSizeOfSnaccGiant(g1); 108 rtn += feeSizeOfSnaccGiant(g2); 109 szprint(("feeSizeOfDERSig: size %d\n", rtn + 4)); 110 return rtn + 4; 111 } 112 113 /* perform 2's complement of byte array, expressed MS byte first */ 114 static void twosComplement( 115 unsigned char *bytePtr, // points to MS byte 116 unsigned numBytes) 117 { 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)) { 124 /* overflow/carry */ 125 carry = 1; 126 } 127 else { 128 carry = 0; 129 } 130 outp--; 131 } 132 } 133 134 /* 135 * CSSM_DATA --> unsigned int 136 */ 137 static unsigned cssmDataToInt( 138 const CSSM_DATA &cdata) 139 { 140 if((cdata.Length == 0) || (cdata.Data == NULL)) { 141 return 0; 142 } 143 unsigned len = (unsigned)cdata.Length; 144 if(len > sizeof(int)) { 145 feeException::throwMe(FR_BadKeyBlob, "cssmDataToInt"); 146 } 147 148 unsigned rtn = 0; 149 uint8 *cp = cdata.Data; 150 for(unsigned i=0; i<len; i++) { 151 rtn = (rtn << 8) | *cp++; 152 } 153 return rtn; 154 } 155 156 /* 157 * unsigned int --> CSSM_DATA, mallocing from an SecNssCoder 158 */ 159 static void intToCssmData( 160 unsigned num, 161 CSSM_DATA &cdata, 162 SecNssCoder &coder) 163 { 164 unsigned len = 0; 165 166 if(num < 0x100) { 167 len = 1; 168 } 169 else if(num < 0x10000) { 170 len = 2; 171 } 172 else if(num < 0x1000000) { 173 len = 3; 174 } 175 else { 176 len = 4; 177 } 178 cdata.Data = (uint8 *)coder.malloc(len); 179 cdata.Length = len; 180 uint8 *cp = &cdata.Data[len - 1]; 181 for(unsigned i=0; i<len; i++) { 182 *cp-- = num & 0xff; 183 num >>= 8; 184 } 185 } 186 187 /* 188 * Convert a decoded ASN integer, as a CSSM_DATA, to a (mallocd) giant. 189 * Only known exception is a feeException. 190 */ 191 static giant cssmDataToGiant( 192 const CSSM_DATA &cdata) 193 { 194 char *rawOcts = (char *)cdata.Data; 195 unsigned numBytes = (unsigned)cdata.Length; 196 unsigned numGiantDigits; 197 int sign = 1; 198 giant grtn; 199 feeReturn frtn = FR_Success; 200 unsigned char *inp = NULL; 201 unsigned digitDex; // index into g->giantDigit[] 202 203 /* handle degenerate case (value of zero) */ 204 if((numBytes == 0) || ((numBytes == 1) && rawOcts[0] == 0)) { 205 grtn = newGiant(1); 206 if(grtn == NULL) { 207 feeException::throwMe(FR_Memory, "newGiant(1)"); 208 } 209 int_to_giant(0, grtn); 210 return grtn; 211 } 212 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) { 217 sign = -1; 218 numBytes++; 219 byteArray = (unsigned char *)fmalloc(numBytes); 220 didMalloc = true; 221 byteArray[0] = 0xff; 222 memmove(byteArray + 1, rawOcts, numBytes-1); 223 twosComplement(byteArray, numBytes); 224 } 225 else { 226 /* no copy */ 227 char *foo = rawOcts; 228 byteArray = (unsigned char *)foo; 229 } 230 231 /* cook up a new giant */ 232 numGiantDigits = (numBytes + GIANT_BYTES_PER_DIGIT - 1) / 233 GIANT_BYTES_PER_DIGIT; 234 grtn = newGiant(numGiantDigits); 235 if(grtn == NULL) { 236 frtn = FR_Memory; 237 goto abort; 238 } 239 240 /* 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 245 */ 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 251 unsigned shiftCount; 252 for(dex=0; dex<numBytes; ) { // increment dex inside 253 thisDigit = 0; 254 shiftCount = 0; 255 for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) { 256 thisDigit |= ((giantDigit)(*inp--) << shiftCount); 257 shiftCount += 8; 258 if(++dex == numBytes) { 259 /* must be partial giantDigit */ 260 break; 261 } 262 } 263 CKASSERT(digitDex < numGiantDigits); 264 grtn->n[digitDex++] = thisDigit; 265 } 266 grtn->sign = (int)numGiantDigits * sign; 267 268 /* trim leading (MS) zeroes */ 269 gtrimSign(grtn); 270 abort: 271 if(didMalloc) { 272 ffree(byteArray); 273 } 274 if(frtn) { 275 feeException::throwMe(frtn, "bigIntStrToGiant"); 276 } 277 return grtn; 278 } 279 280 /* 281 * Convert a giant to an CSSM_DATA, mallocing using specified coder. 282 * Only known exception is a feeException. 283 */ 284 static void giantToCssmData( 285 giant g, 286 CSSM_DATA &cdata, 287 SecNssCoder &coder) 288 { 289 unsigned char doPrepend = 0; 290 unsigned numGiantDigits = abs(g->sign); 291 unsigned numBytes = numGiantDigits * GIANT_BYTES_PER_DIGIT; 292 giantDigit msGiantBit = 0; 293 if(isZero(g)) { 294 /* special degenerate case */ 295 intToCssmData(0, cdata, coder); 296 return; 297 } 298 else { 299 msGiantBit = g->n[numGiantDigits - 1] >> (GIANT_BITS_PER_DIGIT - 1); 300 } 301 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 305 doPrepend = 1; 306 numBytes++; 307 } 308 309 unsigned char *rawBytes = (unsigned char *)fmalloc(numBytes); 310 if(rawBytes == NULL) { 311 feeException::throwMe(FR_Memory, "giantToCssmData fmalloc(rawBytes)"); 312 } 313 unsigned char *outp = rawBytes; 314 if(doPrepend) { 315 *outp++ = 0; 316 } 317 318 /* 319 * Convert array of giantDigits to bytes. 320 * outp point to MS output byte. 321 */ 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; 331 thisDigit >>= 8; 332 } 333 outp += GIANT_BYTES_PER_DIGIT; 334 } 335 336 /* do two's complement for negative giants */ 337 if(g->sign < 0) { 338 twosComplement(rawBytes, numBytes); 339 } 340 341 /* strip off redundant leading bits (nine zeroes or nine ones) */ 342 outp = rawBytes; 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 347 outp++; 348 numBytes--; 349 } 350 while((*outp == 0xff) && // m.s. byte all ones 351 (outp < endp) && // more bytes exist 352 (outp[1] & 0x80)) { // 9th bit is 1 353 outp++; 354 numBytes--; 355 } 356 cdata.Data = (uint8 *)coder.malloc(numBytes); 357 memmove(cdata.Data, outp, numBytes); 358 cdata.Length = numBytes; 359 ffree(rawBytes); 360 return; 361 } 362 363 /* curveParams : CryptKit <--> FEECurveParametersASN1 */ 364 /* Only known exception is a feeException */ 365 static void feeCurveParamsToASN1( 366 const curveParams *cp, 367 FEECurveParametersASN1 &asnCp, 368 SecNssCoder &coder) 369 { 370 #if PRINT_CURVE_PARAMS 371 printf("===encoding curveParams; cp:\n"); printCurveParams(cp); 372 #endif 373 memset(&asnCp, 0, sizeof(asnCp)); 374 try { 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); 391 } 392 } 393 catch(const feeException &ferr) { 394 throw; 395 } 396 catch(...) { 397 feeException::throwMe(FR_Memory, "feeCurveParamsToSnacc catchall"); // ??? 398 } 399 } 400 401 static curveParams *feeCurveParamsFromAsn1( 402 const FEECurveParametersASN1 &asnCp) 403 { 404 curveParams *cp = newCurveParams(); 405 if(cp == NULL) { 406 feeException::throwMe(FR_Memory, "feeCurveParamsFromSnacc alloc cp"); 407 } 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); 424 } 425 426 /* remaining fields inferred */ 427 curveParamsInferFields(cp); 428 allocRecipGiants(cp); 429 #if PRINT_CURVE_PARAMS 430 printf("===decoding curveParams; cp:\n"); printCurveParams(cp); 431 #endif 432 return cp; 433 } 434 435 /*** 436 *** Public routines. These are usable from C code; they never throw. 437 ***/ 438 439 /* 440 * Encode/decode the two FEE signature types. We malloc returned data via 441 * fmalloc(); caller must free via ffree(). 442 */ 443 feeReturn feeDEREncodeElGamalSignature( 444 giant u, 445 giant PmX, 446 unsigned char **encodedSig, // fmallocd and RETURNED 447 unsigned *encodedSigLen) // RETURNED 448 { 449 /* convert to FEEElGamalSignatureASN1 */ 450 FEEElGamalSignatureASN1 asnSig; 451 SecNssCoder coder; 452 453 try { 454 giantToCssmData(u, asnSig.u, coder); 455 giantToCssmData(PmX, asnSig.pmX, coder); 456 } 457 catch(const feeException &ferr) { 458 return ferr.frtn(); 459 } 460 461 /* DER encode */ 462 PRErrorCode perr; 463 CSSM_DATA encBlob; // mallocd by coder 464 perr = coder.encodeItem(&asnSig, FEEElGamalSignatureASN1Template, encBlob); 465 if(perr) { 466 return FR_Memory; 467 } 468 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); 473 474 #if PRINT_SIG_GIANTS 475 printf("feeEncodeElGamalSignature:\n"); 476 printf(" u : "); printGiantHex(u); 477 printf(" PmX : "); printGiantHex(PmX); 478 #endif 479 480 return FR_Success; 481 } 482 483 /* 484 * Encode a DER formatted ECDSA signature 485 */ 486 feeReturn feeDEREncodeECDSASignature( 487 giant c, 488 giant d, 489 unsigned char **encodedSig, // fmallocd and RETURNED 490 unsigned *encodedSigLen) // RETURNED 491 { 492 /* convert to FEEECDSASignatureASN1 */ 493 FEEECDSASignatureASN1 asnSig; 494 SecNssCoder coder; 495 496 try { 497 giantToCssmData(c, asnSig.c, coder); 498 giantToCssmData(d, asnSig.d, coder); 499 } 500 catch(const feeException &ferr) { 501 return ferr.frtn(); 502 } 503 504 /* DER encode */ 505 PRErrorCode perr; 506 CSSM_DATA encBlob; // mallocd by coder 507 perr = coder.encodeItem(&asnSig, FEEECDSASignatureASN1Template, encBlob); 508 if(perr) { 509 return FR_Memory; 510 } 511 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); 516 517 #if PRINT_SIG_GIANTS 518 printf("feeDEREncodeECDSASignature:\n"); 519 printf(" c : "); printGiantHex(c); 520 printf(" d : "); printGiantHex(d); 521 #endif 522 return FR_Success; 523 524 } 525 526 #if PRINT_SIG_GIANTS 527 static void printHex( 528 const unsigned char *buf, 529 unsigned len, 530 unsigned maxLen) 531 { 532 bool doEllipsis = false; 533 unsigned dex; 534 if(len > maxLen) { 535 len = maxLen; 536 doEllipsis = true; 537 } 538 for(dex=0; dex<len; dex++) { 539 printf("%02X ", *buf++); 540 } 541 if(doEllipsis) { 542 printf("...etc."); 543 } 544 } 545 #endif 546 547 /* 548 * Encode a RAW formatted ECDSA signature 549 */ 550 feeReturn feeRAWEncodeECDSASignature(unsigned groupBytesLen, 551 giant c, 552 giant d, 553 unsigned char **encodedSig, // fmallocd and RETURNED 554 unsigned *encodedSigLen) // RETURNED 555 { 556 /* copy out to caller */ 557 *encodedSig = (unsigned char *)fmalloc(2*groupBytesLen); 558 *encodedSigLen = (unsigned)2*groupBytesLen; 559 560 /* convert to FEEECDSASignatureASN1 */ 561 try { 562 serializeGiant(c, *encodedSig, groupBytesLen); 563 serializeGiant(d, *encodedSig+groupBytesLen, groupBytesLen); 564 } 565 catch(const feeException &ferr) { 566 return ferr.frtn(); 567 } 568 569 #if PRINT_SIG_GIANTS 570 printf("feeRAWEncodeECDSASignature:\n"); 571 printf(" c : "); printGiantHex(c); 572 printf(" d : "); printGiantHex(d); 573 printf(" sig : "); printHex(*encodedSig,*encodedSigLen,512); 574 #endif 575 return FR_Success; 576 577 } 578 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 584 { 585 FEEElGamalSignatureASN1 asnSig; 586 SecNssCoder coder; 587 588 memset(&asnSig, 0, sizeof(asnSig)); 589 PRErrorCode perr = coder.decode(encodedSig, encodedSigLen, 590 FEEElGamalSignatureASN1Template, &asnSig); 591 if(perr) { 592 return FR_BadSignatureFormat; 593 } 594 595 try { 596 *u = cssmDataToGiant(asnSig.u); 597 *PmX = cssmDataToGiant(asnSig.pmX); 598 } 599 catch(const feeException &ferr) { 600 return ferr.frtn(); 601 } 602 catch(...) { 603 /* FIXME - bad sig? memory? */ 604 return FR_Memory; 605 } 606 #if PRINT_SIG_GIANTS 607 printf("feeDecodeElGamalSignature:\n"); 608 printf(" u : "); printGiantHex(*u); 609 printf(" PmX : "); printGiantHex(*PmX); 610 #endif 611 return FR_Success; 612 } 613 614 /* 615 * Decode a DER formatted ECDSA signature 616 */ 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 622 { 623 FEEECDSASignatureASN1 asnSig; 624 SecNssCoder coder; 625 626 memset(&asnSig, 0, sizeof(asnSig)); 627 PRErrorCode perr = coder.decode(encodedSig, encodedSigLen, 628 FEEECDSASignatureASN1Template, &asnSig); 629 if(perr) { 630 return FR_BadSignatureFormat; 631 } 632 633 try { 634 *c = cssmDataToGiant(asnSig.c); 635 *d = cssmDataToGiant(asnSig.d); 636 } 637 catch(const feeException &ferr) { 638 return ferr.frtn(); 639 } 640 catch(...) { 641 /* FIXME - bad sig? memory? */ 642 return FR_Memory; 643 } 644 #if PRINT_SIG_GIANTS 645 printf("feeDERDecodeECDSASignature:\n"); 646 printf(" c : "); printGiantHex(*c); 647 printf(" d : "); printGiantHex(*d); 648 #endif 649 return FR_Success; 650 } 651 652 /* 653 * Decode a RAW formatted ECDSA signature 654 */ 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 660 { 661 662 // Size must be even 663 if (((encodedSigLen & 1) == 1) || (groupBytesLen != (encodedSigLen>>1))) { 664 return FR_BadSignatureFormat; 665 } 666 667 try { 668 *c = giant_with_data((uint8_t*)encodedSig,(int)groupBytesLen); 669 *d = giant_with_data((uint8_t*)encodedSig+groupBytesLen, (int)groupBytesLen); 670 } 671 catch(const feeException &ferr) { 672 return ferr.frtn(); 673 } 674 catch(...) { 675 /* FIXME - bad sig? memory? */ 676 return FR_Memory; 677 } 678 #if PRINT_SIG_GIANTS 679 printf("feeRAWDecodeECDSASignature:\n"); 680 printf(" c : "); printGiantHex(*c); 681 printf(" d : "); printGiantHex(*d); 682 #endif 683 return FR_Success; 684 } 685 686 /* 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. 689 */ 690 feeReturn feeDEREncodePublicKey( 691 int version, 692 const curveParams *cp, 693 giant plusX, 694 giant minusX, 695 giant plusY, // may be NULL 696 unsigned char **keyBlob, // fmallocd and RETURNED 697 unsigned *keyBlobLen) // RETURNED 698 { 699 FEEPublicKeyASN1 asnKey; 700 SecNssCoder coder; 701 702 memset(&asnKey, 0, sizeof(asnKey)); 703 intToCssmData(version, asnKey.version, coder); 704 705 try { 706 feeCurveParamsToASN1(cp, asnKey.curveParams, coder); 707 giantToCssmData(plusX, asnKey.plusX, coder); 708 giantToCssmData(minusX, asnKey.minusX, coder); 709 if(plusY != NULL) { 710 giantToCssmData(plusY, asnKey.plusY, coder); 711 } 712 } 713 catch(const feeException &ferr) { 714 return ferr.frtn(); 715 } 716 717 /* DER encode */ 718 PRErrorCode perr; 719 CSSM_DATA encBlob; // mallocd by coder 720 perr = coder.encodeItem(&asnKey, FEEPublicKeyASN1Template, encBlob); 721 if(perr) { 722 return FR_Memory; 723 } 724 725 /* copy out */ 726 *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length); 727 *keyBlobLen = (unsigned)encBlob.Length; 728 memmove(*keyBlob, encBlob.Data, encBlob.Length); 729 return FR_Success; 730 } 731 732 feeReturn feeDEREncodePrivateKey( 733 int version, 734 const curveParams *cp, 735 const giant privData, 736 unsigned char **keyBlob, // fmallocd and RETURNED 737 unsigned *keyBlobLen) // RETURNED 738 { 739 FEEPrivateKeyASN1 asnKey; 740 SecNssCoder coder; 741 742 memset(&asnKey, 0, sizeof(asnKey)); 743 intToCssmData(version, asnKey.version, coder); 744 745 try { 746 feeCurveParamsToASN1(cp, asnKey.curveParams, coder); 747 giantToCssmData(privData, asnKey.privData, coder); 748 } 749 catch(const feeException &ferr) { 750 return ferr.frtn(); 751 } 752 753 /* DER encode */ 754 PRErrorCode perr; 755 CSSM_DATA encBlob; // mallocd by coder 756 perr = coder.encodeItem(&asnKey, FEEPrivateKeyASN1Template, encBlob); 757 if(perr) { 758 return FR_Memory; 759 } 760 761 /* copy out */ 762 *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length); 763 *keyBlobLen = (unsigned)encBlob.Length; 764 memmove(*keyBlob, encBlob.Data, encBlob.Length); 765 return FR_Success; 766 } 767 768 feeReturn feeDERDecodePublicKey( 769 const unsigned char *keyBlob, 770 unsigned keyBlobLen, 771 int *version, // this and remainder RETURNED 772 curveParams **cp, 773 giant *plusX, 774 giant *minusX, 775 giant *plusY) // may be NULL 776 { 777 FEEPublicKeyASN1 asnKey; 778 SecNssCoder coder; 779 780 memset(&asnKey, 0, sizeof(asnKey)); 781 PRErrorCode perr = coder.decode(keyBlob, keyBlobLen, 782 FEEPublicKeyASN1Template, &asnKey); 783 if(perr) { 784 return FR_BadKeyBlob; 785 } 786 787 try { 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) { 793 /* optional */ 794 *plusY = cssmDataToGiant(asnKey.plusY); 795 } 796 else { 797 *plusY = newGiant(1); 798 int_to_giant(0, *plusY); 799 } 800 } 801 catch(const feeException &ferr) { 802 return ferr.frtn(); 803 } 804 catch(...) { 805 /* FIXME - bad sig? memory? */ 806 return FR_Memory; 807 } 808 return FR_Success; 809 } 810 811 feeReturn feeDERDecodePrivateKey( 812 const unsigned char *keyBlob, 813 unsigned keyBlobLen, 814 int *version, // this and remainder RETURNED 815 curveParams **cp, 816 giant *privData) // RETURNED 817 { 818 FEEPrivateKeyASN1 asnKey; 819 SecNssCoder coder; 820 821 memset(&asnKey, 0, sizeof(asnKey)); 822 PRErrorCode perr = coder.decode(keyBlob, keyBlobLen, 823 FEEPrivateKeyASN1Template, &asnKey); 824 if(perr) { 825 return FR_BadKeyBlob; 826 } 827 828 try { 829 *version = cssmDataToInt(asnKey.version); 830 *cp = feeCurveParamsFromAsn1(asnKey.curveParams); 831 *privData = cssmDataToGiant(asnKey.privData); 832 } 833 catch(const feeException &ferr) { 834 return ferr.frtn(); 835 } 836 catch(...) { 837 /* FIXME - bad sig? memory? */ 838 return FR_Memory; 839 } 840 return FR_Success; 841 } 842 843 #pragma mark --- ECDSA support --- 844 845 /* convert between feeDepth and curve OIDs */ 846 static const CSSM_OID *depthToOid( 847 feeDepth depth) 848 { 849 switch(depth) { 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; 858 default: 859 dbgLog(("depthToOid needs work\n")); 860 return NULL; 861 } 862 } 863 864 static feeReturn curveOidToFeeDepth( 865 const CSSM_OID *curveOid, 866 feeDepth *depth) /* RETURNED */ 867 { 868 if(nssCompareCssmData(curveOid, &CSSMOID_secp192r1)) { 869 *depth = FEE_DEPTH_secp192r1; 870 } 871 else if(nssCompareCssmData(curveOid, &CSSMOID_secp256r1)) { 872 *depth = FEE_DEPTH_secp256r1; 873 } 874 else if(nssCompareCssmData(curveOid, &CSSMOID_secp384r1)) { 875 *depth = FEE_DEPTH_secp384r1; 876 } 877 else if(nssCompareCssmData(curveOid, &CSSMOID_secp521r1)) { 878 *depth = FEE_DEPTH_secp521r1; 879 } 880 else { 881 dbgLog(("curveOidToFeeDepth: unknown curve OID\n")); 882 return FR_BadKeyBlob; 883 } 884 return FR_Success; 885 } 886 887 888 /* 889 * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer 890 * depth from its algorith.parameter 891 */ 892 static feeReturn feeAlgIdToDepth( 893 const CSSM_X509_ALGORITHM_IDENTIFIER *algId, 894 feeDepth *depth) 895 { 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; 901 } 902 903 /* 904 * AlgId.params is curve OID, still encoded since it's an ASN_ANY. 905 * First two bytes of encoded OID are (06, length) 906 */ 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; 911 } 912 913 CSSM_OID decOid = {param->Length-2, algId->parameters.Data+2}; 914 return curveOidToFeeDepth(&decOid, depth); 915 } 916 917 /* 918 * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding. 919 */ 920 static feeReturn feeSetupAlgId( 921 feeDepth depth, 922 SecNssCoder &coder, 923 CSSM_X509_ALGORITHM_IDENTIFIER &algId) 924 { 925 algId.algorithm = CSSMOID_ecPublicKey; 926 const CSSM_OID *curveOid = depthToOid(depth); 927 if(curveOid == NULL) { 928 return FR_IllegalDepth; 929 } 930 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); 936 return FR_Success; 937 } 938 939 #pragma mark --- ECDSA public key, X.509 format --- 940 941 /* 942 * Encode/decode public key in X.509 format. 943 */ 944 feeReturn feeDEREncodeX509PublicKey( 945 const unsigned char *pubBlob, /* x and y octet string */ 946 unsigned pubBlobLen, 947 curveParams *cp, 948 unsigned char **x509Blob, /* fmallocd and RETURNED */ 949 unsigned *x509BlobLen) /* RETURNED */ 950 { 951 SecNssCoder coder; 952 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo; 953 954 memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo)); 955 956 /* The x/y string, to be encoded in a bit string */ 957 nssPubKeyInfo.subjectPublicKey.Data = (uint8 *)pubBlob; 958 nssPubKeyInfo.subjectPublicKey.Length = pubBlobLen * 8; 959 960 feeDepth depth; 961 feeReturn frtn = curveParamsDepth(cp, &depth); 962 if(frtn) { 963 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n")); 964 return frtn; 965 } 966 967 CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPubKeyInfo.algorithm; 968 frtn = feeSetupAlgId(depth, coder, algId); 969 if(frtn) { 970 return frtn; 971 } 972 973 /* DER encode */ 974 CSSM_DATA encBlob; // mallocd by coder 975 PRErrorCode perr = coder.encodeItem(&nssPubKeyInfo, kSecAsn1SubjectPublicKeyInfoTemplate, encBlob); 976 if(perr) { 977 return FR_Memory; 978 } 979 980 /* copy out */ 981 *x509Blob = (unsigned char *)fmalloc((unsigned)encBlob.Length); 982 *x509BlobLen = (unsigned)encBlob.Length; 983 memmove(*x509Blob, encBlob.Data, encBlob.Length); 984 return FR_Success; 985 } 986 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 */ 993 { 994 SecNssCoder coder; 995 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo; 996 PRErrorCode perr; 997 998 memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo)); 999 perr = coder.decode(x509Blob, x509BlobLen, kSecAsn1SubjectPublicKeyInfoTemplate, 1000 &nssPubKeyInfo); 1001 if(perr) { 1002 dbgLog(("decode(SubjectPublicKeyInfo) error")); 1003 return FR_BadKeyBlob; 1004 } 1005 1006 /* verify alg identifier & depth */ 1007 feeReturn frtn = feeAlgIdToDepth(&nssPubKeyInfo.algorithm, depth); 1008 if(frtn) { 1009 return frtn; 1010 } 1011 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) { 1017 return FR_Memory; 1018 } 1019 memmove(*pubBlob, pubKey->Data, keyLen); 1020 *pubBlobLen = keyLen; 1021 return FR_Success; 1022 } 1023 1024 #pragma mark --- ECDSA keys, OpenSSL format --- 1025 1026 /* 1027 * Encode private, and decode private or public key, in unencrypted OpenSSL format. 1028 */ 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, 1034 curveParams *cp, 1035 unsigned char **openBlob, /* fmallocd and RETURNED */ 1036 unsigned *openBlobLen) /* RETURNED */ 1037 { 1038 feeDepth depth; 1039 const CSSM_OID *curveOid; 1040 SecNssCoder coder; 1041 1042 NSS_ECDSA_PrivateKey ecdsaPrivKey; 1043 memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey)); 1044 uint8 vers = 1; 1045 ecdsaPrivKey.version.Data = &vers; 1046 ecdsaPrivKey.version.Length = 1; 1047 ecdsaPrivKey.privateKey.Data = (uint8 *)privBlob; 1048 ecdsaPrivKey.privateKey.Length = privBlobLen; 1049 1050 /* Params - ASN_ANY - actually the curve OID */ 1051 if(curveParamsDepth(cp, &depth)) { 1052 dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth")); 1053 return FR_BadKeyBlob; 1054 } 1055 curveOid = depthToOid(depth); 1056 if(curveOid == NULL) { 1057 return FR_BadKeyBlob; 1058 } 1059 1060 /* quickie DER-encode of the curve OID */ 1061 try { 1062 coder.allocItem(ecdsaPrivKey.params, curveOid->Length + 2); 1063 } 1064 catch(...) { 1065 return FR_Memory; 1066 } 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); 1070 1071 /* public key - optional - bit string, length in bits */ 1072 if(pubBlob) { 1073 ecdsaPrivKey.pubKey.Data = (uint8 *)pubBlob; 1074 ecdsaPrivKey.pubKey.Length = pubBlobLen * 8; 1075 } 1076 1077 CSSM_DATA encPriv = {0, NULL}; 1078 PRErrorCode perr = coder.encodeItem(&ecdsaPrivKey, kSecAsn1ECDSAPrivateKeyInfoTemplate, encPriv); 1079 if(perr) { 1080 return FR_Memory; 1081 } 1082 1083 /* copy out */ 1084 *openBlob = (unsigned char *)fmalloc((unsigned)encPriv.Length); 1085 *openBlobLen = (unsigned)encPriv.Length; 1086 memmove(*openBlob, encPriv.Data, encPriv.Length); 1087 return FR_Success; 1088 } 1089 1090 feeReturn feeDERDecodeOpenSSLKey( 1091 const unsigned char *osBlob, 1092 unsigned osBlobLen, 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) 1098 { 1099 SecNssCoder coder; 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; 1106 } 1107 1108 unsigned keyLen = (unsigned)ecdsaPrivKey.privateKey.Length; 1109 if(keyLen == 0) { 1110 dbgLog(("NULL priv key data in PKCS8\n")); 1111 } 1112 *privBlob = (unsigned char *)fmalloc(keyLen); 1113 if(*privBlob == NULL) { 1114 return FR_Memory; 1115 } 1116 *privBlobLen = keyLen; 1117 memmove(*privBlob, ecdsaPrivKey.privateKey.Data, keyLen); 1118 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; 1126 } 1127 CSSM_OID decOid = {param->Length-2, param->Data+2}; 1128 if(curveOidToFeeDepth(&decOid, depth)) { 1129 return FR_BadKeyBlob; 1130 } 1131 } 1132 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); 1138 } 1139 return FR_Success; 1140 } 1141 1142 #pragma mark --- ECDSA public key, PKCS8 format --- 1143 1144 /* 1145 * Encode/decode private key in unencrypted PKCS8 format. 1146 */ 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, 1152 curveParams *cp, 1153 unsigned char **pkcs8Blob, /* fmallocd and RETURNED */ 1154 unsigned *pkcs8BlobLen) /* RETURNED */ 1155 { 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); 1161 if(frtn) { 1162 return frtn; 1163 } 1164 1165 /* That encoding goes into NSS_PrivateKeyInfo.private key */ 1166 SecNssCoder coder; 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; 1172 uint8 vers = 0; 1173 1174 feeDepth depth; 1175 frtn = curveParamsDepth(cp, &depth); 1176 if(frtn) { 1177 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n")); 1178 goto errOut; 1179 } 1180 frtn = feeSetupAlgId(depth, coder, algId); 1181 if(frtn) { 1182 goto errOut; 1183 } 1184 1185 nssPrivKeyInfo.version.Data = &vers; 1186 nssPrivKeyInfo.version.Length = 1; 1187 1188 /* DER encode */ 1189 CSSM_DATA encPrivInfo; // mallocd by coder 1190 if(coder.encodeItem(&nssPrivKeyInfo, kSecAsn1PrivateKeyInfoTemplate, encPrivInfo)) { 1191 frtn = FR_Memory; 1192 goto errOut; 1193 } 1194 1195 /* copy out */ 1196 *pkcs8Blob = (unsigned char *)fmalloc((unsigned)encPrivInfo.Length); 1197 *pkcs8BlobLen = (unsigned)encPrivInfo.Length; 1198 memmove(*pkcs8Blob, encPrivInfo.Data, encPrivInfo.Length); 1199 errOut: 1200 if(encPriv) { 1201 ffree(encPriv); 1202 } 1203 return frtn; 1204 } 1205 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) 1214 { 1215 NSS_PrivateKeyInfo nssPrivKeyInfo; 1216 PRErrorCode perr; 1217 SecNssCoder coder; 1218 1219 memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo)); 1220 perr = coder.decode(pkcs8Blob, pkcs8BlobLen, kSecAsn1PrivateKeyInfoTemplate, &nssPrivKeyInfo); 1221 if(perr) { 1222 dbgLog(("Error decoding top level PKCS8\n")); 1223 return FR_BadKeyBlob; 1224 } 1225 1226 /* verify alg identifier & depth */ 1227 feeReturn frtn = feeAlgIdToDepth(&nssPrivKeyInfo.algorithm, depth); 1228 if(frtn) { 1229 return frtn; 1230 } 1231 1232 /* 1233 * nssPrivKeyInfo.privateKey is an octet string containing an encoded 1234 * NSS_ECDSA_PrivateKey. 1235 */ 1236 frtn = feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo.privateKey.Data, 1237 (unsigned)nssPrivKeyInfo.privateKey.Length, depth, 1238 privBlob, privBlobLen, 1239 pubBlob, pubBlobLen); 1240 1241 return frtn; 1242 } 1243