]> git.saurik.com Git - apple/security.git/blob - libsecurity_cryptkit/lib/CryptKitDER.cpp
Security-55471.tar.gz
[apple/security.git] / libsecurity_cryptkit / lib / CryptKitDER.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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 * Created 3/12/2001 by dmitch.
24 */
25
26 #include "ckconfig.h"
27
28 #if CRYPTKIT_DER_ENABLE
29
30 #include <security_cryptkit/CryptKitDER.h>
31 #include <security_cryptkit/falloc.h>
32 #include <security_cryptkit/feeDebug.h>
33 #include <security_cryptkit/feeFunctions.h>
34 #include "CryptKitAsn1.h"
35 #include <security_asn1/SecNssCoder.h>
36 #include <security_asn1/nssUtils.h>
37 #include <Security/keyTemplates.h>
38 #include <Security/oidsalg.h>
39 #include <Security/oidsattr.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, "giantToBigIntStr 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 feeReturn feeDEREncodeECDSASignature(
484 giant c,
485 giant d,
486 unsigned char **encodedSig, // fmallocd and RETURNED
487 unsigned *encodedSigLen) // RETURNED
488 {
489 /* convert to FEEECDSASignatureASN1 */
490 FEEECDSASignatureASN1 asnSig;
491 SecNssCoder coder;
492
493 try {
494 giantToCssmData(c, asnSig.c, coder);
495 giantToCssmData(d, asnSig.d, coder);
496 }
497 catch(const feeException &ferr) {
498 return ferr.frtn();
499 }
500
501 /* DER encode */
502 PRErrorCode perr;
503 CSSM_DATA encBlob; // mallocd by coder
504 perr = coder.encodeItem(&asnSig, FEEECDSASignatureASN1Template, encBlob);
505 if(perr) {
506 return FR_Memory;
507 }
508
509 /* copy out to caller */
510 *encodedSig = (unsigned char *)fmalloc((unsigned)encBlob.Length);
511 *encodedSigLen = (unsigned)encBlob.Length;
512 memmove(*encodedSig, encBlob.Data, encBlob.Length);
513
514 #if PRINT_SIG_GIANTS
515 printf("feeEncodeECDSASignature:\n");
516 printf(" c : "); printGiantHex(*c);
517 printf(" d : "); printGiantHex(*d);
518 #endif
519 return FR_Success;
520
521 }
522
523 feeReturn feeDERDecodeElGamalSignature(
524 const unsigned char *encodedSig,
525 size_t encodedSigLen,
526 giant *u, // newGiant'd and RETURNED
527 giant *PmX) // newGiant'd and RETURNED
528 {
529 FEEElGamalSignatureASN1 asnSig;
530 SecNssCoder coder;
531
532 memset(&asnSig, 0, sizeof(asnSig));
533 PRErrorCode perr = coder.decode(encodedSig, encodedSigLen,
534 FEEElGamalSignatureASN1Template, &asnSig);
535 if(perr) {
536 return FR_BadSignatureFormat;
537 }
538
539 try {
540 *u = cssmDataToGiant(asnSig.u);
541 *PmX = cssmDataToGiant(asnSig.pmX);
542 }
543 catch(const feeException &ferr) {
544 return ferr.frtn();
545 }
546 catch(...) {
547 /* FIXME - bad sig? memory? */
548 return FR_Memory;
549 }
550 #if PRINT_SIG_GIANTS
551 printf("feeDecodeElGamalSignature:\n");
552 printf(" u : "); printGiantHex(*u);
553 printf(" PmX : "); printGiantHex(*PmX);
554 #endif
555 return FR_Success;
556 }
557
558 feeReturn feeDERDecodeECDSASignature(
559 const unsigned char *encodedSig,
560 size_t encodedSigLen,
561 giant *c, // newGiant'd and RETURNED
562 giant *d) // newGiant'd and RETURNED
563 {
564 FEEECDSASignatureASN1 asnSig;
565 SecNssCoder coder;
566
567 memset(&asnSig, 0, sizeof(asnSig));
568 PRErrorCode perr = coder.decode(encodedSig, encodedSigLen,
569 FEEECDSASignatureASN1Template, &asnSig);
570 if(perr) {
571 return FR_BadSignatureFormat;
572 }
573
574 try {
575 *c = cssmDataToGiant(asnSig.c);
576 *d = cssmDataToGiant(asnSig.d);
577 }
578 catch(const feeException &ferr) {
579 return ferr.frtn();
580 }
581 catch(...) {
582 /* FIXME - bad sig? memory? */
583 return FR_Memory;
584 }
585 #if PRINT_SIG_GIANTS
586 printf("feeDERDecodeECDSASignature:\n");
587 printf(" u : "); printGiantHex(*u);
588 printf(" PmX : "); printGiantHex(*PmX);
589 #endif
590 return FR_Success;
591 }
592
593 /*
594 * Encode/decode the FEE private and public keys. We malloc returned data via
595 * falloc(); caller must free via ffree(). Public C functions which never throw.
596 */
597 feeReturn feeDEREncodePublicKey(
598 int version,
599 const curveParams *cp,
600 giant plusX,
601 giant minusX,
602 giant plusY, // may be NULL
603 unsigned char **keyBlob, // fmallocd and RETURNED
604 unsigned *keyBlobLen) // RETURNED
605 {
606 FEEPublicKeyASN1 asnKey;
607 SecNssCoder coder;
608
609 memset(&asnKey, 0, sizeof(asnKey));
610 intToCssmData(version, asnKey.version, coder);
611
612 try {
613 feeCurveParamsToASN1(cp, asnKey.curveParams, coder);
614 giantToCssmData(plusX, asnKey.plusX, coder);
615 giantToCssmData(minusX, asnKey.minusX, coder);
616 if(plusY != NULL) {
617 giantToCssmData(plusY, asnKey.plusY, coder);
618 }
619 }
620 catch(const feeException &ferr) {
621 return ferr.frtn();
622 }
623
624 /* DER encode */
625 PRErrorCode perr;
626 CSSM_DATA encBlob; // mallocd by coder
627 perr = coder.encodeItem(&asnKey, FEEPublicKeyASN1Template, encBlob);
628 if(perr) {
629 return FR_Memory;
630 }
631
632 /* copy out */
633 *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
634 *keyBlobLen = (unsigned)encBlob.Length;
635 memmove(*keyBlob, encBlob.Data, encBlob.Length);
636 return FR_Success;
637 }
638
639 feeReturn feeDEREncodePrivateKey(
640 int version,
641 const curveParams *cp,
642 const giant privData,
643 unsigned char **keyBlob, // fmallocd and RETURNED
644 unsigned *keyBlobLen) // RETURNED
645 {
646 FEEPrivateKeyASN1 asnKey;
647 SecNssCoder coder;
648
649 memset(&asnKey, 0, sizeof(asnKey));
650 intToCssmData(version, asnKey.version, coder);
651
652 try {
653 feeCurveParamsToASN1(cp, asnKey.curveParams, coder);
654 giantToCssmData(privData, asnKey.privData, coder);
655 }
656 catch(const feeException &ferr) {
657 return ferr.frtn();
658 }
659
660 /* DER encode */
661 PRErrorCode perr;
662 CSSM_DATA encBlob; // mallocd by coder
663 perr = coder.encodeItem(&asnKey, FEEPrivateKeyASN1Template, encBlob);
664 if(perr) {
665 return FR_Memory;
666 }
667
668 /* copy out */
669 *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
670 *keyBlobLen = (unsigned)encBlob.Length;
671 memmove(*keyBlob, encBlob.Data, encBlob.Length);
672 return FR_Success;
673 }
674
675 feeReturn feeDERDecodePublicKey(
676 const unsigned char *keyBlob,
677 unsigned keyBlobLen,
678 int *version, // this and remainder RETURNED
679 curveParams **cp,
680 giant *plusX,
681 giant *minusX,
682 giant *plusY) // may be NULL
683 {
684 FEEPublicKeyASN1 asnKey;
685 SecNssCoder coder;
686
687 memset(&asnKey, 0, sizeof(asnKey));
688 PRErrorCode perr = coder.decode(keyBlob, keyBlobLen,
689 FEEPublicKeyASN1Template, &asnKey);
690 if(perr) {
691 return FR_BadKeyBlob;
692 }
693
694 try {
695 *version = cssmDataToInt(asnKey.version);
696 *cp = feeCurveParamsFromAsn1(asnKey.curveParams);
697 *plusX = cssmDataToGiant(asnKey.plusX);
698 *minusX = cssmDataToGiant(asnKey.minusX);
699 if(asnKey.plusY.Data != NULL) {
700 /* optional */
701 *plusY = cssmDataToGiant(asnKey.plusY);
702 }
703 else {
704 *plusY = newGiant(1);
705 int_to_giant(0, *plusY);
706 }
707 }
708 catch(const feeException &ferr) {
709 return ferr.frtn();
710 }
711 catch(...) {
712 /* FIXME - bad sig? memory? */
713 return FR_Memory;
714 }
715 return FR_Success;
716 }
717
718 feeReturn feeDERDecodePrivateKey(
719 const unsigned char *keyBlob,
720 unsigned keyBlobLen,
721 int *version, // this and remainder RETURNED
722 curveParams **cp,
723 giant *privData) // RETURNED
724 {
725 FEEPrivateKeyASN1 asnKey;
726 SecNssCoder coder;
727
728 memset(&asnKey, 0, sizeof(asnKey));
729 PRErrorCode perr = coder.decode(keyBlob, keyBlobLen,
730 FEEPrivateKeyASN1Template, &asnKey);
731 if(perr) {
732 return FR_BadKeyBlob;
733 }
734
735 try {
736 *version = cssmDataToInt(asnKey.version);
737 *cp = feeCurveParamsFromAsn1(asnKey.curveParams);
738 *privData = cssmDataToGiant(asnKey.privData);
739 }
740 catch(const feeException &ferr) {
741 return ferr.frtn();
742 }
743 catch(...) {
744 /* FIXME - bad sig? memory? */
745 return FR_Memory;
746 }
747 return FR_Success;
748 }
749
750 #pragma mark --- ECDSA support ---
751
752 /* convert between feeDepth and curve OIDs */
753 static const CSSM_OID *depthToOid(
754 feeDepth depth)
755 {
756 switch(depth) {
757 case FEE_DEPTH_secp192r1:
758 return &CSSMOID_secp192r1;
759 case FEE_DEPTH_secp256r1:
760 return &CSSMOID_secp256r1;
761 case FEE_DEPTH_secp384r1:
762 return &CSSMOID_secp384r1;
763 case FEE_DEPTH_secp521r1:
764 return &CSSMOID_secp521r1;
765 default:
766 dbgLog(("depthToOid needs work\n"));
767 return NULL;
768 }
769 }
770
771 static feeReturn curveOidToFeeDepth(
772 const CSSM_OID *curveOid,
773 feeDepth *depth) /* RETURNED */
774 {
775 if(nssCompareCssmData(curveOid, &CSSMOID_secp192r1)) {
776 *depth = FEE_DEPTH_secp192r1;
777 }
778 else if(nssCompareCssmData(curveOid, &CSSMOID_secp256r1)) {
779 *depth = FEE_DEPTH_secp256r1;
780 }
781 else if(nssCompareCssmData(curveOid, &CSSMOID_secp384r1)) {
782 *depth = FEE_DEPTH_secp384r1;
783 }
784 else if(nssCompareCssmData(curveOid, &CSSMOID_secp521r1)) {
785 *depth = FEE_DEPTH_secp521r1;
786 }
787 else {
788 dbgLog(("curveOidToFeeDepth: unknown curve OID\n"));
789 return FR_BadKeyBlob;
790 }
791 return FR_Success;
792 }
793
794
795 /*
796 * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer
797 * depth from its algorith.parameter
798 */
799 static feeReturn feeAlgIdToDepth(
800 const CSSM_X509_ALGORITHM_IDENTIFIER *algId,
801 feeDepth *depth)
802 {
803 const CSSM_OID *oid = &algId->algorithm;
804 /* FIXME what's the value here for a private key!? */
805 if(!nssCompareCssmData(oid, &CSSMOID_ecPublicKey)) {
806 dbgLog(("feeAlgIdToDepth: bad OID"));
807 return FR_BadKeyBlob;
808 }
809
810 /*
811 * AlgId.params is curve OID, still encoded since it's an ASN_ANY.
812 * First two bytes of encoded OID are (06, length)
813 */
814 const CSSM_DATA *param = &algId->parameters;
815 if((param->Length <= 2) || (param->Data[0] != BER_TAG_OID)) {
816 dbgLog(("feeAlgIdToDepth: no curve params\n"));
817 return FR_BadKeyBlob;
818 }
819
820 CSSM_OID decOid = {param->Length-2, algId->parameters.Data+2};
821 return curveOidToFeeDepth(&decOid, depth);
822 }
823
824 /*
825 * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding.
826 */
827 static feeReturn feeSetupAlgId(
828 feeDepth depth,
829 SecNssCoder &coder,
830 CSSM_X509_ALGORITHM_IDENTIFIER &algId)
831 {
832 algId.algorithm = CSSMOID_ecPublicKey;
833 const CSSM_OID *curveOid = depthToOid(depth);
834 if(curveOid == NULL) {
835 return FR_IllegalDepth;
836 }
837
838 /* quick & dirty encode of the parameter OID; it's an ASN_ANY in the template */
839 coder.allocItem(algId.parameters, curveOid->Length + 2);
840 algId.parameters.Data[0] = BER_TAG_OID;
841 algId.parameters.Data[1] = curveOid->Length;
842 memmove(algId.parameters.Data+2, curveOid->Data, curveOid->Length);
843 return FR_Success;
844 }
845
846 #pragma mark --- ECDSA public key, X.509 format ---
847
848 /*
849 * Encode/decode public key in X.509 format.
850 */
851 feeReturn feeDEREncodeX509PublicKey(
852 const unsigned char *pubBlob, /* x and y octet string */
853 unsigned pubBlobLen,
854 curveParams *cp,
855 unsigned char **x509Blob, /* fmallocd and RETURNED */
856 unsigned *x509BlobLen) /* RETURNED */
857 {
858 SecNssCoder coder;
859 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo;
860
861 memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo));
862
863 /* The x/y string, to be encoded in a bit string */
864 nssPubKeyInfo.subjectPublicKey.Data = (uint8 *)pubBlob;
865 nssPubKeyInfo.subjectPublicKey.Length = pubBlobLen * 8;
866
867 feeDepth depth;
868 feeReturn frtn = curveParamsDepth(cp, &depth);
869 if(frtn) {
870 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
871 return frtn;
872 }
873
874 CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPubKeyInfo.algorithm;
875 frtn = feeSetupAlgId(depth, coder, algId);
876 if(frtn) {
877 return frtn;
878 }
879
880 /* DER encode */
881 CSSM_DATA encBlob; // mallocd by coder
882 PRErrorCode perr = coder.encodeItem(&nssPubKeyInfo, kSecAsn1SubjectPublicKeyInfoTemplate, encBlob);
883 if(perr) {
884 return FR_Memory;
885 }
886
887 /* copy out */
888 *x509Blob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
889 *x509BlobLen = (unsigned)encBlob.Length;
890 memmove(*x509Blob, encBlob.Data, encBlob.Length);
891 return FR_Success;
892 }
893
894 feeReturn feeDERDecodeX509PublicKey(
895 const unsigned char *x509Blob,
896 unsigned x509BlobLen,
897 feeDepth *depth, /* RETURNED */
898 unsigned char **pubBlob, /* x and y octet string RETURNED */
899 unsigned *pubBlobLen) /* RETURNED */
900 {
901 SecNssCoder coder;
902 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo;
903 PRErrorCode perr;
904
905 memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo));
906 perr = coder.decode(x509Blob, x509BlobLen, kSecAsn1SubjectPublicKeyInfoTemplate,
907 &nssPubKeyInfo);
908 if(perr) {
909 dbgLog(("decode(SubjectPublicKeyInfo) error"));
910 return FR_BadKeyBlob;
911 }
912
913 /* verify alg identifier & depth */
914 feeReturn frtn = feeAlgIdToDepth(&nssPubKeyInfo.algorithm, depth);
915 if(frtn) {
916 return frtn;
917 }
918
919 /* copy public key string - it's in bits here */
920 CSSM_DATA *pubKey = &nssPubKeyInfo.subjectPublicKey;
921 unsigned keyLen =(unsigned) (pubKey->Length + 7) / 8;
922 *pubBlob = (unsigned char *)fmalloc(keyLen);
923 if(*pubBlob == NULL) {
924 return FR_Memory;
925 }
926 memmove(*pubBlob, pubKey->Data, keyLen);
927 *pubBlobLen = keyLen;
928 return FR_Success;
929 }
930
931 #pragma mark --- ECDSA keys, OpenSSL format ---
932
933 /*
934 * Encode private, and decode private or public key, in unencrypted OpenSSL format.
935 */
936 feeReturn feeDEREncodeOpenSSLPrivateKey(
937 const unsigned char *privBlob, /* private data octet string */
938 unsigned privBlobLen,
939 const unsigned char *pubBlob, /* public key, optional */
940 unsigned pubBlobLen,
941 curveParams *cp,
942 unsigned char **openBlob, /* fmallocd and RETURNED */
943 unsigned *openBlobLen) /* RETURNED */
944 {
945 feeDepth depth;
946 const CSSM_OID *curveOid;
947 SecNssCoder coder;
948
949 NSS_ECDSA_PrivateKey ecdsaPrivKey;
950 memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey));
951 uint8 vers = 1;
952 ecdsaPrivKey.version.Data = &vers;
953 ecdsaPrivKey.version.Length = 1;
954 ecdsaPrivKey.privateKey.Data = (uint8 *)privBlob;
955 ecdsaPrivKey.privateKey.Length = privBlobLen;
956
957 /* Params - ASN_ANY - actually the curve OID */
958 if(curveParamsDepth(cp, &depth)) {
959 dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth"));
960 return FR_BadKeyBlob;
961 }
962 curveOid = depthToOid(depth);
963 if(curveOid == NULL) {
964 return FR_BadKeyBlob;
965 }
966
967 /* quickie DER-encode of the curve OID */
968 try {
969 coder.allocItem(ecdsaPrivKey.params, curveOid->Length + 2);
970 }
971 catch(...) {
972 return FR_Memory;
973 }
974 ecdsaPrivKey.params.Data[0] = BER_TAG_OID;
975 ecdsaPrivKey.params.Data[1] = curveOid->Length;
976 memmove(ecdsaPrivKey.params.Data+2, curveOid->Data, curveOid->Length);
977
978 /* public key - optional - bit string, length in bits */
979 if(pubBlob) {
980 ecdsaPrivKey.pubKey.Data = (uint8 *)pubBlob;
981 ecdsaPrivKey.pubKey.Length = pubBlobLen * 8;
982 }
983
984 CSSM_DATA encPriv = {0, NULL};
985 PRErrorCode perr = coder.encodeItem(&ecdsaPrivKey, kSecAsn1ECDSAPrivateKeyInfoTemplate, encPriv);
986 if(perr) {
987 return FR_Memory;
988 }
989
990 /* copy out */
991 *openBlob = (unsigned char *)fmalloc((unsigned)encPriv.Length);
992 *openBlobLen = (unsigned)encPriv.Length;
993 memmove(*openBlob, encPriv.Data, encPriv.Length);
994 return FR_Success;
995 }
996
997 feeReturn feeDERDecodeOpenSSLKey(
998 const unsigned char *osBlob,
999 unsigned osBlobLen,
1000 feeDepth *depth, /* RETURNED */
1001 unsigned char **privBlob, /* private data octet string RETURNED */
1002 unsigned *privBlobLen, /* RETURNED */
1003 unsigned char **pubBlob, /* public data octet string optionally RETURNED */
1004 unsigned *pubBlobLen)
1005 {
1006 SecNssCoder coder;
1007 NSS_ECDSA_PrivateKey ecdsaPrivKey;
1008 memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey));
1009 if(coder.decode(osBlob, osBlobLen,
1010 kSecAsn1ECDSAPrivateKeyInfoTemplate, &ecdsaPrivKey)) {
1011 dbgLog(("Error decoding openssl priv key\n"));
1012 return FR_BadKeyBlob;
1013 }
1014
1015 unsigned keyLen = (unsigned)ecdsaPrivKey.privateKey.Length;
1016 if(keyLen == 0) {
1017 dbgLog(("NULL priv key data in PKCS8\n"));
1018 }
1019 *privBlob = (unsigned char *)fmalloc(keyLen);
1020 if(*privBlob == NULL) {
1021 return FR_Memory;
1022 }
1023 *privBlobLen = keyLen;
1024 memmove(*privBlob, ecdsaPrivKey.privateKey.Data, keyLen);
1025
1026 /* curve OID --> depth */
1027 if(ecdsaPrivKey.params.Data != NULL) {
1028 /* quickie decode */
1029 const CSSM_DATA *param = &ecdsaPrivKey.params;
1030 if((param->Data[0] != BER_TAG_OID) || (param->Length <= 2)) {
1031 dbgLog(("feeDERDecodeOpenSSLKey: bad curve params\n"));
1032 return FR_BadKeyBlob;
1033 }
1034 CSSM_OID decOid = {param->Length-2, param->Data+2};
1035 if(curveOidToFeeDepth(&decOid, depth)) {
1036 return FR_BadKeyBlob;
1037 }
1038 }
1039
1040 /* Public key, if it's there and caller wants it */
1041 if((ecdsaPrivKey.pubKey.Length != 0) && (pubBlob != NULL)) {
1042 *pubBlobLen = (unsigned)(ecdsaPrivKey.pubKey.Length + 7) / 8;
1043 *pubBlob = (unsigned char *)fmalloc(*pubBlobLen);
1044 memmove(*pubBlob, ecdsaPrivKey.pubKey.Data, *pubBlobLen);
1045 }
1046 return FR_Success;
1047 }
1048
1049 #pragma mark --- ECDSA public key, PKCS8 format ---
1050
1051 /*
1052 * Encode/decode private key in unencrypted PKCS8 format.
1053 */
1054 feeReturn feeDEREncodePKCS8PrivateKey(
1055 const unsigned char *privBlob, /* private data octet string */
1056 unsigned privBlobLen,
1057 const unsigned char *pubBlob, /* public blob, optional */
1058 unsigned pubBlobLen,
1059 curveParams *cp,
1060 unsigned char **pkcs8Blob, /* fmallocd and RETURNED */
1061 unsigned *pkcs8BlobLen) /* RETURNED */
1062 {
1063 /* First encode a NSS_ECDSA_PrivateKey */
1064 unsigned char *encPriv = NULL;
1065 unsigned encPrivLen = 0;
1066 feeReturn frtn = feeDEREncodeOpenSSLPrivateKey(privBlob, privBlobLen,
1067 pubBlob, pubBlobLen, cp, &encPriv, &encPrivLen);
1068 if(frtn) {
1069 return frtn;
1070 }
1071
1072 /* That encoding goes into NSS_PrivateKeyInfo.private key */
1073 SecNssCoder coder;
1074 NSS_PrivateKeyInfo nssPrivKeyInfo;
1075 CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPrivKeyInfo.algorithm;
1076 memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo));
1077 nssPrivKeyInfo.privateKey.Data = (uint8 *)encPriv;
1078 nssPrivKeyInfo.privateKey.Length = encPrivLen;
1079 uint8 vers = 0;
1080
1081 feeDepth depth;
1082 frtn = curveParamsDepth(cp, &depth);
1083 if(frtn) {
1084 dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
1085 goto errOut;
1086 }
1087 frtn = feeSetupAlgId(depth, coder, algId);
1088 if(frtn) {
1089 goto errOut;
1090 }
1091
1092 nssPrivKeyInfo.version.Data = &vers;
1093 nssPrivKeyInfo.version.Length = 1;
1094
1095 /* DER encode */
1096 CSSM_DATA encPrivInfo; // mallocd by coder
1097 if(coder.encodeItem(&nssPrivKeyInfo, kSecAsn1PrivateKeyInfoTemplate, encPrivInfo)) {
1098 frtn = FR_Memory;
1099 goto errOut;
1100 }
1101
1102 /* copy out */
1103 *pkcs8Blob = (unsigned char *)fmalloc((unsigned)encPrivInfo.Length);
1104 *pkcs8BlobLen = (unsigned)encPrivInfo.Length;
1105 memmove(*pkcs8Blob, encPrivInfo.Data, encPrivInfo.Length);
1106 errOut:
1107 if(encPriv) {
1108 ffree(encPriv);
1109 }
1110 return frtn;
1111 }
1112
1113 feeReturn feeDERDecodePKCS8PrivateKey(
1114 const unsigned char *pkcs8Blob,
1115 unsigned pkcs8BlobLen,
1116 feeDepth *depth, /* RETURNED */
1117 unsigned char **privBlob, /* private data octet string RETURNED */
1118 unsigned *privBlobLen, /* RETURNED */
1119 unsigned char **pubBlob, /* optionally returned, if it's there */
1120 unsigned *pubBlobLen)
1121 {
1122 NSS_PrivateKeyInfo nssPrivKeyInfo;
1123 PRErrorCode perr;
1124 SecNssCoder coder;
1125
1126 memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo));
1127 perr = coder.decode(pkcs8Blob, pkcs8BlobLen, kSecAsn1PrivateKeyInfoTemplate, &nssPrivKeyInfo);
1128 if(perr) {
1129 dbgLog(("Error decoding top level PKCS8\n"));
1130 return FR_BadKeyBlob;
1131 }
1132
1133 /* verify alg identifier & depth */
1134 feeReturn frtn = feeAlgIdToDepth(&nssPrivKeyInfo.algorithm, depth);
1135 if(frtn) {
1136 return frtn;
1137 }
1138
1139 /*
1140 * nssPrivKeyInfo.privateKey is an octet string containing an encoded
1141 * NSS_ECDSA_PrivateKey.
1142 */
1143 frtn = feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo.privateKey.Data,
1144 (unsigned)nssPrivKeyInfo.privateKey.Length, depth,
1145 privBlob, privBlobLen,
1146 pubBlob, pubBlobLen);
1147
1148 return frtn;
1149 }
1150
1151 #endif /* CRYPTKIT_DER_ENABLE */