]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_cryptkit/lib/CryptKitDER.cpp
Security-57031.30.12.tar.gz
[apple/security.git] / Security / 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 #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 */
52 class feeException
53 {
54 protected:
55 feeException(feeReturn frtn, const char *op);
56 public:
57 ~feeException() throw() {}
58 feeReturn frtn() const throw() { return mFrtn; }
59 static void throwMe(feeReturn frtn, const char *op = NULL) __attribute__((noreturn));
60 private:
61 feeReturn mFrtn;
62 };
63
64 feeException::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
74 void 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 */
93 static 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... */
102 unsigned 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 */
113 static 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 */
136 static 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 */
158 static 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 */
190 static 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);
269 abort:
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 */
364 static 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
400 static 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 */
442 feeReturn 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
482 feeReturn 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
522 feeReturn 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
557 feeReturn 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 */
596 feeReturn 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
638 feeReturn 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
674 feeReturn 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
717 feeReturn 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 */
752 static 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
770 static 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 */
798 static 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 */
826 static 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 */
850 feeReturn 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
893 feeReturn 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 */
935 feeReturn 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
996 feeReturn 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 */
1053 feeReturn 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);
1105 errOut:
1106 if(encPriv) {
1107 ffree(encPriv);
1108 }
1109 return frtn;
1110 }
1111
1112 feeReturn 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 */