| @@ -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; |