summaryrefslogtreecommitdiffstats
path: root/debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch')
-rw-r--r--debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch493
1 files changed, 493 insertions, 0 deletions
diff --git a/debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch b/debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch
new file mode 100644
index 0000000..71a751d
--- /dev/null
+++ b/debian/patches/63_02-nettle-avoid-normalization-of-mpz_t-in-deterministic.patch
@@ -0,0 +1,493 @@
+From 6f6c8db008e943967a5d0f706e2884c23baa0aa7 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Fri, 12 Jan 2024 17:56:58 +0900
+Subject: [PATCH 2/5] nettle: avoid normalization of mpz_t in deterministic
+ ECDSA
+
+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 | 84 +++++++++++++++++++------------
+ lib/nettle/int/dsa-compute-k.h | 31 +++++++++---
+ lib/nettle/int/ecdsa-compute-k.c | 33 +++---------
+ lib/nettle/int/ecdsa-compute-k.h | 8 +--
+ lib/nettle/pk.c | 79 ++++++++++++++++++++---------
+ tests/sign-verify-deterministic.c | 2 +-
+ 6 files changed, 139 insertions(+), 98 deletions(-)
+
+--- a/lib/nettle/int/dsa-compute-k.c
++++ b/lib/nettle/int/dsa-compute-k.c
+@@ -29,53 +29,58 @@
+ #include "gnutls_int.h"
+ #include "mem.h"
+ #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
++
++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;
++
++ for (i = 0, w = 0; i < n; i++)
++ w |= ap[i];
+
+-/* 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)
+-
+-int
+-_gnutls_dsa_compute_k(mpz_t k,
+- const mpz_t q,
+- const mpz_t x,
+- gnutls_mac_algorithm_t mac,
+- const uint8_t *digest,
+- size_t length)
++ 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)
+ {
+ uint8_t V[MAX_HASH_SIZE];
+ 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;
+ const uint8_t c0 = 0x00;
+ const uint8_t c1 = 0x01;
+ 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);
+ if (unlikely(length > MAX_HASH_SIZE))
+ 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);
+
+ if (hn < qn)
+@@ -95,16 +100,16 @@ _gnutls_dsa_compute_k(mpz_t k,
+
+ if (shift % GMP_NUMB_BITS > 0)
+ 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);
+
+ /* Step b */
+ memset(V, c1, length);
+@@ -176,16 +181,12 @@ _gnutls_dsa_compute_k(mpz_t k,
+ /* Step 3 */
+ mpn_set_base256 (h, qn, tp, tlen);
+ 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)
+ goto out;
+ ret = gnutls_hmac(hd, V, length);
+@@ -205,5 +206,26 @@ _gnutls_dsa_compute_k(mpz_t k,
+ zeroize_key(xp, sizeof(xp));
+ zeroize_key(tp, sizeof(tp));
+
+ 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);
++}
+--- a/lib/nettle/int/dsa-compute-k.h
++++ b/lib/nettle/int/dsa-compute-k.h
+@@ -24,14 +24,31 @@
+ #define GNUTLS_LIB_NETTLE_INT_DSA_COMPUTE_K_H
+
+ #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,
+- gnutls_mac_algorithm_t mac,
+- const uint8_t *digest,
+- size_t length);
++#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 */
+--- a/lib/nettle/int/ecdsa-compute-k.c
++++ b/lib/nettle/int/ecdsa-compute-k.c
+@@ -27,43 +27,42 @@
+ #include "ecdsa-compute-k.h"
+
+ #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"
+ "5D03BB5C9B8899C47AEBB6FB71E91386"
+ "409",
+@@ -71,25 +70,5 @@ _gnutls_ecc_curve_to_dsa_q(mpz_t *q, gnu
+ return 0;
+ default:
+ return gnutls_assert_val(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;
+-}
+--- a/lib/nettle/int/ecdsa-compute-k.h
++++ b/lib/nettle/int/ecdsa-compute-k.h
+@@ -24,14 +24,8 @@
+ #define GNUTLS_LIB_NETTLE_INT_ECDSA_COMPUTE_K_H
+
+ #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 */
+--- a/lib/nettle/pk.c
++++ b/lib/nettle/pk.c
+@@ -95,14 +95,20 @@ static void rnd_nonce_func(void *_ctx, s
+ if (gnutls_rnd(GNUTLS_RND_NONCE, data, length) < 0) {
+ _gnutls_switch_lib_state(LIB_STATE_ERROR);
+ }
+ }
+
+-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)
+ {
+ if (unlikely(_gnutls_get_lib_state() != LIB_STATE_SELFTEST)) {
+@@ -1074,11 +1080,14 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ {
+ struct ecc_scalar priv;
+ 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;
+
+ curve = get_supported_nist_curve(curve_id);
+ if (curve == NULL) {
+@@ -1121,23 +1130,36 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ break;
+ default:
+ 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],
+- DIG_TO_MAC(sign_params->dsa_dig),
+- vdata->data,
+- vdata->size);
++ 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;
+ }
+ ecdsa_sign(&priv, random_ctx, random_func, hash_len,
+@@ -1154,11 +1176,11 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ &sig.s);
+
+ ecdsa_cleanup:
+ dsa_signature_clear(&sig);
+ ecc_scalar_zclear(&priv);
+- mpz_clear(k);
++ mpz_clear(q);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+@@ -1167,11 +1189,13 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ case GNUTLS_PK_DSA:
+ {
+ 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;
+
+ /* DSA is currently being defined as sunset with the
+ * current draft of FIPS 186-5 */
+@@ -1194,25 +1218,31 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ ("Security level of algorithm requires hash %s(%d) or better (have: %d)\n",
+ _gnutls_mac_get_name(me), hash_len, (int)vdata->size);
+ hash_len = vdata->size;
+ }
+
+- mpz_init(k);
+ if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
+ (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
+- ret = _gnutls_dsa_compute_k(k,
+- pub.q,
+- TOMPZ(priv),
+- DIG_TO_MAC(sign_params->dsa_dig),
+- vdata->data,
+- vdata->size);
++ mp_limb_t h[DSA_COMPUTE_K_ITCH];
++
++ ret = _gnutls_dsa_compute_k(
++ 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;
+ }
+ ret =
+@@ -1228,11 +1258,10 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm
+ _gnutls_encode_ber_rs(signature, &sig.r,
+ &sig.s);
+
+ dsa_fail:
+ dsa_signature_clear(&sig);
+- mpz_clear(k);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+--- a/tests/sign-verify-deterministic.c
++++ b/tests/sign-verify-deterministic.c
+@@ -195,11 +195,11 @@ void doit(void)
+ ret =
+ gnutls_pubkey_verify_data2(pubkey, tests[i].sigalgo, 0, &tests[i].msg,
+ &signature);
+ if (ret < 0)
+ testfail("gnutls_pubkey_verify_data2\n");
+- success(" - pass");
++ success(" - pass\n");
+
+ next:
+ gnutls_free(signature.data);
+ gnutls_privkey_deinit(privkey);
+ gnutls_pubkey_deinit(pubkey);