Safe (EC)DSA nonces.
This change causes (EC)DSA nonces be to calculated by hashing the message and private key along with entropy.
This commit is contained in:
parent
6aea58d0ea
commit
d4b4f085d9
@ -520,6 +520,16 @@ int BN_rand_range(BIGNUM *rnd, const BIGNUM *range);
|
||||
/* BN_pseudo_rand_range is an alias for BN_rand_range. */
|
||||
int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range);
|
||||
|
||||
/* BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike
|
||||
* BN_rand_range, it also includes the contents of |priv| and |message| in the
|
||||
* generation so that an RNG failure isn't fatal as long as |priv| remains
|
||||
* secret. This is intended for use in DSA and ECDSA where an RNG weakness
|
||||
* leads directly to private key exposure unless this function is used.
|
||||
* It returns one on success and zero on error. */
|
||||
int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv,
|
||||
const uint8_t *message, size_t message_len,
|
||||
BN_CTX *ctx);
|
||||
|
||||
/* BN_GENCB holds a callback function that is used by generation functions that
|
||||
* can take a very long time to complete. Use |BN_GENCB_set| to initialise a
|
||||
* |BN_GENCB| structure.
|
||||
@ -769,6 +779,7 @@ unsigned BN_num_bits_word(BN_ULONG l);
|
||||
#define BN_F_BN_mod_lshift_quick 119
|
||||
#define BN_F_BN_CTX_new 120
|
||||
#define BN_F_BN_mod_inverse_no_branch 121
|
||||
#define BN_F_BN_generate_dsa_nonce 122
|
||||
#define BN_R_NOT_A_SQUARE 100
|
||||
#define BN_R_TOO_MANY_ITERATIONS 101
|
||||
#define BN_R_INPUT_NOT_REDUCED 102
|
||||
@ -783,5 +794,6 @@ unsigned BN_num_bits_word(BN_ULONG l);
|
||||
#define BN_R_INVALID_RANGE 111
|
||||
#define BN_R_ARG2_LT_ARG3 112
|
||||
#define BN_R_BIGNUM_TOO_LONG 113
|
||||
#define BN_R_PRIVATE_KEY_TOO_LARGE 114
|
||||
|
||||
#endif /* OPENSSL_HEADER_BN_H */
|
||||
|
@ -25,6 +25,7 @@ const ERR_STRING_DATA BN_error_string_data[] = {
|
||||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_div, 0), "BN_div"},
|
||||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_div_recp, 0), "BN_div_recp"},
|
||||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_exp, 0), "BN_exp"},
|
||||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_generate_dsa_nonce, 0), "BN_generate_dsa_nonce"},
|
||||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp2_mont, 0), "BN_mod_exp2_mont"},
|
||||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp_mont, 0), "BN_mod_exp_mont"},
|
||||
{ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp_mont_consttime, 0), "BN_mod_exp_mont_consttime"},
|
||||
@ -50,6 +51,7 @@ const ERR_STRING_DATA BN_error_string_data[] = {
|
||||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_NOT_A_SQUARE), "NOT_A_SQUARE"},
|
||||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_NOT_INITIALIZED), "NOT_INITIALIZED"},
|
||||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_NO_INVERSE), "NO_INVERSE"},
|
||||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_PRIVATE_KEY_TOO_LARGE), "PRIVATE_KEY_TOO_LARGE"},
|
||||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_P_IS_NOT_PRIME), "P_IS_NOT_PRIME"},
|
||||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_TOO_MANY_ITERATIONS), "TOO_MANY_ITERATIONS"},
|
||||
{ERR_PACK(ERR_LIB_BN, 0, BN_R_TOO_MANY_TEMPORARY_VARIABLES), "TOO_MANY_TEMPORARY_VARIABLES"},
|
||||
|
@ -111,6 +111,7 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
uint8_t *buf = NULL;
|
||||
@ -235,3 +236,68 @@ int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
return BN_rand_range(r, range);
|
||||
}
|
||||
|
||||
int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv,
|
||||
const uint8_t *message, size_t message_len,
|
||||
BN_CTX *ctx) {
|
||||
SHA512_CTX sha;
|
||||
/* We use 512 bits of random data per iteration to
|
||||
* ensure that we have at least |range| bits of randomness. */
|
||||
uint8_t random_bytes[64];
|
||||
uint8_t digest[SHA512_DIGEST_LENGTH];
|
||||
size_t done, todo;
|
||||
/* We generate |range|+8 bytes of random output. */
|
||||
const unsigned num_k_bytes = BN_num_bytes(range) + 8;
|
||||
uint8_t private_bytes[96];
|
||||
uint8_t *k_bytes;
|
||||
int ret = 0;
|
||||
|
||||
k_bytes = OPENSSL_malloc(num_k_bytes);
|
||||
if (!k_bytes) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* We copy |priv| into a local buffer to avoid furthur exposing its
|
||||
* length. */
|
||||
todo = sizeof(priv->d[0]) * priv->top;
|
||||
if (todo > sizeof(private_bytes)) {
|
||||
/* No reasonable DSA or ECDSA key should have a private key
|
||||
* this large and we don't handle this case in order to avoid
|
||||
* leaking the length of the private key. */
|
||||
OPENSSL_PUT_ERROR(BN, BN_generate_dsa_nonce, BN_R_PRIVATE_KEY_TOO_LARGE);
|
||||
goto err;
|
||||
}
|
||||
memcpy(private_bytes, priv->d, todo);
|
||||
memset(private_bytes + todo, 0, sizeof(private_bytes) - todo);
|
||||
|
||||
for (done = 0; done < num_k_bytes;) {
|
||||
if (RAND_pseudo_bytes(random_bytes, sizeof(random_bytes)) != 1) {
|
||||
goto err;
|
||||
}
|
||||
SHA512_Init(&sha);
|
||||
SHA512_Update(&sha, &done, sizeof(done));
|
||||
SHA512_Update(&sha, private_bytes, sizeof(private_bytes));
|
||||
SHA512_Update(&sha, message, message_len);
|
||||
SHA512_Update(&sha, random_bytes, sizeof(random_bytes));
|
||||
SHA512_Final(digest, &sha);
|
||||
|
||||
todo = num_k_bytes - done;
|
||||
if (todo > SHA512_DIGEST_LENGTH) {
|
||||
todo = SHA512_DIGEST_LENGTH;
|
||||
}
|
||||
memcpy(k_bytes + done, digest, todo);
|
||||
done += todo;
|
||||
}
|
||||
|
||||
if (!BN_bin2bn(k_bytes, num_k_bytes, out) ||
|
||||
BN_mod(out, out, range, ctx) != 1) {
|
||||
goto err;
|
||||
}
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (k_bytes) {
|
||||
OPENSSL_free(k_bytes);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -313,10 +313,10 @@ int DSA_size(const DSA *dsa) {
|
||||
int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv,
|
||||
BIGNUM **out_r) {
|
||||
if (dsa->meth->sign_setup) {
|
||||
return dsa->meth->sign_setup(dsa, ctx, out_kinv, out_r);
|
||||
return dsa->meth->sign_setup(dsa, ctx, out_kinv, out_r, NULL, 0);
|
||||
}
|
||||
|
||||
return DSA_default_method.sign_setup(dsa, ctx, out_kinv, out_r);
|
||||
return DSA_default_method.sign_setup(dsa, ctx, out_kinv, out_r, NULL, 0);
|
||||
}
|
||||
|
||||
int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
|
||||
|
@ -304,7 +304,8 @@ struct dsa_method {
|
||||
|
||||
DSA_SIG *(*sign)(const uint8_t *digest, size_t digest_len, DSA *dsa);
|
||||
|
||||
int (*sign_setup)(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp);
|
||||
int (*sign_setup)(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp,
|
||||
const uint8_t *digest, size_t digest_len);
|
||||
|
||||
int (*verify)(int *out_valid, const uint8_t *digest, size_t digest_len,
|
||||
DSA_SIG *sig, const DSA *dsa);
|
||||
|
@ -74,7 +74,7 @@
|
||||
#define DSS_prime_checks 50
|
||||
|
||||
static int sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
BIGNUM **rp) {
|
||||
BIGNUM **rp, const uint8_t *digest, size_t digest_len) {
|
||||
BN_CTX *ctx;
|
||||
BIGNUM k, kq, *K, *kinv = NULL, *r = NULL;
|
||||
int ret = 0;
|
||||
@ -102,7 +102,18 @@ static int sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
|
||||
/* Get random k */
|
||||
do {
|
||||
if (!BN_rand_range(&k, dsa->q)) {
|
||||
/* If possible, we'll include the private key and message digest in the k
|
||||
* generation. The |digest| argument is only empty if |DSA_sign_setup| is
|
||||
* being used. */
|
||||
int ok;
|
||||
|
||||
if (digest_len > 0) {
|
||||
ok = BN_generate_dsa_nonce(&k, dsa->q, dsa->priv_key, digest, digest_len,
|
||||
ctx);
|
||||
} else {
|
||||
ok = BN_rand_range(&k, dsa->q);
|
||||
}
|
||||
if (!ok) {
|
||||
goto err;
|
||||
}
|
||||
} while (BN_is_zero(&k));
|
||||
|
@ -222,8 +222,9 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
BIGNUM **rp) {
|
||||
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
BIGNUM **rp, const uint8_t *digest,
|
||||
size_t digest_len) {
|
||||
BN_CTX *ctx = NULL;
|
||||
BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL;
|
||||
EC_POINT *tmp_point = NULL;
|
||||
@ -231,13 +232,13 @@ int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
int ret = 0;
|
||||
|
||||
if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_PASSED_NULL_PARAMETER);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx_in == NULL) {
|
||||
if ((ctx = BN_CTX_new()) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_MALLOC_FAILURE);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@ -249,24 +250,34 @@ int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
order = BN_new();
|
||||
X = BN_new();
|
||||
if (!k || !r || !order || !X) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_MALLOC_FAILURE);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
tmp_point = EC_POINT_new(group);
|
||||
if (tmp_point == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_EC_LIB);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
if (!EC_GROUP_get_order(group, order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_EC_LIB);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
do {
|
||||
/* get random k */
|
||||
/* If possible, we'll include the private key and message digest in the k
|
||||
* generation. The |digest| argument is only empty if |ECDSA_sign_setup| is
|
||||
* being used. */
|
||||
do {
|
||||
if (!BN_rand_range(k, order)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup,
|
||||
int ok;
|
||||
|
||||
if (digest_len > 0) {
|
||||
ok = BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
|
||||
digest, digest_len, ctx);
|
||||
} else {
|
||||
ok = BN_rand_range(k, order);
|
||||
}
|
||||
if (!ok) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup,
|
||||
ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
|
||||
goto err;
|
||||
}
|
||||
@ -287,23 +298,23 @@ int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
|
||||
/* compute r the x-coordinate of generator * k */
|
||||
if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_EC_LIB);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_EC_LIB);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_nnmod(r, X, order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_BN_LIB);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
} while (BN_is_zero(r));
|
||||
|
||||
/* compute the inverse of k */
|
||||
if (!BN_mod_inverse(k, k, order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_BN_LIB);
|
||||
OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
/* clear old values if necessary */
|
||||
@ -339,6 +350,10 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **rp) {
|
||||
return ecdsa_sign_setup(eckey, ctx, kinv, rp, NULL, 0);
|
||||
}
|
||||
|
||||
ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len,
|
||||
const BIGNUM *in_kinv, const BIGNUM *in_r,
|
||||
EC_KEY *eckey) {
|
||||
@ -385,7 +400,7 @@ ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len,
|
||||
}
|
||||
for (;;) {
|
||||
if (in_kinv == NULL || in_r == NULL) {
|
||||
if (!ECDSA_sign_setup(eckey, ctx, &kinv, &ret->r)) {
|
||||
if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, digest, digest_len)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_ECDSA_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp);
|
||||
#define ECDSA_F_ECDSA_sign_setup 102
|
||||
#define ECDSA_F_ECDSA_do_sign_ex 103
|
||||
#define ECDSA_F_ECDSA_sign_ex 104
|
||||
#define ECDSA_F_ecdsa_sign_setup 105
|
||||
#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED 100
|
||||
#define ECDSA_R_NEED_NEW_SETUP_VALUES 101
|
||||
#define ECDSA_R_MISSING_PARAMETERS 102
|
||||
|
@ -22,6 +22,7 @@ const ERR_STRING_DATA ECDSA_error_string_data[] = {
|
||||
{ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_ECDSA_sign_ex, 0), "ECDSA_sign_ex"},
|
||||
{ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_ECDSA_sign_setup, 0), "ECDSA_sign_setup"},
|
||||
{ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_digest_to_bn, 0), "digest_to_bn"},
|
||||
{ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_ecdsa_sign_setup, 0), "ecdsa_sign_setup"},
|
||||
{ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_BAD_SIGNATURE), "BAD_SIGNATURE"},
|
||||
{ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_MISSING_PARAMETERS), "MISSING_PARAMETERS"},
|
||||
{ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_NEED_NEW_SETUP_VALUES), "NEED_NEW_SETUP_VALUES"},
|
||||
|
Loading…
Reference in New Issue
Block a user