Mon Aug 31 20:29:14 2020 UTC ()
wg: Verify or send cookie challenge before looking up session.

This step doesn't depend on the session, so let's avoid touching the
session state until we've passed it.


(riastradh)
diff -r1.44 -r1.45 src/sys/net/if_wg.c

cvs diff -r1.44 -r1.45 src/sys/net/if_wg.c (expand / switch to unified diff)

--- src/sys/net/if_wg.c 2020/08/31 20:27:06 1.44
+++ src/sys/net/if_wg.c 2020/08/31 20:29:14 1.45
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: if_wg.c,v 1.44 2020/08/31 20:27:06 riastradh Exp $ */ 1/* $NetBSD: if_wg.c,v 1.45 2020/08/31 20:29:14 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright (C) Ryota Ozaki <ozaki.ryota@gmail.com> 4 * Copyright (C) Ryota Ozaki <ozaki.ryota@gmail.com>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -31,27 +31,27 @@ @@ -31,27 +31,27 @@
31 31
32/* 32/*
33 * This network interface aims to implement the WireGuard protocol. 33 * This network interface aims to implement the WireGuard protocol.
34 * The implementation is based on the paper of WireGuard as of 34 * The implementation is based on the paper of WireGuard as of
35 * 2018-06-30 [1]. The paper is referred in the source code with label 35 * 2018-06-30 [1]. The paper is referred in the source code with label
36 * [W]. Also the specification of the Noise protocol framework as of 36 * [W]. Also the specification of the Noise protocol framework as of
37 * 2018-07-11 [2] is referred with label [N]. 37 * 2018-07-11 [2] is referred with label [N].
38 * 38 *
39 * [1] https://www.wireguard.com/papers/wireguard.pdf 39 * [1] https://www.wireguard.com/papers/wireguard.pdf
40 * [2] http://noiseprotocol.org/noise.pdf 40 * [2] http://noiseprotocol.org/noise.pdf
41 */ 41 */
42 42
43#include <sys/cdefs.h> 43#include <sys/cdefs.h>
44__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.44 2020/08/31 20:27:06 riastradh Exp $"); 44__KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.45 2020/08/31 20:29:14 riastradh Exp $");
45 45
46#ifdef _KERNEL_OPT 46#ifdef _KERNEL_OPT
47#include "opt_inet.h" 47#include "opt_inet.h"
48#endif 48#endif
49 49
50#include <sys/param.h> 50#include <sys/param.h>
51#include <sys/types.h> 51#include <sys/types.h>
52 52
53#include <sys/atomic.h> 53#include <sys/atomic.h>
54#include <sys/callout.h> 54#include <sys/callout.h>
55#include <sys/cprng.h> 55#include <sys/cprng.h>
56#include <sys/cpu.h> 56#include <sys/cpu.h>
57#include <sys/device.h> 57#include <sys/device.h>
@@ -1389,86 +1389,86 @@ wg_handle_msg_init(struct wg_softc *wg,  @@ -1389,86 +1389,86 @@ wg_handle_msg_init(struct wg_softc *wg,
1389 WG_LOG_RATECHECK(&wg->wg_ppsratecheck, LOG_DEBUG, 1389 WG_LOG_RATECHECK(&wg->wg_ppsratecheck, LOG_DEBUG,
1390 "wg_algo_aead_dec for secret key failed\n"); 1390 "wg_algo_aead_dec for secret key failed\n");
1391 return; 1391 return;
1392 } 1392 }
1393 /* Hi := HASH(Hi || msg.static) */ 1393 /* Hi := HASH(Hi || msg.static) */
1394 wg_algo_hash(hash, wgmi->wgmi_static, sizeof(wgmi->wgmi_static)); 1394 wg_algo_hash(hash, wgmi->wgmi_static, sizeof(wgmi->wgmi_static));
1395 1395
1396 wgp = wg_lookup_peer_by_pubkey(wg, peer_pubkey, &psref_peer); 1396 wgp = wg_lookup_peer_by_pubkey(wg, peer_pubkey, &psref_peer);
1397 if (wgp == NULL) { 1397 if (wgp == NULL) {
1398 WG_DLOG("peer not found\n"); 1398 WG_DLOG("peer not found\n");
1399 return; 1399 return;
1400 } 1400 }
1401 1401
1402 wgs = wg_lock_unstable_session(wgp); 
1403 if (wgs->wgs_state == WGS_STATE_DESTROYING) { 
1404 /* 
1405 * We can assume that the peer doesn't have an 
1406 * established session, so clear it now. If the timer 
1407 * fired, tough -- it won't have any effect unless we 
1408 * manage to transition back to WGS_STATE_DESTROYING. 
1409 */ 
1410 WG_TRACE("Session destroying, but force to clear"); 
1411 callout_stop(&wgp->wgp_session_dtor_timer); 
1412 wg_clear_states(wgs); 
1413 wgs->wgs_state = WGS_STATE_UNKNOWN; 
1414 } 
1415 if (wgs->wgs_state == WGS_STATE_INIT_ACTIVE) { 
1416 WG_TRACE("Sesssion already initializing, ignoring the message"); 
1417 mutex_exit(wgs->wgs_lock); 
1418 goto out_wgp; 
1419 } 
1420 if (wgs->wgs_state == WGS_STATE_INIT_PASSIVE) { 
1421 WG_TRACE("Sesssion already initializing, destroying old states"); 
1422 wg_clear_states(wgs); 
1423 } 
1424 wgs->wgs_state = WGS_STATE_INIT_PASSIVE; 
1425 wg_get_session(wgs, &psref_session); 
1426 mutex_exit(wgs->wgs_lock); 
1427 
1428 if (__predict_false(wg_is_underload(wg, wgp, WG_MSG_TYPE_INIT))) { 1402 if (__predict_false(wg_is_underload(wg, wgp, WG_MSG_TYPE_INIT))) {
1429 WG_TRACE("under load"); 1403 WG_TRACE("under load");
1430 /* 1404 /*
1431 * [W] 5.3: Denial of Service Mitigation & Cookies 1405 * [W] 5.3: Denial of Service Mitigation & Cookies
1432 * "the responder, ..., and when under load may reject messages 1406 * "the responder, ..., and when under load may reject messages
1433 * with an invalid msg.mac2. If the responder receives a 1407 * with an invalid msg.mac2. If the responder receives a
1434 * message with a valid msg.mac1 yet with an invalid msg.mac2, 1408 * message with a valid msg.mac1 yet with an invalid msg.mac2,
1435 * and is under load, it may respond with a cookie reply 1409 * and is under load, it may respond with a cookie reply
1436 * message" 1410 * message"
1437 */ 1411 */
1438 uint8_t zero[WG_MAC_LEN] = {0}; 1412 uint8_t zero[WG_MAC_LEN] = {0};
1439 if (consttime_memequal(wgmi->wgmi_mac2, zero, sizeof(zero))) { 1413 if (consttime_memequal(wgmi->wgmi_mac2, zero, sizeof(zero))) {
1440 WG_TRACE("sending a cookie message: no cookie included"); 1414 WG_TRACE("sending a cookie message: no cookie included");
1441 (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender, 1415 (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender,
1442 wgmi->wgmi_mac1, src); 1416 wgmi->wgmi_mac1, src);
1443 goto out; 1417 goto out_wgp;
1444 } 1418 }
1445 if (!wgp->wgp_last_sent_cookie_valid) { 1419 if (!wgp->wgp_last_sent_cookie_valid) {
1446 WG_TRACE("sending a cookie message: no cookie sent ever"); 1420 WG_TRACE("sending a cookie message: no cookie sent ever");
1447 (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender, 1421 (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender,
1448 wgmi->wgmi_mac1, src); 1422 wgmi->wgmi_mac1, src);
1449 goto out; 1423 goto out_wgp;
1450 } 1424 }
1451 uint8_t mac2[WG_MAC_LEN]; 1425 uint8_t mac2[WG_MAC_LEN];
1452 wg_algo_mac(mac2, sizeof(mac2), wgp->wgp_last_sent_cookie, 1426 wg_algo_mac(mac2, sizeof(mac2), wgp->wgp_last_sent_cookie,
1453 WG_COOKIE_LEN, (const uint8_t *)wgmi, 1427 WG_COOKIE_LEN, (const uint8_t *)wgmi,
1454 offsetof(struct wg_msg_init, wgmi_mac2), NULL, 0); 1428 offsetof(struct wg_msg_init, wgmi_mac2), NULL, 0);
1455 if (!consttime_memequal(mac2, wgmi->wgmi_mac2, sizeof(mac2))) { 1429 if (!consttime_memequal(mac2, wgmi->wgmi_mac2, sizeof(mac2))) {
1456 WG_DLOG("mac2 is invalid\n"); 1430 WG_DLOG("mac2 is invalid\n");
1457 goto out; 1431 goto out_wgp;
1458 } 1432 }
1459 WG_TRACE("under load, but continue to sending"); 1433 WG_TRACE("under load, but continue to sending");
1460 } 1434 }
1461 1435
 1436 wgs = wg_lock_unstable_session(wgp);
 1437 if (wgs->wgs_state == WGS_STATE_DESTROYING) {
 1438 /*
 1439 * We can assume that the peer doesn't have an
 1440 * established session, so clear it now. If the timer
 1441 * fired, tough -- it won't have any effect unless we
 1442 * manage to transition back to WGS_STATE_DESTROYING.
 1443 */
 1444 WG_TRACE("Session destroying, but force to clear");
 1445 callout_stop(&wgp->wgp_session_dtor_timer);
 1446 wg_clear_states(wgs);
 1447 wgs->wgs_state = WGS_STATE_UNKNOWN;
 1448 }
 1449 if (wgs->wgs_state == WGS_STATE_INIT_ACTIVE) {
 1450 WG_TRACE("Sesssion already initializing, ignoring the message");
 1451 mutex_exit(wgs->wgs_lock);
 1452 goto out_wgp;
 1453 }
 1454 if (wgs->wgs_state == WGS_STATE_INIT_PASSIVE) {
 1455 WG_TRACE("Sesssion already initializing, destroying old states");
 1456 wg_clear_states(wgs);
 1457 }
 1458 wgs->wgs_state = WGS_STATE_INIT_PASSIVE;
 1459 wg_get_session(wgs, &psref_session);
 1460 mutex_exit(wgs->wgs_lock);
 1461
