mirror of
https://github.com/openssl/openssl.git
synced 2024-12-03 05:41:46 +08:00
7f9822a482
This extends the recently added ECDSA signature blinding to blind DSA too. This is based on side channel attacks demonstrated by Keegan Ryan (NCC Group) for ECDSA which are likely to be able to be applied to DSA. Normally, as in ECDSA, during signing the signer calculates: s:= k^-1 * (m + r * priv_key) mod order In ECDSA, the addition operation above provides a sufficient signal for a flush+reload attack to derive the private key given sufficient signature operations. As a mitigation (based on a suggestion from Keegan) we add blinding to the operation so that: s := k^-1 * blind^-1 (blind * m + blind * r * priv_key) mod order Since this attack is a localhost side channel only no CVE is assigned. This commit also tweaks the previous ECDSA blinding so that blinding is only removed at the last possible step. Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/6522)
396 lines
10 KiB
C
396 lines
10 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
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "internal/cryptlib.h"
|
|
#include <openssl/bn.h>
|
|
#include <openssl/sha.h>
|
|
#include "dsa_locl.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
|
|
};
|
|
|
|
static const DSA_METHOD *default_DSA_method = &openssl_dsa_meth;
|
|
|
|
void DSA_set_default_method(const DSA_METHOD *meth)
|
|
{
|
|
default_DSA_method = meth;
|
|
}
|
|
|
|
const DSA_METHOD *DSA_get_default_method(void)
|
|
{
|
|
return default_DSA_method;
|
|
}
|
|
|
|
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, *blind, *blindm, *tmp;
|
|
BN_CTX *ctx = NULL;
|
|
int reason = ERR_R_BN_LIB;
|
|
DSA_SIG *ret = NULL;
|
|
int rv = 0;
|
|
|
|
if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
|
|
reason = DSA_R_MISSING_PARAMETERS;
|
|
goto err;
|
|
}
|
|
|
|
ret = DSA_SIG_new();
|
|
if (ret == NULL)
|
|
goto err;
|
|
ret->r = BN_new();
|
|
ret->s = BN_new();
|
|
if (ret->r == NULL || ret->s == NULL)
|
|
goto err;
|
|
|
|
ctx = BN_CTX_new();
|
|
if (ctx == NULL)
|
|
goto err;
|
|
m = BN_CTX_get(ctx);
|
|
blind = BN_CTX_get(ctx);
|
|
blindm = BN_CTX_get(ctx);
|
|
tmp = BN_CTX_get(ctx);
|
|
if (tmp == NULL)
|
|
goto err;
|
|
|
|
redo:
|
|
if (!dsa_sign_setup(dsa, ctx, &kinv, &ret->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;
|
|
|
|
/*
|
|
* The normal signature calculation is:
|
|
*
|
|
* s := k^-1 * (m + r * priv_key) mod q
|
|
*
|
|
* We will blind this to protect against side channel attacks
|
|
*
|
|
* s := blind^-1 * k^-1 * (blind * m + blind * r * priv_key) mod q
|
|
*/
|
|
|
|
/* Generate a blinding value */
|
|
do {
|
|
if (!BN_priv_rand(blind, BN_num_bits(dsa->q) - 1,
|
|
BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
|
|
goto err;
|
|
} while (BN_is_zero(blind));
|
|
BN_set_flags(blind, BN_FLG_CONSTTIME);
|
|
BN_set_flags(blindm, BN_FLG_CONSTTIME);
|
|
BN_set_flags(tmp, BN_FLG_CONSTTIME);
|
|
|
|
/* tmp := blind * priv_key * r mod q */
|
|
if (!BN_mod_mul(tmp, blind, dsa->priv_key, dsa->q, ctx))
|
|
goto err;
|
|
if (!BN_mod_mul(tmp, tmp, ret->r, dsa->q, ctx))
|
|
goto err;
|
|
|
|
/* blindm := blind * m mod q */
|
|
if (!BN_mod_mul(blindm, blind, m, dsa->q, ctx))
|
|
goto err;
|
|
|
|
/* s : = (blind * priv_key * r) + (blind * m) mod q */
|
|
if (!BN_mod_add_quick(ret->s, tmp, blindm, dsa->q))
|
|
goto err;
|
|
|
|
/* s := s * k^-1 mod q */
|
|
if (!BN_mod_mul(ret->s, ret->s, kinv, dsa->q, ctx))
|
|
goto err;
|
|
|
|
/* s:= s * blind^-1 mod q */
|
|
if (BN_mod_inverse(blind, blind, dsa->q, ctx) == NULL)
|
|
goto err;
|
|
if (!BN_mod_mul(ret->s, ret->s, blind, 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(ret->r) || BN_is_zero(ret->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(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, *kinv = NULL, *r = *rp;
|
|
BIGNUM *l, *m;
|
|
int ret = 0;
|
|
int q_bits;
|
|
|
|
if (!dsa->p || !dsa->q || !dsa->g) {
|
|
DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_MISSING_PARAMETERS);
|
|
return 0;
|
|
}
|
|
|
|
k = BN_new();
|
|
l = BN_new();
|
|
m = BN_new();
|
|
if (k == NULL || l == NULL || m == NULL)
|
|
goto err;
|
|
|
|
if (ctx_in == NULL) {
|
|
if ((ctx = BN_CTX_new()) == NULL)
|
|
goto err;
|
|
} else
|
|
ctx = ctx_in;
|
|
|
|
/* Preallocate space */
|
|
q_bits = BN_num_bits(dsa->q);
|
|
if (!BN_set_bit(k, q_bits)
|
|
|| !BN_set_bit(l, q_bits)
|
|
|| !BN_set_bit(m, q_bits))
|
|
goto err;
|
|
|
|
/* 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_priv_rand_range(k, dsa->q))
|
|
goto err;
|
|
} while (BN_is_zero(k));
|
|
|
|
BN_set_flags(k, BN_FLG_CONSTTIME);
|
|
|
|
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 */
|
|
|
|
/*
|
|
* We do not want timing information to leak the length of k, so we
|
|
* compute G^k using an equivalent scalar of fixed bit-length.
|
|
*
|
|
* We unconditionally perform both of these additions to prevent a
|
|
* small timing information leakage. We then choose the sum that is
|
|
* one bit longer than the modulus.
|
|
*
|
|
* TODO: revisit the BN_copy aiming for a memory access agnostic
|
|
* conditional copy.
|
|
*/
|
|
if (!BN_add(l, k, dsa->q)
|
|
|| !BN_add(m, l, dsa->q)
|
|
|| !BN_copy(k, BN_num_bits(l) > q_bits ? l : m))
|
|
goto err;
|
|
|
|
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(l);
|
|
BN_clear_free(m);
|
|
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;
|
|
const 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(sig, &r, &s);
|
|
|
|
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;
|
|
}
|