summaryrefslogtreecommitdiffstats
path: root/meta/recipes-support/gnutls/gnutls/CVE-2024-28834.patch
blob: 6c06fc2782ff6e5fae693256f7d8108110c526ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
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>

CVE: CVE-2024-28834

Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/1c4701ffc342259fc5965d5a0de90d87f780e3e5]

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
---
 lib/nettle/int/dsa-compute-k.c    | 86 ++++++++++++++++++++-----------
 lib/nettle/int/dsa-compute-k.h    | 32 +++++++++---
 lib/nettle/int/ecdsa-compute-k.c  | 32 +++---------
 lib/nettle/int/ecdsa-compute-k.h  |  8 +--
 lib/nettle/pk.c                   | 78 +++++++++++++++++++---------
 tests/sign-verify-deterministic.c |  2 +-
 6 files changed, 141 insertions(+), 97 deletions(-)

diff --git a/lib/nettle/int/dsa-compute-k.c b/lib/nettle/int/dsa-compute-k.c
index 3f5105a..f937693 100644
--- a/lib/nettle/int/dsa-compute-k.c
+++ b/lib/nettle/int/dsa-compute-k.c
@@ -31,33 +31,39 @@
 #include "mpn-base256.h"
 #include <string.h>

-#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)
-
-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)
+/* 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];
+
+
+	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;
@@ -66,6 +72,7 @@ _gnutls_dsa_compute_k(mpz_t k,
	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);
@@ -73,7 +80,7 @@ _gnutls_dsa_compute_k(mpz_t k,
		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);
@@ -97,12 +104,12 @@ _gnutls_dsa_compute_k(mpz_t k,
			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);

@@ -178,12 +185,8 @@ _gnutls_dsa_compute_k(mpz_t k,
		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)
@@ -207,3 +210,24 @@ _gnutls_dsa_compute_k(mpz_t k,

	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 64e90e0..778c484 100644
--- a/lib/nettle/int/dsa-compute-k.h
+++ b/lib/nettle/int/dsa-compute-k.h
@@ -26,12 +26,30 @@
 #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 */
diff --git a/lib/nettle/int/ecdsa-compute-k.c b/lib/nettle/int/ecdsa-compute-k.c
index 94914eb..fc3b2ba 100644
--- a/lib/nettle/int/ecdsa-compute-k.c
+++ b/lib/nettle/int/ecdsa-compute-k.c
@@ -29,39 +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"
@@ -74,22 +73,3 @@ _gnutls_ecc_curve_to_dsa_q(mpz_t *q, gnutls_ecc_curve_t curve)
	}
 }

-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 7ca401d..a7e612b 100644
--- a/lib/nettle/int/ecdsa-compute-k.h
+++ b/lib/nettle/int/ecdsa-compute-k.h
@@ -26,12 +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 eba246f..799cc9d 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -97,10 +97,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)
@@ -1076,7 +1082,11 @@ _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;

@@ -1123,19 +1133,31 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
				hash_len = vdata->size;
			}

-			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;
@@ -1156,7 +1178,7 @@ _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();
@@ -1169,7 +1191,10 @@ _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;

@@ -1196,21 +1221,25 @@ _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)) {
-				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;
@@ -1230,7 +1259,6 @@ _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 6e90728..25aa553 100644
--- a/tests/sign-verify-deterministic.c
+++ b/tests/sign-verify-deterministic.c
@@ -197,7 +197,7 @@ void doit(void)
					      &signature);
		if (ret < 0)
			testfail("gnutls_pubkey_verify_data2\n");
-		success(" - pass");
+		success(" - pass\n");

	next:
		gnutls_free(signature.data);
--
2.40.0