New EVP sign and verify functionality.

This commit is contained in:
Dr. Stephen Henson 2007-04-03 21:01:29 +00:00
parent e6fa7c1276
commit 9719193222
8 changed files with 253 additions and 157 deletions

View file

@ -4,6 +4,14 @@
Changes between 0.9.8e and 0.9.8f-fips [xx XXX xxxx]
*) New flag EVP_MD_FLAG_SVCTX which passes EVP_MD_CTX and key to underlying
sign/verify method. This permits the method to perform finalization
and signing itself and have access to the EVP_MD_CTX structure in case
additional parameters are needed. Modify fips_{dsa,rsa}_{sign,verify}
to use EVP_MD_FLAG_SVCTX and support PSS and X9.31 RSA modes.
Modify RSA algorithm test programs to use new parameters.
[Steve Henson]
*) Add small standalone ASN1 encoder/decoder to handle DSA signature format.
Modify test, algorithm test and selftest routines to use EVP for DSA.
Move FIPS implementation of EVP_sha*() and EVP_dss1() under fips-1.0.

View file

@ -254,11 +254,19 @@ typedef int evp_verify_method(int type,const unsigned char *m,
unsigned int m_length,const unsigned char *sigbuf,
unsigned int siglen, void *key);
typedef struct
{
EVP_MD_CTX *mctx;
void *key;
} EVP_MD_SVCTX;
#define EVP_MD_FLAG_ONESHOT 0x0001 /* digest can only handle a single
* block */
#define EVP_MD_FLAG_FIPS 0x0400 /* Note if suitable for use in FIPS mode */
#define EVP_MD_FLAG_SVCTX 0x0800 /* pass EVP_MD_SVCTX to sign/verify */
#define EVP_PKEY_NULL_method NULL,NULL,{0,0,0,0}
#ifndef OPENSSL_NO_DSA
@ -312,6 +320,15 @@ struct env_md_ctx_st
#define EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 0x0008 /* Allow use of non FIPS digest
* in FIPS mode */
#define EVP_MD_CTX_FLAG_PAD_MASK 0xF0 /* RSA mode to use */
#define EVP_MD_CTX_FLAG_PAD_PKCS1 0x00 /* PKCS#1 v1.5 mode */
#define EVP_MD_CTX_FLAG_PAD_X931 0x10 /* X9.31 mode */
#define EVP_MD_CTX_FLAG_PAD_PSS 0x20 /* PSS mode */
#define M_EVP_MD_CTX_FLAG_PSS_SALT(ctx) \
((ctx->flags>>16) &0xFFFF) /* seed length */
#define EVP_MD_CTX_FLAG_PSS_MDLEN 0xFFFF /* salt len same as digest */
#define EVP_MD_CTX_FLAG_PSS_MREC 0xFFFE /* salt max or auto recovered */
struct evp_cipher_st
{
int nid;
@ -448,6 +465,8 @@ typedef int (EVP_PBE_KEYGEN)(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
#define M_EVP_MD_CTX_clear_flags(ctx,flgs) ((ctx)->flags&=~(flgs))
#define M_EVP_MD_CTX_test_flags(ctx,flgs) ((ctx)->flags&(flgs))
#define M_EVP_MD_type(e) ((e)->type)
#define M_EVP_MD_CTX_type(e) M_EVP_MD_type(M_EVP_MD_CTX_md(e))
#define M_EVP_MD_CTX_md(e) ((e)->digest)
int EVP_MD_type(const EVP_MD *md);

View file

@ -84,10 +84,6 @@ int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, unsigned int *siglen,
MS_STATIC EVP_MD_CTX tmp_ctx;
*siglen=0;
EVP_MD_CTX_init(&tmp_ctx);
EVP_MD_CTX_copy_ex(&tmp_ctx,ctx);
EVP_DigestFinal_ex(&tmp_ctx,&(m[0]),&m_len);
EVP_MD_CTX_cleanup(&tmp_ctx);
for (i=0; i<4; i++)
{
v=ctx->digest->required_pkey_type[i];
@ -108,7 +104,23 @@ int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, unsigned int *siglen,
EVPerr(EVP_F_EVP_SIGNFINAL,EVP_R_NO_SIGN_FUNCTION_CONFIGURED);
return(0);
}
return(ctx->digest->sign(ctx->digest->type,m,m_len,sigret,siglen,
pkey->pkey.ptr));
EVP_MD_CTX_init(&tmp_ctx);
EVP_MD_CTX_copy_ex(&tmp_ctx,ctx);
if (ctx->digest->flags & EVP_MD_FLAG_SVCTX)
{
EVP_MD_SVCTX sctmp;
sctmp.mctx = &tmp_ctx;
sctmp.key = pkey->pkey.ptr;
i = ctx->digest->sign(ctx->digest->type,
NULL, -1, sigret, siglen, &sctmp);
}
else
{
EVP_DigestFinal_ex(&tmp_ctx,&(m[0]),&m_len);
i = ctx->digest->sign(ctx->digest->type,m,m_len,sigret,siglen,
pkey->pkey.ptr);
}
EVP_MD_CTX_cleanup(&tmp_ctx);
return i;
}

View file

@ -85,17 +85,29 @@ int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
EVPerr(EVP_F_EVP_VERIFYFINAL,EVP_R_WRONG_PUBLIC_KEY_TYPE);
return(-1);
}
EVP_MD_CTX_init(&tmp_ctx);
EVP_MD_CTX_copy_ex(&tmp_ctx,ctx);
EVP_DigestFinal_ex(&tmp_ctx,&(m[0]),&m_len);
EVP_MD_CTX_cleanup(&tmp_ctx);
if (ctx->digest->verify == NULL)
if (ctx->digest->verify == NULL)
{
EVPerr(EVP_F_EVP_VERIFYFINAL,EVP_R_NO_VERIFY_FUNCTION_CONFIGURED);
return(0);
}
return(ctx->digest->verify(ctx->digest->type,m,m_len,
sigbuf,siglen,pkey->pkey.ptr));
EVP_MD_CTX_init(&tmp_ctx);
EVP_MD_CTX_copy_ex(&tmp_ctx,ctx);
if (ctx->digest->flags & EVP_MD_FLAG_SVCTX)
{
EVP_MD_SVCTX sctmp;
sctmp.mctx = &tmp_ctx;
sctmp.key = pkey->pkey.ptr;
i = ctx->digest->verify(ctx->digest->type,
NULL, -1, sigbuf, siglen, &sctmp);
}
else
{
EVP_DigestFinal_ex(&tmp_ctx,&(m[0]),&m_len);
i = ctx->digest->verify(ctx->digest->type,m,m_len,
sigbuf,siglen,pkey->pkey.ptr);
}
EVP_MD_CTX_cleanup(&tmp_ctx);
return i;
}

