]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
nettle: avoid normalization of mpz_t in deterministic ECDSA
authorDaiki Ueno <ueno@gnu.org>
Fri, 12 Jan 2024 08:56:58 +0000 (17:56 +0900)
committerZoltan Fridrich <zfridric@redhat.com>
Mon, 18 Mar 2024 12:41:53 +0000 (13:41 +0100)
This removes function calls that potentially leak bit-length of a
private key used to calculate a nonce in deterministic ECDSA.  Namely:

- _gnutls_dsa_compute_k has been rewritten to work on always
  zero-padded mp_limb_t arrays instead of mpz_t
- rnd_mpz_func has been replaced with rnd_datum_func, which is backed
  by a byte array instead of an mpz_t value

Signed-off-by: Daiki Ueno <ueno@gnu.org>
lib/nettle/int/dsa-compute-k.c
lib/nettle/int/dsa-compute-k.h
lib/nettle/int/ecdsa-compute-k.c
lib/nettle/int/ecdsa-compute-k.h
lib/nettle/pk.c
tests/sign-verify-deterministic.c

index 8ff5739c2be374038e24d7589269212cba1a924b..2fcb2bb80ed52221637d4343c1e7fba760f90798 100644 (file)
 #include "mpn-base256.h"
 #include <string.h>
 
-#define BITS_TO_LIMBS(bits) (((bits) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
+/* For mini-gmp */
+#ifndef GMP_LIMB_BITS
+#define GMP_LIMB_BITS GMP_NUMB_BITS
+#endif
 
