xref: /linux/drivers/net/wireguard/cookie.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1e7096c13SJason A. Donenfeld // SPDX-License-Identifier: GPL-2.0
2e7096c13SJason A. Donenfeld /*
3e7096c13SJason A. Donenfeld  * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4e7096c13SJason A. Donenfeld  */
5e7096c13SJason A. Donenfeld 
6e7096c13SJason A. Donenfeld #include "cookie.h"
7e7096c13SJason A. Donenfeld #include "peer.h"
8e7096c13SJason A. Donenfeld #include "device.h"
9e7096c13SJason A. Donenfeld #include "messages.h"
10e7096c13SJason A. Donenfeld #include "ratelimiter.h"
11e7096c13SJason A. Donenfeld #include "timers.h"
12e7096c13SJason A. Donenfeld 
13e7096c13SJason A. Donenfeld #include <crypto/blake2s.h>
14e7096c13SJason A. Donenfeld #include <crypto/chacha20poly1305.h>
15*d90dde8cSHerbert Xu #include <crypto/utils.h>
16e7096c13SJason A. Donenfeld 
17e7096c13SJason A. Donenfeld #include <net/ipv6.h>
18e7096c13SJason A. Donenfeld 
wg_cookie_checker_init(struct cookie_checker * checker,struct wg_device * wg)19e7096c13SJason A. Donenfeld void wg_cookie_checker_init(struct cookie_checker *checker,
20e7096c13SJason A. Donenfeld 			    struct wg_device *wg)
21e7096c13SJason A. Donenfeld {
22e7096c13SJason A. Donenfeld 	init_rwsem(&checker->secret_lock);
23e7096c13SJason A. Donenfeld 	checker->secret_birthdate = ktime_get_coarse_boottime_ns();
24e7096c13SJason A. Donenfeld 	get_random_bytes(checker->secret, NOISE_HASH_LEN);
25e7096c13SJason A. Donenfeld 	checker->device = wg;
26e7096c13SJason A. Donenfeld }
27e7096c13SJason A. Donenfeld 
28e7096c13SJason A. Donenfeld enum { COOKIE_KEY_LABEL_LEN = 8 };
29e7096c13SJason A. Donenfeld static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
30e7096c13SJason A. Donenfeld static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
31e7096c13SJason A. Donenfeld 
precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],const u8 pubkey[NOISE_PUBLIC_KEY_LEN],const u8 label[COOKIE_KEY_LABEL_LEN])32e7096c13SJason A. Donenfeld static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],
33e7096c13SJason A. Donenfeld 			   const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
34e7096c13SJason A. Donenfeld 			   const u8 label[COOKIE_KEY_LABEL_LEN])
35e7096c13SJason A. Donenfeld {
36e7096c13SJason A. Donenfeld 	struct blake2s_state blake;
37e7096c13SJason A. Donenfeld 
38e7096c13SJason A. Donenfeld 	blake2s_init(&blake, NOISE_SYMMETRIC_KEY_LEN);
39e7096c13SJason A. Donenfeld 	blake2s_update(&blake, label, COOKIE_KEY_LABEL_LEN);
40e7096c13SJason A. Donenfeld 	blake2s_update(&blake, pubkey, NOISE_PUBLIC_KEY_LEN);
41e7096c13SJason A. Donenfeld 	blake2s_final(&blake, key);
42e7096c13SJason A. Donenfeld }
43e7096c13SJason A. Donenfeld 
44e7096c13SJason A. Donenfeld /* Must hold peer->handshake.static_identity->lock */
wg_cookie_checker_precompute_device_keys(struct cookie_checker * checker)45e7096c13SJason A. Donenfeld void wg_cookie_checker_precompute_device_keys(struct cookie_checker *checker)
46e7096c13SJason A. Donenfeld {
47e7096c13SJason A. Donenfeld 	if (likely(checker->device->static_identity.has_identity)) {
48e7096c13SJason A. Donenfeld 		precompute_key(checker->cookie_encryption_key,
49e7096c13SJason A. Donenfeld 			       checker->device->static_identity.static_public,
50e7096c13SJason A. Donenfeld 			       cookie_key_label);
51e7096c13SJason A. Donenfeld 		precompute_key(checker->message_mac1_key,
52e7096c13SJason A. Donenfeld 			       checker->device->static_identity.static_public,
53e7096c13SJason A. Donenfeld 			       mac1_key_label);
54e7096c13SJason A. Donenfeld 	} else {
55e7096c13SJason A. Donenfeld 		memset(checker->cookie_encryption_key, 0,
56e7096c13SJason A. Donenfeld 		       NOISE_SYMMETRIC_KEY_LEN);
57e7096c13SJason A. Donenfeld 		memset(checker->message_mac1_key, 0, NOISE_SYMMETRIC_KEY_LEN);
58e7096c13SJason A. Donenfeld 	}
59e7096c13SJason A. Donenfeld }
60e7096c13SJason A. Donenfeld 
wg_cookie_checker_precompute_peer_keys(struct wg_peer * peer)61e7096c13SJason A. Donenfeld void wg_cookie_checker_precompute_peer_keys(struct wg_peer *peer)
62e7096c13SJason A. Donenfeld {
63e7096c13SJason A. Donenfeld 	precompute_key(peer->latest_cookie.cookie_decryption_key,
64e7096c13SJason A. Donenfeld 		       peer->handshake.remote_static, cookie_key_label);
65e7096c13SJason A. Donenfeld 	precompute_key(peer->latest_cookie.message_mac1_key,
66e7096c13SJason A. Donenfeld 		       peer->handshake.remote_static, mac1_key_label);
67e7096c13SJason A. Donenfeld }
68e7096c13SJason A. Donenfeld 
wg_cookie_init(struct cookie * cookie)69e7096c13SJason A. Donenfeld void wg_cookie_init(struct cookie *cookie)
70e7096c13SJason A. Donenfeld {
71e7096c13SJason A. Donenfeld 	memset(cookie, 0, sizeof(*cookie));
72e7096c13SJason A. Donenfeld 	init_rwsem(&cookie->lock);
73e7096c13SJason A. Donenfeld }
74e7096c13SJason A. Donenfeld 
compute_mac1(u8 mac1[COOKIE_LEN],const void * message,size_t len,const u8 key[NOISE_SYMMETRIC_KEY_LEN])75e7096c13SJason A. Donenfeld static void compute_mac1(u8 mac1[COOKIE_LEN], const void *message, size_t len,
76e7096c13SJason A. Donenfeld 			 const u8 key[NOISE_SYMMETRIC_KEY_LEN])
77e7096c13SJason A. Donenfeld {
78e7096c13SJason A. Donenfeld 	len = len - sizeof(struct message_macs) +
79e7096c13SJason A. Donenfeld 	      offsetof(struct message_macs, mac1);
80e7096c13SJason A. Donenfeld 	blake2s(mac1, message, key, COOKIE_LEN, len, NOISE_SYMMETRIC_KEY_LEN);
81e7096c13SJason A. Donenfeld }
82e7096c13SJason A. Donenfeld 
compute_mac2(u8 mac2[COOKIE_LEN],const void * message,size_t len,const u8 cookie[COOKIE_LEN])83e7096c13SJason A. Donenfeld static void compute_mac2(u8 mac2[COOKIE_LEN], const void *message, size_t len,
84e7096c13SJason A. Donenfeld 			 const u8 cookie[COOKIE_LEN])
85e7096c13SJason A. Donenfeld {
86e7096c13SJason A. Donenfeld 	len = len - sizeof(struct message_macs) +
87e7096c13SJason A. Donenfeld 	      offsetof(struct message_macs, mac2);
88e7096c13SJason A. Donenfeld 	blake2s(mac2, message, cookie, COOKIE_LEN, len, COOKIE_LEN);
89e7096c13SJason A. Donenfeld }
90e7096c13SJason A. Donenfeld 
make_cookie(u8 cookie[COOKIE_LEN],struct sk_buff * skb,struct cookie_checker * checker)91e7096c13SJason A. Donenfeld static void make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb,
92e7096c13SJason A. Donenfeld 			struct cookie_checker *checker)
93e7096c13SJason A. Donenfeld {
94e7096c13SJason A. Donenfeld 	struct blake2s_state state;
95e7096c13SJason A. Donenfeld 
96e7096c13SJason A. Donenfeld 	if (wg_birthdate_has_expired(checker->secret_birthdate,
97e7096c13SJason A. Donenfeld 				     COOKIE_SECRET_MAX_AGE)) {
98e7096c13SJason A. Donenfeld 		down_write(&checker->secret_lock);
99e7096c13SJason A. Donenfeld 		checker->secret_birthdate = ktime_get_coarse_boottime_ns();
100e7096c13SJason A. Donenfeld 		get_random_bytes(checker->secret, NOISE_HASH_LEN);
101e7096c13SJason A. Donenfeld 		up_write(&checker->secret_lock);
102e7096c13SJason A. Donenfeld 	}
103e7096c13SJason A. Donenfeld 
104e7096c13SJason A. Donenfeld 	down_read(&checker->secret_lock);
105e7096c13SJason A. Donenfeld 
106e7096c13SJason A. Donenfeld 	blake2s_init_key(&state, COOKIE_LEN, checker->secret, NOISE_HASH_LEN);
107e7096c13SJason A. Donenfeld 	if (skb->protocol == htons(ETH_P_IP))
108e7096c13SJason A. Donenfeld 		blake2s_update(&state, (u8 *)&ip_hdr(skb)->saddr,
109e7096c13SJason A. Donenfeld 			       sizeof(struct in_addr));
110e7096c13SJason A. Donenfeld 	else if (skb->protocol == htons(ETH_P_IPV6))
111e7096c13SJason A. Donenfeld 		blake2s_update(&state, (u8 *)&ipv6_hdr(skb)->saddr,
112e7096c13SJason A. Donenfeld 			       sizeof(struct in6_addr));
113e7096c13SJason A. Donenfeld 	blake2s_update(&state, (u8 *)&udp_hdr(skb)->source, sizeof(__be16));
114e7096c13SJason A. Donenfeld 	blake2s_final(&state, cookie);
115e7096c13SJason A. Donenfeld 
116e7096c13SJason A. Donenfeld 	up_read(&checker->secret_lock);
117e7096c13SJason A. Donenfeld }
118e7096c13SJason A. Donenfeld 
wg_cookie_validate_packet(struct cookie_checker * checker,struct sk_buff * skb,bool check_cookie)119e7096c13SJason A. Donenfeld enum cookie_mac_state wg_cookie_validate_packet(struct cookie_checker *checker,
120e7096c13SJason A. Donenfeld 						struct sk_buff *skb,
121e7096c13SJason A. Donenfeld 						bool check_cookie)
122e7096c13SJason A. Donenfeld {
123e7096c13SJason A. Donenfeld 	struct message_macs *macs = (struct message_macs *)
124e7096c13SJason A. Donenfeld 		(skb->data + skb->len - sizeof(*macs));
125e7096c13SJason A. Donenfeld 	enum cookie_mac_state ret;
126e7096c13SJason A. Donenfeld 	u8 computed_mac[COOKIE_LEN];
127e7096c13SJason A. Donenfeld 	u8 cookie[COOKIE_LEN];
128e7096c13SJason A. Donenfeld 
129e7096c13SJason A. Donenfeld 	ret = INVALID_MAC;
130e7096c13SJason A. Donenfeld 	compute_mac1(computed_mac, skb->data, skb->len,
131e7096c13SJason A. Donenfeld 		     checker->message_mac1_key);
132e7096c13SJason A. Donenfeld 	if (crypto_memneq(computed_mac, macs->mac1, COOKIE_LEN))
133e7096c13SJason A. Donenfeld 		goto out;
134e7096c13SJason A. Donenfeld 
135e7096c13SJason A. Donenfeld 	ret = VALID_MAC_BUT_NO_COOKIE;
136e7096c13SJason A. Donenfeld 
137e7096c13SJason A. Donenfeld 	if (!check_cookie)
138e7096c13SJason A. Donenfeld 		goto out;
139e7096c13SJason A. Donenfeld 
140e7096c13SJason A. Donenfeld 	make_cookie(cookie, skb, checker);
141e7096c13SJason A. Donenfeld 
142e7096c13SJason A. Donenfeld 	compute_mac2(computed_mac, skb->data, skb->len, cookie);
143e7096c13SJason A. Donenfeld 	if (crypto_memneq(computed_mac, macs->mac2, COOKIE_LEN))
144e7096c13SJason A. Donenfeld 		goto out;
145e7096c13SJason A. Donenfeld 
146e7096c13SJason A. Donenfeld 	ret = VALID_MAC_WITH_COOKIE_BUT_RATELIMITED;
147e7096c13SJason A. Donenfeld 	if (!wg_ratelimiter_allow(skb, dev_net(checker->device->dev)))
148e7096c13SJason A. Donenfeld 		goto out;
149e7096c13SJason A. Donenfeld 
150e7096c13SJason A. Donenfeld 	ret = VALID_MAC_WITH_COOKIE;
151e7096c13SJason A. Donenfeld 
152e7096c13SJason A. Donenfeld out:
153e7096c13SJason A. Donenfeld 	return ret;
154e7096c13SJason A. Donenfeld }
155e7096c13SJason A. Donenfeld 
wg_cookie_add_mac_to_packet(void * message,size_t len,struct wg_peer * peer)156e7096c13SJason A. Donenfeld void wg_cookie_add_mac_to_packet(void *message, size_t len,
157e7096c13SJason A. Donenfeld 				 struct wg_peer *peer)
158e7096c13SJason A. Donenfeld {
159e7096c13SJason A. Donenfeld 	struct message_macs *macs = (struct message_macs *)
160e7096c13SJason A. Donenfeld 		((u8 *)message + len - sizeof(*macs));
161e7096c13SJason A. Donenfeld 
162e7096c13SJason A. Donenfeld 	down_write(&peer->latest_cookie.lock);
163e7096c13SJason A. Donenfeld 	compute_mac1(macs->mac1, message, len,
164e7096c13SJason A. Donenfeld 		     peer->latest_cookie.message_mac1_key);
165e7096c13SJason A. Donenfeld 	memcpy(peer->latest_cookie.last_mac1_sent, macs->mac1, COOKIE_LEN);
166e7096c13SJason A. Donenfeld 	peer->latest_cookie.have_sent_mac1 = true;
167e7096c13SJason A. Donenfeld 	up_write(&peer->latest_cookie.lock);
168e7096c13SJason A. Donenfeld 
169e7096c13SJason A. Donenfeld 	down_read(&peer->latest_cookie.lock);
170e7096c13SJason A. Donenfeld 	if (peer->latest_cookie.is_valid &&
171e7096c13SJason A. Donenfeld 	    !wg_birthdate_has_expired(peer->latest_cookie.birthdate,
172e7096c13SJason A. Donenfeld 				COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY))
173e7096c13SJason A. Donenfeld 		compute_mac2(macs->mac2, message, len,
174e7096c13SJason A. Donenfeld 			     peer->latest_cookie.cookie);
175e7096c13SJason A. Donenfeld 	else
176e7096c13SJason A. Donenfeld 		memset(macs->mac2, 0, COOKIE_LEN);
177e7096c13SJason A. Donenfeld 	up_read(&peer->latest_cookie.lock);
178e7096c13SJason A. Donenfeld }
179e7096c13SJason A. Donenfeld 
wg_cookie_message_create(struct message_handshake_cookie * dst,struct sk_buff * skb,__le32 index,struct cookie_checker * checker)180e7096c13SJason A. Donenfeld void wg_cookie_message_create(struct message_handshake_cookie *dst,
181e7096c13SJason A. Donenfeld 			      struct sk_buff *skb, __le32 index,
182e7096c13SJason A. Donenfeld 			      struct cookie_checker *checker)
183e7096c13SJason A. Donenfeld {
184e7096c13SJason A. Donenfeld 	struct message_macs *macs = (struct message_macs *)
185e7096c13SJason A. Donenfeld 		((u8 *)skb->data + skb->len - sizeof(*macs));
186e7096c13SJason A. Donenfeld 	u8 cookie[COOKIE_LEN];
187e7096c13SJason A. Donenfeld 
188e7096c13SJason A. Donenfeld 	dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE);
189e7096c13SJason A. Donenfeld 	dst->receiver_index = index;
190e7096c13SJason A. Donenfeld 	get_random_bytes_wait(dst->nonce, COOKIE_NONCE_LEN);
191e7096c13SJason A. Donenfeld 
192e7096c13SJason A. Donenfeld 	make_cookie(cookie, skb, checker);
193e7096c13SJason A. Donenfeld 	xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN,
194e7096c13SJason A. Donenfeld 				  macs->mac1, COOKIE_LEN, dst->nonce,
195e7096c13SJason A. Donenfeld 				  checker->cookie_encryption_key);
196e7096c13SJason A. Donenfeld }
197e7096c13SJason A. Donenfeld 
wg_cookie_message_consume(struct message_handshake_cookie * src,struct wg_device * wg)198e7096c13SJason A. Donenfeld void wg_cookie_message_consume(struct message_handshake_cookie *src,
199e7096c13SJason A. Donenfeld 			       struct wg_device *wg)
200e7096c13SJason A. Donenfeld {
201e7096c13SJason A. Donenfeld 	struct wg_peer *peer = NULL;
202e7096c13SJason A. Donenfeld 	u8 cookie[COOKIE_LEN];
203e7096c13SJason A. Donenfeld 	bool ret;
204e7096c13SJason A. Donenfeld 
205e7096c13SJason A. Donenfeld 	if (unlikely(!wg_index_hashtable_lookup(wg->index_hashtable,
206e7096c13SJason A. Donenfeld 						INDEX_HASHTABLE_HANDSHAKE |
207e7096c13SJason A. Donenfeld 						INDEX_HASHTABLE_KEYPAIR,
208e7096c13SJason A. Donenfeld 						src->receiver_index, &peer)))
209e7096c13SJason A. Donenfeld 		return;
210e7096c13SJason A. Donenfeld 
211e7096c13SJason A. Donenfeld 	down_read(&peer->latest_cookie.lock);
212e7096c13SJason A. Donenfeld 	if (unlikely(!peer->latest_cookie.have_sent_mac1)) {
213e7096c13SJason A. Donenfeld 		up_read(&peer->latest_cookie.lock);
214e7096c13SJason A. Donenfeld 		goto out;
215e7096c13SJason A. Donenfeld 	}
216e7096c13SJason A. Donenfeld 	ret = xchacha20poly1305_decrypt(
217e7096c13SJason A. Donenfeld 		cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie),
218e7096c13SJason A. Donenfeld 		peer->latest_cookie.last_mac1_sent, COOKIE_LEN, src->nonce,
219e7096c13SJason A. Donenfeld 		peer->latest_cookie.cookie_decryption_key);
220e7096c13SJason A. Donenfeld 	up_read(&peer->latest_cookie.lock);
221e7096c13SJason A. Donenfeld 
222e7096c13SJason A. Donenfeld 	if (ret) {
223e7096c13SJason A. Donenfeld 		down_write(&peer->latest_cookie.lock);
224e7096c13SJason A. Donenfeld 		memcpy(peer->latest_cookie.cookie, cookie, COOKIE_LEN);
225e7096c13SJason A. Donenfeld 		peer->latest_cookie.birthdate = ktime_get_coarse_boottime_ns();
226e7096c13SJason A. Donenfeld 		peer->latest_cookie.is_valid = true;
227e7096c13SJason A. Donenfeld 		peer->latest_cookie.have_sent_mac1 = false;
228e7096c13SJason A. Donenfeld 		up_write(&peer->latest_cookie.lock);
229e7096c13SJason A. Donenfeld 	} else {
230e7096c13SJason A. Donenfeld 		net_dbg_ratelimited("%s: Could not decrypt invalid cookie response\n",
231e7096c13SJason A. Donenfeld 				    wg->dev->name);
232e7096c13SJason A. Donenfeld 	}
233e7096c13SJason A. Donenfeld 
234e7096c13SJason A. Donenfeld out:
235e7096c13SJason A. Donenfeld 	wg_peer_put(peer);
236e7096c13SJason A. Donenfeld }
237