+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-/*
- * CryptKitDER.h - snacc-based routines to create and parse DER-encoded FEE
- * keys and signatures
- *
- */
-
-#include "ckconfig.h"
-
-#if CRYPTKIT_DER_ENABLE
-
-#include <security_cryptkit/CryptKitDER.h>
-#include <security_cryptkit/falloc.h>
-#include <security_cryptkit/feeDebug.h>
-#include <security_cryptkit/feeFunctions.h>
-#include "CryptKitAsn1.h"
-#include <security_asn1/SecNssCoder.h>
-#include <security_asn1/nssUtils.h>
-#include <Security/keyTemplates.h>
-#include <Security/oidsalg.h>
-#include <Security/oidsattr.h>
-
-#define PRINT_SIG_GIANTS 0
-#define PRINT_CURVE_PARAMS 0
-#define PRINT_SIZES 0
-#if PRINT_SIZES
-#define szprint(s) printf s
-#else
-#define szprint(s)
-#endif
-
-/*
- * Trivial exception class associated with a feeReturn.
- */
-class feeException
-{
-protected:
- feeException(feeReturn frtn, const char *op);
-public:
- ~feeException() throw() {}
- feeReturn frtn() const throw() { return mFrtn; }
- static void throwMe(feeReturn frtn, const char *op = NULL) __attribute__((noreturn));
-private:
- feeReturn mFrtn;
-};
-
-feeException::feeException(
- feeReturn frtn,
- const char *op)
- : mFrtn(frtn)
-{
- if(op) {
- dbgLog(("%s: %s\n", op, feeReturnString(frtn)));
- }
-}
-
-void feeException::throwMe(feeReturn frtn, const char *op /*= NULL*/) { throw feeException(frtn, op); }
-
-/*
- * ASN1 encoding rules specify that an integer's sign is indicated by the MSB
- * of the first (MS) content byte. For a non-negative number, if the MSB of
- * the MS byte (of the unencoded number) is one, then the encoding starts with
- * a byte of zeroes to indicate positive sign. For a negative number, the first
- * nine bits can not be all 1 - if they are (in the undecoded number), leading
- * bytes of 0xff are trimmed off until the first nine bits are something other
- * than one. Also, the first nine bits of the encoded number can not all be
- * zero.
- *
- * CryptKit giants express their sign as part of the giantstruct.sign field.
- * The giantDigit array (giantstruct.n[]) is stored l.s. digit first.
- *
- * These routines are independent of platform, endianness, and giatn digit size.
- */
-
-/* routines to guess maximum size of DER-encoded objects */
-static unsigned feeSizeOfSnaccGiant(
- giant g)
-{
- unsigned rtn = abs(g->sign) * GIANT_BYTES_PER_DIGIT;
- szprint(("feeSizeOfSnaccGiant: sign %d size %d\n", g->sign, rtn + 4));
- return rtn + 4;
-}
-
-/* PUBLIC... */
-unsigned feeSizeOfDERSig(
- giant g1,
- giant g2)
-{
- unsigned rtn = feeSizeOfSnaccGiant(g1);
- rtn += feeSizeOfSnaccGiant(g2);
- szprint(("feeSizeOfDERSig: size %d\n", rtn + 4));
- return rtn + 4;
-}
-
-/* perform 2's complement of byte array, expressed MS byte first */
-static void twosComplement(
- unsigned char *bytePtr, // points to MS byte
- unsigned numBytes)
-{
- unsigned char *outp = bytePtr + numBytes - 1;
- unsigned char carry = 1; // first time thru, carry = 1 to add one to 1's comp
- for(unsigned byteDex=0; byteDex<numBytes; byteDex++) {
- /* first complement, then add carry */
- *outp = ~*outp + carry;
- if(carry && (*outp == 0)) {
- /* overflow/carry */
- carry = 1;
- }
- else {
- carry = 0;
- }
- outp--;
- }
-}
-
-/*
- * CSSM_DATA --> unsigned int
- */
-static unsigned cssmDataToInt(
- const CSSM_DATA &cdata)
-{
- if((cdata.Length == 0) || (cdata.Data == NULL)) {
- return 0;
- }
- unsigned len = (unsigned)cdata.Length;
- if(len > sizeof(int)) {
- feeException::throwMe(FR_BadKeyBlob, "cssmDataToInt");
- }
-
- unsigned rtn = 0;
- uint8 *cp = cdata.Data;
- for(unsigned i=0; i<len; i++) {
- rtn = (rtn << 8) | *cp++;
- }
- return rtn;
-}
-
-/*
- * unsigned int --> CSSM_DATA, mallocing from an SecNssCoder
- */
-static void intToCssmData(
- unsigned num,
- CSSM_DATA &cdata,
- SecNssCoder &coder)
-{
- unsigned len = 0;
-
- if(num < 0x100) {
- len = 1;
- }
- else if(num < 0x10000) {
- len = 2;
- }
- else if(num < 0x1000000) {
- len = 3;
- }
- else {
- len = 4;
- }
- cdata.Data = (uint8 *)coder.malloc(len);
- cdata.Length = len;
- uint8 *cp = &cdata.Data[len - 1];
- for(unsigned i=0; i<len; i++) {
- *cp-- = num & 0xff;
- num >>= 8;
- }
-}
-
-/*
- * Convert a decoded ASN integer, as a CSSM_DATA, to a (mallocd) giant.
- * Only known exception is a feeException.
- */
-static giant cssmDataToGiant(
- const CSSM_DATA &cdata)
-{
- char *rawOcts = (char *)cdata.Data;
- unsigned numBytes = (unsigned)cdata.Length;
- unsigned numGiantDigits;
- int sign = 1;
- giant grtn;
- feeReturn frtn = FR_Success;
- unsigned char *inp = NULL;
- unsigned digitDex; // index into g->giantDigit[]
-
- /* handle degenerate case (value of zero) */
- if((numBytes == 0) || ((numBytes == 1) && rawOcts[0] == 0)) {
- grtn = newGiant(1);
- if(grtn == NULL) {
- feeException::throwMe(FR_Memory, "newGiant(1)");
- }
- int_to_giant(0, grtn);
- return grtn;
- }
-
- /* make a copy of raw octets if we have to do two's complement */
- unsigned char *byteArray = NULL;
- bool didMalloc = false;
- if(rawOcts[0] & 0x80) {
- sign = -1;
- numBytes++;
- byteArray = (unsigned char *)fmalloc(numBytes);
- didMalloc = true;
- byteArray[0] = 0xff;
- memmove(byteArray + 1, rawOcts, numBytes-1);
- twosComplement(byteArray, numBytes);
- }
- else {
- /* no copy */
- char *foo = rawOcts;
- byteArray = (unsigned char *)foo;
- }
-
- /* cook up a new giant */
- numGiantDigits = (numBytes + GIANT_BYTES_PER_DIGIT - 1) /
- GIANT_BYTES_PER_DIGIT;
- grtn = newGiant(numGiantDigits);
- if(grtn == NULL) {
- frtn = FR_Memory;
- goto abort;
- }
-
- /*
- * Convert byteArray to array of giantDigits
- * inp - raw input bytes, LSB last
- * grtn->n[] - output array of giantDigits, LSD first
- * Start at LS byte and LD digit
- */
- digitDex = 0; // index into g->giantDigit[]
- giantDigit thisDigit;
- inp = byteArray + numBytes - 1;
- unsigned dex; // total byte counter
- unsigned byteDex; // index into one giantDigit
- unsigned shiftCount;
- for(dex=0; dex<numBytes; ) { // increment dex inside
- thisDigit = 0;
- shiftCount = 0;
- for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) {
- thisDigit |= ((giantDigit)(*inp--) << shiftCount);
- shiftCount += 8;
- if(++dex == numBytes) {
- /* must be partial giantDigit */
- break;
- }
- }
- CKASSERT(digitDex < numGiantDigits);
- grtn->n[digitDex++] = thisDigit;
- }
- grtn->sign = (int)numGiantDigits * sign;
-
- /* trim leading (MS) zeroes */
- gtrimSign(grtn);
-abort:
- if(didMalloc) {
- ffree(byteArray);
- }
- if(frtn) {
- feeException::throwMe(frtn, "bigIntStrToGiant");
- }
- return grtn;
-}
-
-/*
- * Convert a giant to an CSSM_DATA, mallocing using specified coder.
- * Only known exception is a feeException.
- */
- static void giantToCssmData(
- giant g,
- CSSM_DATA &cdata,
- SecNssCoder &coder)
-{
- unsigned char doPrepend = 0;
- unsigned numGiantDigits = abs(g->sign);
- unsigned numBytes = numGiantDigits * GIANT_BYTES_PER_DIGIT;
- giantDigit msGiantBit = 0;
- if(isZero(g)) {
- /* special degenerate case */
- intToCssmData(0, cdata, coder);
- return;
- }
- else {
- msGiantBit = g->n[numGiantDigits - 1] >> (GIANT_BITS_PER_DIGIT - 1);
- }
-
- /* prepend a byte of zero if necessary */
- if((g->sign < 0) || // negative - to handle 2's complement
- ((g->sign > 0) && msGiantBit)) { // ensure MS byte is zero
- doPrepend = 1;
- numBytes++;
- }
-
- unsigned char *rawBytes = (unsigned char *)fmalloc(numBytes);
- if(rawBytes == NULL) {
- feeException::throwMe(FR_Memory, "giantToBigIntStr fmalloc(rawBytes)");
- }
- unsigned char *outp = rawBytes;
- if(doPrepend) {
- *outp++ = 0;
- }
-
- /*
- * Convert array of giantDigits to bytes.
- * outp point to MS output byte.
- */
- int digitDex; // index into g->giantDigit[]
- unsigned byteDex; // byte index into a giantDigit
- for(digitDex=numGiantDigits-1; digitDex>=0; digitDex--) {
- /* one loop per giantDigit, starting at MS end */
- giantDigit thisDigit = g->n[digitDex];
- unsigned char *bp = outp + GIANT_BYTES_PER_DIGIT - 1;
- for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) {
- /* one loop per byte within the digit, starting at LS end */
- *bp-- = (unsigned char)(thisDigit) & 0xff;
- thisDigit >>= 8;
- }
- outp += GIANT_BYTES_PER_DIGIT;
- }
-
- /* do two's complement for negative giants */
- if(g->sign < 0) {
- twosComplement(rawBytes, numBytes);
- }
-
- /* strip off redundant leading bits (nine zeroes or nine ones) */
- outp = rawBytes;
- unsigned char *endp = outp + numBytes - 1;
- while((*outp == 0) && // m.s. byte zero
- (outp < endp) && // more bytes exist
- (!(outp[1] & 0x80))) { // 9th bit is 0
- outp++;
- numBytes--;
- }
- while((*outp == 0xff) && // m.s. byte all ones
- (outp < endp) && // more bytes exist
- (outp[1] & 0x80)) { // 9th bit is 1
- outp++;
- numBytes--;
- }
- cdata.Data = (uint8 *)coder.malloc(numBytes);
- memmove(cdata.Data, outp, numBytes);
- cdata.Length = numBytes;
- ffree(rawBytes);
- return;
-}
-
-/* curveParams : CryptKit <--> FEECurveParametersASN1 */
-/* Only known exception is a feeException */
-static void feeCurveParamsToASN1(
- const curveParams *cp,
- FEECurveParametersASN1 &asnCp,
- SecNssCoder &coder)
-{
- #if PRINT_CURVE_PARAMS
- printf("===encoding curveParams; cp:\n"); printCurveParams(cp);
- #endif
- memset(&asnCp, 0, sizeof(asnCp));
- try {
- intToCssmData(cp->primeType, asnCp.primeType, coder);
- intToCssmData(cp->curveType, asnCp.curveType, coder);
- intToCssmData(cp->q, asnCp.q, coder);
- intToCssmData(cp->k, asnCp.k, coder);
- intToCssmData(cp->m, asnCp.m, coder);
- giantToCssmData(cp->a, asnCp.a, coder);
- giantToCssmData(cp->b, asnCp.b_, coder);
- giantToCssmData(cp->c, asnCp.c, coder);
- giantToCssmData(cp->x1Plus, asnCp.x1Plus, coder);
- giantToCssmData(cp->x1Minus, asnCp.x1Minus, coder);
- giantToCssmData(cp->cOrderPlus, asnCp.cOrderPlus, coder);
- giantToCssmData(cp->cOrderMinus, asnCp.cOrderMinus, coder);
- giantToCssmData(cp->x1OrderPlus, asnCp.x1OrderPlus, coder);
- giantToCssmData(cp->x1OrderMinus, asnCp.x1OrderMinus, coder);
- if(cp->primeType == FPT_General) {
- giantToCssmData(cp->basePrime, asnCp.basePrime, coder);
- }
- }
- catch(const feeException &ferr) {
- throw;
- }
- catch(...) {
- feeException::throwMe(FR_Memory, "feeCurveParamsToSnacc catchall"); // ???
- }
-}
-
-static curveParams *feeCurveParamsFromAsn1(
- const FEECurveParametersASN1 &asnCp)
-{
- curveParams *cp = newCurveParams();
- if(cp == NULL) {
- feeException::throwMe(FR_Memory, "feeCurveParamsFromSnacc alloc cp");
- }
- cp->primeType = (feePrimeType)cssmDataToInt(asnCp.primeType);
- cp->curveType = (feeCurveType)cssmDataToInt(asnCp.curveType);
- cp->q = cssmDataToInt(asnCp.q);
- cp->k = cssmDataToInt(asnCp.k);
- cp->m = cssmDataToInt(asnCp.m);
- cp->a = cssmDataToGiant(asnCp.a);
- cp->b = cssmDataToGiant(asnCp.b_);
- cp->c = cssmDataToGiant(asnCp.c);
- cp->x1Plus = cssmDataToGiant(asnCp.x1Plus);
- cp->x1Minus = cssmDataToGiant(asnCp.x1Minus);
- cp->cOrderPlus = cssmDataToGiant(asnCp.cOrderPlus);
- cp->cOrderMinus = cssmDataToGiant(asnCp.cOrderMinus);
- cp->x1OrderPlus = cssmDataToGiant(asnCp.x1OrderPlus);
- cp->x1OrderMinus = cssmDataToGiant(asnCp.x1OrderMinus);
- if(asnCp.basePrime.Data != NULL) {
- cp->basePrime = cssmDataToGiant(asnCp.basePrime);
- }
-
- /* remaining fields inferred */
- curveParamsInferFields(cp);
- allocRecipGiants(cp);
- #if PRINT_CURVE_PARAMS
- printf("===decoding curveParams; cp:\n"); printCurveParams(cp);
- #endif
- return cp;
-}
-
-/***
- *** Public routines. These are usable from C code; they never throw.
- ***/
-
-/*
- * Encode/decode the two FEE signature types. We malloc returned data via
- * fmalloc(); caller must free via ffree().
- */
-feeReturn feeDEREncodeElGamalSignature(
- giant u,
- giant PmX,
- unsigned char **encodedSig, // fmallocd and RETURNED
- unsigned *encodedSigLen) // RETURNED
-{
- /* convert to FEEElGamalSignatureASN1 */
- FEEElGamalSignatureASN1 asnSig;
- SecNssCoder coder;
-
- try {
- giantToCssmData(u, asnSig.u, coder);
- giantToCssmData(PmX, asnSig.pmX, coder);
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
-
- /* DER encode */
- PRErrorCode perr;
- CSSM_DATA encBlob; // mallocd by coder
- perr = coder.encodeItem(&asnSig, FEEElGamalSignatureASN1Template, encBlob);
- if(perr) {
- return FR_Memory;
- }
-
- /* copy out to caller */
- *encodedSig = (unsigned char *)fmalloc((unsigned)encBlob.Length);
- *encodedSigLen = (unsigned)encBlob.Length;
- memmove(*encodedSig, encBlob.Data, encBlob.Length);
-
- #if PRINT_SIG_GIANTS
- printf("feeEncodeElGamalSignature:\n");
- printf(" u : "); printGiantHex(u);
- printf(" PmX : "); printGiantHex(PmX);
- #endif
-
- return FR_Success;
-}
-
-feeReturn feeDEREncodeECDSASignature(
- giant c,
- giant d,
- unsigned char **encodedSig, // fmallocd and RETURNED
- unsigned *encodedSigLen) // RETURNED
-{
- /* convert to FEEECDSASignatureASN1 */
- FEEECDSASignatureASN1 asnSig;
- SecNssCoder coder;
-
- try {
- giantToCssmData(c, asnSig.c, coder);
- giantToCssmData(d, asnSig.d, coder);
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
-
- /* DER encode */
- PRErrorCode perr;
- CSSM_DATA encBlob; // mallocd by coder
- perr = coder.encodeItem(&asnSig, FEEECDSASignatureASN1Template, encBlob);
- if(perr) {
- return FR_Memory;
- }
-
- /* copy out to caller */
- *encodedSig = (unsigned char *)fmalloc((unsigned)encBlob.Length);
- *encodedSigLen = (unsigned)encBlob.Length;
- memmove(*encodedSig, encBlob.Data, encBlob.Length);
-
- #if PRINT_SIG_GIANTS
- printf("feeEncodeECDSASignature:\n");
- printf(" c : "); printGiantHex(*c);
- printf(" d : "); printGiantHex(*d);
- #endif
- return FR_Success;
-
-}
-
-feeReturn feeDERDecodeElGamalSignature(
- const unsigned char *encodedSig,
- size_t encodedSigLen,
- giant *u, // newGiant'd and RETURNED
- giant *PmX) // newGiant'd and RETURNED
-{
- FEEElGamalSignatureASN1 asnSig;
- SecNssCoder coder;
-
- memset(&asnSig, 0, sizeof(asnSig));
- PRErrorCode perr = coder.decode(encodedSig, encodedSigLen,
- FEEElGamalSignatureASN1Template, &asnSig);
- if(perr) {
- return FR_BadSignatureFormat;
- }
-
- try {
- *u = cssmDataToGiant(asnSig.u);
- *PmX = cssmDataToGiant(asnSig.pmX);
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
- catch(...) {
- /* FIXME - bad sig? memory? */
- return FR_Memory;
- }
- #if PRINT_SIG_GIANTS
- printf("feeDecodeElGamalSignature:\n");
- printf(" u : "); printGiantHex(*u);
- printf(" PmX : "); printGiantHex(*PmX);
- #endif
- return FR_Success;
-}
-
-feeReturn feeDERDecodeECDSASignature(
- const unsigned char *encodedSig,
- size_t encodedSigLen,
- giant *c, // newGiant'd and RETURNED
- giant *d) // newGiant'd and RETURNED
-{
- FEEECDSASignatureASN1 asnSig;
- SecNssCoder coder;
-
- memset(&asnSig, 0, sizeof(asnSig));
- PRErrorCode perr = coder.decode(encodedSig, encodedSigLen,
- FEEECDSASignatureASN1Template, &asnSig);
- if(perr) {
- return FR_BadSignatureFormat;
- }
-
- try {
- *c = cssmDataToGiant(asnSig.c);
- *d = cssmDataToGiant(asnSig.d);
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
- catch(...) {
- /* FIXME - bad sig? memory? */
- return FR_Memory;
- }
- #if PRINT_SIG_GIANTS
- printf("feeDERDecodeECDSASignature:\n");
- printf(" u : "); printGiantHex(*u);
- printf(" PmX : "); printGiantHex(*PmX);
- #endif
- return FR_Success;
-}
-
-/*
- * Encode/decode the FEE private and public keys. We malloc returned data via
- * falloc(); caller must free via ffree(). Public C functions which never throw.
- */
-feeReturn feeDEREncodePublicKey(
- int version,
- const curveParams *cp,
- giant plusX,
- giant minusX,
- giant plusY, // may be NULL
- unsigned char **keyBlob, // fmallocd and RETURNED
- unsigned *keyBlobLen) // RETURNED
-{
- FEEPublicKeyASN1 asnKey;
- SecNssCoder coder;
-
- memset(&asnKey, 0, sizeof(asnKey));
- intToCssmData(version, asnKey.version, coder);
-
- try {
- feeCurveParamsToASN1(cp, asnKey.curveParams, coder);
- giantToCssmData(plusX, asnKey.plusX, coder);
- giantToCssmData(minusX, asnKey.minusX, coder);
- if(plusY != NULL) {
- giantToCssmData(plusY, asnKey.plusY, coder);
- }
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
-
- /* DER encode */
- PRErrorCode perr;
- CSSM_DATA encBlob; // mallocd by coder
- perr = coder.encodeItem(&asnKey, FEEPublicKeyASN1Template, encBlob);
- if(perr) {
- return FR_Memory;
- }
-
- /* copy out */
- *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
- *keyBlobLen = (unsigned)encBlob.Length;
- memmove(*keyBlob, encBlob.Data, encBlob.Length);
- return FR_Success;
-}
-
-feeReturn feeDEREncodePrivateKey(
- int version,
- const curveParams *cp,
- const giant privData,
- unsigned char **keyBlob, // fmallocd and RETURNED
- unsigned *keyBlobLen) // RETURNED
-{
- FEEPrivateKeyASN1 asnKey;
- SecNssCoder coder;
-
- memset(&asnKey, 0, sizeof(asnKey));
- intToCssmData(version, asnKey.version, coder);
-
- try {
- feeCurveParamsToASN1(cp, asnKey.curveParams, coder);
- giantToCssmData(privData, asnKey.privData, coder);
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
-
- /* DER encode */
- PRErrorCode perr;
- CSSM_DATA encBlob; // mallocd by coder
- perr = coder.encodeItem(&asnKey, FEEPrivateKeyASN1Template, encBlob);
- if(perr) {
- return FR_Memory;
- }
-
- /* copy out */
- *keyBlob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
- *keyBlobLen = (unsigned)encBlob.Length;
- memmove(*keyBlob, encBlob.Data, encBlob.Length);
- return FR_Success;
-}
-
-feeReturn feeDERDecodePublicKey(
- const unsigned char *keyBlob,
- unsigned keyBlobLen,
- int *version, // this and remainder RETURNED
- curveParams **cp,
- giant *plusX,
- giant *minusX,
- giant *plusY) // may be NULL
-{
- FEEPublicKeyASN1 asnKey;
- SecNssCoder coder;
-
- memset(&asnKey, 0, sizeof(asnKey));
- PRErrorCode perr = coder.decode(keyBlob, keyBlobLen,
- FEEPublicKeyASN1Template, &asnKey);
- if(perr) {
- return FR_BadKeyBlob;
- }
-
- try {
- *version = cssmDataToInt(asnKey.version);
- *cp = feeCurveParamsFromAsn1(asnKey.curveParams);
- *plusX = cssmDataToGiant(asnKey.plusX);
- *minusX = cssmDataToGiant(asnKey.minusX);
- if(asnKey.plusY.Data != NULL) {
- /* optional */
- *plusY = cssmDataToGiant(asnKey.plusY);
- }
- else {
- *plusY = newGiant(1);
- int_to_giant(0, *plusY);
- }
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
- catch(...) {
- /* FIXME - bad sig? memory? */
- return FR_Memory;
- }
- return FR_Success;
-}
-
-feeReturn feeDERDecodePrivateKey(
- const unsigned char *keyBlob,
- unsigned keyBlobLen,
- int *version, // this and remainder RETURNED
- curveParams **cp,
- giant *privData) // RETURNED
-{
- FEEPrivateKeyASN1 asnKey;
- SecNssCoder coder;
-
- memset(&asnKey, 0, sizeof(asnKey));
- PRErrorCode perr = coder.decode(keyBlob, keyBlobLen,
- FEEPrivateKeyASN1Template, &asnKey);
- if(perr) {
- return FR_BadKeyBlob;
- }
-
- try {
- *version = cssmDataToInt(asnKey.version);
- *cp = feeCurveParamsFromAsn1(asnKey.curveParams);
- *privData = cssmDataToGiant(asnKey.privData);
- }
- catch(const feeException &ferr) {
- return ferr.frtn();
- }
- catch(...) {
- /* FIXME - bad sig? memory? */
- return FR_Memory;
- }
- return FR_Success;
-}
-
-#pragma mark --- ECDSA support ---
-
-/* convert between feeDepth and curve OIDs */
-static const CSSM_OID *depthToOid(
- feeDepth depth)
-{
- switch(depth) {
- case FEE_DEPTH_secp192r1:
- return &CSSMOID_secp192r1;
- case FEE_DEPTH_secp256r1:
- return &CSSMOID_secp256r1;
- case FEE_DEPTH_secp384r1:
- return &CSSMOID_secp384r1;
- case FEE_DEPTH_secp521r1:
- return &CSSMOID_secp521r1;
- default:
- dbgLog(("depthToOid needs work\n"));
- return NULL;
- }
-}
-
-static feeReturn curveOidToFeeDepth(
- const CSSM_OID *curveOid,
- feeDepth *depth) /* RETURNED */
-{
- if(nssCompareCssmData(curveOid, &CSSMOID_secp192r1)) {
- *depth = FEE_DEPTH_secp192r1;
- }
- else if(nssCompareCssmData(curveOid, &CSSMOID_secp256r1)) {
- *depth = FEE_DEPTH_secp256r1;
- }
- else if(nssCompareCssmData(curveOid, &CSSMOID_secp384r1)) {
- *depth = FEE_DEPTH_secp384r1;
- }
- else if(nssCompareCssmData(curveOid, &CSSMOID_secp521r1)) {
- *depth = FEE_DEPTH_secp521r1;
- }
- else {
- dbgLog(("curveOidToFeeDepth: unknown curve OID\n"));
- return FR_BadKeyBlob;
- }
- return FR_Success;
-}
-
-
-/*
- * Validate a decoded CSSM_X509_ALGORITHM_IDENTIFIER and infer
- * depth from its algorith.parameter
- */
-static feeReturn feeAlgIdToDepth(
- const CSSM_X509_ALGORITHM_IDENTIFIER *algId,
- feeDepth *depth)
-{
- const CSSM_OID *oid = &algId->algorithm;
- /* FIXME what's the value here for a private key!? */
- if(!nssCompareCssmData(oid, &CSSMOID_ecPublicKey)) {
- dbgLog(("feeAlgIdToDepth: bad OID"));
- return FR_BadKeyBlob;
- }
-
- /*
- * AlgId.params is curve OID, still encoded since it's an ASN_ANY.
- * First two bytes of encoded OID are (06, length)
- */
- const CSSM_DATA *param = &algId->parameters;
- if((param->Length <= 2) || (param->Data[0] != BER_TAG_OID)) {
- dbgLog(("feeAlgIdToDepth: no curve params\n"));
- return FR_BadKeyBlob;
- }
-
- CSSM_OID decOid = {param->Length-2, algId->parameters.Data+2};
- return curveOidToFeeDepth(&decOid, depth);
-}
-
-/*
- * Prepare an CSSM_X509_ALGORITHM_IDENTIFIER for encoding.
- */
-static feeReturn feeSetupAlgId(
- feeDepth depth,
- SecNssCoder &coder,
- CSSM_X509_ALGORITHM_IDENTIFIER &algId)
-{
- algId.algorithm = CSSMOID_ecPublicKey;
- const CSSM_OID *curveOid = depthToOid(depth);
- if(curveOid == NULL) {
- return FR_IllegalDepth;
- }
-
- /* quick & dirty encode of the parameter OID; it's an ASN_ANY in the template */
- coder.allocItem(algId.parameters, curveOid->Length + 2);
- algId.parameters.Data[0] = BER_TAG_OID;
- algId.parameters.Data[1] = curveOid->Length;
- memmove(algId.parameters.Data+2, curveOid->Data, curveOid->Length);
- return FR_Success;
-}
-
-#pragma mark --- ECDSA public key, X.509 format ---
-
-/*
- * Encode/decode public key in X.509 format.
- */
-feeReturn feeDEREncodeX509PublicKey(
- const unsigned char *pubBlob, /* x and y octet string */
- unsigned pubBlobLen,
- curveParams *cp,
- unsigned char **x509Blob, /* fmallocd and RETURNED */
- unsigned *x509BlobLen) /* RETURNED */
-{
- SecNssCoder coder;
- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo;
-
- memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo));
-
- /* The x/y string, to be encoded in a bit string */
- nssPubKeyInfo.subjectPublicKey.Data = (uint8 *)pubBlob;
- nssPubKeyInfo.subjectPublicKey.Length = pubBlobLen * 8;
-
- feeDepth depth;
- feeReturn frtn = curveParamsDepth(cp, &depth);
- if(frtn) {
- dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
- return frtn;
- }
-
- CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPubKeyInfo.algorithm;
- frtn = feeSetupAlgId(depth, coder, algId);
- if(frtn) {
- return frtn;
- }
-
- /* DER encode */
- CSSM_DATA encBlob; // mallocd by coder
- PRErrorCode perr = coder.encodeItem(&nssPubKeyInfo, kSecAsn1SubjectPublicKeyInfoTemplate, encBlob);
- if(perr) {
- return FR_Memory;
- }
-
- /* copy out */
- *x509Blob = (unsigned char *)fmalloc((unsigned)encBlob.Length);
- *x509BlobLen = (unsigned)encBlob.Length;
- memmove(*x509Blob, encBlob.Data, encBlob.Length);
- return FR_Success;
-}
-
-feeReturn feeDERDecodeX509PublicKey(
- const unsigned char *x509Blob,
- unsigned x509BlobLen,
- feeDepth *depth, /* RETURNED */
- unsigned char **pubBlob, /* x and y octet string RETURNED */
- unsigned *pubBlobLen) /* RETURNED */
-{
- SecNssCoder coder;
- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO nssPubKeyInfo;
- PRErrorCode perr;
-
- memset(&nssPubKeyInfo, 0, sizeof(nssPubKeyInfo));
- perr = coder.decode(x509Blob, x509BlobLen, kSecAsn1SubjectPublicKeyInfoTemplate,
- &nssPubKeyInfo);
- if(perr) {
- dbgLog(("decode(SubjectPublicKeyInfo) error"));
- return FR_BadKeyBlob;
- }
-
- /* verify alg identifier & depth */
- feeReturn frtn = feeAlgIdToDepth(&nssPubKeyInfo.algorithm, depth);
- if(frtn) {
- return frtn;
- }
-
- /* copy public key string - it's in bits here */
- CSSM_DATA *pubKey = &nssPubKeyInfo.subjectPublicKey;
- unsigned keyLen =(unsigned) (pubKey->Length + 7) / 8;
- *pubBlob = (unsigned char *)fmalloc(keyLen);
- if(*pubBlob == NULL) {
- return FR_Memory;
- }
- memmove(*pubBlob, pubKey->Data, keyLen);
- *pubBlobLen = keyLen;
- return FR_Success;
-}
-
-#pragma mark --- ECDSA keys, OpenSSL format ---
-
-/*
- * Encode private, and decode private or public key, in unencrypted OpenSSL format.
- */
-feeReturn feeDEREncodeOpenSSLPrivateKey(
- const unsigned char *privBlob, /* private data octet string */
- unsigned privBlobLen,
- const unsigned char *pubBlob, /* public key, optional */
- unsigned pubBlobLen,
- curveParams *cp,
- unsigned char **openBlob, /* fmallocd and RETURNED */
- unsigned *openBlobLen) /* RETURNED */
-{
- feeDepth depth;
- const CSSM_OID *curveOid;
- SecNssCoder coder;
-
- NSS_ECDSA_PrivateKey ecdsaPrivKey;
- memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey));
- uint8 vers = 1;
- ecdsaPrivKey.version.Data = &vers;
- ecdsaPrivKey.version.Length = 1;
- ecdsaPrivKey.privateKey.Data = (uint8 *)privBlob;
- ecdsaPrivKey.privateKey.Length = privBlobLen;
-
- /* Params - ASN_ANY - actually the curve OID */
- if(curveParamsDepth(cp, &depth)) {
- dbgLog(("feeDEREncodeOpenSSLPrivateKey: bad depth"));
- return FR_BadKeyBlob;
- }
- curveOid = depthToOid(depth);
- if(curveOid == NULL) {
- return FR_BadKeyBlob;
- }
-
- /* quickie DER-encode of the curve OID */
- try {
- coder.allocItem(ecdsaPrivKey.params, curveOid->Length + 2);
- }
- catch(...) {
- return FR_Memory;
- }
- ecdsaPrivKey.params.Data[0] = BER_TAG_OID;
- ecdsaPrivKey.params.Data[1] = curveOid->Length;
- memmove(ecdsaPrivKey.params.Data+2, curveOid->Data, curveOid->Length);
-
- /* public key - optional - bit string, length in bits */
- if(pubBlob) {
- ecdsaPrivKey.pubKey.Data = (uint8 *)pubBlob;
- ecdsaPrivKey.pubKey.Length = pubBlobLen * 8;
- }
-
- CSSM_DATA encPriv = {0, NULL};
- PRErrorCode perr = coder.encodeItem(&ecdsaPrivKey, kSecAsn1ECDSAPrivateKeyInfoTemplate, encPriv);
- if(perr) {
- return FR_Memory;
- }
-
- /* copy out */
- *openBlob = (unsigned char *)fmalloc((unsigned)encPriv.Length);
- *openBlobLen = (unsigned)encPriv.Length;
- memmove(*openBlob, encPriv.Data, encPriv.Length);
- return FR_Success;
-}
-
-feeReturn feeDERDecodeOpenSSLKey(
- const unsigned char *osBlob,
- unsigned osBlobLen,
- feeDepth *depth, /* RETURNED */
- unsigned char **privBlob, /* private data octet string RETURNED */
- unsigned *privBlobLen, /* RETURNED */
- unsigned char **pubBlob, /* public data octet string optionally RETURNED */
- unsigned *pubBlobLen)
-{
- SecNssCoder coder;
- NSS_ECDSA_PrivateKey ecdsaPrivKey;
- memset(&ecdsaPrivKey, 0, sizeof(ecdsaPrivKey));
- if(coder.decode(osBlob, osBlobLen,
- kSecAsn1ECDSAPrivateKeyInfoTemplate, &ecdsaPrivKey)) {
- dbgLog(("Error decoding openssl priv key\n"));
- return FR_BadKeyBlob;
- }
-
- unsigned keyLen = (unsigned)ecdsaPrivKey.privateKey.Length;
- if(keyLen == 0) {
- dbgLog(("NULL priv key data in PKCS8\n"));
- }
- *privBlob = (unsigned char *)fmalloc(keyLen);
- if(*privBlob == NULL) {
- return FR_Memory;
- }
- *privBlobLen = keyLen;
- memmove(*privBlob, ecdsaPrivKey.privateKey.Data, keyLen);
-
- /* curve OID --> depth */
- if(ecdsaPrivKey.params.Data != NULL) {
- /* quickie decode */
- const CSSM_DATA *param = &ecdsaPrivKey.params;
- if((param->Data[0] != BER_TAG_OID) || (param->Length <= 2)) {
- dbgLog(("feeDERDecodeOpenSSLKey: bad curve params\n"));
- return FR_BadKeyBlob;
- }
- CSSM_OID decOid = {param->Length-2, param->Data+2};
- if(curveOidToFeeDepth(&decOid, depth)) {
- return FR_BadKeyBlob;
- }
- }
-
- /* Public key, if it's there and caller wants it */
- if((ecdsaPrivKey.pubKey.Length != 0) && (pubBlob != NULL)) {
- *pubBlobLen = (unsigned)(ecdsaPrivKey.pubKey.Length + 7) / 8;
- *pubBlob = (unsigned char *)fmalloc(*pubBlobLen);
- memmove(*pubBlob, ecdsaPrivKey.pubKey.Data, *pubBlobLen);
- }
- return FR_Success;
-}
-
-#pragma mark --- ECDSA public key, PKCS8 format ---
-
-/*
- * Encode/decode private key in unencrypted PKCS8 format.
- */
-feeReturn feeDEREncodePKCS8PrivateKey(
- const unsigned char *privBlob, /* private data octet string */
- unsigned privBlobLen,
- const unsigned char *pubBlob, /* public blob, optional */
- unsigned pubBlobLen,
- curveParams *cp,
- unsigned char **pkcs8Blob, /* fmallocd and RETURNED */
- unsigned *pkcs8BlobLen) /* RETURNED */
-{
- /* First encode a NSS_ECDSA_PrivateKey */
- unsigned char *encPriv = NULL;
- unsigned encPrivLen = 0;
- feeReturn frtn = feeDEREncodeOpenSSLPrivateKey(privBlob, privBlobLen,
- pubBlob, pubBlobLen, cp, &encPriv, &encPrivLen);
- if(frtn) {
- return frtn;
- }
-
- /* That encoding goes into NSS_PrivateKeyInfo.private key */
- SecNssCoder coder;
- NSS_PrivateKeyInfo nssPrivKeyInfo;
- CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssPrivKeyInfo.algorithm;
- memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo));
- nssPrivKeyInfo.privateKey.Data = (uint8 *)encPriv;
- nssPrivKeyInfo.privateKey.Length = encPrivLen;
- uint8 vers = 0;
-
- feeDepth depth;
- frtn = curveParamsDepth(cp, &depth);
- if(frtn) {
- dbgLog(("feeDEREncodePKCS8PrivateKey: curveParamsDepth error\n"));
- goto errOut;
- }
- frtn = feeSetupAlgId(depth, coder, algId);
- if(frtn) {
- goto errOut;
- }
-
- nssPrivKeyInfo.version.Data = &vers;
- nssPrivKeyInfo.version.Length = 1;
-
- /* DER encode */
- CSSM_DATA encPrivInfo; // mallocd by coder
- if(coder.encodeItem(&nssPrivKeyInfo, kSecAsn1PrivateKeyInfoTemplate, encPrivInfo)) {
- frtn = FR_Memory;
- goto errOut;
- }
-
- /* copy out */
- *pkcs8Blob = (unsigned char *)fmalloc((unsigned)encPrivInfo.Length);
- *pkcs8BlobLen = (unsigned)encPrivInfo.Length;
- memmove(*pkcs8Blob, encPrivInfo.Data, encPrivInfo.Length);
-errOut:
- if(encPriv) {
- ffree(encPriv);
- }
- return frtn;
-}
-
-feeReturn feeDERDecodePKCS8PrivateKey(
- const unsigned char *pkcs8Blob,
- unsigned pkcs8BlobLen,
- feeDepth *depth, /* RETURNED */
- unsigned char **privBlob, /* private data octet string RETURNED */
- unsigned *privBlobLen, /* RETURNED */
- unsigned char **pubBlob, /* optionally returned, if it's there */
- unsigned *pubBlobLen)
-{
- NSS_PrivateKeyInfo nssPrivKeyInfo;
- PRErrorCode perr;
- SecNssCoder coder;
-
- memset(&nssPrivKeyInfo, 0, sizeof(nssPrivKeyInfo));
- perr = coder.decode(pkcs8Blob, pkcs8BlobLen, kSecAsn1PrivateKeyInfoTemplate, &nssPrivKeyInfo);
- if(perr) {
- dbgLog(("Error decoding top level PKCS8\n"));
- return FR_BadKeyBlob;
- }
-
- /* verify alg identifier & depth */
- feeReturn frtn = feeAlgIdToDepth(&nssPrivKeyInfo.algorithm, depth);
- if(frtn) {
- return frtn;
- }
-
- /*
- * nssPrivKeyInfo.privateKey is an octet string containing an encoded
- * NSS_ECDSA_PrivateKey.
- */
- frtn = feeDERDecodeOpenSSLKey((const unsigned char *)nssPrivKeyInfo.privateKey.Data,
- (unsigned)nssPrivKeyInfo.privateKey.Length, depth,
- privBlob, privBlobLen,
- pubBlob, pubBlobLen);
-
- return frtn;
-}
-
-#endif /* CRYPTKIT_DER_ENABLE */