aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-5.4/080-wireguard-0095-wireguard-noise-error-out-precomputed-DH-during-hand.patch
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2021-03-02 09:24:45 +0100
committerPetr Štetiar <ynezz@true.cz>2021-03-02 09:30:22 +0100
commitd54072587146dd0db9bb52b513234d944edabda3 (patch)
treead10796da858d6956e8937950cf525498df26025 /target/linux/generic/backport-5.4/080-wireguard-0095-wireguard-noise-error-out-precomputed-DH-during-hand.patch
parentb0376462c164344d6be9fe1568a9f13ffd8fbb16 (diff)
downloadupstream-d54072587146dd0db9bb52b513234d944edabda3.tar.gz
upstream-d54072587146dd0db9bb52b513234d944edabda3.tar.bz2
upstream-d54072587146dd0db9bb52b513234d944edabda3.zip
kernel-5.4: backport fd16931a2f51 for chacha neon
Without this patch, the chacha block counter is not incremented on neon rounds, resulting in incorrect calculations and corrupt packets. This also switches to using `--no-numbered --zero-commit` so that future diffs are smaller. Reported-by: Hans Geiblinger <cybrnook2002@yahoo.com> Reviewed-by: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com> Cc: David Bauer <mail@david-bauer.net> Cc: Petr Štetiar <ynezz@true.cz> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'target/linux/generic/backport-5.4/080-wireguard-0095-wireguard-noise-error-out-precomputed-DH-during-hand.patch')
-rw-r--r--target/linux/generic/backport-5.4/080-wireguard-0095-wireguard-noise-error-out-precomputed-DH-during-hand.patch224
1 files changed, 224 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.4/080-wireguard-0095-wireguard-noise-error-out-precomputed-DH-during-hand.patch b/target/linux/generic/backport-5.4/080-wireguard-0095-wireguard-noise-error-out-precomputed-DH-during-hand.patch
new file mode 100644
index 0000000000..dac3046e47
--- /dev/null
+++ b/target/linux/generic/backport-5.4/080-wireguard-0095-wireguard-noise-error-out-precomputed-DH-during-hand.patch
@@ -0,0 +1,224 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 18 Mar 2020 18:30:47 -0600
+Subject: [PATCH] wireguard: noise: error out precomputed DH during handshake
+ rather than config
+
+commit 11a7686aa99c7fe4b3f80f6dcccd54129817984d upstream.
+
+We precompute the static-static ECDH during configuration time, in order
+to save an expensive computation later when receiving network packets.
+However, not all ECDH computations yield a contributory result. Prior,
+we were just not letting those peers be added to the interface. However,
+this creates a strange inconsistency, since it was still possible to add
+other weird points, like a valid public key plus a low-order point, and,
+like points that result in zeros, a handshake would not complete. In
+order to make the behavior more uniform and less surprising, simply
+allow all peers to be added. Then, we'll error out later when doing the
+crypto if there's an issue. This also adds more separation between the
+crypto layer and the configuration layer.
+
+Discussed-with: Mathias Hall-Andersen <mathias@hall-andersen.dk>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/netlink.c | 8 +---
+ drivers/net/wireguard/noise.c | 55 ++++++++++++----------
+ drivers/net/wireguard/noise.h | 12 ++---
+ drivers/net/wireguard/peer.c | 7 +--
+ tools/testing/selftests/wireguard/netns.sh | 15 ++++--
+ 5 files changed, 49 insertions(+), 48 deletions(-)
+
+--- a/drivers/net/wireguard/netlink.c
++++ b/drivers/net/wireguard/netlink.c
+@@ -417,11 +417,7 @@ static int set_peer(struct wg_device *wg
+
+ peer = wg_peer_create(wg, public_key, preshared_key);
+ if (IS_ERR(peer)) {
+- /* Similar to the above, if the key is invalid, we skip
+- * it without fanfare, so that services don't need to
+- * worry about doing key validation themselves.
+- */
+- ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer);
++ ret = PTR_ERR(peer);
+ peer = NULL;
+ goto out;
+ }
+@@ -575,7 +571,7 @@ static int wg_set_device(struct sk_buff
+ private_key);
+ list_for_each_entry_safe(peer, temp, &wg->peer_list,
+ peer_list) {
+- BUG_ON(!wg_noise_precompute_static_static(peer));
++ wg_noise_precompute_static_static(peer);
+ wg_noise_expire_current_peer_keypairs(peer);
+ }
+ wg_cookie_checker_precompute_device_keys(&wg->cookie_checker);
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -44,32 +44,23 @@ void __init wg_noise_init(void)
+ }
+
+ /* Must hold peer->handshake.static_identity->lock */
+-bool wg_noise_precompute_static_static(struct wg_peer *peer)
++void wg_noise_precompute_static_static(struct wg_peer *peer)
+ {
+- bool ret;
+-
+ down_write(&peer->handshake.lock);
+- if (peer->handshake.static_identity->has_identity) {
+- ret = curve25519(
+- peer->handshake.precomputed_static_static,
++ if (!peer->handshake.static_identity->has_identity ||
++ !curve25519(peer->handshake.precomputed_static_static,
+ peer->handshake.static_identity->static_private,
+- peer->handshake.remote_static);
+- } else {
+- u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 };
+-
+- ret = curve25519(empty, empty, peer->handshake.remote_static);
++ peer->handshake.remote_static))
+ memset(peer->handshake.precomputed_static_static, 0,
+ NOISE_PUBLIC_KEY_LEN);
+- }
+ up_write(&peer->handshake.lock);
+- return ret;
+ }
+
+-bool wg_noise_handshake_init(struct noise_handshake *handshake,
+- struct noise_static_identity *static_identity,
+- const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
+- const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
+- struct wg_peer *peer)
++void wg_noise_handshake_init(struct noise_handshake *handshake,
++ struct noise_static_identity *static_identity,
++ const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
++ const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
++ struct wg_peer *peer)
+ {
+ memset(handshake, 0, sizeof(*handshake));
+ init_rwsem(&handshake->lock);
+@@ -81,7 +72,7 @@ bool wg_noise_handshake_init(struct nois
+ NOISE_SYMMETRIC_KEY_LEN);
+ handshake->static_identity = static_identity;
+ handshake->state = HANDSHAKE_ZEROED;
+- return wg_noise_precompute_static_static(peer);
++ wg_noise_precompute_static_static(peer);
+ }
+
+ static void handshake_zero(struct noise_handshake *handshake)
+@@ -403,6 +394,19 @@ static bool __must_check mix_dh(u8 chain
+ return true;
+ }
+
++static bool __must_check mix_precomputed_dh(u8 chaining_key[NOISE_HASH_LEN],
++ u8 key[NOISE_SYMMETRIC_KEY_LEN],
++ const u8 precomputed[NOISE_PUBLIC_KEY_LEN])
++{
++ static u8 zero_point[NOISE_PUBLIC_KEY_LEN];
++ if (unlikely(!crypto_memneq(precomputed, zero_point, NOISE_PUBLIC_KEY_LEN)))
++ return false;
++ kdf(chaining_key, key, NULL, precomputed, NOISE_HASH_LEN,
++ NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
++ chaining_key);
++ return true;
++}
++
+ static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len)
+ {
+ struct blake2s_state blake;
+@@ -531,10 +535,9 @@ wg_noise_handshake_create_initiation(str
+ NOISE_PUBLIC_KEY_LEN, key, handshake->hash);
+
+ /* ss */
+- kdf(handshake->chaining_key, key, NULL,
+- handshake->precomputed_static_static, NOISE_HASH_LEN,
+- NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
+- handshake->chaining_key);
++ if (!mix_precomputed_dh(handshake->chaining_key, key,
++ handshake->precomputed_static_static))
++ goto out;
+
+ /* {t} */
+ tai64n_now(timestamp);
+@@ -595,9 +598,9 @@ wg_noise_handshake_consume_initiation(st
+ handshake = &peer->handshake;
+
+ /* ss */
+- kdf(chaining_key, key, NULL, handshake->precomputed_static_static,
+- NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
+- chaining_key);
++ if (!mix_precomputed_dh(chaining_key, key,
++ handshake->precomputed_static_static))
++ goto out;
+
+ /* {t} */
+ if (!message_decrypt(t, src->encrypted_timestamp,
+--- a/drivers/net/wireguard/noise.h
++++ b/drivers/net/wireguard/noise.h
+@@ -94,11 +94,11 @@ struct noise_handshake {
+ struct wg_device;
+
+ void wg_noise_init(void);
+-bool wg_noise_handshake_init(struct noise_handshake *handshake,
+- struct noise_static_identity *static_identity,
+- const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
+- const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
+- struct wg_peer *peer);
++void wg_noise_handshake_init(struct noise_handshake *handshake,
++ struct noise_static_identity *static_identity,
++ const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
++ const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
++ struct wg_peer *peer);
+ void wg_noise_handshake_clear(struct noise_handshake *handshake);
+ static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns)
+ {
+@@ -116,7 +116,7 @@ void wg_noise_expire_current_peer_keypai
+ void wg_noise_set_static_identity_private_key(
+ struct noise_static_identity *static_identity,
+ const u8 private_key[NOISE_PUBLIC_KEY_LEN]);
+-bool wg_noise_precompute_static_static(struct wg_peer *peer);
++void wg_noise_precompute_static_static(struct wg_peer *peer);
+
+ bool
+ wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
+--- a/drivers/net/wireguard/peer.c
++++ b/drivers/net/wireguard/peer.c
+@@ -34,11 +34,8 @@ struct wg_peer *wg_peer_create(struct wg
+ return ERR_PTR(ret);
+ peer->device = wg;
+
+- if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
+- public_key, preshared_key, peer)) {
+- ret = -EKEYREJECTED;
+- goto err_1;
+- }
++ wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
++ public_key, preshared_key, peer);
+ if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
+ goto err_1;
+ if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false,
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -527,11 +527,16 @@ n0 wg set wg0 peer "$pub2" allowed-ips 0
+ n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
+ n0 wg set wg0 peer "$pub2" allowed-ips ::/0
+ n0 wg set wg0 peer "$pub2" remove
+-low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= )
+-n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer }
+-[[ -z $(n0 wg show wg0 peers) ]]
+-n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer }
+-[[ -z $(n0 wg show wg0 peers) ]]
++for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
++ n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
++done
++[[ -n $(n0 wg show wg0 peers) ]]
++exec 4< <(n0 ncat -l -u -p 1111)
++ncat_pid=$!
++waitncatudp $netns0 $ncat_pid
++ip0 link set wg0 up
++! read -r -n 1 -t 2 <&4 || false
++kill $ncat_pid
+ ip0 link del wg0
+
+ declare -A objects