#include "openRsaSnacc.h"
#include "opensslUtils.h"
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <Security/asn-incl.h>
#include <Security/sm_vdatypes.h>
#include <Security/sm_x501ud.h>
#include <Security/sm_x411ub.h>
#include <Security/sm_x411mtsas.h>
#include <Security/sm_x501if.h>
#include <Security/sm_x520sa.h>
#include <Security/sm_x509cmn.h>
#include <Security/sm_x509af.h>
#include <Security/sm_x509ce.h>
#include <Security/pkcs1oids.h>
#include <Security/pkcs9oids.h>
#include <Security/sm_cms.h>
#include <Security/sm_ess.h>
#include <Security/pkcs7.h>
#include <Security/pkcs8.h>
#include <Security/cdsaUtils.h>
#include <Security/debugging.h>
#include <Security/appleoids.h>
#define sslSnaccDebug(args...) debug("sslSnacc", ##args)
BIGNUM *bigIntStrToBn(
BigIntegerStr &snaccInt)
{
BIGNUM *bn = BN_new();
BIGNUM *rtn;
char *rawOcts = snaccInt;
unsigned numBytes = snaccInt.Len();
rtn = BN_bin2bn((unsigned char *)rawOcts, numBytes, bn);
if(rtn == NULL) {
BN_free(bn);
CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
}
return bn;
}
void bnToBigIntStr(
BIGNUM *bn,
BigIntegerStr &snaccInt)
{
unsigned numBytes = BN_num_bytes(bn);
unsigned char *buf;
unsigned char *bp;
buf = (unsigned char *)Malloc(numBytes + 1); if(buf == NULL) {
throw openSslException(CSSMERR_CSP_MEMORY_ERROR);
}
BN_bn2bin(bn, buf + 1);
if(buf[1] & 0x80) {
buf[0] = 0;
bp = buf;
numBytes++;
}
else {
bp = buf+1;
}
snaccInt.ReSet((char *)bp, numBytes);
Free(buf);
}
unsigned sizeofBigInt(
BigIntegerStr &bigInt)
{
return bigInt.Len() + 4;
}
static void nullAlgParams(
AlgorithmIdentifier &snaccAlgId)
{
snaccAlgId.parameters = new AsnAny;
char encodedNull[2] = {NULLTYPE_TAG_CODE, 0};
CSM_Buffer *cbuf = new CSM_Buffer(encodedNull, 2);
snaccAlgId.parameters->value = cbuf;
}
void snaccIntToBigIntegerStr(
int i,
BigIntegerStr &bigInt)
{
char c[4];
int dex;
int numChars;
if(i >= 0x1000000) {
numChars = 4;
}
else if(i > 0x10000) {
numChars = 3;
}
else if(i > 0x100) {
numChars = 2;
}
else {
numChars = 1;
}
for(dex=numChars-1; dex>=0; dex--) {
c[dex] = i & 0xff;
i >>= 8;
}
bigInt.ReSet(c, 4);
}
CSSM_RETURN RSAPublicKeyDecode(
RSA *openKey,
void *p,
size_t length)
{
RSAPublicKey snaccPubKey;
CssmData cData(p, length);
try {
SC_decodeAsnObj(cData, snaccPubKey);
}
catch(...) {
return CSSMERR_CSP_INVALID_KEY;
}
try {
openKey->n = bigIntStrToBn(snaccPubKey.modulus);
openKey->e = bigIntStrToBn(snaccPubKey.publicExponent);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
CSSM_RETURN RSAPublicKeyEncode(
RSA *openKey,
CssmOwnedData &encodedKey)
{
RSAPublicKey snaccPubKey;
try {
bnToBigIntStr(openKey->n, snaccPubKey.modulus);
bnToBigIntStr(openKey->e, snaccPubKey.publicExponent);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
unsigned maxSize = sizeofBigInt(snaccPubKey.modulus) +
sizeofBigInt(snaccPubKey.publicExponent) +
20;
try {
SC_encodeAsnObj(snaccPubKey, encodedKey, maxSize);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
CSSM_RETURN RSAPrivateKeyDecode(
RSA *openKey,
void *p,
size_t length)
{
PrivateKeyInfo snaccPrivKeyInfo;
CssmData cData(p, length);
try {
SC_decodeAsnObj(cData, snaccPrivKeyInfo);
}
catch(...) {
return CSSMERR_CSP_INVALID_KEY;
}
if(snaccPrivKeyInfo.privateKeyAlgorithm == NULL) {
sslSnaccDebug("RSAPrivateKeyDecode: no privateKeyAlgorithm");
return CSSMERR_CSP_INVALID_KEY;
}
if(snaccPrivKeyInfo.privateKeyAlgorithm->algorithm != rsaEncryption) {
sslSnaccDebug("RSAPrivateKeyDecode: bad privateKeyAlgorithm");
return CSSMERR_CSP_ALGID_MISMATCH;
}
char *rawOcts = snaccPrivKeyInfo.privateKey;
unsigned numBytes = snaccPrivKeyInfo.privateKey.Len();
RSAPrivateKey snaccPrivKey;
CssmData cData2(rawOcts, numBytes);
try {
SC_decodeAsnObj(cData2, snaccPrivKey);
}
catch(...) {
sslSnaccDebug("RSAPrivateKeyDecode: bad snaccPrivKeyInfo.privateKey");
return CSSMERR_CSP_INVALID_KEY;
}
try {
openKey->version = snaccPrivKey.version;
openKey->n = bigIntStrToBn(snaccPrivKey.modulus);
openKey->e = bigIntStrToBn(snaccPrivKey.publicExponent);
openKey->d = bigIntStrToBn(snaccPrivKey.privateExponent);
openKey->p = bigIntStrToBn(snaccPrivKey.prime1);
openKey->q = bigIntStrToBn(snaccPrivKey.prime2);
openKey->dmp1 = bigIntStrToBn(snaccPrivKey.exponent1);
openKey->dmq1 = bigIntStrToBn(snaccPrivKey.exponent2);
openKey->iqmp = bigIntStrToBn(snaccPrivKey.coefficient);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
CSSM_RETURN RSAPrivateKeyEncode(
RSA *openKey,
CssmOwnedData &encodedKey)
{
RSAPrivateKey snaccPrivKey;
try {
snaccPrivKey.version = openKey->version;
bnToBigIntStr(openKey->n, snaccPrivKey.modulus);
bnToBigIntStr(openKey->e, snaccPrivKey.publicExponent);
bnToBigIntStr(openKey->d, snaccPrivKey.privateExponent);
bnToBigIntStr(openKey->p, snaccPrivKey.prime1);
bnToBigIntStr(openKey->q, snaccPrivKey.prime2);
bnToBigIntStr(openKey->dmp1, snaccPrivKey.exponent1);
bnToBigIntStr(openKey->dmq1, snaccPrivKey.exponent2);
bnToBigIntStr(openKey->iqmp, snaccPrivKey.coefficient);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
unsigned maxSize = sizeofBigInt(snaccPrivKey.modulus) +
sizeofBigInt(snaccPrivKey.publicExponent) +
sizeofBigInt(snaccPrivKey.privateExponent) +
sizeofBigInt(snaccPrivKey.prime1) +
sizeofBigInt(snaccPrivKey.prime2) +
sizeofBigInt(snaccPrivKey.exponent1) +
sizeofBigInt(snaccPrivKey.exponent2) +
sizeofBigInt(snaccPrivKey.coefficient) +
64;
try {
SC_encodeAsnObj(snaccPrivKey, encodedKey, maxSize);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
PrivateKeyInfo snaccPrivKeyInfo;
snaccPrivKeyInfo.version = 0;
snaccPrivKeyInfo.privateKeyAlgorithm = new AlgorithmIdentifier;
snaccPrivKeyInfo.privateKeyAlgorithm->algorithm = rsaEncryption;
nullAlgParams(*snaccPrivKeyInfo.privateKeyAlgorithm);
snaccPrivKeyInfo.privateKey.Set((char *)encodedKey.data(), encodedKey.length());
encodedKey.reset();
try {
SC_encodeAsnObj(snaccPrivKeyInfo, encodedKey, maxSize);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
CSSM_RETURN generateDigestInfo(
const void *msgDigest,
size_t digestLen,
CSSM_ALGORITHMS digestAlg, CssmOwnedData &encodedInfo,
size_t maxEncodedSize)
{
if(digestAlg == CSSM_ALGID_NONE) {
encodedInfo.copy(msgDigest, digestLen);
return 0;
}
DigestInfo info;
info.digest.Set((char *)msgDigest, digestLen);
info.digestAlgorithm = new DigestAlgorithmIdentifier;
switch(digestAlg) {
case CSSM_ALGID_MD5:
info.digestAlgorithm->algorithm = md5;
break;
case CSSM_ALGID_MD2:
info.digestAlgorithm->algorithm = md2;
break;
case CSSM_ALGID_SHA1:
info.digestAlgorithm->algorithm = sha_1;
break;
default:
return CSSMERR_CSP_INVALID_ALGORITHM;
}
nullAlgParams(*info.digestAlgorithm);
try {
SC_encodeAsnObj(info, encodedInfo, maxEncodedSize);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
unsigned sizeofAsnBits(
AsnBits &bits)
{
return (bits.BitLen() * 8) + 4;
}
unsigned sizeofAsnOcts(
AsnOcts &octs)
{
return octs.Len() + 4;
}
static DSAAlgorithmId *dsaToSnaccAlgId(
const DSA *openKey)
{
try {
DSAAlgorithmId *algId = new DSAAlgorithmId;
algId->algorithm = dsa_bsafe;
algId->params = new DSABsafeParams;
algId->params->keySizeInBits = BN_num_bits(openKey->p);
bnToBigIntStr(openKey->p, algId->params->p);
bnToBigIntStr(openKey->q, algId->params->q);
bnToBigIntStr(openKey->g, algId->params->g);
return algId;
}
catch(...) {
return NULL;
}
}
static CSSM_RETURN snaccAlgIdToDsa(
DSAAlgorithmId &algId,
DSA *openKey)
{
if(algId.algorithm != dsa_bsafe) {
sslSnaccDebug("snaccAlgIdToDsa: bad algorithm");
return CSSMERR_CSP_ALGID_MISMATCH;
}
if(algId.params == NULL) {
sslSnaccDebug("snaccAlgIdToDsa: bad params");
return CSSMERR_CSP_INVALID_KEY;
}
openKey->p = bigIntStrToBn(algId.params->p);
openKey->q = bigIntStrToBn(algId.params->q);
openKey->g = bigIntStrToBn(algId.params->g);
return 0;
}
static unsigned sizeOfDsaAlg(
const DSAAlgorithmId &algId)
{
return sizeofBigInt(algId.params->p) +
sizeofBigInt(algId.params->g) +
sizeofBigInt(algId.params->q) +
30;
}
CSSM_RETURN DSAPublicKeyDecode(
DSA *openKey,
unsigned char *p,
unsigned length)
{
DSAPublicKey snaccPubKey;
CSSM_RETURN rtn;
CssmData cData(p, length);
try {
SC_decodeAsnObj(cData, snaccPubKey);
rtn = snaccAlgIdToDsa(*snaccPubKey.dsaAlg, openKey);
if(rtn) {
return rtn;
}
char *keyOcts = (char *)snaccPubKey.publicKey.BitOcts();
CssmData kData(keyOcts, (snaccPubKey.publicKey.BitLen() + 7) / 8);
BigIntegerStr pubKeyOcts;
SC_decodeAsnObj(kData, pubKeyOcts);
openKey->pub_key = bigIntStrToBn(pubKeyOcts);
if(openKey->pub_key == NULL) {
return CSSMERR_CSP_INVALID_KEY;
}
return 0;
}
catch(...) {
return CSSMERR_CSP_INVALID_KEY;
}
}
CSSM_RETURN DSAPublicKeyEncode(
DSA *openKey,
CssmOwnedData &encodedKey)
{
try {
DSAPublicKey snaccPubKey;
snaccPubKey.dsaAlg = dsaToSnaccAlgId(openKey);
if(snaccPubKey.dsaAlg == NULL) {
return CSSMERR_CSP_MEMORY_ERROR;
}
BigIntegerStr pubKeyInt;
bnToBigIntStr(openKey->pub_key, pubKeyInt);
unsigned maxSize = sizeofBigInt(pubKeyInt);
SC_encodeAsnObj(pubKeyInt, encodedKey, maxSize);
snaccPubKey.publicKey.Set((char *)encodedKey.data(), encodedKey.length() * 8);
maxSize = sizeOfDsaAlg(*snaccPubKey.dsaAlg) +
sizeofAsnBits(snaccPubKey.publicKey) +
20;
encodedKey.reset();
SC_encodeAsnObj(snaccPubKey, encodedKey, maxSize);
return 0;
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
}
CSSM_RETURN DSAPrivateKeyDecode(
DSA *openKey,
unsigned char *p,
unsigned length)
{
DSAPrivateKey snaccPrivKey;
int rtn;
CssmData cData(p, length);
try {
SC_decodeAsnObj(cData, snaccPrivKey);
openKey->version = snaccPrivKey.version;
rtn = snaccAlgIdToDsa(*snaccPrivKey.dsaAlg, openKey);
if(rtn) {
return rtn;
}
char *keyOcts = snaccPrivKey.privateKey;
CssmData kData(keyOcts, snaccPrivKey.privateKey.Len());
DSAPrivateKeyOcts privKeyOcts;
SC_decodeAsnObj(kData, privKeyOcts);
openKey->priv_key = bigIntStrToBn(privKeyOcts.privateKey);
if(openKey->priv_key == NULL) {
return CSSMERR_CSP_INVALID_KEY;
}
return 0;
}
catch(...) {
return CSSMERR_CSP_INVALID_KEY;
}
}
CSSM_RETURN DSAPrivateKeyEncode(
DSA *openKey,
CssmOwnedData &encodedKey)
{
try {
DSAPrivateKey snaccPrivKey;
snaccPrivKey.version = openKey->version;
snaccPrivKey.dsaAlg = dsaToSnaccAlgId(openKey);
if(snaccPrivKey.dsaAlg == NULL) {
return CSSMERR_CSP_MEMORY_ERROR;
}
DSAPrivateKeyOcts privKeyOcts;
bnToBigIntStr(openKey->priv_key, privKeyOcts.privateKey);
unsigned maxSize = sizeofBigInt(privKeyOcts.privateKey) +
10;
SC_encodeAsnObj(privKeyOcts, encodedKey, maxSize);
snaccPrivKey.privateKey.Set((char *)encodedKey.data(), encodedKey.length());
maxSize = maxSize + sizeOfDsaAlg(*snaccPrivKey.dsaAlg) +
40;
encodedKey.reset();
SC_encodeAsnObj(snaccPrivKey, encodedKey, maxSize);
return 0;
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
}
CSSM_RETURN DSASigEncode(
DSA_SIG *openSig,
CssmOwnedData &encodedSig)
{
DSASignature snaccSig;
try {
bnToBigIntStr(openSig->r, snaccSig.r);
bnToBigIntStr(openSig->s, snaccSig.s);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
unsigned maxSize = sizeofBigInt(snaccSig.r) +
sizeofBigInt(snaccSig.s) +
10;
try {
SC_encodeAsnObj(snaccSig, encodedSig, maxSize);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
CSSM_RETURN DSASigDecode(
DSA_SIG *openSig,
const void *p,
unsigned length)
{
DSASignature snaccSig;
CssmData cData((char *)p, length);
try {
SC_decodeAsnObj(cData, snaccSig);
}
catch(...) {
return CSSMERR_CSP_INVALID_SIGNATURE;
}
try {
openSig->r = bigIntStrToBn(snaccSig.r);
openSig->s = bigIntStrToBn(snaccSig.s);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
CSSM_RETURN DHPrivateKeyDecode(
DH *openKey,
unsigned char *p,
unsigned length)
{
DHPrivateKey snaccPrivKey;
CssmData cData(p, length);
try {
SC_decodeAsnObj(cData, snaccPrivKey);
}
catch(...) {
return CSSMERR_CSP_INVALID_KEY;
}
if(snaccPrivKey.dHOid != dhKeyAgreement) {
sslSnaccDebug("DHPrivateKeyDecode: bad privateKeyAlgorithm");
return CSSMERR_CSP_ALGID_MISMATCH;
}
DHParameter *params = snaccPrivKey.params;
if(params == NULL) {
sslSnaccDebug("DHPrivateKeyDecode: missing key params");
return CSSMERR_CSP_INVALID_KEY;
}
try {
openKey->priv_key = bigIntStrToBn(snaccPrivKey.secretPart);
openKey->p = bigIntStrToBn(params->prime);
openKey->g = bigIntStrToBn(params->base);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}
CSSM_RETURN DHPrivateKeyEncode(
DH *openKey,
CssmOwnedData &encodedKey)
{
DHPrivateKey snaccPrivKey;
snaccPrivKey.params = new DHParameter;
DHParameter *params = snaccPrivKey.params;
try {
snaccPrivKey.dHOid.Set(dhKeyAgreement_arc);
bnToBigIntStr(openKey->priv_key, snaccPrivKey.secretPart);
bnToBigIntStr(openKey->p, params->prime);
bnToBigIntStr(openKey->g, params->base);
if(openKey->length) {
params->privateValueLength = new BigIntegerStr();
snaccIntToBigIntegerStr(openKey->length, *params->privateValueLength);
}
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
unsigned maxSize = sizeofBigInt(snaccPrivKey.secretPart) +
sizeofBigInt(params->prime) +
sizeofBigInt(params->base) +
60; if(openKey->length) {
maxSize += sizeofBigInt(*params->privateValueLength);
}
try {
SC_encodeAsnObj(snaccPrivKey, encodedKey, maxSize);
}
catch(...) {
return CSSMERR_CSP_MEMORY_ERROR;
}
return 0;
}