From 4bf1a2c3834cd70292c5a01869d2aca4ffbbf974 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 16 Aug 2024 22:13:23 +0900 Subject: [PATCH] network/wireguard: introduce [WireGuardPeer] PublicKeyFile= Similar to PresharedKeyFile=, but for public key. Closes #34012. --- man/systemd.netdev.xml | 13 ++++++++++ src/network/netdev/netdev-gperf.gperf | 3 ++- src/network/netdev/wireguard.c | 26 ++++++++++++++++--- src/network/netdev/wireguard.h | 3 ++- .../conf/25-wireguard-public-key.txt | 1 + .../conf/25-wireguard.netdev.d/peer.conf | 2 +- test/test-network/systemd-networkd-tests.py | 2 +- 7 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 test/test-network/conf/25-wireguard-public-key.txt diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index a9ebd153b89..b0058c11c87 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -2026,6 +2026,19 @@ + + PublicKeyFile= + + Takes an absolute path to a file which contains the Base64 encoded public key for the peer. + When this option is specified, then PublicKey= will be ignored. Note that the + file must be readable by the user systemd-network, so it should be, e.g., owned + by root:systemd-network with a 0640 file mode. If the path + refers to an AF_UNIX stream socket in the file system a connection is made to + it and the key read from it. + + + + PresharedKey= diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index 2ac92e061fc..03a4791ee48 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -250,8 +250,9 @@ WireGuard.RouteMetric, config_parse_wireguard_route_priority, WireGuardPeer.AllowedIPs, config_parse_wireguard_allowed_ips, 0, 0 WireGuardPeer.Endpoint, config_parse_wireguard_endpoint, 0, 0 WireGuardPeer.PublicKey, config_parse_wireguard_peer_key, 0, 0 +WireGuardPeer.PublicKeyFile, config_parse_wireguard_peer_key_file, 0, 0 WireGuardPeer.PresharedKey, config_parse_wireguard_peer_key, 0, 0 -WireGuardPeer.PresharedKeyFile, config_parse_wireguard_preshared_key_file, 0, 0 +WireGuardPeer.PresharedKeyFile, config_parse_wireguard_peer_key_file, 0, 0 WireGuardPeer.PersistentKeepalive, config_parse_wireguard_keepalive, 0, 0 WireGuardPeer.RouteTable, config_parse_wireguard_peer_route_table, 0, 0 WireGuardPeer.RouteMetric, config_parse_wireguard_peer_route_priority,0, 0 diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index fed1be8d110..ba013e3ba54 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -60,6 +60,7 @@ static WireguardPeer* wireguard_peer_free(WireguardPeer *peer) { free(peer->endpoint_host); free(peer->endpoint_port); + free(peer->public_key_file); free(peer->preshared_key_file); explicit_bzero_safe(peer->preshared_key, WG_KEY_LEN); @@ -609,7 +610,7 @@ int config_parse_wireguard_peer_key( return 0; } -int config_parse_wireguard_preshared_key_file( +int config_parse_wireguard_peer_key_file( const char *unit, const char *filename, unsigned line, @@ -624,14 +625,25 @@ int config_parse_wireguard_preshared_key_file( Wireguard *w = WIREGUARD(data); _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL; _cleanup_free_ char *path = NULL; + char **key_file; int r; + assert(filename); + assert(lvalue); + r = wireguard_peer_new_static(w, filename, section_line, &peer); if (r < 0) return log_oom(); + if (streq(lvalue, "PublicKeyFile")) + key_file = &peer->public_key_file; + else if (streq(lvalue, "PresharedKeyFile")) + key_file = &peer->preshared_key_file; + else + assert_not_reached(); + if (isempty(rvalue)) { - peer->preshared_key_file = mfree(peer->preshared_key_file); + *key_file = mfree(*key_file); TAKE_PTR(peer); return 0; } @@ -643,7 +655,7 @@ int config_parse_wireguard_preshared_key_file( if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0) return 0; - free_and_replace(peer->preshared_key_file, path); + free_and_replace(*key_file, path); TAKE_PTR(peer); return 0; } @@ -1099,6 +1111,14 @@ static int wireguard_peer_verify(WireguardPeer *peer) { if (section_is_invalid(peer->section)) return -EINVAL; + r = wireguard_read_key_file(peer->public_key_file, peer->public_key); + if (r < 0) + return log_netdev_error_errno(netdev, r, + "%s: Failed to read public key from '%s'. " + "Ignoring [WireGuardPeer] section from line %u.", + peer->section->filename, peer->public_key_file, + peer->section->line); + if (eqzero(peer->public_key)) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "%s: WireGuardPeer section without PublicKey= configured. " diff --git a/src/network/netdev/wireguard.h b/src/network/netdev/wireguard.h index 09dca88bbf0..8e5b3b58f56 100644 --- a/src/network/netdev/wireguard.h +++ b/src/network/netdev/wireguard.h @@ -28,6 +28,7 @@ typedef struct WireguardPeer { uint8_t public_key[WG_KEY_LEN]; uint8_t preshared_key[WG_KEY_LEN]; + char *public_key_file; char *preshared_key_file; uint32_t flags; uint16_t persistent_keepalive_interval; @@ -74,9 +75,9 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_allowed_ips); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_endpoint); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_peer_key); +CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_peer_key_file); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key_file); -CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key_file); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_keepalive); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_route_table); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_peer_route_table); diff --git a/test/test-network/conf/25-wireguard-public-key.txt b/test/test-network/conf/25-wireguard-public-key.txt new file mode 100644 index 00000000000..0267479682b --- /dev/null +++ b/test/test-network/conf/25-wireguard-public-key.txt @@ -0,0 +1 @@ +lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= diff --git a/test/test-network/conf/25-wireguard.netdev.d/peer.conf b/test/test-network/conf/25-wireguard.netdev.d/peer.conf index f559ea68f6c..9f8770de594 100644 --- a/test/test-network/conf/25-wireguard.netdev.d/peer.conf +++ b/test/test-network/conf/25-wireguard.netdev.d/peer.conf @@ -1,5 +1,5 @@ [WireGuardPeer] -PublicKey=lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= +PublicKeyFile=/run/systemd/network/25-wireguard-public-key.txt AllowedIPs=fdbc:bae2:7871:0500:e1fe:0793:8636:dad1/128 AllowedIPs=fdbc:bae2:7871:e1fe:0793:8636::/96 PresharedKeyFile=/run/systemd/network/25-wireguard-preshared-key.txt diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 0b95bfff143..3a30c8bfd19 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1940,7 +1940,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): copy_network_unit('25-wireguard.netdev', '25-wireguard.network', '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network', - '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt', + '25-wireguard-public-key.txt', '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt', '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network') start_networkd() self.wait_online('wg99:routable', 'wg98:routable', 'wg97:carrier') -- 2.47.3