#ifdef CRYPTKIT_CSP_ENABLE
#include <Security/asn-incl.h>
#include <Security/sm_vdatypes.h>
#include <CryptKit/CryptKitDER.h>
#include <CryptKit/falloc.h>
#include <CryptKit/feeDebug.h>
#include <CryptKit/feeFunctions.h>
#include <Security/cdsaUtils.h>
#include <Security/appleoids.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
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); }
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;
}
static unsigned feeSizeofSnaccInt()
{
return 7;
}
unsigned feeSizeOfDERSig(
giant g1,
giant g2)
{
unsigned rtn = feeSizeOfSnaccGiant(g1);
rtn += feeSizeOfSnaccGiant(g2);
szprint(("feeSizeOfDERSig: size %d\n", rtn + 4));
return rtn + 4;
}
static unsigned feeSizeofSnaccCurveParams(const curveParams *cp)
{
unsigned rtn = 5 * feeSizeofSnaccInt(); rtn += 10 * feeSizeOfSnaccGiant(cp->basePrime);
szprint(("feeSizeofSnaccCurveParams: size %d\n", rtn));
return rtn;
}
static unsigned feeSizeOfSnaccPubKey(const curveParams *cp)
{
unsigned rtn = 11; rtn += feeSizeofSnaccCurveParams(cp);
rtn += (3 * feeSizeOfSnaccGiant(cp->basePrime));
szprint(("feeSizeOfSnaccPubKey: size %d\n", rtn));
return rtn;
}
static unsigned feeSizeOfSnaccPrivKey(const curveParams *cp)
{
unsigned rtn = 11; rtn += feeSizeofSnaccCurveParams(cp);
rtn += feeSizeOfSnaccGiant(cp->basePrime);
szprint(("feeSizeOfSnaccPrivKey: size %d\n", rtn));
return rtn;
}
static void twosComplement(
unsigned char *bytePtr, unsigned numBytes)
{
unsigned char *outp = bytePtr + numBytes - 1;
unsigned char carry = 1; for(unsigned byteDex=0; byteDex<numBytes; byteDex++) {
*outp = ~*outp + carry;
if(carry && (*outp == 0)) {
carry = 1;
}
else {
carry = 0;
}
outp--;
}
}
static giant bigIntStrToGiant(
BigIntegerStr &bigInt)
{
char *rawOcts = bigInt;
unsigned numBytes = bigInt.Len();
unsigned numGiantDigits;
int sign = 1;
giant grtn;
feeReturn frtn = FR_Success;
unsigned char *inp = NULL;
unsigned digitDex;
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;
}
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 {
char *foo = rawOcts;
byteArray = (unsigned char *)foo;
}
numGiantDigits = (numBytes + GIANT_BYTES_PER_DIGIT - 1) /
GIANT_BYTES_PER_DIGIT;
grtn = newGiant(numGiantDigits);
if(grtn == NULL) {
frtn = FR_Memory;
goto abort;
}
digitDex = 0; giantDigit thisDigit;
inp = byteArray + numBytes - 1;
unsigned dex; unsigned byteDex; unsigned shiftCount;
for(dex=0; dex<numBytes; ) { thisDigit = 0;
shiftCount = 0;
for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) {
thisDigit |= ((giantDigit)(*inp--) << shiftCount);
shiftCount += 8;
if(++dex == numBytes) {
break;
}
}
CKASSERT(digitDex < numGiantDigits);
grtn->n[digitDex++] = thisDigit;
}
grtn->sign = (int)numGiantDigits * sign;
gtrimSign(grtn);
abort:
if(didMalloc) {
ffree(byteArray);
}
if(frtn) {
feeException::throwMe(frtn, "bigIntStrToGiant");
}
return grtn;
}
static void giantToBigIntStr(
giant g,
BigIntegerStr &bigInt)
{
unsigned char doPrepend = 0;
unsigned numGiantDigits = abs(g->sign);
unsigned numBytes = numGiantDigits * GIANT_BYTES_PER_DIGIT;
giantDigit msGiantBit = 0;
if(isZero(g)) {
bigInt.ReSet("", 1);
return;
}
else {
msGiantBit = g->n[numGiantDigits - 1] >> (GIANT_BITS_PER_DIGIT - 1);
}
if((g->sign < 0) || ((g->sign > 0) && msGiantBit)) { 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;
}
int digitDex; unsigned byteDex; for(digitDex=numGiantDigits-1; digitDex>=0; digitDex--) {
giantDigit thisDigit = g->n[digitDex];
unsigned char *bp = outp + GIANT_BYTES_PER_DIGIT - 1;
for(byteDex=0; byteDex<GIANT_BYTES_PER_DIGIT; byteDex++) {
*bp-- = (unsigned char)(thisDigit) & 0xff;
thisDigit >>= 8;
}
outp += GIANT_BYTES_PER_DIGIT;
}
if(g->sign < 0) {
twosComplement(rawBytes, numBytes);
}
outp = rawBytes;
unsigned char *endp = outp + numBytes - 1;
while((*outp == 0) && (outp < endp) && (!(outp[1] & 0x80))) { outp++;
numBytes--;
}
while((*outp == 0xff) && (outp < endp) && (outp[1] & 0x80)) { outp++;
numBytes--;
}
bigInt.ReSet(reinterpret_cast<const char *>(outp), numBytes);
ffree(rawBytes);
}
static FEECurveParameters *feeCurveParamsToSnacc(
const curveParams *cp)
{
#if PRINT_CURVE_PARAMS
printf("===encoding curveParams; cp:\n"); printCurveParams(cp);
#endif
FEECurveParameters *snaccCp = NULL;
try {
snaccCp = new FEECurveParameters();
AsnIntType val;
switch(cp->primeType) {
case FPT_Mersenne:
val = FEEPrimeType::pt_mersenne;
break;
case FPT_FEE:
val = FEEPrimeType::pt_fee;
break;
case FPT_General:
val = FEEPrimeType::pt_general;
break;
default:
feeException::throwMe(FR_Internal, "bad cp->primeType");
}
snaccCp->primeType.Set(val);
switch(cp->curveType) {
case FCT_Montgomery:
val = FEECurveType::ct_montgomery;
break;
case FCT_Weierstrass:
val = FEECurveType::ct_weierstrass;
break;
case FCT_General:
val = FEECurveType::ct_general;
break;
default:
feeException::throwMe(FR_Internal, "bad cp->curveType");
}
snaccCp->curveType.Set(val);
snaccCp->q.Set(cp->q);
snaccCp->k.Set(cp->k);
snaccCp->m.Set(cp->m);
giantToBigIntStr(cp->a, snaccCp->a);
giantToBigIntStr(cp->b, snaccCp->bb);
giantToBigIntStr(cp->c, snaccCp->c);
giantToBigIntStr(cp->x1Plus, snaccCp->x1Plus);
giantToBigIntStr(cp->x1Minus, snaccCp->x1Minus);
giantToBigIntStr(cp->cOrderPlus, snaccCp->cOrderPlus);
giantToBigIntStr(cp->cOrderMinus, snaccCp->cOrderMinus);
giantToBigIntStr(cp->x1OrderPlus, snaccCp->x1OrderPlus);
giantToBigIntStr(cp->x1OrderMinus, snaccCp->x1OrderMinus);
if(cp->primeType == FPT_General) {
snaccCp->basePrime = new BigIntegerStr();
giantToBigIntStr(cp->basePrime, *snaccCp->basePrime);
}
}
catch(const feeException &ferr) {
delete snaccCp;
throw;
}
catch(...) {
delete snaccCp;
feeException::throwMe(FR_Memory, "feeCurveParamsToSnacc catchall"); }
return snaccCp;
}
static curveParams *feeCurveParamsFromSnacc(
FEECurveParameters &snaccCp)
{
curveParams *cp = newCurveParams();
if(cp == NULL) {
feeException::throwMe(FR_Memory, "feeCurveParamsFromSnacc alloc cp");
}
AsnIntType val = snaccCp.primeType;
switch(val) {
case FEEPrimeType::pt_mersenne:
cp->primeType = FPT_Mersenne;
break;
case FEEPrimeType::pt_fee:
cp->primeType = FPT_FEE;
break;
case FEEPrimeType::pt_general:
cp->primeType = FPT_General;
break;
default:
feeException::throwMe(FR_BadPubKey, "feeCurveParamsFromSnacc bad primeType");
}
val = snaccCp.curveType;
switch(val) {
case FEECurveType::ct_montgomery:
cp->curveType = FCT_Montgomery;
break;
case FEECurveType::ct_weierstrass:
cp->curveType = FCT_Weierstrass;
break;
case FEECurveType::ct_general:
cp->curveType = FCT_General;
break;
default:
feeException::throwMe(FR_BadPubKey, "feeCurveParamsFromSnacc bad curveType");
}
cp->q = snaccCp.q;
cp->k = snaccCp.k;
cp->m = snaccCp.m;
cp->a = bigIntStrToGiant(snaccCp.a);
cp->b = bigIntStrToGiant(snaccCp.bb);
cp->c = bigIntStrToGiant(snaccCp.c);
cp->x1Plus = bigIntStrToGiant(snaccCp.x1Plus);
cp->x1Minus = bigIntStrToGiant(snaccCp.x1Minus);
cp->cOrderPlus = bigIntStrToGiant(snaccCp.cOrderPlus);
cp->cOrderMinus = bigIntStrToGiant(snaccCp.cOrderMinus);
cp->x1OrderPlus = bigIntStrToGiant(snaccCp.x1OrderPlus);
cp->x1OrderMinus = bigIntStrToGiant(snaccCp.x1OrderMinus);
if(snaccCp.basePrime != NULL) {
cp->basePrime = bigIntStrToGiant(*snaccCp.basePrime);
}
curveParamsInferFields(cp);
allocRecipGiants(cp);
#if PRINT_CURVE_PARAMS
printf("===decoding curveParams; cp:\n"); printCurveParams(cp);
#endif
return cp;
}
feeReturn feeDEREncodeElGamalSignature(
giant u,
giant PmX,
unsigned char **encodedSig, unsigned *encodedSigLen) {
FEEElGamalSignature snaccSig;
CssmAutoData oData(CssmAllocator::standard(CssmAllocator::sensitive));
try {
giantToBigIntStr(u, snaccSig.u);
giantToBigIntStr(PmX, snaccSig.pmX);
}
catch(const feeException &ferr) {
return ferr.frtn();
}
try {
SC_encodeAsnObj(snaccSig, oData, feeSizeOfDERSig(u, PmX));
}
catch(...) {
return FR_BadSignatureFormat;
}
*encodedSig = (unsigned char *)fmalloc(oData.length());
*encodedSigLen = oData.length();
memmove(*encodedSig, oData.get().Data, oData.length());
#if PRINT_SIG_GIANTS
printf("feeEncodeElGamalSignature:\n");
printf(" u : "); printGiantHex(u);
printf(" PmX : "); printGiantHex(PmX);
printf(" u : "); snaccSig.u.Print(cout); printf("\n");
printf(" PmX : "); snaccSig.pmX.Print(cout); printf("\n");
#endif
return FR_Success;
}
feeReturn feeDEREncodeECDSASignature(
giant c,
giant d,
unsigned char **encodedSig, unsigned *encodedSigLen) {
FEEECDSASignature snaccSig;
CssmAutoData oData(CssmAllocator::standard(CssmAllocator::sensitive));
try {
giantToBigIntStr(c, snaccSig.c);
giantToBigIntStr(d, snaccSig.d);
}
catch(const feeException &ferr) {
return ferr.frtn();
}
try {
SC_encodeAsnObj(snaccSig, oData, feeSizeOfDERSig(c, d));
}
catch(...) {
return FR_BadSignatureFormat;
}
*encodedSig = (unsigned char *)fmalloc(oData.length());
*encodedSigLen = oData.length();
memmove(*encodedSig, oData.get().Data, oData.length());
#if PRINT_SIG_GIANTS
printf("feeEncodeECDSASignature:\n");
printf(" c : "); printGiantHex(*c);
printf(" d : "); printGiantHex(*d);
printf(" c : "); snaccSig.c.Print(cout); printf("\n");
printf(" d : "); snaccSig.d.Print(cout); printf("\n");
#endif
return FR_Success;
}
feeReturn feeDERDecodeElGamalSignature(
const unsigned char *encodedSig,
unsigned encodedSigLen,
giant *u, giant *PmX) {
FEEElGamalSignature snaccSig;
CssmData cData((void *)encodedSig, encodedSigLen);
try {
SC_decodeAsnObj(cData, snaccSig);
}
catch(...) {
return FR_BadSignatureFormat;
}
try {
*u = bigIntStrToGiant(snaccSig.u);
*PmX = bigIntStrToGiant(snaccSig.pmX);
}
catch(const feeException &ferr) {
return ferr.frtn();
}
catch(...) {
return FR_Memory;
}
#if PRINT_SIG_GIANTS
printf("feeDecodeElGamalSignature:\n");
printf(" u : "); printGiantHex(*u);
printf(" PmX : "); printGiantHex(*PmX);
printf(" u : "); snaccSig.u.Print(cout); printf("\n");
printf(" PmX : "); snaccSig.pmX.Print(cout); printf("\n");
#endif
return FR_Success;
}
feeReturn feeDERDecodeECDSASignature(
const unsigned char *encodedSig,
unsigned encodedSigLen,
giant *c, giant *d) {
FEEECDSASignature snaccSig;
CssmData cData((void *)encodedSig, encodedSigLen);
try {
SC_decodeAsnObj(cData, snaccSig);
}
catch(...) {
return FR_BadSignatureFormat;
}
try {
*c = bigIntStrToGiant(snaccSig.c);
*d = bigIntStrToGiant(snaccSig.d);
}
catch(const feeException &ferr) {
return ferr.frtn();
}
catch(...) {
return FR_Memory;
}
#if PRINT_SIG_GIANTS
printf("feeDecodeECDSASignature:\n");
printf(" c : "); printGiantHex(*c);
printf(" d : "); printGiantHex(*d);
printf(" c : "); snaccSig.c.Print(cout); printf("\n");
printf(" d : "); snaccSig.d.Print(cout); printf("\n");
#endif
return FR_Success;
}
feeReturn feeDEREncodePublicKey(
int version,
const curveParams *cp,
giant plusX,
giant minusX,
giant plusY, unsigned char **keyBlob, unsigned *keyBlobLen) {
FEEPublicKey snaccKey;
snaccKey.version.Set(version);
try {
snaccKey.curveParams = feeCurveParamsToSnacc(cp);
giantToBigIntStr(plusX, snaccKey.plusX);
giantToBigIntStr(minusX, snaccKey.minusX);
if(plusY != NULL) {
snaccKey.plusY = new BigIntegerStr();
giantToBigIntStr(plusY, *snaccKey.plusY);
}
}
catch(const feeException &ferr) {
return ferr.frtn();
}
CssmAutoData oData(CssmAllocator::standard(CssmAllocator::sensitive));
try {
SC_encodeAsnObj(snaccKey, oData, feeSizeOfSnaccPubKey(cp));
}
catch(...) {
return FR_Memory;
}
*keyBlob = (unsigned char *)fmalloc(oData.length());
*keyBlobLen = oData.length();
memmove(*keyBlob, oData.get().Data, oData.length());
return FR_Success;
}
feeReturn feeDEREncodePrivateKey(
int version,
const curveParams *cp,
const giant privData,
unsigned char **keyBlob, unsigned *keyBlobLen) {
FEEPrivateKey snaccKey;
snaccKey.version.Set(version);
try {
snaccKey.curveParams = feeCurveParamsToSnacc(cp);
giantToBigIntStr(privData, snaccKey.privData);
}
catch(const feeException &ferr) {
return ferr.frtn();
}
CssmAutoData oData(CssmAllocator::standard(CssmAllocator::sensitive));
try {
SC_encodeAsnObj(snaccKey, oData, feeSizeOfSnaccPrivKey(cp));
}
catch(...) {
return FR_Memory;
}
*keyBlob = (unsigned char *)fmalloc(oData.length());
*keyBlobLen = oData.length();
memmove(*keyBlob, oData.get().Data, oData.length());
return FR_Success;
}
feeReturn feeDERDecodePublicKey(
const unsigned char *keyBlob,
unsigned keyBlobLen,
int *version, curveParams **cp,
giant *plusX,
giant *minusX,
giant *plusY) {
FEEPublicKey snaccKey;
CssmData cData((unsigned char *)keyBlob, (size_t)keyBlobLen);
try {
SC_decodeAsnObj(cData, snaccKey);
}
catch(...) {
return FR_BadPubKey;
}
try {
*version = snaccKey.version;
*cp = feeCurveParamsFromSnacc(*snaccKey.curveParams);
*plusX = bigIntStrToGiant(snaccKey.plusX);
*minusX = bigIntStrToGiant(snaccKey.minusX);
if(snaccKey.plusY != NULL) {
*plusY = bigIntStrToGiant(*snaccKey.plusY);
}
else {
*plusY = newGiant(1);
int_to_giant(0, *plusY);
}
}
catch(const feeException &ferr) {
return ferr.frtn();
}
catch(...) {
return FR_Memory;
}
return FR_Success;
}
feeReturn feeDERDecodePrivateKey(
const unsigned char *keyBlob,
unsigned keyBlobLen,
int *version, curveParams **cp,
giant *privData) {
FEEPrivateKey snaccKey;
CssmData cData((unsigned char *)keyBlob, (size_t)keyBlobLen);
try {
SC_decodeAsnObj(cData, snaccKey);
}
catch(...) {
return FR_BadPubKey;
}
try {
*version = snaccKey.version;
*cp = feeCurveParamsFromSnacc(*snaccKey.curveParams);
*privData = bigIntStrToGiant(snaccKey.privData);
}
catch(const feeException &ferr) {
return ferr.frtn();
}
catch(...) {
return FR_Memory;
}
return FR_Success;
}
#endif