#include "RSA_DSA_Keys.h"
#include <opensslUtils/opensslUtils.h>
#include <opensslUtils/openRsaSnacc.h>
#include <Security/cssmdata.h>
#include <AppleCSP/AppleCSPSession.h>
#include <AppleCSP/AppleCSPUtils.h>
#include <assert.h>
#include <Security/debugging.h>
#include "RSA_DSA_utils.h"
#include <AppleCSP/YarrowConnection.h>
#include <Security/appleoids.h>
#include <Security/cdsaUtils.h>
#define RSA_PUB_EXPONENT 0x10001
#define rsaKeyDebug(args...) debug("rsaKey", ## args)
RSABinaryKey::RSABinaryKey(RSA *rsaKey)
: mRsaKey(rsaKey)
{
}
RSABinaryKey::~RSABinaryKey()
{
if(mRsaKey) {
RSA_free(mRsaKey);
mRsaKey = NULL;
}
}
void RSABinaryKey::generateKeyBlob(
CssmAllocator &allocator,
CssmData &blob,
CSSM_KEYBLOB_FORMAT &format)
{
bool isPub;
CSSM_RETURN crtn;
switch(mKeyHeader.KeyClass) {
case CSSM_KEYCLASS_PUBLIC_KEY:
isPub = true;
format = RSA_PUB_KEY_FORMAT;
break;
case CSSM_KEYCLASS_PRIVATE_KEY:
isPub = false;
format = RSA_PRIV_KEY_FORMAT;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
CssmAutoData encodedKey(allocator);
if(isPub) {
crtn = RSAPublicKeyEncode(mRsaKey, encodedKey);
}
else {
crtn = RSAPrivateKeyEncode(mRsaKey, encodedKey);
}
if(crtn) {
CssmError::throwMe(crtn);
}
blob = encodedKey.release();
}
void RSAKeyPairGenContext::generate(
const Context &context,
CssmKey &pubKey,
CssmKey &privKey)
{
RSABinaryKey *pubBinKey = new RSABinaryKey();
RSABinaryKey *privBinKey = new RSABinaryKey();
try {
AppleKeyPairGenContext::generate(context,
session(),
pubKey,
pubBinKey,
privKey,
privBinKey);
}
catch (...) {
delete pubBinKey;
delete privBinKey;
throw;
}
}
void RSAKeyPairGenContext::generate(
const Context &context,
BinaryKey &pubBinKey,
BinaryKey &privBinKey,
uint32 &keyBits)
{
RSABinaryKey &rPubBinKey =
dynamic_cast<RSABinaryKey &>(pubBinKey);
RSABinaryKey &rPrivBinKey =
dynamic_cast<RSABinaryKey &>(privBinKey);
keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
rPrivBinKey.mRsaKey = RSA_generate_key(keyBits,
RSA_PUB_EXPONENT,
NULL, NULL);
if(rPrivBinKey.mRsaKey == NULL) {
rsaKeyDebug("RSA_generate_key returned NULL");
CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); }
rPubBinKey.mRsaKey = RSA_new();
if(rPrivBinKey.mRsaKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
}
RSA *pub = rPubBinKey.mRsaKey;
RSA *priv = rPrivBinKey.mRsaKey;
pub->n = BN_dup(priv->n);
pub->e = BN_dup(priv->e);
if((pub->n == NULL) || (pub->e == NULL)) {
CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
}
}
RSAKeyInfoProvider::RSAKeyInfoProvider(
const CssmKey &cssmKey) :
CSPKeyInfoProvider(cssmKey)
{
switch(cssmKey.algorithm()) {
case CSSM_ALGID_RSA:
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
switch(cssmKey.keyClass()) {
case CSSM_KEYCLASS_PUBLIC_KEY:
case CSSM_KEYCLASS_PRIVATE_KEY:
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
return;
}
void RSAKeyInfoProvider::CssmKeyToBinary(
BinaryKey **binKey)
{
*binKey = NULL;
RSA *rsaKey = NULL;
rsaKey = rawCssmKeyToRsa(mKey);
RSABinaryKey *rsaBinKey = new RSABinaryKey(rsaKey);
*binKey = rsaBinKey;
}
void RSAKeyInfoProvider::QueryKeySizeInBits(
CSSM_KEY_SIZE &keySize)
{
RSA *rsaKey = NULL;
if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
}
rsaKey = rawCssmKeyToRsa(mKey);
keySize.LogicalKeySizeInBits = RSA_size(rsaKey) * 8;
keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
RSA_free(rsaKey);
}
DSABinaryKey::DSABinaryKey(DSA *dsaKey)
: mDsaKey(dsaKey)
{
}
DSABinaryKey::~DSABinaryKey()
{
if(mDsaKey) {
DSA_free(mDsaKey);
mDsaKey = NULL;
}
}
void DSABinaryKey::generateKeyBlob(
CssmAllocator &allocator,
CssmData &blob,
CSSM_KEYBLOB_FORMAT &format)
{
bool isPub;
CSSM_RETURN crtn;
switch(mKeyHeader.KeyClass) {
case CSSM_KEYCLASS_PUBLIC_KEY:
isPub = true;
format = DSA_PUB_KEY_FORMAT;
break;
case CSSM_KEYCLASS_PRIVATE_KEY:
isPub = false;
format = DSA_PRIV_KEY_FORMAT;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
CssmAutoData encodedKey(allocator);
if(isPub) {
crtn = DSAPublicKeyEncode(mDsaKey, encodedKey);
}
else {
crtn = DSAPrivateKeyEncode(mDsaKey, encodedKey);
}
if(crtn) {
CssmError::throwMe(crtn);
}
blob = encodedKey.release();
}
void DSAKeyPairGenContext::generate(
const Context &context,
CssmKey &pubKey,
CssmKey &privKey)
{
DSABinaryKey *pubBinKey = new DSABinaryKey();
DSABinaryKey *privBinKey = new DSABinaryKey();
try {
AppleKeyPairGenContext::generate(context,
session(),
pubKey,
pubBinKey,
privKey,
privBinKey);
}
catch (...) {
delete pubBinKey;
delete privBinKey;
throw;
}
}
void DSAKeyPairGenContext::generate(
const Context &context,
BinaryKey &pubBinKey,
BinaryKey &privBinKey,
uint32 &keyBits)
{
DSABinaryKey &rPubBinKey =
dynamic_cast<DSABinaryKey &>(pubBinKey);
DSABinaryKey &rPrivBinKey =
dynamic_cast<DSABinaryKey &>(privBinKey);
keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
CssmData *paramData = context.get<CssmData>(CSSM_ATTRIBUTE_ALG_PARAMS);
DSAAlgParams algParams;
if(paramData != NULL) {
try {
SC_decodeAsnObj(*paramData, algParams);
}
catch(...) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS);
}
}
else {
dsaGenParams(keyBits, NULL, 0, algParams);
}
rPrivBinKey.mDsaKey = DSA_new();
if(rPrivBinKey.mDsaKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
}
DSA *dsaKey = rPrivBinKey.mDsaKey;
dsaKey->p = bigIntStrToBn(algParams.p);
dsaKey->q = bigIntStrToBn(algParams.q);
dsaKey->g = bigIntStrToBn(algParams.g);
int irtn = DSA_generate_key(dsaKey);
if(!irtn) {
throwRsaDsa("DSA_generate_key");
}
rPubBinKey.mDsaKey = DSA_new();
if(rPrivBinKey.mDsaKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
}
DSA *pub = rPubBinKey.mDsaKey;
DSA *priv = rPrivBinKey.mDsaKey;
pub->p = BN_dup(priv->p);
pub->q = BN_dup(priv->q);
pub->g = BN_dup(priv->g);
pub->pub_key = BN_dup(priv->pub_key);
if((pub->p == NULL) || (pub->q == NULL) || (pub->g == NULL) ||
(pub->pub_key == NULL)) {
CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
}
}
void DSAKeyPairGenContext::generate(
const Context &context,
uint32 bitSize,
CssmData ¶ms,
uint32 &attrCount,
Context::Attr * &attrs)
{
void *seed = NULL;
unsigned seedLen = 0;
CssmData *seedData = context.get<CssmData>(CSSM_ATTRIBUTE_SEED);
if(seedData) {
seed = seedData->data();
seedLen = seedData->length();
}
DSAAlgParams algParams;
dsaGenParams(bitSize, seed, seedLen, algParams);
size_t maxSize = sizeofBigInt(algParams.p) +
sizeofBigInt(algParams.q) +
sizeofBigInt(algParams.g) +
10;
CssmAutoData aDerData(session());
SC_encodeAsnObj(algParams, aDerData, maxSize);
CSSM_DATA_PTR derData = (CSSM_DATA_PTR)session().malloc(sizeof(CSSM_DATA));
*derData = aDerData.release();
freeGenAttrs();
mGenAttrs = (Context::Attr *)session().malloc(sizeof(Context::Attr));
mGenAttrs->AttributeType = CSSM_ATTRIBUTE_ALG_PARAMS;
mGenAttrs->AttributeLength = sizeof(CSSM_DATA);
mGenAttrs->Attribute.Data = derData;
copyCssmData(CssmData::overlay(*derData), params, session());
attrCount = 1;
attrs = mGenAttrs;
}
void DSAKeyPairGenContext::freeGenAttrs()
{
if(mGenAttrs == NULL) {
return;
}
if(mGenAttrs->Attribute.Data) {
if(mGenAttrs->Attribute.Data->Data) {
session().free(mGenAttrs->Attribute.Data->Data);
}
session().free(mGenAttrs->Attribute.Data);
}
session().free(mGenAttrs);
}
void DSAKeyPairGenContext::dsaGenParams(
uint32 keySizeInBits,
const void *inSeed, unsigned inSeedLen,
DSAAlgParams &algParams)
{
unsigned char seedBuf[SHA1_DIGEST_SIZE];
void *seedPtr;
if((keySizeInBits < DSA_MIN_KEY_SIZE) ||
(keySizeInBits > DSA_MAX_KEY_SIZE) ||
(keySizeInBits & DSA_KEY_BITS_MASK)) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
}
if(inSeed == NULL) {
session().getRandomBytes(SHA1_DIGEST_SIZE, seedBuf);
seedPtr = seedBuf;
}
else if(inSeedLen == SHA1_DIGEST_SIZE) {
seedPtr = (void *)inSeed;
}
else {
cspGenSha1Hash(inSeed, inSeedLen, seedBuf);
seedPtr = seedBuf;
}
DSA *dsaKey = DSA_generate_parameters(keySizeInBits,
(unsigned char *)seedPtr,
SHA1_DIGEST_SIZE,
NULL, NULL, NULL,
NULL);
if(dsaKey == NULL) {
throwRsaDsa("DSA_generate_parameters");
}
bnToBigIntStr(dsaKey->p, algParams.p);
bnToBigIntStr(dsaKey->q, algParams.q);
bnToBigIntStr(dsaKey->g, algParams.g);
DSA_free(dsaKey);
}
DSAKeyInfoProvider::DSAKeyInfoProvider(
const CssmKey &cssmKey) :
CSPKeyInfoProvider(cssmKey)
{
switch(cssmKey.algorithm()) {
case CSSM_ALGID_DSA:
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
switch(cssmKey.keyClass()) {
case CSSM_KEYCLASS_PUBLIC_KEY:
case CSSM_KEYCLASS_PRIVATE_KEY:
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
return;
}
void DSAKeyInfoProvider::CssmKeyToBinary(
BinaryKey **binKey)
{
*binKey = NULL;
DSA *dsaKey = NULL;
dsaKey = rawCssmKeyToDsa(mKey);
DSABinaryKey *dsaBinKey = new DSABinaryKey(dsaKey);
*binKey = dsaBinKey;
}
void DSAKeyInfoProvider::QueryKeySizeInBits(
CSSM_KEY_SIZE &keySize)
{
DSA *dsaKey = NULL;
if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
}
dsaKey = rawCssmKeyToDsa(mKey);
keySize.LogicalKeySizeInBits = BN_num_bits(dsaKey->p);
keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
DSA_free(dsaKey);
}