1462 /* [N] 2.2: "ss" */ 1462 /* [N] 2.2: "ss" */
1463 /* Ci, k := KDF2(Ci, DH(Si^priv, Sr^pub)) */ 1463 /* Ci, k := KDF2(Ci, DH(Si^priv, Sr^pub)) */
1464 wg_algo_dh_kdf(ckey, cipher_key, wg->wg_privkey, wgp->wgp_pubkey); 1464 wg_algo_dh_kdf(ckey, cipher_key, wg->wg_privkey, wgp->wgp_pubkey);
1465 1465
1466 /* msg.timestamp := AEAD(k, TIMESTAMP(), Hi) */ 1466 /* msg.timestamp := AEAD(k, TIMESTAMP(), Hi) */
1467 wg_timestamp_t timestamp; 1467 wg_timestamp_t timestamp;
1468 error = wg_algo_aead_dec(timestamp, sizeof(timestamp), cipher_key, 0, 1468 error = wg_algo_aead_dec(timestamp, sizeof(timestamp), cipher_key, 0,
1469 wgmi->wgmi_timestamp, sizeof(wgmi->wgmi_timestamp), 1469 wgmi->wgmi_timestamp, sizeof(wgmi->wgmi_timestamp),
1470 hash, sizeof(hash)); 1470 hash, sizeof(hash));
1471 if (error != 0) { 1471 if (error != 0) {
1472 WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, 1472 WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG,
1473 "wg_algo_aead_dec for timestamp failed\n"); 1473 "wg_algo_aead_dec for timestamp failed\n");
1474 goto out; 1474 goto out;