diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-03-04 14:19:21 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-03-13 12:02:03 +0900 |
commit | 76df77794a902c7a7bce6cf689114fde9e139b22 (patch) | |
tree | a5726bd5610ea3bcdc7297cc4112c9d51234e31d | |
parent | 9cc9021aed09c064cfd56d28704474d1cc4f7de7 (diff) | |
download | systemd-76df77794a902c7a7bce6cf689114fde9e139b22.tar.gz |
wireguard: add PrivateKeyFile= option
Closes #11878.
-rw-r--r-- | man/systemd.netdev.xml | 14 | ||||
-rw-r--r-- | src/network/netdev/netdev-gperf.gperf | 1 | ||||
-rw-r--r-- | src/network/netdev/wireguard.c | 84 | ||||
-rw-r--r-- | src/network/netdev/wireguard.h | 2 | ||||
-rw-r--r-- | test/fuzz/fuzz-netdev-parser/directives.netdev | 1 |
5 files changed, 100 insertions, 2 deletions
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 69e7d53fc7..9d8f045da6 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -1113,13 +1113,25 @@ <para>The Base64 encoded private key for the interface. It can be generated using the <command>wg genkey</command> command (see <citerefentry project="wireguard"><refentrytitle>wg</refentrytitle><manvolnum>8</manvolnum></citerefentry>). - This option is mandatory to use WireGuard. + This option or <varname>PrivateKeyFile=</varname> is mandatory to use WireGuard. Note that because this information is secret, you may want to set the permissions of the .netdev file to be owned by <literal>root:systemd-network</literal> with a <literal>0640</literal> file mode.</para> </listitem> </varlistentry> <varlistentry> + <term><varname>PrivateKeyFile=</varname></term> + <listitem> + <para>Takes a absolute path to a file which contains the Base64 encoded private key for the interface. + If both <varname>PrivateKey=</varname> and <varname>PrivateKeyFile=</varname> are specified, and if + the file specified in <varname>PrivateKeyFile=</varname> contains valid wireguard key, then + the key provided by <varname>PrivateKey=</varname> is ignored. + Note that the file must be readable by the user <literal>systemd-network</literal>, so it + should be, e.g., owned by <literal>root:systemd-network</literal> with a + <literal>0640</literal> file mode.</para> + </listitem> + </varlistentry> + <varlistentry> <term><varname>ListenPort=</varname></term> <listitem> <para>Sets UDP port for listening. Takes either value between 1 and 65535 diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index f7ca98fa46..29bdc65a21 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -167,6 +167,7 @@ VRF.Table, config_parse_uint32, 0, WireGuard.FwMark, config_parse_unsigned, 0, offsetof(Wireguard, fwmark) WireGuard.ListenPort, config_parse_wireguard_listen_port, 0, offsetof(Wireguard, port) WireGuard.PrivateKey, config_parse_wireguard_private_key, 0, 0 +WireGuard.PrivateKeyFile, config_parse_wireguard_private_key_file, 0, 0 WireGuardPeer.AllowedIPs, config_parse_wireguard_allowed_ips, 0, 0 WireGuardPeer.Endpoint, config_parse_wireguard_endpoint, 0, 0 WireGuardPeer.PublicKey, config_parse_wireguard_public_key, 0, 0 diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index c5c60c1752..eefb543c4d 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -11,12 +11,14 @@ #include "alloc-util.h" #include "event-util.h" #include "fd-util.h" +#include "fileio.h" #include "hexdecoct.h" #include "netlink-util.h" #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-util.h" #include "parse-util.h" +#include "path-util.h" #include "resolve-private.h" #include "string-util.h" #include "strv.h" @@ -529,6 +531,40 @@ int config_parse_wireguard_private_key(const char *unit, } +int config_parse_wireguard_private_key_file( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_free_ char *path = NULL; + Wireguard *w; + + assert(data); + w = WIREGUARD(data); + assert(w); + + if (isempty(rvalue)) { + w->private_key_file = mfree(w->private_key_file); + return 0; + } + + path = strdup(rvalue); + if (!path) + return log_oom(); + + if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0) + return 0; + + return free_and_replace(w->private_key_file, path); +} + int config_parse_wireguard_preshared_key(const char *unit, const char *filename, unsigned line, @@ -807,11 +843,50 @@ static void wireguard_done(NetDev *netdev) { sd_event_source_unref(w->resolve_retry_event_source); + free(w->private_key_file); + hashmap_free_with_destructor(w->peers_by_section, wireguard_peer_free); set_free(w->peers_with_unresolved_endpoint); set_free(w->peers_with_failed_endpoint); } +static int wireguard_read_private_key_file(Wireguard *w, bool fatal) { + _cleanup_free_ char *contents = NULL; + _cleanup_free_ void *key = NULL; + size_t size, key_len; + NetDev *netdev; + int level, r; + + assert(w); + + netdev = NETDEV(w); + + if (!w->private_key_file) + return 0; + + level = fatal ? LOG_ERR : LOG_INFO; + + r = read_full_file(w->private_key_file, &contents, &size); + if (r < 0) + return log_netdev_full(netdev, level, r, + "Failed to read private key from '%s'%s: %m", + w->private_key_file, fatal ? "" : ", ignoring"); + + r = unbase64mem(contents, size, &key, &key_len); + if (r < 0) + return log_netdev_full(netdev, level, r, + "Failed to decode private key%s: %m", + fatal ? "" : ", ignoring"); + + if (key_len != WG_KEY_LEN) + return log_netdev_full(netdev, level, SYNTHETIC_ERRNO(EINVAL), + "Wireguard private key has invalid length (%zu bytes)%s: %m", + key_len, fatal ? "" : ", ignoring"); + + memcpy(w->private_key, key, WG_KEY_LEN); + return 0; +} + static int wireguard_peer_verify(WireguardPeer *peer) { NetDev *netdev = NETDEV(peer->wireguard); @@ -830,16 +905,23 @@ static int wireguard_peer_verify(WireguardPeer *peer) { static int wireguard_verify(NetDev *netdev, const char *filename) { WireguardPeer *peer, *peer_next; Wireguard *w; + bool empty; + int r; assert(netdev); w = WIREGUARD(netdev); assert(w); - if (eqzero(w->private_key)) + empty = eqzero(w->private_key); + if (empty && !w->private_key_file) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "%s: Missing PrivateKey= or PrivateKeyFile=, ignoring.", filename); + r = wireguard_read_private_key_file(w, empty); + if (r < 0 && empty) + return r; + LIST_FOREACH_SAFE(peers, peer, peer_next, w->peers) if (wireguard_peer_verify(peer) < 0) wireguard_peer_free(peer); diff --git a/src/network/netdev/wireguard.h b/src/network/netdev/wireguard.h index 65e9ac24b9..6cf6eec14d 100644 --- a/src/network/netdev/wireguard.h +++ b/src/network/netdev/wireguard.h @@ -38,6 +38,7 @@ struct Wireguard { uint32_t flags; uint8_t private_key[WG_KEY_LEN]; + char *private_key_file; uint16_t port; uint32_t fwmark; @@ -60,5 +61,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_public_key); 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); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_keepalive); diff --git a/test/fuzz/fuzz-netdev-parser/directives.netdev b/test/fuzz/fuzz-netdev-parser/directives.netdev index cd7c3aaded..419ccda7dc 100644 --- a/test/fuzz/fuzz-netdev-parser/directives.netdev +++ b/test/fuzz/fuzz-netdev-parser/directives.netdev @@ -9,6 +9,7 @@ Mode= [WireGuard] ListenPort= PrivateKey= +PrivateKeyFile= FwMark= [MACVTAP] Mode= |