diff options
Diffstat (limited to 'src/common')
35 files changed, 0 insertions, 10768 deletions
diff --git a/src/common/aes.c b/src/common/aes.c deleted file mode 100644 index 70e48a74f3..0000000000 --- a/src/common/aes.c +++ /dev/null @@ -1,409 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file aes.c - * \brief Implements a counter-mode stream cipher on top of AES. - **/ - -#include "orconfig.h" - -#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ - #include <winsock2.h> - #include <ws2tcpip.h> -#endif - -#include "common/compat_openssl.h" -#include <openssl/opensslv.h> -#include "common/crypto_openssl_mgt.h" - -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) -#error "We require OpenSSL >= 1.0.0" -#endif - -DISABLE_GCC_WARNING(redundant-decls) - -#include <stdlib.h> -#include <string.h> -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/modes.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#include "common/compat.h" -#include "common/aes.h" -#include "common/util.h" -#include "common/torlog.h" -#include "lib/ctime/di_ops.h" - -#ifdef ANDROID -/* Android's OpenSSL seems to have removed all of its Engine support. */ -#define DISABLE_ENGINES -#endif - -/* We have five strategies for implementing AES counter mode. - * - * Best with x86 and x86_64: Use EVP_aes_*_ctr() and EVP_EncryptUpdate(). - * This is possible with OpenSSL 1.0.1, where the counter-mode implementation - * can use bit-sliced or vectorized AES or AESNI as appropriate. - * - * Otherwise: Pick the best possible AES block implementation that OpenSSL - * gives us, and the best possible counter-mode implementation, and combine - * them. - */ -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,1,0) - -/* With newer OpenSSL versions, the older fallback modes don't compile. So - * don't use them, even if we lack specific acceleration. */ - -#define USE_EVP_AES_CTR - -#elif OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,0,1) && \ - (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || \ - defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__)) - -#define USE_EVP_AES_CTR - -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,1,0) || ... */ - -/* We have 2 strategies for getting the AES block cipher: Via OpenSSL's - * AES_encrypt function, or via OpenSSL's EVP_EncryptUpdate function. - * - * If there's any hardware acceleration in play, we want to be using EVP_* so - * we can get it. Otherwise, we'll want AES_*, which seems to be about 5% - * faster than indirecting through the EVP layer. - */ - -/* We have 2 strategies for getting a plug-in counter mode: use our own, or - * use OpenSSL's. - * - * Here we have a counter mode that's faster than the one shipping with - * OpenSSL pre-1.0 (by about 10%!). But OpenSSL 1.0.0 added a counter mode - * implementation faster than the one here (by about 7%). So we pick which - * one to used based on the Openssl version above. (OpenSSL 1.0.0a fixed a - * critical bug in that counter mode implementation, so we need to test to - * make sure that we have a fixed version.) - */ - -#ifdef USE_EVP_AES_CTR - -/* We don't actually define the struct here. */ - -aes_cnt_cipher_t * -aes_new_cipher(const uint8_t *key, const uint8_t *iv, int key_bits) -{ - EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new(); - const EVP_CIPHER *c; - switch (key_bits) { - case 128: c = EVP_aes_128_ctr(); break; - case 192: c = EVP_aes_192_ctr(); break; - case 256: c = EVP_aes_256_ctr(); break; - default: tor_assert(0); // LCOV_EXCL_LINE - } - EVP_EncryptInit(cipher, c, key, iv); - return (aes_cnt_cipher_t *) cipher; -} -void -aes_cipher_free_(aes_cnt_cipher_t *cipher_) -{ - if (!cipher_) - return; - EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; -#ifdef OPENSSL_1_1_API - EVP_CIPHER_CTX_reset(cipher); -#else - EVP_CIPHER_CTX_cleanup(cipher); -#endif - EVP_CIPHER_CTX_free(cipher); -} -void -aes_crypt_inplace(aes_cnt_cipher_t *cipher_, char *data, size_t len) -{ - int outl; - EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *) cipher_; - - tor_assert(len < INT_MAX); - - EVP_EncryptUpdate(cipher, (unsigned char*)data, - &outl, (unsigned char*)data, (int)len); -} -int -evaluate_evp_for_aes(int force_val) -{ - (void) force_val; - log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP " - "counter-mode implementation. Using it."); - return 0; -} -int -evaluate_ctr_for_aes(void) -{ - return 0; -} -#else /* !(defined(USE_EVP_AES_CTR)) */ - -/*======================================================================*/ -/* Interface to AES code, and counter implementation */ - -/** Implements an AES counter-mode cipher. */ -struct aes_cnt_cipher { -/** This next element (however it's defined) is the AES key. */ - union { - EVP_CIPHER_CTX evp; - AES_KEY aes; - } key; - -#if !defined(WORDS_BIGENDIAN) -#define USING_COUNTER_VARS - /** These four values, together, implement a 128-bit counter, with - * counter0 as the low-order word and counter3 as the high-order word. */ - uint32_t counter3; - uint32_t counter2; - uint32_t counter1; - uint32_t counter0; -#endif /* !defined(WORDS_BIGENDIAN) */ - - union { - /** The counter, in big-endian order, as bytes. */ - uint8_t buf[16]; - /** The counter, in big-endian order, as big-endian words. Note that - * on big-endian platforms, this is redundant with counter3...0, - * so we just use these values instead. */ - uint32_t buf32[4]; - } ctr_buf; - - /** The encrypted value of ctr_buf. */ - uint8_t buf[16]; - /** Our current stream position within buf. */ - unsigned int pos; - - /** True iff we're using the evp implementation of this cipher. */ - uint8_t using_evp; -}; - -/** True iff we should prefer the EVP implementation for AES, either because - * we're testing it or because we have hardware acceleration configured */ -static int should_use_EVP = 0; - -/** Check whether we should use the EVP interface for AES. If <b>force_val</b> - * is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP - * if there is an engine enabled for aes-ecb. */ -int -evaluate_evp_for_aes(int force_val) -{ - ENGINE *e; - - if (force_val >= 0) { - should_use_EVP = force_val; - return 0; - } -#ifdef DISABLE_ENGINES - should_use_EVP = 0; -#else - e = ENGINE_get_cipher_engine(NID_aes_128_ecb); - - if (e) { - log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.", - ENGINE_get_name(e)); - should_use_EVP = 1; - } else { - log_info(LD_CRYPTO, "No AES engine found; using AES_* functions."); - should_use_EVP = 0; - } -#endif /* defined(DISABLE_ENGINES) */ - - return 0; -} - -/** Test the OpenSSL counter mode implementation to see whether it has the - * counter-mode bug from OpenSSL 1.0.0. If the implementation works, then - * we will use it for future encryption/decryption operations. - * - * We can't just look at the OpenSSL version, since some distributions update - * their OpenSSL packages without changing the version number. - **/ -int -evaluate_ctr_for_aes(void) -{ - /* Result of encrypting an all-zero block with an all-zero 128-bit AES key. - * This should be the same as encrypting an all-zero block with an all-zero - * 128-bit AES key in counter mode, starting at position 0 of the stream. - */ - static const unsigned char encrypt_zero[] = - "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e"; - unsigned char zero[16]; - unsigned char output[16]; - unsigned char ivec[16]; - unsigned char ivec_tmp[16]; - unsigned int pos, i; - AES_KEY key; - memset(zero, 0, sizeof(zero)); - memset(ivec, 0, sizeof(ivec)); - AES_set_encrypt_key(zero, 128, &key); - - pos = 0; - /* Encrypting a block one byte at a time should make the error manifest - * itself for known bogus openssl versions. */ - for (i=0; i<16; ++i) - AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos); - - if (fast_memneq(output, encrypt_zero, 16)) { - /* Counter mode is buggy */ - /* LCOV_EXCL_START */ - log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " - "quitting tor."); - exit(1); // exit ok: openssl is broken. - /* LCOV_EXCL_STOP */ - } - return 0; -} - -#if !defined(USING_COUNTER_VARS) -#define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)]) -#else -#define COUNTER(c, n) ((c)->counter ## n) -#endif - -static void aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, - int key_bits); -static void aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv); - -/** - * Return a newly allocated counter-mode AES128 cipher implementation, - * using the 128-bit key <b>key</b> and the 128-bit IV <b>iv</b>. - */ -aes_cnt_cipher_t* -aes_new_cipher(const uint8_t *key, const uint8_t *iv, int bits) -{ - aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t)); - - aes_set_key(result, key, bits); - aes_set_iv(result, iv); - - return result; -} - -/** Set the key of <b>cipher</b> to <b>key</b>, which is - * <b>key_bits</b> bits long (must be 128, 192, or 256). Also resets - * the counter to 0. - */ -static void -aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, int key_bits) -{ - if (should_use_EVP) { - const EVP_CIPHER *c = 0; - switch (key_bits) { - case 128: c = EVP_aes_128_ecb(); break; - case 192: c = EVP_aes_192_ecb(); break; - case 256: c = EVP_aes_256_ecb(); break; - default: tor_assert(0); // LCOV_EXCL_LINE - } - EVP_EncryptInit(&cipher->key.evp, c, key, NULL); - cipher->using_evp = 1; - } else { - AES_set_encrypt_key(key, key_bits,&cipher->key.aes); - cipher->using_evp = 0; - } - -#ifdef USING_COUNTER_VARS - cipher->counter0 = 0; - cipher->counter1 = 0; - cipher->counter2 = 0; - cipher->counter3 = 0; -#endif /* defined(USING_COUNTER_VARS) */ - - memset(cipher->ctr_buf.buf, 0, sizeof(cipher->ctr_buf.buf)); - - cipher->pos = 0; - - memset(cipher->buf, 0, sizeof(cipher->buf)); -} - -/** Release storage held by <b>cipher</b> - */ -void -aes_cipher_free_(aes_cnt_cipher_t *cipher) -{ - if (!cipher) - return; - if (cipher->using_evp) { - EVP_CIPHER_CTX_cleanup(&cipher->key.evp); - } - memwipe(cipher, 0, sizeof(aes_cnt_cipher_t)); - tor_free(cipher); -} - -#if defined(USING_COUNTER_VARS) -#define UPDATE_CTR_BUF(c, n) STMT_BEGIN \ - (c)->ctr_buf.buf32[3-(n)] = htonl((c)->counter ## n); \ - STMT_END -#else -#define UPDATE_CTR_BUF(c, n) -#endif /* defined(USING_COUNTER_VARS) */ - -/* Helper function to use EVP with openssl's counter-mode wrapper. */ -static void -evp_block128_fn(const uint8_t in[16], - uint8_t out[16], - const void *key) -{ - EVP_CIPHER_CTX *ctx = (void*)key; - int inl=16, outl=16; - EVP_EncryptUpdate(ctx, out, &outl, in, inl); -} - -/** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place. - * Uses the key in <b>cipher</b>, and advances the counter by <b>len</b> bytes - * as it encrypts. - */ -void -aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) -{ - /* Note that the "128" below refers to the length of the counter, - * not the length of the AES key. */ - if (cipher->using_evp) { - /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If - * it weren't disabled, it might be better just to use that. - */ - CRYPTO_ctr128_encrypt((const unsigned char *)data, - (unsigned char *)data, - len, - &cipher->key.evp, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos, - evp_block128_fn); - } else { - AES_ctr128_encrypt((const unsigned char *)data, - (unsigned char *)data, - len, - &cipher->key.aes, - cipher->ctr_buf.buf, - cipher->buf, - &cipher->pos); - } -} - -/** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value - * in <b>iv</b>. */ -static void -aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv) -{ -#ifdef USING_COUNTER_VARS - cipher->counter3 = ntohl(get_uint32(iv)); - cipher->counter2 = ntohl(get_uint32(iv+4)); - cipher->counter1 = ntohl(get_uint32(iv+8)); - cipher->counter0 = ntohl(get_uint32(iv+12)); -#endif /* defined(USING_COUNTER_VARS) */ - cipher->pos = 0; - memcpy(cipher->ctr_buf.buf, iv, 16); -} - -#endif /* defined(USE_EVP_AES_CTR) */ - diff --git a/src/common/aes.h b/src/common/aes.h deleted file mode 100644 index e1287d330e..0000000000 --- a/src/common/aes.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/* Implements a minimal interface to counter-mode AES. */ - -#ifndef TOR_AES_H -#define TOR_AES_H - -/** - * \file aes.h - * \brief Headers for aes.c - */ - -typedef struct aes_cnt_cipher aes_cnt_cipher_t; - -aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv, - int key_bits); -void aes_cipher_free_(aes_cnt_cipher_t *cipher); -#define aes_cipher_free(cipher) \ - FREE_AND_NULL(aes_cnt_cipher_t, aes_cipher_free_, (cipher)) -void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len); - -int evaluate_evp_for_aes(int force_value); -int evaluate_ctr_for_aes(void); - -#endif /* !defined(TOR_AES_H) */ - diff --git a/src/common/buffers_tls.c b/src/common/buffers_tls.c deleted file mode 100644 index 0a57b95529..0000000000 --- a/src/common/buffers_tls.c +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#define BUFFERS_PRIVATE -#include "orconfig.h" -#include <stddef.h> -#include "common/buffers.h" -#include "common/buffers_tls.h" -#include "common/compat.h" -#include "lib/compress/compress.h" -#include "common/util.h" -#include "lib/cc/torint.h" -#include "common/torlog.h" -#include "common/tortls.h" -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -/** As read_to_chunk(), but return (negative) error code on error, blocking, - * or TLS, and the number of bytes read otherwise. */ -static inline int -read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, - size_t at_most) -{ - int read_result; - - tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most); - read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most); - if (read_result < 0) - return read_result; - buf->datalen += read_result; - chunk->datalen += read_result; - return read_result; -} - -/** As read_to_buf, but reads from a TLS connection, and returns a TLS - * status value rather than the number of bytes read. - * - * Using TLS on OR connections complicates matters in two ways. - * - * First, a TLS stream has its own read buffer independent of the - * connection's read buffer. (TLS needs to read an entire frame from - * the network before it can decrypt any data. Thus, trying to read 1 - * byte from TLS can require that several KB be read from the network - * and decrypted. The extra data is stored in TLS's decrypt buffer.) - * Because the data hasn't been read by Tor (it's still inside the TLS), - * this means that sometimes a connection "has stuff to read" even when - * poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is - * used in connection.c to detect TLS objects with non-empty internal - * buffers and read from them again. - * - * Second, the TLS stream's events do not correspond directly to network - * events: sometimes, before a TLS stream can read, the network must be - * ready to write -- or vice versa. - */ -int -buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) -{ - int r = 0; - size_t total_read = 0; - - check_no_tls_errors(); - - if (BUG(buf->datalen >= INT_MAX)) - return -1; - if (BUG(buf->datalen >= INT_MAX - at_most)) - return -1; - - while (at_most > total_read) { - size_t readlen = at_most - total_read; - chunk_t *chunk; - if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { - chunk = buf_add_chunk_with_capacity(buf, at_most, 1); - if (readlen > chunk->memlen) - readlen = chunk->memlen; - } else { - size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); - chunk = buf->tail; - if (cap < readlen) - readlen = cap; - } - - r = read_to_chunk_tls(buf, chunk, tls, readlen); - if (r < 0) - return r; /* Error */ - tor_assert(total_read+r < INT_MAX); - total_read += r; - if ((size_t)r < readlen) /* eof, block, or no more to read. */ - break; - } - return (int)total_read; -} - -/** Helper for buf_flush_to_tls(): try to write <b>sz</b> bytes from chunk - * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write - * more if there is a forced pending write size.) On success, deduct the - * bytes written from *<b>buf_flushlen</b>. Return the number of bytes - * written on success, and a TOR_TLS error code on failure or blocking. - */ -static inline int -flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, - size_t sz, size_t *buf_flushlen) -{ - int r; - size_t forced; - char *data; - - forced = tor_tls_get_forced_write_size(tls); - if (forced > sz) - sz = forced; - if (chunk) { - data = chunk->data; - tor_assert(sz <= chunk->datalen); - } else { - data = NULL; - tor_assert(sz == 0); - } - r = tor_tls_write(tls, data, sz); - if (r < 0) - return r; - if (*buf_flushlen > (size_t)r) - *buf_flushlen -= r; - else - *buf_flushlen = 0; - buf_drain(buf, r); - log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.", - r,(int)*buf_flushlen,(int)buf->datalen); - return r; -} - -/** As buf_flush_to_socket(), but writes data to a TLS connection. Can write - * more than <b>flushlen</b> bytes. - */ -int -buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, - size_t *buf_flushlen) -{ - int r; - size_t flushed = 0; - ssize_t sz; - tor_assert(buf_flushlen); - if (BUG(*buf_flushlen > buf->datalen)) { - *buf_flushlen = buf->datalen; - } - if (BUG(flushlen > *buf_flushlen)) { - flushlen = *buf_flushlen; - } - sz = (ssize_t) flushlen; - - /* we want to let tls write even if flushlen is zero, because it might - * have a partial record pending */ - check_no_tls_errors(); - - do { - size_t flushlen0; - if (buf->head) { - if ((ssize_t)buf->head->datalen >= sz) - flushlen0 = sz; - else - flushlen0 = buf->head->datalen; - } else { - flushlen0 = 0; - } - - r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen); - if (r < 0) - return r; - flushed += r; - sz -= r; - if (r == 0) /* Can't flush any more now. */ - break; - } while (sz > 0); - tor_assert(flushed < INT_MAX); - return (int)flushed; -} - diff --git a/src/common/buffers_tls.h b/src/common/buffers_tls.h deleted file mode 100644 index d9d26c82bd..0000000000 --- a/src/common/buffers_tls.h +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_BUFFERS_TLS_H -#define TOR_BUFFERS_TLS_H - -struct buf_t; -struct tor_tls_t; - -int buf_read_from_tls(struct buf_t *buf, - struct tor_tls_t *tls, size_t at_most); -int buf_flush_to_tls(struct buf_t *buf, struct tor_tls_t *tls, - size_t sz, size_t *buf_flushlen); - -#endif /* !defined(TOR_BUFFERS_TLS_H) */ - diff --git a/src/common/ciphers.inc b/src/common/ciphers.inc deleted file mode 100644 index 0084b3e325..0000000000 --- a/src/common/ciphers.inc +++ /dev/null @@ -1,100 +0,0 @@ -/* This is an include file used to define the list of ciphers clients should - * advertise. Before including it, you should define the CIPHER and XCIPHER - * macros. - * - * This file was automatically generated by get_mozilla_ciphers.py; - * TLSv1.3 ciphers were added manually. - */ - -/* Here are the TLS1.3 ciphers. Note that we don't have XCIPHER instances - * here, since we don't want to ever fake them. - */ -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - CIPHER(0x1301, TLS1_3_TXT_AES_128_GCM_SHA256) -#endif -#ifdef TLS1_3_TXT_AES_256_GCM_SHA384 - CIPHER(0x1302, TLS1_3_TXT_AES_256_GCM_SHA384) -#endif -#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256 - CIPHER(0x1303, TLS1_3_TXT_CHACHA20_POLY1305_SHA256) -#endif -#ifdef TLS1_3_TXT_AES_128_CCM_SHA256 - CIPHER(0x1304, TLS1_3_TXT_AES_128_CCM_SHA256) -#endif - -/* Here's the machine-generated list. */ -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - CIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) -#else - XCIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - CIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256) -#else - XCIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 - CIPHER(0xcca9, TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305) -#else - XCIPHER(0xcca9, TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 - CIPHER(0xcca8, TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305) -#else - XCIPHER(0xcca8, TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - CIPHER(0xc02c, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) -#else - XCIPHER(0xc02c, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - CIPHER(0xc030, TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384) -#else - XCIPHER(0xc030, TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -#else - XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -#else - XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA - CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) -#else - XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA - CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) -#else - XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA - CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) -#else - XCIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA - CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) -#else - XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) -#endif -#ifdef TLS1_TXT_RSA_WITH_AES_128_SHA - CIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) -#else - XCIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) -#endif -#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA - CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) -#else - XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) -#endif -#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA - CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) -#else - XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) -#endif diff --git a/src/common/compat_openssl.h b/src/common/compat_openssl.h deleted file mode 100644 index a94b264927..0000000000 --- a/src/common/compat_openssl.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_COMPAT_OPENSSL_H -#define TOR_COMPAT_OPENSSL_H - -#include <openssl/opensslv.h> -#include "common/crypto_openssl_mgt.h" - -/** - * \file compat_openssl.h - * - * \brief compatibility definitions for working with different openssl forks - **/ - -#if !defined(LIBRESSL_VERSION_NUMBER) && \ - OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,1) -#error "We require OpenSSL >= 1.0.1" -#endif - -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && \ - ! defined(LIBRESSL_VERSION_NUMBER) -/* We define this macro if we're trying to build with the majorly refactored - * API in OpenSSL 1.1 */ -#define OPENSSL_1_1_API -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && ... */ - -#ifndef OPENSSL_VERSION -#define OPENSSL_VERSION SSLEAY_VERSION -#endif - -#ifndef OPENSSL_1_1_API -#define OpenSSL_version(v) SSLeay_version(v) -#define OpenSSL_version_num() SSLeay() -#define RAND_OpenSSL() RAND_SSLeay() -#define STATE_IS_SW_SERVER_HELLO(st) \ - (((st) == SSL3_ST_SW_SRVR_HELLO_A) || \ - ((st) == SSL3_ST_SW_SRVR_HELLO_B)) -#define OSSL_HANDSHAKE_STATE int -#define CONST_IF_OPENSSL_1_1_API -#else /* !(!defined(OPENSSL_1_1_API)) */ -#define STATE_IS_SW_SERVER_HELLO(st) \ - ((st) == TLS_ST_SW_SRVR_HELLO) -#define CONST_IF_OPENSSL_1_1_API const -#endif /* !defined(OPENSSL_1_1_API) */ - -#endif /* !defined(TOR_COMPAT_OPENSSL_H) */ - diff --git a/src/common/crypto.c b/src/common/crypto.c deleted file mode 100644 index 8a8bb2b770..0000000000 --- a/src/common/crypto.c +++ /dev/null @@ -1,508 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto.c - * \brief Wrapper functions to present a consistent interface to - * public-key and symmetric cryptography operations from OpenSSL and - * other places. - **/ - -#include "orconfig.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <wincrypt.h> -/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually - * use either definition. */ -#undef OCSP_RESPONSE -#endif /* defined(_WIN32) */ - -#define CRYPTO_PRIVATE -#include "common/compat_openssl.h" -#include "common/crypto.h" -#include "common/crypto_curve25519.h" -#include "common/crypto_digest.h" -#include "common/crypto_dh.h" -#include "common/crypto_ed25519.h" -#include "common/crypto_format.h" -#include "common/crypto_rand.h" -#include "common/crypto_rsa.h" -#include "common/crypto_util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> -#include <openssl/ssl.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif /* __GNUC__ && GCC_VERSION >= 402 */ - -#ifdef HAVE_CTYPE_H -#include <ctype.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "common/torlog.h" -#include "lib/cc/torint.h" -#include "common/aes.h" -#include "common/util.h" -#include "common/container.h" -#include "common/compat.h" -#include "common/sandbox.h" -#include "common/util_format.h" - -#include "keccak-tiny/keccak-tiny.h" - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_early_initialized_ = 0; - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_global_initialized_ = 0; - -#ifndef DISABLE_ENGINES -/** Log any OpenSSL engines we're using at NOTICE. */ -static void -log_engine(const char *fn, ENGINE *e) -{ - if (e) { - const char *name, *id; - name = ENGINE_get_name(e); - id = ENGINE_get_id(e); - log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]", - fn, name?name:"?", id?id:"?"); - } else { - log_info(LD_CRYPTO, "Using default implementation for %s", fn); - } -} -#endif /* !defined(DISABLE_ENGINES) */ - -#ifndef DISABLE_ENGINES -/** Try to load an engine in a shared library via fully qualified path. - */ -static ENGINE * -try_load_engine(const char *path, const char *engine) -{ - ENGINE *e = ENGINE_by_id("dynamic"); - if (e) { - if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) || - !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { - ENGINE_free(e); - e = NULL; - } - } - return e; -} -#endif /* !defined(DISABLE_ENGINES) */ - -static int have_seeded_siphash = 0; - -/** Set up the siphash key if we haven't already done so. */ -int -crypto_init_siphash_key(void) -{ - struct sipkey key; - if (have_seeded_siphash) - return 0; - - crypto_rand((char*) &key, sizeof(key)); - siphash_set_global_key(&key); - have_seeded_siphash = 1; - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_early_init(void) -{ - if (!crypto_early_initialized_) { - - crypto_early_initialized_ = 1; - -#ifdef OPENSSL_1_1_API - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | - OPENSSL_INIT_LOAD_CRYPTO_STRINGS | - OPENSSL_INIT_ADD_ALL_CIPHERS | - OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); -#else - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); -#endif - - setup_openssl_threading(); - - unsigned long version_num = OpenSSL_version_num(); - const char *version_str = OpenSSL_version(OPENSSL_VERSION); - if (version_num == OPENSSL_VERSION_NUMBER && - !strcmp(version_str, OPENSSL_VERSION_TEXT)) { - log_info(LD_CRYPTO, "OpenSSL version matches version from headers " - "(%lx: %s).", version_num, version_str); - } else { - log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " - "version we're running with. If you get weird crashes, that " - "might be why. (Compiled with %lx: %s; running with %lx: %s).", - (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, - version_num, version_str); - } - - crypto_force_rand_ssleay(); - - if (crypto_seed_rng() < 0) - return -1; - if (crypto_init_siphash_key() < 0) - return -1; - - curve25519_init(); - ed25519_init(); - } - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_global_init(int useAccel, const char *accelName, const char *accelDir) -{ - if (!crypto_global_initialized_) { - if (crypto_early_init() < 0) - return -1; - - crypto_global_initialized_ = 1; - - if (useAccel > 0) { -#ifdef DISABLE_ENGINES - (void)accelName; - (void)accelDir; - log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled."); -#else - ENGINE *e = NULL; - - log_info(LD_CRYPTO, "Initializing OpenSSL engine support."); - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); - - if (accelName) { - if (accelDir) { - log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\"" - " via path \"%s\".", accelName, accelDir); - e = try_load_engine(accelName, accelDir); - } else { - log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\"" - " acceleration support.", accelName); - e = ENGINE_by_id(accelName); - } - if (!e) { - log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".", - accelName); - } else { - log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".", - accelName); - } - } - if (e) { - log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine," - " setting default ciphers."); - ENGINE_set_default(e, ENGINE_METHOD_ALL); - } - /* Log, if available, the intersection of the set of algorithms - used by Tor and the set of algorithms available in the engine */ - log_engine("RSA", ENGINE_get_default_RSA()); - log_engine("DH", ENGINE_get_default_DH()); -#ifdef OPENSSL_1_1_API - log_engine("EC", ENGINE_get_default_EC()); -#else - log_engine("ECDH", ENGINE_get_default_ECDH()); - log_engine("ECDSA", ENGINE_get_default_ECDSA()); -#endif /* defined(OPENSSL_1_1_API) */ - log_engine("RAND", ENGINE_get_default_RAND()); - log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); - log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); - log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); - log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); - log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); -#ifdef NID_aes_128_ctr - log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); -#endif -#ifdef NID_aes_128_gcm - log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); -#endif - log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); -#ifdef NID_aes_256_gcm - log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); -#endif - -#endif /* defined(DISABLE_ENGINES) */ - } else { - log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); - } - - if (crypto_force_rand_ssleay()) { - if (crypto_seed_rng() < 0) - return -1; - } - - evaluate_evp_for_aes(-1); - evaluate_ctr_for_aes(); - } - return 0; -} - -/** Free crypto resources held by this thread. */ -void -crypto_thread_cleanup(void) -{ -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. Key length must be 128, 192, or 256 */ -crypto_cipher_t * -crypto_cipher_new_with_iv_and_bits(const uint8_t *key, - const uint8_t *iv, - int bits) -{ - tor_assert(key); - tor_assert(iv); - - return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits); -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. - */ -crypto_cipher_t * -crypto_cipher_new_with_iv(const char *key, const char *iv) -{ - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv, - 128); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all - * zero bytes and key length <b>bits</b>. Key length must be 128, 192, or - * 256. */ -crypto_cipher_t * -crypto_cipher_new_with_bits(const char *key, int bits) -{ - char zeroiv[CIPHER_IV_LEN]; - memset(zeroiv, 0, sizeof(zeroiv)); - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv, - bits); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> (of - * CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */ -crypto_cipher_t * -crypto_cipher_new(const char *key) -{ - return crypto_cipher_new_with_bits(key, 128); -} - -/** Free a symmetric cipher. - */ -void -crypto_cipher_free_(crypto_cipher_t *env) -{ - if (!env) - return; - - aes_cipher_free(env); -} - -/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces - * every four characters. */ -void -crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) -{ - int n = 0; - char *end = out+outlen; - tor_assert(outlen < SIZE_T_CEILING); - - while (*in && out<end) { - *out++ = *in++; - if (++n == 4 && *in && out<end) { - n = 0; - *out++ = ' '; - } - } - tor_assert(out<end); - *out = '\0'; -} - -/* symmetric crypto */ - -/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_encrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(env); - tor_assert(from); - tor_assert(fromlen); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_decrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; - * on success. Does not check for failure. - */ -void -crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) -{ - tor_assert(len < SIZE_T_CEILING); - aes_crypt_inplace(env, buf, len); -} - -/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in - * <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_encrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen < 1) - return -1; - if (tolen < fromlen + CIPHER_IV_LEN) - return -1; - - char iv[CIPHER_IV_LEN]; - crypto_rand(iv, sizeof(iv)); - cipher = crypto_cipher_new_with_iv(key, iv); - - memcpy(to, iv, CIPHER_IV_LEN); - crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); - crypto_cipher_free(cipher); - memwipe(iv, 0, sizeof(iv)); - return (int)(fromlen + CIPHER_IV_LEN); -} - -/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b> - * with the key in <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_decrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(key); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen <= CIPHER_IV_LEN) - return -1; - if (tolen < fromlen - CIPHER_IV_LEN) - return -1; - - cipher = crypto_cipher_new_with_iv(key, from); - - crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN); - crypto_cipher_free(cipher); - return (int)(fromlen - CIPHER_IV_LEN); -} - -/** @{ */ -/** Uninitialize the crypto library. Return 0 on success. Does not detect - * failure. - */ -int -crypto_global_cleanup(void) -{ -#ifndef OPENSSL_1_1_API - EVP_cleanup(); -#endif -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -#ifndef OPENSSL_1_1_API - ERR_free_strings(); -#endif - - crypto_dh_free_all(); - -#ifndef DISABLE_ENGINES -#ifndef OPENSSL_1_1_API - ENGINE_cleanup(); -#endif -#endif - - CONF_modules_unload(1); -#ifndef OPENSSL_1_1_API - CRYPTO_cleanup_all_ex_data(); -#endif - - crypto_openssl_free_all(); - - crypto_early_initialized_ = 0; - crypto_global_initialized_ = 0; - have_seeded_siphash = 0; - siphash_unset_global_key(); - - return 0; -} - -/** @} */ diff --git a/src/common/crypto.h b/src/common/crypto.h deleted file mode 100644 index 1324468097..0000000000 --- a/src/common/crypto.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto.h - * - * \brief Headers for crypto.c - **/ - -#ifndef TOR_CRYPTO_H -#define TOR_CRYPTO_H - -#include "orconfig.h" - -#include <stdio.h> -#include "lib/cc/torint.h" -#include "common/compat.h" -#include "common/util.h" -#include "common/crypto_rsa.h" - -/** Length of our symmetric cipher's keys of 128-bit. */ -#define CIPHER_KEY_LEN 16 -/** Length of our symmetric cipher's IV of 128-bit. */ -#define CIPHER_IV_LEN 16 -/** Length of our symmetric cipher's keys of 256-bit. */ -#define CIPHER256_KEY_LEN 32 - -/** Length of encoded public key fingerprints, including space; but not - * including terminating NUL. */ -#define FINGERPRINT_LEN 49 - -typedef struct aes_cnt_cipher crypto_cipher_t; - -/* global state */ -int crypto_init_siphash_key(void); -int crypto_early_init(void) ATTR_WUR; -int crypto_global_init(int hardwareAccel, - const char *accelName, - const char *accelPath) ATTR_WUR; - -void crypto_thread_cleanup(void); -int crypto_global_cleanup(void); - -/* environment setup */ -crypto_cipher_t *crypto_cipher_new(const char *key); -crypto_cipher_t *crypto_cipher_new_with_bits(const char *key, int bits); -crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv); -crypto_cipher_t *crypto_cipher_new_with_iv_and_bits(const uint8_t *key, - const uint8_t *iv, - int bits); -void crypto_cipher_free_(crypto_cipher_t *env); -#define crypto_cipher_free(c) \ - FREE_AND_NULL(crypto_cipher_t, crypto_cipher_free_, (c)) - -/* symmetric crypto */ -const char *crypto_cipher_get_key(crypto_cipher_t *env); - -int crypto_cipher_encrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen); -int crypto_cipher_decrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen); -void crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *d, size_t len); - -int crypto_cipher_encrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen); -int crypto_cipher_decrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen); - -void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in); - -#endif /* !defined(TOR_CRYPTO_H) */ diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c deleted file mode 100644 index f28cebb887..0000000000 --- a/src/common/crypto_curve25519.c +++ /dev/null @@ -1,359 +0,0 @@ -/* Copyright (c) 2012-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_curve25519.c - * - * \brief Wrapper code for a curve25519 implementation. - * - * Curve25519 is an Elliptic-Curve Diffie Hellman handshake, designed by - * Dan Bernstein. For more information, see https://cr.yp.to/ecdh.html - * - * Tor uses Curve25519 as the basis of its "ntor" circuit extension - * handshake, and in related code. The functions in this module are - * used to find the most suitable available Curve25519 implementation, - * to provide wrappers around it, and so on. - */ - -#define CRYPTO_CURVE25519_PRIVATE -#include "orconfig.h" -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#include "common/container.h" -#include "common/crypto_curve25519.h" -#include "common/crypto_digest.h" -#include "common/crypto_format.h" -#include "common/crypto_rand.h" -#include "common/crypto_util.h" -#include "common/util.h" -#include "common/torlog.h" - -#include "ed25519/donna/ed25519_donna_tor.h" - -/* ============================== - Part 1: wrap a suitable curve25519 implementation as curve25519_impl - ============================== */ - -#ifdef USE_CURVE25519_DONNA -int curve25519_donna(uint8_t *mypublic, - const uint8_t *secret, const uint8_t *basepoint); -#endif -#ifdef USE_CURVE25519_NACL -#ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H -#include <crypto_scalarmult_curve25519.h> -#elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H) -#include <nacl/crypto_scalarmult_curve25519.h> -#endif -#endif /* defined(USE_CURVE25519_NACL) */ - -static void pick_curve25519_basepoint_impl(void); - -/** This is set to 1 if we have an optimized Ed25519-based - * implementation for multiplying a value by the basepoint; to 0 if we - * don't, and to -1 if we haven't checked. */ -static int curve25519_use_ed = -1; - -/** - * Helper function: call the most appropriate backend to compute the - * scalar "secret" times the point "point". Store the result in - * "output". Return 0 on success, negative on failure. - **/ -STATIC int -curve25519_impl(uint8_t *output, const uint8_t *secret, - const uint8_t *point) -{ - uint8_t bp[CURVE25519_PUBKEY_LEN]; - int r; - memcpy(bp, point, CURVE25519_PUBKEY_LEN); - /* Clear the high bit, in case our backend foolishly looks at it. */ - bp[31] &= 0x7f; -#ifdef USE_CURVE25519_DONNA - r = curve25519_donna(output, secret, bp); -#elif defined(USE_CURVE25519_NACL) - r = crypto_scalarmult_curve25519(output, secret, bp); -#else -#error "No implementation of curve25519 is available." -#endif /* defined(USE_CURVE25519_DONNA) || ... */ - memwipe(bp, 0, sizeof(bp)); - return r; -} - -/** - * Helper function: Multiply the scalar "secret" by the Curve25519 - * basepoint (X=9), and store the result in "output". Return 0 on - * success, -1 on failure. - */ -STATIC int -curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret) -{ - int r = 0; - if (BUG(curve25519_use_ed == -1)) { - /* LCOV_EXCL_START - Only reached if we forgot to call curve25519_init() */ - pick_curve25519_basepoint_impl(); - /* LCOV_EXCL_STOP */ - } - - /* TODO: Someone should benchmark curved25519_scalarmult_basepoint versus - * an optimized NaCl build to see which should be used when compiled with - * NaCl available. I suspected that the ed25519 optimization always wins. - */ - if (PREDICT_LIKELY(curve25519_use_ed == 1)) { - curved25519_scalarmult_basepoint_donna(output, secret); - r = 0; - } else { - static const uint8_t basepoint[32] = {9}; - r = curve25519_impl(output, secret, basepoint); - } - return r; -} - -/** - * Override the decision of whether to use the Ed25519-based basepoint - * multiply function. Used for testing. - */ -void -curve25519_set_impl_params(int use_ed) -{ - curve25519_use_ed = use_ed; -} - -/* ============================== - Part 2: Wrap curve25519_impl with some convenience types and functions. - ============================== */ - -/** - * Return true iff a curve25519_public_key_t seems valid. (It's not necessary - * to see if the point is on the curve, since the twist is also secure, but we - * do need to make sure that it isn't the point at infinity.) */ -int -curve25519_public_key_is_ok(const curve25519_public_key_t *key) -{ - return !safe_mem_is_zero(key->public_key, CURVE25519_PUBKEY_LEN); -} - -/** - * Generate CURVE25519_SECKEY_LEN random bytes in <b>out</b>. If - * <b>extra_strong</b> is true, this key is possibly going to get used more - * than once, so use a better-than-usual RNG. Return 0 on success, -1 on - * failure. - * - * This function does not adjust the output of the RNG at all; the will caller - * will need to clear or set the appropriate bits to make curve25519 work. - */ -int -curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong) -{ - if (extra_strong) - crypto_strongest_rand(out, CURVE25519_SECKEY_LEN); - else - crypto_rand((char*)out, CURVE25519_SECKEY_LEN); - - return 0; -} - -/** Generate a new keypair and return the secret key. If <b>extra_strong</b> - * is true, this key is possibly going to get used more than once, so - * use a better-than-usual RNG. Return 0 on success, -1 on failure. */ -int -curve25519_secret_key_generate(curve25519_secret_key_t *key_out, - int extra_strong) -{ - if (curve25519_rand_seckey_bytes(key_out->secret_key, extra_strong) < 0) - return -1; - - key_out->secret_key[0] &= 248; - key_out->secret_key[31] &= 127; - key_out->secret_key[31] |= 64; - - return 0; -} - -/** - * Given a secret key in <b>seckey</b>, create the corresponding public - * key in <b>key_out</b>. - */ -void -curve25519_public_key_generate(curve25519_public_key_t *key_out, - const curve25519_secret_key_t *seckey) -{ - curve25519_basepoint_impl(key_out->public_key, seckey->secret_key); -} - -/** - * Construct a new keypair in *<b>keypair_out</b>. If <b>extra_strong</b> - * is true, this key is possibly going to get used more than once, so - * use a better-than-usual RNG. Return 0 on success, -1 on failure. */ -int -curve25519_keypair_generate(curve25519_keypair_t *keypair_out, - int extra_strong) -{ - if (curve25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0) - return -1; - curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey); - return 0; -} - -/** Store the keypair <b>keypair</b>, including its secret and public - * parts, to the file <b>fname</b>. Use the string tag <b>tag</b> to - * distinguish this from other Curve25519 keypairs. Return 0 on success, - * -1 on failure. - * - * See crypto_write_tagged_contents_to_file() for more information on - * the metaformat used for these keys.*/ -int -curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, - const char *fname, - const char *tag) -{ - uint8_t contents[CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN]; - int r; - - memcpy(contents, keypair->seckey.secret_key, CURVE25519_SECKEY_LEN); - memcpy(contents+CURVE25519_SECKEY_LEN, - keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); - - r = crypto_write_tagged_contents_to_file(fname, - "c25519v1", - tag, - contents, - sizeof(contents)); - - memwipe(contents, 0, sizeof(contents)); - return r; -} - -/** Read a curve25519 keypair from a file named <b>fname</b> created by - * curve25519_keypair_write_to_file(). Store the keypair in - * <b>keypair_out</b>, and the associated tag string in <b>tag_out</b>. - * Return 0 on success, and -1 on failure. */ -int -curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, - char **tag_out, - const char *fname) -{ - uint8_t content[CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN]; - ssize_t len; - int r = -1; - - len = crypto_read_tagged_contents_from_file(fname, "c25519v1", tag_out, - content, sizeof(content)); - if (len != sizeof(content)) - goto end; - - /* Make sure that the public key matches the secret key */ - memcpy(keypair_out->seckey.secret_key, content, CURVE25519_SECKEY_LEN); - curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey); - if (tor_memneq(keypair_out->pubkey.public_key, - content + CURVE25519_SECKEY_LEN, - CURVE25519_PUBKEY_LEN)) - goto end; - - r = 0; - - end: - memwipe(content, 0, sizeof(content)); - if (r != 0) { - memset(keypair_out, 0, sizeof(*keypair_out)); - tor_free(*tag_out); - } - return r; -} - -/** Perform the curve25519 ECDH handshake with <b>skey</b> and <b>pkey</b>, - * writing CURVE25519_OUTPUT_LEN bytes of output into <b>output</b>. */ -void -curve25519_handshake(uint8_t *output, - const curve25519_secret_key_t *skey, - const curve25519_public_key_t *pkey) -{ - curve25519_impl(output, skey->secret_key, pkey->public_key); -} - -/** Check whether the ed25519-based curve25519 basepoint optimization seems to - * be working. If so, return 0; otherwise return -1. */ -static int -curve25519_basepoint_spot_check(void) -{ - static const uint8_t alicesk[32] = { - 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d, - 0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45, - 0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a, - 0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a - }; - static const uint8_t alicepk[32] = { - 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54, - 0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a, - 0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4, - 0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a - }; - const int loop_max=200; - int save_use_ed = curve25519_use_ed; - unsigned char e1[32] = { 5 }; - unsigned char e2[32] = { 5 }; - unsigned char x[32],y[32]; - int i; - int r=0; - - /* Check the most basic possible sanity via the test secret/public key pair - * used in "Cryptography in NaCl - 2. Secret keys and public keys". This - * may catch catastrophic failures on systems where Curve25519 is expensive, - * without requiring a ton of key generation. - */ - curve25519_use_ed = 1; - r |= curve25519_basepoint_impl(x, alicesk); - if (fast_memneq(x, alicepk, 32)) - goto fail; - - /* Ok, the optimization appears to produce passable results, try a few more - * values, maybe there's something subtle wrong. - */ - for (i = 0; i < loop_max; ++i) { - curve25519_use_ed = 0; - r |= curve25519_basepoint_impl(x, e1); - curve25519_use_ed = 1; - r |= curve25519_basepoint_impl(y, e2); - if (fast_memneq(x,y,32)) - goto fail; - memcpy(e1, x, 32); - memcpy(e2, x, 32); - } - - goto end; - // LCOV_EXCL_START -- we can only hit this code if there is a bug in our - // curve25519-basepoint implementation. - fail: - r = -1; - // LCOV_EXCL_STOP - end: - curve25519_use_ed = save_use_ed; - return r; -} - -/** Choose whether to use the ed25519-based curve25519-basepoint - * implementation. */ -static void -pick_curve25519_basepoint_impl(void) -{ - curve25519_use_ed = 1; - - if (curve25519_basepoint_spot_check() == 0) - return; - - /* LCOV_EXCL_START - * only reachable if our basepoint implementation broken */ - log_warn(LD_BUG|LD_CRYPTO, "The ed25519-based curve25519 basepoint " - "multiplication seems broken; using the curve25519 " - "implementation."); - curve25519_use_ed = 0; - /* LCOV_EXCL_STOP */ -} - -/** Initialize the curve25519 implementations. This is necessary if you're - * going to use them in a multithreaded setting, and not otherwise. */ -void -curve25519_init(void) -{ - pick_curve25519_basepoint_impl(); -} - diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h deleted file mode 100644 index 8a5b9b2018..0000000000 --- a/src/common/crypto_curve25519.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2012-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_CURVE25519_H -#define TOR_CRYPTO_CURVE25519_H - -#include "common/testsupport.h" -#include "lib/cc/torint.h" -#include "common/crypto_digest.h" -#include "common/crypto_openssl_mgt.h" - -/** Length of a curve25519 public key when encoded. */ -#define CURVE25519_PUBKEY_LEN 32 -/** Length of a curve25519 secret key when encoded. */ -#define CURVE25519_SECKEY_LEN 32 -/** Length of the result of a curve25519 handshake. */ -#define CURVE25519_OUTPUT_LEN 32 - -/** Wrapper type for a curve25519 public key. - * - * (We define a separate type for these to make it less likely that we'll - * mistake them for secret keys.) - * */ -typedef struct curve25519_public_key_t { - uint8_t public_key[CURVE25519_PUBKEY_LEN]; -} curve25519_public_key_t; - -/** Wrapper type for a curve25519 secret key - * - * (We define a separate type for these to make it less likely that we'll - * mistake them for public keys.) - **/ -typedef struct curve25519_secret_key_t { - uint8_t secret_key[CURVE25519_SECKEY_LEN]; -} curve25519_secret_key_t; - -/** A paired public and private key for curve25519. **/ -typedef struct curve25519_keypair_t { - curve25519_public_key_t pubkey; - curve25519_secret_key_t seckey; -} curve25519_keypair_t; - -/* These functions require that we actually know how to use curve25519 keys. - * The other data structures and functions in this header let us parse them, - * store them, and move them around. - */ - -int curve25519_public_key_is_ok(const curve25519_public_key_t *); - -int curve25519_secret_key_generate(curve25519_secret_key_t *key_out, - int extra_strong); -void curve25519_public_key_generate(curve25519_public_key_t *key_out, - const curve25519_secret_key_t *seckey); -int curve25519_keypair_generate(curve25519_keypair_t *keypair_out, - int extra_strong); - -void curve25519_handshake(uint8_t *output, - const curve25519_secret_key_t *, - const curve25519_public_key_t *); - -int curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, - const char *fname, - const char *tag); - -int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, - char **tag_out, - const char *fname); - -int curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong); - -#ifdef CRYPTO_CURVE25519_PRIVATE -STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret, - const uint8_t *basepoint); - -STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret); -#endif /* defined(CRYPTO_CURVE25519_PRIVATE) */ - -#define CURVE25519_BASE64_PADDED_LEN 44 - -int curve25519_public_from_base64(curve25519_public_key_t *pkey, - const char *input); -int curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey); - -void curve25519_set_impl_params(int use_ed); -void curve25519_init(void); - -#endif /* !defined(TOR_CRYPTO_CURVE25519_H) */ - diff --git a/src/common/crypto_dh.c b/src/common/crypto_dh.c deleted file mode 100644 index a9bd348ff4..0000000000 --- a/src/common/crypto_dh.c +++ /dev/null @@ -1,510 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_dh.c - * \brief Block of functions related with DH utilities and operations. - **/ - -#include "common/compat_openssl.h" -#include "common/crypto_dh.h" -#include "common/crypto_digest.h" -#include "common/crypto_hkdf.h" -#include "common/crypto_util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/dh.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#include <openssl/bn.h> - -#include "common/torlog.h" - -/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake - * while we're waiting for the second.*/ -struct crypto_dh_t { - DH *dh; /**< The openssl DH object */ -}; - -static int tor_check_dh_key(int severity, const BIGNUM *bn); - -/** Used by tortls.c: Get the DH* from a crypto_dh_t. - */ -DH * -crypto_dh_get_dh_(crypto_dh_t *dh) -{ - return dh->dh; -} - -/** Our DH 'g' parameter */ -#define DH_GENERATOR 2 - -/** Shared P parameter for our circuit-crypto DH key exchanges. */ -static BIGNUM *dh_param_p = NULL; -/** Shared P parameter for our TLS DH key exchanges. */ -static BIGNUM *dh_param_p_tls = NULL; -/** Shared G parameter for our DH key exchanges. */ -static BIGNUM *dh_param_g = NULL; - -/** Validate a given set of Diffie-Hellman parameters. This is moderately - * computationally expensive (milliseconds), so should only be called when - * the DH parameters change. Returns 0 on success, * -1 on failure. - */ -static int -crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) -{ - DH *dh = NULL; - int ret = -1; - - /* Copy into a temporary DH object, just so that DH_check() can be called. */ - if (!(dh = DH_new())) - goto out; -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p, *dh_g; - if (!(dh_p = BN_dup(p))) - goto out; - if (!(dh_g = BN_dup(g))) - goto out; - if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) - goto out; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (!(dh->p = BN_dup(p))) - goto out; - if (!(dh->g = BN_dup(g))) - goto out; -#endif /* defined(OPENSSL_1_1_API) */ - - /* Perform the validation. */ - int codes = 0; - if (!DH_check(dh, &codes)) - goto out; - if (BN_is_word(g, DH_GENERATOR_2)) { - /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters - * - * OpenSSL checks the prime is congruent to 11 when g = 2; while the - * IETF's primes are congruent to 23 when g = 2. - */ - BN_ULONG residue = BN_mod_word(p, 24); - if (residue == 11 || residue == 23) - codes &= ~DH_NOT_SUITABLE_GENERATOR; - } - if (codes != 0) /* Specifics on why the params suck is irrelevant. */ - goto out; - - /* Things are probably not evil. */ - ret = 0; - - out: - if (dh) - DH_free(dh); - return ret; -} - -/** Set the global Diffie-Hellman generator, used for both TLS and internal - * DH stuff. - */ -static void -crypto_set_dh_generator(void) -{ - BIGNUM *generator; - int r; - - if (dh_param_g) - return; - - generator = BN_new(); - tor_assert(generator); - - r = BN_set_word(generator, DH_GENERATOR); - tor_assert(r); - - dh_param_g = generator; -} - -/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH - * modulus. */ -void -crypto_set_tls_dh_prime(void) -{ - BIGNUM *tls_prime = NULL; - int r; - - /* If the space is occupied, free the previous TLS DH prime */ - if (BUG(dh_param_p_tls)) { - /* LCOV_EXCL_START - * - * We shouldn't be calling this twice. - */ - BN_clear_free(dh_param_p_tls); - dh_param_p_tls = NULL; - /* LCOV_EXCL_STOP */ - } - - tls_prime = BN_new(); - tor_assert(tls_prime); - - /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see - * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this - * prime. - */ - r = BN_hex2bn(&tls_prime, - "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" - "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" - "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" - "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" - "B0E7393E0F24218EB3"); - tor_assert(r); - - tor_assert(tls_prime); - - dh_param_p_tls = tls_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g)); -} - -/** Initialize dh_param_p and dh_param_g if they are not already - * set. */ -static void -init_dh_param(void) -{ - BIGNUM *circuit_dh_prime; - int r; - if (BUG(dh_param_p && dh_param_g)) - return; // LCOV_EXCL_LINE This function isn't supposed to be called twice. - - circuit_dh_prime = BN_new(); - tor_assert(circuit_dh_prime); - - /* This is from rfc2409, section 6.2. It's a safe prime, and - supposedly it equals: - 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. - */ - r = BN_hex2bn(&circuit_dh_prime, - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE65381FFFFFFFFFFFFFFFF"); - tor_assert(r); - - /* Set the new values as the global DH parameters. */ - dh_param_p = circuit_dh_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g)); - - if (!dh_param_p_tls) { - crypto_set_tls_dh_prime(); - } -} - -/** Number of bits to use when choosing the x or y value in a Diffie-Hellman - * handshake. Since we exponentiate by this value, choosing a smaller one - * lets our handhake go faster. - */ -#define DH_PRIVATE_KEY_BITS 320 - -/** Allocate and return a new DH object for a key exchange. Returns NULL on - * failure. - */ -crypto_dh_t * -crypto_dh_new(int dh_type) -{ - crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t)); - - tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS || - dh_type == DH_TYPE_REND); - - if (!dh_param_p) - init_dh_param(); - - if (!(res->dh = DH_new())) - goto err; - -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p = NULL, *dh_g = NULL; - - if (dh_type == DH_TYPE_TLS) { - dh_p = BN_dup(dh_param_p_tls); - } else { - dh_p = BN_dup(dh_param_p); - } - if (!dh_p) - goto err; - - dh_g = BN_dup(dh_param_g); - if (!dh_g) { - BN_free(dh_p); - goto err; - } - - if (!DH_set0_pqg(res->dh, dh_p, NULL, dh_g)) { - goto err; - } - - if (!DH_set_length(res->dh, DH_PRIVATE_KEY_BITS)) - goto err; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (dh_type == DH_TYPE_TLS) { - if (!(res->dh->p = BN_dup(dh_param_p_tls))) - goto err; - } else { - if (!(res->dh->p = BN_dup(dh_param_p))) - goto err; - } - - if (!(res->dh->g = BN_dup(dh_param_g))) - goto err; - - res->dh->length = DH_PRIVATE_KEY_BITS; -#endif /* defined(OPENSSL_1_1_API) */ - - return res; - - /* LCOV_EXCL_START - * This error condition is only reached when an allocation fails */ - err: - crypto_log_errors(LOG_WARN, "creating DH object"); - if (res->dh) DH_free(res->dh); /* frees p and g too */ - tor_free(res); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Return a copy of <b>dh</b>, sharing its internal state. */ -crypto_dh_t * -crypto_dh_dup(const crypto_dh_t *dh) -{ - crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); - tor_assert(dh); - tor_assert(dh->dh); - dh_new->dh = dh->dh; - DH_up_ref(dh->dh); - return dh_new; -} - -/** Return the length of the DH key in <b>dh</b>, in bytes. - */ -int -crypto_dh_get_bytes(crypto_dh_t *dh) -{ - tor_assert(dh); - return DH_size(dh->dh); -} - -/** Generate \<x,g^x\> for our part of the key exchange. Return 0 on - * success, -1 on failure. - */ -int -crypto_dh_generate_public(crypto_dh_t *dh) -{ -#ifndef OPENSSL_1_1_API - again: -#endif - if (!DH_generate_key(dh->dh)) { - /* LCOV_EXCL_START - * To test this we would need some way to tell openssl to break DH. */ - crypto_log_errors(LOG_WARN, "generating DH key"); - return -1; - /* LCOV_EXCL_STOP */ - } -#ifdef OPENSSL_1_1_API - /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without - * recreating the DH object. I have no idea what sort of aliasing madness - * can occur here, so do the check, and just bail on failure. - */ - const BIGNUM *pub_key, *priv_key; - DH_get0_key(dh->dh, &pub_key, &priv_key); - if (tor_check_dh_key(LOG_WARN, pub_key)<0) { - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Treating as a failure."); - return -1; - } -#else /* !(defined(OPENSSL_1_1_API)) */ - if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { - /* LCOV_EXCL_START - * If this happens, then openssl's DH implementation is busted. */ - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Trying again."); - /* Free and clear the keys, so OpenSSL will actually try again. */ - BN_clear_free(dh->dh->pub_key); - BN_clear_free(dh->dh->priv_key); - dh->dh->pub_key = dh->dh->priv_key = NULL; - goto again; - /* LCOV_EXCL_STOP */ - } -#endif /* defined(OPENSSL_1_1_API) */ - return 0; -} - -/** Generate g^x as necessary, and write the g^x for the key exchange - * as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on - * success, -1 on failure. <b>pubkey_len</b> must be \>= DH_BYTES. - */ -int -crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) -{ - int bytes; - tor_assert(dh); - - const BIGNUM *dh_pub; - -#ifdef OPENSSL_1_1_API - const BIGNUM *dh_priv; - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif /* defined(OPENSSL_1_1_API) */ - - if (!dh_pub) { - if (crypto_dh_generate_public(dh)<0) - return -1; - else { -#ifdef OPENSSL_1_1_API - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif - } - } - - tor_assert(dh_pub); - bytes = BN_num_bytes(dh_pub); - tor_assert(bytes >= 0); - if (pubkey_len < (size_t)bytes) { - log_warn(LD_CRYPTO, - "Weird! pubkey_len (%d) was smaller than DH_BYTES (%d)", - (int) pubkey_len, bytes); - return -1; - } - - memset(pubkey, 0, pubkey_len); - BN_bn2bin(dh_pub, (unsigned char*)(pubkey+(pubkey_len-bytes))); - - return 0; -} - -/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is - * okay (in the subgroup [2,p-2]), or -1 if it's bad. - * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. - */ -static int -tor_check_dh_key(int severity, const BIGNUM *bn) -{ - BIGNUM *x; - char *s; - tor_assert(bn); - x = BN_new(); - tor_assert(x); - if (BUG(!dh_param_p)) - init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this. - BN_set_word(x, 1); - if (BN_cmp(bn,x)<=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); - goto err; - } - BN_copy(x,dh_param_p); - BN_sub_word(x, 1); - if (BN_cmp(bn,x)>=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); - goto err; - } - BN_clear_free(x); - return 0; - err: - BN_clear_free(x); - s = BN_bn2hex(bn); - log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); - OPENSSL_free(s); - return -1; -} - -/** Given a DH key exchange object, and our peer's value of g^y (as a - * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate - * <b>secret_bytes_out</b> bytes of shared key material and write them - * to <b>secret_out</b>. Return the number of bytes generated on success, - * or -1 on failure. - * - * (We generate key material by computing - * SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ... - * where || is concatenation.) - */ -ssize_t -crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_bytes_out) -{ - char *secret_tmp = NULL; - BIGNUM *pubkey_bn = NULL; - size_t secret_len=0, secret_tmp_len=0; - int result=0; - tor_assert(dh); - tor_assert(secret_bytes_out/DIGEST_LEN <= 255); - tor_assert(pubkey_len < INT_MAX); - - if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, - (int)pubkey_len, NULL))) - goto error; - if (tor_check_dh_key(severity, pubkey_bn)<0) { - /* Check for invalid public keys. */ - log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); - goto error; - } - secret_tmp_len = crypto_dh_get_bytes(dh); - secret_tmp = tor_malloc(secret_tmp_len); - result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh); - if (result < 0) { - log_warn(LD_CRYPTO,"DH_compute_key() failed."); - goto error; - } - secret_len = result; - if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len, - (uint8_t*)secret_out, secret_bytes_out)<0) - goto error; - secret_len = secret_bytes_out; - - goto done; - error: - result = -1; - done: - crypto_log_errors(LOG_WARN, "completing DH handshake"); - if (pubkey_bn) - BN_clear_free(pubkey_bn); - if (secret_tmp) { - memwipe(secret_tmp, 0, secret_tmp_len); - tor_free(secret_tmp); - } - if (result < 0) - return result; - else - return secret_len; -} - -/** Free a DH key exchange object. - */ -void -crypto_dh_free_(crypto_dh_t *dh) -{ - if (!dh) - return; - tor_assert(dh->dh); - DH_free(dh->dh); - tor_free(dh); -} - -void -crypto_dh_free_all(void) -{ - if (dh_param_p) - BN_clear_free(dh_param_p); - if (dh_param_p_tls) - BN_clear_free(dh_param_p_tls); - if (dh_param_g) - BN_clear_free(dh_param_g); - - dh_param_p = dh_param_p_tls = dh_param_g = NULL; -} diff --git a/src/common/crypto_dh.h b/src/common/crypto_dh.h deleted file mode 100644 index 1e77acc011..0000000000 --- a/src/common/crypto_dh.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_dh.h - * - * \brief Headers for crypto_dh.c - **/ - -#ifndef TOR_CRYPTO_DH_H -#define TOR_CRYPTO_DH_H - -#include "common/util.h" - -/** Length of our DH keys. */ -#define DH_BYTES (1024/8) - -typedef struct crypto_dh_t crypto_dh_t; - -/* Key negotiation */ -#define DH_TYPE_CIRCUIT 1 -#define DH_TYPE_REND 2 -#define DH_TYPE_TLS 3 -void crypto_set_tls_dh_prime(void); -crypto_dh_t *crypto_dh_new(int dh_type); -crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh); -int crypto_dh_get_bytes(crypto_dh_t *dh); -int crypto_dh_generate_public(crypto_dh_t *dh); -int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, - size_t pubkey_out_len); -ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_out_len); -void crypto_dh_free_(crypto_dh_t *dh); -#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh)) - -/* Crypto DH free */ -void crypto_dh_free_all(void); - -/* Prototypes for private functions only used by tortls.c, crypto.c, and the - * unit tests. */ -struct dh_st; -struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); - -#endif /* !defined(TOR_CRYPTO_DH_H) */ - diff --git a/src/common/crypto_digest.c b/src/common/crypto_digest.c deleted file mode 100644 index 708fbf9be6..0000000000 --- a/src/common/crypto_digest.c +++ /dev/null @@ -1,583 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_digest.c - * \brief Block of functions related with digest and xof utilities and - * operations. - **/ - -#include "common/container.h" -#include "common/crypto_digest.h" -#include "common/crypto_openssl_mgt.h" -#include "common/crypto_util.h" -#include "common/torlog.h" - -#include "keccak-tiny/keccak-tiny.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/hmac.h> -#include <openssl/sha.h> - -ENABLE_GCC_WARNING(redundant-decls) - -/* Crypto digest functions */ - -/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in - * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>. - * Return 0 on success, -1 on failure. - */ -int -crypto_digest(char *digest, const char *m, size_t len) -{ - tor_assert(m); - tor_assert(digest); - if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) - return -1; - return 0; -} - -/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>, - * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result - * into <b>digest</b>. Return 0 on success, -1 on failure. */ -int -crypto_digest256(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - - int ret = 0; - if (algorithm == DIGEST_SHA256) - ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL); - else - ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) - > -1); - - if (!ret) - return -1; - return 0; -} - -/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>, - * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result - * into <b>digest</b>. Return 0 on success, -1 on failure. */ -int -crypto_digest512(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - - int ret = 0; - if (algorithm == DIGEST_SHA512) - ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest) - != NULL); - else - ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) - > -1); - - if (!ret) - return -1; - return 0; -} - -/** Set the common_digests_t in <b>ds_out</b> to contain every digest on the - * <b>len</b> bytes in <b>m</b> that we know how to compute. Return 0 on - * success, -1 on failure. */ -int -crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len) -{ - tor_assert(ds_out); - memset(ds_out, 0, sizeof(*ds_out)); - if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0) - return -1; - if (crypto_digest256(ds_out->d[DIGEST_SHA256], m, len, DIGEST_SHA256) < 0) - return -1; - - return 0; -} - -/** Return the name of an algorithm, as used in directory documents. */ -const char * -crypto_digest_algorithm_get_name(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: - return "sha1"; - case DIGEST_SHA256: - return "sha256"; - case DIGEST_SHA512: - return "sha512"; - case DIGEST_SHA3_256: - return "sha3-256"; - case DIGEST_SHA3_512: - return "sha3-512"; - // LCOV_EXCL_START - default: - tor_fragile_assert(); - return "??unknown_digest??"; - // LCOV_EXCL_STOP - } -} - -/** Given the name of a digest algorithm, return its integer value, or -1 if - * the name is not recognized. */ -int -crypto_digest_algorithm_parse_name(const char *name) -{ - if (!strcmp(name, "sha1")) - return DIGEST_SHA1; - else if (!strcmp(name, "sha256")) - return DIGEST_SHA256; - else if (!strcmp(name, "sha512")) - return DIGEST_SHA512; - else if (!strcmp(name, "sha3-256")) - return DIGEST_SHA3_256; - else if (!strcmp(name, "sha3-512")) - return DIGEST_SHA3_512; - else - return -1; -} - -/** Given an algorithm, return the digest length in bytes. */ -size_t -crypto_digest_algorithm_get_length(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: - return DIGEST_LEN; - case DIGEST_SHA256: - return DIGEST256_LEN; - case DIGEST_SHA512: - return DIGEST512_LEN; - case DIGEST_SHA3_256: - return DIGEST256_LEN; - case DIGEST_SHA3_512: - return DIGEST512_LEN; - default: - tor_assert(0); // LCOV_EXCL_LINE - return 0; /* Unreachable */ // LCOV_EXCL_LINE - } -} - -/** Intermediate information about the digest of a stream of data. */ -struct crypto_digest_t { - digest_algorithm_t algorithm; /**< Which algorithm is in use? */ - /** State for the digest we're using. Only one member of the - * union is usable, depending on the value of <b>algorithm</b>. Note also - * that space for other members might not even be allocated! - */ - union { - SHA_CTX sha1; /**< state for SHA1 */ - SHA256_CTX sha2; /**< state for SHA256 */ - SHA512_CTX sha512; /**< state for SHA512 */ - keccak_state sha3; /**< state for SHA3-[256,512] */ - } d; -}; - -#ifdef TOR_UNIT_TESTS - -digest_algorithm_t -crypto_digest_get_algorithm(crypto_digest_t *digest) -{ - tor_assert(digest); - - return digest->algorithm; -} - -#endif /* defined(TOR_UNIT_TESTS) */ - -/** - * Return the number of bytes we need to malloc in order to get a - * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe - * when we free one. - */ -static size_t -crypto_digest_alloc_bytes(digest_algorithm_t alg) -{ - /* Helper: returns the number of bytes in the 'f' field of 'st' */ -#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) - /* Gives the length of crypto_digest_t through the end of the field 'd' */ -#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ - STRUCT_FIELD_SIZE(crypto_digest_t, f)) - switch (alg) { - case DIGEST_SHA1: - return END_OF_FIELD(d.sha1); - case DIGEST_SHA256: - return END_OF_FIELD(d.sha2); - case DIGEST_SHA512: - return END_OF_FIELD(d.sha512); - case DIGEST_SHA3_256: - case DIGEST_SHA3_512: - return END_OF_FIELD(d.sha3); - default: - tor_assert(0); // LCOV_EXCL_LINE - return 0; // LCOV_EXCL_LINE - } -#undef END_OF_FIELD -#undef STRUCT_FIELD_SIZE -} - -/** - * Internal function: create and return a new digest object for 'algorithm'. - * Does not typecheck the algorithm. - */ -static crypto_digest_t * -crypto_digest_new_internal(digest_algorithm_t algorithm) -{ - crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); - r->algorithm = algorithm; - - switch (algorithm) - { - case DIGEST_SHA1: - SHA1_Init(&r->d.sha1); - break; - case DIGEST_SHA256: - SHA256_Init(&r->d.sha2); - break; - case DIGEST_SHA512: - SHA512_Init(&r->d.sha512); - break; - case DIGEST_SHA3_256: - keccak_digest_init(&r->d.sha3, 256); - break; - case DIGEST_SHA3_512: - keccak_digest_init(&r->d.sha3, 512); - break; - default: - tor_assert_unreached(); - } - - return r; -} - -/** Allocate and return a new digest object to compute SHA1 digests. - */ -crypto_digest_t * -crypto_digest_new(void) -{ - return crypto_digest_new_internal(DIGEST_SHA1); -} - -/** Allocate and return a new digest object to compute 256-bit digests - * using <b>algorithm</b>. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` - * C_RUST_COUPLED: `crypto::digest::Sha256::default` - */ -crypto_digest_t * -crypto_digest256_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - return crypto_digest_new_internal(algorithm); -} - -/** Allocate and return a new digest object to compute 512-bit digests - * using <b>algorithm</b>. */ -crypto_digest_t * -crypto_digest512_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - return crypto_digest_new_internal(algorithm); -} - -/** Deallocate a digest object. - */ -void -crypto_digest_free_(crypto_digest_t *digest) -{ - if (!digest) - return; - size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - memwipe(digest, 0, bytes); - tor_free(digest); -} - -/** Add <b>len</b> bytes from <b>data</b> to the digest object. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` - * C_RUST_COUPLED: `crypto::digest::Sha256::process` - */ -void -crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, - size_t len) -{ - tor_assert(digest); - tor_assert(data); - /* Using the SHA*_*() calls directly means we don't support doing - * SHA in hardware. But so far the delay of getting the question - * to the hardware, and hearing the answer, is likely higher than - * just doing it ourselves. Hashes are fast. - */ - switch (digest->algorithm) { - case DIGEST_SHA1: - SHA1_Update(&digest->d.sha1, (void*)data, len); - break; - case DIGEST_SHA256: - SHA256_Update(&digest->d.sha2, (void*)data, len); - break; - case DIGEST_SHA512: - SHA512_Update(&digest->d.sha512, (void*)data, len); - break; - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); - break; - default: - /* LCOV_EXCL_START */ - tor_fragile_assert(); - break; - /* LCOV_EXCL_STOP */ - } -} - -/** Compute the hash of the data that has been passed to the digest - * object; write the first out_len bytes of the result to <b>out</b>. - * <b>out_len</b> must be \<= DIGEST512_LEN. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` - * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` - */ -void -crypto_digest_get_digest(crypto_digest_t *digest, - char *out, size_t out_len) -{ - unsigned char r[DIGEST512_LEN]; - crypto_digest_t tmpenv; - tor_assert(digest); - tor_assert(out); - tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); - - /* The SHA-3 code handles copying into a temporary ctx, and also can handle - * short output buffers by truncating appropriately. */ - if (digest->algorithm == DIGEST_SHA3_256 || - digest->algorithm == DIGEST_SHA3_512) { - keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); - return; - } - - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - /* memcpy into a temporary ctx, since SHA*_Final clears the context */ - memcpy(&tmpenv, digest, alloc_bytes); - switch (digest->algorithm) { - case DIGEST_SHA1: - SHA1_Final(r, &tmpenv.d.sha1); - break; - case DIGEST_SHA256: - SHA256_Final(r, &tmpenv.d.sha2); - break; - case DIGEST_SHA512: - SHA512_Final(r, &tmpenv.d.sha512); - break; -//LCOV_EXCL_START - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - default: - log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); - /* This is fatal, because it should never happen. */ - tor_assert_unreached(); - break; -//LCOV_EXCL_STOP - } - memcpy(out, r, out_len); - memwipe(r, 0, sizeof(r)); -} - -/** Allocate and return a new digest object with the same state as - * <b>digest</b> - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` - * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` - */ -crypto_digest_t * -crypto_digest_dup(const crypto_digest_t *digest) -{ - tor_assert(digest); - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - return tor_memdup(digest, alloc_bytes); -} - -/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>. - * Asserts that <b>digest</b> is a SHA1 digest object. - */ -void -crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, - const crypto_digest_t *digest) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - tor_assert(bytes <= sizeof(checkpoint->mem)); - memcpy(checkpoint->mem, digest, bytes); -} - -/** Restore the state of <b>digest</b> from <b>checkpoint</b>. - * Asserts that <b>digest</b> is a SHA1 digest object. Requires that the - * state was previously stored with crypto_digest_checkpoint() */ -void -crypto_digest_restore(crypto_digest_t *digest, - const crypto_digest_checkpoint_t *checkpoint) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - memcpy(digest, checkpoint->mem, bytes); -} - -/** Replace the state of the digest object <b>into</b> with the state - * of the digest object <b>from</b>. Requires that 'into' and 'from' - * have the same digest type. - */ -void -crypto_digest_assign(crypto_digest_t *into, - const crypto_digest_t *from) -{ - tor_assert(into); - tor_assert(from); - tor_assert(into->algorithm == from->algorithm); - const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); - memcpy(into,from,alloc_bytes); -} - -/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest - * at <b>digest_out</b> to the hash of the concatenation of those strings, - * plus the optional string <b>append</b>, computed with the algorithm - * <b>alg</b>. - * <b>out_len</b> must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist(char *digest_out, size_t len_out, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); -} - -/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest - * at <b>digest_out</b> to the hash of the concatenation of: the - * optional string <b>prepend</b>, those strings, - * and the optional string <b>append</b>, computed with the algorithm - * <b>alg</b>. - * <b>len_out</b> must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, - const char *prepend, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_t *d = crypto_digest_new_internal(alg); - if (prepend) - crypto_digest_add_bytes(d, prepend, strlen(prepend)); - SMARTLIST_FOREACH(lst, const char *, cp, - crypto_digest_add_bytes(d, cp, strlen(cp))); - if (append) - crypto_digest_add_bytes(d, append, strlen(append)); - crypto_digest_get_digest(d, digest_out, len_out); - crypto_digest_free(d); -} - -/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using - * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte - * result in <b>hmac_out</b>. Asserts on failure. - */ -void -crypto_hmac_sha256(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len) -{ - unsigned char *rv = NULL; - /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ - tor_assert(key_len < INT_MAX); - tor_assert(msg_len < INT_MAX); - tor_assert(hmac_out); - rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, - (unsigned char*)hmac_out, NULL); - tor_assert(rv); -} - -/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a - * <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length - * <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in - * <b>mac_out</b>. This function can't fail. */ -void -crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, - const uint8_t *key, size_t key_len, - const uint8_t *msg, size_t msg_len) -{ - crypto_digest_t *digest; - - const uint64_t key_len_netorder = tor_htonll(key_len); - - tor_assert(mac_out); - tor_assert(key); - tor_assert(msg); - - digest = crypto_digest256_new(DIGEST_SHA3_256); - - /* Order matters here that is any subsystem using this function should - * expect this very precise ordering in the MAC construction. */ - crypto_digest_add_bytes(digest, (const char *) &key_len_netorder, - sizeof(key_len_netorder)); - crypto_digest_add_bytes(digest, (const char *) key, key_len); - crypto_digest_add_bytes(digest, (const char *) msg, msg_len); - crypto_digest_get_digest(digest, (char *) mac_out, len_out); - crypto_digest_free(digest); -} - -/* xof functions */ - -/** Internal state for a eXtendable-Output Function (XOF). */ -struct crypto_xof_t { - keccak_state s; -}; - -/** Allocate a new XOF object backed by SHAKE-256. The security level - * provided is a function of the length of the output used. Read and - * understand FIPS-202 A.2 "Additional Consideration for Extendable-Output - * Functions" before using this construct. - */ -crypto_xof_t * -crypto_xof_new(void) -{ - crypto_xof_t *xof; - xof = tor_malloc(sizeof(crypto_xof_t)); - keccak_xof_init(&xof->s, 256); - return xof; -} - -/** Absorb bytes into a XOF object. Must not be called after a call to - * crypto_xof_squeeze_bytes() for the same instance, and will assert - * if attempted. - */ -void -crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len) -{ - int i = keccak_xof_absorb(&xof->s, data, len); - tor_assert(i == 0); -} - -/** Squeeze bytes out of a XOF object. Calling this routine will render - * the XOF instance ineligible to absorb further data. - */ -void -crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len) -{ - int i = keccak_xof_squeeze(&xof->s, out, len); - tor_assert(i == 0); -} - -/** Cleanse and deallocate a XOF object. */ -void -crypto_xof_free_(crypto_xof_t *xof) -{ - if (!xof) - return; - memwipe(xof, 0, sizeof(crypto_xof_t)); - tor_free(xof); -} - diff --git a/src/common/crypto_digest.h b/src/common/crypto_digest.h deleted file mode 100644 index 96ac038507..0000000000 --- a/src/common/crypto_digest.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_digest.h - * - * \brief Headers for crypto_digest.c - **/ - -#ifndef TOR_CRYPTO_DIGEST_H -#define TOR_CRYPTO_DIGEST_H - -#include <stdio.h> - -#include "common/container.h" -#include "lib/cc/torint.h" - -/** Length of the output of our message digest. */ -#define DIGEST_LEN 20 -/** Length of the output of our second (improved) message digests. (For now - * this is just sha256, but it could be any other 256-bit digest.) */ -#define DIGEST256_LEN 32 -/** Length of the output of our 64-bit optimized message digests (SHA512). */ -#define DIGEST512_LEN 64 - -/** Length of a sha1 message digest when encoded in base32 with trailing = - * signs removed. */ -#define BASE32_DIGEST_LEN 32 -/** Length of a sha1 message digest when encoded in base64 with trailing = - * signs removed. */ -#define BASE64_DIGEST_LEN 27 -/** Length of a sha256 message digest when encoded in base64 with trailing = - * signs removed. */ -#define BASE64_DIGEST256_LEN 43 -/** Length of a sha512 message digest when encoded in base64 with trailing = - * signs removed. */ -#define BASE64_DIGEST512_LEN 86 - -/** Length of hex encoding of SHA1 digest, not including final NUL. */ -#define HEX_DIGEST_LEN 40 -/** Length of hex encoding of SHA256 digest, not including final NUL. */ -#define HEX_DIGEST256_LEN 64 -/** Length of hex encoding of SHA512 digest, not including final NUL. */ -#define HEX_DIGEST512_LEN 128 - -typedef enum { - DIGEST_SHA1 = 0, - DIGEST_SHA256 = 1, - DIGEST_SHA512 = 2, - DIGEST_SHA3_256 = 3, - DIGEST_SHA3_512 = 4, -} digest_algorithm_t; -#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+1) -#define N_COMMON_DIGEST_ALGORITHMS (DIGEST_SHA256+1) - -#define DIGEST_CHECKPOINT_BYTES (SIZEOF_VOID_P + 512) -/** Structure used to temporarily save the a digest object. Only implemented - * for SHA1 digest for now. */ -typedef struct crypto_digest_checkpoint_t { - uint8_t mem[DIGEST_CHECKPOINT_BYTES]; -} crypto_digest_checkpoint_t; - -/** A set of all the digests we commonly compute, taken on a single - * string. Any digests that are shorter than 512 bits are right-padded - * with 0 bits. - * - * Note that this representation wastes 44 bytes for the SHA1 case, so - * don't use it for anything where we need to allocate a whole bunch at - * once. - **/ -typedef struct { - char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN]; -} common_digests_t; - -typedef struct crypto_digest_t crypto_digest_t; -typedef struct crypto_xof_t crypto_xof_t; - -/* SHA-1 and other digests */ -int crypto_digest(char *digest, const char *m, size_t len); -int crypto_digest256(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm); -int crypto_digest512(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm); -int crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len); -void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, - const char *prepend, - const struct smartlist_t *lst, - const char *append, - digest_algorithm_t alg); -void crypto_digest_smartlist(char *digest_out, size_t len_out, - const struct smartlist_t *lst, const char *append, - digest_algorithm_t alg); -const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg); -size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg); -int crypto_digest_algorithm_parse_name(const char *name); -crypto_digest_t *crypto_digest_new(void); -crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm); -crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm); -void crypto_digest_free_(crypto_digest_t *digest); -#define crypto_digest_free(d) \ - FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d)) -void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, - size_t len); -void crypto_digest_get_digest(crypto_digest_t *digest, - char *out, size_t out_len); -crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest); -void crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, - const crypto_digest_t *digest); -void crypto_digest_restore(crypto_digest_t *digest, - const crypto_digest_checkpoint_t *checkpoint); -void crypto_digest_assign(crypto_digest_t *into, - const crypto_digest_t *from); -void crypto_hmac_sha256(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len); -void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, - const uint8_t *key, size_t key_len, - const uint8_t *msg, size_t msg_len); - -/* xof functions*/ -crypto_xof_t *crypto_xof_new(void); -void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len); -void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len); -void crypto_xof_free_(crypto_xof_t *xof); -#define crypto_xof_free(xof) \ - FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof)) - -#ifdef TOR_UNIT_TESTS -digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest); -#endif - -#endif /* !defined(TOR_CRYPTO_DIGEST_H) */ - diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c deleted file mode 100644 index b0b954796c..0000000000 --- a/src/common/crypto_ed25519.c +++ /dev/null @@ -1,817 +0,0 @@ -/* Copyright (c) 2013-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_ed25519.c - * - * \brief Wrapper code for an ed25519 implementation. - * - * Ed25519 is a Schnorr signature on a Twisted Edwards curve, defined - * by Dan Bernstein. For more information, see https://ed25519.cr.yp.to/ - * - * This module wraps our choice of Ed25519 backend, and provides a few - * convenience functions for checking and generating signatures. It also - * provides Tor-specific tools for key blinding and for converting Ed25519 - * keys to and from the corresponding Curve25519 keys. - */ - -#define CRYPTO_ED25519_PRIVATE -#include "orconfig.h" -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif - -#include "common/crypto_curve25519.h" -#include "common/crypto_digest.h" -#include "common/crypto_ed25519.h" -#include "common/crypto_format.h" -#include "common/crypto_rand.h" -#include "common/crypto_util.h" -#include "common/torlog.h" -#include "common/util.h" -#include "common/util_format.h" - -#include "ed25519/ref10/ed25519_ref10.h" -#include "ed25519/donna/ed25519_donna_tor.h" - -static void pick_ed25519_impl(void); - -/** An Ed25519 implementation, as a set of function pointers. */ -typedef struct { - int (*selftest)(void); - - int (*seckey)(unsigned char *); - int (*seckey_expand)(unsigned char *, const unsigned char *); - int (*pubkey)(unsigned char *, const unsigned char *); - int (*keygen)(unsigned char *, unsigned char *); - - int (*open)(const unsigned char *, const unsigned char *, size_t, const - unsigned char *); - int (*sign)(unsigned char *, const unsigned char *, size_t, - const unsigned char *, const unsigned char *); - int (*open_batch)(const unsigned char **, size_t *, const unsigned char **, - const unsigned char **, size_t, int *); - - int (*blind_secret_key)(unsigned char *, const unsigned char *, - const unsigned char *); - int (*blind_public_key)(unsigned char *, const unsigned char *, - const unsigned char *); - - int (*pubkey_from_curve25519_pubkey)(unsigned char *, const unsigned char *, - int); - - int (*ed25519_scalarmult_with_group_order)(unsigned char *, - const unsigned char *); -} ed25519_impl_t; - -/** The Ref10 Ed25519 implementation. This one is pure C and lightly - * optimized. */ -static const ed25519_impl_t impl_ref10 = { - NULL, - - ed25519_ref10_seckey, - ed25519_ref10_seckey_expand, - ed25519_ref10_pubkey, - ed25519_ref10_keygen, - - ed25519_ref10_open, - ed25519_ref10_sign, - NULL, - - ed25519_ref10_blind_secret_key, - ed25519_ref10_blind_public_key, - - ed25519_ref10_pubkey_from_curve25519_pubkey, - ed25519_ref10_scalarmult_with_group_order, -}; - -/** The Ref10 Ed25519 implementation. This one is heavily optimized, but still - * mostly C. The C still tends to be heavily platform-specific. */ -static const ed25519_impl_t impl_donna = { - ed25519_donna_selftest, - - ed25519_donna_seckey, - ed25519_donna_seckey_expand, - ed25519_donna_pubkey, - ed25519_donna_keygen, - - ed25519_donna_open, - ed25519_donna_sign, - ed25519_sign_open_batch_donna, - - ed25519_donna_blind_secret_key, - ed25519_donna_blind_public_key, - - ed25519_donna_pubkey_from_curve25519_pubkey, - ed25519_donna_scalarmult_with_group_order, -}; - -/** Which Ed25519 implementation are we using? NULL if we haven't decided - * yet. */ -static const ed25519_impl_t *ed25519_impl = NULL; - -/** Helper: Return our chosen Ed25519 implementation. - * - * This should only be called after we've picked an implementation, but - * it _does_ recover if you forget this. - **/ -static inline const ed25519_impl_t * -get_ed_impl(void) -{ - if (BUG(ed25519_impl == NULL)) { - pick_ed25519_impl(); // LCOV_EXCL_LINE - We always call ed25519_init(). - } - return ed25519_impl; -} - -#ifdef TOR_UNIT_TESTS -/** For testing: used to remember our actual choice of Ed25519 - * implementation */ -static const ed25519_impl_t *saved_ed25519_impl = NULL; -/** For testing: Use the Ed25519 implementation called <b>name</b> until - * crypto_ed25519_testing_restore_impl is called. Recognized names are - * "donna" and "ref10". */ -void -crypto_ed25519_testing_force_impl(const char *name) -{ - tor_assert(saved_ed25519_impl == NULL); - saved_ed25519_impl = ed25519_impl; - if (! strcmp(name, "donna")) { - ed25519_impl = &impl_donna; - } else { - tor_assert(!strcmp(name, "ref10")); - ed25519_impl = &impl_ref10; - } -} -/** For testing: go back to whatever Ed25519 implementation we had picked - * before crypto_ed25519_testing_force_impl was called. - */ -void -crypto_ed25519_testing_restore_impl(void) -{ - ed25519_impl = saved_ed25519_impl; - saved_ed25519_impl = NULL; -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** - * Initialize a new ed25519 secret key in <b>seckey_out</b>. If - * <b>extra_strong</b>, take the RNG inputs directly from the operating - * system. Return 0 on success, -1 on failure. - */ -int -ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out, - int extra_strong) -{ - int r; - uint8_t seed[32]; - if (extra_strong) - crypto_strongest_rand(seed, sizeof(seed)); - else - crypto_rand((char*)seed, sizeof(seed)); - - r = get_ed_impl()->seckey_expand(seckey_out->seckey, seed); - memwipe(seed, 0, sizeof(seed)); - - return r < 0 ? -1 : 0; -} - -/** - * Given a 32-byte random seed in <b>seed</b>, expand it into an ed25519 - * secret key in <b>seckey_out</b>. Return 0 on success, -1 on failure. - */ -int -ed25519_secret_key_from_seed(ed25519_secret_key_t *seckey_out, - const uint8_t *seed) -{ - if (get_ed_impl()->seckey_expand(seckey_out->seckey, seed) < 0) - return -1; - return 0; -} - -/** - * Given a secret key in <b>seckey</b>, expand it into an - * ed25519 public key. Return 0 on success, -1 on failure. - */ -int -ed25519_public_key_generate(ed25519_public_key_t *pubkey_out, - const ed25519_secret_key_t *seckey) -{ - if (get_ed_impl()->pubkey(pubkey_out->pubkey, seckey->seckey) < 0) - return -1; - return 0; -} - -/** Generate a new ed25519 keypair in <b>keypair_out</b>. If - * <b>extra_strong</b> is set, try to mix some system entropy into the key - * generation process. Return 0 on success, -1 on failure. */ -int -ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong) -{ - if (ed25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0) - return -1; - if (ed25519_public_key_generate(&keypair_out->pubkey, - &keypair_out->seckey)<0) - return -1; - return 0; -} - -/** Return true iff 'pubkey' is set to zero (eg to indicate that it is not - * set). */ -int -ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey) -{ - return tor_mem_is_zero((char*)pubkey->pubkey, ED25519_PUBKEY_LEN); -} - -/* Return a heap-allocated array that contains <b>msg</b> prefixed by the - * string <b>prefix_str</b>. Set <b>final_msg_len_out</b> to the size of the - * final array. If an error occurred, return NULL. It's the responsibility of - * the caller to free the returned array. */ -static uint8_t * -get_prefixed_msg(const uint8_t *msg, size_t msg_len, - const char *prefix_str, - size_t *final_msg_len_out) -{ - size_t prefixed_msg_len, prefix_len; - uint8_t *prefixed_msg; - - tor_assert(prefix_str); - tor_assert(final_msg_len_out); - - prefix_len = strlen(prefix_str); - - /* msg_len + strlen(prefix_str) must not overflow. */ - if (msg_len > SIZE_T_CEILING - prefix_len) { - return NULL; - } - - prefixed_msg_len = msg_len + prefix_len; - prefixed_msg = tor_malloc_zero(prefixed_msg_len); - - memcpy(prefixed_msg, prefix_str, prefix_len); - memcpy(prefixed_msg + prefix_len, msg, msg_len); - - *final_msg_len_out = prefixed_msg_len; - return prefixed_msg; -} - -/** - * Set <b>signature_out</b> to a signature of the <b>len</b>-byte message - * <b>msg</b>, using the secret and public key in <b>keypair</b>. - * - * Return 0 if we successfully signed the message, otherwise return -1. - */ -int -ed25519_sign(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const ed25519_keypair_t *keypair) -{ - if (get_ed_impl()->sign(signature_out->sig, msg, len, - keypair->seckey.seckey, - keypair->pubkey.pubkey) < 0) { - return -1; - } - - return 0; -} - -/** - * Like ed25519_sign(), but also prefix <b>msg</b> with <b>prefix_str</b> - * before signing. <b>prefix_str</b> must be a NUL-terminated string. - */ -MOCK_IMPL(int, -ed25519_sign_prefixed,(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t msg_len, - const char *prefix_str, - const ed25519_keypair_t *keypair)) -{ - int retval; - size_t prefixed_msg_len; - uint8_t *prefixed_msg; - - tor_assert(prefix_str); - - prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, - &prefixed_msg_len); - if (BUG(!prefixed_msg)) { - /* LCOV_EXCL_START -- only possible when the message and prefix are - * ridiculously huge */ - log_warn(LD_GENERAL, "Failed to get prefixed msg."); - return -1; - /* LCOV_EXCL_STOP */ - } - - retval = ed25519_sign(signature_out, - prefixed_msg, prefixed_msg_len, - keypair); - tor_free(prefixed_msg); - - return retval; -} - -/** - * Check whether if <b>signature</b> is a valid signature for the - * <b>len</b>-byte message in <b>msg</b> made with the key <b>pubkey</b>. - * - * Return 0 if the signature is valid; -1 if it isn't. - */ -MOCK_IMPL(int, -ed25519_checksig,(const ed25519_signature_t *signature, - const uint8_t *msg, size_t len, - const ed25519_public_key_t *pubkey)) -{ - return - get_ed_impl()->open(signature->sig, msg, len, pubkey->pubkey) < 0 ? -1 : 0; -} - -/** - * Like ed2519_checksig(), but also prefix <b>msg</b> with <b>prefix_str</b> - * before verifying signature. <b>prefix_str</b> must be a NUL-terminated - * string. - */ -int -ed25519_checksig_prefixed(const ed25519_signature_t *signature, - const uint8_t *msg, size_t msg_len, - const char *prefix_str, - const ed25519_public_key_t *pubkey) -{ - int retval; - size_t prefixed_msg_len; - uint8_t *prefixed_msg; - - prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, - &prefixed_msg_len); - if (BUG(!prefixed_msg)) { - /* LCOV_EXCL_START -- only possible when the message and prefix are - * ridiculously huge */ - log_warn(LD_GENERAL, "Failed to get prefixed msg."); - return -1; - /* LCOV_EXCL_STOP */ - } - - retval = ed25519_checksig(signature, - prefixed_msg, prefixed_msg_len, - pubkey); - tor_free(prefixed_msg); - - return retval; -} - -/** Validate every signature among those in <b>checkable</b>, which contains - * exactly <b>n_checkable</b> elements. If <b>okay_out</b> is non-NULL, set - * the i'th element of <b>okay_out</b> to 1 if the i'th element of - * <b>checkable</b> is valid, and to 0 otherwise. Return 0 if every signature - * was valid. Otherwise return -N, where N is the number of invalid - * signatures. - */ -MOCK_IMPL(int, -ed25519_checksig_batch,(int *okay_out, - const ed25519_checkable_t *checkable, - int n_checkable)) -{ - int i, res; - const ed25519_impl_t *impl = get_ed_impl(); - - if (impl->open_batch == NULL) { - /* No batch verification implementation available, fake it by checking the - * each signature individually. - */ - res = 0; - for (i = 0; i < n_checkable; ++i) { - const ed25519_checkable_t *ch = &checkable[i]; - int r = ed25519_checksig(&ch->signature, ch->msg, ch->len, ch->pubkey); - if (r < 0) - --res; - if (okay_out) - okay_out[i] = (r == 0); - } - } else { - /* ed25519-donna style batch verification available. - * - * Theoretically, this should only be called if n_checkable >= 3, since - * that's the threshold where the batch verification actually kicks in, - * but the only difference is a few mallocs/frees. - */ - const uint8_t **ms; - size_t *lens; - const uint8_t **pks; - const uint8_t **sigs; - int *oks; - int all_ok; - - ms = tor_calloc(n_checkable, sizeof(uint8_t*)); - lens = tor_calloc(n_checkable, sizeof(size_t)); - pks = tor_calloc(n_checkable, sizeof(uint8_t*)); - sigs = tor_calloc(n_checkable, sizeof(uint8_t*)); - oks = okay_out ? okay_out : tor_calloc(n_checkable, sizeof(int)); - - for (i = 0; i < n_checkable; ++i) { - ms[i] = checkable[i].msg; - lens[i] = checkable[i].len; - pks[i] = checkable[i].pubkey->pubkey; - sigs[i] = checkable[i].signature.sig; - oks[i] = 0; - } - - res = 0; - all_ok = impl->open_batch(ms, lens, pks, sigs, n_checkable, oks); - for (i = 0; i < n_checkable; ++i) { - if (!oks[i]) - --res; - } - /* XXX: For now sanity check oks with the return value. Once we have - * more confidence in the code, if `all_ok == 0` we can skip iterating - * over oks since all the signatures were found to be valid. - */ - tor_assert(((res == 0) && !all_ok) || ((res < 0) && all_ok)); - - tor_free(ms); - tor_free(lens); - tor_free(pks); - tor_free(sigs); - if (! okay_out) - tor_free(oks); - } - - return res; -} - -/** - * Given a curve25519 keypair in <b>inp</b>, generate a corresponding - * ed25519 keypair in <b>out</b>, and set <b>signbit_out</b> to the - * sign bit of the X coordinate of the ed25519 key. - * - * NOTE THAT IT IS PROBABLY NOT SAFE TO USE THE GENERATED KEY FOR ANYTHING - * OUTSIDE OF WHAT'S PRESENTED IN PROPOSAL 228. In particular, it's probably - * not a great idea to use it to sign attacker-supplied anything. - */ -int -ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, - int *signbit_out, - const curve25519_keypair_t *inp) -{ - const char string[] = "Derive high part of ed25519 key from curve25519 key"; - ed25519_public_key_t pubkey_check; - crypto_digest_t *ctx; - uint8_t sha512_output[DIGEST512_LEN]; - - memcpy(out->seckey.seckey, inp->seckey.secret_key, 32); - - ctx = crypto_digest512_new(DIGEST_SHA512); - crypto_digest_add_bytes(ctx, (const char*)out->seckey.seckey, 32); - crypto_digest_add_bytes(ctx, (const char*)string, sizeof(string)); - crypto_digest_get_digest(ctx, (char *)sha512_output, sizeof(sha512_output)); - crypto_digest_free(ctx); - memcpy(out->seckey.seckey + 32, sha512_output, 32); - - ed25519_public_key_generate(&out->pubkey, &out->seckey); - - *signbit_out = out->pubkey.pubkey[31] >> 7; - - ed25519_public_key_from_curve25519_public_key(&pubkey_check, &inp->pubkey, - *signbit_out); - - tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); - - memwipe(&pubkey_check, 0, sizeof(pubkey_check)); - memwipe(sha512_output, 0, sizeof(sha512_output)); - - return 0; -} - -/** - * Given a curve25519 public key and sign bit of X coordinate of the ed25519 - * public key, generate the corresponding ed25519 public key. - */ -int -ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, - const curve25519_public_key_t *pubkey_in, - int signbit) -{ - return get_ed_impl()->pubkey_from_curve25519_pubkey(pubkey->pubkey, - pubkey_in->public_key, - signbit); -} - -/** - * Given an ed25519 keypair in <b>inp</b>, generate a corresponding - * ed25519 keypair in <b>out</b>, blinded by the corresponding 32-byte input - * in 'param'. - * - * Tor uses key blinding for the "next-generation" hidden services design: - * service descriptors are encrypted with a key derived from the service's - * long-term public key, and then signed with (and stored at a position - * indexed by) a short-term key derived by blinding the long-term keys. - * - * Return 0 if blinding was successful, else return -1. */ -int -ed25519_keypair_blind(ed25519_keypair_t *out, - const ed25519_keypair_t *inp, - const uint8_t *param) -{ - ed25519_public_key_t pubkey_check; - - get_ed_impl()->blind_secret_key(out->seckey.seckey, - inp->seckey.seckey, param); - - if (ed25519_public_blind(&pubkey_check, &inp->pubkey, param) < 0) { - return -1; - } - ed25519_public_key_generate(&out->pubkey, &out->seckey); - - tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); - - memwipe(&pubkey_check, 0, sizeof(pubkey_check)); - - return 0; -} - -/** - * Given an ed25519 public key in <b>inp</b>, generate a corresponding blinded - * public key in <b>out</b>, blinded with the 32-byte parameter in - * <b>param</b>. Return 0 on success, -1 on railure. - */ -int -ed25519_public_blind(ed25519_public_key_t *out, - const ed25519_public_key_t *inp, - const uint8_t *param) -{ - return get_ed_impl()->blind_public_key(out->pubkey, inp->pubkey, param); -} - -/** - * Store seckey unencrypted to <b>filename</b>, marking it with <b>tag</b>. - * Return 0 on success, -1 on failure. - */ -int -ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey, - const char *filename, - const char *tag) -{ - return crypto_write_tagged_contents_to_file(filename, - "ed25519v1-secret", - tag, - seckey->seckey, - sizeof(seckey->seckey)); -} - -/** - * Read seckey unencrypted from <b>filename</b>, storing it into - * <b>seckey_out</b>. Set *<b>tag_out</b> to the tag it was marked with. - * Return 0 on success, -1 on failure. - */ -int -ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out, - char **tag_out, - const char *filename) -{ - ssize_t len; - - len = crypto_read_tagged_contents_from_file(filename, "ed25519v1-secret", - tag_out, seckey_out->seckey, - sizeof(seckey_out->seckey)); - if (len == sizeof(seckey_out->seckey)) { - return 0; - } else if (len >= 0) { - errno = EINVAL; - } - - tor_free(*tag_out); - return -1; -} - -/** - * Store pubkey unencrypted to <b>filename</b>, marking it with <b>tag</b>. - * Return 0 on success, -1 on failure. - */ -int -ed25519_pubkey_write_to_file(const ed25519_public_key_t *pubkey, - const char *filename, - const char *tag) -{ - return crypto_write_tagged_contents_to_file(filename, - "ed25519v1-public", - tag, - pubkey->pubkey, - sizeof(pubkey->pubkey)); -} - -/** - * Store pubkey unencrypted to <b>filename</b>, marking it with <b>tag</b>. - * Return 0 on success, -1 on failure. - */ -int -ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, - char **tag_out, - const char *filename) -{ - ssize_t len; - - len = crypto_read_tagged_contents_from_file(filename, "ed25519v1-public", - tag_out, pubkey_out->pubkey, - sizeof(pubkey_out->pubkey)); - if (len == sizeof(pubkey_out->pubkey)) { - return 0; - } else if (len >= 0) { - errno = EINVAL; - } - - tor_free(*tag_out); - return -1; -} - -/** Release all storage held for <b>kp</b>. */ -void -ed25519_keypair_free_(ed25519_keypair_t *kp) -{ - if (! kp) - return; - - memwipe(kp, 0, sizeof(*kp)); - tor_free(kp); -} - -/** Return true iff <b>key1</b> and <b>key2</b> are the same public key. */ -int -ed25519_pubkey_eq(const ed25519_public_key_t *key1, - const ed25519_public_key_t *key2) -{ - tor_assert(key1); - tor_assert(key2); - return tor_memeq(key1->pubkey, key2->pubkey, ED25519_PUBKEY_LEN); -} - -/** - * Set <b>dest</b> to contain the same key as <b>src</b>. - */ -void -ed25519_pubkey_copy(ed25519_public_key_t *dest, - const ed25519_public_key_t *src) -{ - tor_assert(dest); - tor_assert(src); - memcpy(dest, src, sizeof(ed25519_public_key_t)); -} - -/** Check whether the given Ed25519 implementation seems to be working. - * If so, return 0; otherwise return -1. */ -MOCK_IMPL(STATIC int, -ed25519_impl_spot_check,(void)) -{ - static const uint8_t alicesk[32] = { - 0xc5,0xaa,0x8d,0xf4,0x3f,0x9f,0x83,0x7b, - 0xed,0xb7,0x44,0x2f,0x31,0xdc,0xb7,0xb1, - 0x66,0xd3,0x85,0x35,0x07,0x6f,0x09,0x4b, - 0x85,0xce,0x3a,0x2e,0x0b,0x44,0x58,0xf7 - }; - static const uint8_t alicepk[32] = { - 0xfc,0x51,0xcd,0x8e,0x62,0x18,0xa1,0xa3, - 0x8d,0xa4,0x7e,0xd0,0x02,0x30,0xf0,0x58, - 0x08,0x16,0xed,0x13,0xba,0x33,0x03,0xac, - 0x5d,0xeb,0x91,0x15,0x48,0x90,0x80,0x25 - }; - static const uint8_t alicemsg[2] = { 0xaf, 0x82 }; - static const uint8_t alicesig[64] = { - 0x62,0x91,0xd6,0x57,0xde,0xec,0x24,0x02, - 0x48,0x27,0xe6,0x9c,0x3a,0xbe,0x01,0xa3, - 0x0c,0xe5,0x48,0xa2,0x84,0x74,0x3a,0x44, - 0x5e,0x36,0x80,0xd7,0xdb,0x5a,0xc3,0xac, - 0x18,0xff,0x9b,0x53,0x8d,0x16,0xf2,0x90, - 0xae,0x67,0xf7,0x60,0x98,0x4d,0xc6,0x59, - 0x4a,0x7c,0x15,0xe9,0x71,0x6e,0xd2,0x8d, - 0xc0,0x27,0xbe,0xce,0xea,0x1e,0xc4,0x0a - }; - const ed25519_impl_t *impl = get_ed_impl(); - uint8_t sk[ED25519_SECKEY_LEN]; - uint8_t pk[ED25519_PUBKEY_LEN]; - uint8_t sig[ED25519_SIG_LEN]; - int r = 0; - - /* Some implementations (eg: The modified Ed25519-donna) have handy self-test - * code that sanity-checks the internals. If present, use that to screen out - * catastrophic errors like massive compiler failure. - */ - if (impl->selftest && impl->selftest() != 0) - goto fail; - - /* Validate results versus known answer tests. People really should be - * running "make test" instead of relying on this, but it's better than - * nothing. - * - * Test vectors taken from "EdDSA & Ed25519 - 6. Test Vectors for Ed25519 - * (TEST3)" (draft-josefsson-eddsa-ed25519-03). - */ - - /* Key expansion, public key derivation. */ - if (impl->seckey_expand(sk, alicesk) < 0) - goto fail; - if (impl->pubkey(pk, sk) < 0) - goto fail; - if (fast_memneq(pk, alicepk, ED25519_PUBKEY_LEN)) - goto fail; - - /* Signing, verification. */ - if (impl->sign(sig, alicemsg, sizeof(alicemsg), sk, pk) < 0) - return -1; - if (fast_memneq(sig, alicesig, ED25519_SIG_LEN)) - return -1; - if (impl->open(sig, alicemsg, sizeof(alicemsg), pk) < 0) - return -1; - - /* XXX/yawning: Someone that's more paranoid than I am, can write "Assume - * ref0 is canonical, and fuzz impl against it" if they want, but I doubt - * that will catch anything that the known answer tests won't. - */ - goto end; - - // LCOV_EXCL_START -- We can only reach this if our ed25519 implementation is - // broken. - fail: - r = -1; - // LCOV_EXCL_STOP - end: - return r; -} - -/** Force the Ed25519 implementation to a given one, without sanity checking - * the output. Used for testing. - */ -void -ed25519_set_impl_params(int use_donna) -{ - if (use_donna) - ed25519_impl = &impl_donna; - else - ed25519_impl = &impl_ref10; -} - -/** Choose whether to use the Ed25519-donna implementation. */ -static void -pick_ed25519_impl(void) -{ - ed25519_impl = &impl_donna; - - if (ed25519_impl_spot_check() == 0) - return; - - /* LCOV_EXCL_START - * unreachable unless ed25519_donna is broken */ - log_warn(LD_CRYPTO, "The Ed25519-donna implementation seems broken; using " - "the ref10 implementation."); - ed25519_impl = &impl_ref10; - /* LCOV_EXCL_STOP */ -} - -/* Initialize the Ed25519 implementation. This is necessary if you're - * going to use them in a multithreaded setting, and not otherwise. */ -void -ed25519_init(void) -{ - pick_ed25519_impl(); -} - -/* Return true if <b>point</b> is the identity element of the ed25519 group. */ -static int -ed25519_point_is_identity_element(const uint8_t *point) -{ - /* The identity element in ed25159 is the point with coordinates (0,1). */ - static const uint8_t ed25519_identity[32] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - tor_assert(sizeof(ed25519_identity) == ED25519_PUBKEY_LEN); - return tor_memeq(point, ed25519_identity, sizeof(ed25519_identity)); -} - -/** Validate <b>pubkey</b> to ensure that it has no torsion component. - * Return 0 if <b>pubkey</b> is valid, else return -1. */ -int -ed25519_validate_pubkey(const ed25519_public_key_t *pubkey) -{ - uint8_t result[32] = {9}; - - /* First check that we were not given the identity element */ - if (ed25519_point_is_identity_element(pubkey->pubkey)) { - log_warn(LD_CRYPTO, "ed25519 pubkey is the identity"); - return -1; - } - - /* For any point on the curve, doing l*point should give the identity element - * (where l is the group order). Do the computation and check that the - * identity element is returned. */ - if (get_ed_impl()->ed25519_scalarmult_with_group_order(result, - pubkey->pubkey) < 0) { - log_warn(LD_CRYPTO, "ed25519 group order scalarmult failed"); - return -1; - } - - if (!ed25519_point_is_identity_element(result)) { - log_warn(LD_CRYPTO, "ed25519 validation failed"); - return -1; - } - - return 0; -} - diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h deleted file mode 100644 index 981b0dce28..0000000000 --- a/src/common/crypto_ed25519.h +++ /dev/null @@ -1,145 +0,0 @@ -/* Copyright (c) 2012-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_ED25519_H -#define TOR_CRYPTO_ED25519_H - -#include "common/testsupport.h" -#include "lib/cc/torint.h" -#include "common/crypto_curve25519.h" -#include "common/util.h" - -#define ED25519_PUBKEY_LEN 32 -#define ED25519_SECKEY_LEN 64 -#define ED25519_SECKEY_SEED_LEN 32 -#define ED25519_SIG_LEN 64 - -/** An Ed25519 signature. */ -typedef struct { - uint8_t sig[ED25519_SIG_LEN]; -} ed25519_signature_t; - -/** An Ed25519 public key */ -typedef struct { - uint8_t pubkey[ED25519_PUBKEY_LEN]; -} ed25519_public_key_t; - -/** An Ed25519 secret key */ -typedef struct { - /** Note that we store secret keys in an expanded format that doesn't match - * the format from standard ed25519. Ed25519 stores a 32-byte value k and - * expands it into a 64-byte H(k), using the first 32 bytes for a multiplier - * of the base point, and second 32 bytes as an input to a hash function - * for deriving r. But because we implement key blinding, we need to store - * keys in the 64-byte expanded form. */ - uint8_t seckey[ED25519_SECKEY_LEN]; -} ed25519_secret_key_t; - -/** An Ed25519 keypair. */ -typedef struct { - ed25519_public_key_t pubkey; - ed25519_secret_key_t seckey; -} ed25519_keypair_t; - -int ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out, - int extra_strong); -int ed25519_secret_key_from_seed(ed25519_secret_key_t *seckey_out, - const uint8_t *seed); - -int ed25519_public_key_generate(ed25519_public_key_t *pubkey_out, - const ed25519_secret_key_t *seckey); -int ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong); -int ed25519_sign(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const ed25519_keypair_t *key); -MOCK_DECL(int,ed25519_checksig,(const ed25519_signature_t *signature, - const uint8_t *msg, size_t len, - const ed25519_public_key_t *pubkey)); - -MOCK_DECL(int, -ed25519_sign_prefixed,(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const char *prefix_str, - const ed25519_keypair_t *keypair)); - -int -ed25519_checksig_prefixed(const ed25519_signature_t *signature, - const uint8_t *msg, size_t len, - const char *prefix_str, - const ed25519_public_key_t *pubkey); - -int ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey); - -/** - * A collection of information necessary to check an Ed25519 signature. Used - * for batch verification. - */ -typedef struct { - /** The public key that supposedly generated the signature. */ - const ed25519_public_key_t *pubkey; - /** The signature to check. */ - ed25519_signature_t signature; - /** The message that the signature is supposed to have been applied to. */ - const uint8_t *msg; - /** The length of the message. */ - size_t len; -} ed25519_checkable_t; - -MOCK_DECL(int, ed25519_checksig_batch,(int *okay_out, - const ed25519_checkable_t *checkable, - int n_checkable)); - -int ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, - int *signbit_out, - const curve25519_keypair_t *inp); - -int ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, - const curve25519_public_key_t *pubkey_in, - int signbit); -int ed25519_keypair_blind(ed25519_keypair_t *out, - const ed25519_keypair_t *inp, - const uint8_t *param); -int ed25519_public_blind(ed25519_public_key_t *out, - const ed25519_public_key_t *inp, - const uint8_t *param); - -/* XXXX read encrypted, write encrypted. */ - -int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey, - const char *filename, - const char *tag); -int ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out, - char **tag_out, - const char *filename); -int ed25519_pubkey_write_to_file(const ed25519_public_key_t *pubkey, - const char *filename, - const char *tag); -int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, - char **tag_out, - const char *filename); - -void ed25519_keypair_free_(ed25519_keypair_t *kp); -#define ed25519_keypair_free(kp) \ - FREE_AND_NULL(ed25519_keypair_t, ed25519_keypair_free_, (kp)) - -int ed25519_pubkey_eq(const ed25519_public_key_t *key1, - const ed25519_public_key_t *key2); -void ed25519_pubkey_copy(ed25519_public_key_t *dest, - const ed25519_public_key_t *src); - -void ed25519_set_impl_params(int use_donna); -void ed25519_init(void); - -int ed25519_validate_pubkey(const ed25519_public_key_t *pubkey); - -#ifdef TOR_UNIT_TESTS -void crypto_ed25519_testing_force_impl(const char *name); -void crypto_ed25519_testing_restore_impl(void); -#endif - -#ifdef CRYPTO_ED25519_PRIVATE -MOCK_DECL(STATIC int, ed25519_impl_spot_check, (void)); -#endif - -#endif /* !defined(TOR_CRYPTO_ED25519_H) */ - diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c deleted file mode 100644 index 6245b70ccb..0000000000 --- a/src/common/crypto_format.c +++ /dev/null @@ -1,299 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_format.c - * - * \brief Formatting and parsing code for crypto-related data structures. - */ - -#include "orconfig.h" -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#include "common/container.h" -#include "common/crypto_curve25519.h" -#include "common/crypto_digest.h" -#include "common/crypto_ed25519.h" -#include "common/crypto_format.h" -#include "common/crypto_util.h" -#include "common/util.h" -#include "common/util_format.h" -#include "common/torlog.h" - -/** Write the <b>datalen</b> bytes from <b>data</b> to the file named - * <b>fname</b> in the tagged-data format. This format contains a - * 32-byte header, followed by the data itself. The header is the - * NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length - * of <b>typestring</b> and <b>tag</b> must therefore be no more than - * 24. - **/ -int -crypto_write_tagged_contents_to_file(const char *fname, - const char *typestring, - const char *tag, - const uint8_t *data, - size_t datalen) -{ - char header[32]; - smartlist_t *chunks = smartlist_new(); - sized_chunk_t ch0, ch1; - int r = -1; - - memset(header, 0, sizeof(header)); - if (tor_snprintf(header, sizeof(header), - "== %s: %s ==", typestring, tag) < 0) - goto end; - ch0.bytes = header; - ch0.len = 32; - ch1.bytes = (const char*) data; - ch1.len = datalen; - smartlist_add(chunks, &ch0); - smartlist_add(chunks, &ch1); - - r = write_chunks_to_file(fname, chunks, 1, 0); - - end: - smartlist_free(chunks); - return r; -} - -/** Read a tagged-data file from <b>fname</b> into the - * <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the - * typestring matches <b>typestring</b>; store the tag into a newly allocated - * string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of - * data on success. Preserves the errno from reading the file. */ -ssize_t -crypto_read_tagged_contents_from_file(const char *fname, - const char *typestring, - char **tag_out, - uint8_t *data_out, - ssize_t data_out_len) -{ - char prefix[33]; - char *content = NULL; - struct stat st; - ssize_t r = -1; - size_t st_size = 0; - int saved_errno = 0; - - *tag_out = NULL; - st.st_size = 0; - content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); - if (! content) { - saved_errno = errno; - goto end; - } - if (st.st_size < 32 || st.st_size > 32 + data_out_len) { - saved_errno = EINVAL; - goto end; - } - st_size = (size_t)st.st_size; - - memcpy(prefix, content, 32); - prefix[32] = 0; - /* Check type, extract tag. */ - if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") || - ! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) { - saved_errno = EINVAL; - goto end; - } - - if (strcmpstart(prefix+3, typestring) || - 3+strlen(typestring) >= 32 || - strcmpstart(prefix+3+strlen(typestring), ": ")) { - saved_errno = EINVAL; - goto end; - } - - *tag_out = tor_strndup(prefix+5+strlen(typestring), - strlen(prefix)-8-strlen(typestring)); - - memcpy(data_out, content+32, st_size-32); - r = st_size - 32; - - end: - if (content) - memwipe(content, 0, st_size); - tor_free(content); - if (saved_errno) - errno = saved_errno; - return r; -} - -/** Encode <b>pkey</b> as a base64-encoded string, without trailing "=" - * characters, in the buffer <b>output</b>, which must have at least - * CURVE25519_BASE64_PADDED_LEN+1 bytes available. Return 0 on success, -1 on - * failure. */ -int -curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey) -{ - char buf[128]; - base64_encode(buf, sizeof(buf), - (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN, 0); - buf[CURVE25519_BASE64_PADDED_LEN] = '\0'; - memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1); - return 0; -} - -/** Try to decode a base64-encoded curve25519 public key from <b>input</b> - * into the object at <b>pkey</b>. Return 0 on success, -1 on failure. - * Accepts keys with or without a trailing "=". */ -int -curve25519_public_from_base64(curve25519_public_key_t *pkey, - const char *input) -{ - size_t len = strlen(input); - if (len == CURVE25519_BASE64_PADDED_LEN - 1) { - /* not padded */ - return digest256_from_base64((char*)pkey->public_key, input); - } else if (len == CURVE25519_BASE64_PADDED_LEN) { - char buf[128]; - if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN) - return -1; - memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN); - return 0; - } else { - return -1; - } -} - -/** For logging convenience: Convert <b>pkey</b> to a statically allocated - * base64 string and return it. Not threadsafe. Format not meant to be - * computer-readable; it may change in the future. Subsequent calls invalidate - * previous returns. */ -const char * -ed25519_fmt(const ed25519_public_key_t *pkey) -{ - static char formatted[ED25519_BASE64_LEN+1]; - if (pkey) { - if (ed25519_public_key_is_zero(pkey)) { - strlcpy(formatted, "<unset>", sizeof(formatted)); - } else { - int r = ed25519_public_to_base64(formatted, pkey); - tor_assert(!r); - } - } else { - strlcpy(formatted, "<null>", sizeof(formatted)); - } - return formatted; -} - -/** Try to decode the string <b>input</b> into an ed25519 public key. On - * success, store the value in <b>pkey</b> and return 0. Otherwise return - * -1. */ -int -ed25519_public_from_base64(ed25519_public_key_t *pkey, - const char *input) -{ - return digest256_from_base64((char*)pkey->pubkey, input); -} - -/** Encode the public key <b>pkey</b> into the buffer at <b>output</b>, - * which must have space for ED25519_BASE64_LEN bytes of encoded key, - * plus one byte for a terminating NUL. Return 0 on success, -1 on failure. - */ -int -ed25519_public_to_base64(char *output, - const ed25519_public_key_t *pkey) -{ - return digest256_to_base64(output, (const char *)pkey->pubkey); -} - -/** Encode the signature <b>sig</b> into the buffer at <b>output</b>, - * which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature, - * plus one byte for a terminating NUL. Return 0 on success, -1 on failure. - */ -int -ed25519_signature_to_base64(char *output, - const ed25519_signature_t *sig) -{ - char buf[256]; - int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN); - tor_assert(n == ED25519_SIG_BASE64_LEN); - memcpy(output, buf, ED25519_SIG_BASE64_LEN+1); - return 0; -} - -/** Try to decode the string <b>input</b> into an ed25519 signature. On - * success, store the value in <b>sig</b> and return 0. Otherwise return - * -1. */ -int -ed25519_signature_from_base64(ed25519_signature_t *sig, - const char *input) -{ - - if (strlen(input) != ED25519_SIG_BASE64_LEN) - return -1; - char buf[ED25519_SIG_BASE64_LEN+3]; - memcpy(buf, input, ED25519_SIG_BASE64_LEN); - buf[ED25519_SIG_BASE64_LEN+0] = '='; - buf[ED25519_SIG_BASE64_LEN+1] = '='; - buf[ED25519_SIG_BASE64_LEN+2] = 0; - char decoded[128]; - int n = base64_decode(decoded, sizeof(decoded), buf, strlen(buf)); - if (n < 0 || n != ED25519_SIG_LEN) - return -1; - memcpy(sig->sig, decoded, ED25519_SIG_LEN); - - return 0; -} - -/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing = - * characters, and store the nul-terminated result in the first - * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */ -/* XXXX unify with crypto_format.c code */ -int -digest_to_base64(char *d64, const char *digest) -{ - char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0); - buf[BASE64_DIGEST_LEN] = '\0'; - memcpy(d64, buf, BASE64_DIGEST_LEN+1); - return 0; -} - -/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without - * trailing newline or = characters), decode it and store the result in the - * first DIGEST_LEN bytes at <b>digest</b>. */ -/* XXXX unify with crypto_format.c code */ -int -digest_from_base64(char *digest, const char *d64) -{ - if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN) - return 0; - else - return -1; -} - -/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the - * trailing = characters, and store the nul-terminated result in the first - * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */ - /* XXXX unify with crypto_format.c code */ -int -digest256_to_base64(char *d64, const char *digest) -{ - char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0); - buf[BASE64_DIGEST256_LEN] = '\0'; - memcpy(d64, buf, BASE64_DIGEST256_LEN+1); - return 0; -} - -/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without - * trailing newline or = characters), decode it and store the result in the - * first DIGEST256_LEN bytes at <b>digest</b>. */ -/* XXXX unify with crypto_format.c code */ -int -digest256_from_base64(char *digest, const char *d64) -{ - if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN) - return 0; - else - return -1; -} - diff --git a/src/common/crypto_format.h b/src/common/crypto_format.h deleted file mode 100644 index 47f52b94b7..0000000000 --- a/src/common/crypto_format.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_FORMAT_H -#define TOR_CRYPTO_FORMAT_H - -#include "common/testsupport.h" -#include "lib/cc/torint.h" -#include "common/crypto_ed25519.h" - -int crypto_write_tagged_contents_to_file(const char *fname, - const char *typestring, - const char *tag, - const uint8_t *data, - size_t datalen); - -ssize_t crypto_read_tagged_contents_from_file(const char *fname, - const char *typestring, - char **tag_out, - uint8_t *data_out, - ssize_t data_out_len); - -#define ED25519_BASE64_LEN 43 -int ed25519_public_from_base64(ed25519_public_key_t *pkey, - const char *input); -int ed25519_public_to_base64(char *output, - const ed25519_public_key_t *pkey); -const char *ed25519_fmt(const ed25519_public_key_t *pkey); - -/* XXXX move these to crypto_format.h */ -#define ED25519_SIG_BASE64_LEN 86 - -int ed25519_signature_from_base64(ed25519_signature_t *sig, - const char *input); -int ed25519_signature_to_base64(char *output, - const ed25519_signature_t *sig); - -int digest_to_base64(char *d64, const char *digest); -int digest_from_base64(char *digest, const char *d64); -int digest256_to_base64(char *d64, const char *digest); -int digest256_from_base64(char *digest, const char *d64); - -#endif /* !defined(TOR_CRYPTO_FORMAT_H) */ - diff --git a/src/common/crypto_hkdf.c b/src/common/crypto_hkdf.c deleted file mode 100644 index 8dc15b6ffb..0000000000 --- a/src/common/crypto_hkdf.c +++ /dev/null @@ -1,193 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_hkdf.c - * \brief Block of functions related with HKDF utilities and operations. - **/ - -#include "common/crypto_hkdf.h" -#include "common/crypto_util.h" -#include "common/crypto_digest.h" - -#include "common/crypto_openssl_mgt.h" -#include <openssl/opensslv.h> - -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) -#define HAVE_OPENSSL_HKDF 1 -#include <openssl/kdf.h> -#endif - -/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b> - * ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in - * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of - * H(K | [00]) | H(K | [01]) | .... - * - * This is the key expansion algorithm used in the "TAP" circuit extension - * mechanism; it shouldn't be used for new protocols. - * - * Return 0 on success, -1 on failure. - */ -int -crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, - uint8_t *key_out, size_t key_out_len) -{ - int i, r = -1; - uint8_t *cp, *tmp = tor_malloc(key_in_len+1); - uint8_t digest[DIGEST_LEN]; - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST_LEN*256); - - memcpy(tmp, key_in, key_in_len); - for (cp = key_out, i=0; cp < key_out+key_out_len; - ++i, cp += DIGEST_LEN) { - tmp[key_in_len] = i; - if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) - goto exit; - memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); - } - - r = 0; - exit: - memwipe(tmp, 0, key_in_len+1); - tor_free(tmp); - memwipe(digest, 0, sizeof(digest)); - return r; -} - -#ifdef HAVE_OPENSSL_HKDF -/** - * Perform RFC5869 HKDF computation using OpenSSL (only to be called from - * crypto_expand_key_material_rfc5869_sha256_openssl). Note that OpenSSL - * requires input key to be nonempty and salt length to be equal or less - * than 1024. - */ -static int -crypto_expand_key_material_rfc5869_sha256_openssl( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len) -{ - int r; - EVP_PKEY_CTX *evp_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); - tor_assert(evp_pkey_ctx); - tor_assert(key_in_len != 0); - tor_assert(salt_in_len <= 1024); - - r = EVP_PKEY_derive_init(evp_pkey_ctx); - tor_assert(r == 1); - - r = EVP_PKEY_CTX_set_hkdf_md(evp_pkey_ctx, EVP_sha256()); - tor_assert(r == 1); - - r = EVP_PKEY_CTX_set1_hkdf_salt(evp_pkey_ctx, salt_in, (int)salt_in_len); - tor_assert(r == 1); - - r = EVP_PKEY_CTX_set1_hkdf_key(evp_pkey_ctx, key_in, (int)key_in_len); - tor_assert(r == 1); - - r = EVP_PKEY_CTX_add1_hkdf_info(evp_pkey_ctx, info_in, (int)info_in_len); - tor_assert(r == 1); - - r = EVP_PKEY_derive(evp_pkey_ctx, key_out, &key_out_len); - tor_assert(r == 1); - - EVP_PKEY_CTX_free(evp_pkey_ctx); - return 0; -} - -#else - -/** - * Perform RFC5869 HKDF computation using our own legacy implementation. - * Only to be called from crypto_expand_key_material_rfc5869_sha256_openssl. - */ -static int -crypto_expand_key_material_rfc5869_sha256_legacy( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len) -{ - uint8_t prk[DIGEST256_LEN]; - uint8_t tmp[DIGEST256_LEN + 128 + 1]; - uint8_t mac[DIGEST256_LEN]; - int i; - uint8_t *outp; - size_t tmp_len; - - crypto_hmac_sha256((char*)prk, - (const char*)salt_in, salt_in_len, - (const char*)key_in, key_in_len); - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST256_LEN * 256); - tor_assert(info_in_len <= 128); - memset(tmp, 0, sizeof(tmp)); - outp = key_out; - i = 1; - - while (key_out_len) { - size_t n; - if (i > 1) { - memcpy(tmp, mac, DIGEST256_LEN); - memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); - tmp[DIGEST256_LEN+info_in_len] = i; - tmp_len = DIGEST256_LEN + info_in_len + 1; - } else { - memcpy(tmp, info_in, info_in_len); - tmp[info_in_len] = i; - tmp_len = info_in_len + 1; - } - crypto_hmac_sha256((char*)mac, - (const char*)prk, DIGEST256_LEN, - (const char*)tmp, tmp_len); - n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; - memcpy(outp, mac, n); - key_out_len -= n; - outp += n; - ++i; - } - - memwipe(tmp, 0, sizeof(tmp)); - memwipe(mac, 0, sizeof(mac)); - return 0; -} -#endif - -/** Expand some secret key material according to RFC5869, using SHA256 as the - * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the - * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the - * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" - * and "info" parameters respectively. On success, write <b>key_out_len</b> - * bytes to <b>key_out</b> and return 0. Assert on failure. - */ -int -crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len) -{ - tor_assert(key_in); - tor_assert(key_in_len > 0); - -#ifdef HAVE_OPENSSL_HKDF - return crypto_expand_key_material_rfc5869_sha256_openssl(key_in, - key_in_len, salt_in, - salt_in_len, info_in, - info_in_len, - key_out, key_out_len); -#else - return crypto_expand_key_material_rfc5869_sha256_legacy(key_in, - key_in_len, salt_in, - salt_in_len, info_in, - info_in_len, - key_out, key_out_len); -#endif -} diff --git a/src/common/crypto_hkdf.h b/src/common/crypto_hkdf.h deleted file mode 100644 index 784f4bbbe4..0000000000 --- a/src/common/crypto_hkdf.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_hkdf.h - * - * \brief Headers for crypto_hkdf.h - **/ - -#ifndef TOR_CRYPTO_HKDF_H -#define TOR_CRYPTO_HKDF_H - -#include "common/util.h" - -int crypto_expand_key_material_TAP(const uint8_t *key_in, - size_t key_in_len, - uint8_t *key_out, size_t key_out_len); -int crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len); - -#endif /* !defined(TOR_CRYPTO_HKDF_H) */ - diff --git a/src/common/crypto_openssl_mgt.c b/src/common/crypto_openssl_mgt.c deleted file mode 100644 index 8acb9cdf1c..0000000000 --- a/src/common/crypto_openssl_mgt.c +++ /dev/null @@ -1,161 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_openssl.c - * - * \brief Block of functions related to operations from OpenSSL. - **/ - -#include "common/compat_openssl.h" -#include "common/crypto_openssl_mgt.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/rsa.h> -#include <openssl/pem.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/rand.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> -#include <openssl/crypto.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#ifndef NEW_THREAD_API -/** A number of preallocated mutexes for use by OpenSSL. */ -static tor_mutex_t **openssl_mutexes_ = NULL; -/** How many mutexes have we allocated for use by OpenSSL? */ -static int n_openssl_mutexes_ = 0; -#endif /* !defined(NEW_THREAD_API) */ - -/** Declare STATIC functions */ -STATIC char * parse_openssl_version_str(const char *raw_version); -#ifndef NEW_THREAD_API -STATIC void openssl_locking_cb_(int mode, int n, const char *file, int line); -STATIC void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid); -#endif - -/* Returns a trimmed and human-readable version of an openssl version string -* <b>raw_version</b>. They are usually in the form of 'OpenSSL 1.0.0b 10 -* May 2012' and this will parse them into a form similar to '1.0.0b' */ -STATIC char * -parse_openssl_version_str(const char *raw_version) -{ - const char *end_of_version = NULL; - /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's - trim that down. */ - if (!strcmpstart(raw_version, "OpenSSL ")) { - raw_version += strlen("OpenSSL "); - end_of_version = strchr(raw_version, ' '); - } - - if (end_of_version) - return tor_strndup(raw_version, - end_of_version-raw_version); - else - return tor_strdup(raw_version); -} - -static char *crypto_openssl_version_str = NULL; -/* Return a human-readable version of the run-time openssl version number. */ -const char * -crypto_openssl_get_version_str(void) -{ - if (crypto_openssl_version_str == NULL) { - const char *raw_version = OpenSSL_version(OPENSSL_VERSION); - crypto_openssl_version_str = parse_openssl_version_str(raw_version); - } - return crypto_openssl_version_str; -} - -static char *crypto_openssl_header_version_str = NULL; -/* Return a human-readable version of the compile-time openssl version -* number. */ -const char * -crypto_openssl_get_header_version_str(void) -{ - if (crypto_openssl_header_version_str == NULL) { - crypto_openssl_header_version_str = - parse_openssl_version_str(OPENSSL_VERSION_TEXT); - } - return crypto_openssl_header_version_str; -} - -#ifndef OPENSSL_THREADS -#error OpenSSL has been built without thread support. Tor requires an \ - OpenSSL library with thread support enabled. -#endif - -#ifndef NEW_THREAD_API -/** Helper: OpenSSL uses this callback to manipulate mutexes. */ -STATIC void -openssl_locking_cb_(int mode, int n, const char *file, int line) -{ - (void)file; - (void)line; - if (!openssl_mutexes_) - /* This is not a really good fix for the - * "release-freed-lock-from-separate-thread-on-shutdown" problem, but - * it can't hurt. */ - return; - if (mode & CRYPTO_LOCK) - tor_mutex_acquire(openssl_mutexes_[n]); - else - tor_mutex_release(openssl_mutexes_[n]); -} - -STATIC void -tor_set_openssl_thread_id(CRYPTO_THREADID *threadid) -{ - CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id()); -} -#endif /* !defined(NEW_THREAD_API) */ - -/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being - * multithreaded. Returns 0. */ -int -setup_openssl_threading(void) -{ -#ifndef NEW_THREAD_API - int i; - int n = CRYPTO_num_locks(); - n_openssl_mutexes_ = n; - openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *)); - for (i=0; i < n; ++i) - openssl_mutexes_[i] = tor_mutex_new(); - CRYPTO_set_locking_callback(openssl_locking_cb_); - CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id); -#endif /* !defined(NEW_THREAD_API) */ - return 0; -} - -/** free OpenSSL variables */ -void -crypto_openssl_free_all(void) -{ - tor_free(crypto_openssl_version_str); - tor_free(crypto_openssl_header_version_str); - -#ifndef NEW_THREAD_API - if (n_openssl_mutexes_) { - int n = n_openssl_mutexes_; - tor_mutex_t **ms = openssl_mutexes_; - int i; - openssl_mutexes_ = NULL; - n_openssl_mutexes_ = 0; - for (i=0;i<n;++i) { - tor_mutex_free(ms[i]); - } - tor_free(ms); - } -#endif /* !defined(NEW_THREAD_API) */ -} - diff --git a/src/common/crypto_openssl_mgt.h b/src/common/crypto_openssl_mgt.h deleted file mode 100644 index e3f5531b7d..0000000000 --- a/src/common/crypto_openssl_mgt.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_openssl.h - * - * \brief Headers for crypto_openssl.c - **/ - -#ifndef TOR_CRYPTO_OPENSSL_H -#define TOR_CRYPTO_OPENSSL_H - -#include <stdio.h> -#include "common/util.h" - -#include <openssl/engine.h> - -/* - Macro to create an arbitrary OpenSSL version number as used by - OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard - to read. - - Don't use this directly, instead use one of the other OPENSSL_V macros - below. - - The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit - status. - */ -#define OPENSSL_VER(a,b,c,d,e) \ - (((a)<<28) | \ - ((b)<<20) | \ - ((c)<<12) | \ - ((d)<< 4) | \ - (e)) -/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the - * version for the released version of 0.9.8j */ -#define OPENSSL_V(a,b,c,d) \ - OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf) -/** An openssl release number for the first release in the series. For - * example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL - * 1.0.0. */ -#define OPENSSL_V_NOPATCH(a,b,c) \ - OPENSSL_VER((a),(b),(c),0,0xf) -/** The first version that would occur for any alpha or beta in an openssl - * series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released - * 0.9.7, and less than any released 0.9.8. */ -#define OPENSSL_V_SERIES(a,b,c) \ - OPENSSL_VER((a),(b),(c),0,0) - -#ifdef ANDROID -/* Android's OpenSSL seems to have removed all of its Engine support. */ -#define DISABLE_ENGINES -#endif - -#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \ - !defined(LIBRESSL_VERSION_NUMBER) -/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require - * seting up various callbacks. - * - * OpenSSL 1.1.0pre4 has a messed up `ERR_remove_thread_state()` prototype, - * while the previous one was restored in pre5, and the function made a no-op - * (along with a deprecated annotation, which produces a compiler warning). - * - * While it is possible to support all three versions of the thread API, - * a version that existed only for one snapshot pre-release is kind of - * pointless, so let's not. - */ -#define NEW_THREAD_API -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */ - -/* global openssl state */ -const char * crypto_openssl_get_version_str(void); -const char * crypto_openssl_get_header_version_str(void); - -/* OpenSSL threading setup function */ -int setup_openssl_threading(void); - -/* Tor OpenSSL utility functions */ -void crypto_openssl_free_all(void); - -#endif /* !defined(TOR_CRYPTO_OPENSSL_H) */ - diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c deleted file mode 100644 index 799a8799e6..0000000000 --- a/src/common/crypto_pwbox.c +++ /dev/null @@ -1,215 +0,0 @@ -/* Copyright (c) 2014-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_pwbox.c - * - * \brief Code for encrypting secrets in a password-protected form and saving - * them to disk. - */ - -#include "common/crypto.h" -#include "common/crypto_digest.h" -#include "common/crypto_pwbox.h" -#include "common/crypto_rand.h" -#include "common/crypto_s2k.h" -#include "common/crypto_util.h" -#include "lib/ctime/di_ops.h" -#include "common/util.h" -#include "trunnel/pwbox.h" - -/* 8 bytes "TORBOX00" - 1 byte: header len (H) - H bytes: header, denoting secret key algorithm. - 16 bytes: IV - Round up to multiple of 128 bytes, then encrypt: - 4 bytes: data len - data - zeros - 32 bytes: HMAC-SHA256 of all previous bytes. -*/ - -#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN) - -/** - * Make an authenticated passphrase-encrypted blob to encode the - * <b>input_len</b> bytes in <b>input</b> using the passphrase - * <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory - * to hold the encrypted data, and store a pointer to that memory in - * *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an - * argument to the passphrase-hashing function. - */ -int -crypto_pwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *input, size_t input_len, - const char *secret, size_t secret_len, - unsigned s2k_flags) -{ - uint8_t *result = NULL, *encrypted_portion; - size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128); - ssize_t result_len; - int spec_len; - uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; - pwbox_encoded_t *enc = NULL; - ssize_t enc_len; - - crypto_cipher_t *cipher; - int rv; - - enc = pwbox_encoded_new(); - - pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN); - - spec_len = secret_to_key_make_specifier( - pwbox_encoded_getarray_skey_header(enc), - S2K_MAXLEN, - s2k_flags); - if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN)) - goto err; - pwbox_encoded_setlen_skey_header(enc, spec_len); - enc->header_len = spec_len; - - crypto_rand((char*)enc->iv, sizeof(enc->iv)); - - pwbox_encoded_setlen_data(enc, encrypted_len); - encrypted_portion = pwbox_encoded_getarray_data(enc); - - set_uint32(encrypted_portion, htonl((uint32_t)input_len)); - memcpy(encrypted_portion+4, input, input_len); - - /* Now that all the data is in position, derive some keys, encrypt, and - * digest */ - const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys), - pwbox_encoded_getarray_skey_header(enc), - spec_len, - secret, secret_len); - if (BUG(s2k_rv < 0)) - goto err; - - cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); - crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len); - crypto_cipher_free(cipher); - - result_len = pwbox_encoded_encoded_len(enc); - if (BUG(result_len < 0)) - goto err; - result = tor_malloc(result_len); - enc_len = pwbox_encoded_encode(result, result_len, enc); - if (BUG(enc_len < 0)) - goto err; - tor_assert(enc_len == result_len); - - crypto_hmac_sha256((char*) result + result_len - 32, - (const char*)keys + CIPHER_KEY_LEN, - DIGEST256_LEN, - (const char*)result, - result_len - 32); - - *out = result; - *outlen_out = result_len; - rv = 0; - goto out; - - /* LCOV_EXCL_START - - This error case is often unreachable if we're correctly coded, unless - somebody adds a new error case somewhere, or unless you're building - without scrypto support. - - - make_specifier can't fail, unless S2K_MAX_LEN is too short. - - secret_to_key_derivekey can't really fail unless we're missing - scrypt, or the underlying function fails, or we pass it a bogus - algorithm or parameters. - - pwbox_encoded_encoded_len can't fail unless we're using trunnel - incorrectly. - - pwbox_encoded_encode can't fail unless we're using trunnel wrong, - or it's buggy. - */ - err: - tor_free(result); - rv = -1; - /* LCOV_EXCL_STOP */ - out: - pwbox_encoded_free(enc); - memwipe(keys, 0, sizeof(keys)); - return rv; -} - -/** - * Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in - * <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes. - * On success, return 0 and allocate a new chunk of memory to hold the - * decrypted data, and store a pointer to that memory in *<b>out</b>, and its - * size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if - * the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is - * definitely corrupt. - */ -int -crypto_unpwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *inp, size_t input_len, - const char *secret, size_t secret_len) -{ - uint8_t *result = NULL; - const uint8_t *encrypted; - uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; - uint8_t hmac[DIGEST256_LEN]; - uint32_t result_len; - size_t encrypted_len; - crypto_cipher_t *cipher = NULL; - int rv = UNPWBOX_CORRUPTED; - ssize_t got_len; - - pwbox_encoded_t *enc = NULL; - - got_len = pwbox_encoded_parse(&enc, inp, input_len); - if (got_len < 0 || (size_t)got_len != input_len) - goto err; - - /* Now derive the keys and check the hmac. */ - if (secret_to_key_derivekey(keys, sizeof(keys), - pwbox_encoded_getarray_skey_header(enc), - pwbox_encoded_getlen_skey_header(enc), - secret, secret_len) < 0) - goto err; - - crypto_hmac_sha256((char *)hmac, - (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN, - (const char*)inp, input_len - DIGEST256_LEN); - - if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) { - rv = UNPWBOX_BAD_SECRET; - goto err; - } - - /* How long is the plaintext? */ - encrypted = pwbox_encoded_getarray_data(enc); - encrypted_len = pwbox_encoded_getlen_data(enc); - if (encrypted_len < 4) - goto err; - - cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); - crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4); - result_len = ntohl(result_len); - if (encrypted_len < result_len + 4) - goto err; - - /* Allocate a buffer and decrypt */ - result = tor_malloc_zero(result_len); - crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len); - - *out = result; - *outlen_out = result_len; - - rv = UNPWBOX_OKAY; - goto out; - - err: - tor_free(result); - - out: - crypto_cipher_free(cipher); - pwbox_encoded_free(enc); - memwipe(keys, 0, sizeof(keys)); - return rv; -} - diff --git a/src/common/crypto_pwbox.h b/src/common/crypto_pwbox.h deleted file mode 100644 index 9ed35a150e..0000000000 --- a/src/common/crypto_pwbox.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2014-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef CRYPTO_PWBOX_H_INCLUDED_ -#define CRYPTO_PWBOX_H_INCLUDED_ - -#include "lib/cc/torint.h" - -#define UNPWBOX_OKAY 0 -#define UNPWBOX_BAD_SECRET -1 -#define UNPWBOX_CORRUPTED -2 - -int crypto_pwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *inp, size_t input_len, - const char *secret, size_t secret_len, - unsigned s2k_flags); - -int crypto_unpwbox(uint8_t **out, size_t *outlen_out, - const uint8_t *inp, size_t input_len, - const char *secret, size_t secret_len); - -#endif /* !defined(CRYPTO_PWBOX_H_INCLUDED_) */ - diff --git a/src/common/crypto_rand.c b/src/common/crypto_rand.c deleted file mode 100644 index 6c88e28d88..0000000000 --- a/src/common/crypto_rand.c +++ /dev/null @@ -1,615 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rand.c - * - * \brief Functions for initialising and seeding (pseudo-)random - * number generators, and working with randomness. - **/ - -#ifndef CRYPTO_RAND_PRIVATE -#define CRYPTO_RAND_PRIVATE - -#include "common/crypto_rand.h" - -#ifdef _WIN32 -#include <windows.h> -#include <wincrypt.h> -#endif /* defined(_WIN32) */ - -#include "common/container.h" -#include "common/compat.h" -#include "common/compat_openssl.h" -#include "common/crypto_util.h" -#include "common/sandbox.h" -#include "common/testsupport.h" -#include "common/torlog.h" -#include "common/util.h" -#include "common/util_format.h" - -DISABLE_GCC_WARNING(redundant-decls) -#include <openssl/rand.h> -ENABLE_GCC_WARNING(redundant-decls) - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif /* __GNUC__ && GCC_VERSION >= 402 */ - -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_SYSCALL_H -#include <sys/syscall.h> -#endif -#ifdef HAVE_SYS_RANDOM_H -#include <sys/random.h> -#endif - -/** - * How many bytes of entropy we add at once. - * - * This is how much entropy OpenSSL likes to add right now, so maybe it will - * work for us too. - **/ -#define ADD_ENTROPY 32 - -/** - * Longest recognized DNS query. - **/ -#define MAX_DNS_LABEL_SIZE 63 - -/** - * Largest strong entropy request permitted. - **/ -#define MAX_STRONGEST_RAND_SIZE 256 - -/** - * Set the seed of the weak RNG to a random value. - **/ -void -crypto_seed_weak_rng(tor_weak_rng_t *rng) -{ - unsigned seed; - crypto_rand((void*)&seed, sizeof(seed)); - tor_init_weak_random(rng, seed); -} - -#ifdef TOR_UNIT_TESTS -int break_strongest_rng_syscall = 0; -int break_strongest_rng_fallback = 0; -#endif - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * via system calls, storing it into <b>out</b>. Return 0 on success, -1 on - * failure. A maximum request size of 256 bytes is imposed. - **/ -static int -crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) -{ - tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE); - - /* We only log at notice-level here because in the case that this function - * fails the crypto_strongest_rand_raw() caller will log with a warning-level - * message and let crypto_strongest_rand() error out and finally terminating - * Tor with an assertion error. - */ - -#ifdef TOR_UNIT_TESTS - if (break_strongest_rng_syscall) - return -1; -#endif - -#if defined(_WIN32) - static int provider_set = 0; - static HCRYPTPROV provider; - - if (!provider_set) { - if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - log_notice(LD_CRYPTO, "Unable to set Windows CryptoAPI provider [1]."); - return -1; - } - provider_set = 1; - } - if (!CryptGenRandom(provider, out_len, out)) { - log_notice(LD_CRYPTO, "Unable get entropy from the Windows CryptoAPI."); - return -1; - } - - return 0; -#elif defined(__linux__) && defined(SYS_getrandom) - static int getrandom_works = 1; /* Be optimistic about our chances... */ - - /* getrandom() isn't as straightforward as getentropy(), and has - * no glibc wrapper. - * - * As far as I can tell from getrandom(2) and the source code, the - * requests we issue will always succeed (though it will block on the - * call if /dev/urandom isn't seeded yet), since we are NOT specifying - * GRND_NONBLOCK and the request is <= 256 bytes. - * - * The manpage is unclear on what happens if a signal interrupts the call - * while the request is blocked due to lack of entropy.... - * - * We optimistically assume that getrandom() is available and functional - * because it is the way of the future, and 2 branch mispredicts pale in - * comparison to the overheads involved with failing to open - * /dev/srandom followed by opening and reading from /dev/urandom. - */ - if (PREDICT_LIKELY(getrandom_works)) { - long ret; - /* A flag of '0' here means to read from '/dev/urandom', and to - * block if insufficient entropy is available to service the - * request. - */ - const unsigned int flags = 0; - do { - ret = syscall(SYS_getrandom, out, out_len, flags); - } while (ret == -1 && ((errno == EINTR) ||(errno == EAGAIN))); - - if (PREDICT_UNLIKELY(ret == -1)) { - /* LCOV_EXCL_START we can't actually make the syscall fail in testing. */ - tor_assert(errno != EAGAIN); - tor_assert(errno != EINTR); - - /* Useful log message for errno. */ - if (errno == ENOSYS) { - log_notice(LD_CRYPTO, "Can't get entropy from getrandom()." - " You are running a version of Tor built to support" - " getrandom(), but the kernel doesn't implement this" - " function--probably because it is too old?" - " Trying fallback method instead."); - } else { - log_notice(LD_CRYPTO, "Can't get entropy from getrandom(): %s." - " Trying fallback method instead.", - strerror(errno)); - } - - getrandom_works = 0; /* Don't bother trying again. */ - return -1; - /* LCOV_EXCL_STOP */ - } - - tor_assert(ret == (long)out_len); - return 0; - } - - return -1; /* getrandom() previously failed unexpectedly. */ -#elif defined(HAVE_GETENTROPY) - /* getentropy() is what Linux's getrandom() wants to be when it grows up. - * the only gotcha is that requests are limited to 256 bytes. - */ - return getentropy(out, out_len); -#else - (void) out; -#endif /* defined(_WIN32) || ... */ - - /* This platform doesn't have a supported syscall based random. */ - return -1; -} - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * via the per-platform fallback mechanism, storing it into <b>out</b>. - * Return 0 on success, -1 on failure. A maximum request size of 256 bytes - * is imposed. - **/ -static int -crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) -{ -#ifdef TOR_UNIT_TESTS - if (break_strongest_rng_fallback) - return -1; -#endif - -#ifdef _WIN32 - /* Windows exclusively uses crypto_strongest_rand_syscall(). */ - (void)out; - (void)out_len; - return -1; -#else /* !(defined(_WIN32)) */ - static const char *filenames[] = { - "/dev/srandom", "/dev/urandom", "/dev/random", NULL - }; - int fd, i; - size_t n; - - for (i = 0; filenames[i]; ++i) { - log_debug(LD_FS, "Considering %s as entropy source", filenames[i]); - fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0); - if (fd<0) continue; - log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); - n = read_all(fd, (char*)out, out_len, 0); - close(fd); - if (n != out_len) { - /* LCOV_EXCL_START - * We can't make /dev/foorandom actually fail. */ - log_notice(LD_CRYPTO, - "Error reading from entropy source %s (read only %lu bytes).", - filenames[i], - (unsigned long)n); - return -1; - /* LCOV_EXCL_STOP */ - } - - return 0; - } - - return -1; -#endif /* defined(_WIN32) */ -} - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * storing it into <b>out</b>. Return 0 on success, -1 on failure. A maximum - * request size of 256 bytes is imposed. - **/ -STATIC int -crypto_strongest_rand_raw(uint8_t *out, size_t out_len) -{ - static const size_t sanity_min_size = 16; - static const int max_attempts = 3; - tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE); - - /* For buffers >= 16 bytes (128 bits), we sanity check the output by - * zero filling the buffer and ensuring that it actually was at least - * partially modified. - * - * Checking that any individual byte is non-zero seems like it would - * fail too often (p = out_len * 1/256) for comfort, but this is an - * "adjust according to taste" sort of check. - */ - memwipe(out, 0, out_len); - for (int i = 0; i < max_attempts; i++) { - /* Try to use the syscall/OS favored mechanism to get strong entropy. */ - if (crypto_strongest_rand_syscall(out, out_len) != 0) { - /* Try to use the less-favored mechanism to get strong entropy. */ - if (crypto_strongest_rand_fallback(out, out_len) != 0) { - /* Welp, we tried. Hopefully the calling code terminates the process - * since we're basically boned without good entropy. - */ - log_warn(LD_CRYPTO, - "Cannot get strong entropy: no entropy source found."); - return -1; - } - } - - if ((out_len < sanity_min_size) || !tor_mem_is_zero((char*)out, out_len)) - return 0; - } - - /* LCOV_EXCL_START - * - * We tried max_attempts times to fill a buffer >= 128 bits long, - * and each time it returned all '0's. Either the system entropy - * source is busted, or the user should go out and buy a ticket to - * every lottery on the planet. - */ - log_warn(LD_CRYPTO, "Strong OS entropy returned all zero buffer."); - - return -1; - /* LCOV_EXCL_STOP */ -} - -/** - * Try to get <b>out_len</b> bytes of the strongest entropy we can generate, - * storing it into <b>out</b>. - **/ -void -crypto_strongest_rand(uint8_t *out, size_t out_len) -{ -#define DLEN SHA512_DIGEST_LENGTH - /* We're going to hash DLEN bytes from the system RNG together with some - * bytes from the openssl PRNG, in order to yield DLEN bytes. - */ - uint8_t inp[DLEN*2]; - uint8_t tmp[DLEN]; - tor_assert(out); - while (out_len) { - crypto_rand((char*) inp, DLEN); - if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) { - // LCOV_EXCL_START - log_err(LD_CRYPTO, "Failed to load strong entropy when generating an " - "important key. Exiting."); - /* Die with an assertion so we get a stack trace. */ - tor_assert(0); - // LCOV_EXCL_STOP - } - if (out_len >= DLEN) { - SHA512(inp, sizeof(inp), out); - out += DLEN; - out_len -= DLEN; - } else { - SHA512(inp, sizeof(inp), tmp); - memcpy(out, tmp, out_len); - break; - } - } - memwipe(tmp, 0, sizeof(tmp)); - memwipe(inp, 0, sizeof(inp)); -#undef DLEN -} - -/** - * Seed OpenSSL's random number generator with bytes from the operating - * system. Return 0 on success, -1 on failure. - **/ -int -crypto_seed_rng(void) -{ - int rand_poll_ok = 0, load_entropy_ok = 0; - uint8_t buf[ADD_ENTROPY]; - - /* OpenSSL has a RAND_poll function that knows about more kinds of - * entropy than we do. We'll try calling that, *and* calling our own entropy - * functions. If one succeeds, we'll accept the RNG as seeded. */ - rand_poll_ok = RAND_poll(); - if (rand_poll_ok == 0) - log_warn(LD_CRYPTO, "RAND_poll() failed."); // LCOV_EXCL_LINE - - load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf)); - if (load_entropy_ok) { - RAND_seed(buf, sizeof(buf)); - } - - memwipe(buf, 0, sizeof(buf)); - - if ((rand_poll_ok || load_entropy_ok) && RAND_status() == 1) - return 0; - else - return -1; -} - -/** - * Write <b>n</b> bytes of strong random data to <b>to</b>. Supports mocking - * for unit tests. - * - * This function is not allowed to fail; if it would fail to generate strong - * entropy, it must terminate the process instead. - **/ -MOCK_IMPL(void, -crypto_rand, (char *to, size_t n)) -{ - crypto_rand_unmocked(to, n); -} - -/** - * Write <b>n</b> bytes of strong random data to <b>to</b>. Most callers - * will want crypto_rand instead. - * - * This function is not allowed to fail; if it would fail to generate strong - * entropy, it must terminate the process instead. - **/ -void -crypto_rand_unmocked(char *to, size_t n) -{ - int r; - if (n == 0) - return; - - tor_assert(n < INT_MAX); - tor_assert(to); - r = RAND_bytes((unsigned char*)to, (int)n); - /* We consider a PRNG failure non-survivable. Let's assert so that we get a - * stack trace about where it happened. - */ - tor_assert(r >= 0); -} - -/** - * Return a pseudorandom integer, chosen uniformly from the values - * between 0 and <b>max</b>-1 inclusive. <b>max</b> must be between 1 and - * INT_MAX+1, inclusive. - */ -int -crypto_rand_int(unsigned int max) -{ - unsigned int val; - unsigned int cutoff; - tor_assert(max <= ((unsigned int)INT_MAX)+1); - tor_assert(max > 0); /* don't div by 0 */ - - /* We ignore any values that are >= 'cutoff,' to avoid biasing the - * distribution with clipping at the upper end of unsigned int's - * range. - */ - cutoff = UINT_MAX - (UINT_MAX%max); - while (1) { - crypto_rand((char*)&val, sizeof(val)); - if (val < cutoff) - return val % max; - } -} - -/** - * Return a pseudorandom integer, chosen uniformly from the values i such - * that min <= i < max. - * - * <b>min</b> MUST be in range [0, <b>max</b>). - * <b>max</b> MUST be in range (min, INT_MAX]. - **/ -int -crypto_rand_int_range(unsigned int min, unsigned int max) -{ - tor_assert(min < max); - tor_assert(max <= INT_MAX); - - /* The overflow is avoided here because crypto_rand_int() returns a value - * between 0 and (max - min) inclusive. */ - return min + crypto_rand_int(max - min); -} - -/** - * As crypto_rand_int_range, but supports uint64_t. - **/ -uint64_t -crypto_rand_uint64_range(uint64_t min, uint64_t max) -{ - tor_assert(min < max); - return min + crypto_rand_uint64(max - min); -} - -/** - * As crypto_rand_int_range, but supports time_t. - **/ -time_t -crypto_rand_time_range(time_t min, time_t max) -{ - tor_assert(min < max); - return min + (time_t)crypto_rand_uint64(max - min); -} - -/** - * Return a pseudorandom 64-bit integer, chosen uniformly from the values - * between 0 and <b>max</b>-1 inclusive. - **/ -uint64_t -crypto_rand_uint64(uint64_t max) -{ - uint64_t val; - uint64_t cutoff; - tor_assert(max < UINT64_MAX); - tor_assert(max > 0); /* don't div by 0 */ - - /* We ignore any values that are >= 'cutoff,' to avoid biasing the - * distribution with clipping at the upper end of unsigned int's - * range. - */ - cutoff = UINT64_MAX - (UINT64_MAX%max); - while (1) { - crypto_rand((char*)&val, sizeof(val)); - if (val < cutoff) - return val % max; - } -} - -/** - * Return a pseudorandom double d, chosen uniformly from the range - * 0.0 <= d < 1.0. - **/ -double -crypto_rand_double(void) -{ - /* We just use an unsigned int here; we don't really care about getting - * more than 32 bits of resolution */ - unsigned int u; - crypto_rand((char*)&u, sizeof(u)); -#if SIZEOF_INT == 4 -#define UINT_MAX_AS_DOUBLE 4294967296.0 -#elif SIZEOF_INT == 8 -#define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19 -#else -#error SIZEOF_INT is neither 4 nor 8 -#endif /* SIZEOF_INT == 4 || ... */ - return ((double)u) / UINT_MAX_AS_DOUBLE; -} - -/** - * Generate and return a new random hostname starting with <b>prefix</b>, - * ending with <b>suffix</b>, and containing no fewer than - * <b>min_rand_len</b> and no more than <b>max_rand_len</b> random base32 - * characters. Does not check for failure. - * - * Clip <b>max_rand_len</b> to MAX_DNS_LABEL_SIZE. - **/ -char * -crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix, - const char *suffix) -{ - char *result, *rand_bytes; - int randlen, rand_bytes_len; - size_t resultlen, prefixlen; - - if (max_rand_len > MAX_DNS_LABEL_SIZE) - max_rand_len = MAX_DNS_LABEL_SIZE; - if (min_rand_len > max_rand_len) - min_rand_len = max_rand_len; - - randlen = crypto_rand_int_range(min_rand_len, max_rand_len+1); - - prefixlen = strlen(prefix); - resultlen = prefixlen + strlen(suffix) + randlen + 16; - - rand_bytes_len = ((randlen*5)+7)/8; - if (rand_bytes_len % 5) - rand_bytes_len += 5 - (rand_bytes_len%5); - rand_bytes = tor_malloc(rand_bytes_len); - crypto_rand(rand_bytes, rand_bytes_len); - - result = tor_malloc(resultlen); - memcpy(result, prefix, prefixlen); - base32_encode(result+prefixlen, resultlen-prefixlen, - rand_bytes, rand_bytes_len); - tor_free(rand_bytes); - strlcpy(result+prefixlen+randlen, suffix, resultlen-(prefixlen+randlen)); - - return result; -} - -/** - * Return a randomly chosen element of <b>sl</b>; or NULL if <b>sl</b> - * is empty. - **/ -void * -smartlist_choose(const smartlist_t *sl) -{ - int len = smartlist_len(sl); - if (len) - return smartlist_get(sl,crypto_rand_int(len)); - return NULL; /* no elements to choose from */ -} - -/** - * Scramble the elements of <b>sl</b> into a random order. - **/ -void -smartlist_shuffle(smartlist_t *sl) -{ - int i; - /* From the end of the list to the front, choose at random from the - positions we haven't looked at yet, and swap that position into the - current position. Remember to give "no swap" the same probability as - any other swap. */ - for (i = smartlist_len(sl)-1; i > 0; --i) { - int j = crypto_rand_int(i+1); - smartlist_swap(sl, i, j); - } -} - -/** Make sure that openssl is using its default PRNG. Return 1 if we had to - * adjust it; 0 otherwise. */ -int -crypto_force_rand_ssleay(void) -{ - RAND_METHOD *default_method; - default_method = RAND_OpenSSL(); - if (RAND_get_rand_method() != default_method) { - log_notice(LD_CRYPTO, "It appears that one of our engines has provided " - "a replacement the OpenSSL RNG. Resetting it to the default " - "implementation."); - RAND_set_rand_method(default_method); - return 1; - } - return 0; -} - -#endif /* !defined(CRYPTO_RAND_PRIVATE) */ - diff --git a/src/common/crypto_rand.h b/src/common/crypto_rand.h deleted file mode 100644 index 8309bb21ca..0000000000 --- a/src/common/crypto_rand.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rand.h - * - * \brief Common functions for using (pseudo-)random number generators. - **/ - -#ifndef TOR_CRYPTO_RAND_H -#define TOR_CRYPTO_RAND_H - -#include "lib/cc/torint.h" -#include "common/util.h" - -/* random numbers */ -int crypto_seed_rng(void) ATTR_WUR; -MOCK_DECL(void,crypto_rand,(char *to, size_t n)); -void crypto_rand_unmocked(char *to, size_t n); -void crypto_strongest_rand(uint8_t *out, size_t out_len); -int crypto_rand_int(unsigned int max); -int crypto_rand_int_range(unsigned int min, unsigned int max); -uint64_t crypto_rand_uint64_range(uint64_t min, uint64_t max); -time_t crypto_rand_time_range(time_t min, time_t max); -uint64_t crypto_rand_uint64(uint64_t max); -double crypto_rand_double(void); -struct tor_weak_rng_t; -void crypto_seed_weak_rng(struct tor_weak_rng_t *rng); - -char *crypto_random_hostname(int min_rand_len, int max_rand_len, - const char *prefix, const char *suffix); - -struct smartlist_t; -void *smartlist_choose(const struct smartlist_t *sl); -void smartlist_shuffle(struct smartlist_t *sl); -int crypto_force_rand_ssleay(void); - -#ifdef CRYPTO_RAND_PRIVATE - -STATIC int crypto_strongest_rand_raw(uint8_t *out, size_t out_len); - -#ifdef TOR_UNIT_TESTS -extern int break_strongest_rng_syscall; -extern int break_strongest_rng_fallback; -#endif -#endif /* defined(CRYPTO_RAND_PRIVATE) */ - -#endif /* !defined(TOR_CRYPTO_RAND_H) */ - diff --git a/src/common/crypto_rsa.c b/src/common/crypto_rsa.c deleted file mode 100644 index 3128983435..0000000000 --- a/src/common/crypto_rsa.c +++ /dev/null @@ -1,1162 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rsa.c - * \brief Block of functions related with RSA utilities and operations. - **/ - -#include "common/crypto.h" -#include "common/crypto_curve25519.h" -#include "common/crypto_digest.h" -#include "common/crypto_format.h" -#include "common/compat_openssl.h" -#include "common/crypto_rand.h" -#include "common/crypto_rsa.h" -#include "common/crypto_util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/rsa.h> -#include <openssl/pem.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/rand.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#include "common/torlog.h" -#include "common/util.h" -#include "common/util_format.h" - -/** Declaration for crypto_pk_t structure. */ -struct crypto_pk_t -{ - int refs; /**< reference count, so we don't have to copy keys */ - RSA *key; /**< The key itself */ -}; - -/** Return the number of bytes added by padding method <b>padding</b>. - */ -int -crypto_get_rsa_padding_overhead(int padding) -{ - switch (padding) - { - case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD; - default: tor_assert(0); return -1; // LCOV_EXCL_LINE - } -} - -/** Given a padding method <b>padding</b>, return the correct OpenSSL constant. - */ -int -crypto_get_rsa_padding(int padding) -{ - switch (padding) - { - case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING; - default: tor_assert(0); return -1; // LCOV_EXCL_LINE - } -} - -/** used internally: quicly validate a crypto_pk_t object as a private key. - * Return 1 iff the public key is valid, 0 if obviously invalid. - */ -static int -crypto_pk_private_ok(const crypto_pk_t *k) -{ -#ifdef OPENSSL_1_1_API - if (!k || !k->key) - return 0; - - const BIGNUM *p, *q; - RSA_get0_factors(k->key, &p, &q); - return p != NULL; /* XXX/yawning: Should we check q? */ -#else /* !(defined(OPENSSL_1_1_API)) */ - return k && k->key && k->key->p; -#endif /* defined(OPENSSL_1_1_API) */ -} - -/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */ -crypto_pk_t * -crypto_new_pk_from_rsa_(RSA *rsa) -{ - crypto_pk_t *env; - tor_assert(rsa); - env = tor_malloc(sizeof(crypto_pk_t)); - env->refs = 1; - env->key = rsa; - return env; -} - -/** Helper, used by tor-gencert.c. Return the RSA from a - * crypto_pk_t. */ -RSA * -crypto_pk_get_rsa_(crypto_pk_t *env) -{ - return env->key; -} - -/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff - * private is set, include the private-key portion of the key. Return a valid - * pointer on success, and NULL on failure. */ -MOCK_IMPL(EVP_PKEY *, -crypto_pk_get_evp_pkey_,(crypto_pk_t *env, int private)) -{ - RSA *key = NULL; - EVP_PKEY *pkey = NULL; - tor_assert(env->key); - if (private) { - if (!(key = RSAPrivateKey_dup(env->key))) - goto error; - } else { - if (!(key = RSAPublicKey_dup(env->key))) - goto error; - } - if (!(pkey = EVP_PKEY_new())) - goto error; - if (!(EVP_PKEY_assign_RSA(pkey, key))) - goto error; - return pkey; - error: - if (pkey) - EVP_PKEY_free(pkey); - if (key) - RSA_free(key); - return NULL; -} - -/** Allocate and return storage for a public key. The key itself will not yet - * be set. - */ -MOCK_IMPL(crypto_pk_t *, -crypto_pk_new,(void)) -{ - RSA *rsa; - - rsa = RSA_new(); - tor_assert(rsa); - return crypto_new_pk_from_rsa_(rsa); -} - -/** Release a reference to an asymmetric key; when all the references - * are released, free the key. - */ -void -crypto_pk_free_(crypto_pk_t *env) -{ - if (!env) - return; - - if (--env->refs > 0) - return; - tor_assert(env->refs == 0); - - if (env->key) - RSA_free(env->key); - - tor_free(env); -} - -/** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>. - * Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits)) -{ - tor_assert(env); - - if (env->key) { - RSA_free(env->key); - env->key = NULL; - } - - { - BIGNUM *e = BN_new(); - RSA *r = NULL; - if (!e) - goto done; - if (! BN_set_word(e, 65537)) - goto done; - r = RSA_new(); - if (!r) - goto done; - if (RSA_generate_key_ex(r, bits, e, NULL) == -1) - goto done; - - env->key = r; - r = NULL; - done: - if (e) - BN_clear_free(e); - if (r) - RSA_free(r); - } - - if (!env->key) { - crypto_log_errors(LOG_WARN, "generating RSA key"); - return -1; - } - - return 0; -} - -/** A PEM callback that always reports a failure to get a password */ -static int -pem_no_password_cb(char *buf, int size, int rwflag, void *u) -{ - (void)buf; - (void)size; - (void)rwflag; - (void)u; - return -1; -} - -/** Read a PEM-encoded private key from the <b>len</b>-byte string <b>s</b> - * into <b>env</b>. Return 0 on success, -1 on failure. If len is -1, - * the string is nul-terminated. - */ -int -crypto_pk_read_private_key_from_string(crypto_pk_t *env, - const char *s, ssize_t len) -{ - BIO *b; - - tor_assert(env); - tor_assert(s); - tor_assert(len < INT_MAX && len < SSIZE_T_CEILING); - - /* Create a read-only memory BIO, backed by the string 's' */ - b = BIO_new_mem_buf((char*)s, (int)len); - if (!b) - return -1; - - if (env->key) - RSA_free(env->key); - - env->key = PEM_read_bio_RSAPrivateKey(b,NULL,pem_no_password_cb,NULL); - - BIO_free(b); - - if (!env->key) { - crypto_log_errors(LOG_WARN, "Error parsing private key"); - return -1; - } - return 0; -} - -/** Read a PEM-encoded private key from the file named by - * <b>keyfile</b> into <b>env</b>. Return 0 on success, -1 on failure. - */ -int -crypto_pk_read_private_key_from_filename(crypto_pk_t *env, - const char *keyfile) -{ - char *contents; - int r; - - /* Read the file into a string. */ - contents = read_file_to_str(keyfile, 0, NULL); - if (!contents) { - log_warn(LD_CRYPTO, "Error reading private key from \"%s\"", keyfile); - return -1; - } - - /* Try to parse it. */ - r = crypto_pk_read_private_key_from_string(env, contents, -1); - memwipe(contents, 0, strlen(contents)); - tor_free(contents); - if (r) - return -1; /* read_private_key_from_string already warned, so we don't.*/ - - /* Make sure it's valid. */ - if (crypto_pk_check_key(env) <= 0) - return -1; - - return 0; -} - -/** Helper function to implement crypto_pk_write_*_key_to_string. Return 0 on - * success, -1 on failure. */ -static int -crypto_pk_write_key_to_string_impl(crypto_pk_t *env, char **dest, - size_t *len, int is_public) -{ - BUF_MEM *buf; - BIO *b; - int r; - - tor_assert(env); - tor_assert(env->key); - tor_assert(dest); - - b = BIO_new(BIO_s_mem()); /* Create a memory BIO */ - if (!b) - return -1; - - /* Now you can treat b as if it were a file. Just use the - * PEM_*_bio_* functions instead of the non-bio variants. - */ - if (is_public) - r = PEM_write_bio_RSAPublicKey(b, env->key); - else - r = PEM_write_bio_RSAPrivateKey(b, env->key, NULL,NULL,0,NULL,NULL); - - if (!r) { - crypto_log_errors(LOG_WARN, "writing RSA key to string"); - BIO_free(b); - return -1; - } - - BIO_get_mem_ptr(b, &buf); - - *dest = tor_malloc(buf->length+1); - memcpy(*dest, buf->data, buf->length); - (*dest)[buf->length] = 0; /* nul terminate it */ - *len = buf->length; - - BIO_free(b); - - return 0; -} - -/** PEM-encode the public key portion of <b>env</b> and write it to a - * newly allocated string. On success, set *<b>dest</b> to the new - * string, *<b>len</b> to the string's length, and return 0. On - * failure, return -1. - */ -int -crypto_pk_write_public_key_to_string(crypto_pk_t *env, char **dest, - size_t *len) -{ - return crypto_pk_write_key_to_string_impl(env, dest, len, 1); -} - -/** PEM-encode the private key portion of <b>env</b> and write it to a - * newly allocated string. On success, set *<b>dest</b> to the new - * string, *<b>len</b> to the string's length, and return 0. On - * failure, return -1. - */ -int -crypto_pk_write_private_key_to_string(crypto_pk_t *env, char **dest, - size_t *len) -{ - return crypto_pk_write_key_to_string_impl(env, dest, len, 0); -} - -/** Read a PEM-encoded public key from the first <b>len</b> characters of - * <b>src</b>, and store the result in <b>env</b>. Return 0 on success, -1 on - * failure. - */ -int -crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src, - size_t len) -{ - BIO *b; - - tor_assert(env); - tor_assert(src); - tor_assert(len<INT_MAX); - - b = BIO_new(BIO_s_mem()); /* Create a memory BIO */ - if (!b) - return -1; - - BIO_write(b, src, (int)len); - - if (env->key) - RSA_free(env->key); - env->key = PEM_read_bio_RSAPublicKey(b, NULL, pem_no_password_cb, NULL); - BIO_free(b); - if (!env->key) { - crypto_log_errors(LOG_WARN, "reading public key from string"); - return -1; - } - - return 0; -} - -/** Write the private key from <b>env</b> into the file named by <b>fname</b>, - * PEM-encoded. Return 0 on success, -1 on failure. - */ -int -crypto_pk_write_private_key_to_filename(crypto_pk_t *env, - const char *fname) -{ - BIO *bio; - char *cp; - long len; - char *s; - int r; - - tor_assert(crypto_pk_private_ok(env)); - - if (!(bio = BIO_new(BIO_s_mem()))) - return -1; - if (PEM_write_bio_RSAPrivateKey(bio, env->key, NULL,NULL,0,NULL,NULL) - == 0) { - crypto_log_errors(LOG_WARN, "writing private key"); - BIO_free(bio); - return -1; - } - len = BIO_get_mem_data(bio, &cp); - tor_assert(len >= 0); - s = tor_malloc(len+1); - memcpy(s, cp, len); - s[len]='\0'; - r = write_str_to_file(fname, s, 0); - BIO_free(bio); - memwipe(s, 0, strlen(s)); - tor_free(s); - return r; -} - -/** Return true iff <b>env</b> has a valid key. - */ -int -crypto_pk_check_key(crypto_pk_t *env) -{ - int r; - tor_assert(env); - - r = RSA_check_key(env->key); - if (r <= 0) - crypto_log_errors(LOG_WARN,"checking RSA key"); - return r; -} - -/** Return true iff <b>key</b> contains the private-key portion of the RSA - * key. */ -int -crypto_pk_key_is_private(const crypto_pk_t *key) -{ - tor_assert(key); - return crypto_pk_private_ok(key); -} - -/** Return true iff <b>env</b> contains a public key whose public exponent - * equals 65537. - */ -int -crypto_pk_public_exponent_ok(crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - - const BIGNUM *e; - -#ifdef OPENSSL_1_1_API - const BIGNUM *n, *d; - RSA_get0_key(env->key, &n, &e, &d); -#else - e = env->key->e; -#endif /* defined(OPENSSL_1_1_API) */ - return BN_is_word(e, 65537); -} - -/** Compare the public-key components of a and b. Return less than 0 - * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is - * considered to be less than all non-NULL keys, and equal to itself. - * - * Note that this may leak information about the keys through timing. - */ -int -crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b) -{ - int result; - char a_is_non_null = (a != NULL) && (a->key != NULL); - char b_is_non_null = (b != NULL) && (b->key != NULL); - char an_argument_is_null = !a_is_non_null | !b_is_non_null; - - result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null)); - if (an_argument_is_null) - return result; - - const BIGNUM *a_n, *a_e; - const BIGNUM *b_n, *b_e; - -#ifdef OPENSSL_1_1_API - const BIGNUM *a_d, *b_d; - RSA_get0_key(a->key, &a_n, &a_e, &a_d); - RSA_get0_key(b->key, &b_n, &b_e, &b_d); -#else - a_n = a->key->n; - a_e = a->key->e; - b_n = b->key->n; - b_e = b->key->e; -#endif /* defined(OPENSSL_1_1_API) */ - - tor_assert(a_n != NULL && a_e != NULL); - tor_assert(b_n != NULL && b_e != NULL); - - result = BN_cmp(a_n, b_n); - if (result) - return result; - return BN_cmp(a_e, b_e); -} - -/** Compare the public-key components of a and b. Return non-zero iff - * a==b. A NULL key is considered to be distinct from all non-NULL - * keys, and equal to itself. - * - * Note that this may leak information about the keys through timing. - */ -int -crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b) -{ - return (crypto_pk_cmp_keys(a, b) == 0); -} - -/** Return the size of the public key modulus in <b>env</b>, in bytes. */ -size_t -crypto_pk_keysize(const crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - - return (size_t) RSA_size((RSA*)env->key); -} - -/** Return the size of the public key modulus of <b>env</b>, in bits. */ -int -crypto_pk_num_bits(crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - -#ifdef OPENSSL_1_1_API - /* It's so stupid that there's no other way to check that n is valid - * before calling RSA_bits(). - */ - const BIGNUM *n, *e, *d; - RSA_get0_key(env->key, &n, &e, &d); - tor_assert(n != NULL); - - return RSA_bits(env->key); -#else /* !(defined(OPENSSL_1_1_API)) */ - tor_assert(env->key->n); - return BN_num_bits(env->key->n); -#endif /* defined(OPENSSL_1_1_API) */ -} - -/** Increase the reference count of <b>env</b>, and return it. - */ -crypto_pk_t * -crypto_pk_dup_key(crypto_pk_t *env) -{ - tor_assert(env); - tor_assert(env->key); - - env->refs++; - return env; -} - -#ifdef TOR_UNIT_TESTS -/** For testing: replace dest with src. (Dest must have a refcount - * of 1) */ -void -crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src) -{ - tor_assert(dest); - tor_assert(dest->refs == 1); - tor_assert(src); - RSA_free(dest->key); - dest->key = RSAPrivateKey_dup(src->key); -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Make a real honest-to-goodness copy of <b>env</b>, and return it. - * Returns NULL on failure. */ -crypto_pk_t * -crypto_pk_copy_full(crypto_pk_t *env) -{ - RSA *new_key; - int privatekey = 0; - tor_assert(env); - tor_assert(env->key); - - if (crypto_pk_private_ok(env)) { - new_key = RSAPrivateKey_dup(env->key); - privatekey = 1; - } else { - new_key = RSAPublicKey_dup(env->key); - } - if (!new_key) { - /* LCOV_EXCL_START - * - * We can't cause RSA*Key_dup() to fail, so we can't really test this. - */ - log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.", - privatekey?"private":"public"); - crypto_log_errors(LOG_ERR, - privatekey ? "Duplicating a private key" : - "Duplicating a public key"); - tor_fragile_assert(); - return NULL; - /* LCOV_EXCL_STOP */ - } - - return crypto_new_pk_from_rsa_(new_key); -} - -/** Perform a hybrid (public/secret) encryption on <b>fromlen</b> - * bytes of data from <b>from</b>, with padding type 'padding', - * storing the results on <b>to</b>. - * - * Returns the number of bytes written on success, -1 on failure. - * - * The encrypted data consists of: - * - The source data, padded and encrypted with the public key, if the - * padded source data is no longer than the public key, and <b>force</b> - * is false, OR - * - The beginning of the source data prefixed with a 16-byte symmetric key, - * padded and encrypted with the public key; followed by the rest of - * the source data encrypted in AES-CTR mode with the symmetric key. - * - * NOTE that this format does not authenticate the symmetrically encrypted - * part of the data, and SHOULD NOT BE USED for new protocols. - */ -int -crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, - char *to, size_t tolen, - const char *from, - size_t fromlen, - int padding, int force) -{ - int overhead, outlen, r; - size_t pkeylen, symlen; - crypto_cipher_t *cipher = NULL; - char *buf = NULL; - - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding)); - pkeylen = crypto_pk_keysize(env); - - if (!force && fromlen+overhead <= pkeylen) { - /* It all fits in a single encrypt. */ - return crypto_pk_public_encrypt(env,to, - tolen, - from,fromlen,padding); - } - tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN); - tor_assert(tolen >= pkeylen); - - char key[CIPHER_KEY_LEN]; - crypto_rand(key, sizeof(key)); /* generate a new key. */ - cipher = crypto_cipher_new(key); - - buf = tor_malloc(pkeylen+1); - memcpy(buf, key, CIPHER_KEY_LEN); - memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN); - - /* Length of symmetrically encrypted data. */ - symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN); - - outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding); - if (outlen!=(int)pkeylen) { - goto err; - } - r = crypto_cipher_encrypt(cipher, to+outlen, - from+pkeylen-overhead-CIPHER_KEY_LEN, symlen); - - if (r<0) goto err; - memwipe(buf, 0, pkeylen); - memwipe(key, 0, sizeof(key)); - tor_free(buf); - crypto_cipher_free(cipher); - tor_assert(outlen+symlen < INT_MAX); - return (int)(outlen + symlen); - err: - - memwipe(buf, 0, pkeylen); - memwipe(key, 0, sizeof(key)); - tor_free(buf); - crypto_cipher_free(cipher); - return -1; -} - -/** Invert crypto_pk_obsolete_public_hybrid_encrypt. Returns the number of - * bytes written on success, -1 on failure. - * - * NOTE that this format does not authenticate the symmetrically encrypted - * part of the data, and SHOULD NOT BE USED for new protocols. - */ -int -crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, - char *to, - size_t tolen, - const char *from, - size_t fromlen, - int padding, int warnOnFailure) -{ - int outlen, r; - size_t pkeylen; - crypto_cipher_t *cipher = NULL; - char *buf = NULL; - - tor_assert(fromlen < SIZE_T_CEILING); - pkeylen = crypto_pk_keysize(env); - - if (fromlen <= pkeylen) { - return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding, - warnOnFailure); - } - - buf = tor_malloc(pkeylen); - outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding, - warnOnFailure); - if (outlen<0) { - log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO, - "Error decrypting public-key data"); - goto err; - } - if (outlen < CIPHER_KEY_LEN) { - log_fn(warnOnFailure?LOG_WARN:LOG_INFO, LD_CRYPTO, - "No room for a symmetric key"); - goto err; - } - cipher = crypto_cipher_new(buf); - if (!cipher) { - goto err; - } - memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN); - outlen -= CIPHER_KEY_LEN; - tor_assert(tolen - outlen >= fromlen - pkeylen); - r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen); - if (r<0) - goto err; - memwipe(buf,0,pkeylen); - tor_free(buf); - crypto_cipher_free(cipher); - tor_assert(outlen + fromlen < INT_MAX); - return (int)(outlen + (fromlen-pkeylen)); - err: - memwipe(buf,0,pkeylen); - tor_free(buf); - crypto_cipher_free(cipher); - return -1; -} - -/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key - * in <b>env</b>, using the padding method <b>padding</b>. On success, - * write the result to <b>to</b>, and return the number of bytes - * written. On failure, return -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen, int padding) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen<INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - - r = RSA_public_encrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - env->key, crypto_get_rsa_padding(padding)); - if (r<0) { - crypto_log_errors(LOG_WARN, "performing RSA encryption"); - return -1; - } - return r; -} - -/** Decrypt <b>fromlen</b> bytes from <b>from</b> with the private key - * in <b>env</b>, using the padding method <b>padding</b>. On success, - * write the result to <b>to</b>, and return the number of bytes - * written. On failure, return -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_private_decrypt(crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen, - int padding, int warnOnFailure) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(env->key); - tor_assert(fromlen<INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - if (!crypto_pk_key_is_private(env)) - /* Not a private key */ - return -1; - - r = RSA_private_decrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - env->key, crypto_get_rsa_padding(padding)); - - if (r<0) { - crypto_log_errors(warnOnFailure?LOG_WARN:LOG_DEBUG, - "performing RSA decryption"); - return -1; - } - return r; -} - -/** Check the signature in <b>from</b> (<b>fromlen</b> bytes long) with the - * public key in <b>env</b>, using PKCS1 padding. On success, write the - * signed data to <b>to</b>, and return the number of bytes written. - * On failure, return -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -MOCK_IMPL(int, -crypto_pk_public_checksig,(const crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen)) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - r = RSA_public_decrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - env->key, RSA_PKCS1_PADDING); - - if (r<0) { - crypto_log_errors(LOG_INFO, "checking RSA signature"); - return -1; - } - return r; -} - -/** Sign <b>fromlen</b> bytes of data from <b>from</b> with the private key in - * <b>env</b>, using PKCS1 padding. On success, write the signature to - * <b>to</b>, and return the number of bytes written. On failure, return - * -1. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen) -{ - int r; - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - tor_assert(tolen >= crypto_pk_keysize(env)); - if (!crypto_pk_key_is_private(env)) - /* Not a private key */ - return -1; - - r = RSA_private_encrypt((int)fromlen, - (unsigned char*)from, (unsigned char*)to, - (RSA*)env->key, RSA_PKCS1_PADDING); - if (r<0) { - crypto_log_errors(LOG_WARN, "generating RSA signature"); - return -1; - } - return r; -} - -/** ASN.1-encode the public portion of <b>pk</b> into <b>dest</b>. - * Return -1 on error, or the number of characters used on success. - */ -int -crypto_pk_asn1_encode(const crypto_pk_t *pk, char *dest, size_t dest_len) -{ - int len; - unsigned char *buf = NULL; - - len = i2d_RSAPublicKey(pk->key, &buf); - if (len < 0 || buf == NULL) - return -1; - - if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) { - OPENSSL_free(buf); - return -1; - } - /* We don't encode directly into 'dest', because that would be illegal - * type-punning. (C99 is smarter than me, C99 is smarter than me...) - */ - memcpy(dest,buf,len); - OPENSSL_free(buf); - return len; -} - -/** Decode an ASN.1-encoded public key from <b>str</b>; return the result on - * success and NULL on failure. - */ -crypto_pk_t * -crypto_pk_asn1_decode(const char *str, size_t len) -{ - RSA *rsa; - unsigned char *buf; - const unsigned char *cp; - cp = buf = tor_malloc(len); - memcpy(buf,str,len); - rsa = d2i_RSAPublicKey(NULL, &cp, len); - tor_free(buf); - if (!rsa) { - crypto_log_errors(LOG_WARN,"decoding public key"); - return NULL; - } - return crypto_new_pk_from_rsa_(rsa); -} - -/** Given a private or public key <b>pk</b>, put a fingerprint of the - * public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 bytes of - * space). Return 0 on success, -1 on failure. - * - * Fingerprints are computed as the SHA1 digest of the ASN.1 encoding - * of the public key, converted to hexadecimal, in upper case, with a - * space after every four digits. - * - * If <b>add_space</b> is false, omit the spaces. - */ -int -crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space) -{ - char digest[DIGEST_LEN]; - char hexdigest[HEX_DIGEST_LEN+1]; - if (crypto_pk_get_digest(pk, digest)) { - return -1; - } - base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN); - if (add_space) { - crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest); - } else { - strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1); - } - return 0; -} - -/** Given a private or public key <b>pk</b>, put a hashed fingerprint of - * the public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 - * bytes of space). Return 0 on success, -1 on failure. - * - * Hashed fingerprints are computed as the SHA1 digest of the SHA1 digest - * of the ASN.1 encoding of the public key, converted to hexadecimal, in - * upper case. - */ -int -crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out) -{ - char digest[DIGEST_LEN], hashed_digest[DIGEST_LEN]; - if (crypto_pk_get_digest(pk, digest)) { - return -1; - } - if (crypto_digest(hashed_digest, digest, DIGEST_LEN) < 0) { - return -1; - } - base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN); - return 0; -} - -/** Check a siglen-byte long signature at <b>sig</b> against - * <b>datalen</b> bytes of data at <b>data</b>, using the public key - * in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for - * SHA1(data). Else return -1. - */ -MOCK_IMPL(int, -crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data, - size_t datalen, const char *sig, - size_t siglen)) -{ - char digest[DIGEST_LEN]; - char *buf; - size_t buflen; - int r; - - tor_assert(env); - tor_assert(data); - tor_assert(sig); - tor_assert(datalen < SIZE_T_CEILING); - tor_assert(siglen < SIZE_T_CEILING); - - if (crypto_digest(digest,data,datalen)<0) { - log_warn(LD_BUG, "couldn't compute digest"); - return -1; - } - buflen = crypto_pk_keysize(env); - buf = tor_malloc(buflen); - r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen); - if (r != DIGEST_LEN) { - log_warn(LD_CRYPTO, "Invalid signature"); - tor_free(buf); - return -1; - } - if (tor_memneq(buf, digest, DIGEST_LEN)) { - log_warn(LD_CRYPTO, "Signature mismatched with digest."); - tor_free(buf); - return -1; - } - tor_free(buf); - - return 0; -} - -/** Compute a SHA1 digest of <b>fromlen</b> bytes of data stored at - * <b>from</b>; sign the data with the private key in <b>env</b>, and - * store it in <b>to</b>. Return the number of bytes written on - * success, and -1 on failure. - * - * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be - * at least the length of the modulus of <b>env</b>. - */ -int -crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen) -{ - int r; - char digest[DIGEST_LEN]; - if (crypto_digest(digest,from,fromlen)<0) - return -1; - r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN); - memwipe(digest, 0, sizeof(digest)); - return r; -} - -/** Given a private or public key <b>pk</b>, put a SHA1 hash of the - * public key into <b>digest_out</b> (must have DIGEST_LEN bytes of space). - * Return 0 on success, -1 on failure. - */ -int -crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out) -{ - char *buf; - size_t buflen; - int len; - int rv = -1; - - buflen = crypto_pk_keysize(pk)*2; - buf = tor_malloc(buflen); - len = crypto_pk_asn1_encode(pk, buf, buflen); - if (len < 0) - goto done; - - if (crypto_digest(digest_out, buf, len) < 0) - goto done; - - rv = 0; - done: - tor_free(buf); - return rv; -} - -/** Compute all digests of the DER encoding of <b>pk</b>, and store them - * in <b>digests_out</b>. Return 0 on success, -1 on failure. */ -int -crypto_pk_get_common_digests(crypto_pk_t *pk, common_digests_t *digests_out) -{ - char *buf; - size_t buflen; - int len; - int rv = -1; - - buflen = crypto_pk_keysize(pk)*2; - buf = tor_malloc(buflen); - len = crypto_pk_asn1_encode(pk, buf, buflen); - if (len < 0) - goto done; - - if (crypto_common_digests(digests_out, (char*)buf, len) < 0) - goto done; - - rv = 0; - done: - tor_free(buf); - return rv; -} - -/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the - * Base64 encoding of the DER representation of the private key as a NUL - * terminated string, and return it via <b>priv_out</b>. Return 0 on - * success, -1 on failure. - * - * It is the caller's responsibility to sanitize and free the resulting buffer. - */ -int -crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out) -{ - unsigned char *der = NULL; - int der_len; - int ret = -1; - - *priv_out = NULL; - - der_len = i2d_RSAPrivateKey(pk->key, &der); - if (der_len < 0 || der == NULL) - return ret; - - size_t priv_len = base64_encode_size(der_len, 0) + 1; - char *priv = tor_malloc_zero(priv_len); - if (base64_encode(priv, priv_len, (char *)der, der_len, 0) >= 0) { - *priv_out = priv; - ret = 0; - } else { - tor_free(priv); - } - - memwipe(der, 0, der_len); - OPENSSL_free(der); - return ret; -} - -/** Given a string containing the Base64 encoded DER representation of the - * private key <b>str</b>, decode and return the result on success, or NULL - * on failure. - */ -crypto_pk_t * -crypto_pk_base64_decode(const char *str, size_t len) -{ - crypto_pk_t *pk = NULL; - - char *der = tor_malloc_zero(len + 1); - int der_len = base64_decode(der, len, str, len); - if (der_len <= 0) { - log_warn(LD_CRYPTO, "Stored RSA private key seems corrupted (base64)."); - goto out; - } - - const unsigned char *dp = (unsigned char*)der; /* Shut the compiler up. */ - RSA *rsa = d2i_RSAPrivateKey(NULL, &dp, der_len); - if (!rsa) { - crypto_log_errors(LOG_WARN, "decoding private key"); - goto out; - } - - pk = crypto_new_pk_from_rsa_(rsa); - - /* Make sure it's valid. */ - if (crypto_pk_check_key(pk) <= 0) { - crypto_pk_free(pk); - pk = NULL; - goto out; - } - - out: - memwipe(der, 0, len + 1); - tor_free(der); - return pk; -} - diff --git a/src/common/crypto_rsa.h b/src/common/crypto_rsa.h deleted file mode 100644 index a80c46bb9f..0000000000 --- a/src/common/crypto_rsa.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_rsa.h - * - * \brief Headers for crypto_rsa.c - **/ - -#ifndef TOR_CRYPTO_RSA_H -#define TOR_CRYPTO_RSA_H - -#include "orconfig.h" - -#include "common/crypto_digest.h" -#include <stdio.h> -#include "lib/cc/torint.h" -#include "common/testsupport.h" -#include "common/compat.h" -#include "common/util.h" -#include "common/torlog.h" - -/** Length of our public keys. */ -#define PK_BYTES (1024/8) - -/** Constant used to indicate OAEP padding for public-key encryption */ -#define PK_PKCS1_OAEP_PADDING 60002 - -/** Number of bytes added for PKCS1-OAEP padding. */ -#define PKCS1_OAEP_PADDING_OVERHEAD 42 - -/** A public key, or a public/private key-pair. */ -typedef struct crypto_pk_t crypto_pk_t; - -/* RSA environment setup */ -MOCK_DECL(crypto_pk_t *,crypto_pk_new,(void)); -void crypto_pk_free_(crypto_pk_t *env); -#define crypto_pk_free(pk) FREE_AND_NULL(crypto_pk_t, crypto_pk_free_, (pk)) -int crypto_get_rsa_padding_overhead(int padding); -int crypto_get_rsa_padding(int padding); - -/* public key crypto */ -MOCK_DECL(int, crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits)); -#define crypto_pk_generate_key(env) \ - crypto_pk_generate_key_with_bits((env), (PK_BYTES*8)) - -int crypto_pk_read_private_key_from_filename(crypto_pk_t *env, - const char *keyfile); -int crypto_pk_write_public_key_to_string(crypto_pk_t *env, - char **dest, size_t *len); -int crypto_pk_write_private_key_to_string(crypto_pk_t *env, - char **dest, size_t *len); -int crypto_pk_read_public_key_from_string(crypto_pk_t *env, - const char *src, size_t len); -int crypto_pk_read_private_key_from_string(crypto_pk_t *env, - const char *s, ssize_t len); -int crypto_pk_write_private_key_to_filename(crypto_pk_t *env, - const char *fname); - -int crypto_pk_check_key(crypto_pk_t *env); -int crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b); -int crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b); -size_t crypto_pk_keysize(const crypto_pk_t *env); -int crypto_pk_num_bits(crypto_pk_t *env); -crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig); -crypto_pk_t *crypto_pk_copy_full(crypto_pk_t *orig); -int crypto_pk_key_is_private(const crypto_pk_t *key); -int crypto_pk_public_exponent_ok(crypto_pk_t *env); -int crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen, - int padding, int force); -int crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen, - int padding, int warnOnFailure); -int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen, int padding); -int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen, - int padding, int warnOnFailure); -MOCK_DECL(int, crypto_pk_public_checksig,(const crypto_pk_t *env, - char *to, size_t tolen, - const char *from, size_t fromlen)); -int crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen); -int crypto_pk_asn1_encode(const crypto_pk_t *pk, char *dest, size_t dest_len); -crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len); -int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space); -int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out); - -MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env, - const char *data, size_t datalen, const char *sig, size_t siglen)); -int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, - const char *from, size_t fromlen); -int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out); -int crypto_pk_get_common_digests(crypto_pk_t *pk, - common_digests_t *digests_out); -int crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out); -crypto_pk_t *crypto_pk_base64_decode(const char *str, size_t len); - -/* Prototypes for private functions only used by tortls.c, crypto.c, and the - * unit tests. */ -struct rsa_st; -struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env); -crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa); -MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_evp_pkey_,(crypto_pk_t *env, - int private)); -struct evp_pkey_st; - -#ifdef TOR_UNIT_TESTS -void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src); -#endif - -#endif - diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c deleted file mode 100644 index db57691f60..0000000000 --- a/src/common/crypto_s2k.c +++ /dev/null @@ -1,476 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_s2k.c - * - * \brief Functions for deriving keys from human-readable passphrases. - */ - -#define CRYPTO_S2K_PRIVATE - -#include "common/compat.h" -#include "common/crypto.h" -#include "common/crypto_digest.h" -#include "common/crypto_hkdf.h" -#include "common/crypto_rand.h" -#include "common/crypto_s2k.h" -#include "common/crypto_util.h" -#include "common/util.h" - -#include <openssl/evp.h> - -#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT) -#define HAVE_SCRYPT -#include <libscrypt.h> -#endif - -/* Encoded secrets take the form: - - u8 type; - u8 salt_and_parameters[depends on type]; - u8 key[depends on type]; - - As a special case, if the encoded secret is exactly 29 bytes long, - type 0 is understood. - - Recognized types are: - 00 -- RFC2440. salt_and_parameters is 9 bytes. key is 20 bytes. - salt_and_parameters is 8 bytes random salt, - 1 byte iteration info. - 01 -- PKBDF2_SHA1. salt_and_parameters is 17 bytes. key is 20 bytes. - salt_and_parameters is 16 bytes random salt, - 1 byte iteration info. - 02 -- SCRYPT_SALSA208_SHA256. salt_and_parameters is 18 bytes. key is - 32 bytes. - salt_and_parameters is 18 bytes random salt, 2 bytes iteration - info. -*/ - -#define S2K_TYPE_RFC2440 0 -#define S2K_TYPE_PBKDF2 1 -#define S2K_TYPE_SCRYPT 2 - -#define PBKDF2_SPEC_LEN 17 -#define PBKDF2_KEY_LEN 20 - -#define SCRYPT_SPEC_LEN 18 -#define SCRYPT_KEY_LEN 32 - -/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the - * specifier part of it, without the prefix type byte. Return -1 if it is not - * a valid algorithm ID. */ -static int -secret_to_key_spec_len(uint8_t type) -{ - switch (type) { - case S2K_TYPE_RFC2440: - return S2K_RFC2440_SPECIFIER_LEN; - case S2K_TYPE_PBKDF2: - return PBKDF2_SPEC_LEN; - case S2K_TYPE_SCRYPT: - return SCRYPT_SPEC_LEN; - default: - return -1; - } -} - -/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the - * its preferred output. */ -static int -secret_to_key_key_len(uint8_t type) -{ - switch (type) { - case S2K_TYPE_RFC2440: - return DIGEST_LEN; - case S2K_TYPE_PBKDF2: - return DIGEST_LEN; - case S2K_TYPE_SCRYPT: - return DIGEST256_LEN; - // LCOV_EXCL_START - default: - tor_fragile_assert(); - return -1; - // LCOV_EXCL_STOP - } -} - -/** Given a specifier in <b>spec_and_key</b> of length - * <b>spec_and_key_len</b>, along with its prefix algorithm ID byte, and along - * with a key if <b>key_included</b> is true, check whether the whole - * specifier-and-key is of valid length, and return the algorithm type if it - * is. Set *<b>legacy_out</b> to 1 iff this is a legacy password hash or - * legacy specifier. Return an error code on failure. - */ -static int -secret_to_key_get_type(const uint8_t *spec_and_key, size_t spec_and_key_len, - int key_included, int *legacy_out) -{ - size_t legacy_len = S2K_RFC2440_SPECIFIER_LEN; - uint8_t type; - int total_len; - - if (key_included) - legacy_len += DIGEST_LEN; - - if (spec_and_key_len == legacy_len) { - *legacy_out = 1; - return S2K_TYPE_RFC2440; - } - - *legacy_out = 0; - if (spec_and_key_len == 0) - return S2K_BAD_LEN; - - type = spec_and_key[0]; - total_len = secret_to_key_spec_len(type); - if (total_len < 0) - return S2K_BAD_ALGORITHM; - if (key_included) { - int keylen = secret_to_key_key_len(type); - if (keylen < 0) - return S2K_BAD_ALGORITHM; - total_len += keylen; - } - - if ((size_t)total_len + 1 == spec_and_key_len) - return type; - else - return S2K_BAD_LEN; -} - -/** - * Write a new random s2k specifier of type <b>type</b>, without prefixing - * type byte, to <b>spec_out</b>, which must have enough room. May adjust - * parameter choice based on <b>flags</b>. - */ -static int -make_specifier(uint8_t *spec_out, uint8_t type, unsigned flags) -{ - int speclen = secret_to_key_spec_len(type); - if (speclen < 0) - return S2K_BAD_ALGORITHM; - - crypto_rand((char*)spec_out, speclen); - switch (type) { - case S2K_TYPE_RFC2440: - /* Hash 64 k of data. */ - spec_out[S2K_RFC2440_SPECIFIER_LEN-1] = 96; - break; - case S2K_TYPE_PBKDF2: - /* 131 K iterations */ - spec_out[PBKDF2_SPEC_LEN-1] = 17; - break; - case S2K_TYPE_SCRYPT: - if (flags & S2K_FLAG_LOW_MEM) { - /* N = 1<<12 */ - spec_out[SCRYPT_SPEC_LEN-2] = 12; - } else { - /* N = 1<<15 */ - spec_out[SCRYPT_SPEC_LEN-2] = 15; - } - /* r = 8; p = 2. */ - spec_out[SCRYPT_SPEC_LEN-1] = (3u << 4) | (1u << 0); - break; - // LCOV_EXCL_START - we should have returned above. - default: - tor_fragile_assert(); - return S2K_BAD_ALGORITHM; - // LCOV_EXCL_STOP - } - - return speclen; -} - -/** Implement RFC2440-style iterated-salted S2K conversion: convert the - * <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte - * <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier - * are a salt; the 9th byte describes how much iteration to do. - * If <b>key_out_len</b> > DIGEST_LEN, use HDKF to expand the result. - */ -void -secret_to_key_rfc2440(char *key_out, size_t key_out_len, const char *secret, - size_t secret_len, const char *s2k_specifier) -{ - crypto_digest_t *d; - uint8_t c; - size_t count, tmplen; - char *tmp; - uint8_t buf[DIGEST_LEN]; - tor_assert(key_out_len < SIZE_T_CEILING); - -#define EXPBIAS 6 - c = s2k_specifier[8]; - count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS); -#undef EXPBIAS - - d = crypto_digest_new(); - tmplen = 8+secret_len; - tmp = tor_malloc(tmplen); - memcpy(tmp,s2k_specifier,8); - memcpy(tmp+8,secret,secret_len); - secret_len += 8; - while (count) { - if (count >= secret_len) { - crypto_digest_add_bytes(d, tmp, secret_len); - count -= secret_len; - } else { - crypto_digest_add_bytes(d, tmp, count); - count = 0; - } - } - crypto_digest_get_digest(d, (char*)buf, sizeof(buf)); - - if (key_out_len <= sizeof(buf)) { - memcpy(key_out, buf, key_out_len); - } else { - crypto_expand_key_material_rfc5869_sha256(buf, DIGEST_LEN, - (const uint8_t*)s2k_specifier, 8, - (const uint8_t*)"EXPAND", 6, - (uint8_t*)key_out, key_out_len); - } - memwipe(tmp, 0, tmplen); - memwipe(buf, 0, sizeof(buf)); - tor_free(tmp); - crypto_digest_free(d); -} - -/** - * Helper: given a valid specifier without prefix type byte in <b>spec</b>, - * whose length must be correct, and given a secret passphrase <b>secret</b> - * of length <b>secret_len</b>, compute the key and store it into - * <b>key_out</b>, which must have enough room for secret_to_key_key_len(type) - * bytes. Return the number of bytes written on success and an error code - * on failure. - */ -STATIC int -secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len, - int type) -{ - int rv; - if (key_out_len > INT_MAX) - return S2K_BAD_LEN; - - switch (type) { - case S2K_TYPE_RFC2440: - secret_to_key_rfc2440((char*)key_out, key_out_len, secret, secret_len, - (const char*)spec); - return (int)key_out_len; - - case S2K_TYPE_PBKDF2: { - uint8_t log_iters; - if (spec_len < 1 || secret_len > INT_MAX || spec_len > INT_MAX) - return S2K_BAD_LEN; - log_iters = spec[spec_len-1]; - if (log_iters > 31) - return S2K_BAD_PARAMS; - rv = PKCS5_PBKDF2_HMAC_SHA1(secret, (int)secret_len, - spec, (int)spec_len-1, - (1<<log_iters), - (int)key_out_len, key_out); - if (rv < 0) - return S2K_FAILED; - return (int)key_out_len; - } - - case S2K_TYPE_SCRYPT: { -#ifdef HAVE_SCRYPT - uint8_t log_N, log_r, log_p; - uint64_t N; - uint32_t r, p; - if (spec_len < 2) - return S2K_BAD_LEN; - log_N = spec[spec_len-2]; - log_r = (spec[spec_len-1]) >> 4; - log_p = (spec[spec_len-1]) & 15; - if (log_N > 63) - return S2K_BAD_PARAMS; - N = ((uint64_t)1) << log_N; - r = 1u << log_r; - p = 1u << log_p; - rv = libscrypt_scrypt((const uint8_t*)secret, secret_len, - spec, spec_len-2, N, r, p, key_out, key_out_len); - if (rv != 0) - return S2K_FAILED; - return (int)key_out_len; -#else /* !(defined(HAVE_SCRYPT)) */ - return S2K_NO_SCRYPT_SUPPORT; -#endif /* defined(HAVE_SCRYPT) */ - } - default: - return S2K_BAD_ALGORITHM; - } -} - -/** - * Given a specifier previously constructed with secret_to_key_make_specifier - * in <b>spec</b> of length <b>spec_len</b>, and a secret password in - * <b>secret</b> of length <b>secret_len</b>, generate <b>key_out_len</b> - * bytes of cryptographic material in <b>key_out</b>. The native output of - * the secret-to-key function will be truncated if key_out_len is short, and - * expanded with HKDF if key_out_len is long. Returns S2K_OKAY on success, - * and an error code on failure. - */ -int -secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len) -{ - int legacy_format = 0; - int type = secret_to_key_get_type(spec, spec_len, 0, &legacy_format); - int r; - - if (type < 0) - return type; -#ifndef HAVE_SCRYPT - if (type == S2K_TYPE_SCRYPT) - return S2K_NO_SCRYPT_SUPPORT; - #endif - - if (! legacy_format) { - ++spec; - --spec_len; - } - - r = secret_to_key_compute_key(key_out, key_out_len, spec, spec_len, - secret, secret_len, type); - if (r < 0) - return r; - else - return S2K_OKAY; -} - -/** - * Construct a new s2k algorithm specifier and salt in <b>buf</b>, according - * to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>. Up to - * <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Return the - * number of bytes used on success and an error code on failure. - */ -int -secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags) -{ - int rv; - int spec_len; -#ifdef HAVE_SCRYPT - uint8_t type = S2K_TYPE_SCRYPT; -#else - uint8_t type = S2K_TYPE_RFC2440; -#endif - - if (flags & S2K_FLAG_NO_SCRYPT) - type = S2K_TYPE_RFC2440; - if (flags & S2K_FLAG_USE_PBKDF2) - type = S2K_TYPE_PBKDF2; - - spec_len = secret_to_key_spec_len(type); - - if ((int)buf_len < spec_len + 1) - return S2K_TRUNCATED; - - buf[0] = type; - rv = make_specifier(buf+1, type, flags); - if (rv < 0) - return rv; - else - return rv + 1; -} - -/** - * Hash a passphrase from <b>secret</b> of length <b>secret_len</b>, according - * to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>, and store the - * hash along with salt and hashing parameters into <b>buf</b>. Up to - * <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Set - * *<b>len_out</b> to the number of bytes used and return S2K_OKAY on success; - * and return an error code on failure. - */ -int -secret_to_key_new(uint8_t *buf, - size_t buf_len, - size_t *len_out, - const char *secret, size_t secret_len, - unsigned flags) -{ - int key_len; - int spec_len; - int type; - int rv; - - spec_len = secret_to_key_make_specifier(buf, buf_len, flags); - - if (spec_len < 0) - return spec_len; - - type = buf[0]; - key_len = secret_to_key_key_len(type); - - if (key_len < 0) - return key_len; - - if ((int)buf_len < key_len + spec_len) - return S2K_TRUNCATED; - - rv = secret_to_key_compute_key(buf + spec_len, key_len, - buf + 1, spec_len-1, - secret, secret_len, type); - if (rv < 0) - return rv; - - *len_out = spec_len + key_len; - - return S2K_OKAY; -} - -/** - * Given a hashed passphrase in <b>spec_and_key</b> of length - * <b>spec_and_key_len</b> as generated by secret_to_key_new(), verify whether - * it is a hash of the passphrase <b>secret</b> of length <b>secret_len</b>. - * Return S2K_OKAY on a match, S2K_BAD_SECRET on a well-formed hash that - * doesn't match this secret, and another error code on other errors. - */ -int -secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len, - const char *secret, size_t secret_len) -{ - int is_legacy = 0; - int type = secret_to_key_get_type(spec_and_key, spec_and_key_len, - 1, &is_legacy); - uint8_t buf[32]; - int spec_len; - int key_len; - int rv; - - if (type < 0) - return type; - - if (! is_legacy) { - spec_and_key++; - spec_and_key_len--; - } - - spec_len = secret_to_key_spec_len(type); - key_len = secret_to_key_key_len(type); - tor_assert(spec_len > 0); - tor_assert(key_len > 0); - tor_assert(key_len <= (int) sizeof(buf)); - tor_assert((int)spec_and_key_len == spec_len + key_len); - rv = secret_to_key_compute_key(buf, key_len, - spec_and_key, spec_len, - secret, secret_len, type); - if (rv < 0) - goto done; - - if (tor_memeq(buf, spec_and_key + spec_len, key_len)) - rv = S2K_OKAY; - else - rv = S2K_BAD_SECRET; - - done: - memwipe(buf, 0, sizeof(buf)); - return rv; -} - diff --git a/src/common/crypto_s2k.h b/src/common/crypto_s2k.h deleted file mode 100644 index b270897b68..0000000000 --- a/src/common/crypto_s2k.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CRYPTO_S2K_H_INCLUDED -#define TOR_CRYPTO_S2K_H_INCLUDED - -#include <stdio.h> -#include "lib/cc/torint.h" - -/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the - * 9th describes how much iteration to do. */ -#define S2K_RFC2440_SPECIFIER_LEN 9 -void secret_to_key_rfc2440( - char *key_out, size_t key_out_len, const char *secret, - size_t secret_len, const char *s2k_specifier); - -/** Flag for secret-to-key function: do not use scrypt. */ -#define S2K_FLAG_NO_SCRYPT (1u<<0) -/** Flag for secret-to-key functions: if using a memory-tuned s2k function, - * assume that we have limited memory. */ -#define S2K_FLAG_LOW_MEM (1u<<1) -/** Flag for secret-to-key functions: force use of pbkdf2. Without this, we - * default to scrypt, then RFC2440. */ -#define S2K_FLAG_USE_PBKDF2 (1u<<2) - -/** Maximum possible output length from secret_to_key_new. */ -#define S2K_MAXLEN 64 - -/** Error code from secret-to-key functions: all is well */ -#define S2K_OKAY 0 -/** Error code from secret-to-key functions: generic failure */ -#define S2K_FAILED -1 -/** Error code from secret-to-key functions: provided secret didn't match */ -#define S2K_BAD_SECRET -2 -/** Error code from secret-to-key functions: didn't recognize the algorithm */ -#define S2K_BAD_ALGORITHM -3 -/** Error code from secret-to-key functions: specifier wasn't valid */ -#define S2K_BAD_PARAMS -4 -/** Error code from secret-to-key functions: compiled without scrypt */ -#define S2K_NO_SCRYPT_SUPPORT -5 -/** Error code from secret-to-key functions: not enough space to write output. - */ -#define S2K_TRUNCATED -6 -/** Error code from secret-to-key functions: Wrong length for specifier. */ -#define S2K_BAD_LEN -7 - -int secret_to_key_new(uint8_t *buf, - size_t buf_len, - size_t *len_out, - const char *secret, size_t secret_len, - unsigned flags); - -int secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags); - -int secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len, - const char *secret, size_t secret_len); - -int secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len); - -#ifdef CRYPTO_S2K_PRIVATE -STATIC int secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len, - const uint8_t *spec, size_t spec_len, - const char *secret, size_t secret_len, - int type); -#endif /* defined(CRYPTO_S2K_PRIVATE) */ - -#endif /* !defined(TOR_CRYPTO_S2K_H_INCLUDED) */ - diff --git a/src/common/crypto_util.c b/src/common/crypto_util.c deleted file mode 100644 index 71707d4bfb..0000000000 --- a/src/common/crypto_util.c +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_util.c - * - * \brief Common cryptographic utilities. - **/ - -#ifndef CRYPTO_UTIL_PRIVATE -#define CRYPTO_UTIL_PRIVATE - -#include "common/crypto_util.h" - -#include <string.h> - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <wincrypt.h> -#endif /* defined(_WIN32) */ - -#include "common/util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/crypto.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#include "common/torlog.h" - -/** - * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to - * the value <b>byte</b>. - * If <b>mem</b> is NULL or <b>sz</b> is zero, nothing happens. - * - * This function is preferable to memset, since many compilers will happily - * optimize out memset() when they can convince themselves that the data being - * cleared will never be read. - * - * Right now, our convention is to use this function when we are wiping data - * that's about to become inaccessible, such as stack buffers that are about - * to go out of scope or structures that are about to get freed. (In - * practice, it appears that the compilers we're currently using will optimize - * out the memset()s for stack-allocated buffers, but not those for - * about-to-be-freed structures. That could change, though, so we're being - * wary.) If there are live reads for the data, then you can just use - * memset(). - */ -void -memwipe(void *mem, uint8_t byte, size_t sz) -{ - if (sz == 0) { - return; - } - /* If sz is nonzero, then mem must not be NULL. */ - tor_assert(mem != NULL); - - /* Data this large is likely to be an underflow. */ - tor_assert(sz < SIZE_T_CEILING); - - /* Because whole-program-optimization exists, we may not be able to just - * have this function call "memset". A smart compiler could inline it, then - * eliminate dead memsets, and declare itself to be clever. */ - -#if defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY) - /* Here's what you do on windows. */ - SecureZeroMemory(mem,sz); -#elif defined(HAVE_RTLSECUREZEROMEMORY) - RtlSecureZeroMemory(mem,sz); -#elif defined(HAVE_EXPLICIT_BZERO) - /* The BSDs provide this. */ - explicit_bzero(mem, sz); -#elif defined(HAVE_MEMSET_S) - /* This is in the C99 standard. */ - memset_s(mem, sz, 0, sz); -#else - /* This is a slow and ugly function from OpenSSL that fills 'mem' with junk - * based on the pointer value, then uses that junk to update a global - * variable. It's an elaborate ruse to trick the compiler into not - * optimizing out the "wipe this memory" code. Read it if you like zany - * programming tricks! In later versions of Tor, we should look for better - * not-optimized-out memory wiping stuff... - * - * ...or maybe not. In practice, there are pure-asm implementations of - * OPENSSL_cleanse() on most platforms, which ought to do the job. - **/ - - OPENSSL_cleanse(mem, sz); -#endif /* defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY) || ... */ - - /* Just in case some caller of memwipe() is relying on getting a buffer - * filled with a particular value, fill the buffer. - * - * If this function gets inlined, this memset might get eliminated, but - * that's okay: We only care about this particular memset in the case where - * the caller should have been using memset(), and the memset() wouldn't get - * eliminated. In other words, this is here so that we won't break anything - * if somebody accidentally calls memwipe() instead of memset(). - **/ - memset(mem, byte, sz); -} - -/** Log all pending crypto errors at level <b>severity</b>. Use - * <b>doing</b> to describe our current activities. - */ -void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - while ((err = ERR_get_error()) != 0) { - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (BUG(!doing)) doing = "(null)"; - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } -} -#endif /* !defined(CRYPTO_UTIL_PRIVATE) */ - diff --git a/src/common/crypto_util.h b/src/common/crypto_util.h deleted file mode 100644 index 3ce34e6f23..0000000000 --- a/src/common/crypto_util.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto_util.h - * - * \brief Common functions for cryptographic routines. - **/ - -#ifndef TOR_CRYPTO_UTIL_H -#define TOR_CRYPTO_UTIL_H - -#include "lib/cc/torint.h" - -/** OpenSSL-based utility functions. */ -void memwipe(void *mem, uint8_t byte, size_t sz); - -/** Log utility function */ -void crypto_log_errors(int severity, const char *doing); - -#ifdef CRYPTO_UTIL_PRIVATE -#ifdef TOR_UNIT_TESTS -#endif /* defined(TOR_UNIT_TESTS) */ -#endif /* defined(CRYPTO_UTIL_PRIVATE) */ - -#endif /* !defined(TOR_CRYPTO_UTIL_H) */ - diff --git a/src/common/include.am b/src/common/include.am index 2869c2ac9d..fb5472f3b9 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -1,13 +1,11 @@ noinst_LIBRARIES += \ src/common/libor.a \ - src/common/libor-crypto.a \ src/common/libor-event.a if UNITTESTS_ENABLED noinst_LIBRARIES += \ src/common/libor-testing.a \ - src/common/libor-crypto-testing.a \ src/common/libor-event-testing.a endif @@ -83,24 +81,6 @@ LIBOR_A_SRC = \ src/common/src_common_libor_testing_a-log.$(OBJEXT) \ src/common/log.$(OBJEXT): micro-revision.i -LIBOR_CRYPTO_A_SRC = \ - src/common/aes.c \ - src/common/buffers_tls.c \ - src/common/crypto.c \ - src/common/crypto_dh.c \ - src/common/crypto_digest.c \ - src/common/crypto_format.c \ - src/common/crypto_hkdf.c \ - src/common/crypto_openssl_mgt.c \ - src/common/crypto_pwbox.c \ - src/common/crypto_rand.c \ - src/common/crypto_rsa.c \ - src/common/crypto_s2k.c \ - src/common/crypto_util.c \ - src/common/tortls.c \ - src/common/crypto_curve25519.c \ - src/common/crypto_ed25519.c - LIBOR_EVENT_A_SRC = \ src/common/compat_libevent.c \ src/common/procmon.c \ @@ -108,53 +88,31 @@ LIBOR_EVENT_A_SRC = \ src/ext/timeouts/timeout.c src_common_libor_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SRC) if UNITTESTS_ENABLED src_common_libor_testing_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SRC) else src_common_libor_testing_a_SOURCES = -src_common_libor_crypto_testing_a_SOURCES = src_common_libor_event_testing_a_SOURCES = endif src_common_libor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_crypto_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_common_libor_event_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) COMMONHEADERS = \ src/common/address.h \ src/common/address_set.h \ src/common/buffers.h \ - src/common/buffers_tls.h \ - src/common/aes.h \ - src/common/ciphers.inc \ src/common/compat.h \ src/common/compat_libevent.h \ - src/common/compat_openssl.h \ src/common/compat_threads.h \ src/common/compat_time.h \ src/common/confline.h \ src/common/container.h \ - src/common/crypto.h \ - src/common/crypto_dh.h \ - src/common/crypto_digest.h \ - src/common/crypto_curve25519.h \ - src/common/crypto_ed25519.h \ - src/common/crypto_format.h \ - src/common/crypto_hkdf.h \ - src/common/crypto_openssl_mgt.h \ - src/common/crypto_pwbox.h \ - src/common/crypto_rand.h \ - src/common/crypto_rsa.h \ - src/common/crypto_s2k.h \ - src/common/crypto_util.h \ src/common/handles.h \ src/common/memarea.h \ src/common/linux_syscalls.inc \ @@ -165,7 +123,6 @@ COMMONHEADERS = \ src/common/timers.h \ src/common/token_bucket.h \ src/common/torlog.h \ - src/common/tortls.h \ src/common/util.h \ src/common/util_bug.h \ src/common/util_format.h \ diff --git a/src/common/tortls.c b/src/common/tortls.c deleted file mode 100644 index 419d9c9316..0000000000 --- a/src/common/tortls.c +++ /dev/null @@ -1,2663 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file tortls.c - * \brief Wrapper functions to present a consistent interface to - * TLS, SSL, and X.509 functions from OpenSSL. - **/ - -/* (Unlike other tor functions, these - * are prefixed with tor_ in order to avoid conflicting with OpenSSL - * functions and variables.) - */ - -#include "orconfig.h" - -#define TORTLS_PRIVATE -#define TORTLS_OPENSSL_PRIVATE - -#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ - #include <winsock2.h> - #include <ws2tcpip.h> -#endif - -#include "common/crypto.h" -#include "common/crypto_rand.h" -#include "common/crypto_dh.h" -#include "common/crypto_util.h" -#include "common/compat.h" - -/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in - * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/opensslv.h> - -#ifdef OPENSSL_NO_EC -#error "We require OpenSSL with ECC support" -#endif - -#include <openssl/ssl.h> -#include <openssl/ssl3.h> -#include <openssl/err.h> -#include <openssl/tls1.h> -#include <openssl/asn1.h> -#include <openssl/bio.h> -#include <openssl/bn.h> -#include <openssl/rsa.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#define TORTLS_PRIVATE -#include "common/tortls.h" -#include "common/util.h" -#include "common/torlog.h" -#include "common/container.h" -#include <string.h> - -#ifdef OPENSSL_1_1_API -#define X509_get_notBefore_const(cert) \ - X509_get0_notBefore(cert) -#define X509_get_notAfter_const(cert) \ - X509_get0_notAfter(cert) -#ifndef X509_get_notBefore -#define X509_get_notBefore(cert) \ - X509_getm_notBefore(cert) -#endif -#ifndef X509_get_notAfter -#define X509_get_notAfter(cert) \ - X509_getm_notAfter(cert) -#endif -#else /* ! OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ -#define X509_get_notBefore_const(cert) \ - ((const ASN1_TIME*) X509_get_notBefore((X509 *)cert)) -#define X509_get_notAfter_const(cert) \ - ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert)) -#endif - -/* Copied from or.h */ -#define LEGAL_NICKNAME_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -/** How long do identity certificates live? (sec) */ -#define IDENTITY_CERT_LIFETIME (365*24*60*60) - -#define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer") - -#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') -/* This is a version of OpenSSL before 1.0.0f. It does not have - * the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and - * SSL3 safely at the same time. - */ -#define DISABLE_SSL3_HANDSHAKE -#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') */ - -/* We redefine these so that we can run correctly even if the vendor gives us - * a version of OpenSSL that does not match its header files. (Apple: I am - * looking at you.) - */ -#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L -#endif -#ifndef SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION -#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010 -#endif - -/** Return values for tor_tls_classify_client_ciphers. - * - * @{ - */ -/** An error occurred when examining the client ciphers */ -#define CIPHERS_ERR -1 -/** The client cipher list indicates that a v1 handshake was in use. */ -#define CIPHERS_V1 1 -/** The client cipher list indicates that the client is using the v2 or the - * v3 handshake, but that it is (probably!) lying about what ciphers it - * supports */ -#define CIPHERS_V2 2 -/** The client cipher list indicates that the client is using the v2 or the - * v3 handshake, and that it is telling the truth about what ciphers it - * supports */ -#define CIPHERS_UNRESTRICTED 3 -/** @} */ - -/** The ex_data index in which we store a pointer to an SSL object's - * corresponding tor_tls_t object. */ -STATIC int tor_tls_object_ex_data_index = -1; - -/** Helper: Allocate tor_tls_object_ex_data_index. */ -STATIC void -tor_tls_allocate_tor_tls_object_ex_data_index(void) -{ - if (tor_tls_object_ex_data_index == -1) { - tor_tls_object_ex_data_index = - SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); - tor_assert(tor_tls_object_ex_data_index != -1); - } -} - -/** Helper: given a SSL* pointer, return the tor_tls_t object using that - * pointer. */ -STATIC tor_tls_t * -tor_tls_get_by_ssl(const SSL *ssl) -{ - tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index); - if (result) - tor_assert(result->magic == TOR_TLS_MAGIC); - return result; -} - -static void tor_tls_context_decref(tor_tls_context_t *ctx); -static void tor_tls_context_incref(tor_tls_context_t *ctx); - -static int check_cert_lifetime_internal(int severity, const X509 *cert, - time_t now, - int past_tolerance, int future_tolerance); - -/** Global TLS contexts. We keep them here because nobody else needs - * to touch them. - * - * @{ */ -STATIC tor_tls_context_t *server_tls_context = NULL; -STATIC tor_tls_context_t *client_tls_context = NULL; -/**@}*/ - -/** True iff tor_tls_init() has been called. */ -static int tls_library_is_initialized = 0; - -/* Module-internal error codes. */ -#define TOR_TLS_SYSCALL_ (MIN_TOR_TLS_ERROR_VAL_ - 2) -#define TOR_TLS_ZERORETURN_ (MIN_TOR_TLS_ERROR_VAL_ - 1) - -/** Write a description of the current state of <b>tls</b> into the - * <b>sz</b>-byte buffer at <b>buf</b>. */ -void -tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz) -{ - const char *ssl_state; - const char *tortls_state; - - if (PREDICT_UNLIKELY(!tls || !tls->ssl)) { - strlcpy(buf, "(No SSL object)", sz); - return; - } - - ssl_state = SSL_state_string_long(tls->ssl); - switch (tls->state) { -#define CASE(st) case TOR_TLS_ST_##st: tortls_state = " in "#st ; break - CASE(HANDSHAKE); - CASE(OPEN); - CASE(GOTCLOSE); - CASE(SENTCLOSE); - CASE(CLOSED); - CASE(RENEGOTIATE); -#undef CASE - case TOR_TLS_ST_BUFFEREVENT: - tortls_state = ""; - break; - default: - tortls_state = " in unknown TLS state"; - break; - } - - tor_snprintf(buf, sz, "%s%s", ssl_state, tortls_state); -} - -/** Log a single error <b>err</b> as returned by ERR_get_error(), which was - * received while performing an operation <b>doing</b> on <b>tls</b>. Log - * the message at <b>severity</b>, in log domain <b>domain</b>. */ -void -tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, - int severity, int domain, const char *doing) -{ - const char *state = NULL, *addr; - const char *msg, *lib, *func; - - state = (tls && tls->ssl)?SSL_state_string_long(tls->ssl):"---"; - - addr = tls ? tls->address : NULL; - - /* Some errors are known-benign, meaning they are the fault of the other - * side of the connection. The caller doesn't know this, so override the - * priority for those cases. */ - switch (ERR_GET_REASON(err)) { - case SSL_R_HTTP_REQUEST: - case SSL_R_HTTPS_PROXY_REQUEST: - case SSL_R_RECORD_LENGTH_MISMATCH: -#ifndef OPENSSL_1_1_API - case SSL_R_RECORD_TOO_LARGE: -#endif - case SSL_R_UNKNOWN_PROTOCOL: - case SSL_R_UNSUPPORTED_PROTOCOL: - severity = LOG_INFO; - break; - default: - break; - } - - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (doing) { - tor_log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)", - doing, addr?" with ":"", addr?addr:"", - msg, lib, func, state); - } else { - tor_log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)", - addr?" with ":"", addr?addr:"", - msg, lib, func, state); - } -} - -/** Log all pending tls errors at level <b>severity</b> in log domain - * <b>domain</b>. Use <b>doing</b> to describe our current activities. - */ -STATIC void -tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) -{ - unsigned long err; - - while ((err = ERR_get_error()) != 0) { - tor_tls_log_one_error(tls, err, severity, domain, doing); - } -} - -/** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error - * code. */ -STATIC int -tor_errno_to_tls_error(int e) -{ - switch (e) { - case SOCK_ERRNO(ECONNRESET): // most common - return TOR_TLS_ERROR_CONNRESET; - case SOCK_ERRNO(ETIMEDOUT): - return TOR_TLS_ERROR_TIMEOUT; - case SOCK_ERRNO(EHOSTUNREACH): - case SOCK_ERRNO(ENETUNREACH): - return TOR_TLS_ERROR_NO_ROUTE; - case SOCK_ERRNO(ECONNREFUSED): - return TOR_TLS_ERROR_CONNREFUSED; // least common - default: - return TOR_TLS_ERROR_MISC; - } -} - -/** Given a TOR_TLS_* error code, return a string equivalent. */ -const char * -tor_tls_err_to_string(int err) -{ - if (err >= 0) - return "[Not an error.]"; - switch (err) { - case TOR_TLS_ERROR_MISC: return "misc error"; - case TOR_TLS_ERROR_IO: return "unexpected close"; - case TOR_TLS_ERROR_CONNREFUSED: return "connection refused"; - case TOR_TLS_ERROR_CONNRESET: return "connection reset"; - case TOR_TLS_ERROR_NO_ROUTE: return "host unreachable"; - case TOR_TLS_ERROR_TIMEOUT: return "connection timed out"; - case TOR_TLS_CLOSE: return "closed"; - case TOR_TLS_WANTREAD: return "want to read"; - case TOR_TLS_WANTWRITE: return "want to write"; - default: return "(unknown error code)"; - } -} - -#define CATCH_SYSCALL 1 -#define CATCH_ZERO 2 - -/** Given a TLS object and the result of an SSL_* call, use - * SSL_get_error to determine whether an error has occurred, and if so - * which one. Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}. - * If extra&CATCH_SYSCALL is true, return TOR_TLS_SYSCALL_ instead of - * reporting syscall errors. If extra&CATCH_ZERO is true, return - * TOR_TLS_ZERORETURN_ instead of reporting zero-return errors. - * - * If an error has occurred, log it at level <b>severity</b> and describe the - * current action as <b>doing</b>. - */ -STATIC int -tor_tls_get_error(tor_tls_t *tls, int r, int extra, - const char *doing, int severity, int domain) -{ - int err = SSL_get_error(tls->ssl, r); - int tor_error = TOR_TLS_ERROR_MISC; - switch (err) { - case SSL_ERROR_NONE: - return TOR_TLS_DONE; - case SSL_ERROR_WANT_READ: - return TOR_TLS_WANTREAD; - case SSL_ERROR_WANT_WRITE: - return TOR_TLS_WANTWRITE; - case SSL_ERROR_SYSCALL: - if (extra&CATCH_SYSCALL) - return TOR_TLS_SYSCALL_; - if (r == 0) { - tor_log(severity, LD_NET, "TLS error: unexpected close while %s (%s)", - doing, SSL_state_string_long(tls->ssl)); - tor_error = TOR_TLS_ERROR_IO; - } else { - int e = tor_socket_errno(tls->socket); - tor_log(severity, LD_NET, - "TLS error: <syscall error while %s> (errno=%d: %s; state=%s)", - doing, e, tor_socket_strerror(e), - SSL_state_string_long(tls->ssl)); - tor_error = tor_errno_to_tls_error(e); - } - tls_log_errors(tls, severity, domain, doing); - return tor_error; - case SSL_ERROR_ZERO_RETURN: - if (extra&CATCH_ZERO) - return TOR_TLS_ZERORETURN_; - tor_log(severity, LD_NET, "TLS connection closed while %s in state %s", - doing, SSL_state_string_long(tls->ssl)); - tls_log_errors(tls, severity, domain, doing); - return TOR_TLS_CLOSE; - default: - tls_log_errors(tls, severity, domain, doing); - return TOR_TLS_ERROR_MISC; - } -} - -/** Initialize OpenSSL, unless it has already been initialized. - */ -static void -tor_tls_init(void) -{ - check_no_tls_errors(); - - if (!tls_library_is_initialized) { -#ifdef OPENSSL_1_1_API - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); -#else - SSL_library_init(); - SSL_load_error_strings(); -#endif - -#if (SIZEOF_VOID_P >= 8 && \ - OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) - long version = OpenSSL_version_num(); - - /* LCOV_EXCL_START : we can't test these lines on the same machine */ - if (version >= OPENSSL_V_SERIES(1,0,1)) { - /* Warn if we could *almost* be running with much faster ECDH. - If we're built for a 64-bit target, using OpenSSL 1.0.1, but we - don't have one of the built-in __uint128-based speedups, we are - just one build operation away from an accelerated handshake. - - (We could be looking at OPENSSL_NO_EC_NISTP_64_GCC_128 instead of - doing this test, but that gives compile-time options, not runtime - behavior.) - */ - EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - const EC_GROUP *g = key ? EC_KEY_get0_group(key) : NULL; - const EC_METHOD *m = g ? EC_GROUP_method_of(g) : NULL; - const int warn = (m == EC_GFp_simple_method() || - m == EC_GFp_mont_method() || - m == EC_GFp_nist_method()); - EC_KEY_free(key); - - if (warn) - log_notice(LD_GENERAL, "We were built to run on a 64-bit CPU, with " - "OpenSSL 1.0.1 or later, but with a version of OpenSSL " - "that apparently lacks accelerated support for the NIST " - "P-224 and P-256 groups. Building openssl with such " - "support (using the enable-ec_nistp_64_gcc_128 option " - "when configuring it) would make ECDH much faster."); - } - /* LCOV_EXCL_STOP */ -#endif /* (SIZEOF_VOID_P >= 8 && ... */ - - tor_tls_allocate_tor_tls_object_ex_data_index(); - - tls_library_is_initialized = 1; - } -} - -/** Free all global TLS structures. */ -void -tor_tls_free_all(void) -{ - check_no_tls_errors(); - - if (server_tls_context) { - tor_tls_context_t *ctx = server_tls_context; - server_tls_context = NULL; - tor_tls_context_decref(ctx); - } - if (client_tls_context) { - tor_tls_context_t *ctx = client_tls_context; - client_tls_context = NULL; - tor_tls_context_decref(ctx); - } -} - -/** We need to give OpenSSL a callback to verify certificates. This is - * it: We always accept peer certs and complete the handshake. We - * don't validate them until later. - */ -STATIC int -always_accept_verify_cb(int preverify_ok, - X509_STORE_CTX *x509_ctx) -{ - (void) preverify_ok; - (void) x509_ctx; - return 1; -} - -/** Return a newly allocated X509 name with commonName <b>cname</b>. */ -static X509_NAME * -tor_x509_name_new(const char *cname) -{ - int nid; - X509_NAME *name; - /* LCOV_EXCL_BR_START : these branches will only fail on OOM errors */ - if (!(name = X509_NAME_new())) - return NULL; - if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error; - if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, - (unsigned char*)cname, -1, -1, 0))) - goto error; - /* LCOV_EXCL_BR_STOP */ - return name; - - /* LCOV_EXCL_START : these lines will only execute on out of memory errors*/ - error: - X509_NAME_free(name); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Generate and sign an X509 certificate with the public key <b>rsa</b>, - * signed by the private key <b>rsa_sign</b>. The commonName of the - * certificate will be <b>cname</b>; the commonName of the issuer will be - * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b> - * seconds, starting from some time in the past. - * - * Return a certificate on success, NULL on failure. - */ -MOCK_IMPL(STATIC X509 *, -tor_tls_create_certificate,(crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime)) -{ - /* OpenSSL generates self-signed certificates with random 64-bit serial - * numbers, so let's do that too. */ -#define SERIAL_NUMBER_SIZE 8 - - time_t start_time, end_time; - BIGNUM *serial_number = NULL; - unsigned char serial_tmp[SERIAL_NUMBER_SIZE]; - EVP_PKEY *sign_pkey = NULL, *pkey=NULL; - X509 *x509 = NULL; - X509_NAME *name = NULL, *name_issuer=NULL; - - tor_tls_init(); - - /* Make sure we're part-way through the certificate lifetime, rather - * than having it start right now. Don't choose quite uniformly, since - * then we might pick a time where we're about to expire. Lastly, be - * sure to start on a day boundary. */ - time_t now = time(NULL); - /* Our certificate lifetime will be cert_lifetime no matter what, but if we - * start cert_lifetime in the past, we'll have 0 real lifetime. instead we - * start up to (cert_lifetime - min_real_lifetime - start_granularity) in - * the past. */ - const time_t min_real_lifetime = 24*3600; - const time_t start_granularity = 24*3600; - time_t earliest_start_time; - /* Don't actually start in the future! */ - if (cert_lifetime <= min_real_lifetime + start_granularity) { - earliest_start_time = now - 1; - } else { - earliest_start_time = now + min_real_lifetime + start_granularity - - cert_lifetime; - } - start_time = crypto_rand_time_range(earliest_start_time, now); - /* Round the start time back to the start of a day. */ - start_time -= start_time % start_granularity; - - end_time = start_time + cert_lifetime; - - tor_assert(rsa); - tor_assert(cname); - tor_assert(rsa_sign); - tor_assert(cname_sign); - if (!(sign_pkey = crypto_pk_get_evp_pkey_(rsa_sign,1))) - goto error; - if (!(pkey = crypto_pk_get_evp_pkey_(rsa,0))) - goto error; - if (!(x509 = X509_new())) - goto error; - if (!(X509_set_version(x509, 2))) - goto error; - - { /* our serial number is 8 random bytes. */ - crypto_rand((char *)serial_tmp, sizeof(serial_tmp)); - if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL))) - goto error; - if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509)))) - goto error; - } - - if (!(name = tor_x509_name_new(cname))) - goto error; - if (!(X509_set_subject_name(x509, name))) - goto error; - if (!(name_issuer = tor_x509_name_new(cname_sign))) - goto error; - if (!(X509_set_issuer_name(x509, name_issuer))) - goto error; - - if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time)) - goto error; - if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time)) - goto error; - if (!X509_set_pubkey(x509, pkey)) - goto error; - - if (!X509_sign(x509, sign_pkey, EVP_sha256())) - goto error; - - goto done; - error: - if (x509) { - X509_free(x509); - x509 = NULL; - } - done: - tls_log_errors(NULL, LOG_WARN, LD_NET, "generating certificate"); - if (sign_pkey) - EVP_PKEY_free(sign_pkey); - if (pkey) - EVP_PKEY_free(pkey); - if (serial_number) - BN_clear_free(serial_number); - if (name) - X509_NAME_free(name); - if (name_issuer) - X509_NAME_free(name_issuer); - return x509; - -#undef SERIAL_NUMBER_SIZE -} - -/** List of ciphers that servers should select from when the client might be - * claiming extra unsupported ciphers in order to avoid fingerprinting. */ -static const char SERVER_CIPHER_LIST[] = -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - /* This one can never actually get selected, since if the client lists it, - * we will assume that the client is honest, and not use this list. - * Nonetheless we list it if it's available, so that the server doesn't - * conclude that it has no valid ciphers if it's running with TLS1.3. - */ - TLS1_3_TXT_AES_128_GCM_SHA256 ":" -#endif - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA; - -/** List of ciphers that servers should select from when we actually have - * our choice of what cipher to use. */ -static const char UNRESTRICTED_SERVER_CIPHER_LIST[] = - /* Here are the TLS 1.3 ciphers we like, in the order we prefer. */ -#ifdef TLS1_3_TXT_AES_256_GCM_SHA384 - TLS1_3_TXT_AES_256_GCM_SHA384 ":" -#endif -#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256 - TLS1_3_TXT_CHACHA20_POLY1305_SHA256 ":" -#endif -#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 - TLS1_3_TXT_AES_128_GCM_SHA256 ":" -#endif -#ifdef TLS1_3_TXT_AES_128_CCM_SHA256 - TLS1_3_TXT_AES_128_CCM_SHA256 ":" -#endif - - /* This list is autogenerated with the gen_server_ciphers.py script; - * don't hand-edit it. */ -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 - TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 - TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA - TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA - TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 - TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 - TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_CCM - TLS1_TXT_DHE_RSA_WITH_AES_256_CCM ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_CCM - TLS1_TXT_DHE_RSA_WITH_AES_128_CCM ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":" -#endif - /* Required */ - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" - /* Required */ - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" -#ifdef TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 - TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 ":" -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 - TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 -#endif - ; - -/* Note: to set up your own private testing network with link crypto - * disabled, set your Tors' cipher list to - * (SSL3_TXT_RSA_NULL_SHA). If you do this, you won't be able to communicate - * with any of the "real" Tors, though. */ - -#define CIPHER(id, name) name ":" -#define XCIPHER(id, name) -/** List of ciphers that clients should advertise, omitting items that - * our OpenSSL doesn't know about. */ -static const char CLIENT_CIPHER_LIST[] = -#include "ciphers.inc" - /* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version - * of any cipher we say. */ - "!SSLv2" - ; -#undef CIPHER -#undef XCIPHER - -/** Free all storage held in <b>cert</b> */ -void -tor_x509_cert_free_(tor_x509_cert_t *cert) -{ - if (! cert) - return; - if (cert->cert) - X509_free(cert->cert); - tor_free(cert->encoded); - memwipe(cert, 0x03, sizeof(*cert)); - /* LCOV_EXCL_BR_START since cert will never be NULL here */ - tor_free(cert); - /* LCOV_EXCL_BR_STOP */ -} - -/** - * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert". - * - * Steals a reference to x509_cert. - */ -MOCK_IMPL(STATIC tor_x509_cert_t *, -tor_x509_cert_new,(X509 *x509_cert)) -{ - tor_x509_cert_t *cert; - EVP_PKEY *pkey; - RSA *rsa; - int length; - unsigned char *buf = NULL; - - if (!x509_cert) - return NULL; - - length = i2d_X509(x509_cert, &buf); - cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); - if (length <= 0 || buf == NULL) { - goto err; - } - cert->encoded_len = (size_t) length; - cert->encoded = tor_malloc(length); - memcpy(cert->encoded, buf, length); - OPENSSL_free(buf); - - cert->cert = x509_cert; - - crypto_common_digests(&cert->cert_digests, - (char*)cert->encoded, cert->encoded_len); - - if ((pkey = X509_get_pubkey(x509_cert)) && - (rsa = EVP_PKEY_get1_RSA(pkey))) { - crypto_pk_t *pk = crypto_new_pk_from_rsa_(rsa); - if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) { - crypto_pk_free(pk); - EVP_PKEY_free(pkey); - goto err; - } - - cert->pkey_digests_set = 1; - crypto_pk_free(pk); - EVP_PKEY_free(pkey); - } - - return cert; - err: - /* LCOV_EXCL_START for the same reason as the exclusion above */ - tor_free(cert); - log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate."); - X509_free(x509_cert); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Return a new copy of <b>cert</b>. */ -tor_x509_cert_t * -tor_x509_cert_dup(const tor_x509_cert_t *cert) -{ - tor_assert(cert); - X509 *x509 = cert->cert; - return tor_x509_cert_new(X509_dup(x509)); -} - -/** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>, - * from a <b>certificate</b>. Return a newly allocated tor_x509_cert_t on - * success and NULL on failure. */ -tor_x509_cert_t * -tor_x509_cert_decode(const uint8_t *certificate, size_t certificate_len) -{ - X509 *x509; - const unsigned char *cp = (const unsigned char *)certificate; - tor_x509_cert_t *newcert; - tor_assert(certificate); - check_no_tls_errors(); - - if (certificate_len > INT_MAX) - goto err; - - x509 = d2i_X509(NULL, &cp, (int)certificate_len); - - if (!x509) - goto err; /* Couldn't decode */ - if (cp - certificate != (int)certificate_len) { - X509_free(x509); - goto err; /* Didn't use all the bytes */ - } - newcert = tor_x509_cert_new(x509); - if (!newcert) { - goto err; - } - if (newcert->encoded_len != certificate_len || - fast_memneq(newcert->encoded, certificate, certificate_len)) { - /* Cert wasn't in DER */ - tor_x509_cert_free(newcert); - goto err; - } - return newcert; - err: - tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "decoding a certificate"); - return NULL; -} - -/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER - * representation and length, respectively. */ -void -tor_x509_cert_get_der(const tor_x509_cert_t *cert, - const uint8_t **encoded_out, size_t *size_out) -{ - tor_assert(cert); - tor_assert(encoded_out); - tor_assert(size_out); - *encoded_out = cert->encoded; - *size_out = cert->encoded_len; -} - -/** Return a set of digests for the public key in <b>cert</b>, or NULL if this - * cert's public key is not one we know how to take the digest of. */ -const common_digests_t * -tor_x509_cert_get_id_digests(const tor_x509_cert_t *cert) -{ - if (cert->pkey_digests_set) - return &cert->pkey_digests; - else - return NULL; -} - -/** Return a set of digests for the public key in <b>cert</b>. */ -const common_digests_t * -tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert) -{ - return &cert->cert_digests; -} - -/** Remove a reference to <b>ctx</b>, and free it if it has no more - * references. */ -static void -tor_tls_context_decref(tor_tls_context_t *ctx) -{ - tor_assert(ctx); - if (--ctx->refcnt == 0) { - SSL_CTX_free(ctx->ctx); - tor_x509_cert_free(ctx->my_link_cert); - tor_x509_cert_free(ctx->my_id_cert); - tor_x509_cert_free(ctx->my_auth_cert); - crypto_pk_free(ctx->link_key); - crypto_pk_free(ctx->auth_key); - /* LCOV_EXCL_BR_START since ctx will never be NULL here */ - tor_free(ctx); - /* LCOV_EXCL_BR_STOP */ - } -} - -/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate - * and ID certificate that we're currently using for our V3 in-protocol - * handshake's certificate chain. If <b>server</b> is true, provide the certs - * that we use in server mode (auth, ID); otherwise, provide the certs that we - * use in client mode. (link, ID) */ -int -tor_tls_get_my_certs(int server, - const tor_x509_cert_t **link_cert_out, - const tor_x509_cert_t **id_cert_out) -{ - tor_tls_context_t *ctx = server ? server_tls_context : client_tls_context; - if (! ctx) - return -1; - if (link_cert_out) - *link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert; - if (id_cert_out) - *id_cert_out = ctx->my_id_cert; - return 0; -} - -/** - * Return the authentication key that we use to authenticate ourselves as a - * client in the V3 in-protocol handshake. - */ -crypto_pk_t * -tor_tls_get_my_client_auth_key(void) -{ - if (! client_tls_context) - return NULL; - return client_tls_context->auth_key; -} - -/** - * Return a newly allocated copy of the public key that a certificate - * certifies. Watch out! This returns NULL if the cert's key is not RSA. - */ -crypto_pk_t * -tor_tls_cert_get_key(tor_x509_cert_t *cert) -{ - crypto_pk_t *result = NULL; - EVP_PKEY *pkey = X509_get_pubkey(cert->cert); - RSA *rsa; - if (!pkey) - return NULL; - rsa = EVP_PKEY_get1_RSA(pkey); - if (!rsa) { - EVP_PKEY_free(pkey); - return NULL; - } - result = crypto_new_pk_from_rsa_(rsa); - EVP_PKEY_free(pkey); - return result; -} - -/** Return true iff the other side of <b>tls</b> has authenticated to us, and - * the key certified in <b>cert</b> is the same as the key they used to do it. - */ -MOCK_IMPL(int, -tor_tls_cert_matches_key,(const tor_tls_t *tls, const tor_x509_cert_t *cert)) -{ - X509 *peercert = SSL_get_peer_certificate(tls->ssl); - EVP_PKEY *link_key = NULL, *cert_key = NULL; - int result; - - if (!peercert) - return 0; - link_key = X509_get_pubkey(peercert); - cert_key = X509_get_pubkey(cert->cert); - - result = link_key && cert_key && EVP_PKEY_cmp(cert_key, link_key) == 1; - - X509_free(peercert); - if (link_key) - EVP_PKEY_free(link_key); - if (cert_key) - EVP_PKEY_free(cert_key); - - return result; -} - -/** Check whether <b>cert</b> is well-formed, currently live, and correctly - * signed by the public key in <b>signing_cert</b>. If <b>check_rsa_1024</b>, - * make sure that it has an RSA key with 1024 bits; otherwise, just check that - * the key is long enough. Return 1 if the cert is good, and 0 if it's bad or - * we couldn't check it. */ -int -tor_tls_cert_is_valid(int severity, - const tor_x509_cert_t *cert, - const tor_x509_cert_t *signing_cert, - time_t now, - int check_rsa_1024) -{ - check_no_tls_errors(); - EVP_PKEY *cert_key; - int r, key_ok = 0; - - if (!signing_cert || !cert) - goto bad; - - EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert); - if (!signing_key) - goto bad; - r = X509_verify(cert->cert, signing_key); - EVP_PKEY_free(signing_key); - if (r <= 0) - goto bad; - - /* okay, the signature checked out right. Now let's check the check the - * lifetime. */ - if (check_cert_lifetime_internal(severity, cert->cert, now, - 48*60*60, 30*24*60*60) < 0) - goto bad; - - cert_key = X509_get_pubkey(cert->cert); - if (check_rsa_1024 && cert_key) { - RSA *rsa = EVP_PKEY_get1_RSA(cert_key); -#ifdef OPENSSL_1_1_API - if (rsa && RSA_bits(rsa) == 1024) -#else - if (rsa && BN_num_bits(rsa->n) == 1024) -#endif - key_ok = 1; - if (rsa) - RSA_free(rsa); - } else if (cert_key) { - int min_bits = 1024; -#ifdef EVP_PKEY_EC - if (EVP_PKEY_base_id(cert_key) == EVP_PKEY_EC) - min_bits = 128; -#endif - if (EVP_PKEY_bits(cert_key) >= min_bits) - key_ok = 1; - } - EVP_PKEY_free(cert_key); - if (!key_ok) - goto bad; - - /* XXXX compare DNs or anything? */ - - return 1; - bad: - tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "checking a certificate"); - return 0; -} - -/** Increase the reference count of <b>ctx</b>. */ -static void -tor_tls_context_incref(tor_tls_context_t *ctx) -{ - ++ctx->refcnt; -} - -/** Create new global client and server TLS contexts. - * - * If <b>server_identity</b> is NULL, this will not generate a server - * TLS context. If TOR_TLS_CTX_IS_PUBLIC_SERVER is set in <b>flags</b>, use - * the same TLS context for incoming and outgoing connections, and - * ignore <b>client_identity</b>. If one of TOR_TLS_CTX_USE_ECDHE_P{224,256} - * is set in <b>flags</b>, use that ECDHE group if possible; otherwise use - * the default ECDHE group. */ -int -tor_tls_context_init(unsigned flags, - crypto_pk_t *client_identity, - crypto_pk_t *server_identity, - unsigned int key_lifetime) -{ - int rv1 = 0; - int rv2 = 0; - const int is_public_server = flags & TOR_TLS_CTX_IS_PUBLIC_SERVER; - check_no_tls_errors(); - - if (is_public_server) { - tor_tls_context_t *new_ctx; - tor_tls_context_t *old_ctx; - - tor_assert(server_identity != NULL); - - rv1 = tor_tls_context_init_one(&server_tls_context, - server_identity, - key_lifetime, flags, 0); - - if (rv1 >= 0) { - new_ctx = server_tls_context; - tor_tls_context_incref(new_ctx); - old_ctx = client_tls_context; - client_tls_context = new_ctx; - - if (old_ctx != NULL) { - tor_tls_context_decref(old_ctx); - } - } - } else { - if (server_identity != NULL) { - rv1 = tor_tls_context_init_one(&server_tls_context, - server_identity, - key_lifetime, - flags, - 0); - } else { - tor_tls_context_t *old_ctx = server_tls_context; - server_tls_context = NULL; - - if (old_ctx != NULL) { - tor_tls_context_decref(old_ctx); - } - } - - rv2 = tor_tls_context_init_one(&client_tls_context, - client_identity, - key_lifetime, - flags, - 1); - } - - tls_log_errors(NULL, LOG_WARN, LD_CRYPTO, "constructing a TLS context"); - return MIN(rv1, rv2); -} - -/** Create a new global TLS context. - * - * You can call this function multiple times. Each time you call it, - * it generates new certificates; all new connections will use - * the new SSL context. - */ -STATIC int -tor_tls_context_init_one(tor_tls_context_t **ppcontext, - crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client) -{ - tor_tls_context_t *new_ctx = tor_tls_context_new(identity, - key_lifetime, - flags, - is_client); - tor_tls_context_t *old_ctx = *ppcontext; - - if (new_ctx != NULL) { - *ppcontext = new_ctx; - - /* Free the old context if one existed. */ - if (old_ctx != NULL) { - /* This is safe even if there are open connections: we reference- - * count tor_tls_context_t objects. */ - tor_tls_context_decref(old_ctx); - } - } - - return ((new_ctx != NULL) ? 0 : -1); -} - -/** The group we should use for ecdhe when none was selected. */ -#define NID_tor_default_ecdhe_group NID_X9_62_prime256v1 - -#define RSA_LINK_KEY_BITS 2048 - -/** Create a new TLS context for use with Tor TLS handshakes. - * <b>identity</b> should be set to the identity key used to sign the - * certificate. - */ -STATIC tor_tls_context_t * -tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, - unsigned flags, int is_client) -{ - crypto_pk_t *rsa = NULL, *rsa_auth = NULL; - EVP_PKEY *pkey = NULL; - tor_tls_context_t *result = NULL; - X509 *cert = NULL, *idcert = NULL, *authcert = NULL; - char *nickname = NULL, *nn2 = NULL; - - tor_tls_init(); - nickname = crypto_random_hostname(8, 20, "www.", ".net"); -#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE - nn2 = crypto_random_hostname(8, 20, "www.", ".net"); -#else - nn2 = crypto_random_hostname(8, 20, "www.", ".com"); -#endif - - /* Generate short-term RSA key for use with TLS. */ - if (!(rsa = crypto_pk_new())) - goto error; - if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0) - goto error; - if (!is_client) { - /* Generate short-term RSA key for use in the in-protocol ("v3") - * authentication handshake. */ - if (!(rsa_auth = crypto_pk_new())) - goto error; - if (crypto_pk_generate_key(rsa_auth)<0) - goto error; - /* Create a link certificate signed by identity key. */ - cert = tor_tls_create_certificate(rsa, identity, nickname, nn2, - key_lifetime); - /* Create self-signed certificate for identity key. */ - idcert = tor_tls_create_certificate(identity, identity, nn2, nn2, - IDENTITY_CERT_LIFETIME); - /* Create an authentication certificate signed by identity key. */ - authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2, - key_lifetime); - if (!cert || !idcert || !authcert) { - log_warn(LD_CRYPTO, "Error creating certificate"); - goto error; - } - } - - result = tor_malloc_zero(sizeof(tor_tls_context_t)); - result->refcnt = 1; - if (!is_client) { - result->my_link_cert = tor_x509_cert_new(X509_dup(cert)); - result->my_id_cert = tor_x509_cert_new(X509_dup(idcert)); - result->my_auth_cert = tor_x509_cert_new(X509_dup(authcert)); - if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert) - goto error; - result->link_key = crypto_pk_dup_key(rsa); - result->auth_key = crypto_pk_dup_key(rsa_auth); - } - -#if 0 - /* Tell OpenSSL to only use TLS1. This may have subtly different results - * from SSLv23_method() with SSLv2 and SSLv3 disabled, so we need to do some - * investigation before we consider adjusting it. It should be compatible - * with existing Tors. */ - if (!(result->ctx = SSL_CTX_new(TLSv1_method()))) - goto error; -#endif /* 0 */ - - /* Tell OpenSSL to use TLS 1.0 or later but not SSL2 or SSL3. */ -#ifdef HAVE_TLS_METHOD - if (!(result->ctx = SSL_CTX_new(TLS_method()))) - goto error; -#else - if (!(result->ctx = SSL_CTX_new(SSLv23_method()))) - goto error; -#endif /* defined(HAVE_TLS_METHOD) */ - SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2); - SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3); - - /* Prefer the server's ordering of ciphers: the client's ordering has - * historically been chosen for fingerprinting resistance. */ - SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - - /* Disable TLS tickets if they're supported. We never want to use them; - * using them can make our perfect forward secrecy a little worse, *and* - * create an opportunity to fingerprint us (since it's unusual to use them - * with TLS sessions turned off). - * - * In 0.2.4, clients advertise support for them though, to avoid a TLS - * distinguishability vector. This can give us worse PFS, though, if we - * get a server that doesn't set SSL_OP_NO_TICKET. With luck, there will - * be few such servers by the time 0.2.4 is more stable. - */ -#ifdef SSL_OP_NO_TICKET - if (! is_client) { - SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET); - } -#endif - - SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE); - SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE); - -#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - SSL_CTX_set_options(result->ctx, - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); -#endif - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. - */ - { - SSL_CTX_set_options(result->ctx, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); - } - - /* Don't actually allow compression; it uses RAM and time, it makes TLS - * vulnerable to CRIME-style attacks, and most of the data we transmit over - * TLS is encrypted (and therefore uncompressible) anyway. */ -#ifdef SSL_OP_NO_COMPRESSION - SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION); -#endif -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) -#ifndef OPENSSL_NO_COMP - if (result->ctx->comp_methods) - result->ctx->comp_methods = NULL; -#endif -#endif /* OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) */ - -#ifdef SSL_MODE_RELEASE_BUFFERS - SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS); -#endif - if (! is_client) { - if (cert && !SSL_CTX_use_certificate(result->ctx,cert)) - goto error; - X509_free(cert); /* We just added a reference to cert. */ - cert=NULL; - if (idcert) { - X509_STORE *s = SSL_CTX_get_cert_store(result->ctx); - tor_assert(s); - X509_STORE_add_cert(s, idcert); - X509_free(idcert); /* The context now owns the reference to idcert */ - idcert = NULL; - } - } - SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF); - if (!is_client) { - tor_assert(rsa); - if (!(pkey = crypto_pk_get_evp_pkey_(rsa,1))) - goto error; - if (!SSL_CTX_use_PrivateKey(result->ctx, pkey)) - goto error; - EVP_PKEY_free(pkey); - pkey = NULL; - if (!SSL_CTX_check_private_key(result->ctx)) - goto error; - } - { - crypto_dh_t *dh = crypto_dh_new(DH_TYPE_TLS); - tor_assert(dh); - SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh)); - crypto_dh_free(dh); - } - if (! is_client) { - int nid; - EC_KEY *ec_key; - if (flags & TOR_TLS_CTX_USE_ECDHE_P224) - nid = NID_secp224r1; - else if (flags & TOR_TLS_CTX_USE_ECDHE_P256) - nid = NID_X9_62_prime256v1; - else - nid = NID_tor_default_ecdhe_group; - /* Use P-256 for ECDHE. */ - ec_key = EC_KEY_new_by_curve_name(nid); - if (ec_key != NULL) /*XXXX Handle errors? */ - SSL_CTX_set_tmp_ecdh(result->ctx, ec_key); - EC_KEY_free(ec_key); - } - SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, - always_accept_verify_cb); - /* let us realloc bufs that we're writing from */ - SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - if (rsa) - crypto_pk_free(rsa); - if (rsa_auth) - crypto_pk_free(rsa_auth); - X509_free(authcert); - tor_free(nickname); - tor_free(nn2); - return result; - - error: - tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context"); - tor_free(nickname); - tor_free(nn2); - if (pkey) - EVP_PKEY_free(pkey); - if (rsa) - crypto_pk_free(rsa); - if (rsa_auth) - crypto_pk_free(rsa_auth); - if (result) - tor_tls_context_decref(result); - if (cert) - X509_free(cert); - if (idcert) - X509_free(idcert); - if (authcert) - X509_free(authcert); - return NULL; -} - -/** Invoked when a TLS state changes: log the change at severity 'debug' */ -STATIC void -tor_tls_debug_state_callback(const SSL *ssl, int type, int val) -{ - /* LCOV_EXCL_START since this depends on whether debug is captured or not */ - log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].", - ssl, SSL_state_string_long(ssl), type, val); - /* LCOV_EXCL_STOP */ -} - -/* Return the name of the negotiated ciphersuite in use on <b>tls</b> */ -const char * -tor_tls_get_ciphersuite_name(tor_tls_t *tls) -{ - return SSL_get_cipher(tls->ssl); -} - -/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to - * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers - * that it claims to support. We'll prune this list to remove the ciphers - * *we* don't recognize. */ -STATIC uint16_t v2_cipher_list[] = { - 0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */ - 0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */ - 0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */ - 0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */ - 0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */ - 0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */ - 0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */ - 0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */ - 0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */ - 0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */ - 0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */ - 0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */ - 0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */ - 0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */ - 0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */ - 0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */ - 0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */ - 0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */ - 0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */ - 0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */ - 0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */ - 0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */ - 0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */ - 0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */ - 0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */ - 0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */ - 0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */ - 0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */ - 0 -}; -/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */ -static int v2_cipher_list_pruned = 0; - -/** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>; - * return 1 if it does support it, or if we have no way to tell. */ -STATIC int -find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) -{ - const SSL_CIPHER *c; -#ifdef HAVE_SSL_CIPHER_FIND - (void) m; - { - unsigned char cipherid[3]; - tor_assert(ssl); - set_uint16(cipherid, htons(cipher)); - cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting - * with a two-byte 'cipherid', it may look for a v2 - * cipher with the appropriate 3 bytes. */ - c = SSL_CIPHER_find((SSL*)ssl, cipherid); - if (c) - tor_assert((SSL_CIPHER_get_id(c) & 0xffff) == cipher); - return c != NULL; - } -#else /* !(defined(HAVE_SSL_CIPHER_FIND)) */ - -# if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) - if (m && m->get_cipher_by_char) { - unsigned char cipherid[3]; - set_uint16(cipherid, htons(cipher)); - cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting - * with a two-byte 'cipherid', it may look for a v2 - * cipher with the appropriate 3 bytes. */ - c = m->get_cipher_by_char(cipherid); - if (c) - tor_assert((c->id & 0xffff) == cipher); - return c != NULL; - } -#endif /* defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) */ -# ifndef OPENSSL_1_1_API - if (m && m->get_cipher && m->num_ciphers) { - /* It would seem that some of the "let's-clean-up-openssl" forks have - * removed the get_cipher_by_char function. Okay, so now you get a - * quadratic search. - */ - int i; - for (i = 0; i < m->num_ciphers(); ++i) { - c = m->get_cipher(i); - if (c && (c->id & 0xffff) == cipher) { - return 1; - } - } - return 0; - } -#endif /* !defined(OPENSSL_1_1_API) */ - (void) ssl; - (void) m; - (void) cipher; - return 1; /* No way to search */ -#endif /* defined(HAVE_SSL_CIPHER_FIND) */ -} - -/** Remove from v2_cipher_list every cipher that we don't support, so that - * comparing v2_cipher_list to a client's cipher list will give a sensible - * result. */ -static void -prune_v2_cipher_list(const SSL *ssl) -{ - uint16_t *inp, *outp; -#ifdef HAVE_TLS_METHOD - const SSL_METHOD *m = TLS_method(); -#else - const SSL_METHOD *m = SSLv23_method(); -#endif - - inp = outp = v2_cipher_list; - while (*inp) { - if (find_cipher_by_id(ssl, m, *inp)) { - *outp++ = *inp++; - } else { - inp++; - } - } - *outp = 0; - - v2_cipher_list_pruned = 1; -} - -/** Examine the client cipher list in <b>ssl</b>, and determine what kind of - * client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2, - * CIPHERS_UNRESTRICTED. - **/ -STATIC int -tor_tls_classify_client_ciphers(const SSL *ssl, - STACK_OF(SSL_CIPHER) *peer_ciphers) -{ - int i, res; - tor_tls_t *tor_tls; - if (PREDICT_UNLIKELY(!v2_cipher_list_pruned)) - prune_v2_cipher_list(ssl); - - tor_tls = tor_tls_get_by_ssl(ssl); - if (tor_tls && tor_tls->client_cipher_list_type) - return tor_tls->client_cipher_list_type; - - /* If we reached this point, we just got a client hello. See if there is - * a cipher list. */ - if (!peer_ciphers) { - log_info(LD_NET, "No ciphers on session"); - res = CIPHERS_ERR; - goto done; - } - /* Now we need to see if there are any ciphers whose presence means we're - * dealing with an updated Tor. */ - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - const char *ciphername = SSL_CIPHER_get_name(cipher); - if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) && - strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) && - strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) && - strcmp(ciphername, "(NONE)")) { - log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername); - // return 1; - goto v2_or_higher; - } - } - res = CIPHERS_V1; - goto done; - v2_or_higher: - { - const uint16_t *v2_cipher = v2_cipher_list; - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff; - if (id == 0x00ff) /* extended renegotiation indicator. */ - continue; - if (!id || id != *v2_cipher) { - res = CIPHERS_UNRESTRICTED; - goto dump_ciphers; - } - ++v2_cipher; - } - if (*v2_cipher != 0) { - res = CIPHERS_UNRESTRICTED; - goto dump_ciphers; - } - res = CIPHERS_V2; - } - - dump_ciphers: - { - smartlist_t *elts = smartlist_new(); - char *s; - for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - const char *ciphername = SSL_CIPHER_get_name(cipher); - smartlist_add(elts, (char*)ciphername); - } - s = smartlist_join_strings(elts, ":", 0, NULL); - log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s. It is: '%s'", - (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s); - tor_free(s); - smartlist_free(elts); - } - done: - if (tor_tls) - return tor_tls->client_cipher_list_type = res; - - return res; -} - -/** Return true iff the cipher list suggested by the client for <b>ssl</b> is - * a list that indicates that the client knows how to do the v2 TLS connection - * handshake. */ -STATIC int -tor_tls_client_is_using_v2_ciphers(const SSL *ssl) -{ - STACK_OF(SSL_CIPHER) *ciphers; -#ifdef HAVE_SSL_GET_CLIENT_CIPHERS - ciphers = SSL_get_client_ciphers(ssl); -#else - SSL_SESSION *session; - if (!(session = SSL_get_session((SSL *)ssl))) { - log_info(LD_NET, "No session on TLS?"); - return CIPHERS_ERR; - } - ciphers = session->ciphers; -#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */ - - return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2; -} - -/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection - * changes state. We use this: - * <ul><li>To alter the state of the handshake partway through, so we - * do not send or request extra certificates in v2 handshakes.</li> - * <li>To detect renegotiation</li></ul> - */ -STATIC void -tor_tls_server_info_callback(const SSL *ssl, int type, int val) -{ - tor_tls_t *tls; - (void) val; - - IF_BUG_ONCE(ssl == NULL) { - return; // LCOV_EXCL_LINE - } - - tor_tls_debug_state_callback(ssl, type, val); - - if (type != SSL_CB_ACCEPT_LOOP) - return; - - OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl); - if (! STATE_IS_SW_SERVER_HELLO(ssl_state)) - return; - tls = tor_tls_get_by_ssl(ssl); - if (tls) { - /* Check whether we're watching for renegotiates. If so, this is one! */ - if (tls->negotiated_callback) - tls->got_renegotiate = 1; - if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/ - ++tls->server_handshake_count; - } else { - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - return; - } - - /* Now check the cipher list. */ - if (tor_tls_client_is_using_v2_ciphers(ssl)) { - if (tls->wasV2Handshake) - return; /* We already turned this stuff off for the first handshake; - * This is a renegotiation. */ - - /* Yes, we're casting away the const from ssl. This is very naughty of us. - * Let's hope openssl doesn't notice! */ - - /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */ - SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN); - /* Don't send a hello request. */ - SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL); - - if (tls) { - tls->wasV2Handshake = 1; - } else { - /* LCOV_EXCL_START this line is not reachable */ - log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); - /* LCOV_EXCL_STOP */ - } - } -} - -/** Callback to get invoked on a server after we've read the list of ciphers - * the client supports, but before we pick our own ciphersuite. - * - * We can't abuse an info_cb for this, since by the time one of the - * client_hello info_cbs is called, we've already picked which ciphersuite to - * use. - * - * Technically, this function is an abuse of this callback, since the point of - * a session_secret_cb is to try to set up and/or verify a shared-secret for - * authentication on the fly. But as long as we return 0, we won't actually be - * setting up a shared secret, and all will be fine. - */ -STATIC int -tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher, - void *arg) -{ - (void) secret; - (void) secret_len; - (void) peer_ciphers; - (void) cipher; - (void) arg; - - if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) == - CIPHERS_UNRESTRICTED) { - SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST); - } - - SSL_set_session_secret_cb(ssl, NULL, NULL); - - return 0; -} -static void -tor_tls_setup_session_secret_cb(tor_tls_t *tls) -{ - SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL); -} - -/** Create a new TLS object from a file descriptor, and a flag to - * determine whether it is functioning as a server. - */ -tor_tls_t * -tor_tls_new(int sock, int isServer) -{ - BIO *bio = NULL; - tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t)); - tor_tls_context_t *context = isServer ? server_tls_context : - client_tls_context; - result->magic = TOR_TLS_MAGIC; - - check_no_tls_errors(); - tor_assert(context); /* make sure somebody made it first */ - if (!(result->ssl = SSL_new(context->ctx))) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "creating SSL object"); - tor_free(result); - goto err; - } - -#ifdef SSL_set_tlsext_host_name - /* Browsers use the TLS hostname extension, so we should too. */ - if (!isServer) { - char *fake_hostname = crypto_random_hostname(4,25, "www.",".com"); - SSL_set_tlsext_host_name(result->ssl, fake_hostname); - tor_free(fake_hostname); - } -#endif /* defined(SSL_set_tlsext_host_name) */ - - if (!SSL_set_cipher_list(result->ssl, - isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers"); -#ifdef SSL_set_tlsext_host_name - SSL_set_tlsext_host_name(result->ssl, NULL); -#endif - SSL_free(result->ssl); - tor_free(result); - goto err; - } - result->socket = sock; - bio = BIO_new_socket(sock, BIO_NOCLOSE); - if (! bio) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO"); -#ifdef SSL_set_tlsext_host_name - SSL_set_tlsext_host_name(result->ssl, NULL); -#endif - SSL_free(result->ssl); - tor_free(result); - goto err; - } - { - int set_worked = - SSL_set_ex_data(result->ssl, tor_tls_object_ex_data_index, result); - if (!set_worked) { - log_warn(LD_BUG, - "Couldn't set the tls for an SSL*; connection will fail"); - } - } - SSL_set_bio(result->ssl, bio, bio); - tor_tls_context_incref(context); - result->context = context; - result->state = TOR_TLS_ST_HANDSHAKE; - result->isServer = isServer; - result->wantwrite_n = 0; - result->last_write_count = (unsigned long) BIO_number_written(bio); - result->last_read_count = (unsigned long) BIO_number_read(bio); - if (result->last_write_count || result->last_read_count) { - log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu", - result->last_read_count, result->last_write_count); - } - if (isServer) { - SSL_set_info_callback(result->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); - } - - if (isServer) - tor_tls_setup_session_secret_cb(result); - - goto done; - err: - result = NULL; - done: - /* Not expected to get called. */ - tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object"); - return result; -} - -/** Make future log messages about <b>tls</b> display the address - * <b>address</b>. - */ -void -tor_tls_set_logged_address(tor_tls_t *tls, const char *address) -{ - tor_assert(tls); - tor_free(tls->address); - tls->address = tor_strdup(address); -} - -/** Set <b>cb</b> to be called with argument <b>arg</b> whenever <b>tls</b> - * next gets a client-side renegotiate in the middle of a read. Do not - * invoke this function until <em>after</em> initial handshaking is done! - */ -void -tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg) -{ - tls->negotiated_callback = cb; - tls->callback_arg = arg; - tls->got_renegotiate = 0; - if (cb) { - SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback); - } else { - SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback); - } -} - -/** If this version of openssl requires it, turn on renegotiation on - * <b>tls</b>. - */ -void -tor_tls_unblock_renegotiation(tor_tls_t *tls) -{ - /* Yes, we know what we are doing here. No, we do not treat a renegotiation - * as authenticating any earlier-received data. */ - SSL_set_options(tls->ssl, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); -} - -/** If this version of openssl supports it, turn off renegotiation on - * <b>tls</b>. (Our protocol never requires this for security, but it's nice - * to use belt-and-suspenders here.) - */ -void -tor_tls_block_renegotiation(tor_tls_t *tls) -{ -#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG - tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; -#else - (void) tls; -#endif -} - -/** Assert that the flags that allow legacy renegotiation are still set */ -void -tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls) -{ -#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && \ - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION != 0 - long options = SSL_get_options(tls->ssl); - tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); -#else - (void) tls; -#endif /* defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && ... */ -} - -/** Return whether this tls initiated the connect (client) or - * received it (server). */ -int -tor_tls_is_server(tor_tls_t *tls) -{ - tor_assert(tls); - return tls->isServer; -} - -/** Release resources associated with a TLS object. Does not close the - * underlying file descriptor. - */ -void -tor_tls_free_(tor_tls_t *tls) -{ - if (!tls) - return; - tor_assert(tls->ssl); - { - size_t r,w; - tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */ - } -#ifdef SSL_set_tlsext_host_name - SSL_set_tlsext_host_name(tls->ssl, NULL); -#endif - SSL_free(tls->ssl); - tls->ssl = NULL; - tls->negotiated_callback = NULL; - if (tls->context) - tor_tls_context_decref(tls->context); - tor_free(tls->address); - tls->magic = 0x99999999; - tor_free(tls); -} - -/** Underlying function for TLS reading. Reads up to <b>len</b> - * characters from <b>tls</b> into <b>cp</b>. On success, returns the - * number of characters read. On failure, returns TOR_TLS_ERROR, - * TOR_TLS_CLOSE, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE. - */ -MOCK_IMPL(int, -tor_tls_read,(tor_tls_t *tls, char *cp, size_t len)) -{ - int r, err; - tor_assert(tls); - tor_assert(tls->ssl); - tor_assert(tls->state == TOR_TLS_ST_OPEN); - tor_assert(len<INT_MAX); - r = SSL_read(tls->ssl, cp, (int)len); - if (r > 0) { - if (tls->got_renegotiate) { - /* Renegotiation happened! */ - log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls)); - if (tls->negotiated_callback) - tls->negotiated_callback(tls, tls->callback_arg); - tls->got_renegotiate = 0; - } - return r; - } - err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); - if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) { - log_debug(LD_NET,"read returned r=%d; TLS is closed",r); - tls->state = TOR_TLS_ST_CLOSED; - return TOR_TLS_CLOSE; - } else { - tor_assert(err != TOR_TLS_DONE); - log_debug(LD_NET,"read returned r=%d, err=%d",r,err); - return err; - } -} - -/** Total number of bytes that we've used TLS to send. Used to track TLS - * overhead. */ -STATIC uint64_t total_bytes_written_over_tls = 0; -/** Total number of bytes that TLS has put on the network for us. Used to - * track TLS overhead. */ -STATIC uint64_t total_bytes_written_by_tls = 0; - -/** Underlying function for TLS writing. Write up to <b>n</b> - * characters from <b>cp</b> onto <b>tls</b>. On success, returns the - * number of characters written. On failure, returns TOR_TLS_ERROR, - * TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE. - */ -int -tor_tls_write(tor_tls_t *tls, const char *cp, size_t n) -{ - int r, err; - tor_assert(tls); - tor_assert(tls->ssl); - tor_assert(tls->state == TOR_TLS_ST_OPEN); - tor_assert(n < INT_MAX); - if (n == 0) - return 0; - if (tls->wantwrite_n) { - /* if WANTWRITE last time, we must use the _same_ n as before */ - tor_assert(n >= tls->wantwrite_n); - log_debug(LD_NET,"resuming pending-write, (%d to flush, reusing %d)", - (int)n, (int)tls->wantwrite_n); - n = tls->wantwrite_n; - tls->wantwrite_n = 0; - } - r = SSL_write(tls->ssl, cp, (int)n); - err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET); - if (err == TOR_TLS_DONE) { - total_bytes_written_over_tls += r; - return r; - } - if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) { - tls->wantwrite_n = n; - } - return err; -} - -/** Perform initial handshake on <b>tls</b>. When finished, returns - * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, - * or TOR_TLS_WANTWRITE. - */ -int -tor_tls_handshake(tor_tls_t *tls) -{ - int r; - tor_assert(tls); - tor_assert(tls->ssl); - tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE); - - check_no_tls_errors(); - - OSSL_HANDSHAKE_STATE oldstate = SSL_get_state(tls->ssl); - - if (tls->isServer) { - log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls, - SSL_state_string_long(tls->ssl)); - r = SSL_accept(tls->ssl); - } else { - log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls, - SSL_state_string_long(tls->ssl)); - r = SSL_connect(tls->ssl); - } - - OSSL_HANDSHAKE_STATE newstate = SSL_get_state(tls->ssl); - - if (oldstate != newstate) - log_debug(LD_HANDSHAKE, "After call, %p was in state %s", - tls, SSL_state_string_long(tls->ssl)); - /* We need to call this here and not earlier, since OpenSSL has a penchant - * for clearing its flags when you say accept or connect. */ - tor_tls_unblock_renegotiation(tls); - r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE); - if (ERR_peek_error() != 0) { - tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE, - "handshaking"); - return TOR_TLS_ERROR_MISC; - } - if (r == TOR_TLS_DONE) { - tls->state = TOR_TLS_ST_OPEN; - return tor_tls_finish_handshake(tls); - } - return r; -} - -/** Perform the final part of the initial TLS handshake on <b>tls</b>. This - * should be called for the first handshake only: it determines whether the v1 - * or the v2 handshake was used, and adjusts things for the renegotiation - * handshake as appropriate. - * - * tor_tls_handshake() calls this on its own; you only need to call this if - * bufferevent is doing the handshake for you. - */ -int -tor_tls_finish_handshake(tor_tls_t *tls) -{ - int r = TOR_TLS_DONE; - check_no_tls_errors(); - if (tls->isServer) { - SSL_set_info_callback(tls->ssl, NULL); - SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb); - SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN); - if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) { - /* This check is redundant, but back when we did it in the callback, - * we might have not been able to look up the tor_tls_t if the code - * was buggy. Fixing that. */ - if (!tls->wasV2Handshake) { - log_warn(LD_BUG, "For some reason, wasV2Handshake didn't" - " get set. Fixing that."); - } - tls->wasV2Handshake = 1; - log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting" - " for renegotiation."); - } else { - tls->wasV2Handshake = 0; - } - } else { - /* Client-side */ - tls->wasV2Handshake = 1; - /* XXXX this can move, probably? -NM */ - if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) { - tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers"); - r = TOR_TLS_ERROR_MISC; - } - } - tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake"); - return r; -} - -/** Shut down an open tls connection <b>tls</b>. When finished, returns - * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, - * or TOR_TLS_WANTWRITE. - */ -int -tor_tls_shutdown(tor_tls_t *tls) -{ - int r, err; - char buf[128]; - tor_assert(tls); - tor_assert(tls->ssl); - check_no_tls_errors(); - - while (1) { - if (tls->state == TOR_TLS_ST_SENTCLOSE) { - /* If we've already called shutdown once to send a close message, - * we read until the other side has closed too. - */ - do { - r = SSL_read(tls->ssl, buf, 128); - } while (r>0); - err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down", - LOG_INFO, LD_NET); - if (err == TOR_TLS_ZERORETURN_) { - tls->state = TOR_TLS_ST_GOTCLOSE; - /* fall through... */ - } else { - return err; - } - } - - r = SSL_shutdown(tls->ssl); - if (r == 1) { - /* If shutdown returns 1, the connection is entirely closed. */ - tls->state = TOR_TLS_ST_CLOSED; - return TOR_TLS_DONE; - } - err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down", - LOG_INFO, LD_NET); - if (err == TOR_TLS_SYSCALL_) { - /* The underlying TCP connection closed while we were shutting down. */ - tls->state = TOR_TLS_ST_CLOSED; - return TOR_TLS_DONE; - } else if (err == TOR_TLS_ZERORETURN_) { - /* The TLS connection says that it sent a shutdown record, but - * isn't done shutting down yet. Make sure that this hasn't - * happened before, then go back to the start of the function - * and try to read. - */ - if (tls->state == TOR_TLS_ST_GOTCLOSE || - tls->state == TOR_TLS_ST_SENTCLOSE) { - log_warn(LD_NET, - "TLS returned \"half-closed\" value while already half-closed"); - return TOR_TLS_ERROR_MISC; - } - tls->state = TOR_TLS_ST_SENTCLOSE; - /* fall through ... */ - } else { - return err; - } - } /* end loop */ -} - -/** Return true iff this TLS connection is authenticated. - */ -int -tor_tls_peer_has_cert(tor_tls_t *tls) -{ - X509 *cert; - cert = SSL_get_peer_certificate(tls->ssl); - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate"); - if (!cert) - return 0; - X509_free(cert); - return 1; -} - -/** Return a newly allocated copy of the peer certificate, or NULL if there - * isn't one. */ -MOCK_IMPL(tor_x509_cert_t *, -tor_tls_get_peer_cert,(tor_tls_t *tls)) -{ - X509 *cert; - cert = SSL_get_peer_certificate(tls->ssl); - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate"); - if (!cert) - return NULL; - return tor_x509_cert_new(cert); -} - -/** Return a newly allocated copy of the cerficate we used on the connection, - * or NULL if somehow we didn't use one. */ -MOCK_IMPL(tor_x509_cert_t *, -tor_tls_get_own_cert,(tor_tls_t *tls)) -{ - X509 *cert = SSL_get_certificate(tls->ssl); - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, - "getting own-connection certificate"); - if (!cert) - return NULL; - /* Fun inconsistency: SSL_get_peer_certificate increments the reference - * count, but SSL_get_certificate does not. */ - X509 *duplicate = X509_dup(cert); - if (BUG(duplicate == NULL)) - return NULL; - return tor_x509_cert_new(duplicate); -} - -/** Warn that a certificate lifetime extends through a certain range. */ -static void -log_cert_lifetime(int severity, const X509 *cert, const char *problem, - time_t now) -{ - BIO *bio = NULL; - BUF_MEM *buf; - char *s1=NULL, *s2=NULL; - char mytime[33]; - struct tm tm; - size_t n; - - if (problem) - tor_log(severity, LD_GENERAL, - "Certificate %s. Either their clock is set wrong, or your clock " - "is wrong.", - problem); - - if (!(bio = BIO_new(BIO_s_mem()))) { - log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end; - } - if (!(ASN1_TIME_print(bio, X509_get_notBefore_const(cert)))) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime"); - goto end; - } - BIO_get_mem_ptr(bio, &buf); - s1 = tor_strndup(buf->data, buf->length); - - (void)BIO_reset(bio); - if (!(ASN1_TIME_print(bio, X509_get_notAfter_const(cert)))) { - tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime"); - goto end; - } - BIO_get_mem_ptr(bio, &buf); - s2 = tor_strndup(buf->data, buf->length); - - n = strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm)); - if (n > 0) { - tor_log(severity, LD_GENERAL, - "(certificate lifetime runs from %s through %s. Your time is %s.)", - s1,s2,mytime); - } else { - tor_log(severity, LD_GENERAL, - "(certificate lifetime runs from %s through %s. " - "Couldn't get your time.)", - s1, s2); - } - - end: - /* Not expected to get invoked */ - tls_log_errors(NULL, LOG_WARN, LD_NET, "getting certificate lifetime"); - if (bio) - BIO_free(bio); - tor_free(s1); - tor_free(s2); -} - -/** Helper function: try to extract a link certificate and an identity - * certificate from <b>tls</b>, and store them in *<b>cert_out</b> and - * *<b>id_cert_out</b> respectively. Log all messages at level - * <b>severity</b>. - * - * Note that a reference is added to cert_out, so it needs to be - * freed. id_cert_out doesn't. */ -MOCK_IMPL(STATIC void, -try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, - X509 **cert_out, X509 **id_cert_out)) -{ - X509 *cert = NULL, *id_cert = NULL; - STACK_OF(X509) *chain = NULL; - int num_in_chain, i; - *cert_out = *id_cert_out = NULL; - if (!(cert = SSL_get_peer_certificate(tls->ssl))) - return; - *cert_out = cert; - if (!(chain = SSL_get_peer_cert_chain(tls->ssl))) - return; - num_in_chain = sk_X509_num(chain); - /* 1 means we're receiving (server-side), and it's just the id_cert. - * 2 means we're connecting (client-side), and it's both the link - * cert and the id_cert. - */ - if (num_in_chain < 1) { - log_fn(severity,LD_PROTOCOL, - "Unexpected number of certificates in chain (%d)", - num_in_chain); - return; - } - for (i=0; i<num_in_chain; ++i) { - id_cert = sk_X509_value(chain, i); - if (X509_cmp(id_cert, cert) != 0) - break; - } - *id_cert_out = id_cert; -} - -/** If the provided tls connection is authenticated and has a - * certificate chain that is currently valid and signed, then set - * *<b>identity_key</b> to the identity certificate's key and return - * 0. Else, return -1 and log complaints with log-level <b>severity</b>. - */ -int -tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key) -{ - X509 *cert = NULL, *id_cert = NULL; - EVP_PKEY *id_pkey = NULL; - RSA *rsa; - int r = -1; - - check_no_tls_errors(); - *identity_key = NULL; - - try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert); - if (!cert) - goto done; - if (!id_cert) { - log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found"); - goto done; - } - tls_log_errors(tls, severity, LD_HANDSHAKE, "before verifying certificate"); - - if (!(id_pkey = X509_get_pubkey(id_cert)) || - X509_verify(cert, id_pkey) <= 0) { - log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0"); - tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate"); - goto done; - } - - rsa = EVP_PKEY_get1_RSA(id_pkey); - if (!rsa) - goto done; - *identity_key = crypto_new_pk_from_rsa_(rsa); - - r = 0; - - done: - if (cert) - X509_free(cert); - if (id_pkey) - EVP_PKEY_free(id_pkey); - - /* This should never get invoked, but let's make sure in case OpenSSL - * acts unexpectedly. */ - tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify"); - - return r; -} - -/** Check whether the certificate set on the connection <b>tls</b> is expired - * give or take <b>past_tolerance</b> seconds, or not-yet-valid give or take - * <b>future_tolerance</b> seconds. Return 0 for valid, -1 for failure. - * - * NOTE: you should call tor_tls_verify before tor_tls_check_lifetime. - */ -int -tor_tls_check_lifetime(int severity, tor_tls_t *tls, - time_t now, - int past_tolerance, int future_tolerance) -{ - X509 *cert; - int r = -1; - - if (!(cert = SSL_get_peer_certificate(tls->ssl))) - goto done; - - if (check_cert_lifetime_internal(severity, cert, now, - past_tolerance, future_tolerance) < 0) - goto done; - - r = 0; - done: - if (cert) - X509_free(cert); - /* Not expected to get invoked */ - tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime"); - - return r; -} - -/** Helper: check whether <b>cert</b> is expired give or take - * <b>past_tolerance</b> seconds, or not-yet-valid give or take - * <b>future_tolerance</b> seconds. (Relative to the current time - * <b>now</b>.) If it is live, return 0. If it is not live, log a message - * and return -1. */ -static int -check_cert_lifetime_internal(int severity, const X509 *cert, - time_t now, - int past_tolerance, int future_tolerance) -{ - time_t t; - - t = now + future_tolerance; - if (X509_cmp_time(X509_get_notBefore_const(cert), &t) > 0) { - log_cert_lifetime(severity, cert, "not yet valid", now); - return -1; - } - t = now - past_tolerance; - if (X509_cmp_time(X509_get_notAfter_const(cert), &t) < 0) { - log_cert_lifetime(severity, cert, "already expired", now); - return -1; - } - - return 0; -} - -#ifdef TOR_UNIT_TESTS -/* Testing only: return a new x509 cert with the same contents as <b>inp</b>, - but with the expiration time <b>new_expiration_time</b>, signed with - <b>signing_key</b>. */ -STATIC tor_x509_cert_t * -tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp, - time_t new_expiration_time, - crypto_pk_t *signing_key) -{ - X509 *newc = X509_dup(inp->cert); - X509_time_adj(X509_get_notAfter(newc), 0, &new_expiration_time); - EVP_PKEY *pk = crypto_pk_get_evp_pkey_(signing_key, 1); - tor_assert(X509_sign(newc, pk, EVP_sha256())); - EVP_PKEY_free(pk); - return tor_x509_cert_new(newc); -} -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Return the number of bytes available for reading from <b>tls</b>. - */ -int -tor_tls_get_pending_bytes(tor_tls_t *tls) -{ - tor_assert(tls); - return SSL_pending(tls->ssl); -} - -/** If <b>tls</b> requires that the next write be of a particular size, - * return that size. Otherwise, return 0. */ -size_t -tor_tls_get_forced_write_size(tor_tls_t *tls) -{ - return tls->wantwrite_n; -} - -/** Sets n_read and n_written to the number of bytes read and written, - * respectively, on the raw socket used by <b>tls</b> since the last time this - * function was called on <b>tls</b>. */ -void -tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written) -{ - BIO *wbio, *tmpbio; - unsigned long r, w; - r = (unsigned long) BIO_number_read(SSL_get_rbio(tls->ssl)); - /* We want the number of bytes actually for real written. Unfortunately, - * sometimes OpenSSL replaces the wbio on tls->ssl with a buffering bio, - * which makes the answer turn out wrong. Let's cope with that. Note - * that this approach will fail if we ever replace tls->ssl's BIOs with - * buffering bios for reasons of our own. As an alternative, we could - * save the original BIO for tls->ssl in the tor_tls_t structure, but - * that would be tempting fate. */ - wbio = SSL_get_wbio(tls->ssl); -#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) - /* BIO structure is opaque as of OpenSSL 1.1.0-pre5-dev. Again, not - * supposed to use this form of the version macro, but the OpenSSL developers - * introduced major API changes in the pre-release stage. - */ - if (BIO_method_type(wbio) == BIO_TYPE_BUFFER && - (tmpbio = BIO_next(wbio)) != NULL) - wbio = tmpbio; -#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5)) */ - if (wbio->method == BIO_f_buffer() && (tmpbio = BIO_next(wbio)) != NULL) - wbio = tmpbio; -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) */ - w = (unsigned long) BIO_number_written(wbio); - - /* We are ok with letting these unsigned ints go "negative" here: - * If we wrapped around, this should still give us the right answer, unless - * we wrapped around by more than ULONG_MAX since the last time we called - * this function. - */ - *n_read = (size_t)(r - tls->last_read_count); - *n_written = (size_t)(w - tls->last_write_count); - if (*n_read > INT_MAX || *n_written > INT_MAX) { - log_warn(LD_BUG, "Preposterously large value in tor_tls_get_n_raw_bytes. " - "r=%lu, last_read=%lu, w=%lu, last_written=%lu", - r, tls->last_read_count, w, tls->last_write_count); - } - total_bytes_written_by_tls += *n_written; - tls->last_read_count = r; - tls->last_write_count = w; -} - -/** Return a ratio of the bytes that TLS has sent to the bytes that we've told - * it to send. Used to track whether our TLS records are getting too tiny. */ -MOCK_IMPL(double, -tls_get_write_overhead_ratio,(void)) -{ - if (total_bytes_written_over_tls == 0) - return 1.0; - - return U64_TO_DBL(total_bytes_written_by_tls) / - U64_TO_DBL(total_bytes_written_over_tls); -} - -/** Implement check_no_tls_errors: If there are any pending OpenSSL - * errors, log an error message. */ -void -check_no_tls_errors_(const char *fname, int line) -{ - if (ERR_peek_error() == 0) - return; - log_warn(LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ", - tor_fix_source_file(fname), line); - tls_log_errors(NULL, LOG_WARN, LD_NET, NULL); -} - -/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2 - * TLS handshake. Output is undefined if the handshake isn't finished. */ -int -tor_tls_used_v1_handshake(tor_tls_t *tls) -{ - return ! tls->wasV2Handshake; -} - -/** Return the number of server handshakes that we've noticed doing on - * <b>tls</b>. */ -int -tor_tls_get_num_server_handshakes(tor_tls_t *tls) -{ - return tls->server_handshake_count; -} - -/** Return true iff the server TLS connection <b>tls</b> got the renegotiation - * request it was waiting for. */ -int -tor_tls_server_got_renegotiate(tor_tls_t *tls) -{ - return tls->got_renegotiate; -} - -#ifndef HAVE_SSL_GET_CLIENT_RANDOM -static size_t -SSL_get_client_random(SSL *s, uint8_t *out, size_t len) -{ - if (len == 0) - return SSL3_RANDOM_SIZE; - tor_assert(len == SSL3_RANDOM_SIZE); - tor_assert(s->s3); - memcpy(out, s->s3->client_random, len); - return len; -} -#endif /* !defined(HAVE_SSL_GET_CLIENT_RANDOM) */ - -#ifndef HAVE_SSL_GET_SERVER_RANDOM -static size_t -SSL_get_server_random(SSL *s, uint8_t *out, size_t len) -{ - if (len == 0) - return SSL3_RANDOM_SIZE; - tor_assert(len == SSL3_RANDOM_SIZE); - tor_assert(s->s3); - memcpy(out, s->s3->server_random, len); - return len; -} -#endif /* !defined(HAVE_SSL_GET_SERVER_RANDOM) */ - -#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY -STATIC size_t -SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len) -{ - tor_assert(s); - if (len == 0) - return s->master_key_length; - tor_assert(len == (size_t)s->master_key_length); - tor_assert(out); - memcpy(out, s->master_key, len); - return len; -} -#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */ - -/** Set the DIGEST256_LEN buffer at <b>secrets_out</b> to the value used in - * the v3 handshake to prove that the client knows the TLS secrets for the - * connection <b>tls</b>. Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) -{ -#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification" - uint8_t buf[128]; - size_t len; - tor_assert(tls); - - SSL *const ssl = tls->ssl; - SSL_SESSION *const session = SSL_get_session(ssl); - - tor_assert(ssl); - tor_assert(session); - - const size_t server_random_len = SSL_get_server_random(ssl, NULL, 0); - const size_t client_random_len = SSL_get_client_random(ssl, NULL, 0); - const size_t master_key_len = SSL_SESSION_get_master_key(session, NULL, 0); - - tor_assert(server_random_len); - tor_assert(client_random_len); - tor_assert(master_key_len); - - len = client_random_len + server_random_len + strlen(TLSSECRET_MAGIC) + 1; - tor_assert(len <= sizeof(buf)); - - { - size_t r = SSL_get_client_random(ssl, buf, client_random_len); - tor_assert(r == client_random_len); - } - - { - size_t r = SSL_get_server_random(ssl, - buf+client_random_len, - server_random_len); - tor_assert(r == server_random_len); - } - - uint8_t *master_key = tor_malloc_zero(master_key_len); - { - size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len); - tor_assert(r == master_key_len); - } - - uint8_t *nextbuf = buf + client_random_len + server_random_len; - memcpy(nextbuf, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1); - - /* - The value is an HMAC, using the TLS master key as the HMAC key, of - client_random | server_random | TLSSECRET_MAGIC - */ - crypto_hmac_sha256((char*)secrets_out, - (char*)master_key, - master_key_len, - (char*)buf, len); - memwipe(buf, 0, sizeof(buf)); - memwipe(master_key, 0, master_key_len); - tor_free(master_key); - - return 0; -} - -/** Using the RFC5705 key material exporting construction, and the - * provided <b>context</b> (<b>context_len</b> bytes long) and - * <b>label</b> (a NUL-terminated string), compute a 32-byte secret in - * <b>secrets_out</b> that only the parties to this TLS session can - * compute. Return 0 on success and -1 on failure. - */ -MOCK_IMPL(int, -tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out, - const uint8_t *context, - size_t context_len, - const char *label)) -{ - tor_assert(tls); - tor_assert(tls->ssl); - - int r = SSL_export_keying_material(tls->ssl, - secrets_out, DIGEST256_LEN, - label, strlen(label), - context, context_len, 1); - return (r == 1) ? 0 : -1; -} - -/** Examine the amount of memory used and available for buffers in <b>tls</b>. - * Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read - * buffer and *<b>rbuf_bytes</b> to the amount actually used. - * Set *<b>wbuf_capacity</b> to the amount of storage allocated for the write - * buffer and *<b>wbuf_bytes</b> to the amount actually used. - * - * Return 0 on success, -1 on failure.*/ -int -tor_tls_get_buffer_sizes(tor_tls_t *tls, - size_t *rbuf_capacity, size_t *rbuf_bytes, - size_t *wbuf_capacity, size_t *wbuf_bytes) -{ -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) - (void)tls; - (void)rbuf_capacity; - (void)rbuf_bytes; - (void)wbuf_capacity; - (void)wbuf_bytes; - - return -1; -#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)) */ - if (tls->ssl->s3->rbuf.buf) - *rbuf_capacity = tls->ssl->s3->rbuf.len; - else - *rbuf_capacity = 0; - if (tls->ssl->s3->wbuf.buf) - *wbuf_capacity = tls->ssl->s3->wbuf.len; - else - *wbuf_capacity = 0; - *rbuf_bytes = tls->ssl->s3->rbuf.left; - *wbuf_bytes = tls->ssl->s3->wbuf.left; - return 0; -#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ -} - -/** Check whether the ECC group requested is supported by the current OpenSSL - * library instance. Return 1 if the group is supported, and 0 if not. - */ -int -evaluate_ecgroup_for_tls(const char *ecgroup) -{ - EC_KEY *ec_key; - int nid; - int ret; - - if (!ecgroup) - nid = NID_tor_default_ecdhe_group; - else if (!strcasecmp(ecgroup, "P256")) - nid = NID_X9_62_prime256v1; - else if (!strcasecmp(ecgroup, "P224")) - nid = NID_secp224r1; - else - return 0; - - ec_key = EC_KEY_new_by_curve_name(nid); - ret = (ec_key != NULL); - EC_KEY_free(ec_key); - - return ret; -} - diff --git a/src/common/tortls.h b/src/common/tortls.h deleted file mode 100644 index c7b319761d..0000000000 --- a/src/common/tortls.h +++ /dev/null @@ -1,295 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_TORTLS_H -#define TOR_TORTLS_H - -/** - * \file tortls.h - * \brief Headers for tortls.c - **/ - -#include "common/crypto_rsa.h" -#include "common/compat_openssl.h" -#include "common/compat.h" -#include "common/testsupport.h" - -/* Opaque structure to hold a TLS connection. */ -typedef struct tor_tls_t tor_tls_t; - -/* Opaque structure to hold an X509 certificate. */ -typedef struct tor_x509_cert_t tor_x509_cert_t; - -/* Possible return values for most tor_tls_* functions. */ -#define MIN_TOR_TLS_ERROR_VAL_ -9 -#define TOR_TLS_ERROR_MISC -9 -/* Rename to unexpected close or something. XXXX */ -#define TOR_TLS_ERROR_IO -8 -#define TOR_TLS_ERROR_CONNREFUSED -7 -#define TOR_TLS_ERROR_CONNRESET -6 -#define TOR_TLS_ERROR_NO_ROUTE -5 -#define TOR_TLS_ERROR_TIMEOUT -4 -#define TOR_TLS_CLOSE -3 -#define TOR_TLS_WANTREAD -2 -#define TOR_TLS_WANTWRITE -1 -#define TOR_TLS_DONE 0 - -/** Collection of case statements for all TLS errors that are not due to - * underlying IO failure. */ -#define CASE_TOR_TLS_ERROR_ANY_NONIO \ - case TOR_TLS_ERROR_MISC: \ - case TOR_TLS_ERROR_CONNREFUSED: \ - case TOR_TLS_ERROR_CONNRESET: \ - case TOR_TLS_ERROR_NO_ROUTE: \ - case TOR_TLS_ERROR_TIMEOUT - -/** Use this macro in a switch statement to catch _any_ TLS error. That way, - * if more errors are added, your switches will still work. */ -#define CASE_TOR_TLS_ERROR_ANY \ - CASE_TOR_TLS_ERROR_ANY_NONIO: \ - case TOR_TLS_ERROR_IO - -#define TOR_TLS_IS_ERROR(rv) ((rv) < TOR_TLS_CLOSE) - -#ifdef TORTLS_PRIVATE -#define TOR_TLS_MAGIC 0x71571571 - -typedef enum { - TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE, - TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE, - TOR_TLS_ST_BUFFEREVENT -} tor_tls_state_t; -#define tor_tls_state_bitfield_t ENUM_BF(tor_tls_state_t) - -struct x509_st; -struct ssl_st; -struct ssl_ctx_st; -struct ssl_session_st; - -/** Holds a SSL_CTX object and related state used to configure TLS - * connections. - */ -typedef struct tor_tls_context_t { - int refcnt; - struct ssl_ctx_st *ctx; - tor_x509_cert_t *my_link_cert; - tor_x509_cert_t *my_id_cert; - tor_x509_cert_t *my_auth_cert; - crypto_pk_t *link_key; - crypto_pk_t *auth_key; -} tor_tls_context_t; - -/** Structure that we use for a single certificate. */ -struct tor_x509_cert_t { - struct x509_st *cert; - uint8_t *encoded; - size_t encoded_len; - unsigned pkey_digests_set : 1; - common_digests_t cert_digests; - common_digests_t pkey_digests; -}; - -/** Holds a SSL object and its associated data. Members are only - * accessed from within tortls.c. - */ -struct tor_tls_t { - uint32_t magic; - tor_tls_context_t *context; /** A link to the context object for this tls. */ - struct ssl_st *ssl; /**< An OpenSSL SSL object. */ - int socket; /**< The underlying file descriptor for this TLS connection. */ - char *address; /**< An address to log when describing this connection. */ - tor_tls_state_bitfield_t state : 3; /**< The current SSL state, - * depending on which operations - * have completed successfully. */ - unsigned int isServer:1; /**< True iff this is a server-side connection */ - unsigned int wasV2Handshake:1; /**< True iff the original handshake for - * this connection used the updated version - * of the connection protocol (client sends - * different cipher list, server sends only - * one certificate). */ - /** True iff we should call negotiated_callback when we're done reading. */ - unsigned int got_renegotiate:1; - /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't - * called that function yet. */ - int8_t client_cipher_list_type; - /** Incremented every time we start the server side of a handshake. */ - uint8_t server_handshake_count; - size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last - * time. */ - /** Last values retrieved from BIO_number_read()/write(); see - * tor_tls_get_n_raw_bytes() for usage. - */ - unsigned long last_write_count; - unsigned long last_read_count; - /** If set, a callback to invoke whenever the client tries to renegotiate - * the handshake. */ - void (*negotiated_callback)(tor_tls_t *tls, void *arg); - /** Argument to pass to negotiated_callback. */ - void *callback_arg; -}; - -STATIC int tor_errno_to_tls_error(int e); -STATIC int tor_tls_get_error(tor_tls_t *tls, int r, int extra, - const char *doing, int severity, int domain); -STATIC tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl); -STATIC void tor_tls_allocate_tor_tls_object_ex_data_index(void); -#ifdef TORTLS_OPENSSL_PRIVATE -STATIC int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx); -STATIC int tor_tls_classify_client_ciphers(const struct ssl_st *ssl, - STACK_OF(SSL_CIPHER) *peer_ciphers); -#endif -STATIC int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl); -MOCK_DECL(STATIC void, try_to_extract_certs_from_tls, - (int severity, tor_tls_t *tls, struct x509_st **cert_out, - struct x509_st **id_cert_out)); -#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY -STATIC size_t SSL_SESSION_get_master_key(struct ssl_session_st *s, - uint8_t *out, - size_t len); -#endif -STATIC void tor_tls_debug_state_callback(const struct ssl_st *ssl, - int type, int val); -STATIC void tor_tls_server_info_callback(const struct ssl_st *ssl, - int type, int val); -#ifdef TORTLS_OPENSSL_PRIVATE -STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret, - int *secret_len, - STACK_OF(SSL_CIPHER) *peer_ciphers, - CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher, - void *arg); -STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, - uint16_t cipher); -#endif /* defined(TORTLS_OPENSSL_PRIVATE) */ -MOCK_DECL(STATIC struct x509_st *, tor_tls_create_certificate, - (crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime)); -STATIC tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity, - unsigned int key_lifetime, unsigned flags, int is_client); -MOCK_DECL(STATIC tor_x509_cert_t *, tor_x509_cert_new, - (struct x509_st *x509_cert)); -STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext, - crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client); -STATIC void tls_log_errors(tor_tls_t *tls, int severity, int domain, - const char *doing); - -#ifdef TOR_UNIT_TESTS -extern int tor_tls_object_ex_data_index; -extern tor_tls_context_t *server_tls_context; -extern tor_tls_context_t *client_tls_context; -extern uint16_t v2_cipher_list[]; -extern uint64_t total_bytes_written_over_tls; -extern uint64_t total_bytes_written_by_tls; - -STATIC tor_x509_cert_t *tor_x509_cert_replace_expiration( - const tor_x509_cert_t *inp, - time_t new_expiration_time, - crypto_pk_t *signing_key); -#endif /* defined(TOR_UNIT_TESTS) */ - -#endif /* defined(TORTLS_PRIVATE) */ - -tor_x509_cert_t *tor_x509_cert_dup(const tor_x509_cert_t *cert); -const char *tor_tls_err_to_string(int err); -void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz); - -void tor_tls_free_all(void); - -#define TOR_TLS_CTX_IS_PUBLIC_SERVER (1u<<0) -#define TOR_TLS_CTX_USE_ECDHE_P256 (1u<<1) -#define TOR_TLS_CTX_USE_ECDHE_P224 (1u<<2) - -int tor_tls_context_init(unsigned flags, - crypto_pk_t *client_identity, - crypto_pk_t *server_identity, - unsigned int key_lifetime); -tor_tls_t *tor_tls_new(int sock, int is_server); -void tor_tls_set_logged_address(tor_tls_t *tls, const char *address); -void tor_tls_set_renegotiate_callback(tor_tls_t *tls, - void (*cb)(tor_tls_t *, void *arg), - void *arg); -int tor_tls_is_server(tor_tls_t *tls); -void tor_tls_free_(tor_tls_t *tls); -#define tor_tls_free(tls) FREE_AND_NULL(tor_tls_t, tor_tls_free_, (tls)) -int tor_tls_peer_has_cert(tor_tls_t *tls); -MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls)); -MOCK_DECL(tor_x509_cert_t *,tor_tls_get_own_cert,(tor_tls_t *tls)); -int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity); -int tor_tls_check_lifetime(int severity, - tor_tls_t *tls, time_t now, - int past_tolerance, - int future_tolerance); -MOCK_DECL(int, tor_tls_read, (tor_tls_t *tls, char *cp, size_t len)); -int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n); -int tor_tls_handshake(tor_tls_t *tls); -int tor_tls_finish_handshake(tor_tls_t *tls); -void tor_tls_unblock_renegotiation(tor_tls_t *tls); -void tor_tls_block_renegotiation(tor_tls_t *tls); -void tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls); -int tor_tls_shutdown(tor_tls_t *tls); -int tor_tls_get_pending_bytes(tor_tls_t *tls); -size_t tor_tls_get_forced_write_size(tor_tls_t *tls); - -void tor_tls_get_n_raw_bytes(tor_tls_t *tls, - size_t *n_read, size_t *n_written); - -int tor_tls_get_buffer_sizes(tor_tls_t *tls, - size_t *rbuf_capacity, size_t *rbuf_bytes, - size_t *wbuf_capacity, size_t *wbuf_bytes); - -MOCK_DECL(double, tls_get_write_overhead_ratio, (void)); - -int tor_tls_used_v1_handshake(tor_tls_t *tls); -int tor_tls_get_num_server_handshakes(tor_tls_t *tls); -int tor_tls_server_got_renegotiate(tor_tls_t *tls); -MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)); -MOCK_DECL(int,tor_tls_export_key_material,( - tor_tls_t *tls, uint8_t *secrets_out, - const uint8_t *context, - size_t context_len, - const char *label)); - -/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack. - */ -#define check_no_tls_errors() check_no_tls_errors_(__FILE__,__LINE__) - -void check_no_tls_errors_(const char *fname, int line); -void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, - int severity, int domain, const char *doing); - -void tor_x509_cert_free_(tor_x509_cert_t *cert); -#define tor_x509_cert_free(c) \ - FREE_AND_NULL(tor_x509_cert_t, tor_x509_cert_free_, (c)) -tor_x509_cert_t *tor_x509_cert_decode(const uint8_t *certificate, - size_t certificate_len); -void tor_x509_cert_get_der(const tor_x509_cert_t *cert, - const uint8_t **encoded_out, size_t *size_out); -const common_digests_t *tor_x509_cert_get_id_digests( - const tor_x509_cert_t *cert); -const common_digests_t *tor_x509_cert_get_cert_digests( - const tor_x509_cert_t *cert); -int tor_tls_get_my_certs(int server, - const tor_x509_cert_t **link_cert_out, - const tor_x509_cert_t **id_cert_out); -crypto_pk_t *tor_tls_get_my_client_auth_key(void); -crypto_pk_t *tor_tls_cert_get_key(tor_x509_cert_t *cert); -MOCK_DECL(int,tor_tls_cert_matches_key,(const tor_tls_t *tls, - const tor_x509_cert_t *cert)); -int tor_tls_cert_is_valid(int severity, - const tor_x509_cert_t *cert, - const tor_x509_cert_t *signing_cert, - time_t now, - int check_rsa_1024); -const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls); - -int evaluate_ecgroup_for_tls(const char *ecgroup); - -#endif /* !defined(TOR_TORTLS_H) */ - |