123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2015-2019 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
- */
- #include "cookie.h"
- #include "peer.h"
- #include "device.h"
- #include "messages.h"
- #include "ratelimiter.h"
- #include "timers.h"
- #include <crypto/blake2s.h>
- #include <crypto/chacha20poly1305.h>
- #include <net/ipv6.h>
- #include <crypto/algapi.h>
- void wg_cookie_checker_init(struct cookie_checker *checker,
- struct wg_device *wg)
- {
- init_rwsem(&checker->secret_lock);
- checker->secret_birthdate = ktime_get_coarse_boottime_ns();
- get_random_bytes(checker->secret, NOISE_HASH_LEN);
- checker->device = wg;
- }
- enum { COOKIE_KEY_LABEL_LEN = 8 };
- static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
- static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
- static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],
- const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
- const u8 label[COOKIE_KEY_LABEL_LEN])
- {
- struct blake2s_state blake;
- blake2s_init(&blake, NOISE_SYMMETRIC_KEY_LEN);
- blake2s_update(&blake, label, COOKIE_KEY_LABEL_LEN);
- blake2s_update(&blake, pubkey, NOISE_PUBLIC_KEY_LEN);
- blake2s_final(&blake, key);
- }
- /* Must hold peer->handshake.static_identity->lock */
- void wg_cookie_checker_precompute_device_keys(struct cookie_checker *checker)
- {
- if (likely(checker->device->static_identity.has_identity)) {
- precompute_key(checker->cookie_encryption_key,
- checker->device->static_identity.static_public,
- cookie_key_label);
- precompute_key(checker->message_mac1_key,
- checker->device->static_identity.static_public,
- mac1_key_label);
- } else {
- memset(checker->cookie_encryption_key, 0,
- NOISE_SYMMETRIC_KEY_LEN);
- memset(checker->message_mac1_key, 0, NOISE_SYMMETRIC_KEY_LEN);
- }
- }
- void wg_cookie_checker_precompute_peer_keys(struct wg_peer *peer)
- {
- precompute_key(peer->latest_cookie.cookie_decryption_key,
- peer->handshake.remote_static, cookie_key_label);
- precompute_key(peer->latest_cookie.message_mac1_key,
- peer->handshake.remote_static, mac1_key_label);
- }
- void wg_cookie_init(struct cookie *cookie)
- {
- memset(cookie, 0, sizeof(*cookie));
- init_rwsem(&cookie->lock);
- }
- static void compute_mac1(u8 mac1[COOKIE_LEN], const void *message, size_t len,
- const u8 key[NOISE_SYMMETRIC_KEY_LEN])
- {
- len = len - sizeof(struct message_macs) +
- offsetof(struct message_macs, mac1);
- blake2s(mac1, message, key, COOKIE_LEN, len, NOISE_SYMMETRIC_KEY_LEN);
- }
- static void compute_mac2(u8 mac2[COOKIE_LEN], const void *message, size_t len,
- const u8 cookie[COOKIE_LEN])
- {
- len = len - sizeof(struct message_macs) +
- offsetof(struct message_macs, mac2);
- blake2s(mac2, message, cookie, COOKIE_LEN, len, COOKIE_LEN);
- }
- static void make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb,
- struct cookie_checker *checker)
- {
- struct blake2s_state state;
- if (wg_birthdate_has_expired(checker->secret_birthdate,
- COOKIE_SECRET_MAX_AGE)) {
- down_write(&checker->secret_lock);
- checker->secret_birthdate = ktime_get_coarse_boottime_ns();
- get_random_bytes(checker->secret, NOISE_HASH_LEN);
- up_write(&checker->secret_lock);
- }
- down_read(&checker->secret_lock);
- blake2s_init_key(&state, COOKIE_LEN, checker->secret, NOISE_HASH_LEN);
- if (skb->protocol == htons(ETH_P_IP))
- blake2s_update(&state, (u8 *)&ip_hdr(skb)->saddr,
- sizeof(struct in_addr));
- else if (skb->protocol == htons(ETH_P_IPV6))
- blake2s_update(&state, (u8 *)&ipv6_hdr(skb)->saddr,
- sizeof(struct in6_addr));
- blake2s_update(&state, (u8 *)&udp_hdr(skb)->source, sizeof(__be16));
- blake2s_final(&state, cookie);
- up_read(&checker->secret_lock);
- }
- enum cookie_mac_state wg_cookie_validate_packet(struct cookie_checker *checker,
- struct sk_buff *skb,
- bool check_cookie)
- {
- struct message_macs *macs = (struct message_macs *)
- (skb->data + skb->len - sizeof(*macs));
- enum cookie_mac_state ret;
- u8 computed_mac[COOKIE_LEN];
- u8 cookie[COOKIE_LEN];
- ret = INVALID_MAC;
- compute_mac1(computed_mac, skb->data, skb->len,
- checker->message_mac1_key);
- if (crypto_memneq(computed_mac, macs->mac1, COOKIE_LEN))
- goto out;
- ret = VALID_MAC_BUT_NO_COOKIE;
- if (!check_cookie)
- goto out;
- make_cookie(cookie, skb, checker);
- compute_mac2(computed_mac, skb->data, skb->len, cookie);
- if (crypto_memneq(computed_mac, macs->mac2, COOKIE_LEN))
- goto out;
- ret = VALID_MAC_WITH_COOKIE_BUT_RATELIMITED;
- if (!wg_ratelimiter_allow(skb, dev_net(checker->device->dev)))
- goto out;
- ret = VALID_MAC_WITH_COOKIE;
- out:
- return ret;
- }
- void wg_cookie_add_mac_to_packet(void *message, size_t len,
- struct wg_peer *peer)
- {
- struct message_macs *macs = (struct message_macs *)
- ((u8 *)message + len - sizeof(*macs));
- down_write(&peer->latest_cookie.lock);
- compute_mac1(macs->mac1, message, len,
- peer->latest_cookie.message_mac1_key);
- memcpy(peer->latest_cookie.last_mac1_sent, macs->mac1, COOKIE_LEN);
- peer->latest_cookie.have_sent_mac1 = true;
- up_write(&peer->latest_cookie.lock);
- down_read(&peer->latest_cookie.lock);
- if (peer->latest_cookie.is_valid &&
- !wg_birthdate_has_expired(peer->latest_cookie.birthdate,
- COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY))
- compute_mac2(macs->mac2, message, len,
- peer->latest_cookie.cookie);
- else
- memset(macs->mac2, 0, COOKIE_LEN);
- up_read(&peer->latest_cookie.lock);
- }
- void wg_cookie_message_create(struct message_handshake_cookie *dst,
- struct sk_buff *skb, __le32 index,
- struct cookie_checker *checker)
- {
- struct message_macs *macs = (struct message_macs *)
- ((u8 *)skb->data + skb->len - sizeof(*macs));
- u8 cookie[COOKIE_LEN];
- dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE);
- dst->receiver_index = index;
- get_random_bytes_wait(dst->nonce, COOKIE_NONCE_LEN);
- make_cookie(cookie, skb, checker);
- xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN,
- macs->mac1, COOKIE_LEN, dst->nonce,
- checker->cookie_encryption_key);
- }
- void wg_cookie_message_consume(struct message_handshake_cookie *src,
- struct wg_device *wg)
- {
- struct wg_peer *peer = NULL;
- u8 cookie[COOKIE_LEN];
- bool ret;
- if (unlikely(!wg_index_hashtable_lookup(wg->index_hashtable,
- INDEX_HASHTABLE_HANDSHAKE |
- INDEX_HASHTABLE_KEYPAIR,
- src->receiver_index, &peer)))
- return;
- down_read(&peer->latest_cookie.lock);
- if (unlikely(!peer->latest_cookie.have_sent_mac1)) {
- up_read(&peer->latest_cookie.lock);
- goto out;
- }
- ret = xchacha20poly1305_decrypt(
- cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie),
- peer->latest_cookie.last_mac1_sent, COOKIE_LEN, src->nonce,
- peer->latest_cookie.cookie_decryption_key);
- up_read(&peer->latest_cookie.lock);
- if (ret) {
- down_write(&peer->latest_cookie.lock);
- memcpy(peer->latest_cookie.cookie, cookie, COOKIE_LEN);
- peer->latest_cookie.birthdate = ktime_get_coarse_boottime_ns();
- peer->latest_cookie.is_valid = true;
- peer->latest_cookie.have_sent_mac1 = false;
- up_write(&peer->latest_cookie.lock);
- } else {
- net_dbg_ratelimited("%s: Could not decrypt invalid cookie response\n",
- wg->dev->name);
- }
- out:
- wg_peer_put(peer);
- }
|