c014fc3a5f35901f3ba44276f6503208f88a8d57
[openwrt/staging/blocktrron.git] /
1 From 3c5c9d96cea67a8dc381e6ca0f5a894f1ce099ea Mon Sep 17 00:00:00 2001
2 From: "Jason A. Donenfeld" <Jason@zx2c4.com>
3 Date: Wed, 18 Mar 2020 18:30:47 -0600
4 Subject: [PATCH 094/124] wireguard: noise: error out precomputed DH during
5 handshake rather than config
6
7 commit 11a7686aa99c7fe4b3f80f6dcccd54129817984d upstream.
8
9 We precompute the static-static ECDH during configuration time, in order
10 to save an expensive computation later when receiving network packets.
11 However, not all ECDH computations yield a contributory result. Prior,
12 we were just not letting those peers be added to the interface. However,
13 this creates a strange inconsistency, since it was still possible to add
14 other weird points, like a valid public key plus a low-order point, and,
15 like points that result in zeros, a handshake would not complete. In
16 order to make the behavior more uniform and less surprising, simply
17 allow all peers to be added. Then, we'll error out later when doing the
18 crypto if there's an issue. This also adds more separation between the
19 crypto layer and the configuration layer.
20
21 Discussed-with: Mathias Hall-Andersen <mathias@hall-andersen.dk>
22 Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
23 Signed-off-by: David S. Miller <davem@davemloft.net>
24 Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
25 ---
26 drivers/net/wireguard/netlink.c | 8 +---
27 drivers/net/wireguard/noise.c | 55 ++++++++++++----------
28 drivers/net/wireguard/noise.h | 12 ++---
29 drivers/net/wireguard/peer.c | 7 +--
30 tools/testing/selftests/wireguard/netns.sh | 15 ++++--
31 5 files changed, 49 insertions(+), 48 deletions(-)
32
33 --- a/drivers/net/wireguard/netlink.c
34 +++ b/drivers/net/wireguard/netlink.c
35 @@ -417,11 +417,7 @@ static int set_peer(struct wg_device *wg
36
37 peer = wg_peer_create(wg, public_key, preshared_key);
38 if (IS_ERR(peer)) {
39 - /* Similar to the above, if the key is invalid, we skip
40 - * it without fanfare, so that services don't need to
41 - * worry about doing key validation themselves.
42 - */
43 - ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer);
44 + ret = PTR_ERR(peer);
45 peer = NULL;
46 goto out;
47 }
48 @@ -575,7 +571,7 @@ static int wg_set_device(struct sk_buff
49 private_key);
50 list_for_each_entry_safe(peer, temp, &wg->peer_list,
51 peer_list) {
52 - BUG_ON(!wg_noise_precompute_static_static(peer));
53 + wg_noise_precompute_static_static(peer);
54 wg_noise_expire_current_peer_keypairs(peer);
55 }
56 wg_cookie_checker_precompute_device_keys(&wg->cookie_checker);
57 --- a/drivers/net/wireguard/noise.c
58 +++ b/drivers/net/wireguard/noise.c
59 @@ -44,32 +44,23 @@ void __init wg_noise_init(void)
60 }
61
62 /* Must hold peer->handshake.static_identity->lock */
63 -bool wg_noise_precompute_static_static(struct wg_peer *peer)
64 +void wg_noise_precompute_static_static(struct wg_peer *peer)
65 {
66 - bool ret;
67 -
68 down_write(&peer->handshake.lock);
69 - if (peer->handshake.static_identity->has_identity) {
70 - ret = curve25519(
71 - peer->handshake.precomputed_static_static,
72 + if (!peer->handshake.static_identity->has_identity ||
73 + !curve25519(peer->handshake.precomputed_static_static,
74 peer->handshake.static_identity->static_private,
75 - peer->handshake.remote_static);
76 - } else {
77 - u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 };
78 -
79 - ret = curve25519(empty, empty, peer->handshake.remote_static);
80 + peer->handshake.remote_static))
81 memset(peer->handshake.precomputed_static_static, 0,
82 NOISE_PUBLIC_KEY_LEN);
83 - }
84 up_write(&peer->handshake.lock);
85 - return ret;
86 }
87
88 -bool wg_noise_handshake_init(struct noise_handshake *handshake,
89 - struct noise_static_identity *static_identity,
90 - const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
91 - const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
92 - struct wg_peer *peer)
93 +void wg_noise_handshake_init(struct noise_handshake *handshake,
94 + struct noise_static_identity *static_identity,
95 + const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
96 + const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
97 + struct wg_peer *peer)
98 {
99 memset(handshake, 0, sizeof(*handshake));
100 init_rwsem(&handshake->lock);
101 @@ -81,7 +72,7 @@ bool wg_noise_handshake_init(struct nois
102 NOISE_SYMMETRIC_KEY_LEN);
103 handshake->static_identity = static_identity;
104 handshake->state = HANDSHAKE_ZEROED;
105 - return wg_noise_precompute_static_static(peer);
106 + wg_noise_precompute_static_static(peer);
107 }
108
109 static void handshake_zero(struct noise_handshake *handshake)
110 @@ -403,6 +394,19 @@ static bool __must_check mix_dh(u8 chain
111 return true;
112 }
113
114 +static bool __must_check mix_precomputed_dh(u8 chaining_key[NOISE_HASH_LEN],
115 + u8 key[NOISE_SYMMETRIC_KEY_LEN],
116 + const u8 precomputed[NOISE_PUBLIC_KEY_LEN])
117 +{
118 + static u8 zero_point[NOISE_PUBLIC_KEY_LEN];
119 + if (unlikely(!crypto_memneq(precomputed, zero_point, NOISE_PUBLIC_KEY_LEN)))
120 + return false;
121 + kdf(chaining_key, key, NULL, precomputed, NOISE_HASH_LEN,
122 + NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
123 + chaining_key);
124 + return true;
125 +}
126 +
127 static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len)
128 {
129 struct blake2s_state blake;
130 @@ -531,10 +535,9 @@ wg_noise_handshake_create_initiation(str
131 NOISE_PUBLIC_KEY_LEN, key, handshake->hash);
132
133 /* ss */
134 - kdf(handshake->chaining_key, key, NULL,
135 - handshake->precomputed_static_static, NOISE_HASH_LEN,
136 - NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
137 - handshake->chaining_key);
138 + if (!mix_precomputed_dh(handshake->chaining_key, key,
139 + handshake->precomputed_static_static))
140 + goto out;
141
142 /* {t} */
143 tai64n_now(timestamp);
144 @@ -595,9 +598,9 @@ wg_noise_handshake_consume_initiation(st
145 handshake = &peer->handshake;
146
147 /* ss */
148 - kdf(chaining_key, key, NULL, handshake->precomputed_static_static,
149 - NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
150 - chaining_key);
151 + if (!mix_precomputed_dh(chaining_key, key,
152 + handshake->precomputed_static_static))
153 + goto out;
154
155 /* {t} */
156 if (!message_decrypt(t, src->encrypted_timestamp,
157 --- a/drivers/net/wireguard/noise.h
158 +++ b/drivers/net/wireguard/noise.h
159 @@ -94,11 +94,11 @@ struct noise_handshake {
160 struct wg_device;
161
162 void wg_noise_init(void);
163 -bool wg_noise_handshake_init(struct noise_handshake *handshake,
164 - struct noise_static_identity *static_identity,
165 - const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
166 - const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
167 - struct wg_peer *peer);
168 +void wg_noise_handshake_init(struct noise_handshake *handshake,
169 + struct noise_static_identity *static_identity,
170 + const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
171 + const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
172 + struct wg_peer *peer);
173 void wg_noise_handshake_clear(struct noise_handshake *handshake);
174 static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns)
175 {
176 @@ -116,7 +116,7 @@ void wg_noise_expire_current_peer_keypai
177 void wg_noise_set_static_identity_private_key(
178 struct noise_static_identity *static_identity,
179 const u8 private_key[NOISE_PUBLIC_KEY_LEN]);
180 -bool wg_noise_precompute_static_static(struct wg_peer *peer);
181 +void wg_noise_precompute_static_static(struct wg_peer *peer);
182
183 bool
184 wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
185 --- a/drivers/net/wireguard/peer.c
186 +++ b/drivers/net/wireguard/peer.c
187 @@ -34,11 +34,8 @@ struct wg_peer *wg_peer_create(struct wg
188 return ERR_PTR(ret);
189 peer->device = wg;
190
191 - if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
192 - public_key, preshared_key, peer)) {
193 - ret = -EKEYREJECTED;
194 - goto err_1;
195 - }
196 + wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
197 + public_key, preshared_key, peer);
198 if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
199 goto err_1;
200 if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false,
201 --- a/tools/testing/selftests/wireguard/netns.sh
202 +++ b/tools/testing/selftests/wireguard/netns.sh
203 @@ -527,11 +527,16 @@ n0 wg set wg0 peer "$pub2" allowed-ips 0
204 n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
205 n0 wg set wg0 peer "$pub2" allowed-ips ::/0
206 n0 wg set wg0 peer "$pub2" remove
207 -low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= )
208 -n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer }
209 -[[ -z $(n0 wg show wg0 peers) ]]
210 -n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer }
211 -[[ -z $(n0 wg show wg0 peers) ]]
212 +for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
213 + n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
214 +done
215 +[[ -n $(n0 wg show wg0 peers) ]]
216 +exec 4< <(n0 ncat -l -u -p 1111)
217 +ncat_pid=$!
218 +waitncatudp $netns0 $ncat_pid
219 +ip0 link set wg0 up
220 +! read -r -n 1 -t 2 <&4 || false
221 +kill $ncat_pid
222 ip0 link del wg0
223
224 declare -A objects