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#if CRYPTKIT_DER_ENABLE 28 29#include <security_cryptkit/CryptKitDER.h> 30#include <security_cryptkit/falloc.h> 31#include <security_cryptkit/feeDebug.h> 32#include <security_cryptkit/feeFunctions.h> 33#include "CryptKitAsn1.h" 34#include <security_asn1/SecNssCoder.h> 35#include <security_asn1/nssUtils.h> 36#include <Security/keyTemplates.h> 37#include <Security/oidsalg.h> 38#include <Security/oidsattr.h> 39 40#define PRINT_SIG_GIANTS 0 41#define PRINT_CURVE_PARAMS 0 42#define PRINT_SIZES 0 43#if PRINT_SIZES 44#define szprint(s) printf s 45#else 46#define szprint(s) 47#endif 48 49/* 50 * Trivial exception class associated with a feeReturn. 51 */ 52class feeException 53{ 54protected: 55 feeException(feeReturn frtn, const char *op); 56public: 57 ~feeException() throw() {} 58 feeReturn frtn() const throw() { return mFrtn; } 59 static void throwMe(feeReturn frtn, const char *op = NULL) __attribute__((noreturn)); 60private: 61 feeReturn mFrtn; 62}; 63 64feeException::feeException( 65 feeReturn frtn, 66 const char *op) 67 : mFrtn(frtn) 68{ 69 if(op) { 70 dbgLog(("%s: %s\n", op, feeReturnString(frtn))); 71 } 72} 73 74void feeException::throwMe(feeReturn frtn, const char *op /*= NULL*/) { throw feeException(frtn, op); } 75 76/* 77 * ASN1 encoding rules specify that an integer's sign is indicated by the MSB 78 * of the first (MS) content byte. For a non-negative number, if the MSB of 79 * the MS byte (of the unencoded number) is one, then the encoding starts with 80 * a byte of zeroes to indicate positive sign. For a negative number, the first 81 * nine bits can not be all 1 - if they are (in the undecoded number), leading 82 * bytes of 0xff are trimmed off until the first nine bits are something other 83 * than one. Also, the first nine bits of the encoded number can not all be 84 * zero. 85 * 86 * CryptKit giants express their sign as part of the giantstruct.sign field. 87 * The giantDigit array (giantstruct.n[]) is stored l.s. digit first. 88 * 89 * These routines are independent of platform, endianness, and giatn digit size. 90 */ 91 92/* routines to guess maximum size of DER-encoded objects */ 93static unsigned feeSizeOfSnaccGiant( 94 giant g) 95{ 96 unsigned rtn = abs(g->sign) * GIANT_BYTES_PER_DIGIT; 97 szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g->sign, rtn + 4)); 98 return rtn + 4; 99} 100 101/* PUBLIC... */ 102unsigned feeSizeOfDERSig( 103 giant g1, 104 giant g2) 105{ 106 unsigned rtn = feeSizeOfSnaccGiant(g1); 107 rtn += feeSizeOfSnaccGiant(g2); 108 szprint(("feeSizeOfDERSig: size %d\n", rtn + 4)); 109 return rtn + 4; 110} 111 112/* perform 2's complement of byte array, expressed MS byte first */ 113static void twosComplement( 114 unsigned char *bytePtr, // points to MS byte 115 unsigned numBytes) 116{ 117 unsigned char *outp = bytePtr + numBytes - 1; 118 unsigned char carry = 1; // first time thru, carry = 1 to add one to 1's comp 119 for(unsigned byteDex=0; byteDex<numBytes; byteDex++) { 120 /* first complement, then add carry */ 121 *outp = ~*outp + carry; 122 if(carry && (*outp == 0)) { 123 /* overflow/carry */ 124 carry = 1; 125 } 126 else { 127 carry = 0; 128 } 129 outp--; 130 } 131} 132 133/* 134 * CSSM_DATA --> unsigned int 135 */ 136static unsigned cssmDataToInt( 137 const CSSM_DATA &cdata) 138{ 139 if((cdata.Length == 0) || (cdata.Data == NULL)) { 140 return 0; 141 } 142 unsigned len = (unsigned)cdata.Length; 143 if(len > sizeof(int)) { 144 feeException::throwMe(FR_BadKeyBlob, "cssmDataToInt"); 145 } 146 147 unsigned rtn = 0; 148 uint8 *cp = cdata.Data; 149 for(unsigned i=0; i<len; i++) { 150 rtn = (rtn << 8) | *cp++; 151 } 152 return rtn; 153} 154 155/* 156 * unsigned int --> CSSM_DATA, mallocing from an SecNssCoder 157 */ 158static void intToCssmData( 159 unsigned num, 160 CSSM_DATA &cdata, 161 SecNssCoder &coder) 162{ 163 unsigned len = 0; 164 165 if(num < 0x100) { 166 len = 1; 167 } 168 else if(num < 0x10000) { 169 len = 2; 170 } 171 else if(num < 0x1000000) { 172 len = 3; 173 } 174 else { 175 len = 4; 176 } 177 cdata.Data = (uint8 *)coder.malloc(len); 178 cdata.Length = len; 179 uint8 *cp = &cdata.Data[len - 1]; 180 for(unsigned i=0; i<len; i++) { 181 *cp-- = num & 0xff; 182 num >>= 8; 183 } 184} 185 186/* 187 * Convert a decoded ASN integer, as a CSSM_DATA, to a (mallocd) giant. 188 * Only known exception is a feeException. 189 */ 190static giant cssmDataToGiant( 191 const CSSM_DATA &cdata) 192{ 193 char *rawOcts = (char *)cdata.Data; 194 unsigned numBytes = (unsigned)cdata.Length; 195 unsigned numGiantDigits; 196 int sign = 1; 197 giant grtn; 198 feeReturn frtn = FR_Success; 199 unsigned char *inp = NULL; 200 unsigned digitDex; // index into g->giantDigit[] 201 202 /* handle degenerate case (value of zero) */ 203 if((numBytes == 0) || ((numBytes == 1) && rawOcts[0] == 0)) { 204 grtn = newGiant(1); 205 if(grtn == NULL) { 206 feeException::throwMe(FR_Memory, "newGiant(1)"); 207 } 208 int_to_giant(0, grtn); 209 return grtn; 210 } 211 212 /* make a copy of raw octets if we have to do two's complement */ 213 unsigned char *byteArray = NULL; 214 bool didMalloc = false; 215 if(rawOcts[0] & 0x80) { 216 sign = -1; 217 numBytes++; 218 byteArray = (unsigned char *)fmalloc(numBytes); 219 didMalloc = true; 220 byteArray[0] = 0xff; 221 memmove(byteArray + 1, rawOcts, numBytes-1); 222 twosComplement(byteArray, numBytes); 223 } 224 else { 225 /* no copy */ 226 char *foo = rawOcts; 227 byteArray = (unsigned char *)foo; 228 } 229 230 /* cook up a new giant */ 231 numGiantDigits = (numBytes + GIANT_BYTES_PER_DIGIT - 1) / 232 GIANT_BYTES_PER_DIGIT; 233 grtn = newGiant(numGiantDigits); 234 if(grtn == NULL) { 235 frtn = FR_Memory; 236 goto abort; 237 } 238 239 /* 240 * Convert byteArray to array of giantDigits 241 * inp - raw input bytes, LSB last 242 * grtn->n[] - output array of giantDigits, LSD first 243 * Start at LS byte and LD digit 244 */ 245 digitDex = 0; // index into g->giantDigit[] 246 giantDigit thisDigit; 247 inp = byteArray + numBytes - 1; 248 unsigned dex; // total byte counter 249 unsigned byteDex; // index into one giantDigit 250 unsigned shiftCount; 251 for(dex=0; dex<numBytes; ) { // increment dex inside 252 thisDigit = 0; 253 shiftCount = 0; 254 for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) { 255 thisDigit |= ((giantDigit)(*inp--) << shiftCount); 256 shiftCount += 8; 257 if(++dex == numBytes) { 258 /* must be partial giantDigit */ 259 break; 260 } 261 } 262 CKASSERT(digitDex < numGiantDigits); 263 grtn->n[digitDex++] = thisDigit; 264 } 265 grtn->sign = (int)numGiantDigits * sign; 266 267 /* trim leading (MS) zeroes */ 268 gtrimSign(grtn); 269abort: 270 if(didMalloc) { 271 ffree(byteArray); 272 } 273 if(frtn) { 274 feeException::throwMe(frtn, "bigIntStrToGiant"); 275 } 276 return grtn; 277} 278 279/* 280 * Convert a giant to an CSSM_DATA, mallocing using specified coder. 281 * Only known exception is a feeException. 282 */ 283 static void giantToCssmData( 284 giant g, 285 CSSM_DATA &cdata, 286 SecNssCoder &coder) 287{ 288 unsigned char doPrepend = 0; 289 unsigned numGiantDigits = abs(g->sign); 290 unsigned numBytes = numGiantDigits * GIANT_BYTES_PER_DIGIT; 291 giantDigit msGiantBit = 0; 292 if(isZero(g)) { 293 /* special degenerate case */ 294 intToCssmData(0, cdata, coder); 295 return; 296 } 297 else { 298 msGiantBit = g->n[numGiantDigits - 1] >> (GIANT_BITS_PER_DIGIT - 1); 299 } 300 301 /* prepend a byte of zero if necessary */ 302 if((g->sign < 0) || // negative - to handle 2's complement 303 ((g->sign > 0) && msGiantBit)) { // ensure MS byte is zero 304 doPrepend = 1; 305 numBytes++; 306 } 307 308 unsigned char *rawBytes = (unsigned char *)fmalloc(numBytes); 309 if(rawBytes == NULL) { 310 feeException::throwMe(FR_Memory, "giantToBigIntStr fmalloc(rawBytes)"); 311 } 312 unsigned char *outp = rawBytes; 313 if(doPrepend) { 314 *outp++ = 0; 315 } 316 317 /* 318 * Convert array of giantDigits to bytes. 319 * outp point to MS output byte. 320 */ 321 int digitDex; // index into g->giantDigit[] 322 unsigned byteDex; // byte index into a giantDigit 323 for(digitDex=numGiantDigits-1; digitDex>=0; digitDex--) { 324 /* one loop per giantDigit, starting at MS end */ 325 giantDigit thisDigit = g->n[digitDex]; 326 unsigned char *bp = outp + GIANT_BYTES_PER_DIGIT - 1; 327 for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) { 328 /* one loop per byte within the digit, starting at LS end */ 329 *bp-- = (unsigned char)(thisDigit) & 0xff; 330 thisDigit >>= 8; 331 } 332 outp += GIANT_BYTES_PER_DIGIT; 333 } 334 335 /* do two's complement for negative giants */ 336 if(g->sign < 0) { 337 twosComplement(rawBytes, numBytes); 338 } 339 340 /* strip off redundant leading bits (nine zeroes or nine ones) */ 341 outp = rawBytes; 342 unsigned char *endp = outp + numBytes - 1; 343 while((*outp == 0) && // m.s. byte zero 344 (outp < endp) && // more bytes exist 345 (!(outp[1] & 0x80))) { // 9th bit is 0 346 outp++; 347 numBytes--; 348 } 349 while((*outp == 0xff) && // m.s. byte all ones 350 (outp < endp) && // more bytes exist 351 (outp[1] & 0x80)) { // 9th bit is 1 352 outp++; 353 numBytes--; 354 } 355 cdata.Data = (uint8 *)coder.malloc(numBytes); 356 memmove(cdata.Data, outp, numBytes); 357 cdata.Length = numBytes; 358 ffree(rawBytes); 359 return; 360} 361 362/* curveParams : CryptKit <--> FEECurveParametersASN1 */ 363/* Only known exception is a feeException */ 364static void feeCurveParamsToASN1( 365 const curveParams *cp, 366 FEECurveParametersASN1 &asnCp, 367 SecNssCoder &coder) 368{ 369 #if PRINT_CURVE_PARAMS 370 printf("===encoding curveParams; cp:\n"); printCurveParams(cp); 371 #endif 372 memset(&asnCp, 0, sizeof(asnCp)); 373 try { 374 intToCssmData(cp->primeType, asnCp.primeType, coder); 375 intToCssmData(cp->curveType, asnCp.curveType, coder); 376 intToCssmData(cp->q, asnCp.q, coder); 377 intToCssmData(cp->k, asnCp.k, coder); 378 intToCssmData(cp->m, asnCp.m, coder); 379 giantToCssmData(cp->a, asnCp.a, coder); 380 giantToCssmData(cp->b, asnCp.b_, coder); 381 giantToCssmData(cp->c, asnCp.c, coder); 382 giantToCssmData(cp->x1Plus, asnCp.x1Plus, coder); 383 giantToCssmData(cp->x1Minus, asnCp.x1Minus, coder); 384 giantToCssmData(cp->cOrderPlus, asnCp.cOrderPlus, coder); 385 giantToCssmData(cp->cOrderMinus, asnCp.cOrderMinus, coder); 386 giantToCssmData(cp->x1OrderPlus, asnCp.x1OrderPlus, coder); 387 giantToCssmData(cp->x1OrderMinus, asnCp.x1OrderMinus, coder); 388 if(cp->primeType == FPT_General) { 389 giantToCssmData(cp->basePrime, asnCp.basePrime, coder); 390 } 391 } 392 catch(const feeException &ferr) { 393 throw; 394 } 395 catch(...) { 396 feeException::throwMe(FR_Memory, "feeCurveParamsToSnacc catchall"); // ??? 397 } 398} 399 400static curveParams *feeCurveParamsFromAsn1( 401 const FEECurveParametersASN1 &asnCp) 402{ 403 curveParams *cp = newCurveParams(); 404 if(cp == NULL) { 405 feeException::throwMe(FR_Memory, "feeCurveParamsFromSnacc alloc cp"); 406 } 407 cp->primeType = (feePrimeType)cssmDataToInt(asnCp.primeType); 408 cp->curveType = (feeCurveType)cssmDataToInt(asnCp.curveType); 409 cp->q = cssmDataToInt(asnCp.q); 410 cp->k = cssmDataToInt(asnCp.k); 411 cp->m = cssmDataToInt(asnCp.m); 412 cp->a = cssmDataToGiant(asnCp.a); 413 cp->b = cssmDataToGiant(asnCp.b_); 414 cp->c = cssmDataToGiant(asnCp.c); 415 cp->x1Plus = cssmDataToGiant(asnCp.x1Plus); 416 cp->x1Minus = cssmDataToGiant(asnCp.x1Minus); 417 cp->cOrderPlus = cssmDataToGiant(asnCp.cOrderPlus); 418 cp->cOrderMinus = cssmDataToGiant(asnCp.cOrderMinus); 419 cp->x1OrderPlus = cssmDataToGiant(asnCp.x1OrderPlus); 420 cp->x1OrderMinus = cssmDataToGiant(asnCp.x1OrderMinus); 421 if(asnCp.basePrime.Data != NULL) { 422 cp->basePrime = cssmDataToGiant(asnCp.basePrime); 423 } 424 425 /* remaining fields inferred */ 426 curveParamsInferFields(cp); 427 allocRecipGiants(cp); 428 #if PRINT_CURVE_PARAMS 429 printf("===decoding curveParams; cp:\n"); printCurveParams(cp); 430 #endif 431 return cp; 432} 433 434/*** 435 *** Public routines. These are usable from C code; they never throw. 436 ***/ 437 438/* 439 * Encode/decode the two FEE signature types. We malloc returned data via 440 * fmalloc(); caller must free via ffree(). 441 */ 442feeReturn feeDEREncodeElGamalSignature( 443 giant u, 444 giant PmX, 445 unsigned char **encodedSig, // fmallocd and RETURNED 446 unsigned *encodedSigLen) // RETURNED 447{ 448 /* convert to FEEElGamalSignatureASN1 */ 449 FEEElGamalSignatureASN1 asnSig; 450 SecNssCoder coder; 451 452 try { 453 giantToCssmData(u, asnSig.u, coder); 454 giantToCssmData(PmX, asnSig.pmX, coder); 455 } 456 catch(const feeException &ferr) { 457 return ferr.frtn(); 458 } 459 460 /* DER encode */ 461 PRErrorCode perr; 462 CSSM_DATA encBlob; // mallocd by coder 463 perr = coder.encodeItem(&asnSig, FEEElGamalSignatureASN1Template, encBlob); 464 if(perr) { 465 return FR_Memory; 466 } 467 468 /* copy out to caller */ 469 *encodedSig = (unsigned char *)fmalloc((unsigned)encBlob.Length); 470 *encodedSigLen = (unsigned)encBlob.Length; 471 memmove(*encodedSig, encBlob.Data, encBlob.Length); 472 473 #if PRINT_SIG_GIANTS 474 printf("feeEncodeElGamalSignature:\n"); 475 printf(" u : "); printGiantHex(u); 476 printf(" PmX : "); printGiantHex(PmX); 477 #endif 478 479 return FR_Success; 480} 481 482feeReturn feeDEREncodeECDSASignature( 483 giant c, 484 giant d, 485 unsigned char **encodedSig, // fmallocd and RETURNED 486 unsigned *encodedSigLen) // RETURNED 487{ 488 /* convert to FEEECDSASignatureASN1 */ 489 FEEECDSASignatureASN1 asnSig; 490 SecNssCoder coder; 491 492 try { 493 giantToCssmData(c, asnSig.c, coder); 494 giantToCssmData(d, asnSig.d, coder); 495 } 496 catch(const feeException &ferr) { 497 return ferr.frtn(); 498 } 499 500 /* DER encode */ 501 PRErrorCode perr; 502 CSSM_DATA encBlob; // mallocd by coder 503 perr = coder.encodeItem(&asnSig, FEEECDSASignatureASN1Template, encBlob); 504 if(perr) { 505 return FR_Memory; 506 } 507 508 /* copy out to caller */ 509 *encodedSig = (unsigned char *)fmalloc((unsigned)encBlob.Length); 510 *encodedSigLen = (unsigned)encBlob.Length; 511 memmove(*encodedSig, encBlob.Data, encBlob.Length); 512 513 #if PRINT_SIG_GIANTS 514 printf("feeEncodeECDSASignature:\n"); 515 printf(" c : "); printGiantHex(*c); 516 printf(" d : "); printGiantHex(*d); 517 #endif 518 return FR_Success; 519 520} 521 522feeReturn feeDERDecodeElGamalSignature( 523 const unsigned char *encodedSig, 524 size_t encodedSigLen, 525 giant *u, // newGiant'd and RETURNED 526 giant *PmX) // newGiant'd and RETURNED 527{ 528 FEEElGamalSignatureASN1 asnSig; 529 SecNssCoder coder; 530 531 memset(&asnSig, 0, sizeof(asnSig)); 532 PRErrorCode perr = coder.decode(encodedSig, encodedSigLen, 533 FEEElGamalSignatureASN1Template, &asnSig); 534 if(perr) { 535 return FR_BadSignatureFormat; 536 } 537 538 try { 539 *u = cssmDataToGiant(asnSig.u); 540 *PmX = cssmDataToGiant(asnSig.pmX); 541 } 542 catch(const feeException &ferr) { 543 return ferr.frtn(); 544 } 545 catch(...) { 546 /* FIXME - bad sig? memory? */ 547 return FR_Memory; 548 } 549 #if PRINT_SIG_GIANTS 550 printf("feeDecodeElGamalSignature:\n"); 551 printf(" u : "); printGiantHex(*u); 552 printf(" PmX : "); printGiantHex(*PmX); 553 #endif 554 return FR_Success; 555} 556 557feeReturn feeDERDecodeECDSASignature( 558 const unsigned char *encodedSig, 559 size_t encodedSigLen, 560 giant *c, // newGiant'd and RETURNED 561 giant *d) // newGiant'd and RETURNED 562{ 563 FEEECDSASignatureASN1 asnSig; 564 SecNssCoder coder; 565 566 memset(&asnSig, 0, sizeof(asnSig)); 567 PRErrorCode perr = coder.decode(encodedSig, encodedSigLen, 568 FEEECDSASignatureASN1Template, &asnSig); 569 if(perr) { 570 return FR_BadSignatureFormat; 571 } 572 573 try { 574 *c = cssmDataToGiant(asnSig.c); 575 *d = cssmDataToGiant(asnSig.d); 576 } 577 catch(const feeException &ferr) { 578 return ferr.frtn(); 579 } 580 catch(...) { 581 /* FIXME - bad sig? memory? */ 582 return FR_Memory; 583 } 584 #if PRINT_SIG_GIANTS 585 printf("feeDERDecodeECDSASignature:\n"); 586 printf(" u : "); printGiantHex(*u); 587 printf(" PmX : "); printGiantHex(*PmX); 588 #endif 589 return FR_Success; 590} 591 592/* 593 * Encode/decode the FEE private and public keys. We malloc returned data via 594 * falloc(); caller must free via ffree(). Public C functions which never throw. 595 */ 596feeReturn feeDEREncodePublicKey( 597 int version, 598 const curveParams *cp, 599 giant plusX, 600 giant minusX, 601 giant plusY, // may be NULL 602 unsigned char **keyBlob, // fmallocd and RETURNED 603 unsigned *keyBlobLen) // RETURNED 604{ 605 FEEPublicKeyASN1 asnKey; 606 SecNssCoder coder; 607 608 memset(&asnKey, 0, sizeof(asnKey)); 609 intToCssmData(version, asnKey.version, coder); 610 611 try { 612 feeCurveParamsToASN1(cp, asnKey.curveParams, coder); 613 giantToCssmData(plusX, asnKey.plusX, coder); 614 giantToCssmData(minusX, asnKey.minusX, coder); 615 if(plusY != NULL) { 616 giantToCssmData(plusY, asnKey.plusY, coder); 617 } 618 } 619 catch(const feeException &ferr) { 620 return ferr.frtn(); 621 } 622 623 /* DER encode */ 624 PRErrorCode perr; 625 CSSM_DATA encBlob; // mallocd by coder 626 perr = coder.encodeItem(&asnKey, FEEPublicKeyASN1Template, encBlob); 627 if(perr) { 628 return FR_Memory; 629 } 630 631 /* copy out */ 632 *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length); 633 *keyBlobLen = (unsigned)encBlob.Length; 634 memmove(*keyBlob, encBlob.Data, encBlob.Length); 635 return FR_Success; 636} 637 638feeReturn feeDEREncodePrivateKey( 639 int version, 640 const curveParams *cp, 641 const giant privData, 642 unsigned char **keyBlob, // fmallocd and RETURNED 643 unsigned *keyBlobLen) // RETURNED 644{ 645 FEEPrivateKeyASN1 asnKey; 646 SecNssCoder coder; 647 648 memset(&asnKey, 0, sizeof(asnKey)); 649 intToCssmData(version, asnKey.version, coder); 650 651 try { 652 feeCurveParamsToASN1(cp, asnKey.curveParams, coder); 653 giantToCssmData(privData, asnKey.privData, coder); 654 } 655 catch(const feeException &ferr) { 656 return ferr.frtn(); 657 } 658 659 /* DER encode */ 660 PRErrorCode perr; 661 CSSM_DATA encBlob; // mallocd by coder 662 perr = coder.encodeItem(&asnKey, FEEPrivateKeyASN1Template, encBlob); 663 if(perr) { 664 return FR_Memory; 665 } 666 667 /* copy out */ 668 *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length); 669 *keyBlobLen = (unsigned)encBlob.Length; 670 memmove(*keyBlob, encBlob.Data, encBlob.Length); 671 return FR_Success; 672} 673 674feeReturn feeDERDecodePublicKey( 675 const unsigned char *keyBlob, 676 unsigned keyBlobLen, 677 int *version, // this and remainder RETURNED 678 curveParams **cp, 679 giant *plusX, 680 giant *minusX, 681 giant *plusY) // may be NULL 682{ 683 FEEPublicKeyASN1 asnKey; 684 SecNssCoder coder; 685 686 memset(&asnKey, 0, sizeof(asnKey)); 687 PRErrorCode perr = coder.decode(keyBlob, keyBlobLen, 688 FEEPublicKeyASN1Template, &asnKey); 689 if(perr) { 690 return FR_BadKeyBlob; 691 } 692 693 try { 694 *version = cssmDataToInt(asnKey.version); 695 *cp = feeCurveParamsFromAsn1(asnKey.curveParams); 696 *plusX = cssmDataToGiant(asnKey.plusX); 697 *minusX = cssmDataToGiant(asnKey.minusX); 698 if(asnKey.plusY.Data != NULL) { 699 /* optional */ 700 *plusY = cssmDataToGiant(asnKey.plusY); 701 } 702 else { 703 *plusY = newGiant(1); 704 int_to_giant(0, *plusY); 705 } 706 } 707 catch(const feeException &ferr) { 708 return ferr.frtn(); 709 } 710 catch(...) { 711 /* FIXME - bad sig? memory? */ 712 return FR_Memory; 713 } 714 return FR_Success; 715} 716 717feeReturn feeDERDecodePrivateKey( 718 const unsigned char *keyBlob, 719 unsigned keyBlobLen, 720 int *version, // this and remainder RETURNED 721 curveParams **cp, 722 giant *privData) // RETURNED 723{ 724 FEEPrivateKeyASN1 asnKey; 725 SecNssCoder coder; 726 727 memset(&asnKey, 0, sizeof(asnKey)); 728 PRErrorCode perr = coder.decode(keyBlob, keyBlobLen, 729 FEEPrivateKeyASN1Template, &asnKey); 730 if(perr) { 731 return FR_BadKeyBlob; 732 } 733 734 try { 735 *version = cssmDataToInt(asnKey.version); 736 *cp = feeCurveParamsFromAsn1(asnKey.curveParams); 737 *privData = cssmDataToGiant(asnKey.privData); 738 } 739 catch(const feeException &ferr) { 740 return ferr.frtn(); 741 } 742 catch(...) { 743 /* FIXME - bad sig? memory? */ 744 return FR_Memory; 745 } 746 return FR_Success; 747} 748 749#pragma mark --- ECDSA support --- 750 751/* convert between feeDepth and curve OIDs */ 752static const CSSM_OID *depthToOid( 753 feeDepth depth) 754{ 755 switch(depth) { 756 case FEE_DEPTH_secp192r1: 757 return &CSSMOID_secp192r1; 758 case FEE_DEPTH_secp256r1: 759 return &CSSMOID_secp256r1; 760 case FEE_DEPTH_secp384r1: 761 return &CSSMOID_secp384r1; 762 case FEE_DEPTH_secp521r1: 763 return &CSSMOID_secp521r1; 764 default: 765 dbgLog(("depthToOid needs work\n")); 766 return NULL; 767 } 768} 769 770static feeReturn curveOidToFeeDepth( 771 const CSSM_OID *curveOid, 772 feeDepth *depth) /* RETURNED */ 773{ 774 if(nssCompareCssmData(curveOid, &CSSMOID_secp192r1)) { 775 *depth = FEE_DEPTH_secp192r1; 776 } 777 else if(nssCompareCssmData(curveOid, &CSSMOID_secp256r1)) { 778 *depth = FEE_DEPTH_secp256r1; 779 } 780 else if(nssCompareCssmData(curveOid, &CSSMOID_secp384r1)) { 781 *depth = FEE_DEPTH_secp384r1; 782 } 783 else if(nssCompareCssmData(curveOid, &CSSMOID_secp521r1)) { 784 *depth = FEE_DEPTH_secp521r1; 785 } 786 else { 787 dbgLog(("curveOidToFeeDepth: unknown curve OID\n")); 788 return FR_BadKeyBlob; 789 } 790 return FR_Success; 791} 792 793 794/* 795 * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer 796 * depth from its algorith.parameter 797 */ 798static feeReturn feeAlgIdToDepth( 799 const CSSM_X509_ALGORITHM_IDENTIFIER *algId, 800 feeDepth *depth) 801{ 802 const CSSM_OID *oid = &algId->algorithm; 803 /* FIXME what's the value here for a private key!? */ 804 if(!nssCompareCssmData(oid, &CSSMOID_ecPublicKey)) { 805 dbgLog(("feeAlgIdToDepth: bad OID")); 806 return FR_BadKeyBlob; 807 } 808 809 /* 810 * AlgId.params is curve OID, still encoded since it's an ASN_ANY. 811 * First two bytes of encoded OID are (06, length) 812 */ 813 const CSSM_DATA *param = &algId->parameters; 814 if((param->Length <= 2) || (param->Data[0] != BER_TAG_OID)) { 815 dbgLog(("feeAlgIdToDepth: no curve params\n")); 816 return FR_BadKeyBlob; 817 } 818 819 CSSM_OID decOid = {param->Length-2, algId->parameters.Data+2}; 820 return curveOidToFeeDepth(&decOid, depth); 821} 822 823/* 824 * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding. 825 */ 826static feeReturn feeSetupAlgId( 827 feeDepth depth, 828 SecNssCoder &coder, 829 CSSM_X509_ALGORITHM_IDENTIFIER &algId) 830{ 831 algId.algorithm = CSSMOID_ecPublicKey; 832 const CSSM_OID *curveOid = depthToOid(depth); 833 if(curveOid == NULL) { 834 return FR_IllegalDepth; 835 } 836 837 /* quick & dirty encode of the parameter OID; it's an ASN_ANY in the template */ 838 coder.allocItem(algId.parameters, curveOid->Length + 2); 839 algId.parameters.Data[0] = BER_TAG_OID; 840 algId.parameters.Data[1] = curveOid->Length; 841 memmove(algId.parameters.Data+2, curveOid->Data, curveOid->Length); 842 return FR_Success; 843} 844 845#pragma mark --- ECDSA public key, X.509 format --- 846 847/* 848 * Encode/decode public key in X.509 format. 849 */ 850feeReturn feeDEREncodeX509PublicKey( 851 const unsigned char *pubBlob, /* x and y octet string */ 852 unsigned pubBlobLen, 853 curveParams *cp, 854 unsigned char **x509Blob, /* fmallocd and RETURNED */ 855 unsigned *x509BlobLen) /* RETURNED */ 856{ 857 SecNssCoder coder; 858 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo; 859 860 memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo)); 861 862 /* The x/y string, to be encoded in a bit string */ 863 nssPubKeyInfo.subjectPublicKey.Data = (uint8 *)pubBlob; 864 nssPubKeyInfo.subjectPublicKey.Length = pubBlobLen * 8; 865 866 feeDepth depth; 867 feeReturn frtn = curveParamsDepth(cp, &depth); 868 if(frtn) { 869 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n")); 870 return frtn; 871 } 872 873 CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPubKeyInfo.algorithm; 874 frtn = feeSetupAlgId(depth, coder, algId); 875 if(frtn) { 876 return frtn; 877 } 878 879 /* DER encode */ 880 CSSM_DATA encBlob; // mallocd by coder 881 PRErrorCode perr = coder.encodeItem(&nssPubKeyInfo, kSecAsn1SubjectPublicKeyInfoTemplate, encBlob); 882 if(perr) { 883 return FR_Memory; 884 } 885 886 /* copy out */ 887 *x509Blob = (unsigned char *)fmalloc((unsigned)encBlob.Length); 888 *x509BlobLen = (unsigned)encBlob.Length; 889 memmove(*x509Blob, encBlob.Data, encBlob.Length); 890 return FR_Success; 891} 892 893feeReturn feeDERDecodeX509PublicKey( 894 const unsigned char *x509Blob, 895 unsigned x509BlobLen, 896 feeDepth *depth, /* RETURNED */ 897 unsigned char **pubBlob, /* x and y octet string RETURNED */ 898 unsigned *pubBlobLen) /* RETURNED */ 899{ 900 SecNssCoder coder; 901 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo; 902 PRErrorCode perr; 903 904 memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo)); 905 perr = coder.decode(x509Blob, x509BlobLen, kSecAsn1SubjectPublicKeyInfoTemplate, 906 &nssPubKeyInfo); 907 if(perr) { 908 dbgLog(("decode(SubjectPublicKeyInfo) error")); 909 return FR_BadKeyBlob; 910 } 911 912 /* verify alg identifier & depth */ 913 feeReturn frtn = feeAlgIdToDepth(&nssPubKeyInfo.algorithm, depth); 914 if(frtn) { 915 return frtn; 916 } 917 918 /* copy public key string - it's in bits here */ 919 CSSM_DATA *pubKey = &nssPubKeyInfo.subjectPublicKey; 920 unsigned keyLen =(unsigned) (pubKey->Length + 7) / 8; 921 *pubBlob = (unsigned char *)fmalloc(keyLen); 922 if(*pubBlob == NULL) { 923 return FR_Memory; 924 } 925 memmove(*pubBlob, pubKey->Data, keyLen); 926 *pubBlobLen = keyLen; 927 return FR_Success; 928} 929 930#pragma mark --- ECDSA keys, OpenSSL format --- 931 932/* 933 * Encode private, and decode private or public key, in unencrypted OpenSSL format. 934 */ 935feeReturn feeDEREncodeOpenSSLPrivateKey( 936 const unsigned char *privBlob, /* private data octet string */ 937 unsigned privBlobLen, 938 const unsigned char *pubBlob, /* public key, optional */ 939 unsigned pubBlobLen, 940 curveParams *cp, 941 unsigned char **openBlob, /* fmallocd and RETURNED */ 942 unsigned *openBlobLen) /* RETURNED */ 943{ 944 feeDepth depth; 945 const CSSM_OID *curveOid; 946 SecNssCoder coder; 947 948 NSS_ECDSA_PrivateKey ecdsaPrivKey; 949 memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey)); 950 uint8 vers = 1; 951 ecdsaPrivKey.version.Data = &vers; 952 ecdsaPrivKey.version.Length = 1; 953 ecdsaPrivKey.privateKey.Data = (uint8 *)privBlob; 954 ecdsaPrivKey.privateKey.Length = privBlobLen; 955 956 /* Params - ASN_ANY - actually the curve OID */ 957 if(curveParamsDepth(cp, &depth)) { 958 dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth")); 959 return FR_BadKeyBlob; 960 } 961 curveOid = depthToOid(depth); 962 if(curveOid == NULL) { 963 return FR_BadKeyBlob; 964 } 965 966 /* quickie DER-encode of the curve OID */ 967 try { 968 coder.allocItem(ecdsaPrivKey.params, curveOid->Length + 2); 969 } 970 catch(...) { 971 return FR_Memory; 972 } 973 ecdsaPrivKey.params.Data[0] = BER_TAG_OID; 974 ecdsaPrivKey.params.Data[1] = curveOid->Length; 975 memmove(ecdsaPrivKey.params.Data+2, curveOid->Data, curveOid->Length); 976 977 /* public key - optional - bit string, length in bits */ 978 if(pubBlob) { 979 ecdsaPrivKey.pubKey.Data = (uint8 *)pubBlob; 980 ecdsaPrivKey.pubKey.Length = pubBlobLen * 8; 981 } 982 983 CSSM_DATA encPriv = {0, NULL}; 984 PRErrorCode perr = coder.encodeItem(&ecdsaPrivKey, kSecAsn1ECDSAPrivateKeyInfoTemplate, encPriv); 985 if(perr) { 986 return FR_Memory; 987 } 988 989 /* copy out */ 990 *openBlob = (unsigned char *)fmalloc((unsigned)encPriv.Length); 991 *openBlobLen = (unsigned)encPriv.Length; 992 memmove(*openBlob, encPriv.Data, encPriv.Length); 993 return FR_Success; 994} 995 996feeReturn feeDERDecodeOpenSSLKey( 997 const unsigned char *osBlob, 998 unsigned osBlobLen, 999 feeDepth *depth, /* RETURNED */ 1000 unsigned char **privBlob, /* private data octet string RETURNED */ 1001 unsigned *privBlobLen, /* RETURNED */ 1002 unsigned char **pubBlob, /* public data octet string optionally RETURNED */ 1003 unsigned *pubBlobLen) 1004{ 1005 SecNssCoder coder; 1006 NSS_ECDSA_PrivateKey ecdsaPrivKey; 1007 memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey)); 1008 if(coder.decode(osBlob, osBlobLen, 1009 kSecAsn1ECDSAPrivateKeyInfoTemplate, &ecdsaPrivKey)) { 1010 dbgLog(("Error decoding openssl priv key\n")); 1011 return FR_BadKeyBlob; 1012 } 1013 1014 unsigned keyLen = (unsigned)ecdsaPrivKey.privateKey.Length; 1015 if(keyLen == 0) { 1016 dbgLog(("NULL priv key data in PKCS8\n")); 1017 } 1018 *privBlob = (unsigned char *)fmalloc(keyLen); 1019 if(*privBlob == NULL) { 1020 return FR_Memory; 1021 } 1022 *privBlobLen = keyLen; 1023 memmove(*privBlob, ecdsaPrivKey.privateKey.Data, keyLen); 1024 1025 /* curve OID --> depth */ 1026 if(ecdsaPrivKey.params.Data != NULL) { 1027 /* quickie decode */ 1028 const CSSM_DATA *param = &ecdsaPrivKey.params; 1029 if((param->Data[0] != BER_TAG_OID) || (param->Length <= 2)) { 1030 dbgLog(("feeDERDecodeOpenSSLKey: bad curve params\n")); 1031 return FR_BadKeyBlob; 1032 } 1033 CSSM_OID decOid = {param->Length-2, param->Data+2}; 1034 if(curveOidToFeeDepth(&decOid, depth)) { 1035 return FR_BadKeyBlob; 1036 } 1037 } 1038 1039 /* Public key, if it's there and caller wants it */ 1040 if((ecdsaPrivKey.pubKey.Length != 0) && (pubBlob != NULL)) { 1041 *pubBlobLen = (unsigned)(ecdsaPrivKey.pubKey.Length + 7) / 8; 1042 *pubBlob = (unsigned char *)fmalloc(*pubBlobLen); 1043 memmove(*pubBlob, ecdsaPrivKey.pubKey.Data, *pubBlobLen); 1044 } 1045 return FR_Success; 1046} 1047 1048#pragma mark --- ECDSA public key, PKCS8 format --- 1049 1050/* 1051 * Encode/decode private key in unencrypted PKCS8 format. 1052 */ 1053feeReturn feeDEREncodePKCS8PrivateKey( 1054 const unsigned char *privBlob, /* private data octet string */ 1055 unsigned privBlobLen, 1056 const unsigned char *pubBlob, /* public blob, optional */ 1057 unsigned pubBlobLen, 1058 curveParams *cp, 1059 unsigned char **pkcs8Blob, /* fmallocd and RETURNED */ 1060 unsigned *pkcs8BlobLen) /* RETURNED */ 1061{ 1062 /* First encode a NSS_ECDSA_PrivateKey */ 1063 unsigned char *encPriv = NULL; 1064 unsigned encPrivLen = 0; 1065 feeReturn frtn = feeDEREncodeOpenSSLPrivateKey(privBlob, privBlobLen, 1066 pubBlob, pubBlobLen, cp, &encPriv, &encPrivLen); 1067 if(frtn) { 1068 return frtn; 1069 } 1070 1071 /* That encoding goes into NSS_PrivateKeyInfo.private key */ 1072 SecNssCoder coder; 1073 NSS_PrivateKeyInfo nssPrivKeyInfo; 1074 CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPrivKeyInfo.algorithm; 1075 memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo)); 1076 nssPrivKeyInfo.privateKey.Data = (uint8 *)encPriv; 1077 nssPrivKeyInfo.privateKey.Length = encPrivLen; 1078 uint8 vers = 0; 1079 1080 feeDepth depth; 1081 frtn = curveParamsDepth(cp, &depth); 1082 if(frtn) { 1083 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n")); 1084 goto errOut; 1085 } 1086 frtn = feeSetupAlgId(depth, coder, algId); 1087 if(frtn) { 1088 goto errOut; 1089 } 1090 1091 nssPrivKeyInfo.version.Data = &vers; 1092 nssPrivKeyInfo.version.Length = 1; 1093 1094 /* DER encode */ 1095 CSSM_DATA encPrivInfo; // mallocd by coder 1096 if(coder.encodeItem(&nssPrivKeyInfo, kSecAsn1PrivateKeyInfoTemplate, encPrivInfo)) { 1097 frtn = FR_Memory; 1098 goto errOut; 1099 } 1100 1101 /* copy out */ 1102 *pkcs8Blob = (unsigned char *)fmalloc((unsigned)encPrivInfo.Length); 1103 *pkcs8BlobLen = (unsigned)encPrivInfo.Length; 1104 memmove(*pkcs8Blob, encPrivInfo.Data, encPrivInfo.Length); 1105errOut: 1106 if(encPriv) { 1107 ffree(encPriv); 1108 } 1109 return frtn; 1110} 1111 1112feeReturn feeDERDecodePKCS8PrivateKey( 1113 const unsigned char *pkcs8Blob, 1114 unsigned pkcs8BlobLen, 1115 feeDepth *depth, /* RETURNED */ 1116 unsigned char **privBlob, /* private data octet string RETURNED */ 1117 unsigned *privBlobLen, /* RETURNED */ 1118 unsigned char **pubBlob, /* optionally returned, if it's there */ 1119 unsigned *pubBlobLen) 1120{ 1121 NSS_PrivateKeyInfo nssPrivKeyInfo; 1122 PRErrorCode perr; 1123 SecNssCoder coder; 1124 1125 memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo)); 1126 perr = coder.decode(pkcs8Blob, pkcs8BlobLen, kSecAsn1PrivateKeyInfoTemplate, &nssPrivKeyInfo); 1127 if(perr) { 1128 dbgLog(("Error decoding top level PKCS8\n")); 1129 return FR_BadKeyBlob; 1130 } 1131 1132 /* verify alg identifier & depth */ 1133 feeReturn frtn = feeAlgIdToDepth(&nssPrivKeyInfo.algorithm, depth); 1134 if(frtn) { 1135 return frtn; 1136 } 1137 1138 /* 1139 * nssPrivKeyInfo.privateKey is an octet string containing an encoded 1140 * NSS_ECDSA_PrivateKey. 1141 */ 1142 frtn = feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo.privateKey.Data, 1143 (unsigned)nssPrivKeyInfo.privateKey.Length, depth, 1144 privBlob, privBlobLen, 1145 pubBlob, pubBlobLen); 1146 1147 return frtn; 1148} 1149 1150#endif /* CRYPTKIT_DER_ENABLE */ 1151