summaryrefslogtreecommitdiffstats
path: root/crypto/dsa/dsa_ossl.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2018-06-19 15:07:02 +0100
committerMatt Caswell <matt@openssl.org>2018-06-21 10:15:57 +0100
commit7f9822a48213dd2feca845dbbb6bcb8beb9550de (patch)
tree36b9afd40719605332a498a4ea37aa627d14f04e /crypto/dsa/dsa_ossl.c
parent95aec8641fb6f596f170f97852e1e2839f4ec2fc (diff)
Add blinding to a DSA signature
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)
Diffstat (limited to 'crypto/dsa/dsa_ossl.c')
-rw-r--r--crypto/dsa/dsa_ossl.c66
1 files changed, 49 insertions, 17 deletions
diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c
index d78c5f00cb..5237794d8f 100644
--- a/crypto/dsa/dsa_ossl.c
+++ b/crypto/dsa/dsa_ossl.c
@@ -59,19 +59,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 *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;
}
@@ -87,6 +81,13 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
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;
@@ -101,17 +102,50 @@ 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, ret->r, dsa->q, ctx))
- goto err; /* s = xr */
- if (!BN_add(ret->s, xr, m))
- goto err; /* s = m + xr */
- if (BN_cmp(ret->s, dsa->q) > 0)
- if (!BN_sub(ret->s, ret->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;
+ } 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.
@@ -128,8 +162,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;
}
span class="w"> GtkWidget * widget, gint x, gint y); void gui_gtk_form_move(GtkForm *form, GtkWidget * widget, gint x, gint y); void gui_gtk_form_move_resize(GtkForm * form, GtkWidget * widget, gint x, gint y, gint w, gint h); // These disable and enable moving and repainting respectively. If you // want to update the layout's offsets but do not want it to repaint // itself, you should use these functions. void gui_gtk_form_freeze(GtkForm *form); void gui_gtk_form_thaw(GtkForm *form); #ifdef __cplusplus } #endif #endif // __GTK_FORM_H__