Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP6:Update
gnutls.36178
gnutls-CVE-2024-28834.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File gnutls-CVE-2024-28834.patch of Package gnutls.36178
From 1c4701ffc342259fc5965d5a0de90d87f780e3e5 Mon Sep 17 00:00:00 2001 From: Daiki Ueno <ueno@gnu.org> Date: Fri, 12 Jan 2024 17:56:58 +0900 Subject: [PATCH] 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 | 70 +++++++++++++++++++++---------- lib/nettle/int/dsa-compute-k.h | 23 +++++++++- lib/nettle/int/ecdsa-compute-k.c | 28 +++---------- lib/nettle/int/ecdsa-compute-k.h | 4 +- lib/nettle/pk.c | 65 +++++++++++++++++++++------- tests/sign-verify-deterministic.c | 2 +- 6 files changed, 127 insertions(+), 65 deletions(-) diff --git a/lib/nettle/int/dsa-compute-k.c b/lib/nettle/int/dsa-compute-k.c index 8ff5739c2b..2fcb2bb80e 100644 --- a/lib/nettle/int/dsa-compute-k.c +++ b/lib/nettle/int/dsa-compute-k.c @@ -31,19 +31,30 @@ #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); +} diff --git a/lib/nettle/int/dsa-compute-k.h b/lib/nettle/int/dsa-compute-k.h index 49d243acb4..2f0667a01e 100644 --- a/lib/nettle/int/dsa-compute-k.h +++ b/lib/nettle/int/dsa-compute-k.h @@ -26,8 +26,29 @@ #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 */ diff --git a/lib/nettle/int/ecdsa-compute-k.c b/lib/nettle/int/ecdsa-compute-k.c index 3b7f886160..4e25235c40 100644 --- a/lib/nettle/int/ecdsa-compute-k.c +++ b/lib/nettle/int/ecdsa-compute-k.c @@ -29,38 +29,38 @@ #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; -} diff --git a/lib/nettle/int/ecdsa-compute-k.h b/lib/nettle/int/ecdsa-compute-k.h index be8beddb5d..207685763f 100644 --- a/lib/nettle/int/ecdsa-compute-k.h +++ b/lib/nettle/int/ecdsa-compute-k.h @@ -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 */ diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index 305548f4d1..dd6b9936a8 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -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(); diff --git a/tests/sign-verify-deterministic.c b/tests/sign-verify-deterministic.c index 6969b57a11..bdd5a49c7d 100644 --- a/tests/sign-verify-deterministic.c +++ b/tests/sign-verify-deterministic.c @@ -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); -- GitLab
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor