*/
#include "system.h"
-#include "crypto.h"
#include "conf.h"
#include "control.h"
#include "control_common.h"
#include "route.h"
#include "utils.h"
#include "xalloc.h"
+#include "random.h"
char controlcookie[65];
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "../system.h"
+#include "crypto.h"
-#include <gcrypt.h>
-
-#include "../crypto.h"
-
-void crypto_init(void) {
-}
-
-void crypto_exit(void) {
-}
-
-void randomize(void *out, size_t outlen) {
- gcry_create_nonce(out, outlen);
-}
+// No-op for those cryptographic libraries that
+// do not require any additional initialization.
+void crypto_init(void) {}
*/
extern void crypto_init(void);
-extern void crypto_exit(void);
extern uint64_t xoshiro(void);
extern void prng_init(void);
extern void prng_randomize(void *buf, size_t buflen);
-extern void randomize(void *buf, size_t buflen);
static inline uint32_t prng(uint32_t limit) {
uint64_t bins = UINT64_MAX / limit;
*/
#include "../system.h"
+#include "../random.h"
#include "ed25519.h"
uint8_t private[64];
} ecdh_t;
-#include "../crypto.h"
#include "../ecdh.h"
#include "../xalloc.h"
uint8_t public[32];
} ecdsa_t;
-#include "../crypto.h"
#include "../ecdsagen.h"
#include "../utils.h"
#include "../xalloc.h"
+#include "../random.h"
// Generate ECDSA key
src_lib_crypto = files(
'cipher.c',
- 'crypto.c',
'digest.c',
'pem.c',
'prf.c',
#include <syslog.h>
#endif
+#ifdef HAVE_SYS_RANDOM_H
+#include <sys/random.h>
+#endif
+
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
-
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "tincctl.h"
#include "utils.h"
#include "xalloc.h"
+#include "random.h"
#include "ed25519/sha512.h"
check_headers += [
'linux/if_tun.h',
- 'sys/epoll.h',
'netpacket/packet.h',
+ 'sys/epoll.h',
+ 'sys/random.h',
]
-check_functions += 'recvmmsg'
+check_functions += [
+ 'recvmmsg',
+ 'getrandom',
+]
src_tincd += files('device.c')
'dropin.c',
'keys.c',
'list.c',
+ 'logger.c',
'names.c',
'netutl.c',
'script.c',
'utils.c',
'version.c',
'xoshiro.c',
- 'logger.c',
]
src_tinc = [
deps_tinc = []
deps_tincd = [cc.find_library('m', required: false)]
+if os_name != 'windows'
+ src_lib_common += 'random.c'
+endif
+
if os_name in ['linux', 'android']
subdir('linux')
elif os_name.endswith('bsd') or os_name in ['dragonfly', 'darwin']
subdir(opt_crypto)
+if opt_crypto != 'openssl'
+ src_lib_crypto += 'crypto.c'
+endif
+
if opt_crypto != 'nolegacy'
src_lib_crypto += ['cipher.c', 'digest.c']
endif
#include "protocol.h"
#include "route.h"
#include "utils.h"
+#include "random.h"
/* The minimum size of a probe is 14 bytes, but since we normally use CBC mode
encryption, we can add a few extra random bytes without increasing the
+++ /dev/null
-/*
- crypto.c -- Cryptographic miscellaneous functions and initialisation
- Copyright (C) 2007-2021 Guus Sliepen <guus@tinc-vpn.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#include "../system.h"
-
-#include "../crypto.h"
-
-#ifndef HAVE_WINDOWS
-
-static int random_fd = -1;
-
-static void random_init(void) {
- random_fd = open("/dev/urandom", O_RDONLY);
-
- if(random_fd < 0) {
- random_fd = open("/dev/random", O_RDONLY);
- }
-
- if(random_fd < 0) {
- fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno));
- abort();
- }
-}
-
-static void random_exit(void) {
- close(random_fd);
-}
-
-void randomize(void *vout, size_t outlen) {
- uint8_t *out = vout;
-
- while(outlen) {
- ssize_t len = read(random_fd, out, outlen);
-
- if(len <= 0) {
- if(len == -1 && (errno == EAGAIN || errno == EINTR)) {
- continue;
- }
-
- fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno));
- abort();
- }
-
- out += len;
- outlen -= len;
- }
-}
-
-#else
-
-#include <wincrypt.h>
-HCRYPTPROV prov;
-
-static void random_init(void) {
- if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- fprintf(stderr, "CryptAcquireContext() failed!\n");
- abort();
- }
-}
-
-static void random_exit(void) {
- CryptReleaseContext(prov, 0);
-}
-
-void randomize(void *out, size_t outlen) {
- if(!CryptGenRandom(prov, outlen, out)) {
- fprintf(stderr, "CryptGenRandom() failed\n");
- abort();
- }
-}
-
-#endif
-
-void crypto_init(void) {
- random_init();
-}
-
-void crypto_exit(void) {
- random_exit();
-}
-src_lib_crypto = files(
- 'crypto.c',
- 'prf.c',
-)
+src_lib_crypto = files('prf.c')
dep_crypto = dependency('', required: false)
#include "../crypto.h"
-#ifndef HAVE_WINDOWS
-
-static int random_fd = -1;
-
-static void random_init(void) {
- random_fd = open("/dev/urandom", O_RDONLY);
-
- if(random_fd < 0) {
- random_fd = open("/dev/random", O_RDONLY);
- }
-
- if(random_fd < 0) {
- fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno));
- abort();
- }
-}
-
-static void random_exit(void) {
- close(random_fd);
-}
-
-void randomize(void *vout, size_t outlen) {
- uint8_t *out = vout;
-
- while(outlen) {
- ssize_t len = read(random_fd, out, outlen);
-
- if(len <= 0) {
- if(len == -1 && (errno == EAGAIN || errno == EINTR)) {
- continue;
- }
-
- fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno));
- abort();
- }
-
- out += len;
- outlen -= len;
- }
-}
-
-#else
-
-#include <wincrypt.h>
-HCRYPTPROV prov;
-
-static void random_init(void) {
- if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- fprintf(stderr, "CryptAcquireContext() failed!\n");
- abort();
- }
-}
-
-static void random_exit(void) {
- CryptReleaseContext(prov, 0);
-}
-
-void randomize(void *out, size_t outlen) {
- if(!CryptGenRandom(prov, outlen, out)) {
- fprintf(stderr, "CryptGenRandom() failed\n");
- abort();
- }
-}
-
-#endif
-
void crypto_init(void) {
- random_init();
-
#if OPENSSL_VERSION_MAJOR < 3
ENGINE_load_builtin_engines();
#endif
abort();
}
}
-
-void crypto_exit(void) {
- random_exit();
-}
#include "control.h"
#include "control_common.h"
#include "cipher.h"
-#include "crypto.h"
#include "digest.h"
#include "ecdsa.h"
#include "edge.h"
#include "sptps.h"
#include "utils.h"
#include "xalloc.h"
+#include "random.h"
#include "ed25519/sha512.h"
#include "keys.h"
#include "sptps.h"
#include "utils.h"
#include "compression.h"
+#include "random.h"
void send_key_changed(void) {
#ifndef DISABLE_LEGACY
--- /dev/null
+#include "system.h"
+
+#include "random.h"
+
+#ifndef HAVE_GETRANDOM
+static int random_fd = -1;
+#endif
+
+void random_init(void) {
+#ifndef HAVE_GETRANDOM
+ random_fd = open("/dev/urandom", O_RDONLY);
+
+ if(random_fd < 0) {
+ random_fd = open("/dev/random", O_RDONLY);
+ }
+
+ if(random_fd < 0) {
+ fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno));
+ abort();
+ }
+
+#endif
+}
+
+void random_exit(void) {
+#ifndef HAVE_GETRANDOM
+ close(random_fd);
+#endif
+}
+
+void randomize(void *vout, size_t outlen) {
+ uint8_t *out = vout;
+
+ while(outlen) {
+#ifdef HAVE_GETRANDOM
+ ssize_t len = getrandom(out, outlen, 0);
+#else
+ ssize_t len = read(random_fd, out, outlen);
+#endif
+
+ if(len <= 0) {
+ if(len == -1 && (errno == EAGAIN || errno == EINTR)) {
+ continue;
+ }
+
+ fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno));
+ abort();
+ }
+
+ out += len;
+ outlen -= len;
+ }
+}
--- /dev/null
+#ifndef TINC_RANDOM_H
+#define TINC_RANDOM_H
+
+#include "system.h"
+
+extern void random_init(void);
+extern void random_exit(void);
+extern void randomize(void *vout, size_t outlen);
+
+#endif // TINC_RANDOM_H
#include "system.h"
#include "chacha-poly1305/chacha-poly1305.h"
-#include "crypto.h"
#include "ecdh.h"
#include "ecdsa.h"
#include "logger.h"
#include "prf.h"
#include "sptps.h"
+#include "random.h"
unsigned int sptps_replaywin = 16;
#include "system.h"
#include "crypto.h"
+#include "random.h"
#include "ecdsagen.h"
#include "logger.h"
#include "names.h"
{NULL, 0, NULL, 0}
};
-int main(int argc, char *argv[]) {
- program_name = argv[0];
- int r;
- int option_index = 0;
-
- while((r = getopt_long(argc, argv, "", long_options, &option_index)) != EOF) {
- switch(r) {
- case 0: /* long option */
- break;
-
- case '?': /* wrong options */
- usage();
- return 1;
-
- case 1: /* help */
- usage();
- return 0;
-
- default:
- break;
- }
- }
-
- argc -= optind - 1;
- argv += optind - 1;
-
- if(argc != 3) {
- fprintf(stderr, "Wrong number of arguments.\n");
- usage();
- return 1;
- }
-
- crypto_init();
-
+static int generate_keypair(char *argv[]) {
ecdsa_t *key = ecdsa_generate();
if(!key) {
return 1;
}
}
+
+int main(int argc, char *argv[]) {
+ program_name = argv[0];
+ int r;
+ int option_index = 0;
+
+ while((r = getopt_long(argc, argv, "", long_options, &option_index)) != EOF) {
+ switch(r) {
+ case 0: /* long option */
+ break;
+
+ case '?': /* wrong options */
+ usage();
+ return 1;
+
+ case 1: /* help */
+ usage();
+ return 0;
+
+ default:
+ break;
+ }
+ }
+
+ argc -= optind - 1;
+ argv += optind - 1;
+
+ if(argc != 3) {
+ fprintf(stderr, "Wrong number of arguments.\n");
+ usage();
+ return 1;
+ }
+
+ random_init();
+ crypto_init();
+
+ int result = generate_keypair(argv);
+
+ random_exit();
+
+ return result;
+}
#include "meta.h"
#include "protocol.h"
#include "sptps.h"
+#include "random.h"
// Symbols necessary to link with logger.o
bool send_request(struct connection_t *c, const char *msg, ...) {
return false;
}
-int main(int argc, char *argv[]) {
+static int run_benchmark(int argc, char *argv[]) {
ecdsa_t *key1, *key2;
ecdh_t *ecdh1, *ecdh2;
sptps_t sptps1, sptps2;
uint8_t buf1[4096], buf2[4096], buf3[4096];
double duration = argc > 1 ? atof(argv[1]) : 10;
- crypto_init();
-
randomize(buf1, sizeof(buf1));
randomize(buf2, sizeof(buf2));
randomize(buf3, sizeof(buf3));
close(fd[1]);
ecdsa_free(key1);
ecdsa_free(key2);
- crypto_exit();
return 0;
}
+
+int main(int argc, char *argv[]) {
+ random_init();
+ crypto_init();
+
+ int result = run_benchmark(argc, argv);
+
+ random_exit();
+
+ return result;
+}
#include "sptps.h"
#include "utils.h"
#include "names.h"
+#include "random.h"
#ifndef HAVE_WINDOWS
#define closesocket(s) close(s)
fflush(stderr);
}
-int main(int argc, char *argv[]) {
+static int run_test(int argc, char *argv[]) {
program_name = argv[0];
bool initiator = false;
bool datagram = false;
fprintf(stderr, "Connected\n");
}
- crypto_init();
- prng_init();
-
FILE *fp = fopen(argv[1], "r");
if(!fp) {
free(mykey);
free(hiskey);
+ closesocket(sock);
- if(!stopped) {
- return 1;
- }
+ return !stopped;
+}
- closesocket(sock);
+int main(int argc, char *argv[]) {
+ random_init();
+ crypto_init();
+ prng_init();
- return 0;
+ int result = run_test(argc, argv);
+
+ random_exit();
+
+ return result;
}
#include "version.h"
#include "subnet.h"
#include "keys.h"
+#include "random.h"
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
free_names();
}
+static int run_command(int argc, char *argv[]) {
+ if(optind >= argc) {
+ return cmd_shell(argc, argv);
+ }
+
+ for(int i = 0; commands[i].command; i++) {
+ if(!strcasecmp(argv[optind], commands[i].command)) {
+ return commands[i].function(argc - optind, argv + optind);
+ }
+ }
+
+ fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
+ usage(true);
+ return 1;
+}
+
int main(int argc, char *argv[]) {
program_name = argv[0];
orig_argv = argv;
#endif
gettimeofday(&now, NULL);
+ random_init();
crypto_init();
prng_init();
- if(optind >= argc) {
- return cmd_shell(argc, argv);
- }
+ int result = run_command(argc, argv);
- for(int i = 0; commands[i].command; i++) {
- if(!strcasecmp(argv[optind], commands[i].command)) {
- return commands[i].function(argc - optind, argv + optind);
- }
- }
+ random_exit();
- fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
- usage(true);
- return 1;
+ return result;
}
#include "utils.h"
#include "xalloc.h"
#include "version.h"
+#include "random.h"
/* If nonzero, display usage information and exit. */
static bool show_help = false;
#endif
gettimeofday(&now, NULL);
+ random_init();
crypto_init();
prng_init();
free(priority);
- crypto_exit();
+ random_exit();
return status;
}
deps_common += dep
endforeach
+src_lib_common += files('random.c')
src_tincd += files('device.c')
--- /dev/null
+#include "../system.h"
+
+#include <wincrypt.h>
+
+#include "../random.h"
+
+static HCRYPTPROV prov;
+
+void random_init(void) {
+ if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ fprintf(stderr, "CryptAcquireContext() failed!\n");
+ abort();
+ }
+}
+
+void random_exit(void) {
+ CryptReleaseContext(prov, 0);
+}
+
+void randomize(void *vout, size_t outlen) {
+ if(!CryptGenRandom(prov, outlen, vout)) {
+ fprintf(stderr, "CryptGenRandom() failed\n");
+ abort();
+ }
+}
#include "system.h"
#include "crypto.h"
+#include "random.h"
/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid
generators. It has excellent (sub-ns) speed, a state (256 bits) that is
# 'code': 'test1.c', // or ['test1.c', 'test1_util.c']
# 'mock': ['foo', 'bar'], // list of functions to mock (default: empty)
# 'link': link_tinc, // which binary to link with (default: tincd)
+# 'fail': true, // whether the test should fail (default: false)
# }
tests = {
+ 'random': {
+ 'code': 'test_random.c',
+ },
+ 'random_noinit': {
+ 'code': 'test_random_noinit.c',
+ 'fail': true,
+ },
'net': {
'code': 'test_net.c',
'mock': ['execute_script', 'environment_init', 'environment_exit'],
include_directories: inc_conf,
build_by_default: false)
+ must_fail = data.get('fail', false)
+
test(test,
exe,
suite: 'unit',
timeout: 60,
- protocol: 'tap',
- env: env)
+ protocol: must_fail ? 'exitcode' : 'tap',
+ env: env,
+ should_fail: must_fail)
endforeach
--- /dev/null
+#include "unittest.h"
+#include "../../src/random.h"
+#include "../../src/xalloc.h"
+
+static int setup(void **state) {
+ (void)state;
+ random_init();
+ return 0;
+}
+
+static int teardown(void **state) {
+ (void)state;
+ random_exit();
+ return 0;
+}
+
+#define zerolen 128
+static const uint8_t zero[zerolen] = {0};
+
+static void test_randomize_zero_must_not_change_memory(void **state) {
+ (void)state;
+
+ uint8_t buf[zerolen] = {0};
+ randomize(buf, 0);
+
+ assert_memory_equal(zero, buf, sizeof(buf));
+}
+
+static void test_randomize_does_not_overflow(void **state) {
+ (void)state;
+
+ uint8_t buf[zerolen] = {0};
+ const size_t half = sizeof(buf) / 2;
+ randomize(buf, half);
+
+ assert_memory_not_equal(zero, buf, half);
+ assert_memory_equal(zero, &buf[half], half);
+}
+
+static void test_randomize_full_changes_memory(void **state) {
+ (void)state;
+
+ uint8_t buf[zerolen] = {0};
+ randomize(buf, sizeof(buf));
+
+ assert_memory_not_equal(zero, buf, sizeof(buf));
+}
+
+static void test_randomize_does_not_repeat(void **state) {
+ (void)state;
+
+ // Ask randomize() for small chunks so there's more
+ // chance for it to repeat itself (within reason).
+#define chunklen 16
+
+ const size_t chunks = 1024;
+ uint8_t (*buffers)[chunklen] = xzalloc(chunks * chunklen);
+
+ // Fill buffers with (hopefully) random data
+ for(size_t i = 0; i < chunks; ++i) {
+ randomize(buffers[i], chunklen);
+
+ // Check there was no overflow to the right
+ if(i < chunks - 1) {
+ assert_memory_equal(zero, buffers[i + 1], chunklen);
+ }
+ }
+
+ // Check there were no repetitions (with 128-bit buffers collisions are very unlikely)
+ for(size_t i = 0; i < chunks - 1; ++i) {
+ for(size_t j = i + 1; j < chunks; ++j) {
+ assert_memory_not_equal(buffers[i], buffers[j], chunklen);
+ }
+ }
+
+ free(buffers);
+#undef chunklen
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_randomize_zero_must_not_change_memory),
+ cmocka_unit_test(test_randomize_does_not_overflow),
+ cmocka_unit_test(test_randomize_full_changes_memory),
+ cmocka_unit_test(test_randomize_does_not_repeat),
+ };
+ return cmocka_run_group_tests(tests, setup, teardown);
+}
--- /dev/null
+// Test that randomize() kills the process when called without initialization
+
+#include "unittest.h"
+
+#ifdef HAVE_GETRANDOM
+int main(void) {
+ return 1;
+}
+#else
+#include "../../src/random.h"
+
+static void on_abort(int sig) {
+ (void)sig;
+ exit(1);
+}
+
+int main(void) {
+ signal(SIGABRT, on_abort);
+ u_int8_t buf[16];
+ randomize(buf, sizeof(buf));
+ return 0;
+}
+#endif // HAVE_GETRANDOM