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