Sitelet https://github.com/openssl/openssl/commit/415c3356
Skip to content

Commit 415c335

Browse files
committed
DSA mod inverse fix
There is a side channel attack against the division used to calculate one of the modulo inverses in the DSA algorithm. This change takes advantage of the primality of the modulo and Fermat's little theorem to calculate the inverse without leaking information. Thanks to Samuel Weiser for finding and reporting this. Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com> Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de> (Merged from #7487)
1 parent 59f9055 commit 415c335

1 file changed

Lines changed: 31 additions & 1 deletion

File tree

‎crypto/dsa/dsa_ossl.c‎

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ static int dsa_do_verify(const unsigned char *dgst, int dgst_len,
2323
DSA_SIG *sig, DSA *dsa);
2424
static int dsa_init(DSA *dsa);
2525
static int dsa_finish(DSA *dsa);
26+
static BIGNUM *dsa_mod_inverse_fermat(const BIGNUM *k, const BIGNUM *q,
27+
BN_CTX *ctx);
2628

2729
static DSA_METHOD openssl_dsa_meth = {
2830
"OpenSSL DSA method",
@@ -259,7 +261,7 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
259261
goto err;
260262

261263
/* Compute part of 's = inv(k) (m + xr) mod q' */
262-
if ((kinv = BN_mod_inverse(NULL, k, dsa->q, ctx)) == NULL)
264+
if ((kinv = dsa_mod_inverse_fermat(k, dsa->q, ctx)) == NULL)
263265
goto err;
264266

265267
BN_clear_free(*kinvp);
@@ -393,3 +395,31 @@ static int dsa_finish(DSA *dsa)
393395
BN_MONT_CTX_free(dsa->method_mont_p);
394396
return 1;
395397
}
398+
399+
/*
400+
* Compute the inverse of k modulo q.
401+
* Since q is prime, Fermat's Little Theorem applies, which reduces this to
402+
* mod-exp operation. Both the exponent and modulus are public information
403+
* so a mod-exp that doesn't leak the base is sufficient. A newly allocated
404+
* BIGNUM is returned which the caller must free.
405+
*/
406+
static BIGNUM *dsa_mod_inverse_fermat(const BIGNUM *k, const BIGNUM *q,
407+
BN_CTX *ctx)
408+
{
409+
BIGNUM *res = NULL;
410+
BIGNUM *r, *e;
411+
412+
if ((r = BN_new()) == NULL)
413+
return NULL;
414+
415+
BN_CTX_start(ctx);
416+
if ((e = BN_CTX_get(ctx)) != NULL
417+
&& BN_set_word(r, 2)
418+
&& BN_sub(e, q, r)
419+
&& BN_mod_exp_mont(r, k, e, q, ctx, NULL))
420+
res = r;
421+
else
422+
BN_free(r);
423+
BN_CTX_end(ctx);
424+
return res;
425+
}

0 commit comments

Comments
 (0)