]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/CryptKitDER.cpp
Security-59306.11.20.tar.gz
[apple/security.git] / OSX / libsecurity_cryptkit / lib / 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() throw() {}
59 feeReturn frtn() const throw() { 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