]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
wireguard: add PrivateKeyFile= option
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 4 Mar 2019 05:19:21 +0000 (14:19 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 13 Mar 2019 03:02:03 +0000 (12:02 +0900)
Closes #11878.

man/systemd.netdev.xml
src/network/netdev/netdev-gperf.gperf
src/network/netdev/wireguard.c
src/network/netdev/wireguard.h
test/fuzz/fuzz-netdev-parser/directives.netdev

index 69e7d53fc7d4ab4d0ce33383f272def793521b47..9d8f045da6eb5ba3260518587dea1bd5cf17cc4f 100644 (file)
           <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>
index f7ca98fa4671bb5b6c111ec7c75ac047b2ce4253..29bdc65a21f3526207933e5977566a168f911e5c 100644 (file)
@@ -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
index c5c60c1752f45eced6091854b1a711770cacf3d7..eefb543c4d38931a493f0af0a14b69b17034d51a 100644 (file)
 #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);
index 65e9ac24b9a3170a8aed7bb5f7201dbe3ed59862..6cf6eec14db49a266543f3ac8f53948ceb7ded24 100644 (file)
@@ -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);
index cd7c3aadedb29925f064a4fd1545879baa84f136..419ccda7dccce4bfe952d64c8dd16a7476ba6a23 100644 (file)
@@ -9,6 +9,7 @@ Mode=
 [WireGuard]
 ListenPort=
 PrivateKey=
+PrivateKeyFile=
 FwMark=
 [MACVTAP]
 Mode=