aboutsummaryrefslogtreecommitdiffstats
path: root/main/hostapd/0006-SAE-Use-const_time-selection-for-PWE-in-FFC.patch
blob: f336d5b74a8cb097faeb690ee1e8de88cf2afb37 (plain) (blame)
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
From f8f20717f87eff1f025f48ed585c7684debacf72 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <jouni@codeaurora.org>
Date: Sat, 2 Mar 2019 12:45:33 +0200
Subject: [PATCH] SAE: Use const_time selection for PWE in FFC

This is an initial step towards making the FFC case use strictly
constant time operations similarly to the ECC case.
sae_test_pwd_seed_ffc() does not yet have constant time behavior,
though.

This is related to CVE-2019-9494.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
---
 src/common/sae.c | 53 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 35 insertions(+), 18 deletions(-)

diff --git a/src/common/sae.c b/src/common/sae.c
index 75b1b4a83..fa9a145e3 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -612,17 +612,28 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
 			      const u8 *addr2, const u8 *password,
 			      size_t password_len, const char *identifier)
 {
-	u8 counter, k;
+	u8 counter, k, sel_counter = 0;
 	u8 addrs[2 * ETH_ALEN];
 	const u8 *addr[3];
 	size_t len[3];
 	size_t num_elem;
-	int found = 0;
-	struct crypto_bignum *pwe = NULL;
+	u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+		       * mask */
+	u8 mask;
+	struct crypto_bignum *pwe;
+	size_t prime_len = sae->tmp->prime_len * 8;
+	u8 *pwe_buf;
 
 	crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
 	sae->tmp->pwe_ffc = NULL;
 
+	/* Allocate a buffer to maintain selected and candidate PWE for constant
+	 * time selection. */
+	pwe_buf = os_zalloc(prime_len * 2);
+	pwe = crypto_bignum_init();
+	if (!pwe_buf || !pwe)
+		goto fail;
+
 	wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
 			      password, password_len);
 
@@ -661,27 +672,33 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
 		if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
 				       addr, len, pwd_seed) < 0)
 			break;
-		if (!pwe) {
-			pwe = crypto_bignum_init();
-			if (!pwe)
-				break;
-		}
 		res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
+		/* res is -1 for fatal failure, 0 if a valid PWE was not found,
+		 * or 1 if a valid PWE was found. */
 		if (res < 0)
 			break;
-		if (res > 0) {
-			found = 1;
-			if (!sae->tmp->pwe_ffc) {
-				wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
-				sae->tmp->pwe_ffc = pwe;
-				pwe = NULL;
-			}
-		}
+		/* Store the candidate PWE into the second half of pwe_buf and
+		 * the selected PWE in the beginning of pwe_buf using constant
+		 * time selection. */
+		if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
+					 prime_len) < 0)
+			break;
+		const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
+				      prime_len, pwe_buf);
+		sel_counter = const_time_select_u8(found, sel_counter, counter);
+		mask = const_time_eq_u8(res, 1);
+		found = const_time_select_u8(found, found, mask);
 	}
 
-	crypto_bignum_deinit(pwe, 1);
+	if (!found)
+		goto fail;
 
-	return found ? 0 : -1;
+	wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
+	sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
+fail:
+	crypto_bignum_deinit(pwe, 1);
+	bin_clear_free(pwe_buf, prime_len * 2);
+	return sae->tmp->pwe_ffc ? 0 : -1;
 }
 
 
-- 
2.21.0