mirror of
https://github.com/openssl/openssl.git
synced 2024-12-15 06:01:37 +08:00
f943e640ef
The dsa_ossl.c file defined a couple of multi-line macros, but then only used each one once. The macros just serve to complicate the code and make it more difficult to understand what is really going on. Hence they are removed. Reviewed-by: Richard Levitte <levitte@openssl.org>
353 lines
9.1 KiB
C
353 lines
9.1 KiB
C
/*
|
|
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the OpenSSL license (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
/* Original version from Steven Schoch <schoch@sheba.arc.nasa.gov> */
|
|
|
|
#include <stdio.h>
|
|
#include "internal/cryptlib.h"
|
|
#include <openssl/bn.h>
|
|
#include <openssl/sha.h>
|
|
#include "dsa_locl.h"
|
|
#include <openssl/rand.h>
|
|
#include <openssl/asn1.h>
|
|
|
|
static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa);
|
|
static int dsa_sign_setup_no_digest(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
|
|
BIGNUM **rp);
|
|
static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
|
|
BIGNUM **rp, const unsigned char *dgst, int dlen);
|
|
static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
|
|
DSA_SIG *sig, DSA *dsa);
|
|
static int dsa_init(DSA *dsa);
|
|
static int dsa_finish(DSA *dsa);
|
|
|
|
static DSA_METHOD openssl_dsa_meth = {
|
|
"OpenSSL DSA method",
|
|
dsa_do_sign,
|
|
dsa_sign_setup_no_digest,
|
|
dsa_do_verify,
|
|
NULL, /* dsa_mod_exp, */
|
|
NULL, /* dsa_bn_mod_exp, */
|
|
dsa_init,
|
|
dsa_finish,
|
|
DSA_FLAG_FIPS_METHOD,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
const DSA_METHOD *DSA_OpenSSL(void)
|
|
{
|
|
return &openssl_dsa_meth;
|
|
}
|
|
|
|
static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
|
|
{
|
|
BIGNUM *kinv = NULL;
|
|
BIGNUM *m;
|
|
BIGNUM *xr;
|
|
BIGNUM *r, *s;
|
|
BN_CTX *ctx = NULL;
|
|
int reason = ERR_R_BN_LIB;
|
|
DSA_SIG *ret = NULL;
|
|
int rv = 0;
|
|
|
|
m = BN_new();
|
|
xr = BN_new();
|
|
if (m == NULL || xr == NULL)
|
|
goto err;
|
|
|
|
if (!dsa->p || !dsa->q || !dsa->g) {
|
|
reason = DSA_R_MISSING_PARAMETERS;
|
|
goto err;
|
|
}
|
|
|
|
ret = DSA_SIG_new();
|
|
if (ret == NULL)
|
|
goto err;
|
|
|
|
DSA_SIG_get0(&r, &s, ret);
|
|
|
|
ctx = BN_CTX_new();
|
|
if (ctx == NULL)
|
|
goto err;
|
|
redo:
|
|
if (!dsa_sign_setup(dsa, ctx, &kinv, &r, dgst, dlen))
|
|
goto err;
|
|
|
|
if (dlen > BN_num_bytes(dsa->q))
|
|
/*
|
|
* if the digest length is greater than the size of q use the
|
|
* BN_num_bits(dsa->q) leftmost bits of the digest, see fips 186-3,
|
|
* 4.2
|
|
*/
|
|
dlen = BN_num_bytes(dsa->q);
|
|
if (BN_bin2bn(dgst, dlen, m) == NULL)
|
|
goto err;
|
|
|
|
/* Compute s = inv(k) (m + xr) mod q */
|
|
if (!BN_mod_mul(xr, dsa->priv_key, r, dsa->q, ctx))
|
|
goto err; /* s = xr */
|
|
if (!BN_add(s, xr, m))
|
|
goto err; /* s = m + xr */
|
|
if (BN_cmp(s, dsa->q) > 0)
|
|
if (!BN_sub(s, s, dsa->q))
|
|
goto err;
|
|
if (!BN_mod_mul(s, s, kinv, dsa->q, ctx))
|
|
goto err;
|
|
|
|
/*
|
|
* Redo if r or s is zero as required by FIPS 186-3: this is very
|
|
* unlikely.
|
|
*/
|
|
if (BN_is_zero(r) || BN_is_zero(s))
|
|
goto redo;
|
|
|
|
rv = 1;
|
|
|
|
err:
|
|
if (rv == 0) {
|
|
DSAerr(DSA_F_DSA_DO_SIGN, reason);
|
|
DSA_SIG_free(ret);
|
|
ret = NULL;
|
|
}
|
|
BN_CTX_free(ctx);
|
|
BN_clear_free(m);
|
|
BN_clear_free(xr);
|
|
BN_clear_free(kinv);
|
|
return ret;
|
|
}
|
|
|
|
static int dsa_sign_setup_no_digest(DSA *dsa, BN_CTX *ctx_in,
|
|
BIGNUM **kinvp, BIGNUM **rp)
|
|
{
|
|
return dsa_sign_setup(dsa, ctx_in, kinvp, rp, NULL, 0);
|
|
}
|
|
|
|
static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
|
|
BIGNUM **kinvp, BIGNUM **rp,
|
|
const unsigned char *dgst, int dlen)
|
|
{
|
|
BN_CTX *ctx = NULL;
|
|
BIGNUM *k, *kq, *K, *kinv = NULL, *r = *rp;
|
|
int ret = 0;
|
|
|
|
if (!dsa->p || !dsa->q || !dsa->g) {
|
|
DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_MISSING_PARAMETERS);
|
|
return 0;
|
|
}
|
|
|
|
k = BN_new();
|
|
kq = BN_new();
|
|
if (k == NULL || kq == NULL)
|
|
goto err;
|
|
|
|
if (ctx_in == NULL) {
|
|
if ((ctx = BN_CTX_new()) == NULL)
|
|
goto err;
|
|
} else
|
|
ctx = ctx_in;
|
|
|
|
/* Get random k */
|
|
do {
|
|
if (dgst != NULL) {
|
|
/*
|
|
* We calculate k from SHA512(private_key + H(message) + random).
|
|
* This protects the private key from a weak PRNG.
|
|
*/
|
|
if (!BN_generate_dsa_nonce(k, dsa->q, dsa->priv_key, dgst,
|
|
dlen, ctx))
|
|
goto err;
|
|
} else if (!BN_rand_range(k, dsa->q))
|
|
goto err;
|
|
} while (BN_is_zero(k));
|
|
|
|
if (dsa->flags & DSA_FLAG_CACHE_MONT_P) {
|
|
if (!BN_MONT_CTX_set_locked(&dsa->method_mont_p,
|
|
dsa->lock, dsa->p, ctx))
|
|
goto err;
|
|
}
|
|
|
|
/* Compute r = (g^k mod p) mod q */
|
|
|
|
if ((dsa->flags & DSA_FLAG_NO_EXP_CONSTTIME) == 0) {
|
|
if (!BN_copy(kq, k))
|
|
goto err;
|
|
|
|
/*
|
|
* We do not want timing information to leak the length of k, so we
|
|
* compute g^k using an equivalent exponent of fixed length. (This
|
|
* is a kludge that we need because the BN_mod_exp_mont() does not
|
|
* let us specify the desired timing behaviour.)
|
|
*/
|
|
|
|
if (!BN_add(kq, kq, dsa->q))
|
|
goto err;
|
|
if (BN_num_bits(kq) <= BN_num_bits(dsa->q)) {
|
|
if (!BN_add(kq, kq, dsa->q))
|
|
goto err;
|
|
}
|
|
|
|
K = kq;
|
|
} else {
|
|
K = k;
|
|
}
|
|
|
|
if ((dsa->flags & DSA_FLAG_NO_EXP_CONSTTIME) == 0) {
|
|
BN_set_flags(K, BN_FLG_CONSTTIME);
|
|
}
|
|
|
|
if ((dsa)->meth->bn_mod_exp != NULL) {
|
|
if (!dsa->meth->bn_mod_exp(dsa, r, dsa->g, K, dsa->p, ctx,
|
|
dsa->method_mont_p))
|
|
goto err;
|
|
} else {
|
|
if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p))
|
|
goto err;
|
|
}
|
|
|
|
|
|
if (!BN_mod(r, r, dsa->q, ctx))
|
|
goto err;
|
|
|
|
/* Compute part of 's = inv(k) (m + xr) mod q' */
|
|
if ((kinv = BN_mod_inverse(NULL, k, dsa->q, ctx)) == NULL)
|
|
goto err;
|
|
|
|
BN_clear_free(*kinvp);
|
|
*kinvp = kinv;
|
|
kinv = NULL;
|
|
ret = 1;
|
|
err:
|
|
if (!ret)
|
|
DSAerr(DSA_F_DSA_SIGN_SETUP, ERR_R_BN_LIB);
|
|
if (ctx != ctx_in)
|
|
BN_CTX_free(ctx);
|
|
BN_clear_free(k);
|
|
BN_clear_free(kq);
|
|
return ret;
|
|
}
|
|
|
|
static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
|
|
DSA_SIG *sig, DSA *dsa)
|
|
{
|
|
BN_CTX *ctx;
|
|
BIGNUM *u1, *u2, *t1;
|
|
BN_MONT_CTX *mont = NULL;
|
|
BIGNUM *r, *s;
|
|
int ret = -1, i;
|
|
if (!dsa->p || !dsa->q || !dsa->g) {
|
|
DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_MISSING_PARAMETERS);
|
|
return -1;
|
|
}
|
|
|
|
i = BN_num_bits(dsa->q);
|
|
/* fips 186-3 allows only different sizes for q */
|
|
if (i != 160 && i != 224 && i != 256) {
|
|
DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_BAD_Q_VALUE);
|
|
return -1;
|
|
}
|
|
|
|
if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) {
|
|
DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_MODULUS_TOO_LARGE);
|
|
return -1;
|
|
}
|
|
u1 = BN_new();
|
|
u2 = BN_new();
|
|
t1 = BN_new();
|
|
ctx = BN_CTX_new();
|
|
if (u1 == NULL || u2 == NULL || t1 == NULL || ctx == NULL)
|
|
goto err;
|
|
|
|
DSA_SIG_get0(&r, &s, sig);
|
|
|
|
if (BN_is_zero(r) || BN_is_negative(r) ||
|
|
BN_ucmp(r, dsa->q) >= 0) {
|
|
ret = 0;
|
|
goto err;
|
|
}
|
|
if (BN_is_zero(s) || BN_is_negative(s) ||
|
|
BN_ucmp(s, dsa->q) >= 0) {
|
|
ret = 0;
|
|
goto err;
|
|
}
|
|
|
|
/*
|
|
* Calculate W = inv(S) mod Q save W in u2
|
|
*/
|
|
if ((BN_mod_inverse(u2, s, dsa->q, ctx)) == NULL)
|
|
goto err;
|
|
|
|
/* save M in u1 */
|
|
if (dgst_len > (i >> 3))
|
|
/*
|
|
* if the digest length is greater than the size of q use the
|
|
* BN_num_bits(dsa->q) leftmost bits of the digest, see fips 186-3,
|
|
* 4.2
|
|
*/
|
|
dgst_len = (i >> 3);
|
|
if (BN_bin2bn(dgst, dgst_len, u1) == NULL)
|
|
goto err;
|
|
|
|
/* u1 = M * w mod q */
|
|
if (!BN_mod_mul(u1, u1, u2, dsa->q, ctx))
|
|
goto err;
|
|
|
|
/* u2 = r * w mod q */
|
|
if (!BN_mod_mul(u2, r, u2, dsa->q, ctx))
|
|
goto err;
|
|
|
|
if (dsa->flags & DSA_FLAG_CACHE_MONT_P) {
|
|
mont = BN_MONT_CTX_set_locked(&dsa->method_mont_p,
|
|
dsa->lock, dsa->p, ctx);
|
|
if (!mont)
|
|
goto err;
|
|
}
|
|
|
|
if (dsa->meth->dsa_mod_exp != NULL) {
|
|
if (!dsa->meth->dsa_mod_exp(dsa, t1, dsa->g, u1, dsa->pub_key, u2,
|
|
dsa->p, ctx, mont))
|
|
goto err;
|
|
} else {
|
|
if (!BN_mod_exp2_mont(t1, dsa->g, u1, dsa->pub_key, u2, dsa->p, ctx,
|
|
mont))
|
|
goto err;
|
|
}
|
|
|
|
/* let u1 = u1 mod q */
|
|
if (!BN_mod(u1, t1, dsa->q, ctx))
|
|
goto err;
|
|
|
|
/*
|
|
* V is now in u1. If the signature is correct, it will be equal to R.
|
|
*/
|
|
ret = (BN_ucmp(u1, r) == 0);
|
|
|
|
err:
|
|
if (ret < 0)
|
|
DSAerr(DSA_F_DSA_DO_VERIFY, ERR_R_BN_LIB);
|
|
BN_CTX_free(ctx);
|
|
BN_free(u1);
|
|
BN_free(u2);
|
|
BN_free(t1);
|
|
return (ret);
|
|
}
|
|
|
|
static int dsa_init(DSA *dsa)
|
|
{
|
|
dsa->flags |= DSA_FLAG_CACHE_MONT_P;
|
|
return (1);
|
|
}
|
|
|
|
static int dsa_finish(DSA *dsa)
|
|
{
|
|
BN_MONT_CTX_free(dsa->method_mont_p);
|
|
return (1);
|
|
}
|