View file

@ -177,11 +177,16 @@ int FIPS_dsa_sig_decode(DSA_SIG *sig, const unsigned char *in, int inlen)
return 1;
}
static int fips_dsa_sign(int type, const unsigned char *dgst, int dlen,
unsigned char *sig, unsigned int *siglen, DSA *dsa)
static int fips_dsa_sign(int type, const unsigned char *x, int y,
unsigned char *sig, unsigned int *siglen, EVP_MD_SVCTX *sv)
{
DSA *dsa = sv->key;
unsigned char dig[EVP_MAX_MD_SIZE];
unsigned int dlen;
DSA_SIG *s;
s=dsa->meth->dsa_do_sign(dgst,dlen,dsa);
EVP_DigestFinal_ex(sv->mctx, dig, &dlen);
s=dsa->meth->dsa_do_sign(dig,dlen,dsa);
OPENSSL_cleanse(dig, dlen);
if (s == NULL)
{
*siglen=0;
@ -194,18 +199,23 @@ static int fips_dsa_sign(int type, const unsigned char *dgst, int dlen,
return 1;
}
static int fips_dsa_verify(int type, const unsigned char *dgst, int dgst_len,
const unsigned char *sigbuf, int siglen, DSA *dsa)
static int fips_dsa_verify(int type, const unsigned char *x, int y,
const unsigned char *sigbuf, unsigned int siglen, EVP_MD_SVCTX *sv)
{
DSA *dsa = sv->key;
DSA_SIG *s;
int ret=-1;
unsigned char dig[EVP_MAX_MD_SIZE];
unsigned int dlen;
s = DSA_SIG_new();
if (s == NULL)
return ret;
if (!FIPS_dsa_sig_decode(s,sigbuf,siglen))
goto err;
ret=dsa->meth->dsa_do_verify(dgst,dgst_len,s,dsa);
EVP_DigestFinal_ex(sv->mctx, dig, &dlen);
ret=dsa->meth->dsa_do_verify(dig,dlen,s,dsa);
OPENSSL_cleanse(dig, dlen);
err:
DSA_SIG_free(s);
return ret;
@ -225,7 +235,7 @@ static const EVP_MD dss1_md=
NID_dsa,
NID_dsaWithSHA1,
SHA_DIGEST_LENGTH,
EVP_MD_FLAG_FIPS,
EVP_MD_FLAG_FIPS|EVP_MD_FLAG_SVCTX,
init,
update,
final,

View file

@ -126,107 +126,207 @@ static const unsigned char *fips_digestinfo_encoding(int nid, unsigned int *len)
}
}
static int fips_rsa_sign(int type, const unsigned char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, RSA *rsa)
static int fips_rsa_sign(int type, const unsigned char *x, unsigned int y,
unsigned char *sigret, unsigned int *siglen, EVP_MD_SVCTX *sv)
{
int i,j,ret=1;
int i,j,ret=0;
unsigned int dlen;
const unsigned char *der;
unsigned int m_len;
int pad_mode = sv->mctx->flags & EVP_MD_CTX_FLAG_PAD_MASK;
int rsa_pad_mode;
RSA *rsa = sv->key;
/* Largest DigestInfo: 19 (max encoding) + max MD */
unsigned char tmpdinfo[19 + EVP_MAX_MD_SIZE];
unsigned char md[EVP_MAX_MD_SIZE + 1];
EVP_DigestFinal_ex(sv->mctx, md, &m_len);
if((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_sign)
{
return rsa->meth->rsa_sign(type, m, m_len,
ret = rsa->meth->rsa_sign(type, md, m_len,
sigret, siglen, rsa);
goto done;
}
if(m_len > EVP_MAX_MD_SIZE)
if (pad_mode == EVP_MD_CTX_FLAG_PAD_X931)
{
RSAerr(RSA_F_RSA_SIGN,RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
memcpy(tmpdinfo, md, m_len);
tmpdinfo[m_len] = RSA_X931_hash_id(M_EVP_MD_CTX_type(sv->mctx));
i = m_len + 1;
rsa_pad_mode = RSA_X931_PADDING;
}
der = fips_digestinfo_encoding(type, &dlen);
if (!der)
else if (pad_mode == EVP_MD_CTX_FLAG_PAD_PKCS1)
{
RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE);
return(0);
}
memcpy(tmpdinfo, der, dlen);
memcpy(tmpdinfo + dlen, m, m_len);
i = dlen + m_len;
der = fips_digestinfo_encoding(type, &dlen);
if (!der)
{
RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE);
return(0);
}
memcpy(tmpdinfo, der, dlen);
memcpy(tmpdinfo + dlen, md, m_len);
i = dlen + m_len;
rsa_pad_mode = RSA_PKCS1_PADDING;
}
else if (pad_mode == EVP_MD_CTX_FLAG_PAD_PSS)
{
unsigned char *sbuf;
int saltlen;
i = RSA_size(rsa);
sbuf = OPENSSL_malloc(RSA_size(rsa));
saltlen = M_EVP_MD_CTX_FLAG_PSS_SALT(sv->mctx);
if (saltlen == EVP_MD_CTX_FLAG_PSS_MDLEN)
saltlen = -1;
else if (saltlen == EVP_MD_CTX_FLAG_PSS_MREC)
saltlen = -2;
if (!sbuf)
{
RSAerr(RSA_F_RSA_SIGN,ERR_R_MALLOC_FAILURE);
goto psserr;
}
if (!RSA_padding_add_PKCS1_PSS(rsa, sbuf, md,
M_EVP_MD_CTX_md(sv->mctx), saltlen))
goto psserr;
j=rsa->meth->rsa_priv_enc(i,sbuf,sigret,rsa,RSA_NO_PADDING);
if (j > 0)
{
ret=1;
*siglen=j;
}
psserr:
OPENSSL_cleanse(md,m_len);
OPENSSL_cleanse(sbuf, i);
OPENSSL_free(sbuf);
return ret;
}
j=RSA_size(rsa);
if (i > (j-RSA_PKCS1_PADDING_SIZE))
{
RSAerr(RSA_F_RSA_SIGN,RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
return(0);
goto done;
}
/* NB: call underlying method directly to avoid FIPS blocking */
j=rsa->meth->rsa_priv_enc(i,tmpdinfo,sigret,rsa,RSA_PKCS1_PADDING);
if (j <= 0)
ret=0;
else
j=rsa->meth->rsa_priv_enc(i,tmpdinfo,sigret,rsa,rsa_pad_mode);
if (j > 0)
{
ret=1;
*siglen=j;
}
done:
OPENSSL_cleanse(tmpdinfo,i);
return(ret);
OPENSSL_cleanse(md,m_len);
return ret;
}
static int fips_rsa_verify(int dtype,
const unsigned char *m, unsigned int m_len,
unsigned char *sigbuf, unsigned int siglen, RSA *rsa)
const unsigned char *x, unsigned int y,
unsigned char *sigbuf, unsigned int siglen, EVP_MD_SVCTX *sv)
{
int i,ret=0;
unsigned int dlen;
unsigned int dlen, diglen;
int pad_mode = sv->mctx->flags & EVP_MD_CTX_FLAG_PAD_MASK;
int rsa_pad_mode;
unsigned char *s;
const unsigned char *der;
unsigned char dig[EVP_MAX_MD_SIZE];
RSA *rsa = sv->key;
if (siglen != (unsigned int)RSA_size(rsa))
if (siglen != (unsigned int)RSA_size(sv->key))
{
RSAerr(RSA_F_RSA_VERIFY,RSA_R_WRONG_SIGNATURE_LENGTH);
return(0);
}
EVP_DigestFinal_ex(sv->mctx, dig, &diglen);
if((rsa->flags & RSA_FLAG_SIGN_VER) && rsa->meth->rsa_verify)
{
return rsa->meth->rsa_verify(dtype, m, m_len,
return rsa->meth->rsa_verify(dtype, dig, diglen,
sigbuf, siglen, rsa);
}
s= OPENSSL_malloc((unsigned int)siglen);
if (s == NULL)
{
RSAerr(RSA_F_RSA_VERIFY,ERR_R_MALLOC_FAILURE);
goto err;
}
if (pad_mode == EVP_MD_CTX_FLAG_PAD_X931)
rsa_pad_mode = RSA_X931_PADDING;
else if (pad_mode == EVP_MD_CTX_FLAG_PAD_PKCS1)
rsa_pad_mode = RSA_PKCS1_PADDING;
else if (pad_mode == EVP_MD_CTX_FLAG_PAD_PSS)
rsa_pad_mode = RSA_NO_PADDING;
/* NB: call underlying method directly to avoid FIPS blocking */
i=rsa->meth->rsa_pub_dec((int)siglen,sigbuf,s,rsa,RSA_PKCS1_PADDING);
i=rsa->meth->rsa_pub_dec((int)siglen,sigbuf,s, rsa, rsa_pad_mode);
if (i <= 0) goto err;
der = fips_digestinfo_encoding(dtype, &dlen);
if (!der)
if (pad_mode == EVP_MD_CTX_FLAG_PAD_X931)
{
RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE);
return(0);
}
/* Compare, DigestInfo length, DigestInfo header and finally
* digest value itself
*/
if ((i != (int)(dlen + m_len)) || memcmp(der, s, dlen)
|| memcmp(s + dlen, m, m_len))
{
RSAerr(RSA_F_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
goto err;
}
else
if (i != diglen + 1)
{
RSAerr(RSA_F_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
goto err;
}
if (s[diglen] != RSA_X931_hash_id(M_EVP_MD_CTX_type(sv->mctx)))
{
RSAerr(RSA_F_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
goto err;
}
if (memcmp(s, dig, diglen))
{
RSAerr(RSA_F_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
goto err;
}
ret = 1;
}
else if (pad_mode == EVP_MD_CTX_FLAG_PAD_PKCS1)
{
der = fips_digestinfo_encoding(dtype, &dlen);
if (!der)
{
RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE);
return(0);
}
/* Compare, DigestInfo length, DigestInfo header and finally
* digest value itself
*/
if ((i != (int)(dlen + diglen)) || memcmp(der, s, dlen)
|| memcmp(s + dlen, dig, diglen))
{
RSAerr(RSA_F_RSA_VERIFY,RSA_R_BAD_SIGNATURE);
goto err;
}
else
ret = 1;
}
else if (pad_mode == EVP_MD_CTX_FLAG_PAD_PSS)
{
int saltlen;
saltlen = M_EVP_MD_CTX_FLAG_PSS_SALT(sv->mctx);
if (saltlen == EVP_MD_CTX_FLAG_PSS_MDLEN)
saltlen = -1;
else if (saltlen == EVP_MD_CTX_FLAG_PSS_MREC)
saltlen = -2;
ret = RSA_verify_PKCS1_PSS(rsa, dig, M_EVP_MD_CTX_md(sv->mctx),
s, saltlen);
if (ret < 0)
ret = 0;
}
err:
if (s != NULL)
{
@ -255,7 +355,7 @@ static const EVP_MD sha1_md=
NID_sha1,
NID_sha1WithRSAEncryption,
SHA_DIGEST_LENGTH,
EVP_MD_FLAG_FIPS,
EVP_MD_FLAG_FIPS|EVP_MD_FLAG_SVCTX,
init,
update,
final,
@ -290,7 +390,7 @@ static const EVP_MD sha224_md=
NID_sha224,
NID_sha224WithRSAEncryption,
SHA224_DIGEST_LENGTH,
EVP_MD_FLAG_FIPS,
EVP_MD_FLAG_FIPS|EVP_MD_FLAG_SVCTX,
init224,
update256,
final256,
@ -309,7 +409,7 @@ static const EVP_MD sha256_md=
NID_sha256,
NID_sha256WithRSAEncryption,
SHA256_DIGEST_LENGTH,
EVP_MD_FLAG_FIPS,
EVP_MD_FLAG_FIPS|EVP_MD_FLAG_SVCTX,
init256,
update256,
final256,
@ -338,7 +438,7 @@ static const EVP_MD sha384_md=
NID_sha384,
NID_sha384WithRSAEncryption,
SHA384_DIGEST_LENGTH,
EVP_MD_FLAG_FIPS,
EVP_MD_FLAG_FIPS|EVP_MD_FLAG_SVCTX,
init384,
update512,
final512,
@ -357,7 +457,7 @@ static const EVP_MD sha512_md=
NID_sha512,
NID_sha512WithRSAEncryption,
SHA512_DIGEST_LENGTH,
EVP_MD_FLAG_FIPS,
EVP_MD_FLAG_FIPS|EVP_MD_FLAG_SVCTX,
init512,
update512,
final512,

View file

@ -336,46 +336,19 @@ static int rsa_printsig(FILE *out, RSA *rsa, const EVP_MD *dgst,
EVP_MD_CTX_init(&ctx);
if (Saltlen != -1)
if (Saltlen >= 0)
{
unsigned int mdlen;
unsigned char mdtmp[EVP_MAX_MD_SIZE + 1];
if (!EVP_DigestInit_ex(&ctx, dgst, NULL))
goto error;
if (!EVP_DigestUpdate(&ctx, Msg, Msglen))
goto error;
if (!EVP_DigestFinal(&ctx, mdtmp, &mdlen))
goto error;
if (Saltlen == -2)
{
mdtmp[mdlen] = RSA_X931_hash_id(M_EVP_MD_type(dgst));
siglen = RSA_private_encrypt(mdlen + 1, mdtmp,
sigbuf, rsa, RSA_X931_PADDING);
if (siglen <= 0)
goto error;
}
else
{
if (!RSA_padding_add_PKCS1_PSS(rsa, sigbuf, mdtmp,
dgst, Saltlen))
goto error;
siglen = RSA_private_encrypt(siglen, sigbuf, sigbuf,
rsa, RSA_NO_PADDING);
if (siglen <= 0)
goto error;
}
}
else
{
if (!EVP_SignInit_ex(&ctx, dgst, NULL))
goto error;
if (!EVP_SignUpdate(&ctx, Msg, Msglen))
goto error;
if (!EVP_SignFinal(&ctx, sigbuf, (unsigned int *)&siglen, &pk))
goto error;
M_EVP_MD_CTX_set_flags(&ctx,
EVP_MD_CTX_FLAG_PAD_PSS | (Saltlen << 16));
}
else if (Saltlen == -2)
M_EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_PAD_X931);
if (!EVP_SignInit_ex(&ctx, dgst, NULL))
goto error;
if (!EVP_SignUpdate(&ctx, Msg, Msglen))
goto error;
if (!EVP_SignFinal(&ctx, sigbuf, (unsigned int *)&siglen, &pk))
goto error;
EVP_MD_CTX_cleanup(&ctx);

View file

@ -336,58 +336,20 @@ static int rsa_printver(FILE *out,
EVP_MD_CTX_init(&ctx);
if (Saltlen != -1)
if (Saltlen >= 0)
{
int pad;
unsigned char mdtmp[EVP_MAX_MD_SIZE];
buf = OPENSSL_malloc(RSA_size(rsa_pubkey));
if (Saltlen == -2)
pad = RSA_X931_PADDING;
else
pad = RSA_NO_PADDING;
if (!buf)
goto error;
r = RSA_public_decrypt(Slen, S, buf, rsa_pubkey, pad);
if (r > 0)
{
EVP_DigestInit_ex(&ctx, dgst, NULL);
if (!EVP_DigestUpdate(&ctx, Msg, Msglen))
goto error;
if (!EVP_DigestFinal_ex(&ctx, mdtmp, NULL))
goto error;
if (pad == RSA_X931_PADDING)
{
int mdlen = M_EVP_MD_size(dgst);
if (r != mdlen + 1)
r = 0;
else if (buf[mdlen] !=
RSA_X931_hash_id(M_EVP_MD_type(dgst)))
r = 0;
else if (memcmp(buf, mdtmp, mdlen))
r = 0;
else
r = 1;
}
else
r = RSA_verify_PKCS1_PSS(rsa_pubkey,
mdtmp, dgst,
buf, Saltlen);
}
if (r < 0)
r = 0;
M_EVP_MD_CTX_set_flags(&ctx,
EVP_MD_CTX_FLAG_PAD_PSS | (Saltlen << 16));
}
else
{
else if (Saltlen == -2)
M_EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_PAD_X931);
if (!EVP_VerifyInit_ex(&ctx, dgst, NULL))
goto error;
if (!EVP_VerifyUpdate(&ctx, Msg, Msglen))
goto error;
if (!EVP_VerifyInit_ex(&ctx, dgst, NULL))
goto error;
if (!EVP_VerifyUpdate(&ctx, Msg, Msglen))
goto error;
r = EVP_VerifyFinal(&ctx, S, Slen, &pk);
r = EVP_VerifyFinal(&ctx, S, Slen, &pk);
}
EVP_MD_CTX_cleanup(&ctx);