RSA_DSA_signature.cpp [plain text]
#include "RSA_DSA_signature.h"
#include "RSA_DSA_utils.h"
#include <stdexcept>
#include <assert.h>
#include <Security/debugging.h>
#include <Security/cssmdata.h>
#include <opensslUtils/opensslUtils.h>
#include <opensslUtils/openRsaSnacc.h>
#define rsaSigDebug(args...) debug("rsaSig", ## args)
RSASigner::~RSASigner()
{
if(mWeMallocdRsaKey) {
assert(mRsaKey != NULL);
RSA_free(mRsaKey);
mRsaKey = NULL;
mWeMallocdRsaKey = false;
}
}
void RSASigner::signerInit(
const Context &context,
bool isSigning)
{
setIsSigning(isSigning);
keyFromContext(context);
uint32 padding;
bool padPresent = context.getInt(CSSM_ATTRIBUTE_PADDING, padding);
if(padPresent) {
switch(padding) {
case CSSM_PADDING_NONE:
mPadding = RSA_NO_PADDING;
break;
case CSSM_PADDING_PKCS1:
mPadding = RSA_PKCS1_PADDING;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
}
}
setInitFlag(true);
}
void RSASigner::sign(
const void *data,
size_t dataLen,
void *sig,
size_t *sigLen)
{
if(mRsaKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
}
CssmAutoData encodedInfo(alloc());
int irtn = generateDigestInfo(data,
dataLen,
digestAlg(),
encodedInfo,
RSA_size(mRsaKey));
if(irtn) {
rsaSigDebug("***digestInfo error\n");
throwOpensslErr(irtn);
}
irtn = RSA_private_encrypt(encodedInfo.length(),
(unsigned char *)encodedInfo.data(),
(unsigned char *)sig,
mRsaKey,
mPadding);
if(irtn < 0) {
throwRsaDsa("RSA_private_encrypt");
}
if((unsigned)irtn > *sigLen) {
rsaSigDebug("RSA_private_encrypt: sig overflow");
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
}
*sigLen = (unsigned)irtn;
}
void RSASigner::verify(
const void *data,
size_t dataLen,
const void *sig,
size_t sigLen)
{
const char *op = NULL;
bool throwSigVerify = false;
if(mRsaKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
}
CssmAutoData encodedInfo(alloc());
int irtn = generateDigestInfo(data,
dataLen,
digestAlg(),
encodedInfo,
RSA_size(mRsaKey));
if(irtn) {
rsaSigDebug("***digestInfo error\n");
CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
}
unsigned char *decryptSig =
(unsigned char *)alloc().malloc(RSA_size(mRsaKey));
unsigned decryptSigLen;
irtn = RSA_public_decrypt(sigLen,
(unsigned char *)sig,
decryptSig,
mRsaKey,
mPadding);
if(irtn < 0) {
op = "RSA_public_decrypt";
throwSigVerify = true;
goto abort;
}
decryptSigLen = (unsigned)irtn;
if(decryptSigLen != encodedInfo.length()) {
rsaSigDebug("***Decrypted signature length error (exp %ld, got %d)\n",
encodedInfo.length(), decryptSigLen);
throwSigVerify = true;
op = "RSA Sig length check";
goto abort;
}
if(memcmp(decryptSig, encodedInfo.data(), decryptSigLen)) {
rsaSigDebug("***Signature miscompare\n");
throwSigVerify = true;
op = "RSA Sig miscompare";
goto abort;
}
else {
irtn = 0;
}
abort:
if(decryptSig != NULL) {
alloc().free(decryptSig);
}
if(throwSigVerify) {
CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
}
}
size_t RSASigner::maxSigSize()
{
if(mRsaKey == NULL) {
return 0;
}
return RSA_size(mRsaKey);
}
void RSASigner::keyFromContext(
const Context &context)
{
if(initFlag() && (mRsaKey != NULL)) {
return;
}
CSSM_KEYCLASS keyClass;
CSSM_KEYUSE keyUse;
if(isSigning()) {
keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
keyUse = CSSM_KEYUSE_SIGN;
}
else {
keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
keyUse = CSSM_KEYUSE_VERIFY;
}
if(mRsaKey == NULL) {
mRsaKey = contextToRsaKey(context,
mSession,
keyClass,
keyUse,
mWeMallocdRsaKey);
}
}
DSASigner::~DSASigner()
{
if(mWeMallocdDsaKey) {
assert(mDsaKey != NULL);
DSA_free(mDsaKey);
mDsaKey = NULL;
mWeMallocdDsaKey = false;
}
}
void DSASigner::signerInit(
const Context &context,
bool isSigning)
{
setIsSigning(isSigning);
keyFromContext(context);
setInitFlag(true);
}
void DSASigner::sign(
const void *data,
size_t dataLen,
void *sig,
size_t *sigLen)
{
if(mDsaKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
}
if(mDsaKey->priv_key == NULL) {
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
DSA_SIG *dsaSig = DSA_do_sign((unsigned char *)data, dataLen, mDsaKey);
if(dsaSig == NULL) {
throwRsaDsa("DSA_do_sign");
}
CssmAutoData encodedSig(alloc());
int irtn = DSASigEncode(dsaSig, encodedSig);
if(irtn) {
throwRsaDsa("DSASigEncode");
}
if(encodedSig.length() > *sigLen) {
throwRsaDsa("DSA sign overflow");
}
memmove(sig, encodedSig.data(), encodedSig.length());
*sigLen = encodedSig.length();
DSA_SIG_free(dsaSig);
}
void DSASigner::verify(
const void *data,
size_t dataLen,
const void *sig,
size_t sigLen)
{
bool throwSigVerify = false;
DSA_SIG *dsaSig = NULL;
CSSM_RETURN crtn = CSSM_OK;
int irtn;
if(mDsaKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
}
if(mDsaKey->pub_key == NULL) {
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
dsaSig = DSA_SIG_new();
crtn = DSASigDecode(dsaSig, sig, sigLen);
if(crtn) {
goto abort;
}
irtn = DSA_do_verify((unsigned char *)data, dataLen, dsaSig, mDsaKey);
if(!irtn) {
throwSigVerify = true;
}
abort:
if(dsaSig != NULL) {
DSA_SIG_free(dsaSig);
}
if(throwSigVerify) {
CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
}
else if(crtn) {
CssmError::throwMe(crtn);
}
}
size_t DSASigner::maxSigSize()
{
if(mDsaKey == NULL) {
return 0;
}
size_t outSize;
size_t sizeOfOneInt;
sizeOfOneInt = (160 / 8) + 1 + 2; outSize = (2 * sizeOfOneInt) + 5;
return outSize;
}
void DSASigner::keyFromContext(
const Context &context)
{
if(initFlag() && (mDsaKey != NULL)) {
return;
}
CSSM_KEYCLASS keyClass;
CSSM_KEYUSE keyUse;
if(isSigning()) {
keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
keyUse = CSSM_KEYUSE_SIGN;
}
else {
keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
keyUse = CSSM_KEYUSE_VERIFY;
}
if(mDsaKey == NULL) {
mDsaKey = contextToDsaKey(context,
mSession,
keyClass,
keyUse,
mWeMallocdDsaKey);
}
}