summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-03-04 14:19:21 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-03-13 12:02:03 +0900
commit76df77794a902c7a7bce6cf689114fde9e139b22 (patch)
treea5726bd5610ea3bcdc7297cc4112c9d51234e31d
parent9cc9021aed09c064cfd56d28704474d1cc4f7de7 (diff)
downloadsystemd-76df77794a902c7a7bce6cf689114fde9e139b22.tar.gz
wireguard: add PrivateKeyFile= option
Closes #11878.
-rw-r--r--man/systemd.netdev.xml14
-rw-r--r--src/network/netdev/netdev-gperf.gperf1
-rw-r--r--src/network/netdev/wireguard.c84
-rw-r--r--src/network/netdev/wireguard.h2
-rw-r--r--test/fuzz/fuzz-netdev-parser/directives.netdev1
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=