-/* The maximum size of q, chosen from the fact that we support
- * 521-bit elliptic curve generator and 512-bit DSA subgroup at
- * maximum. */
-#define MAX_Q_BITS 521
-#define MAX_Q_SIZE ((MAX_Q_BITS + 7) / 8)
-#define MAX_Q_LIMBS BITS_TO_LIMBS(MAX_Q_BITS)
+static inline int is_zero_limb(mp_limb_t x)
+{
+       x |= (x << 1);
+       return ((x >> 1) - 1) >> (GMP_LIMB_BITS - 1);
+}
+
+static int sec_zero_p(const mp_limb_t *ap, mp_size_t n)
+{
+       volatile mp_limb_t w;
+       mp_size_t i;
 
-#define MAX_HASH_BITS (MAX_HASH_SIZE * 8)
-#define MAX_HASH_LIMBS BITS_TO_LIMBS(MAX_HASH_BITS)
+       for (i = 0, w = 0; i < n; i++)
+               w |= ap[i];
 
-int _gnutls_dsa_compute_k(mpz_t k, const mpz_t q, const mpz_t x,
+       return is_zero_limb(w);
+}
+
+int _gnutls_dsa_compute_k(mp_limb_t *h, const mp_limb_t *q, const mp_limb_t *x,
+                         mp_size_t qn, mp_bitcnt_t q_bits,
                          gnutls_mac_algorithm_t mac, const uint8_t *digest,
                          size_t length)
 {
@@ -51,9 +62,6 @@ int _gnutls_dsa_compute_k(mpz_t k, const mpz_t q, const mpz_t x,
        uint8_t K[MAX_HASH_SIZE];
        uint8_t xp[MAX_Q_SIZE];
        uint8_t tp[MAX_Q_SIZE];
-       mp_limb_t h[MAX(MAX_Q_LIMBS, MAX_HASH_LIMBS)];
-       mp_bitcnt_t q_bits = mpz_sizeinbase(q, 2);
-       mp_size_t qn = mpz_size(q);
        mp_bitcnt_t h_bits = length * 8;
        mp_size_t hn = BITS_TO_LIMBS(h_bits);
        size_t nbytes = (q_bits + 7) / 8;
@@ -62,6 +70,7 @@ int _gnutls_dsa_compute_k(mpz_t k, const mpz_t q, const mpz_t x,
        mp_limb_t cy;
        gnutls_hmac_hd_t hd;
        int ret = 0;
+       mp_limb_t scratch[MAX_Q_LIMBS];
 
        if (unlikely(q_bits > MAX_Q_BITS))
                return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
@@ -69,7 +78,7 @@ int _gnutls_dsa_compute_k(mpz_t k, const mpz_t q, const mpz_t x,
                return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
        /* int2octets(x) */
-       mpn_get_base256(xp, nbytes, mpz_limbs_read(x), qn);
+       mpn_get_base256(xp, nbytes, x, qn);
 
        /* bits2octets(h) */
        mpn_set_base256(h, hn, digest, length);
@@ -93,12 +102,12 @@ int _gnutls_dsa_compute_k(mpz_t k, const mpz_t q, const mpz_t x,
                        mpn_rshift(h, h, hn, shift % GMP_NUMB_BITS);
        }
 
-       cy = mpn_sub_n(h, h, mpz_limbs_read(q), qn);
+       cy = mpn_sub_n(h, h, q, qn);
        /* Fall back to addmul_1, if nettle is linked with mini-gmp. */
 #ifdef mpn_cnd_add_n
-       mpn_cnd_add_n(cy, h, h, mpz_limbs_read(q), qn);
+       mpn_cnd_add_n(cy, h, h, q, qn);
 #else
-       mpn_addmul_1(h, mpz_limbs_read(q), qn, cy != 0);
+       mpn_addmul_1(h, q, qn, cy != 0);
 #endif
        mpn_get_base256(tp, nbytes, h, qn);
 
@@ -174,12 +183,8 @@ int _gnutls_dsa_compute_k(mpz_t k, const mpz_t q, const mpz_t x,
                if (tlen * 8 > q_bits)
                        mpn_rshift(h, h, qn, tlen * 8 - q_bits);
                /* Check if k is in [1,q-1] */
-               if (!mpn_zero_p(h, qn) &&
-                   mpn_cmp(h, mpz_limbs_read(q), qn) < 0) {
-                       mpn_copyi(mpz_limbs_write(k, qn), h, qn);
-                       mpz_limbs_finish(k, qn);
+               if (!sec_zero_p(h, qn) && mpn_sub_n(scratch, h, q, qn))
                        break;
-               }
 
                ret = gnutls_hmac_init(&hd, mac, K, length);
                if (ret < 0)
@@ -203,3 +208,24 @@ out:
 
        return ret;
 }
+
+/* cancel-out dsa_sign's addition of 1 to random data */
+void _gnutls_dsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+                                 mp_size_t n)
+{
+       /* Fall back to sub_1, if nettle is linked with mini-gmp. */
+#ifdef mpn_sec_sub_1
+       mp_limb_t t[MAX_Q_LIMBS];
+
+       mpn_sec_sub_1(h, h, n, 1, t);
+#else
+       mpn_sub_1(h, h, n, 1);
+#endif
+       mpn_get_base256(k, nbytes, h, n);
+}
+
+void _gnutls_ecdsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+                                   mp_size_t n)
+{
+       mpn_get_base256(k, nbytes, h, n);
+}
index 49d243acb46781c29181a524028d9e6f46be877e..2f0667a01e885fc6cd17eef38743a08f01b6f109 100644 (file)
 #include <gnutls/gnutls.h>
 #include <nettle/bignum.h> /* includes gmp.h */
 
-int _gnutls_dsa_compute_k(mpz_t k, const mpz_t q, const mpz_t x,
+#define BITS_TO_LIMBS(bits) (((bits) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
+
+/* The maximum size of q, chosen from the fact that we support
+ * 521-bit elliptic curve generator and 512-bit DSA subgroup at
+ * maximum. */
+#define MAX_Q_BITS 521
+#define MAX_Q_SIZE ((MAX_Q_BITS + 7) / 8)
+#define MAX_Q_LIMBS BITS_TO_LIMBS(MAX_Q_BITS)
+
+#define MAX_HASH_BITS (MAX_HASH_SIZE * 8)
+#define MAX_HASH_LIMBS BITS_TO_LIMBS(MAX_HASH_BITS)
+
+#define DSA_COMPUTE_K_ITCH MAX(MAX_Q_LIMBS, MAX_HASH_LIMBS)
+
+int _gnutls_dsa_compute_k(mp_limb_t *h, const mp_limb_t *q, const mp_limb_t *x,
+                         mp_size_t qn, mp_bitcnt_t q_bits,
                          gnutls_mac_algorithm_t mac, const uint8_t *digest,
                          size_t length);
 
+void _gnutls_dsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+                                 mp_size_t n);
+
+void _gnutls_ecdsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+                                   mp_size_t n);
+
 #endif /* GNUTLS_LIB_NETTLE_INT_DSA_COMPUTE_K_H */
index 3b7f886160baa66b5be4f89b408592b48af56534..4e25235c40bdb4970a7a5e1a5adb44f7cad1612a 100644 (file)
 #include "dsa-compute-k.h"
 #include "gnutls_int.h"
 
-static inline int _gnutls_ecc_curve_to_dsa_q(mpz_t *q, gnutls_ecc_curve_t curve)
+int _gnutls_ecc_curve_to_dsa_q(mpz_t q, gnutls_ecc_curve_t curve)
 {
        switch (curve) {
 #ifdef ENABLE_NON_SUITEB_CURVES
        case GNUTLS_ECC_CURVE_SECP192R1:
-               mpz_init_set_str(*q,
+               mpz_init_set_str(q,
                                 "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836"
                                 "146BC9B1B4D22831",
                                 16);
                return 0;
        case GNUTLS_ECC_CURVE_SECP224R1:
-               mpz_init_set_str(*q,
+               mpz_init_set_str(q,
                                 "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2"
                                 "E0B8F03E13DD29455C5C2A3D",
                                 16);
                return 0;
 #endif
        case GNUTLS_ECC_CURVE_SECP256R1:
-               mpz_init_set_str(*q,
+               mpz_init_set_str(q,
                                 "FFFFFFFF00000000FFFFFFFFFFFFFFFF"
                                 "BCE6FAADA7179E84F3B9CAC2FC632551",
                                 16);
                return 0;
        case GNUTLS_ECC_CURVE_SECP384R1:
-               mpz_init_set_str(*q,
+               mpz_init_set_str(q,
                                 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
                                 "FFFFFFFFFFFFFFFFC7634D81F4372DDF"
                                 "581A0DB248B0A77AECEC196ACCC52973",
                                 16);
                return 0;
        case GNUTLS_ECC_CURVE_SECP521R1:
-               mpz_init_set_str(*q,
+               mpz_init_set_str(q,
                                 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
                                 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
                                 "FFA51868783BF2F966B7FCC0148F709A"
@@ -73,19 +73,3 @@ static inline int _gnutls_ecc_curve_to_dsa_q(mpz_t *q, gnutls_ecc_curve_t curve)
                        GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
        }
 }
-
-int _gnutls_ecdsa_compute_k(mpz_t k, gnutls_ecc_curve_t curve, const mpz_t x,
-                           gnutls_mac_algorithm_t mac, const uint8_t *digest,
-                           size_t length)
-{
-       mpz_t q;
-       int ret;
-
-       ret = _gnutls_ecc_curve_to_dsa_q(&q, curve);
-       if (ret < 0)
-               return gnutls_assert_val(ret);
-
-       ret = _gnutls_dsa_compute_k(k, q, x, mac, digest, length);
-       mpz_clear(q);
-       return ret;
-}
index be8beddb5df0a9ec194802ed48f584f8645d4e43..207685763f583c16e68d23c824198ec412a85ea3 100644 (file)
@@ -26,8 +26,6 @@
 #include <gnutls/gnutls.h>
 #include <nettle/bignum.h> /* includes gmp.h */
 
-int _gnutls_ecdsa_compute_k(mpz_t k, gnutls_ecc_curve_t curve, const mpz_t x,
-                           gnutls_mac_algorithm_t mac, const uint8_t *digest,
-                           size_t length);
+int _gnutls_ecc_curve_to_dsa_q(mpz_t q, gnutls_ecc_curve_t curve);
 
 #endif /* GNUTLS_LIB_NETTLE_INT_ECDSA_COMPUTE_K_H */
index 305548f4d1b1be39f97bafebadd42e05d47de296..dd6b9936a8d1a592dea9ca5c693d641a2a8778b0 100644 (file)
@@ -103,10 +103,16 @@ static void rnd_nonce_func(void *_ctx, size_t length, uint8_t *data)
        }
 }
 
-static void rnd_mpz_func(void *_ctx, size_t length, uint8_t *data)
+static void rnd_datum_func(void *ctx, size_t length, uint8_t *data)
 {
-       mpz_t *k = _ctx;
-       nettle_mpz_get_str_256(length, data, *k);
+       gnutls_datum_t *d = ctx;
+
+       if (length > d->size) {
+               memset(data, 0, length - d->size);
+               memcpy(data + (length - d->size), d->data, d->size);
+       } else {
+               memcpy(data, d->data, length);
+       }
 }
 
 static void rnd_nonce_func_fallback(void *_ctx, size_t length, uint8_t *data)
@@ -1403,7 +1409,10 @@ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                struct dsa_signature sig;
                int curve_id = pk_params->curve;
                const struct ecc_curve *curve;
-               mpz_t k;
+               mpz_t q;
+               /* 521-bit elliptic curve generator at maximum */
+               uint8_t buf[(521 + 7) / 8];
+               gnutls_datum_t k = { NULL, 0 };
                void *random_ctx;
                nettle_random_func *random_func;
 
@@ -1447,17 +1456,32 @@ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        not_approved = true;
                }
 
-               mpz_init(k);
+               mpz_init(q);
+
                if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
                    (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
-                       ret = _gnutls_ecdsa_compute_k(
-                               k, curve_id, pk_params->params[ECC_K],
+                       mp_limb_t h[DSA_COMPUTE_K_ITCH];
+
+                       ret = _gnutls_ecc_curve_to_dsa_q(q, curve_id);
+                       if (ret < 0)
+                               goto ecdsa_cleanup;
+
+                       ret = _gnutls_dsa_compute_k(
+                               h, mpz_limbs_read(q), priv.p,
+                               ecc_size(priv.ecc), ecc_bit_size(priv.ecc),
                                DIG_TO_MAC(sign_params->dsa_dig), vdata->data,
                                vdata->size);
                        if (ret < 0)
                                goto ecdsa_cleanup;
+
+                       k.data = buf;
+                       k.size = (ecc_bit_size(priv.ecc) + 7) / 8;
+
+                       _gnutls_ecdsa_compute_k_finish(k.data, k.size, h,
+                                                      ecc_size(priv.ecc));
+
                        random_ctx = &k;
-                       random_func = rnd_mpz_func;
+                       random_func = rnd_datum_func;
                } else {
                        random_ctx = NULL;
                        random_func = rnd_nonce_func;
@@ -1476,7 +1500,7 @@ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
        ecdsa_cleanup:
                dsa_signature_clear(&sig);
                ecc_scalar_zclear(&priv);
-               mpz_clear(k);
+               mpz_clear(q);
 
                if (ret < 0) {
                        gnutls_assert();
@@ -1488,7 +1512,9 @@ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                struct dsa_params pub;
                bigint_t priv;
                struct dsa_signature sig;
-               mpz_t k;
+               /* 512-bit DSA subgroup at maximum */
+               uint8_t buf[(512 + 7) / 8];
+               gnutls_datum_t k = { NULL, 0 };
                void *random_ctx;
                nettle_random_func *random_func;
 
@@ -1515,19 +1541,27 @@ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        hash_len = vdata->size;
                }
 
-               mpz_init(k);
                if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
                    (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
+                       mp_limb_t h[DSA_COMPUTE_K_ITCH];
+
                        ret = _gnutls_dsa_compute_k(
-                               k, pub.q, TOMPZ(priv),
+                               h, mpz_limbs_read(pub.q),
+                               mpz_limbs_read(TOMPZ(priv)), mpz_size(pub.q),
+                               mpz_sizeinbase(pub.q, 2),
                                DIG_TO_MAC(sign_params->dsa_dig), vdata->data,
                                vdata->size);
                        if (ret < 0)
                                goto dsa_fail;
-                       /* cancel-out dsa_sign's addition of 1 to random data */
-                       mpz_sub_ui(k, k, 1);
+
+                       k.data = buf;
+                       k.size = (mpz_sizeinbase(pub.q, 2) + 7) / 8;
+
+                       _gnutls_dsa_compute_k_finish(k.data, k.size, h,
+                                                    mpz_size(pub.q));
+
                        random_ctx = &k;
-                       random_func = rnd_mpz_func;
+                       random_func = rnd_datum_func;
                } else {
                        random_ctx = NULL;
                        random_func = rnd_nonce_func;
@@ -1544,7 +1578,6 @@ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
 
        dsa_fail:
                dsa_signature_clear(&sig);
-               mpz_clear(k);
 
                if (ret < 0) {
                        gnutls_assert();
index 6969b57a11a82709b2352bde49ea4bf492119a98..bdd5a49c7db3cefcc724b70fd5656b93f83cbb69 100644 (file)
@@ -198,7 +198,7 @@ void doit(void)
                                                 &tests[i].msg, &signature);
                if (ret < 0)
                        testfail("gnutls_pubkey_verify_data2\n");
-               success(" - pass");
+               success(" - pass\n");
 
        next:
                gnutls_free(signature.data);