X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_cryptkit/lib/CryptKitDER.cpp diff --git a/Security/libsecurity_cryptkit/lib/CryptKitDER.cpp b/Security/libsecurity_cryptkit/lib/CryptKitDER.cpp deleted file mode 100644 index e6fe06ab..00000000 --- a/Security/libsecurity_cryptkit/lib/CryptKitDER.cpp +++ /dev/null @@ -1,1150 +0,0 @@ -/* - * 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 -#include -#include -#include -#include "CryptKitAsn1.h" -#include -#include -#include -#include -#include - -#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 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 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>= 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; dexn[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>= 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 */