]> git.ipfire.org Git - thirdparty/wireguard-tools.git/commitdiff
examples: add key extractor
authorJason A. Donenfeld <Jason@zx2c4.com>
Wed, 24 Aug 2016 15:44:41 +0000 (17:44 +0200)
committerJason A. Donenfeld <Jason@zx2c4.com>
Fri, 26 Aug 2016 02:52:50 +0000 (04:52 +0200)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
contrib/extract-keys/Makefile [new file with mode: 0644]
contrib/extract-keys/README [new file with mode: 0644]
contrib/extract-keys/config.c [new file with mode: 0644]
contrib/extract-keys/extract-keys.c [new file with mode: 0644]

diff --git a/contrib/extract-keys/Makefile b/contrib/extract-keys/Makefile
new file mode 100644 (file)
index 0000000..a1dd7a2
--- /dev/null
@@ -0,0 +1,27 @@
+ifeq ($(KERNELRELEASE),)
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+CFLAGS ?= -O3 -march=native
+CFLAGS += -Wall -pedantic -std=gnu11
+
+extract-keys: extract-keys.c config.h
+       $(CC) $(CFLAGS) $(CPPFLAGS) -D_FILE_OFFSET_BITS=64 -o $@ -lresolv $<
+
+config.o: config.c
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) $@
+       objcopy -j '.rodata*' $@ $@
+
+config: config.c config.o
+       $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
+
+config.h: config
+       ./$< > $@
+
+clean:
+       rm -f extract-keys config config.h
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
+
+.PHONY: clean
+else
+config-m := config.o
+endif
diff --git a/contrib/extract-keys/README b/contrib/extract-keys/README
new file mode 100644 (file)
index 0000000..a91363d
--- /dev/null
@@ -0,0 +1,23 @@
+Key Extractor
+=============
+
+This will extract the symmetric ChaCha20Poly1305 session keys from the kernel
+for a WireGuard interface, for use in making packet dissectors.
+
+
+Build:
+    $ make
+
+Run (as root):
+    # ./extract-keys INTERFACE
+
+Output:
+    REMOTE_KEY_ID SENDING_KEY
+    LOCAL_KEY_ID RECEIVING_KEY
+
+Example:
+    # ./extract-keys wg0
+    0x57b56068 tMTSEOJpEYFAQV2UviDiYooX0A1AD/ONqrzoQVHa1rQ=
+    0xa182fd19 xvQSkQ5HTX5RUeJ74eAAb/xfNhdrDThxG91GXZIPKmY=
+    0x01662508 LbMc84JULzXJiHotSkdSOPZ0bHh6IDwOrbxWLfwosTs=
+    0xbd819021 4VA8lZ3I1HjnJcWTmhEzBdC92W1Aag9Lnyy2GkroOYI=
diff --git a/contrib/extract-keys/config.c b/contrib/extract-keys/config.c
new file mode 100644 (file)
index 0000000..0dc4841
--- /dev/null
@@ -0,0 +1,32 @@
+struct def {
+       const char *name;
+       long long value;
+};
+extern const struct def defs[];
+
+#ifdef __KERNEL__
+#include "../../../src/wireguard.h"
+const struct def defs[] = {
+       { "SOCK_DEVICE_OFFSET", offsetof(struct sock, sk_user_data) },
+       { "DEVICE_NAME_OFFSET", -ALIGN(sizeof(struct net_device), NETDEV_ALIGN) + offsetof(struct net_device, name) },
+       { "IFNAMSIZ", IFNAMSIZ },
+       { "DEVICE_PEERS_OFFSET", offsetof(struct wireguard_device, peer_list) },
+       { "PEERS_PEER_OFFSET", -offsetof(struct wireguard_peer, peer_list) },
+       { "PEER_CURRENTKEY_OFFSET", offsetof(struct wireguard_peer, keypairs.current_keypair) },
+       { "PEER_PREVIOUSKEY_OFFSET", offsetof(struct wireguard_peer, keypairs.previous_keypair) },
+       { "PEER_NEXTKEY_OFFSET", offsetof(struct wireguard_peer, keypairs.next_keypair) },
+       { "KEY_LOCALID_OFFSET", offsetof(struct noise_keypair, entry.index) },
+       { "KEY_REMOTEID_OFFSET", offsetof(struct noise_keypair, remote_index) },
+       { "KEY_SENDING_OFFSET", offsetof(struct noise_keypair, sending.key) },
+       { "KEY_RECEIVING_OFFSET", offsetof(struct noise_keypair, receiving.key) },
+       { NULL, 0 }
+};
+#else
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+       for (const struct def *def = defs; def->name; ++def)
+               printf("#define %s %lld\n", def->name, def->value);
+       return 0;
+}
+#endif
diff --git a/contrib/extract-keys/extract-keys.c b/contrib/extract-keys/extract-keys.c
new file mode 100644 (file)
index 0000000..5d7de32
--- /dev/null
@@ -0,0 +1,139 @@
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "config.h"
+
+static int fd;
+
+static void open_kmem(void)
+{
+       fd = open("/dev/kmem", O_RDONLY);
+       if (fd < 0) {
+               perror("open(/dev/kmem)");
+               exit(errno);
+       }
+}
+
+static void read_kmem(void *buffer, size_t len, unsigned long addr)
+{
+       if (lseek(fd, addr, SEEK_SET) == (off_t)-1) {
+               perror("lseek");
+               exit(errno);
+       }
+       if (read(fd, buffer, len) != len) {
+               perror("read");
+               exit(errno);
+       }
+}
+
+static inline unsigned int read_int(unsigned long addr)
+{
+       unsigned int ret;
+       read_kmem(&ret, sizeof(ret), addr);
+       return ret;
+}
+
+static inline unsigned long read_long(unsigned long addr)
+{
+       unsigned long ret;
+       read_kmem(&ret, sizeof(ret), addr);
+       return ret;
+}
+
+static unsigned long find_interface(const char *interface)
+{
+       FILE *f = fopen("/proc/net/udp", "r");
+       char line[256], *ptr;
+       unsigned long addr = 0;
+       char name[IFNAMSIZ + 1] = { 0 };
+
+       if (!f) {
+               perror("fopen(/proc/net/udp)");
+               exit(errno);
+       }
+       if (!fgets(line, 256, f))
+               goto out;
+       while (fgets(line, 256, f)) {
+               ptr = line + strlen(line) - 1;
+               while (*--ptr == ' ');
+               while (*--ptr != ' ');
+               while (*(--ptr - 1) != ' ');
+               addr = strtoul(ptr, NULL, 16);
+               if (!addr)
+                       continue;
+               addr = read_long(addr + SOCK_DEVICE_OFFSET);
+               if (!addr)
+                       continue;
+               read_kmem(name, IFNAMSIZ, addr + DEVICE_NAME_OFFSET);
+               if (!strcmp(name, interface))
+                       goto out;
+       }
+       addr = 0;
+out:
+       fclose(f);
+       return addr;
+}
+
+static bool print_key(unsigned long key)
+{
+       unsigned char sending[32], receiving[32];
+       char sending_b64[45], receiving_b64[45];
+       unsigned int local_index, remote_index;
+
+       if (!key)
+               return false;
+
+       local_index = le32toh(read_int(key + KEY_LOCALID_OFFSET));
+       remote_index = le32toh(read_int(key + KEY_REMOTEID_OFFSET));
+       read_kmem(sending, 32, key + KEY_SENDING_OFFSET);
+       read_kmem(receiving, 32, key + KEY_RECEIVING_OFFSET);
+
+       b64_ntop(sending, 32, sending_b64, 45);
+       b64_ntop(receiving, 32, receiving_b64, 45);
+
+       printf("0x%08x %s\n", local_index, receiving_b64);
+       printf("0x%08x %s\n", remote_index, sending_b64);
+       return true;
+}
+
+static bool walk_peers(unsigned long peer_head)
+{
+       unsigned long peer, peer_entry;
+       bool found = false;
+       for (peer_entry = read_long(peer_head); peer_entry != peer_head; peer_entry = read_long(peer_entry)) {
+               peer = peer_entry + PEERS_PEER_OFFSET;
+               if (print_key(read_long(peer + PEER_CURRENTKEY_OFFSET)))
+                       found = true;
+               if (print_key(read_long(peer + PEER_PREVIOUSKEY_OFFSET)))
+                       found = true;
+               if (print_key(read_long(peer + PEER_NEXTKEY_OFFSET)))
+                       found = true;
+       }
+       return found;
+}
+
+int main(int argc, char *argv[])
+{
+       unsigned long wireguard_device;
+       if (argc < 2) {
+               fprintf(stderr, "Usage: %s WIREGUARD_INTERFACE\n", argv[0]);
+               return EINVAL;
+       }
+       open_kmem();
+       wireguard_device = find_interface(argv[1]);
+       if (!wireguard_device) {
+               fprintf(stderr, "Could not find interface %s\n", argv[1]);
+               return EBADSLT;
+       }
+       if (!walk_peers(wireguard_device + DEVICE_PEERS_OFFSET)) {
+               fprintf(stderr, "No active sessions\n");
+               return ENOKEY;
+       }
+       return 0;
+}