1// SPDX-License-Identifier: GPL-2.0 OR MIT
2/*
3 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4 */
5
6#include <errno.h>
7#include <stdio.h>
8#include <stdbool.h>
9#include <unistd.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <string.h>
13#include <fcntl.h>
14#ifdef __linux__
15#include <sys/syscall.h>
16#endif
17#ifdef __APPLE__
18#include <AvailabilityMacros.h>
19#ifndef MAC_OS_X_VERSION_10_12
20#define MAC_OS_X_VERSION_10_12 101200
21#endif
22#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
23#include <sys/random.h>
24#endif
25#endif
26
27#include "curve25519.h"
28#include "encoding.h"
29#include "subcommands.h"
30
31#ifndef _WIN32
32static inline bool __attribute__((__warn_unused_result__)) get_random_bytes(uint8_t *out, size_t len)
33{
34	ssize_t ret = 0;
35	size_t i;
36	int fd;
37
38	if (len > 256) {
39		errno = EOVERFLOW;
40		return false;
41	}
42
43#if defined(__OpenBSD__) || (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) || (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)))
44	if (!getentropy(out, len))
45		return true;
46#endif
47
48#if defined(__NR_getrandom) && defined(__linux__)
49	if (syscall(__NR_getrandom, out, len, 0) == (ssize_t)len)
50		return true;
51#endif
52
53	fd = open("/dev/urandom", O_RDONLY);
54	if (fd < 0)
55		return false;
56	for (errno = 0, i = 0; i < len; i += ret, ret = 0) {
57		ret = read(fd, out + i, len - i);
58		if (ret <= 0) {
59			ret = errno ? -errno : -EIO;
60			break;
61		}
62	}
63	close(fd);
64	errno = -ret;
65	return i == len;
66}
67#else
68#include <ntsecapi.h>
69static inline bool __attribute__((__warn_unused_result__)) get_random_bytes(uint8_t *out, size_t len)
70{
71        return RtlGenRandom(out, len);
72}
73#endif
74
75int genkey_main(int argc, const char *argv[])
76{
77	uint8_t key[WG_KEY_LEN];
78	char base64[WG_KEY_LEN_BASE64];
79	struct stat stat;
80
81	if (argc != 1) {
82		fprintf(stderr, "Usage: %s %s\n", PROG_NAME, argv[0]);
83		return 1;
84	}
85
86	if (!fstat(STDOUT_FILENO, &stat) && S_ISREG(stat.st_mode) && stat.st_mode & S_IRWXO)
87		fputs("Warning: writing to world accessible file.\nConsider setting the umask to 077 and trying again.\n", stderr);
88
89	if (!get_random_bytes(key, WG_KEY_LEN)) {
90		perror("getrandom");
91		return 1;
92	}
93	if (!strcmp(argv[0], "genkey"))
94		curve25519_clamp_secret(key);
95
96	key_to_base64(base64, key);
97	puts(base64);
98	return 0;
99}
100