X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fdsa%2Fdsa_ossl.c;h=37c654d20ccd5cc5ce7b59a684d8b5dd78dbb260;hp=81c52398692a7f4acb1567e70a04a9e030e005ee;hb=3cdbea65b375bf00b31699c068c8404fe75c7d4c;hpb=033dc8fad03a23f650e347204446c882bcadcfdf diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c index 81c5239869..37c654d20c 100644 --- a/crypto/dsa/dsa_ossl.c +++ b/crypto/dsa/dsa_ossl.c @@ -1,20 +1,18 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (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 */ - #include #include "internal/cryptlib.h" +#include "internal/bn_int.h" #include #include #include "dsa_locl.h" -#include #include static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa); @@ -26,6 +24,8 @@ 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 BIGNUM *dsa_mod_inverse_fermat(const BIGNUM *k, const BIGNUM *q, + BN_CTX *ctx); static DSA_METHOD openssl_dsa_meth = { "OpenSSL DSA method", @@ -42,6 +42,18 @@ static DSA_METHOD openssl_dsa_meth = { 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; @@ -50,20 +62,13 @@ const DSA_METHOD *DSA_OpenSSL(void) static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) { BIGNUM *kinv = NULL; - BIGNUM *m; - BIGNUM *xr; - BIGNUM *r, *s; + BIGNUM *m, *blind, *blindm, *tmp; 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) { + if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) { reason = DSA_R_MISSING_PARAMETERS; goto err; } @@ -71,14 +76,23 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) ret = DSA_SIG_new(); if (ret == NULL) goto err; - - DSA_SIG_get0(&r, &s, ret); + 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, &r, dgst, dlen)) + if (!dsa_sign_setup(dsa, ctx, &kinv, &ret->r, dgst, dlen)) goto err; if (dlen > BN_num_bytes(dsa->q)) @@ -91,22 +105,55 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) 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)) + /* + * 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; - if (!BN_mod_mul(s, s, kinv, dsa->q, ctx)) + } 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(r) || BN_is_zero(s)) + if (BN_is_zero(ret->r) || BN_is_zero(ret->s)) goto redo; rv = 1; @@ -118,8 +165,6 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) ret = NULL; } BN_CTX_free(ctx); - BN_clear_free(m); - BN_clear_free(xr); BN_clear_free(kinv); return ret; } @@ -136,7 +181,9 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, { BN_CTX *ctx = NULL; BIGNUM *k, *kinv = NULL, *r = *rp; + BIGNUM *l; int ret = 0; + int q_bits, q_words; if (!dsa->p || !dsa->q || !dsa->g) { DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_MISSING_PARAMETERS); @@ -144,7 +191,8 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, } k = BN_new(); - if (k == NULL) + l = BN_new(); + if (k == NULL || l == NULL) goto err; if (ctx_in == NULL) { @@ -153,6 +201,13 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, } else ctx = ctx_in; + /* Preallocate space */ + q_bits = BN_num_bits(dsa->q); + q_words = bn_get_top(dsa->q); + if (!bn_wexpand(k, q_words + 2) + || !bn_wexpand(l, q_words + 2)) + goto err; + /* Get random k */ do { if (dgst != NULL) { @@ -163,10 +218,13 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, if (!BN_generate_dsa_nonce(k, dsa->q, dsa->priv_key, dgst, dlen, ctx)) goto err; - } else if (!BN_rand_range(k, dsa->q)) + } else if (!BN_priv_rand_range(k, dsa->q)) goto err; } while (BN_is_zero(k)); + BN_set_flags(k, BN_FLG_CONSTTIME); + BN_set_flags(l, 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)) @@ -177,19 +235,22 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, /* * 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.) + * 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. + * + * There are some concerns about the efficacy of doing this. More + * specificly refer to the discussion starting with: + * https://github.com/openssl/openssl/pull/7486#discussion_r228323705 + * The fix is to rework BN so these gymnastics aren't required. */ - - if (!BN_add(k, k, dsa->q)) + if (!BN_add(l, k, dsa->q) + || !BN_add(k, l, dsa->q)) goto err; - if (BN_num_bits(k) <= BN_num_bits(dsa->q)) { - if (!BN_add(k, k, dsa->q)) - goto err; - } - BN_set_flags(k, BN_FLG_CONSTTIME); + BN_consttime_swap(BN_is_bit_set(l, q_bits), k, l, q_words + 2); if ((dsa)->meth->bn_mod_exp != NULL) { if (!dsa->meth->bn_mod_exp(dsa, r, dsa->g, k, dsa->p, ctx, @@ -200,12 +261,11 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, 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) + /* Compute part of 's = inv(k) (m + xr) mod q' */ + if ((kinv = dsa_mod_inverse_fermat(k, dsa->q, ctx)) == NULL) goto err; BN_clear_free(*kinvp); @@ -218,6 +278,7 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, if (ctx != ctx_in) BN_CTX_free(ctx); BN_clear_free(k); + BN_clear_free(l); return ret; } @@ -227,7 +288,7 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len, BN_CTX *ctx; BIGNUM *u1, *u2, *t1; BN_MONT_CTX *mont = NULL; - BIGNUM *r, *s; + 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); @@ -252,7 +313,7 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len, if (u1 == NULL || u2 == NULL || t1 == NULL || ctx == NULL) goto err; - DSA_SIG_get0(&r, &s, sig); + DSA_SIG_get0(sig, &r, &s); if (BN_is_zero(r) || BN_is_negative(r) || BN_ucmp(r, dsa->q) >= 0) { @@ -323,17 +384,45 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len, BN_free(u1); BN_free(u2); BN_free(t1); - return (ret); + return ret; } static int dsa_init(DSA *dsa) { dsa->flags |= DSA_FLAG_CACHE_MONT_P; - return (1); + return 1; } static int dsa_finish(DSA *dsa) { BN_MONT_CTX_free(dsa->method_mont_p); - return (1); + return 1; +} + +/* + * Compute the inverse of k modulo q. + * Since q is prime, Fermat's Little Theorem applies, which reduces this to + * mod-exp operation. Both the exponent and modulus are public information + * so a mod-exp that doesn't leak the base is sufficient. A newly allocated + * BIGNUM is returned which the caller must free. + */ +static BIGNUM *dsa_mod_inverse_fermat(const BIGNUM *k, const BIGNUM *q, + BN_CTX *ctx) +{ + BIGNUM *res = NULL; + BIGNUM *r, *e; + + if ((r = BN_new()) == NULL) + return NULL; + + BN_CTX_start(ctx); + if ((e = BN_CTX_get(ctx)) != NULL + && BN_set_word(r, 2) + && BN_sub(e, q, r) + && BN_mod_exp_mont(r, k, e, q, ctx, NULL)) + res = r; + else + BN_free(r); + BN_CTX_end(ctx); + return res; }