aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/tools
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-04-16 01:20:43 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2017-04-19 18:26:32 +0200
commit94273094f6607923f7e52b16717325f6ed7d9d46 (patch)
treef35a0bbd1d17ca66f857bc75b3434d59dddb7227 /src/tools
parentnetns: cleanup and add diagram (diff)
downloadwireguard-monolithic-historical-94273094f6607923f7e52b16717325f6ed7d9d46.tar.xz
wireguard-monolithic-historical-94273094f6607923f7e52b16717325f6ed7d9d46.zip
tools: side channel resistant base64
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/Makefile1
-rw-r--r--src/tools/base64.c258
-rw-r--r--src/tools/base64.h17
-rw-r--r--src/tools/config.c4
-rw-r--r--src/tools/genkey.c17
-rw-r--r--src/tools/ipc.c2
-rw-r--r--src/tools/pubkey.c19
-rw-r--r--src/tools/show.c12
-rw-r--r--src/tools/showconf.c15
9 files changed, 86 insertions, 259 deletions
diff --git a/src/tools/Makefile b/src/tools/Makefile
index 6502c3d..ec75052 100644
--- a/src/tools/Makefile
+++ b/src/tools/Makefile
@@ -36,7 +36,6 @@ CFLAGS += -std=gnu11
CFLAGS += -Wall -Wextra
CFLAGS += -MMD -MP
CFLAGS += -DRUNSTATEDIR="\"$(RUNSTATEDIR)\""
-LDLIBS += -lresolv
ifeq ($(shell uname -s),Linux)
LIBMNL_CFLAGS := $(shell $(PKG_CONFIG) --cflags libmnl 2>/dev/null)
LIBMNL_LDLIBS := $(shell $(PKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl)
diff --git a/src/tools/base64.c b/src/tools/base64.c
index cf37464..48ac1be 100644
--- a/src/tools/base64.c
+++ b/src/tools/base64.c
@@ -1,220 +1,66 @@
-/*
- * Copyright (c) 1996, 1998 by Internet Software Consortium.
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- *
- * Portions Copyright (c) 1995 by International Business Machines, Inc.
- *
- * International Business Machines, Inc. (hereinafter called IBM) grants
- * permission under its copyrights to use, copy, modify, and distribute this
- * Software with or without fee, provided that the above copyright notice and
- * all paragraphs of this notice appear in all copies, and that the name of IBM
- * not be used in connection with the marketing of any product incorporating
- * the Software or modifications thereof, without specific, written prior
- * permission.
- *
- * To the extent it has a right to do so, IBM grants an immunity from suit
- * under its patents, if any, for the use, sale or manufacture of products to
- * the extent that such products are used for performing Domain Name System
- * dynamic updates in TCP/IP networks by means of the Software. No immunity is
- * granted for any product per se or for any other function of any product.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
- * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
- * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * This is a specialized constant-time base64 implementation that resists side-channel attacks.
*/
+#include <string.h>
#include "base64.h"
-#include <sys/types.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#if defined(NEED_B64_NTOP) || defined(NEED_B64_PTON)
-static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char pad64 = '=';
-#endif
-#ifdef NEED_B64_NTOP
-int b64_ntop(unsigned char const *src, size_t srclength, char *target, size_t targsize)
+static inline void encode(char dest[4], const uint8_t src[3])
{
- size_t datalength = 0;
- uint8_t input[3];
- uint8_t output[4];
- size_t i;
+ const uint8_t input[] = { (src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63 };
+ for (unsigned int i = 0; i < 4; ++i)
+ dest[i] = input[i] + 'A'
+ + (((25 - input[i]) >> 8) & 6)
+ - (((51 - input[i]) >> 8) & 75)
+ - (((61 - input[i]) >> 8) & 15)
+ + (((62 - input[i]) >> 8) & 3);
- while (2 < srclength) {
- input[0] = *src++;
- input[1] = *src++;
- input[2] = *src++;
- srclength -= 3;
-
- output[0] = input[0] >> 2;
- output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
- output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
- output[3] = input[2] & 0x3f;
- assert(output[0] < 64);
- assert(output[1] < 64);
- assert(output[2] < 64);
- assert(output[3] < 64);
-
- if (datalength + 4 > targsize)
- return -1;
- target[datalength++] = base64[output[0]];
- target[datalength++] = base64[output[1]];
- target[datalength++] = base64[output[2]];
- target[datalength++] = base64[output[3]];
- }
- if (0 != srclength) {
- input[0] = input[1] = input[2] = '\0';
- for (i = 0; i < srclength; i++)
- input[i] = *src++;
- output[0] = input[0] >> 2;
- output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
- output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
- assert(output[0] < 64);
- assert(output[1] < 64);
- assert(output[2] < 64);
-
- if (datalength + 4 > targsize)
- return -1;
- target[datalength++] = base64[output[0]];
- target[datalength++] = base64[output[1]];
- if (srclength == 1)
- target[datalength++] = pad64;
- else
- target[datalength++] = base64[output[2]];
- target[datalength++] = pad64;
- }
- if (datalength >= targsize)
- return (-1);
- target[datalength] = '\0';
- return datalength;
}
-#endif
-#ifdef NEED_B64_PTON
-int b64_pton(char const *src, uint8_t *target, size_t targsize)
+void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN])
{
- static int b64rmap_initialized = 0;
- static uint8_t b64rmap[256];
- static const uint8_t b64rmap_special = 0xf0;
- static const uint8_t b64rmap_end = 0xfd;
- static const uint8_t b64rmap_space = 0xfe;
- static const uint8_t b64rmap_invalid = 0xff;
- int tarindex, state, ch;
- uint8_t ofs;
-
- if (!b64rmap_initialized) {
- int i;
- char ch;
- b64rmap[0] = b64rmap_end;
- for (i = 1; i < 256; ++i) {
- ch = (char)i;
- if (isspace(ch))
- b64rmap[i] = b64rmap_space;
- else if (ch == pad64)
- b64rmap[i] = b64rmap_end;
- else
- b64rmap[i] = b64rmap_invalid;
- }
- for (i = 0; base64[i] != '\0'; ++i)
- b64rmap[(uint8_t)base64[i]] = i;
- b64rmap_initialized = 1;
- }
-
- state = 0;
- tarindex = 0;
-
- for (;;) {
- ch = *src++;
- ofs = b64rmap[ch];
-
- if (ofs >= b64rmap_special) {
- if (ofs == b64rmap_space)
- continue;
- if (ofs == b64rmap_end)
- break;
- return -1;
- }
-
- switch (state) {
- case 0:
- if ((size_t)tarindex >= targsize)
- return -1;
- target[tarindex] = ofs << 2;
- state = 1;
- break;
- case 1:
- if ((size_t)tarindex + 1 >= targsize)
- return -1;
- target[tarindex] |= ofs >> 4;
- target[tarindex+1] = (ofs & 0x0f) << 4 ;
- tarindex++;
- state = 2;
- break;
- case 2:
- if ((size_t)tarindex + 1 >= targsize)
- return -1;
- target[tarindex] |= ofs >> 2;
- target[tarindex+1] = (ofs & 0x03) << 6;
- tarindex++;
- state = 3;
- break;
- case 3:
- if ((size_t)tarindex >= targsize)
- return -1;
- target[tarindex] |= ofs;
- tarindex++;
- state = 0;
- break;
- default:
- abort();
- }
- }
+ unsigned int i;
+ for (i = 0; i < WG_KEY_LEN / 3; ++i)
+ encode(&base64[i * 4], &key[i * 3]);
+ encode(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
+ base64[WG_KEY_LEN_BASE64 - 2] = '=';
+ base64[WG_KEY_LEN_BASE64 - 1] = '\0';
+}
- if (ch == pad64) {
- ch = *src++;
- switch (state) {
- case 0:
- case 1:
- return -1;
+static inline int decode(const char src[4])
+{
+ int val = 0;
+ for (unsigned int i = 0; i < 4; ++i)
+ val |= (-1
+ + ((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) & (src[i] - 64))
+ + ((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) & (src[i] - 70))
+ + ((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5))
+ + ((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63)
+ + ((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64)
+ ) << (18 - 6 * i);
+ return val;
+}
- case 2:
- for (; ch; ch = *src++) {
- if (b64rmap[ch] != b64rmap_space)
- break;
- }
- if (ch != pad64)
- return -1;
- ch = *src++;
- case 3:
- for (; ch; ch = *src++) {
- if (b64rmap[ch] != b64rmap_space)
- return -1;
- }
- if (target[tarindex] != 0)
- return -1;
- }
- } else {
- if (state != 0)
- return -1;
+bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
+{
+ unsigned int i;
+ int val;
+ if (strlen(base64) != WG_KEY_LEN_BASE64 - 1 || base64[WG_KEY_LEN_BASE64 - 2] != '=')
+ return false;
+
+ for (i = 0; i < WG_KEY_LEN / 3; ++i) {
+ val = decode(&base64[i * 4]);
+ if (val < 0)
+ return false;
+ key[i * 3 + 0] = (val >> 16) & 0xff;
+ key[i * 3 + 1] = (val >> 8) & 0xff;
+ key[i * 3 + 2] = val & 0xff;
}
-
- return tarindex;
+ val = decode((const char[]){ base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A' });
+ if (val < 0 || val & 0xff)
+ return false;
+ key[i * 3 + 0] = (val >> 16) & 0xff;
+ key[i * 3 + 1] = (val >> 8) & 0xff;
+ return true;
}
-#endif
diff --git a/src/tools/base64.h b/src/tools/base64.h
index 4ad0ac3..37cf1b9 100644
--- a/src/tools/base64.h
+++ b/src/tools/base64.h
@@ -3,18 +3,13 @@
#ifndef BASE64_H
#define BASE64_H
-#include <resolv.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "../uapi.h"
-#define b64_len(len) ((((len) + 2) / 3) * 4 + 1)
+#define WG_KEY_LEN_BASE64 ((((WG_KEY_LEN) + 2) / 3) * 4 + 1)
-#ifndef b64_ntop
-int b64_ntop(unsigned char const *, size_t, char *, size_t);
-#define NEED_B64_NTOP
-#endif
-
-#ifndef b64_pton
-int b64_pton(char const *, unsigned char *, size_t);
-#define NEED_B64_PTON
-#endif
+void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN]);
+bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64);
#endif
diff --git a/src/tools/config.c b/src/tools/config.c
index e95626c..8f75804 100644
--- a/src/tools/config.c
+++ b/src/tools/config.c
@@ -118,12 +118,10 @@ static inline bool parse_fwmark(uint32_t *fwmark, unsigned int *flags, const cha
static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char *value)
{
- uint8_t tmp[WG_KEY_LEN + 1];
- if (strlen(value) != b64_len(WG_KEY_LEN) - 1 || b64_pton(value, tmp, WG_KEY_LEN + 1) != WG_KEY_LEN) {
+ if (!key_from_base64(key, value)) {
fprintf(stderr, "Key is not the correct length or format: `%s`\n", value);
return false;
}
- memcpy(key, tmp, WG_KEY_LEN);
return true;
}
diff --git a/src/tools/genkey.c b/src/tools/genkey.c
index d3bc846..bf35aed 100644
--- a/src/tools/genkey.c
+++ b/src/tools/genkey.c
@@ -34,8 +34,8 @@ static inline ssize_t get_random_bytes(uint8_t *out, size_t len)
int genkey_main(int argc, char *argv[])
{
- unsigned char private_key[CURVE25519_POINT_SIZE];
- char private_key_base64[b64_len(CURVE25519_POINT_SIZE)];
+ uint8_t key[WG_KEY_LEN];
+ char base64[WG_KEY_LEN_BASE64];
struct stat stat;
if (argc != 1) {
@@ -46,19 +46,14 @@ int genkey_main(int argc, char *argv[])
if (!fstat(STDOUT_FILENO, &stat) && S_ISREG(stat.st_mode) && stat.st_mode & S_IRWXO)
fputs("Warning: writing to world accessible file.\nConsider setting the umask to 077 and trying again.\n", stderr);
- if (get_random_bytes(private_key, CURVE25519_POINT_SIZE) != CURVE25519_POINT_SIZE) {
+ if (get_random_bytes(key, WG_KEY_LEN) != WG_KEY_LEN) {
perror("getrandom");
return 1;
}
if (argc && !strcmp(argv[0], "genkey"))
- curve25519_normalize_secret(private_key);
+ curve25519_normalize_secret(key);
- if (b64_ntop(private_key, sizeof(private_key), private_key_base64, sizeof(private_key_base64)) != sizeof(private_key_base64) - 1) {
- fprintf(stderr, "%s: Could not convert key to base64\n", PROG_NAME);
- return 1;
- }
-
- puts(private_key_base64);
+ key_to_base64(base64, key);
+ puts(base64);
return 0;
-
}
diff --git a/src/tools/ipc.c b/src/tools/ipc.c
index c26da21..ed18128 100644
--- a/src/tools/ipc.c
+++ b/src/tools/ipc.c
@@ -177,7 +177,7 @@ static int userspace_set_device(struct wgdevice *dev)
if (fd < 0)
return fd;
for_each_wgpeer(dev, peer, len);
- len = (unsigned char *)peer - (unsigned char *)dev;
+ len = (uint8_t *)peer - (uint8_t *)dev;
ret = -EBADMSG;
if (!len)
goto out;
diff --git a/src/tools/pubkey.c b/src/tools/pubkey.c
index f567223..009cd15 100644
--- a/src/tools/pubkey.c
+++ b/src/tools/pubkey.c
@@ -1,7 +1,6 @@
/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
#include <errno.h>
-#include <resolv.h>
#include <stdio.h>
#include <ctype.h>
@@ -11,8 +10,8 @@
int pubkey_main(int argc, char *argv[])
{
- unsigned char private_key[CURVE25519_POINT_SIZE + 1] = { 0 }, public_key[CURVE25519_POINT_SIZE] = { 0 };
- char private_key_base64[b64_len(CURVE25519_POINT_SIZE)] = { 0 }, public_key_base64[b64_len(CURVE25519_POINT_SIZE)] = { 0 };
+ uint8_t key[WG_KEY_LEN];
+ char base64[WG_KEY_LEN_BASE64];
int trailing_char;
if (argc != 1) {
@@ -20,11 +19,12 @@ int pubkey_main(int argc, char *argv[])
return 1;
}
- if (fread(private_key_base64, 1, sizeof(private_key_base64) - 1, stdin) != sizeof(private_key_base64) - 1) {
+ if (fread(base64, 1, sizeof(base64) - 1, stdin) != sizeof(base64) - 1) {
errno = EINVAL;
fprintf(stderr, "%s: Key is not the correct length or format\n", PROG_NAME);
return 1;
}
+ base64[WG_KEY_LEN_BASE64 - 1] = '\0';
for (;;) {
trailing_char = getc(stdin);
@@ -36,15 +36,12 @@ int pubkey_main(int argc, char *argv[])
return 1;
}
- if (b64_pton(private_key_base64, private_key, sizeof(private_key)) != sizeof(private_key) - 1) {
+ if (!key_from_base64(key, base64)) {
fprintf(stderr, "%s: Key is not the correct length or format\n", PROG_NAME);
return 1;
}
- curve25519_generate_public(public_key, private_key);
- if (b64_ntop(public_key, sizeof(public_key), public_key_base64, sizeof(public_key_base64)) != sizeof(public_key_base64) - 1) {
- fprintf(stderr, "%s: Could not convert key to base64\n", PROG_NAME);
- return 1;
- }
- puts(public_key_base64);
+ curve25519_generate_public(key, key);
+ key_to_base64(base64, key);
+ puts(base64);
return 0;
}
diff --git a/src/tools/show.c b/src/tools/show.c
index 7b057cf..c9ba473 100644
--- a/src/tools/show.c
+++ b/src/tools/show.c
@@ -4,7 +4,6 @@
#include <inttypes.h>
#include <netinet/in.h>
#include <net/if.h>
-#include <resolv.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -78,17 +77,16 @@ static void sort_peers(struct wgdevice *device)
static const uint8_t zero[WG_KEY_LEN] = { 0 };
-static char *key(const unsigned char key[static WG_KEY_LEN])
+static char *key(const uint8_t key[static WG_KEY_LEN])
{
- static char b64[b64_len(WG_KEY_LEN)];
+ static char base64[WG_KEY_LEN_BASE64];
if (!memcmp(key, zero, WG_KEY_LEN))
return "(none)";
- memset(b64, 0, b64_len(WG_KEY_LEN));
- b64_ntop(key, WG_KEY_LEN, b64, b64_len(WG_KEY_LEN));
- return b64;
+ key_to_base64(base64, key);
+ return base64;
}
-static char *masked_key(const unsigned char masked_key[static WG_KEY_LEN])
+static char *masked_key(const uint8_t masked_key[static WG_KEY_LEN])
{
const char *var = getenv("WG_HIDE_KEYS");
if (var && !strcmp(var, "never"))
diff --git a/src/tools/showconf.c b/src/tools/showconf.c
index 585b08d..da48486 100644
--- a/src/tools/showconf.c
+++ b/src/tools/showconf.c
@@ -3,7 +3,6 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
-#include <resolv.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
@@ -18,7 +17,7 @@
int showconf_main(int argc, char *argv[])
{
static const uint8_t zero[WG_KEY_LEN] = { 0 };
- char b64[b64_len(WG_KEY_LEN)] = { 0 };
+ char base64[WG_KEY_LEN_BASE64];
char ip[INET6_ADDRSTRLEN];
struct wgdevice *device = NULL;
struct wgpeer *peer;
@@ -48,17 +47,17 @@ int showconf_main(int argc, char *argv[])
if (device->fwmark)
printf("FwMark = 0x%x\n", device->fwmark);
if (memcmp(device->private_key, zero, WG_KEY_LEN)) {
- b64_ntop(device->private_key, WG_KEY_LEN, b64, b64_len(WG_KEY_LEN));
- printf("PrivateKey = %s\n", b64);
+ key_to_base64(base64, device->private_key);
+ printf("PrivateKey = %s\n", base64);
}
if (memcmp(device->preshared_key, zero, WG_KEY_LEN)) {
- b64_ntop(device->preshared_key, WG_KEY_LEN, b64, b64_len(WG_KEY_LEN));
- printf("PresharedKey = %s\n", b64);
+ key_to_base64(base64, device->preshared_key);
+ printf("PresharedKey = %s\n", base64);
}
printf("\n");
for_each_wgpeer(device, peer, i) {
- b64_ntop(peer->public_key, WG_KEY_LEN, b64, b64_len(WG_KEY_LEN));
- printf("[Peer]\nPublicKey = %s\n", b64);
+ key_to_base64(base64, peer->public_key);
+ printf("[Peer]\nPublicKey = %s\n", base64);
if (peer->num_ipmasks)
printf("AllowedIPs = ");
for_each_wgipmask(peer, ipmask, j) {