Merge branch 'nss_squashed' into nss_merge

This commit is contained in:
Nick Mathewson
2018-09-04 20:21:07 -04:00
108 changed files with 11223 additions and 7115 deletions
+8
View File
@@ -133,6 +133,14 @@ TOR_INTERNAL_TESTING_LIBS = \
src/lib/libtor-trace.a
endif
TOR_LDFLAGS_CRYPTLIB=@TOR_LDFLAGS_openssl@
TOR_LIBS_CRYPTLIB=@TOR_OPENSSL_LIBS@
TOR_CFLAGS_CRYPTLIB=
if USE_NSS
TOR_CFLAGS_CRYPTLIB+=@NSS_CFLAGS@
TOR_LIBS_CRYPTLIB+=@NSS_LIBS@
endif
# All libraries used to link tor-cov
include src/include.am
+7
View File
@@ -0,0 +1,7 @@
o Major features (portability, cryptography, experimental, TLS):
- Tor now has the option to compile with the NSS library instead of
OpenSSL. This feature is experimental, and we expect that bugs may
remain. It is mainly intended for environments where Tor's performance
is not CPU-bound, and where NSS is already known to be installed.
To try it out, configure Tor with the --enable-nss flag.
Closes ticket 26631.
+3
View File
@@ -0,0 +1,3 @@
o Major features (experimental, library support):
- When built with --enable-nss, Tor now uses the NSS library for digests,
AES, and pseudorandom numbers. Closes ticket 26815.
+11
View File
@@ -0,0 +1,11 @@
o Major features (experimental, library support):
- Tor now has _partial_ support for using the NSS cryptography library in
place of OpenSSL. When Tor is configured with --enable-nss, it will
use NSS for several (but not yet all) of its cryptography. (It still
relies on OpenSSL for the rest.) Eventually, if all goes as planned,
"--enable-nss" will produce a version of Tor that does not depend on
OpenSSL. Implements ticket 26816.
WARNING: This feature is experimental. Don't use it for real security
yet, until the code has had much more review, and more bugs have been
shaken out.
+2
View File
@@ -5,6 +5,7 @@
BUILDDIR=@BUILDDIR@
TOR_LDFLAGS_zlib=@TOR_LDFLAGS_zlib@
TOR_LDFLAGS_nss=@TOR_LDFLAGS_nss@
TOR_LDFLAGS_openssl=@TOR_LDFLAGS_openssl@
TOR_LDFLAGS_libevent=@TOR_LDFLAGS_libevent@
TOR_ZLIB_LIBS=@TOR_ZLIB_LIBS@
@@ -20,3 +21,4 @@ TOR_LZMA_LIBS=@TOR_LZMA_LIBS@
TOR_ZSTD_LIBS=@TOR_ZSTD_LIBS@
LIBS=@LIBS@
LDFLAGS=@LDFLAGS@
NSS_LIBS=@NSS_LIBS@
+30
View File
@@ -53,6 +53,8 @@ AC_ARG_ENABLE(restart-debugging,
AS_HELP_STRING(--enable-restart-debugging, [Build Tor with support for debugging in-process restart. Developers only.]))
AC_ARG_ENABLE(zstd-advanced-apis,
AS_HELP_STRING(--disable-zstd-advanced-apis, [Build without support for zstd's "static-only" APIs.]))
AC_ARG_ENABLE(nss,
AS_HELP_STRING(--enable-nss, [Use Mozilla's NSS TLS library. (EXPERIMENTAL)]))
if test "x$enable_coverage" != "xyes" -a "x$enable_asserts_in_tests" = "xno" ; then
AC_MSG_ERROR([Can't disable assertions outside of coverage build])
@@ -64,6 +66,16 @@ AM_CONDITIONAL(DISABLE_ASSERTS_IN_UNIT_TESTS, test "x$enable_asserts_in_tests" =
AM_CONDITIONAL(LIBFUZZER_ENABLED, test "x$enable_libfuzzer" = "xyes")
AM_CONDITIONAL(OSS_FUZZ_ENABLED, test "x$enable_oss_fuzz" = "xyes")
AM_CONDITIONAL(USE_RUST, test "x$enable_rust" = "xyes")
AM_CONDITIONAL(USE_NSS, test "x$enable_nss" = "xyes")
AM_CONDITIONAL(USE_OPENSSL, test "x$enable_nss" != "xyes")
if test "x$enable_nss" = "xyes"; then
AC_DEFINE(ENABLE_NSS, 1,
[Defined if we're building with NSS.])
else
AC_DEFINE(ENABLE_OPENSSL, 1,
[Defined if we're building with OpenSSL or LibreSSL])
fi
if test "$enable_static_tor" = "yes"; then
enable_static_libevent="yes";
@@ -840,9 +852,22 @@ fi
LIBS="$save_LIBS"
AC_SUBST(TOR_LIB_MATH)
dnl ------------------------------------------------------
dnl Hello, NSS. You're new around here.
if test "x$enable_nss" = "xyes"; then
PKG_CHECK_MODULES(NSS,
[nss],
[have_nss=yes],
[have_nss=no; AC_MSG_ERROR([You asked for NSS but I can't find it.])])
AC_SUBST(NSS_CFLAGS)
AC_SUBST(NSS_LIBS)
fi
dnl ------------------------------------------------------
dnl Where do you live, openssl? And how do we call you?
if test "x$enable_nss" != "xyes"; then
tor_openssl_pkg_redhat="openssl"
tor_openssl_pkg_debian="libssl-dev"
tor_openssl_devpkg_redhat="openssl-devel"
@@ -942,6 +967,11 @@ AC_CHECK_SIZEOF(SHA_CTX, , [AC_INCLUDES_DEFAULT()
#include <openssl/sha.h>
])
fi # enable_nss
dnl ======================================================================
dnl Can we use KIST?
dnl Define the set of checks for KIST scheduler support.
AC_DEFUN([CHECK_KIST_SUPPORT],[
dnl KIST needs struct tcp_info and for certain members to exist.
+15 -1
View File
@@ -81,6 +81,12 @@
#include "core/mainloop/cpuworker.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/crypto_init.h"
#ifdef ENABLE_NSS
#include "lib/crypt_ops/crypto_nss_mgt.h"
#else
#include "lib/crypt_ops/crypto_openssl_mgt.h"
#endif
#include "feature/dircache/dirserv.h"
#include "feature/relay/dns.h"
#include "core/or/dos.h"
@@ -1412,7 +1418,8 @@ options_act_reversible(const or_options_t *old_options, char **msg)
* processes. */
if (running_tor && options->RunAsDaemon) {
/* No need to roll back, since you can't change the value. */
start_daemon();
if (start_daemon())
crypto_postfork();
}
#ifdef HAVE_SYSTEMD
@@ -5152,9 +5159,16 @@ options_init_from_torrc(int argc, char **argv)
printf("Libevent\t\t%-15s\t\t%s\n",
tor_libevent_get_header_version_str(),
tor_libevent_get_version_str());
#ifdef ENABLE_OPENSSL
printf("OpenSSL \t\t%-15s\t\t%s\n",
crypto_openssl_get_header_version_str(),
crypto_openssl_get_version_str());
#endif
#ifdef ENABLE_NSS
printf("NSS \t\t%-15s\t\t%s\n",
crypto_nss_get_header_version_str(),
crypto_nss_get_version_str());
#endif
if (tor_compress_supports_method(ZLIB_METHOD)) {
printf("Zlib \t\t%-15s\t\t%s\n",
tor_compress_version_str(ZLIB_METHOD),
+4 -4
View File
@@ -14,10 +14,10 @@ src_app_tor_SOURCES = src/app/main/tor_main.c
# This seems to matter nowhere but on windows, but I assure you that it
# matters a lot there, and is quite hard to debug if you forget to do it.
src_app_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
src_app_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@
src_app_tor_LDADD = $(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
@@ -26,9 +26,9 @@ if COVERAGE_ENABLED
src_app_tor_cov_SOURCES = $(src_app_tor_SOURCES)
src_app_tor_cov_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_app_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_app_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
src_app_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@
src_app_tor_cov_LDADD = $(TOR_INTERNAL_TESTING_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+1 -1
View File
@@ -22,7 +22,7 @@
#define ONION_NTOR_PRIVATE
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_hkdf.h"
#include "lib/crypt_ops/crypto_util.h"
+1 -1
View File
@@ -7,7 +7,7 @@
#include "core/or/or.h"
#include "core/or/circuitlist.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_util.h"
#include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
#include "core/or/relay.h"
+17 -8
View File
@@ -449,6 +449,20 @@ connection_new(int type, int socket_family)
}
}
static void
connection_close_and_invalidate_socket(connection_t *conn)
{
if (connection_speaks_cells(conn)) {
or_connection_t *or_conn = TO_OR_CONN(conn);
tor_tls_free(or_conn->tls);
or_conn->tls = NULL;
or_conn->base_.s = TOR_INVALID_SOCKET;
} else {
tor_close_socket(conn->s);
conn->s = TOR_INVALID_SOCKET;
}
}
/** Initializes conn. (you must call connection_add() to link it into the main
* array).
*
@@ -614,9 +628,8 @@ connection_free_minimal(connection_t *conn)
tor_free(conn->address);
if (connection_speaks_cells(conn)) {
connection_close_and_invalidate_socket(conn);
or_connection_t *or_conn = TO_OR_CONN(conn);
tor_tls_free(or_conn->tls);
or_conn->tls = NULL;
or_handshake_state_free(or_conn->handshake_state);
or_conn->handshake_state = NULL;
tor_free(or_conn->nickname);
@@ -692,9 +705,7 @@ connection_free_minimal(connection_t *conn)
}
if (SOCKET_OK(conn->s)) {
log_debug(LD_NET,"closing fd %d.",(int)conn->s);
tor_close_socket(conn->s);
conn->s = TOR_INVALID_SOCKET;
connection_close_and_invalidate_socket(conn);
}
if (conn->type == CONN_TYPE_OR &&
@@ -820,9 +831,7 @@ connection_close_immediate(connection_t *conn)
conn->read_blocked_on_bw = 0;
conn->write_blocked_on_bw = 0;
if (SOCKET_OK(conn->s))
tor_close_socket(conn->s);
conn->s = TOR_INVALID_SOCKET;
connection_close_and_invalidate_socket(conn);
if (conn->linked)
conn->linked_conn_is_closed = 1;
if (conn->outbuf)
+4 -2
View File
@@ -121,6 +121,7 @@
#include "lib/evloop/compat_libevent.h"
#include "lib/encoding/confline.h"
#include "lib/evloop/timers.h"
#include "lib/crypt_ops/crypto_init.h"
#include <event2/event.h>
@@ -3503,10 +3504,11 @@ tor_init(int argc, char *argv[])
const char *version = get_version();
log_notice(LD_GENERAL, "Tor %s running on %s with Libevent %s, "
"OpenSSL %s, Zlib %s, Liblzma %s, and Libzstd %s.", version,
"%s %s, Zlib %s, Liblzma %s, and Libzstd %s.", version,
get_uname(),
tor_libevent_get_version_str(),
crypto_openssl_get_version_str(),
crypto_get_library_name(),
crypto_get_library_version_string(),
tor_compress_supports_method(ZLIB_METHOD) ?
tor_compress_version_str(ZLIB_METHOD) : "N/A",
tor_compress_supports_method(LZMA_METHOD) ?
+1
View File
@@ -70,6 +70,7 @@
#include "core/or/var_cell_st.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
/** How many CELL_PADDING cells have we received, ever? */
uint64_t stats_n_padding_cells_processed = 0;
+1
View File
@@ -73,6 +73,7 @@
#include "lib/crypt_ops/crypto_format.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
static int connection_tls_finish_handshake(or_connection_t *conn);
static int connection_or_launch_v3_or_handshake(or_connection_t *conn);
+2 -1
View File
@@ -27,7 +27,8 @@
#include "lib/cc/torint.h"
#include "lib/container/map.h"
#include "lib/container/smartlist.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/ctime/di_ops.h"
#include "lib/defs/dh_sizes.h"
#include "lib/encoding/binascii.h"
+11
View File
@@ -25,6 +25,7 @@
#ifdef TINYTEST_LOCAL
#include "tinytest_local.h"
#endif
#define TINYTEST_POSTFORK
#include <stdio.h>
#include <stdlib.h>
@@ -118,6 +119,14 @@ testcase_run_bare_(const struct testcase_t *testcase)
#ifndef NO_FORKING
#ifdef TINYTEST_POSTFORK
void tinytest_prefork(void);
void tinytest_postfork(void);
#else
static void tinytest_prefork(void) { }
static void tinytest_postfork(void) { }
#endif
static enum outcome
testcase_run_forked_(const struct testgroup_t *group,
const struct testcase_t *testcase)
@@ -178,10 +187,12 @@ testcase_run_forked_(const struct testgroup_t *group,
if (opt_verbosity>0)
printf("[forking] ");
tinytest_prefork();
pid = fork();
#ifdef FORK_BREAKS_GCOV
vproc_transaction_begin(0);
#endif
tinytest_postfork();
if (!pid) {
/* child. */
int test_r, write_r;
+2 -2
View File
@@ -4994,7 +4994,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
if (!strcasecmp(key_type_rsa1024, key_type)) {
/* "RSA:<Base64 Blob>" - Loading a pre-existing RSA1024 key. */
pk = crypto_pk_base64_decode(key_blob, strlen(key_blob));
pk = crypto_pk_base64_decode_private(key_blob, strlen(key_blob));
if (!pk) {
err_msg = tor_strdup("512 Failed to decode RSA key\r\n");
goto err;
@@ -5029,7 +5029,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
goto err;
}
if (!discard_pk) {
if (crypto_pk_base64_encode(pk, &key_new_blob)) {
if (crypto_pk_base64_encode_private(pk, &key_new_blob)) {
crypto_pk_free(pk);
tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
key_type_rsa1024);
+1 -1
View File
@@ -14,7 +14,7 @@
#include "lib/string/util_string.h"
#include "lib/string/printf.h"
#include "lib/memarea/memarea.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_rsa.h"
#include <string.h>
+1
View File
@@ -33,6 +33,7 @@
#include "lib/log/log.h"
#include "trunnel/link_handshake.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
#include "core/or/or_handshake_certs_st.h"
+2 -1
View File
@@ -55,6 +55,7 @@
#include "lib/tls/tortls.h"
#include "lib/encoding/confline.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_init.h"
/**
* \file router.c
@@ -579,7 +580,7 @@ init_key_from_file(const char *fname, int generate, int severity,
tor_log(severity, LD_GENERAL,"Error generating onion key");
goto error;
}
if (crypto_pk_check_key(prkey) <= 0) {
if (! crypto_pk_is_valid_private_key(prkey)) {
tor_log(severity, LD_GENERAL,"Generated key seems invalid");
goto error;
}
+1
View File
@@ -24,6 +24,7 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/term/getpass.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
#include "lib/crypt_ops/crypto_format.h"
#define ENC_KEY_HEADER "Boxed Ed25519 key"
+1 -1
View File
@@ -12,7 +12,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "core/or/dos.h"
#include "core/or/relay.h"
#include "feature/rend/rendmid.h"
+1 -1
View File
@@ -1652,7 +1652,7 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
crypto_pk_free(prkey);
goto err;
}
if (crypto_pk_check_key(prkey) <= 0) {
if (! crypto_pk_is_valid_private_key(prkey)) {
log_warn(LD_BUG,"Generated client key seems invalid");
crypto_pk_free(prkey);
goto err;
+106
View File
@@ -0,0 +1,106 @@
/* 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_nss.c
* \brief Use NSS to implement AES_CTR.
**/
#include "orconfig.h"
#include "lib/crypt_ops/aes.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/log/util_bug.h"
DISABLE_GCC_WARNING(strict-prototypes)
#include <pk11pub.h>
#include <secerr.h>
ENABLE_GCC_WARNING(strict-prototypes)
aes_cnt_cipher_t *
aes_new_cipher(const uint8_t *key, const uint8_t *iv,
int key_bits)
{
const CK_MECHANISM_TYPE ckm = CKM_AES_CTR;
SECItem keyItem = { .type = siBuffer,
.data = (unsigned char *)key,
.len = (key_bits / 8) };
CK_AES_CTR_PARAMS params;
params.ulCounterBits = 128;
memcpy(params.cb, iv, 16);
SECItem ivItem = { .type = siBuffer,
.data = (unsigned char *)&params,
.len = sizeof(params) };
PK11SlotInfo *slot = NULL;
PK11SymKey *keyObj = NULL;
SECItem *ivObj = NULL;
PK11Context *result = NULL;
slot = PK11_GetBestSlot(ckm, NULL);
if (!slot)
goto err;
keyObj = PK11_ImportSymKey(slot, ckm, PK11_OriginUnwrap,
CKA_ENCRYPT, &keyItem, NULL);
if (!keyObj)
goto err;
ivObj = PK11_ParamFromIV(ckm, &ivItem);
if (!ivObj)
goto err;
PORT_SetError(SEC_ERROR_IO);
result = PK11_CreateContextBySymKey(ckm, CKA_ENCRYPT, keyObj, ivObj);
err:
memwipe(&params, 0, sizeof(params));
if (ivObj)
SECITEM_FreeItem(ivObj, PR_TRUE);
if (keyObj)
PK11_FreeSymKey(keyObj);
if (slot)
PK11_FreeSlot(slot);
tor_assert(result);
return (aes_cnt_cipher_t *)result;
}
void
aes_cipher_free_(aes_cnt_cipher_t *cipher)
{
if (!cipher)
return;
PK11_DestroyContext((PK11Context*) cipher, PR_TRUE);
}
void
aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data_, size_t len_)
{
tor_assert(len_ <= INT_MAX);
SECStatus s;
PK11Context *ctx = (PK11Context*)cipher;
unsigned char *data = (unsigned char *)data_;
int len = (int) len_;
int result_len = 0;
s = PK11_CipherOp(ctx, data, &result_len, len, data, len);
tor_assert(s == SECSuccess);
tor_assert(result_len == len);
}
int
evaluate_evp_for_aes(int force_value)
{
(void)force_value;
return 0;
}
int
evaluate_ctr_for_aes(void)
{
return 0;
}
@@ -5,8 +5,8 @@
/* See LICENSE for licensing information */
/**
* \file aes.c
* \brief Implements a counter-mode stream cipher on top of AES.
* \file aes_openssl.c
* \brief Use OpenSSL to implement AES_CTR.
**/
#include "orconfig.h"
+6
View File
@@ -7,6 +7,10 @@
#ifndef TOR_COMPAT_OPENSSL_H
#define TOR_COMPAT_OPENSSL_H
#include "orconfig.h"
#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#include "lib/crypt_ops/crypto_openssl_mgt.h"
@@ -47,5 +51,7 @@
#define CONST_IF_OPENSSL_1_1_API const
#endif /* !defined(OPENSSL_1_1_API) */
#endif /* defined(ENABLE_OPENSSL) */
#endif /* !defined(TOR_COMPAT_OPENSSL_H) */
-509
View File
@@ -1,509 +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 "lib/crypt_ops/compat_openssl.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/crypt_ops/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 "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/cc/torint.h"
#include "lib/crypt_ops/aes.h"
#include "lib/encoding/binascii.h"
#include "keccak-tiny/keccak-tiny.h"
#include "siphash.h"
#include <string.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;
}
/** @} */
+190
View File
@@ -0,0 +1,190 @@
/* 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_cipher.c
* \brief Symmetric cryptography (low-level) with AES.
**/
#include "orconfig.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/cc/torint.h"
#include "lib/crypt_ops/aes.h"
#include <string.h>
/** 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);
}
/* 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);
}
@@ -5,19 +5,18 @@
/* See LICENSE for licensing information */
/**
* \file crypto.h
* \file crypto_cipher.h
*
* \brief Headers for crypto.c
* \brief Headers for crypto_cipher.c
**/
#ifndef TOR_CRYPTO_H
#define TOR_CRYPTO_H
#ifndef TOR_CRYPTO_CIPHER_H
#define TOR_CRYPTO_CIPHER_H
#include "orconfig.h"
#include <stdio.h>
#include "lib/cc/torint.h"
#include "lib/crypt_ops/crypto_rsa.h"
/** Length of our symmetric cipher's keys of 128-bit. */
#define CIPHER_KEY_LEN 16
@@ -26,22 +25,8 @@
/** 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);
@@ -69,6 +54,4 @@ 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) */
+43 -441
View File
@@ -7,6 +7,8 @@
/**
* \file crypto_dh.c
* \brief Block of functions related with DH utilities and operations.
* over Z_p. We aren't using this for any new crypto -- EC is more
* efficient.
**/
#include "lib/crypt_ops/compat_openssl.h"
@@ -17,411 +19,50 @@
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/dh.h>
ENABLE_GCC_WARNING(redundant-decls)
#include <openssl/bn.h>
#include <string.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.
const unsigned DH_GENERATOR = 2;
/** 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.
*/
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.
const char TLS_DH_PRIME[] =
"D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98"
"BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A"
"467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7"
"DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68"
"B0E7393E0F24218EB3";
/**
* 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 }.
*/
static void
crypto_set_dh_generator(void)
{
BIGNUM *generator;
int r;
const char OAKLEY_PRIME_2[] =
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
"49286651ECE65381FFFFFFFFFFFFFFFF";
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)
crypto_dh_init(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:
#ifdef ENABLE_OPENSSL
crypto_dh_init_openssl();
#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 \>= DH1024_KEY_LEN.
*/
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;
#ifdef ENABLE_NSS
crypto_dh_init_nss();
#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 DH1024_KEY_LEN (%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)
void
crypto_dh_free_all(void)
{
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;
#ifdef ENABLE_OPENSSL
crypto_dh_free_all_openssl();
#endif
#ifdef ENABLE_NSS
crypto_dh_free_all_nss();
#endif
}
/** Given a DH key exchange object, and our peer's value of g^y (as a
@@ -439,31 +80,20 @@ 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;
}
unsigned char *secret_tmp = NULL;
size_t secret_len=0, secret_tmp_len=0;
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.");
ssize_t result = crypto_dh_handshake(severity, dh, pubkey, pubkey_len,
secret_tmp, secret_tmp_len);
if (result < 0)
goto error;
}
secret_len = result;
if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len,
if (crypto_expand_key_material_TAP(secret_tmp, secret_len,
(uint8_t*)secret_out, secret_bytes_out)<0)
goto error;
secret_len = secret_bytes_out;
@@ -472,9 +102,6 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
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);
@@ -484,28 +111,3 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
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;
}
+20 -3
View File
@@ -19,11 +19,15 @@
typedef struct crypto_dh_t crypto_dh_t;
extern const unsigned DH_GENERATOR;
extern const char TLS_DH_PRIME[];
extern const char OAKLEY_PRIME_2[];
/* Key negotiation */
#define DH_TYPE_CIRCUIT 1
#define DH_TYPE_REND 2
#define DH_TYPE_TLS 3
void crypto_set_tls_dh_prime(void);
void crypto_dh_init(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);
@@ -36,12 +40,25 @@ ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
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 */
ssize_t crypto_dh_handshake(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
unsigned char *secret_out,
size_t secret_bytes_out);
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);
struct dh_st *crypto_dh_new_openssl_tls(void);
#ifdef ENABLE_OPENSSL
void crypto_dh_init_openssl(void);
void crypto_dh_free_all_openssl(void);
#endif
#ifdef ENABLE_NSS
void crypto_dh_init_nss(void);
void crypto_dh_free_all_nss(void);
#endif
#endif /* !defined(TOR_CRYPTO_DH_H) */
+207
View File
@@ -0,0 +1,207 @@
/* 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_nss.h
*
* \brief NSS implementation of Diffie-Hellman over Z_p.
**/
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/encoding/binascii.h"
#include "lib/log/util_bug.h"
#include "lib/malloc/malloc.h"
#include <cryptohi.h>
#include <keyhi.h>
#include <pk11pub.h>
static int dh_initialized = 0;
static SECKEYDHParams tls_dh_param, circuit_dh_param;
static unsigned char tls_dh_prime_data[DH1024_KEY_LEN];
static unsigned char circuit_dh_prime_data[DH1024_KEY_LEN];
static unsigned char dh_generator_data[1];
void
crypto_dh_init_nss(void)
{
if (dh_initialized)
return;
int r;
r = base16_decode((char*)tls_dh_prime_data,
sizeof(tls_dh_prime_data),
TLS_DH_PRIME, strlen(TLS_DH_PRIME));
tor_assert(r == DH1024_KEY_LEN);
r = base16_decode((char*)circuit_dh_prime_data,
sizeof(circuit_dh_prime_data),
OAKLEY_PRIME_2, strlen(OAKLEY_PRIME_2));
tor_assert(r == DH1024_KEY_LEN);
dh_generator_data[0] = DH_GENERATOR;
tls_dh_param.prime.data = tls_dh_prime_data;
tls_dh_param.prime.len = DH1024_KEY_LEN;
tls_dh_param.base.data = dh_generator_data;
tls_dh_param.base.len = 1;
circuit_dh_param.prime.data = circuit_dh_prime_data;
circuit_dh_param.prime.len = DH1024_KEY_LEN;
circuit_dh_param.base.data = dh_generator_data;
circuit_dh_param.base.len = 1;
}
void
crypto_dh_free_all_nss(void)
{
dh_initialized = 0;
}
struct crypto_dh_t {
int dh_type; // XXXX let's remove this later on.
SECKEYPrivateKey *seckey;
SECKEYPublicKey *pubkey;
};
crypto_dh_t *
crypto_dh_new(int dh_type)
{
crypto_dh_t *r = tor_malloc_zero(sizeof(crypto_dh_t));
r->dh_type = dh_type;
return r;
}
crypto_dh_t *
crypto_dh_dup(const crypto_dh_t *dh)
{
tor_assert(dh);
crypto_dh_t *r = crypto_dh_new(dh->dh_type);
if (dh->seckey)
r->seckey = SECKEY_CopyPrivateKey(dh->seckey);
if (dh->pubkey)
r->pubkey = SECKEY_CopyPublicKey(dh->pubkey);
return r;
}
int
crypto_dh_get_bytes(crypto_dh_t *dh)
{
(void)dh;
return DH1024_KEY_LEN;
}
int
crypto_dh_generate_public(crypto_dh_t *dh)
{
tor_assert(dh);
SECKEYDHParams *p;
if (dh->dh_type == DH_TYPE_TLS)
p = &tls_dh_param;
else
p = &circuit_dh_param;
dh->seckey = SECKEY_CreateDHPrivateKey(p, &dh->pubkey, NULL);
if (!dh->seckey || !dh->pubkey)
return -1;
else
return 0;
}
int
crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out,
size_t pubkey_out_len)
{
tor_assert(dh);
tor_assert(pubkey_out);
if (!dh->pubkey) {
if (crypto_dh_generate_public(dh) < 0)
return -1;
}
const SECItem *item = &dh->pubkey->u.dh.publicValue;
if (item->len > pubkey_out_len)
return -1;
/* Left-pad the result with 0s. */
memset(pubkey_out, 0, pubkey_out_len);
memcpy(pubkey_out + pubkey_out_len - item->len,
item->data,
item->len);
return 0;
}
void
crypto_dh_free_(crypto_dh_t *dh)
{
if (!dh)
return;
if (dh->seckey)
SECKEY_DestroyPrivateKey(dh->seckey);
if (dh->pubkey)
SECKEY_DestroyPublicKey(dh->pubkey);
tor_free(dh);
}
ssize_t
crypto_dh_handshake(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
unsigned char *secret_out,
size_t secret_bytes_out)
{
tor_assert(dh);
if (pubkey_len > DH1024_KEY_LEN)
return -1;
if (!dh->pubkey || !dh->seckey)
return -1;
if (secret_bytes_out < DH1024_KEY_LEN)
return -1;
SECKEYPublicKey peer_key;
memset(&peer_key, 0, sizeof(peer_key));
peer_key.keyType = dhKey;
peer_key.pkcs11ID = CK_INVALID_HANDLE;
if (dh->dh_type == DH_TYPE_TLS)
peer_key.u.dh.prime.data = tls_dh_prime_data; // should never use this code
else
peer_key.u.dh.prime.data = circuit_dh_prime_data;
peer_key.u.dh.prime.len = DH1024_KEY_LEN;
peer_key.u.dh.base.data = dh_generator_data;
peer_key.u.dh.base.len = 1;
peer_key.u.dh.publicValue.data = (unsigned char *)pubkey;
peer_key.u.dh.publicValue.len = (int) pubkey_len;
PK11SymKey *sym = PK11_PubDerive(dh->seckey, &peer_key,
PR_FALSE, NULL, NULL, CKM_DH_PKCS_DERIVE,
CKM_GENERIC_SECRET_KEY_GEN /* ??? */,
CKA_DERIVE, 0, NULL);
if (! sym) {
crypto_nss_log_errors(severity, "deriving a DH shared secret");
return -1;
}
SECStatus s = PK11_ExtractKeyValue(sym);
if (s != SECSuccess) {
crypto_nss_log_errors(severity, "extracting a DH shared secret");
PK11_FreeSymKey(sym);
return -1;
}
SECItem *result = PK11_GetKeyData(sym);
tor_assert(result); // This cannot fail.
if (BUG(result->len > secret_bytes_out)) {
PK11_FreeSymKey(sym);
return -1;
}
ssize_t len = result->len;
memcpy(secret_out, result->data, len);
PK11_FreeSymKey(sym);
return len;
}
+471
View File
@@ -0,0 +1,471 @@
/* 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_openssl.c
* \brief Implement Tor's Z_p diffie-hellman stuff for OpenSSL.
**/
#include "lib/crypt_ops/compat_openssl.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_hkdf.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/dh.h>
ENABLE_GCC_WARNING(redundant-decls)
#include <openssl/bn.h>
#include <string.h>
#ifndef ENABLE_NSS
static int tor_check_dh_key(int severity, const BIGNUM *bn);
/** 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 */
};
#endif
static DH *new_openssl_dh_from_params(BIGNUM *p, BIGNUM *g);
/** 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;
}
/**
* Helper: convert <b>hex<b> to a bignum, and return it. Assert that the
* operation was successful.
*/
static BIGNUM *
bignum_from_hex(const char *hex)
{
BIGNUM *result = BN_new();
tor_assert(result);
int r = BN_hex2bn(&result, hex);
tor_assert(r);
tor_assert(result);
return result;
}
/** 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;
}
/** Initialize our DH parameters. Idempotent. */
void
crypto_dh_init_openssl(void)
{
if (dh_param_p && dh_param_g && dh_param_p_tls)
return;
tor_assert(dh_param_g == NULL);
tor_assert(dh_param_p == NULL);
tor_assert(dh_param_p_tls == NULL);
crypto_set_dh_generator();
dh_param_p = bignum_from_hex(OAKLEY_PRIME_2);
dh_param_p_tls = bignum_from_hex(TLS_DH_PRIME);
tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g));
tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g));
}
/** 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
/** Used by tortls.c: Get the DH* for use with TLS.
*/
DH *
crypto_dh_new_openssl_tls(void)
{
return new_openssl_dh_from_params(dh_param_p_tls, dh_param_g);
}
#ifndef ENABLE_NSS
/** 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)
crypto_dh_init();
BIGNUM *dh_p = NULL;
if (dh_type == DH_TYPE_TLS) {
dh_p = dh_param_p_tls;
} else {
dh_p = dh_param_p;
}
res->dh = new_openssl_dh_from_params(dh_p, dh_param_g);
if (res->dh == NULL)
tor_free(res); // sets res to NULL.
return res;
}
#endif
/** Create and return a new openssl DH from a given prime and generator. */
static DH *
new_openssl_dh_from_params(BIGNUM *p, BIGNUM *g)
{
DH *res_dh;
if (!(res_dh = DH_new()))
goto err;
BIGNUM *dh_p = NULL, *dh_g = NULL;
dh_p = BN_dup(p);
if (!dh_p)
goto err;
dh_g = BN_dup(g);
if (!dh_g) {
BN_free(dh_p);
goto err;
}
#ifdef OPENSSL_1_1_API
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)) */
res_dh->p = dh_p;
res_dh->g = dh_g;
res_dh->length = DH_PRIVATE_KEY_BITS;
#endif /* defined(OPENSSL_1_1_API) */
return res_dh;
/* LCOV_EXCL_START
* This error condition is only reached when an allocation fails */
err:
crypto_openssl_log_errors(LOG_WARN, "creating DH object");
if (res_dh) DH_free(res_dh); /* frees p and g too */
return NULL;
/* LCOV_EXCL_STOP */
}
#ifndef ENABLE_NSS
/** 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_openssl_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 \>= DH1024_KEY_LEN.
*/
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 DH1024_KEY_LEN (%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))
crypto_dh_init(); //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
* g^xy as a big-endian integer in <b>secret_out</b>.
* Return the number of bytes generated on success,
* or -1 on failure.
*
* This function MUST validate that g^y is actually in the group.
*/
ssize_t
crypto_dh_handshake(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
unsigned char *secret_out, size_t secret_bytes_out)
{
BIGNUM *pubkey_bn = NULL;
size_t secret_len=0;
int result=0;
tor_assert(dh);
tor_assert(secret_bytes_out/DIGEST_LEN <= 255);
tor_assert(pubkey_len < INT_MAX);
if (BUG(crypto_dh_get_bytes(dh) > (int)secret_bytes_out)) {
goto error;
}
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;
}
result = DH_compute_key(secret_out, pubkey_bn, dh->dh);
if (result < 0) {
log_warn(LD_CRYPTO,"DH_compute_key() failed.");
goto error;
}
secret_len = result;
goto done;
error:
result = -1;
done:
crypto_openssl_log_errors(LOG_WARN, "completing DH handshake");
if (pubkey_bn)
BN_clear_free(pubkey_bn);
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);
}
#endif
void
crypto_dh_free_all_openssl(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;
}
+251 -11
View File
@@ -12,7 +12,6 @@
#include "lib/container/smartlist.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_openssl_mgt.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
@@ -24,12 +23,92 @@
#include "lib/arch/bytes.h"
#ifdef ENABLE_NSS
DISABLE_GCC_WARNING(strict-prototypes)
#include <pk11pub.h>
ENABLE_GCC_WARNING(strict-prototypes)
#else
#include "lib/crypt_ops/crypto_openssl_mgt.h"
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/hmac.h>
#include <openssl/sha.h>
ENABLE_GCC_WARNING(redundant-decls)
#endif
#ifdef ENABLE_NSS
/**
* Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS).
* On failure, return SEC_OID_UNKNOWN. */
static SECOidTag
digest_alg_to_nss_oid(digest_algorithm_t alg)
{
switch (alg) {
case DIGEST_SHA1: return SEC_OID_SHA1;
case DIGEST_SHA256: return SEC_OID_SHA256;
case DIGEST_SHA512: return SEC_OID_SHA512;
case DIGEST_SHA3_256: /* Fall through */
case DIGEST_SHA3_512: /* Fall through */
default:
return SEC_OID_UNKNOWN;
}
}
/* Helper: get an unkeyed digest via pk11wrap */
static int
digest_nss_internal(SECOidTag alg,
char *digest, unsigned len_out,
const char *msg, size_t msg_len)
{
if (alg == SEC_OID_UNKNOWN)
return -1;
tor_assert(msg_len <= UINT_MAX);
int rv = -1;
SECStatus s;
PK11Context *ctx = PK11_CreateDigestContext(alg);
if (!ctx)
return -1;
s = PK11_DigestBegin(ctx);
if (s != SECSuccess)
goto done;
s = PK11_DigestOp(ctx, (const unsigned char *)msg, (unsigned int)msg_len);
if (s != SECSuccess)
goto done;
unsigned int len = 0;
s = PK11_DigestFinal(ctx, (unsigned char *)digest, &len, len_out);
if (s != SECSuccess)
goto done;
rv = 0;
done:
PK11_DestroyContext(ctx, PR_TRUE);
return rv;
}
/** True iff alg is implemented in our crypto library, and we want to use that
* implementation */
static bool
library_supports_digest(digest_algorithm_t alg)
{
switch (alg) {
case DIGEST_SHA1: /* Fall through */
case DIGEST_SHA256: /* Fall through */
case DIGEST_SHA512: /* Fall through */
return true;
case DIGEST_SHA3_256: /* Fall through */
case DIGEST_SHA3_512: /* Fall through */
default:
return false;
}
}
#endif
/* Crypto digest functions */
@@ -37,13 +116,18 @@ ENABLE_GCC_WARNING(redundant-decls)
* <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)
MOCK_IMPL(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)
#ifdef ENABLE_NSS
return digest_nss_internal(SEC_OID_SHA1, digest, DIGEST_LEN, m, len);
#else
if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) {
return -1;
}
#endif
return 0;
}
@@ -59,11 +143,16 @@ crypto_digest256(char *digest, const char *m, size_t len,
tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
int ret = 0;
if (algorithm == DIGEST_SHA256)
if (algorithm == DIGEST_SHA256) {
#ifdef ENABLE_NSS
return digest_nss_internal(SEC_OID_SHA256, digest, DIGEST256_LEN, m, len);
#else
ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
else
#endif
} else {
ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
> -1);
}
if (!ret)
return -1;
@@ -82,12 +171,17 @@ crypto_digest512(char *digest, const char *m, size_t len,
tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
int ret = 0;
if (algorithm == DIGEST_SHA512)
if (algorithm == DIGEST_SHA512) {
#ifdef ENABLE_NSS
return digest_nss_internal(SEC_OID_SHA512, digest, DIGEST512_LEN, m, len);
#else
ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
!= NULL);
else
#endif
} else {
ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
> -1);
}
if (!ret)
return -1;
@@ -181,9 +275,13 @@ struct crypto_digest_t {
* that space for other members might not even be allocated!
*/
union {
#ifdef ENABLE_NSS
PK11Context *ctx;
#else
SHA_CTX sha1; /**< state for SHA1 */
SHA256_CTX sha2; /**< state for SHA256 */
SHA512_CTX sha512; /**< state for SHA512 */
#endif
keccak_state sha3; /**< state for SHA3-[256,512] */
} d;
};
@@ -214,12 +312,19 @@ crypto_digest_alloc_bytes(digest_algorithm_t alg)
#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
STRUCT_FIELD_SIZE(crypto_digest_t, f))
switch (alg) {
#ifdef ENABLE_NSS
case DIGEST_SHA1: /* Fall through */
case DIGEST_SHA256: /* Fall through */
case DIGEST_SHA512:
return END_OF_FIELD(d.ctx);
#else
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);
#endif
case DIGEST_SHA3_256:
case DIGEST_SHA3_512:
return END_OF_FIELD(d.sha3);
@@ -243,6 +348,21 @@ crypto_digest_new_internal(digest_algorithm_t algorithm)
switch (algorithm)
{
#ifdef ENABLE_NSS
case DIGEST_SHA1: /* fall through */
case DIGEST_SHA256: /* fall through */
case DIGEST_SHA512:
r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm));
if (BUG(!r->d.ctx)) {
tor_free(r);
return NULL;
}
if (BUG(SECSuccess != PK11_DigestBegin(r->d.ctx))) {
crypto_digest_free(r);
return NULL;
}
break;
#else
case DIGEST_SHA1:
SHA1_Init(&r->d.sha1);
break;
@@ -252,6 +372,7 @@ crypto_digest_new_internal(digest_algorithm_t algorithm)
case DIGEST_SHA512:
SHA512_Init(&r->d.sha512);
break;
#endif
case DIGEST_SHA3_256:
keccak_digest_init(&r->d.sha3, 256);
break;
@@ -302,6 +423,11 @@ crypto_digest_free_(crypto_digest_t *digest)
{
if (!digest)
return;
#ifdef ENABLE_NSS
if (library_supports_digest(digest->algorithm)) {
PK11_DestroyContext(digest->d.ctx, PR_TRUE);
}
#endif
size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
memwipe(digest, 0, bytes);
tor_free(digest);
@@ -324,6 +450,17 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
* just doing it ourselves. Hashes are fast.
*/
switch (digest->algorithm) {
#ifdef ENABLE_NSS
case DIGEST_SHA1: /* fall through */
case DIGEST_SHA256: /* fall through */
case DIGEST_SHA512:
tor_assert(len <= UINT_MAX);
SECStatus s = PK11_DigestOp(digest->d.ctx,
(const unsigned char *)data,
(unsigned int)len);
tor_assert(s == SECSuccess);
break;
#else
case DIGEST_SHA1:
SHA1_Update(&digest->d.sha1, (void*)data, len);
break;
@@ -333,6 +470,7 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
case DIGEST_SHA512:
SHA512_Update(&digest->d.sha512, (void*)data, len);
break;
#endif
case DIGEST_SHA3_256: /* FALLSTHROUGH */
case DIGEST_SHA3_512:
keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
@@ -357,7 +495,6 @@ 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));
@@ -370,7 +507,26 @@ crypto_digest_get_digest(crypto_digest_t *digest,
return;
}
#ifdef ENABLE_NSS
/* Copy into a temporary buffer since DigestFinal (alters) the context */
unsigned char buf[1024];
unsigned int saved_len = 0;
unsigned rlen;
unsigned char *saved = PK11_SaveContextAlloc(digest->d.ctx,
buf, sizeof(buf),
&saved_len);
tor_assert(saved);
SECStatus s = PK11_DigestFinal(digest->d.ctx, r, &rlen, sizeof(r));
tor_assert(s == SECSuccess);
tor_assert(rlen >= out_len);
s = PK11_RestoreContext(digest->d.ctx, saved, saved_len);
tor_assert(s == SECSuccess);
if (saved != buf) {
PORT_ZFree(saved, saved_len);
}
#else
const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
crypto_digest_t tmpenv;
/* memcpy into a temporary ctx, since SHA*_Final clears the context */
memcpy(&tmpenv, digest, alloc_bytes);
switch (digest->algorithm) {
@@ -393,6 +549,7 @@ crypto_digest_get_digest(crypto_digest_t *digest,
break;
//LCOV_EXCL_STOP
}
#endif
memcpy(out, r, out_len);
memwipe(r, 0, sizeof(r));
}
@@ -408,7 +565,13 @@ 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);
crypto_digest_t *result = tor_memdup(digest, alloc_bytes);
#ifdef ENABLE_NSS
if (library_supports_digest(digest->algorithm)) {
result->d.ctx = PK11_CloneContext(digest->d.ctx);
}
#endif
return result;
}
/** Temporarily save the state of <b>digest</b> in <b>checkpoint</b>.
@@ -420,6 +583,18 @@ crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint,
{
const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
tor_assert(bytes <= sizeof(checkpoint->mem));
#ifdef ENABLE_NSS
if (library_supports_digest(digest->algorithm)) {
unsigned char *allocated;
allocated = PK11_SaveContextAlloc(digest->d.ctx,
(unsigned char *)checkpoint->mem,
sizeof(checkpoint->mem),
&checkpoint->bytes_used);
/* No allocation is allowed here. */
tor_assert(allocated == checkpoint->mem);
return;
}
#endif
memcpy(checkpoint->mem, digest, bytes);
}
@@ -431,6 +606,15 @@ crypto_digest_restore(crypto_digest_t *digest,
const crypto_digest_checkpoint_t *checkpoint)
{
const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
#ifdef ENABLE_NSS
if (library_supports_digest(digest->algorithm)) {
SECStatus s = PK11_RestoreContext(digest->d.ctx,
(unsigned char *)checkpoint->mem,
checkpoint->bytes_used);
tor_assert(s == SECSuccess);
return;
}
#endif
memcpy(digest, checkpoint->mem, bytes);
}
@@ -446,6 +630,13 @@ crypto_digest_assign(crypto_digest_t *into,
tor_assert(from);
tor_assert(into->algorithm == from->algorithm);
const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
#ifdef ENABLE_NSS
if (library_supports_digest(from->algorithm)) {
PK11_DestroyContext(into->d.ctx, PR_TRUE);
into->d.ctx = PK11_CloneContext(from->d.ctx);
return;
}
#endif
memcpy(into,from,alloc_bytes);
}
@@ -496,14 +687,63 @@ 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);
#ifdef ENABLE_NSS
PK11SlotInfo *slot = NULL;
PK11SymKey *symKey = NULL;
PK11Context *hmac = NULL;
int ok = 0;
SECStatus s;
SECItem keyItem, paramItem;
keyItem.data = (unsigned char *)key;
keyItem.len = (unsigned)key_len;
paramItem.type = siBuffer;
paramItem.data = NULL;
paramItem.len = 0;
slot = PK11_GetBestSlot(CKM_SHA256_HMAC, NULL);
if (!slot)
goto done;
symKey = PK11_ImportSymKey(slot, CKM_SHA256_HMAC,
PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL);
if (!symKey)
goto done;
hmac = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, symKey,
&paramItem);
if (!hmac)
goto done;
s = PK11_DigestBegin(hmac);
if (s != SECSuccess)
goto done;
s = PK11_DigestOp(hmac, (const unsigned char *)msg, (unsigned int)msg_len);
if (s != SECSuccess)
goto done;
unsigned int len=0;
s = PK11_DigestFinal(hmac, (unsigned char *)hmac_out, &len, DIGEST256_LEN);
if (s != SECSuccess || len != DIGEST256_LEN)
goto done;
ok = 1;
done:
if (hmac)
PK11_DestroyContext(hmac, PR_TRUE);
if (symKey)
PK11_FreeSymKey(symKey);
if (slot)
PK11_FreeSlot(slot);
tor_assert(ok);
#else
unsigned char *rv = NULL;
rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
(unsigned char*)hmac_out, NULL);
tor_assert(rv);
#endif
}
/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a
+5 -1
View File
@@ -16,6 +16,7 @@
#include "lib/cc/torint.h"
#include "lib/defs/digest_sizes.h"
#include "lib/malloc/malloc.h"
#include "lib/testsupport/testsupport.h"
/** Length of a sha1 message digest when encoded in base32 with trailing =
* signs removed. */
@@ -51,6 +52,9 @@ typedef enum {
/** Structure used to temporarily save the a digest object. Only implemented
* for SHA1 digest for now. */
typedef struct crypto_digest_checkpoint_t {
#ifdef ENABLE_NSS
unsigned int bytes_used;
#endif
uint8_t mem[DIGEST_CHECKPOINT_BYTES];
} crypto_digest_checkpoint_t;
@@ -72,7 +76,7 @@ typedef struct crypto_xof_t crypto_xof_t;
struct smartlist_t;
/* SHA-1 and other digests */
int crypto_digest(char *digest, const char *m, size_t len);
MOCK_DECL(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,
+1
View File
@@ -37,6 +37,7 @@
#include "ed25519/donna/ed25519_donna_tor.h"
#include <string.h>
#include <errno.h>
static void pick_ed25519_impl(void);
+1
View File
@@ -29,6 +29,7 @@
#include "lib/fs/files.h"
#include <string.h>
#include <errno.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
+2
View File
@@ -17,12 +17,14 @@
#include "lib/intmath/cmp.h"
#include "lib/log/util_bug.h"
#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#if defined(HAVE_ERR_LOAD_KDF_STRINGS)
#include <openssl/kdf.h>
#define HAVE_OPENSSL_HKDF 1
#endif
#endif
#include <string.h>
+193
View File
@@ -0,0 +1,193 @@
/* 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_init.c
*
* \brief Initialize and shut down Tor's crypto library and subsystem.
**/
#include "orconfig.h"
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_openssl_mgt.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "siphash.h"
/** Boolean: has our crypto library been initialized? (early phase) */
static int crypto_early_initialized_ = 0;
/** Boolean: has our crypto library been initialized? (late phase) */
static int crypto_global_initialized_ = 0;
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 ENABLE_OPENSSL
crypto_openssl_early_init();
#endif
#ifdef ENABLE_NSS
crypto_nss_early_init(0);
#endif
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;
crypto_dh_init();
#ifdef ENABLE_OPENSSL
if (crypto_openssl_late_init(useAccel, accelName, accelDir) < 0)
return -1;
#else
(void)useAccel;
(void)accelName;
(void)accelDir;
#endif
#ifdef ENABLE_NSS
if (crypto_nss_late_init() < 0)
return -1;
#endif
}
return 0;
}
/** Free crypto resources held by this thread. */
void
crypto_thread_cleanup(void)
{
#ifdef ENABLE_OPENSSL
crypto_openssl_thread_cleanup();
#endif
}
/**
* Uninitialize the crypto library. Return 0 on success. Does not detect
* failure.
*/
int
crypto_global_cleanup(void)
{
crypto_dh_free_all();
#ifdef ENABLE_OPENSSL
crypto_openssl_global_cleanup();
#endif
#ifdef ENABLE_NSS
crypto_nss_global_cleanup();
#endif
crypto_early_initialized_ = 0;
crypto_global_initialized_ = 0;
have_seeded_siphash = 0;
siphash_unset_global_key();
return 0;
}
/** Run operations that the crypto library requires to be happy again
* after forking. */
void
crypto_prefork(void)
{
#ifdef ENABLE_NSS
crypto_nss_prefork();
#endif
}
/** Run operations that the crypto library requires to be happy again
* after forking. */
void
crypto_postfork(void)
{
#ifdef ENABLE_NSS
crypto_nss_postfork();
#endif
}
/** Return the name of the crypto library we're using. */
const char *
crypto_get_library_name(void)
{
#ifdef ENABLE_OPENSSL
return "OpenSSL";
#endif
#ifdef ENABLE_NSS
return "NSS";
#endif
}
/** Return the version of the crypto library we are using, as given in the
* library. */
const char *
crypto_get_library_version_string(void)
{
#ifdef ENABLE_OPENSSL
return crypto_openssl_get_version_str();
#endif
#ifdef ENABLE_NSS
return crypto_nss_get_version_str();
#endif
}
/** Return the version of the crypto library we're using, as given in the
* headers. */
const char *
crypto_get_header_version_string(void)
{
#ifdef ENABLE_OPENSSL
return crypto_openssl_get_header_version_str();
#endif
#ifdef ENABLE_NSS
return crypto_nss_get_header_version_str();
#endif
}
+34
View File
@@ -0,0 +1,34 @@
/* 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_init.h
*
* \brief Headers for crypto_init.c
**/
#ifndef TOR_CRYPTO_INIT_H
#define TOR_CRYPTO_INIT_H
#include "orconfig.h"
#include "lib/cc/compat_compiler.h"
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);
void crypto_prefork(void);
void crypto_postfork(void);
const char *crypto_get_library_name(void);
const char *crypto_get_library_version_string(void);
const char *crypto_get_header_version_string(void);
#endif /* !defined(TOR_CRYPTO_H) */
+132
View File
@@ -0,0 +1,132 @@
/* 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_nss_mgt.c
*
* \brief Manage the NSS library (if used)
**/
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/string/printf.h"
DISABLE_GCC_WARNING(strict-prototypes)
#include <nss.h>
#include <pk11func.h>
#include <ssl.h>
#include <prerror.h>
#include <prtypes.h>
#include <prinit.h>
ENABLE_GCC_WARNING(strict-prototypes)
const char *
crypto_nss_get_version_str(void)
{
return NSS_GetVersion();
}
const char *
crypto_nss_get_header_version_str(void)
{
return NSS_VERSION;
}
/** A password function that always returns NULL. */
static char *
nss_password_func_always_fail(PK11SlotInfo *slot,
PRBool retry,
void *arg)
{
(void) slot;
(void) retry;
(void) arg;
return NULL;
}
void
crypto_nss_early_init(int nss_only)
{
if (! nss_only) {
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
PK11_SetPasswordFunc(nss_password_func_always_fail);
}
/* Eventually we should use NSS_Init() instead -- but that wants a
directory. The documentation says that we can't use this if we want
to use OpenSSL. */
if (NSS_NoDB_Init(NULL) == SECFailure) {
log_err(LD_CRYPTO, "Unable to initialize NSS.");
crypto_nss_log_errors(LOG_ERR, "initializing NSS");
tor_assert_unreached();
}
if (NSS_SetDomesticPolicy() == SECFailure) {
log_err(LD_CRYPTO, "Unable to set NSS cipher policy.");
crypto_nss_log_errors(LOG_ERR, "setting cipher policy");
tor_assert_unreached();
}
/* We need to override the default here, or NSS will reject all the
* legacy Tor certificates. */
SECStatus rv = NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 1024);
if (rv != SECSuccess) {
log_err(LD_CRYPTO, "Unable to set NSS min RSA key size");
crypto_nss_log_errors(LOG_ERR, "setting cipher option.");
tor_assert_unreached();
}
}
void
crypto_nss_log_errors(int severity, const char *doing)
{
PRErrorCode code = PR_GetError();
const char *string = PORT_ErrorToString(code);
const char *name = PORT_ErrorToName(code);
char buf[16];
if (!string)
string = "<unrecognized>";
if (!name) {
tor_snprintf(buf, sizeof(buf), "%d", code);
name = buf;
}
if (doing) {
tor_log(severity, LD_CRYPTO, "NSS error %s while %s: %s",
name, doing, string);
} else {
tor_log(severity, LD_CRYPTO, "NSS error %s: %s", name, string);
}
}
int
crypto_nss_late_init(void)
{
/* Possibly, SSL_OptionSetDefault? */
return 0;
}
void
crypto_nss_global_cleanup(void)
{
NSS_Shutdown();
PL_ArenaFinish();
PR_Cleanup();
}
void
crypto_nss_prefork(void)
{
NSS_Shutdown();
}
void
crypto_nss_postfork(void)
{
crypto_nss_early_init(1);
}
+34
View File
@@ -0,0 +1,34 @@
/* 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_nss_mgt.h
*
* \brief Headers for crypto_nss_mgt.c
**/
#ifndef TOR_CRYPTO_NSS_MGT_H
#define TOR_CRYPTO_NSS_MGT_H
#include "orconfig.h"
#ifdef ENABLE_NSS
/* global nss state */
const char *crypto_nss_get_version_str(void);
const char *crypto_nss_get_header_version_str(void);
void crypto_nss_log_errors(int severity, const char *doing);
void crypto_nss_early_init(int nss_only);
int crypto_nss_late_init(void);
void crypto_nss_global_cleanup(void);
void crypto_nss_prefork(void);
void crypto_nss_postfork(void);
#endif
#endif /* !defined(TOR_CRYPTO_NSS_H) */
+1 -1
View File
@@ -18,8 +18,8 @@
#define CRYPTO_OPE_PRIVATE
#include "lib/crypt_ops/crypto_ope.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/log/util_bug.h"
#include "lib/malloc/malloc.h"
#include "lib/arch/bytes.h"
+226 -2
View File
@@ -12,8 +12,12 @@
#include "lib/crypt_ops/compat_openssl.h"
#include "lib/crypt_ops/crypto_openssl_mgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/aes.h"
#include "lib/string/util_string.h"
#include "lib/lock/compat_mutex.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/testsupport/testsupport.h"
#include "lib/thread/threads.h"
@@ -30,6 +34,7 @@ DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/conf.h>
#include <openssl/hmac.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
ENABLE_GCC_WARNING(redundant-decls)
@@ -49,6 +54,27 @@ 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
/** Log all pending crypto errors at level <b>severity</b>. Use
* <b>doing</b> to describe our current activities.
*/
void
crypto_openssl_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);
}
}
/* 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' */
@@ -127,7 +153,7 @@ tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
* multithreaded. Returns 0. */
int
static int
setup_openssl_threading(void)
{
#ifndef NEW_THREAD_API
@@ -144,7 +170,7 @@ setup_openssl_threading(void)
}
/** free OpenSSL variables */
void
static void
crypto_openssl_free_all(void)
{
tor_free(crypto_openssl_version_str);
@@ -164,3 +190,201 @@ crypto_openssl_free_all(void)
}
#endif /* !defined(NEW_THREAD_API) */
}
/** Perform early (pre-configuration) initialization tasks for OpenSSL. */
void
crypto_openssl_early_init(void)
{
#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();
}
#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) */
#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) */
/** Initialize engines for openssl (if enabled). */
static void
crypto_openssl_init_engines(const char *accelName,
const char *accelDir)
{
#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) */
}
/** Perform late (post-init) initialization tasks for OpenSSL */
int
crypto_openssl_late_init(int useAccel, const char *accelName,
const char *accelDir)
{
if (useAccel > 0) {
crypto_openssl_init_engines(accelName, accelDir);
} 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_openssl_thread_cleanup(void)
{
#ifndef NEW_THREAD_API
ERR_remove_thread_state(NULL);
#endif
}
/** Clean up global resources held by openssl. */
void
crypto_openssl_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
#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();
}
+11 -4
View File
@@ -14,6 +14,8 @@
#define TOR_CRYPTO_OPENSSL_H
#include "orconfig.h"
#ifdef ENABLE_OPENSSL
#include <openssl/engine.h>
/*
@@ -69,14 +71,19 @@
#define NEW_THREAD_API
#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */
void crypto_openssl_log_errors(int severity, const char *doing);
/* 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);
void crypto_openssl_early_init(void);
int crypto_openssl_late_init(int useAccel, const char *accelName,
const char *accelDir);
/* Tor OpenSSL utility functions */
void crypto_openssl_free_all(void);
void crypto_openssl_thread_cleanup(void);
void crypto_openssl_global_cleanup(void);
#endif /* ENABLE_OPENSSL */
#endif /* !defined(TOR_CRYPTO_OPENSSL_H) */
+1 -1
View File
@@ -11,7 +11,7 @@
#include <string.h>
#include "lib/arch/bytes.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_pwbox.h"
#include "lib/crypt_ops/crypto_rand.h"
+111 -11
View File
@@ -35,9 +35,24 @@
#include "lib/testsupport/testsupport.h"
#include "lib/fs/files.h"
#include "lib/defs/digest_sizes.h"
#include "lib/crypt_ops/crypto_digest.h"
#ifdef ENABLE_NSS
#include "lib/crypt_ops/crypto_nss_mgt.h"
#endif
#ifdef ENABLE_OPENSSL
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/rand.h>
ENABLE_GCC_WARNING(redundant-decls)
#endif
#ifdef ENABLE_NSS
#include <pk11pub.h>
#include <secerr.h>
#include <prerror.h>
#endif
#if __GNUC__ && GCC_VERSION >= 402
#if GCC_VERSION >= 406
@@ -67,6 +82,7 @@ ENABLE_GCC_WARNING(redundant-decls)
#endif
#include <string.h>
#include <errno.h>
/**
* How many bytes of entropy we add at once.
@@ -322,16 +338,24 @@ crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
void
crypto_strongest_rand(uint8_t *out, size_t out_len)
{
#define DLEN SHA512_DIGEST_LENGTH
#define DLEN DIGEST512_LEN
/* 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.
* bytes from the PRNGs from our crypto librar(y/ies), in order to yield
* DLEN bytes.
*/
uint8_t inp[DLEN*2];
uint8_t inp[DLEN*3];
uint8_t tmp[DLEN];
tor_assert(out);
while (out_len) {
crypto_rand((char*) inp, DLEN);
if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) {
memset(inp, 0, sizeof(inp));
#ifdef ENABLE_OPENSSL
RAND_bytes(inp, DLEN);
#endif
#ifdef ENABLE_NSS
PK11_GenerateRandom(inp+DLEN, DLEN);
#endif
if (crypto_strongest_rand_raw(inp+DLEN*2, DLEN) < 0) {
// LCOV_EXCL_START
log_err(LD_CRYPTO, "Failed to load strong entropy when generating an "
"important key. Exiting.");
@@ -340,11 +364,11 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
// LCOV_EXCL_STOP
}
if (out_len >= DLEN) {
SHA512(inp, sizeof(inp), out);
crypto_digest512((char*)out, (char*)inp, sizeof(inp), DIGEST_SHA512);
out += DLEN;
out_len -= DLEN;
} else {
SHA512(inp, sizeof(inp), tmp);
crypto_digest512((char*)tmp, (char*)inp, sizeof(inp), DIGEST_SHA512);
memcpy(out, tmp, out_len);
break;
}
@@ -354,12 +378,13 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
#undef DLEN
}
#ifdef ENABLE_OPENSSL
/**
* Seed OpenSSL's random number generator with bytes from the operating
* system. Return 0 on success, -1 on failure.
**/
int
crypto_seed_rng(void)
static int
crypto_seed_openssl_rng(void)
{
int rand_poll_ok = 0, load_entropy_ok = 0;
uint8_t buf[ADD_ENTROPY];
@@ -383,6 +408,52 @@ crypto_seed_rng(void)
else
return -1;
}
#endif
#ifdef ENABLE_NSS
/**
* Seed OpenSSL's random number generator with bytes from the operating
* system. Return 0 on success, -1 on failure.
**/
static int
crypto_seed_nss_rng(void)
{
uint8_t buf[ADD_ENTROPY];
int load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf));
if (load_entropy_ok) {
if (PK11_RandomUpdate(buf, sizeof(buf)) != SECSuccess) {
load_entropy_ok = 0;
}
}
memwipe(buf, 0, sizeof(buf));
return load_entropy_ok ? 0 : -1;
}
#endif
/**
* Seed the RNG for any and all crypto libraries that we're using with bytes
* from the operating system. Return 0 on success, -1 on failure.
*/
int
crypto_seed_rng(void)
{
int seeded = 0;
#ifdef ENABLE_NSS
if (crypto_seed_nss_rng() < 0)
return -1;
++seeded;
#endif
#ifdef ENABLE_OPENSSL
if (crypto_seed_openssl_rng() < 0)
return -1;
++seeded;
#endif
tor_assert(seeded);
return 0;
}
/**
* Write <b>n</b> bytes of strong random data to <b>to</b>. Supports mocking
@@ -407,17 +478,44 @@ crypto_rand, (char *to, size_t n))
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);
#ifdef ENABLE_NSS
SECStatus s = PK11_GenerateRandom((unsigned char*)to, (int)n);
if (s != SECSuccess) {
/* NSS rather sensibly might refuse to generate huge amounts of random
* data at once. Unfortunately, our unit test do this in a couple of
* places. To solve this issue, we use our XOF to stretch a shorter
* output when a longer one is needed.
*
* Yes, this is secure. */
/* This is longer than it needs to be; 1600 bits == 200 bytes is the
* state-size of SHA3. */
#define BUFLEN 512
tor_assert(PR_GetError() == SEC_ERROR_INVALID_ARGS && n > BUFLEN);
unsigned char buf[BUFLEN];
s = PK11_GenerateRandom(buf, BUFLEN);
tor_assert(s == SECSuccess);
crypto_xof_t *xof = crypto_xof_new();
crypto_xof_add_bytes(xof, buf, BUFLEN);
crypto_xof_squeeze_bytes(xof, (unsigned char *)to, n);
crypto_xof_free(xof);
memwipe(buf, 0, BUFLEN);
#undef BUFLEN
}
#else
int 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);
#endif
}
/**
@@ -605,6 +703,7 @@ smartlist_shuffle(smartlist_t *sl)
int
crypto_force_rand_ssleay(void)
{
#ifdef ENABLE_OPENSSL
RAND_METHOD *default_method;
default_method = RAND_OpenSSL();
if (RAND_get_rand_method() != default_method) {
@@ -614,6 +713,7 @@ crypto_force_rand_ssleay(void)
RAND_set_rand_method(default_method);
return 1;
}
#endif
return 0;
}
File diff suppressed because it is too large Load Diff
+39 -9
View File
@@ -29,6 +29,13 @@
/** Number of bytes added for PKCS1-OAEP padding. */
#define PKCS1_OAEP_PADDING_OVERHEAD 42
/** Length of encoded public key fingerprints, including space; but not
* including terminating NUL. */
#define FINGERPRINT_LEN 49
/** Value of 'e' to use in our public keys */
#define TOR_RSA_EXPONENT 65537
/** A public key, or a public/private key-pair. */
typedef struct crypto_pk_t crypto_pk_t;
@@ -57,7 +64,7 @@ int crypto_pk_read_private_key_from_string(crypto_pk_t *env,
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_is_valid_private_key(const 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);
@@ -65,7 +72,7 @@ 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_public_exponent_ok(const 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,
@@ -86,8 +93,12 @@ 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_asn1_encode_private(const crypto_pk_t *pk,
char *dest, size_t dest_len);
crypto_pk_t *crypto_pk_asn1_decode_private(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);
void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in);
MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env,
const char *data, size_t datalen, const char *sig, size_t siglen));
@@ -96,20 +107,39 @@ int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
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);
int crypto_pk_base64_encode_private(const crypto_pk_t *pk, char **priv_out);
crypto_pk_t *crypto_pk_base64_decode_private(const char *str, size_t len);
#ifdef ENABLE_OPENSSL
/* 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;
struct rsa_st *crypto_pk_get_openssl_rsa_(crypto_pk_t *env);
crypto_pk_t *crypto_new_pk_from_openssl_rsa_(struct rsa_st *rsa);
MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_openssl_evp_pkey_,(
crypto_pk_t *env,int private));
#endif
#ifdef ENABLE_NSS
struct SECKEYPublicKeyStr;
struct SECKEYPrivateKeyStr;
crypto_pk_t *crypto_pk_new_from_nss_pubkey(struct SECKEYPublicKeyStr *pub);
const struct SECKEYPublicKeyStr *crypto_pk_get_nss_pubkey(
const crypto_pk_t *key);
const struct SECKEYPrivateKeyStr *crypto_pk_get_nss_privkey(
const crypto_pk_t *key);
#endif
void crypto_pk_assign_public(crypto_pk_t *dest, const crypto_pk_t *src);
void crypto_pk_assign_private(crypto_pk_t *dest, const crypto_pk_t *src);
#ifdef TOR_UNIT_TESTS
void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src);
#ifdef ENABLE_NSS
struct SECItemStr;
STATIC int secitem_uint_cmp(const struct SECItemStr *a,
const struct SECItemStr *b);
#endif
#endif
#endif
+738
View File
@@ -0,0 +1,738 @@
/* 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 NSS implementations of our RSA code.
**/
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/ctime/di_ops.h"
#include "lib/encoding/binascii.h"
#include "lib/fs/files.h"
#include "lib/intmath/cmp.h"
#include "lib/intmath/muldiv.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include <string.h>
#include <keyhi.h>
#include <pk11pub.h>
#include <secder.h>
#ifdef ENABLE_OPENSSL
#include <openssl/rsa.h>
#include <openssl/evp.h>
#endif
/** Declaration for crypto_pk_t structure. */
struct crypto_pk_t
{
SECKEYPrivateKey *seckey;
SECKEYPublicKey *pubkey;
};
/** 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)
{
return key && key->seckey;
}
/** used by tortls.c: wrap a SecKEYPublicKey in a crypto_pk_t. Take ownership
* of the RSA object. */
crypto_pk_t *
crypto_pk_new_from_nss_pubkey(struct SECKEYPublicKeyStr *pub)
{
crypto_pk_t *result = tor_malloc_zero(sizeof(crypto_pk_t));
result->pubkey = pub;
return result;
}
/** Return the SECKEYPublicKey for the provided crypto_pk_t. */
const SECKEYPublicKey *
crypto_pk_get_nss_pubkey(const crypto_pk_t *key)
{
tor_assert(key);
return key->pubkey;
}
/** Return the SECKEYPrivateKey for the provided crypto_pk_t, or NULL if it
* does not exist. */
const SECKEYPrivateKey *
crypto_pk_get_nss_privkey(const crypto_pk_t *key)
{
tor_assert(key);
return key->seckey;
}
#ifdef ENABLE_OPENSSL
/** used by tortls.c: wrap an RSA* in a crypto_pk_t. Take ownership of the
* RSA object. */
crypto_pk_t *
crypto_new_pk_from_openssl_rsa_(RSA *rsa)
{
crypto_pk_t *pk = NULL;
unsigned char *buf = NULL;
int len = i2d_RSAPublicKey(rsa, &buf);
RSA_free(rsa);
if (len < 0 || buf == NULL)
goto end;
pk = crypto_pk_asn1_decode((const char *)buf, len);
end:
if (buf)
OPENSSL_free(buf);
return pk;
}
/** Helper, used by tor-gencert.c. Return the RSA from a
* crypto_pk_t. */
struct rsa_st *
crypto_pk_get_openssl_rsa_(crypto_pk_t *pk)
{
size_t buflen = crypto_pk_keysize(pk)*16;
unsigned char *buf = tor_malloc_zero(buflen);
const unsigned char *cp = buf;
RSA *rsa = NULL;
int used = crypto_pk_asn1_encode_private(pk, (char*)buf, buflen);
if (used < 0)
goto end;
rsa = d2i_RSAPrivateKey(NULL, &cp, used);
end:
memwipe(buf, 0, buflen);
tor_free(buf);
return rsa;
}
/** 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(struct evp_pkey_st *,
crypto_pk_get_openssl_evp_pkey_,(crypto_pk_t *pk, int private))
{
size_t buflen = crypto_pk_keysize(pk)*16;
unsigned char *buf = tor_malloc_zero(buflen);
const unsigned char *cp = buf;
RSA *rsa = NULL;
EVP_PKEY *result = NULL;
if (private) {
int len = crypto_pk_asn1_encode_private(pk, (char*)buf, buflen);
if (len < 0)
goto end;
rsa = d2i_RSAPrivateKey(NULL, &cp, len);
} else {
int len = crypto_pk_asn1_encode(pk, (char*)buf, buflen);
if (len < 0)
goto end;
rsa = d2i_RSAPublicKey(NULL, &cp, len);
}
if (!rsa)
goto end;
if (!(result = EVP_PKEY_new()))
goto end;
if (!(EVP_PKEY_assign_RSA(result, rsa))) {
EVP_PKEY_free(result);
RSA_free(rsa);
result = NULL;
}
end:
memwipe(buf, 0, buflen);
tor_free(buf);
return result;
}
#endif
/** 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))
{
crypto_pk_t *result = tor_malloc_zero(sizeof(crypto_pk_t));
return result;
}
/** Release the NSS objects held in <b>key</b> */
static void
crypto_pk_clear(crypto_pk_t *key)
{
if (key->pubkey)
SECKEY_DestroyPublicKey(key->pubkey);
if (key->seckey)
SECKEY_DestroyPrivateKey(key->seckey);
memset(key, 0, sizeof(crypto_pk_t));
}
/** Release a reference to an asymmetric key; when all the references
* are released, free the key.
*/
void
crypto_pk_free_(crypto_pk_t *key)
{
if (!key)
return;
crypto_pk_clear(key);
tor_free(key);
}
/** 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 *key, int bits))
{
tor_assert(key);
PK11RSAGenParams params = {
.keySizeInBits = bits,
.pe = TOR_RSA_EXPONENT
};
int result = -1;
PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, NULL);
SECKEYPrivateKey *seckey = NULL;
SECKEYPublicKey *pubkey = NULL;
if (!slot) {
crypto_nss_log_errors(LOG_WARN, "getting slot for RSA keygen");
goto done;
}
seckey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &params,
&pubkey,
PR_FALSE /*isPerm */,
PR_FALSE /*isSensitive*/,
NULL);
if (seckey == NULL || pubkey == NULL) {
crypto_nss_log_errors(LOG_WARN, "generating an RSA key");
goto done;
}
crypto_pk_clear(key);
key->seckey = seckey;
key->pubkey = pubkey;
seckey = NULL;
pubkey = NULL;
result = 0;
done:
if (slot)
PK11_FreeSlot(slot);
if (pubkey)
SECKEY_DestroyPublicKey(pubkey);
if (seckey)
SECKEY_DestroyPrivateKey(seckey);
return result;
}
/** Return true iff <b>env</b> is a valid private key.
*/
int
crypto_pk_is_valid_private_key(const crypto_pk_t *key)
{
/* We don't need to do validation here, since unlike OpenSSL, NSS won't let
* us load private keys without validating them. */
return key && key->seckey;
}
/** Return true iff <b>env</b> contains a public key whose public exponent
* equals 65537.
*/
int
crypto_pk_public_exponent_ok(const crypto_pk_t *key)
{
return key &&
key->pubkey &&
key->pubkey->keyType == rsaKey &&
DER_GetUInteger(&key->pubkey->u.rsa.publicExponent) == TOR_RSA_EXPONENT;
}
/** Compare two big-endian integers stored in a and b; return a tristate.
*/
STATIC int
secitem_uint_cmp(const SECItem *a, const SECItem *b)
{
const unsigned abits = SECKEY_BigIntegerBitLength(a);
const unsigned bbits = SECKEY_BigIntegerBitLength(b);
if (abits < bbits)
return -1;
else if (abits > bbits)
return 1;
/* okay, they have the same number of bits set. Get a pair of aligned
* pointers to their bytes that are set... */
const unsigned nbytes = CEIL_DIV(abits, 8);
tor_assert(nbytes <= a->len);
tor_assert(nbytes <= b->len);
const unsigned char *aptr = a->data + (a->len - nbytes);
const unsigned char *bptr = b->data + (b->len - nbytes);
/* And compare them. */
return fast_memcmp(aptr, bptr, nbytes);
}
/** 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->pubkey != NULL);
char b_is_non_null = (b != NULL) && (b->pubkey != 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;
// This is all Tor uses with this structure.
tor_assert(a->pubkey->keyType == rsaKey);
tor_assert(b->pubkey->keyType == rsaKey);
const SECItem *a_n, *a_e, *b_n, *b_e;
a_n = &a->pubkey->u.rsa.modulus;
b_n = &b->pubkey->u.rsa.modulus;
a_e = &a->pubkey->u.rsa.publicExponent;
b_e = &b->pubkey->u.rsa.publicExponent;
result = secitem_uint_cmp(a_n, b_n);
if (result)
return result;
return secitem_uint_cmp(a_e, b_e);
}
/** Return the size of the public key modulus in <b>env</b>, in bytes. */
size_t
crypto_pk_keysize(const crypto_pk_t *key)
{
tor_assert(key);
tor_assert(key->pubkey);
return SECKEY_PublicKeyStrength(key->pubkey);
}
/** Return the size of the public key modulus of <b>env</b>, in bits. */
int
crypto_pk_num_bits(crypto_pk_t *key)
{
tor_assert(key);
tor_assert(key->pubkey);
return SECKEY_PublicKeyStrengthInBits(key->pubkey);
}
/**
* Make a copy of <b>key</b> and return it.
*/
crypto_pk_t *
crypto_pk_dup_key(crypto_pk_t *key)
{
crypto_pk_t *result = crypto_pk_new();
if (key->pubkey)
result->pubkey = SECKEY_CopyPublicKey(key->pubkey);
if (key->seckey)
result->seckey = SECKEY_CopyPrivateKey(key->seckey);
return result;
}
/** For testing: replace dest with src. (Dest must have a refcount
* of 1) */
void
crypto_pk_assign_public(crypto_pk_t *dest, const crypto_pk_t *src)
{
crypto_pk_clear(dest);
if (src->pubkey)
dest->pubkey = SECKEY_CopyPublicKey(src->pubkey);
}
/** For testing: replace dest with src. (Dest must have a refcount
* of 1) */
void
crypto_pk_assign_private(crypto_pk_t *dest, const crypto_pk_t *src)
{
crypto_pk_clear(dest);
if (src->pubkey)
dest->pubkey = SECKEY_CopyPublicKey(src->pubkey);
if (src->seckey)
dest->seckey = SECKEY_CopyPrivateKey(src->seckey);
}
/** 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 *key)
{
// These aren't reference-counted is nss, so it's fine to just
// use the same function.
return crypto_pk_dup_key(key);
}
static const CK_RSA_PKCS_OAEP_PARAMS oaep_params = {
.hashAlg = CKM_SHA_1,
.mgf = CKG_MGF1_SHA1,
.source = CKZ_DATA_SPECIFIED,
.pSourceData = NULL,
.ulSourceDataLen = 0
};
static const SECItem oaep_item = {
.type = siBuffer,
.data = (unsigned char *) &oaep_params,
.len = sizeof(oaep_params)
};
/** Return the mechanism code and parameters for a given padding method when
* used with RSA */
static CK_MECHANISM_TYPE
padding_to_mechanism(int padding, SECItem **item_out)
{
switch (padding) {
case PK_PKCS1_OAEP_PADDING:
*item_out = (SECItem *)&oaep_item;
return CKM_RSA_PKCS_OAEP;
default:
tor_assert_unreached();
*item_out = NULL;
return CKM_INVALID_MECHANISM;
}
}
/** 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)
{
tor_assert(env);
tor_assert(to);
tor_assert(from);
tor_assert(tolen < INT_MAX);
tor_assert(fromlen < INT_MAX);
if (BUG(! env->pubkey))
return -1;
unsigned int result_len = 0;
SECItem *item = NULL;
CK_MECHANISM_TYPE m = padding_to_mechanism(padding, &item);
SECStatus s = PK11_PubEncrypt(env->pubkey, m, item,
(unsigned char *)to, &result_len,
(unsigned int)tolen,
(const unsigned char *)from,
(unsigned int)fromlen,
NULL);
if (s != SECSuccess) {
crypto_nss_log_errors(LOG_WARN, "encrypting to an RSA key");
return -1;
}
return (int)result_len;
}
/** 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>key</b>.
*/
int
crypto_pk_private_decrypt(crypto_pk_t *key, char *to,
size_t tolen,
const char *from, size_t fromlen,
int padding, int warnOnFailure)
{
tor_assert(key);
tor_assert(to);
tor_assert(from);
tor_assert(tolen < INT_MAX);
tor_assert(fromlen < INT_MAX);
if (!crypto_pk_key_is_private(key))
return -1; /* Not a private key. */
unsigned int result_len = 0;
SECItem *item = NULL;
CK_MECHANISM_TYPE m = padding_to_mechanism(padding, &item);
SECStatus s = PK11_PrivDecrypt(key->seckey, m, item,
(unsigned char *)to, &result_len,
(unsigned int)tolen,
(const unsigned char *)from,
(unsigned int)fromlen);
if (s != SECSuccess) {
const int severity = warnOnFailure ? LOG_WARN : LOG_INFO;
crypto_nss_log_errors(severity, "decrypting with an RSA key");
return -1;
}
return (int)result_len;
}
/** Check the signature in <b>from</b> (<b>fromlen</b> bytes long) with the
* public key in <b>key</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>key</b>.
*/
MOCK_IMPL(int,
crypto_pk_public_checksig,(const crypto_pk_t *key, char *to,
size_t tolen,
const char *from, size_t fromlen))
{
tor_assert(key);
tor_assert(to);
tor_assert(from);
tor_assert(tolen < INT_MAX);
tor_assert(fromlen < INT_MAX);
tor_assert(key->pubkey);
SECItem sig = {
.type = siBuffer,
.data = (unsigned char *) from,
.len = (unsigned int) fromlen,
};
SECItem dsig = {
.type = siBuffer,
.data = (unsigned char *) to,
.len = (unsigned int) tolen
};
SECStatus s;
s = PK11_VerifyRecover(key->pubkey, &sig, &dsig, NULL);
if (s != SECSuccess)
return -1;
return (int)dsig.len;
}
/** 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 *key, char *to, size_t tolen,
const char *from, size_t fromlen)
{
tor_assert(key);
tor_assert(to);
tor_assert(from);
tor_assert(tolen < INT_MAX);
tor_assert(fromlen < INT_MAX);
if (BUG(!crypto_pk_key_is_private(key)))
return -1;
SECItem sig = {
.type = siBuffer,
.data = (unsigned char *)to,
.len = (unsigned int) tolen
};
SECItem hash = {
.type = siBuffer,
.data = (unsigned char *)from,
.len = (unsigned int) fromlen
};
CK_MECHANISM_TYPE m = CKM_RSA_PKCS;
SECStatus s = PK11_SignWithMechanism(key->seckey, m, NULL,
&sig, &hash);
if (s != SECSuccess) {
crypto_nss_log_errors(LOG_WARN, "signing with an RSA key");
return -1;
}
return (int)sig.len;
}
/* "This has lead to people trading hard-to-find object identifiers and ASN.1
* definitions like baseball cards" - Peter Gutmann, "X.509 Style Guide". */
static const unsigned char RSA_OID[] = {
/* RSADSI */ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
/* PKCS1 */ 0x01, 0x01,
/* RSA */ 0x01
};
/** 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)
{
tor_assert(pk);
if (pk->pubkey == NULL)
return -1;
CERTSubjectPublicKeyInfo *info;
info = SECKEY_CreateSubjectPublicKeyInfo(pk->pubkey);
if (! info)
return -1;
const SECItem *item = &info->subjectPublicKey;
size_t actual_len = (item->len) >> 3; /* bits to bytes */
size_t n_used = MIN(actual_len, dest_len);
memcpy(dest, item->data, n_used);
SECKEY_DestroySubjectPublicKeyInfo(info);
return (int) n_used;
}
/** 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)
{
tor_assert(str);
if (len >= INT_MAX)
return NULL;
CERTSubjectPublicKeyInfo info = {
.algorithm = {
.algorithm = {
.type = siDEROID,
.data = (unsigned char *)RSA_OID,
.len = sizeof(RSA_OID)
}
},
.subjectPublicKey = {
.type = siBuffer,
.data = (unsigned char *)str,
.len = (unsigned int)(len << 3) /* bytes to bits */
}
};
SECKEYPublicKey *pub = SECKEY_ExtractPublicKey(&info);
if (pub == NULL)
return NULL;
crypto_pk_t *result = crypto_pk_new();
result->pubkey = pub;
return result;
}
DISABLE_GCC_WARNING(unused-parameter)
/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the Base64
* encoding of the DER representation of the private key into the
* <b>dest_len</b>-byte buffer in <b>dest</b>.
* Return the number of bytes written on success, -1 on failure.
*/
int
crypto_pk_asn1_encode_private(const crypto_pk_t *pk,
char *dest, size_t destlen)
{
tor_assert(destlen <= INT_MAX);
if (!crypto_pk_key_is_private(pk))
return -1;
SECKEYPrivateKeyInfo *info = PK11_ExportPrivKeyInfo(pk->seckey, NULL);
if (!info)
return -1;
SECItem *item = &info->privateKey;
if (destlen < item->len) {
SECKEY_DestroyPrivateKeyInfo(info, PR_TRUE);
return -1;
}
int result = (int)item->len;
memcpy(dest, item->data, item->len);
SECKEY_DestroyPrivateKeyInfo(info, PR_TRUE);
return result;
}
/** Given a buffer containing the 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_asn1_decode_private(const char *str, size_t len)
{
tor_assert(str);
tor_assert(len < INT_MAX);
PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS, NULL);
if (!slot)
return NULL;
SECKEYPrivateKeyInfo info = {
.algorithm = {
.algorithm = {
.type = siBuffer,
.data = (unsigned char *)RSA_OID,
.len = sizeof(RSA_OID)
}
},
.privateKey = {
.type = siBuffer,
.data = (unsigned char *)str,
.len = (int)len,
}
};
SECStatus s;
SECKEYPrivateKey *seckey = NULL;
s = PK11_ImportPrivateKeyInfoAndReturnKey(slot, &info,
NULL /* nickname */,
NULL /* publicValue */,
PR_FALSE /* isPerm */,
PR_FALSE /* isPrivate */,
KU_ALL /* keyUsage */,
&seckey, NULL);
crypto_pk_t *output = NULL;
if (s == SECSuccess && seckey) {
output = crypto_pk_new();
output->seckey = seckey;
output->pubkey = SECKEY_ConvertToPublicKey(seckey);
tor_assert(output->pubkey);
} else {
crypto_nss_log_errors(LOG_WARN, "decoding an RSA private key");
}
if (! crypto_pk_is_valid_private_key(output)) {
crypto_pk_free(output);
output = NULL;
}
if (slot)
PK11_FreeSlot(slot);
return output;
}
+590
View File
@@ -0,0 +1,590 @@
/* 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 OpenSSL implementations of our RSA code.
**/
#include "lib/crypt_ops/compat_openssl.h"
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/ctime/di_ops.h"
#include "lib/log/util_bug.h"
#include "lib/fs/files.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/conf.h>
ENABLE_GCC_WARNING(redundant-decls)
#include "lib/log/log.h"
#include "lib/encoding/binascii.h"
#include <string.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 true iff <b>key</b> contains the private-key portion of the RSA
* key. */
int
crypto_pk_key_is_private(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. Takes ownership of
* its argument. */
crypto_pk_t *
crypto_new_pk_from_openssl_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 a copy of the private RSA from a
* crypto_pk_t. */
RSA *
crypto_pk_get_openssl_rsa_(crypto_pk_t *env)
{
return RSAPrivateKey_dup(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_openssl_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_openssl_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, TOR_RSA_EXPONENT))
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_openssl_log_errors(LOG_WARN, "generating RSA key");
return -1;
}
return 0;
}
/** Return true if <b>env</b> has a valid key; false otherwise.
*/
int
crypto_pk_is_valid_private_key(const crypto_pk_t *env)
{
int r;
tor_assert(env);
r = RSA_check_key(env->key);
if (r <= 0) {
crypto_openssl_log_errors(LOG_WARN,"checking RSA key");
return 0;
} else {
return 1;
}
}
/** Return true iff <b>env</b> contains a public key whose public exponent
* equals TOR_RSA_EXPONENT.
*/
int
crypto_pk_public_exponent_ok(const 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, TOR_RSA_EXPONENT);
}
/** 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);
}
/** 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;
}
/** Replace dest with src (private key only). (Dest must have a refcount
* of 1)
*/
void
crypto_pk_assign_private(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);
}
/** Replace dest with src (public key only). (Dest must have a refcount
* of 1)
*/
void
crypto_pk_assign_public(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 = RSAPublicKey_dup(src->key);
}
/** 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_key_is_private(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_openssl_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_openssl_rsa_(new_key);
}
/** 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_openssl_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_openssl_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_openssl_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_openssl_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_openssl_log_errors(LOG_WARN,"decoding public key");
return NULL;
}
return crypto_new_pk_from_openssl_rsa_(rsa);
}
/** ASN.1-encode the private 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_private(const crypto_pk_t *pk, char *dest,
size_t dest_len)
{
int len;
unsigned char *buf = NULL;
len = i2d_RSAPrivateKey(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 private key from <b>str</b>; return the result on
* success and NULL on failure.
*/
crypto_pk_t *
crypto_pk_asn1_decode_private(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_RSAPrivateKey(NULL, &cp, len);
tor_free(buf);
if (!rsa) {
crypto_openssl_log_errors(LOG_WARN,"decoding public key");
return NULL;
}
crypto_pk_t *result = crypto_new_pk_from_openssl_rsa_(rsa);
if (! crypto_pk_is_valid_private_key(result)) {
crypto_pk_free(result);
return NULL;
}
return result;
}
+49 -1
View File
@@ -12,7 +12,7 @@
#define CRYPTO_S2K_PRIVATE
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_digest.h"
#include "lib/crypt_ops/crypto_hkdf.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -20,8 +20,14 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/ctime/di_ops.h"
#include "lib/log/util_bug.h"
#include "lib/intmath/cmp.h"
#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
#endif
#ifdef ENABLE_NSS
#include <pk11pub.h>
#endif
#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT)
#define HAVE_SCRYPT
@@ -271,6 +277,7 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
log_iters = spec[spec_len-1];
if (log_iters > 31)
return S2K_BAD_PARAMS;
#ifdef ENABLE_OPENSSL
rv = PKCS5_PBKDF2_HMAC_SHA1(secret, (int)secret_len,
spec, (int)spec_len-1,
(1<<log_iters),
@@ -278,6 +285,47 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
if (rv < 0)
return S2K_FAILED;
return (int)key_out_len;
#else
SECItem passItem = { .type = siBuffer,
.data = (unsigned char *) secret,
.len = (int)secret_len };
SECItem saltItem = { .type = siBuffer,
.data = (unsigned char *) spec,
.len = (int)spec_len - 1 };
SECAlgorithmID *alg = NULL;
PK11SymKey *key = NULL;
rv = S2K_FAILED;
alg = PK11_CreatePBEV2AlgorithmID(
SEC_OID_PKCS5_PBKDF2, SEC_OID_HMAC_SHA1, SEC_OID_HMAC_SHA1,
(int)key_out_len, (1<<log_iters), &saltItem);
if (alg == NULL)
return S2K_FAILED;
key = PK11_PBEKeyGen(NULL /* slot */,
alg,
&passItem,
false,
NULL);
SECStatus st = PK11_ExtractKeyValue(key);
if (st != SECSuccess)
goto nss_pbkdf_err;
const SECItem *iptr = PK11_GetKeyData(key);
if (iptr == NULL)
goto nss_pbkdf_err;
rv = MIN((int)iptr->len, (int)key_out_len);
memcpy(key_out, iptr->data, rv);
nss_pbkdf_err:
if (key)
PK11_FreeSymKey(key);
if (alg)
SECOID_DestroyAlgorithmID(alg, PR_TRUE);
return rv;
#endif
}
case S2K_TYPE_SCRYPT: {
+4 -25
View File
@@ -10,7 +10,6 @@
* \brief Common cryptographic utilities.
**/
#ifndef CRYPTO_UTIL_PRIVATE
#define CRYPTO_UTIL_PRIVATE
#include "lib/crypt_ops/crypto_util.h"
@@ -24,12 +23,14 @@
#include <wincrypt.h>
#endif /* defined(_WIN32) */
DISABLE_GCC_WARNING(redundant-decls)
#include <stdlib.h>
#ifdef ENABLE_OPENSSL
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
#include <openssl/crypto.h>
ENABLE_GCC_WARNING(redundant-decls)
#endif
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
@@ -105,25 +106,3 @@ memwipe(void *mem, uint8_t byte, size_t sz)
**/
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) */
-9
View File
@@ -18,13 +18,4 @@
/** 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) */
+27 -5
View File
@@ -6,16 +6,15 @@ noinst_LIBRARIES += src/lib/libtor-crypt-ops-testing.a
endif
src_lib_libtor_crypt_ops_a_SOURCES = \
src/lib/crypt_ops/aes.c \
src/lib/crypt_ops/crypto.c \
src/lib/crypt_ops/crypto_cipher.c \
src/lib/crypt_ops/crypto_curve25519.c \
src/lib/crypt_ops/crypto_dh.c \
src/lib/crypt_ops/crypto_digest.c \
src/lib/crypt_ops/crypto_ed25519.c \
src/lib/crypt_ops/crypto_format.c \
src/lib/crypt_ops/crypto_hkdf.c \
src/lib/crypt_ops/crypto_init.c \
src/lib/crypt_ops/crypto_ope.c \
src/lib/crypt_ops/crypto_openssl_mgt.c \
src/lib/crypt_ops/crypto_pwbox.c \
src/lib/crypt_ops/crypto_rand.c \
src/lib/crypt_ops/crypto_rsa.c \
@@ -23,10 +22,31 @@ src_lib_libtor_crypt_ops_a_SOURCES = \
src/lib/crypt_ops/crypto_util.c \
src/lib/crypt_ops/digestset.c
if USE_NSS
src_lib_libtor_crypt_ops_a_SOURCES += \
src/lib/crypt_ops/aes_nss.c \
src/lib/crypt_ops/crypto_dh_nss.c \
src/lib/crypt_ops/crypto_nss_mgt.c \
src/lib/crypt_ops/crypto_rsa_nss.c
else
src_lib_libtor_crypt_ops_a_SOURCES += \
src/lib/crypt_ops/aes_openssl.c \
src/lib/crypt_ops/crypto_rsa_openssl.c
endif
if USE_OPENSSL
src_lib_libtor_crypt_ops_a_SOURCES += \
src/lib/crypt_ops/crypto_dh_openssl.c \
src/lib/crypt_ops/crypto_openssl_mgt.c
endif
src_lib_libtor_crypt_ops_a_CFLAGS = $(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB)
src_lib_libtor_crypt_ops_testing_a_SOURCES = \
$(src_lib_libtor_crypt_ops_a_SOURCES)
src_lib_libtor_crypt_ops_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_crypt_ops_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_lib_libtor_crypt_ops_testing_a_CFLAGS = \
$(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) $(TEST_CFLAGS)
noinst_HEADERS += \
src/lib/crypt_ops/aes.h \
@@ -36,8 +56,10 @@ noinst_HEADERS += \
src/lib/crypt_ops/crypto_digest.h \
src/lib/crypt_ops/crypto_ed25519.h \
src/lib/crypt_ops/crypto_format.h \
src/lib/crypt_ops/crypto.h \
src/lib/crypt_ops/crypto_cipher.h \
src/lib/crypt_ops/crypto_hkdf.h \
src/lib/crypt_ops/crypto_init.h \
src/lib/crypt_ops/crypto_nss_mgt.h \
src/lib/crypt_ops/crypto_openssl_mgt.h \
src/lib/crypt_ops/crypto_ope.h \
src/lib/crypt_ops/crypto_pwbox.h \
+1
View File
@@ -1,5 +1,6 @@
orconfig.h
lib/cc/*.h
lib/ctime/*.h
lib/encoding/*.h
lib/intmath/*.h
lib/log/*.h
+2
View File
@@ -9,6 +9,7 @@ src_lib_libtor_encoding_a_SOURCES = \
src/lib/encoding/confline.c \
src/lib/encoding/cstring.c \
src/lib/encoding/keyval.c \
src/lib/encoding/pem.c \
src/lib/encoding/time_fmt.c
src_lib_libtor_encoding_testing_a_SOURCES = \
@@ -21,4 +22,5 @@ noinst_HEADERS += \
src/lib/encoding/confline.h \
src/lib/encoding/cstring.h \
src/lib/encoding/keyval.h \
src/lib/encoding/pem.h \
src/lib/encoding/time_fmt.h
+106
View File
@@ -0,0 +1,106 @@
/* 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 pem.c
*
* \brief Implement a trivial version of PEM encoding, for use with NSS.
*
* We deliberately do not support any encryption here.
**/
#include "orconfig.h"
#include "lib/encoding/pem.h"
#include "lib/ctime/di_ops.h"
#include "lib/encoding/binascii.h"
#include "lib/log/util_bug.h"
#include "lib/malloc/malloc.h"
#include "lib/string/printf.h"
#include "lib/string/util_string.h"
#include <string.h>
/**
* Return the length of a <b>src_len</b>-byte object when tagged with
* <b>objtype</b> and PEM-encoded. Includes terminating NUL.
*/
size_t
pem_encoded_size(size_t src_len, const char *objtype)
{
return
strlen("-----BEGIN -----\n") +
strlen("-----END -----\n") +
strlen(objtype) * 2 +
base64_encode_size(src_len, BASE64_ENCODE_MULTILINE)
+ 1;
}
/**
* PEM-encode the <b>srclen</b>-byte object at <b>src</b> into the
* <b>destlen<\b>-byte buffer at <b>dest</b>, tagging it with <b>objtype</b>.
* Return 0 on success and -1 on failure.
*/
int
pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen,
const char *objtype)
{
if (tor_snprintf(dest, destlen, "-----BEGIN %s-----\n", objtype) < 0)
return -1;
size_t offset = strlen(dest);
int n = base64_encode(dest + offset, destlen - offset,
(const char *)src, srclen, BASE64_ENCODE_MULTILINE);
if (n < 0)
return -1;
offset += n;
if (BUG(offset > destlen))
return -1;
if (tor_snprintf(dest + offset, destlen - offset,
"-----END %s-----\n", objtype) < 0)
return -1;
tor_assert(strlen(dest) + 1 <= pem_encoded_size(srclen, objtype));
return 0;
}
/**
* Given a PEM-encoded block of size <b>srclen</b> in <b>src</b>, if it has
* object type <b>objtype</b>, decode it into the <b>destlen</b>-byte buffer
* at <b>dest</b>. Return the number of characters decoded on success, or -1
* on failure.
*/
int
pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen,
const char *objtype)
{
const char *eos = src + srclen;
src = eat_whitespace_eos(src, eos);
char *tag = NULL;
tor_asprintf(&tag, "-----BEGIN %s-----\n", objtype);
if ((size_t)(eos-src) < strlen(tag) || fast_memneq(src, tag, strlen(tag))) {
tor_free(tag);
return -1;
}
src += strlen(tag);
tor_free(tag);
// NOTE lack of trailing \n. We do not enforce its presence.
tor_asprintf(&tag, "\n-----END %s-----", objtype);
const char *end_of_base64 = tor_memstr(src, eos-src, tag);
tor_free(tag);
if (end_of_base64 == NULL)
return -1;
/* Should we actually allow extra stuff at the end? */
return base64_decode((char*)dest, destlen, src, end_of_base64-src);
}
+26
View File
@@ -0,0 +1,26 @@
/* 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 pem.h
*
* \brief Header for pem.c
**/
#ifndef TOR_PEM_H
#define TOR_PEM_H
#include "orconfig.h"
#include <stddef.h>
#include "lib/cc/torint.h"
size_t pem_encoded_size(size_t src_len, const char *objtype);
int pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen,
const char *objtype);
int pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen,
const char *objtype);
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
src_lib_libcurve25519_donna_a_CFLAGS=
src_lib_libcurve25519_donna_a_CFLAGS=$(TOR_CFLAGS_CRYPTO)
if BUILD_CURVE25519_DONNA
src_lib_libcurve25519_donna_a_SOURCES=\
+16 -9
View File
@@ -41,15 +41,16 @@ static int daemon_filedes[2];
/** Start putting the process into daemon mode: fork and drop all resources
* except standard fds. The parent process never returns, but stays around
* until finish_daemon is called. (Note: it's safe to call this more
* than once: calls after the first are ignored.)
* than once: calls after the first are ignored.) Return true if we actually
* forked and this is the child; false otherwise.
*/
void
int
start_daemon(void)
{
pid_t pid;
if (start_daemon_called)
return;
return 0;
start_daemon_called = 1;
if (pipe(daemon_filedes)) {
@@ -80,6 +81,7 @@ start_daemon(void)
exit(0); // exit ok: during daemonize, daemonizing.
else
exit(1); /* child reported error. exit ok: daemonize failed. */
return 0; // LCOV_EXCL_LINE unreachable
} else { /* Child */
close(daemon_filedes[0]); /* we only write */
@@ -95,22 +97,23 @@ start_daemon(void)
}
set_main_thread(); /* We are now the main thread. */
return;
return 1;
}
}
/** Finish putting the process into daemon mode: drop standard fds, and tell
* the parent process to exit. (Note: it's safe to call this more than once:
* calls after the first are ignored. Calls start_daemon first if it hasn't
* been called already.)
* been called already.) Return true if we actually did a fork; false if we
* didn't.
*/
void
int
finish_daemon(const char *desired_cwd)
{
int nullfd;
char c = '.';
if (finish_daemon_called)
return;
return 0;
if (!start_daemon_called)
start_daemon();
finish_daemon_called = 1;
@@ -149,16 +152,20 @@ finish_daemon(const char *desired_cwd)
log_err(LD_GENERAL,"write failed. Exiting.");
}
close(daemon_filedes[1]);
return 0;
}
#else /* !(!defined(_WIN32)) */
/* defined(_WIN32) */
void
int
start_daemon(void)
{
return 0;
}
void
int
finish_daemon(const char *cp)
{
(void)cp;
return 0;
}
#endif /* !defined(_WIN32) */
+2 -2
View File
@@ -11,7 +11,7 @@
#ifndef TOR_DAEMON_H
#define TOR_DAEMON_H
void start_daemon(void);
void finish_daemon(const char *desired_cwd);
int start_daemon(void);
int finish_daemon(const char *desired_cwd);
#endif
+21 -3
View File
@@ -7,14 +7,32 @@ endif
src_lib_libtor_tls_a_SOURCES = \
src/lib/tls/buffers_tls.c \
src/lib/tls/tortls.c
src/lib/tls/tortls.c \
src/lib/tls/x509.c
if USE_NSS
src_lib_libtor_tls_a_SOURCES += \
src/lib/tls/tortls_nss.c \
src/lib/tls/x509_nss.c
else
src_lib_libtor_tls_a_SOURCES += \
src/lib/tls/tortls_openssl.c \
src/lib/tls/x509_openssl.c
endif
src_lib_libtor_tls_a_CFLAGS = $(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB)
src_lib_libtor_tls_testing_a_SOURCES = \
$(src_lib_libtor_tls_a_SOURCES)
src_lib_libtor_tls_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_tls_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_lib_libtor_tls_testing_a_CFLAGS = \
$(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) $(TEST_CFLAGS)
noinst_HEADERS += \
src/lib/tls/ciphers.inc \
src/lib/tls/buffers_tls.h \
src/lib/tls/tortls.h
src/lib/tls/tortls.h \
src/lib/tls/tortls_internal.h \
src/lib/tls/tortls_st.h \
src/lib/tls/x509.h \
src/lib/tls/x509_internal.h
+171 -2408
View File
File diff suppressed because it is too large Load Diff
+36 -174
View File
@@ -12,14 +12,27 @@
**/
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/crypt_ops/compat_openssl.h"
#include "lib/testsupport/testsupport.h"
#include "lib/net/nettypes.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;
#ifdef TORTLS_PRIVATE
#ifdef ENABLE_OPENSSL
struct ssl_st;
struct ssl_ctx_st;
struct ssl_session_st;
typedef struct ssl_ctx_st tor_tls_context_impl_t;
typedef struct ssl_st tor_tls_impl_t;
#else
struct PRFileDesc;
typedef struct PRFileDesc tor_tls_context_impl_t;
typedef struct PRFileDesc tor_tls_impl_t;
#endif
#endif
struct tor_x509_cert_t;
/* Possible return values for most tor_tls_* functions. */
#define MIN_TOR_TLS_ERROR_VAL_ -9
@@ -52,164 +65,30 @@ typedef struct tor_x509_cert_t tor_x509_cert_t;
#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;
typedef struct tor_tls_context_t 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)
void tor_tls_init(void);
void tls_log_errors(tor_tls_t *tls, int severity, int domain,
const char *doing);
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_context_incref(tor_tls_context_t *ctx);
void tor_tls_context_decref(tor_tls_context_t *ctx);
tor_tls_context_t *tor_tls_context_get(int is_server);
tor_tls_t *tor_tls_new(tor_socket_t 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),
@@ -218,13 +97,9 @@ 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));
MOCK_DECL(struct tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls));
MOCK_DECL(struct 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);
@@ -232,7 +107,6 @@ 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);
@@ -248,6 +122,8 @@ 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_cert_matches_key,(const tor_tls_t *tls,
const struct tor_x509_cert_t *cert));
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,
@@ -255,37 +131,23 @@ MOCK_DECL(int,tor_tls_export_key_material,(
size_t context_len,
const char *label));
#ifdef ENABLE_OPENSSL
/* 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);
#else
#define check_no_tls_errors() STMT_NIL
#endif
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);
const struct tor_x509_cert_t **link_cert_out,
const struct 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);
+76
View File
@@ -0,0 +1,76 @@
/* 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 TORTLS_INTERNAL_H
#define TORTLS_INTERNAL_H
int tor_errno_to_tls_error(int e);
#ifdef ENABLE_OPENSSL
int tor_tls_get_error(tor_tls_t *tls, int r, int extra,
const char *doing, int severity, int domain);
#endif
MOCK_DECL(void, try_to_extract_certs_from_tls,
(int severity, tor_tls_t *tls,
tor_x509_cert_impl_t **cert_out,
tor_x509_cert_impl_t **id_cert_out));
tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
unsigned int key_lifetime, unsigned flags, int is_client);
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);
int tor_tls_context_init_certificates(tor_tls_context_t *result,
crypto_pk_t *identity,
unsigned key_lifetime,
unsigned flags);
void tor_tls_impl_free_(tor_tls_impl_t *ssl);
#define tor_tls_impl_free(tls) \
FREE_AND_NULL(tor_tls_impl_t, tor_tls_impl_free_, (tls))
void tor_tls_context_impl_free_(tor_tls_context_impl_t *);
#define tor_tls_context_impl_free(ctx) \
FREE_AND_NULL(tor_tls_context_impl_t, tor_tls_context_impl_free_, (ctx))
#ifdef ENABLE_OPENSSL
tor_tls_t *tor_tls_get_by_ssl(const struct ssl_st *ssl);
int tor_tls_client_is_using_v2_ciphers(const struct ssl_st *ssl);
void tor_tls_debug_state_callback(const struct ssl_st *ssl,
int type, int val);
void tor_tls_server_info_callback(const struct ssl_st *ssl,
int type, int val);
void tor_tls_allocate_tor_tls_object_ex_data_index(void);
#if !defined(HAVE_SSL_SESSION_GET_MASTER_KEY)
size_t SSL_SESSION_get_master_key(struct ssl_session_st *s,
uint8_t *out,
size_t len);
#endif
#ifdef TORTLS_OPENSSL_PRIVATE
int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx);
int tor_tls_classify_client_ciphers(const struct ssl_st *ssl,
STACK_OF(SSL_CIPHER) *peer_ciphers);
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
#endif
#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;
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(TORTLS_INTERNAL_H) */
+741
View File
@@ -0,0 +1,741 @@
/* 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_nss.c
* \brief Wrapper functions to present a consistent interface to
* TLS and SSL X.509 functions from NSS.
**/
#include "orconfig.h"
#define TORTLS_PRIVATE
#define TOR_X509_PRIVATE
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/string/printf.h"
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
#include "lib/tls/tortls_st.h"
#include "lib/tls/tortls_internal.h"
#include "lib/log/util_bug.h"
#include <prio.h>
// For access to raw sockets.
#include <private/pprio.h>
#include <ssl.h>
#include <sslt.h>
#include <sslproto.h>
#include <certt.h>
static SECStatus always_accept_cert_cb(void *, PRFileDesc *, PRBool, PRBool);
MOCK_IMPL(void,
try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
tor_x509_cert_impl_t **cert_out,
tor_x509_cert_impl_t **id_cert_out))
{
tor_assert(tls);
tor_assert(cert_out);
tor_assert(id_cert_out);
(void) severity;
*cert_out = *id_cert_out = NULL;
CERTCertificate *peer = SSL_PeerCertificate(tls->ssl);
if (!peer)
return;
*cert_out = peer; /* Now owns pointer. */
CERTCertList *chain = SSL_PeerCertificateChain(tls->ssl);
CERTCertListNode *c = CERT_LIST_HEAD(chain);
for (; !CERT_LIST_END(c, chain); c = CERT_LIST_NEXT(c)) {
if (CERT_CompareCerts(c->cert, peer) == PR_FALSE) {
*id_cert_out = CERT_DupCertificate(c->cert);
break;
}
}
CERT_DestroyCertList(chain);
}
static bool
we_like_ssl_cipher(SSLCipherAlgorithm ca)
{
switch (ca) {
case ssl_calg_null: return false;
case ssl_calg_rc4: return false;
case ssl_calg_rc2: return false;
case ssl_calg_des: return false;
case ssl_calg_3des: return false; /* ???? */
case ssl_calg_idea: return false;
case ssl_calg_fortezza: return false;
case ssl_calg_camellia: return false;
case ssl_calg_seed: return false;
case ssl_calg_aes: return true;
case ssl_calg_aes_gcm: return true;
case ssl_calg_chacha20: return true;
default: return true;
}
}
static bool
we_like_ssl_kea(SSLKEAType kt)
{
switch (kt) {
case ssl_kea_null: return false;
case ssl_kea_rsa: return false; /* ??? */
case ssl_kea_fortezza: return false;
case ssl_kea_ecdh_psk: return false;
case ssl_kea_dh_psk: return false;
case ssl_kea_dh: return true;
case ssl_kea_ecdh: return true;
case ssl_kea_tls13_any: return true;
case ssl_kea_size: return true; /* prevent a warning. */
default: return true;
}
}
static bool
we_like_mac_algorithm(SSLMACAlgorithm ma)
{
switch (ma) {
case ssl_mac_null: return false;
case ssl_mac_md5: return false;
case ssl_hmac_md5: return false;
case ssl_mac_sha: return true;
case ssl_hmac_sha: return true;
case ssl_hmac_sha256: return true;
case ssl_mac_aead: return true;
case ssl_hmac_sha384: return true;
default: return true;
}
}
static bool
we_like_auth_type(SSLAuthType at)
{
switch (at) {
case ssl_auth_null: return false;
case ssl_auth_rsa_decrypt: return false;
case ssl_auth_dsa: return false;
case ssl_auth_kea: return false;
case ssl_auth_ecdsa: return true;
case ssl_auth_ecdh_rsa: return true;
case ssl_auth_ecdh_ecdsa: return true;
case ssl_auth_rsa_sign: return true;
case ssl_auth_rsa_pss: return true;
case ssl_auth_psk: return true;
case ssl_auth_tls13_any: return true;
case ssl_auth_size: return true; /* prevent a warning. */
default: return true;
}
}
tor_tls_context_t *
tor_tls_context_new(crypto_pk_t *identity,
unsigned int key_lifetime, unsigned flags, int is_client)
{
SECStatus s;
tor_assert(identity);
tor_tls_context_t *ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
ctx->refcnt = 1;
if (! is_client) {
if (tor_tls_context_init_certificates(ctx, identity,
key_lifetime, flags) < 0) {
goto err;
}
}
{
/* Create the "model" PRFileDesc that we will use to base others on. */
PRFileDesc *tcp = PR_NewTCPSocket();
if (!tcp)
goto err;
ctx->ctx = SSL_ImportFD(NULL, tcp);
if (!ctx->ctx) {
PR_Close(tcp);
goto err;
}
}
// Configure the certificate.
if (!is_client) {
s = SSL_ConfigServerCert(ctx->ctx,
ctx->my_link_cert->cert,
(SECKEYPrivateKey *)
crypto_pk_get_nss_privkey(ctx->link_key),
NULL, /* ExtraServerCertData */
0 /* DataLen */);
if (s != SECSuccess)
goto err;
}
// We need a certificate from the other side.
if (is_client) {
// XXXX does this do anything?
s = SSL_OptionSet(ctx->ctx, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
if (s != SECSuccess)
goto err;
}
// Always accept other side's cert; we'll check it ourselves in goofy
// tor ways.
s = SSL_AuthCertificateHook(ctx->ctx, always_accept_cert_cb, NULL);
// We allow simultaneous read and write.
s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_FDX, PR_TRUE);
if (s != SECSuccess)
goto err;
// XXXX SSL_ROLLBACK_DETECTION??
// XXXX SSL_ENABLE_ALPN??
// Force client-mode or server_mode.
s = SSL_OptionSet(ctx->ctx,
is_client ? SSL_HANDSHAKE_AS_CLIENT : SSL_HANDSHAKE_AS_SERVER,
PR_TRUE);
if (s != SECSuccess)
goto err;
// Disable everything before TLS 1.0; support everything else.
{
SSLVersionRange vrange;
memset(&vrange, 0, sizeof(vrange));
s = SSL_VersionRangeGetSupported(ssl_variant_stream, &vrange);
if (s != SECSuccess)
goto err;
if (vrange.min < SSL_LIBRARY_VERSION_TLS_1_0)
vrange.min = SSL_LIBRARY_VERSION_TLS_1_0;
s = SSL_VersionRangeSet(ctx->ctx, &vrange);
if (s != SECSuccess)
goto err;
}
// Only support strong ciphers.
{
const PRUint16 *ciphers = SSL_GetImplementedCiphers();
const PRUint16 n_ciphers = SSL_GetNumImplementedCiphers();
PRUint16 i;
for (i = 0; i < n_ciphers; ++i) {
SSLCipherSuiteInfo info;
memset(&info, 0, sizeof(info));
s = SSL_GetCipherSuiteInfo(ciphers[i], &info, sizeof(info));
if (s != SECSuccess)
goto err;
if (BUG(info.cipherSuite != ciphers[i]))
goto err;
int disable = info.effectiveKeyBits < 128 ||
info.macBits < 128 ||
!we_like_ssl_cipher(info.symCipher) ||
!we_like_ssl_kea(info.keaType) ||
!we_like_mac_algorithm(info.macAlgorithm) ||
!we_like_auth_type(info.authType)/* Requires NSS 3.24 */;
s = SSL_CipherPrefSet(ctx->ctx, ciphers[i],
disable ? PR_FALSE : PR_TRUE);
if (s != SECSuccess)
goto err;
}
}
// Only use DH and ECDH keys once.
s = SSL_OptionSet(ctx->ctx, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
if (s != SECSuccess)
goto err;
// don't cache sessions.
s = SSL_OptionSet(ctx->ctx, SSL_NO_CACHE, PR_TRUE);
if (s != SECSuccess)
goto err;
// Enable DH.
s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_SERVER_DHE, PR_TRUE);
if (s != SECSuccess)
goto err;
// Set DH and ECDH groups.
SSLNamedGroup groups[] = {
ssl_grp_ec_curve25519,
ssl_grp_ec_secp256r1,
ssl_grp_ec_secp224r1,
ssl_grp_ffdhe_2048,
};
s = SSL_NamedGroupConfig(ctx->ctx, groups, ARRAY_LENGTH(groups));
if (s != SECSuccess)
goto err;
// These features are off by default, so we don't need to disable them:
// Session tickets
// Renegotiation
// Compression
goto done;
err:
tor_tls_context_decref(ctx);
ctx = NULL;
done:
return ctx;
}
void
tor_tls_context_impl_free_(tor_tls_context_impl_t *ctx)
{
if (!ctx)
return;
PR_Close(ctx);
}
void
tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
{
(void)tls;
(void)buf;
(void)sz;
// AFAICT, NSS doesn't expose its internal state.
buf[0]=0;
}
void
tor_tls_init(void)
{
/* We don't have any global setup to do yet, but that will change */
}
void
tls_log_errors(tor_tls_t *tls, int severity, int domain,
const char *doing)
{
/* This implementation is a little different for NSS than it is for OpenSSL
-- it logs the last error whether anything actually failed or not. So we
have to only call it when something has gone wrong and we have a real
error to report. */
(void)tls;
PRErrorCode code = PORT_GetError();
const char *addr = tls ? tls->address : NULL;
const char *string = PORT_ErrorToString(code);
const char *name = PORT_ErrorToName(code);
char buf[16];
if (!string)
string = "<unrecognized>";
if (!name) {
tor_snprintf(buf, sizeof(buf), "%d", code);
name = buf;
}
const char *with = addr ? " with " : "";
addr = addr ? addr : "";
if (doing) {
log_fn(severity, domain, "TLS error %s while %s%s%s: %s",
name, doing, with, addr, string);
} else {
log_fn(severity, domain, "TLS error %s%s%s: %s", name, string,
with, addr);
}
}
tor_tls_t *
tor_tls_new(tor_socket_t sock, int is_server)
{
(void)sock;
tor_tls_context_t *ctx = tor_tls_context_get(is_server);
PRFileDesc *tcp = NULL;
if (SOCKET_OK(sock)) {
tcp = PR_ImportTCPSocket(sock);
} else {
tcp = PR_NewTCPSocket();
}
if (!tcp)
return NULL;
PRFileDesc *ssl = SSL_ImportFD(ctx->ctx, tcp);
if (!ssl) {
PR_Close(tcp);
return NULL;
}
tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t));
tls->magic = TOR_TLS_MAGIC;
tls->context = ctx;
tor_tls_context_incref(ctx);
tls->ssl = ssl;
tls->socket = sock;
tls->state = TOR_TLS_ST_HANDSHAKE;
tls->isServer = !!is_server;
if (!is_server) {
/* Set a random SNI */
char *fake_hostname = crypto_random_hostname(4,25, "www.",".com");
SSL_SetURL(tls->ssl, fake_hostname);
tor_free(fake_hostname);
}
SECStatus s = SSL_ResetHandshake(ssl, is_server ? PR_TRUE : PR_FALSE);
if (s != SECSuccess) {
tls_log_errors(tls, LOG_WARN, LD_CRYPTO, "resetting handshake state");
}
return tls;
}
void
tor_tls_set_renegotiate_callback(tor_tls_t *tls,
void (*cb)(tor_tls_t *, void *arg),
void *arg)
{
tor_assert(tls);
(void)cb;
(void)arg;
/* We don't support renegotiation-based TLS with NSS. */
}
void
tor_tls_impl_free_(tor_tls_impl_t *tls)
{
// XXXX This will close the underlying fd, which our OpenSSL version does
// not do!
if (!tls)
return;
PR_Close(tls);
}
int
tor_tls_peer_has_cert(tor_tls_t *tls)
{
CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
int result = (cert != NULL);
CERT_DestroyCertificate(cert);
return result;
}
MOCK_IMPL(tor_x509_cert_t *,
tor_tls_get_peer_cert,(tor_tls_t *tls))
{
CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
if (cert)
return tor_x509_cert_new(cert);
else
return NULL;
}
MOCK_IMPL(tor_x509_cert_t *,
tor_tls_get_own_cert,(tor_tls_t *tls))
{
tor_assert(tls);
CERTCertificate *cert = SSL_LocalCertificate(tls->ssl);
if (cert)
return tor_x509_cert_new(cert);
else
return NULL;
}
MOCK_IMPL(int,
tor_tls_read, (tor_tls_t *tls, char *cp, size_t len))
{
tor_assert(tls);
tor_assert(cp);
tor_assert(len < INT_MAX);
PRInt32 rv = PR_Read(tls->ssl, cp, (int)len);
// log_debug(LD_NET, "PR_Read(%zu) returned %d", n, (int)rv);
if (rv > 0) {
tls->n_read_since_last_check += rv;
return rv;
}
if (rv == 0)
return TOR_TLS_CLOSE;
PRErrorCode err = PORT_GetError();
if (err == PR_WOULD_BLOCK_ERROR) {
return TOR_TLS_WANTREAD; // XXXX ????
} else {
tls_log_errors(tls, LOG_NOTICE, LD_CRYPTO, "reading"); // XXXX
return TOR_TLS_ERROR_MISC; // ????
}
}
int
tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
{
tor_assert(tls);
tor_assert(cp || n == 0);
tor_assert(n < INT_MAX);
PRInt32 rv = PR_Write(tls->ssl, cp, (int)n);
// log_debug(LD_NET, "PR_Write(%zu) returned %d", n, (int)rv);
if (rv > 0) {
tls->n_written_since_last_check += rv;
return rv;
}
if (rv == 0)
return TOR_TLS_ERROR_MISC;
PRErrorCode err = PORT_GetError();
if (err == PR_WOULD_BLOCK_ERROR) {
return TOR_TLS_WANTWRITE; // XXXX ????
} else {
tls_log_errors(tls, LOG_NOTICE, LD_CRYPTO, "writing"); // XXXX
return TOR_TLS_ERROR_MISC; // ????
}
}
int
tor_tls_handshake(tor_tls_t *tls)
{
tor_assert(tls);
tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
SECStatus s = SSL_ForceHandshake(tls->ssl);
if (s == SECSuccess) {
tls->state = TOR_TLS_ST_OPEN;
log_debug(LD_NET, "SSL handshake is supposedly complete.");
return tor_tls_finish_handshake(tls);
}
if (PORT_GetError() == PR_WOULD_BLOCK_ERROR)
return TOR_TLS_WANTREAD; /* XXXX What about wantwrite? */
return TOR_TLS_ERROR_MISC; // XXXX
}
int
tor_tls_finish_handshake(tor_tls_t *tls)
{
tor_assert(tls);
// We don't need to do any of the weird handshake nonsense stuff on NSS,
// since we only support recent handshakes.
return TOR_TLS_DONE;
}
void
tor_tls_unblock_renegotiation(tor_tls_t *tls)
{
tor_assert(tls);
/* We don't support renegotiation with NSS. */
}
void
tor_tls_block_renegotiation(tor_tls_t *tls)
{
tor_assert(tls);
/* We don't support renegotiation with NSS. */
}
void
tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
{
tor_assert(tls);
/* We don't support renegotiation with NSS. */
}
int
tor_tls_get_pending_bytes(tor_tls_t *tls)
{
tor_assert(tls);
int n = SSL_DataPending(tls->ssl);
if (n < 0) {
tls_log_errors(tls, LOG_WARN, LD_CRYPTO, "looking up pending bytes");
return 0;
}
return (int)n;
}
size_t
tor_tls_get_forced_write_size(tor_tls_t *tls)
{
tor_assert(tls);
/* NSS doesn't have the same "forced write" restriction as openssl. */
return 0;
}
void
tor_tls_get_n_raw_bytes(tor_tls_t *tls,
size_t *n_read, size_t *n_written)
{
tor_assert(tls);
tor_assert(n_read);
tor_assert(n_written);
/* XXXX We don't curently have a way to measure this information correctly
* in NSS; we could do that with a PRIO layer, but it'll take a little
* coding. For now, we just track the number of bytes sent _in_ the TLS
* stream. Doing this will make our rate-limiting slightly inaccurate. */
*n_read = tls->n_read_since_last_check;
*n_written = tls->n_written_since_last_check;
tls->n_read_since_last_check = tls->n_written_since_last_check = 0;
}
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)
{
tor_assert(tls);
tor_assert(rbuf_capacity);
tor_assert(rbuf_bytes);
tor_assert(wbuf_capacity);
tor_assert(wbuf_bytes);
/* This is an acceptable way to say "we can't measure this." */
return -1;
}
MOCK_IMPL(double,
tls_get_write_overhead_ratio, (void))
{
/* XXX We don't currently have a way to measure this in NSS; we could do that
* XXX with a PRIO layer, but it'll take a little coding. */
return 0.95;
}
int
tor_tls_used_v1_handshake(tor_tls_t *tls)
{
tor_assert(tls);
/* We don't support or allow the V1 handshake with NSS.
*/
return 0;
}
int
tor_tls_server_got_renegotiate(tor_tls_t *tls)
{
tor_assert(tls);
return 0; /* We don't support renegotiation with NSS */
}
MOCK_IMPL(int,
tor_tls_cert_matches_key,(const tor_tls_t *tls,
const struct tor_x509_cert_t *cert))
{
tor_assert(tls);
tor_assert(cert);
int rv = 0;
CERTCertificate *peercert = SSL_PeerCertificate(tls->ssl);
if (!peercert)
goto done;
CERTSubjectPublicKeyInfo *peer_info = &peercert->subjectPublicKeyInfo;
CERTSubjectPublicKeyInfo *cert_info = &cert->cert->subjectPublicKeyInfo;
rv = SECOID_CompareAlgorithmID(&peer_info->algorithm,
&cert_info->algorithm) == 0 &&
SECITEM_ItemsAreEqual(&peer_info->subjectPublicKey,
&cert_info->subjectPublicKey);
done:
if (peercert)
CERT_DestroyCertificate(peercert);
return rv;
}
MOCK_IMPL(int,
tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
{
tor_assert(tls);
tor_assert(secrets_out);
/* There's no way to get this information out of NSS. */
return -1;
}
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(secrets_out);
tor_assert(context);
tor_assert(label);
tor_assert(strlen(label) <= UINT_MAX);
tor_assert(context_len <= UINT_MAX);
SECStatus s;
s = SSL_ExportKeyingMaterial(tls->ssl,
label, (unsigned)strlen(label),
PR_TRUE, context, (unsigned)context_len,
secrets_out, DIGEST256_LEN);
return (s == SECSuccess) ? 0 : -1;
}
const char *
tor_tls_get_ciphersuite_name(tor_tls_t *tls)
{
tor_assert(tls);
SSLChannelInfo channel_info;
SSLCipherSuiteInfo cipher_info;
memset(&channel_info, 0, sizeof(channel_info));
memset(&cipher_info, 0, sizeof(cipher_info));
SECStatus s = SSL_GetChannelInfo(tls->ssl,
&channel_info, sizeof(channel_info));
if (s != SECSuccess)
return NULL;
s = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
&cipher_info, sizeof(cipher_info));
if (s != SECSuccess)
return NULL;
return cipher_info.cipherSuiteName;
}
/** The group we should use for ecdhe when none was selected. */
#define SEC_OID_TOR_DEFAULT_ECDHE_GROUP SEC_OID_ANSIX962_EC_PRIME256V1
int
evaluate_ecgroup_for_tls(const char *ecgroup)
{
SECOidTag tag;
if (!ecgroup)
tag = SEC_OID_TOR_DEFAULT_ECDHE_GROUP;
else if (!strcasecmp(ecgroup, "P256"))
tag = SEC_OID_ANSIX962_EC_PRIME256V1;
else if (!strcasecmp(ecgroup, "P224"))
tag = SEC_OID_SECG_EC_SECP224R1;
else
return 0;
/* I don't think we need any additional tests here for NSS */
(void) tag;
return 1;
}
static SECStatus
always_accept_cert_cb(void *arg, PRFileDesc *ssl, PRBool checkSig,
PRBool isServer)
{
(void)arg;
(void)ssl;
(void)checkSig;
(void)isServer;
return SECSuccess;
}
File diff suppressed because it is too large Load Diff
+74
View File
@@ -0,0 +1,74 @@
/* 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_ST_H
#define TOR_TORTLS_ST_H
#include "lib/net/socket.h"
#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 tor_tls_context_t {
int refcnt;
tor_tls_context_impl_t *ctx;
struct tor_x509_cert_t *my_link_cert;
struct tor_x509_cert_t *my_id_cert;
struct tor_x509_cert_t *my_auth_cert;
crypto_pk_t *link_key;
crypto_pk_t *auth_key;
};
/** 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. */
tor_tls_impl_t *ssl; /**< An OpenSSL SSL object or NSS PRFileDesc. */
tor_socket_t 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;
#ifdef ENABLE_OPENSSL
/** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't
* called that function yet. */
int8_t client_cipher_list_type;
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;
#endif
#ifdef ENABLE_NSS
size_t n_read_since_last_check;
size_t n_written_since_last_check;
#endif
};
#endif
+143
View File
@@ -0,0 +1,143 @@
/* 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 x509_openssl.c
* \brief Wrapper functions to present a consistent interface to
* X.509 functions.
**/
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/log/util_bug.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
/** Choose the start and end times for a certificate */
void
tor_tls_pick_certificate_lifetime(time_t now,
unsigned int cert_lifetime,
time_t *start_time_out,
time_t *end_time_out)
{
time_t start_time, end_time;
/* 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. */
/* 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;
*start_time_out = start_time;
*end_time_out = end_time;
}
/** 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;
}
/** Free all storage held in <b>cert</b> */
void
tor_x509_cert_free_(tor_x509_cert_t *cert)
{
if (! cert)
return;
tor_x509_cert_impl_free(cert->cert);
#ifdef ENABLE_OPENSSL
tor_free(cert->encoded);
#endif
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(tor_x509_cert_t *,
tor_x509_cert_new,(tor_x509_cert_impl_t *x509_cert))
{
tor_x509_cert_t *cert;
if (!x509_cert)
return NULL;
cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
cert->cert = x509_cert;
if (tor_x509_cert_set_cached_der_encoding(cert) < 0)
goto err;
{
const uint8_t *encoded=NULL;
size_t encoded_len=0;
tor_x509_cert_get_der(cert, &encoded, &encoded_len);
tor_assert(encoded);
crypto_common_digests(&cert->cert_digests, (char *)encoded, encoded_len);
}
{
crypto_pk_t *pk = tor_tls_cert_get_key(cert);
if (pk) {
if (crypto_pk_get_common_digests(pk, &cert->pkey_digests) < 0) {
log_warn(LD_CRYPTO, "unable to compute digests of certificate key");
crypto_pk_free(pk);
goto err;
}
}
cert->pkey_digests_set = 1;
crypto_pk_free(pk);
}
return cert;
err:
log_err(LD_CRYPTO, "Couldn't wrap encoded X509 certificate.");
tor_x509_cert_free(cert);
return NULL;
}
/** 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);
tor_assert(cert->cert);
return tor_x509_cert_new(tor_x509_cert_impl_dup_(cert->cert));
}
+75
View File
@@ -0,0 +1,75 @@
/* 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_X509_H
#define TOR_X509_H
/**
* \file x509.h
* \brief Headers for tortls.c
**/
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/testsupport/testsupport.h"
/* Opaque structure to hold an X509 certificate. */
typedef struct tor_x509_cert_t tor_x509_cert_t;
#ifdef ENABLE_NSS
typedef struct CERTCertificateStr tor_x509_cert_impl_t;
#elif defined(ENABLE_OPENSSL)
typedef struct x509_st tor_x509_cert_impl_t;
#endif
#ifdef TOR_X509_PRIVATE
/** Structure that we use for a single certificate. */
struct tor_x509_cert_t {
tor_x509_cert_impl_t *cert;
#ifdef ENABLE_OPENSSL
uint8_t *encoded;
size_t encoded_len;
#endif
unsigned pkey_digests_set : 1;
common_digests_t cert_digests;
common_digests_t pkey_digests;
};
#endif
void tor_tls_pick_certificate_lifetime(time_t now,
unsigned cert_lifetime,
time_t *start_time_out,
time_t *end_time_out);
#ifdef TOR_UNIT_TESTS
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
tor_x509_cert_t *tor_x509_cert_dup(const tor_x509_cert_t *cert);
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);
crypto_pk_t *tor_tls_cert_get_key(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);
#endif
+53
View File
@@ -0,0 +1,53 @@
/* 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_X509_INTERNAL_H
#define TOR_X509_INTERNAL_H
/**
* \file x509.h
* \brief Internal headers for tortls.c
**/
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/testsupport/testsupport.h"
/**
* How skewed do we allow our clock to be with respect to certificates that
* seem to be expired? (seconds)
*/
#define TOR_X509_PAST_SLOP (2*24*60*60)
/**
* How skewed do we allow our clock to be with respect to certificates that
* seem to come from the future? (seconds)
*/
#define TOR_X509_FUTURE_SLOP (30*24*60*60)
MOCK_DECL(tor_x509_cert_impl_t *, tor_tls_create_certificate,
(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
const char *cname,
const char *cname_sign,
unsigned int cert_lifetime));
MOCK_DECL(tor_x509_cert_t *, tor_x509_cert_new,
(tor_x509_cert_impl_t *x509_cert));
int tor_x509_check_cert_lifetime_internal(int severity,
const tor_x509_cert_impl_t *cert,
time_t now,
int past_tolerance,
int future_tolerance);
void tor_x509_cert_impl_free_(tor_x509_cert_impl_t *cert);
#define tor_x509_cert_impl_free(cert) \
FREE_AND_NULL(tor_x509_cert_impl_t, tor_x509_cert_impl_free_, (cert))
tor_x509_cert_impl_t *tor_x509_cert_impl_dup_(tor_x509_cert_impl_t *cert);
#ifdef ENABLE_OPENSSL
int tor_x509_cert_set_cached_der_encoding(tor_x509_cert_t *cert);
#else
#define tor_x509_cert_set_cached_der_encoding(cert) (0)
#endif
#endif
+450
View File
@@ -0,0 +1,450 @@
/* 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 x509_nss.c
* \brief Wrapper functions to present a consistent interface to
* X.509 functions from NSS.
**/
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/log/util_bug.h"
#include "lib/encoding/time_fmt.h"
#include "lib/string/printf.h"
#include <pk11pub.h>
#include <cryptohi.h>
#include <cert.h>
#include <keyhi.h>
#include <time.h>
/* Units of PRTime per second.
*
* (PRTime is based in microseconds since the Unix
* epoch.) */
#define PRTIME_PER_SEC (1000*1000)
static tor_x509_cert_impl_t *tor_x509_cert_decode_internal(
const uint8_t *certificate, int certificate_len);
static tor_x509_cert_impl_t *
tor_tls_create_certificate_internal(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
CERTName *subject_dn,
CERTName *issuer_dn,
time_t start_time,
time_t end_time)
{
if (! crypto_pk_key_is_private(rsa_sign)) {
return NULL;
}
const SECKEYPublicKey *subject_key = crypto_pk_get_nss_pubkey(rsa);
const SECKEYPrivateKey *signing_key = crypto_pk_get_nss_privkey(rsa_sign);
SECStatus s;
CERTSubjectPublicKeyInfo *subject_spki = NULL;
CERTCertificateRequest *request = NULL;
CERTValidity *validity = NULL;
CERTCertificate *cert = NULL;
SECItem der = { .data = NULL, .len = 0 };
SECItem signed_der = { .data = NULL, .len = 0 };
CERTCertificate *result_cert = NULL;
validity = CERT_CreateValidity(((PRTime)start_time) * PRTIME_PER_SEC,
((PRTime)end_time) * PRTIME_PER_SEC);
if (BUG(! validity)) {
/* LCOV_EXCL_START */
crypto_nss_log_errors(LOG_WARN, "creating a validity object");
goto err;
/* LCOV_EXCL_STOP */
}
unsigned long serial_number;
crypto_rand((char*)&serial_number, sizeof(serial_number));
subject_spki = SECKEY_CreateSubjectPublicKeyInfo(subject_key);
if (!subject_spki)
goto err;
/* Make a CSR ... */
// XXX do we need to set any attributes?
request = CERT_CreateCertificateRequest(subject_dn,
subject_spki,
NULL /* attributes */);
if (!request)
goto err;
/* Put it into a certificate ... */
cert = CERT_CreateCertificate(serial_number,
issuer_dn,
validity,
request);
if (!cert)
goto err;
/* version 3 cert */
*cert->version.data = 2; /* 2 means version 3. */
cert->version.len = 1;
// XXX do we need to set anything else on the cert?
/* Sign it. */
KeyType privkey_type = SECKEY_GetPrivateKeyType(signing_key);
SECOidTag oid_tag = SEC_GetSignatureAlgorithmOidTag(privkey_type,
SEC_OID_SHA256);
if (oid_tag == SEC_OID_UNKNOWN)
goto err;
s = SECOID_SetAlgorithmID(cert->arena, &cert->signature, oid_tag, NULL);
if (s != SECSuccess)
goto err;
void *tmp;
tmp = SEC_ASN1EncodeItem(cert->arena, &der, cert,
SEC_ASN1_GET(CERT_CertificateTemplate));
if (!tmp)
goto err;
s = SEC_DerSignDataWithAlgorithmID(cert->arena,
&signed_der,
der.data, der.len,
(SECKEYPrivateKey *)signing_key,//const
&cert->signature);
if (s != SECSuccess)
goto err;
/* Re-parse it, to make sure all the certificates we actually use
* appear via being decoded. */
result_cert = tor_x509_cert_decode_internal(signed_der.data, signed_der.len);
#if 1
{
// Can we check the cert we just signed?
tor_assert(result_cert);
SECKEYPublicKey *issuer_pk = (SECKEYPublicKey *)
crypto_pk_get_nss_pubkey(rsa_sign);
SECStatus cert_ok = CERT_VerifySignedDataWithPublicKey(
&result_cert->signatureWrap, issuer_pk, NULL);
tor_assert(cert_ok == SECSuccess);
}
#endif
err:
if (subject_spki)
SECKEY_DestroySubjectPublicKeyInfo(subject_spki);
if (request)
CERT_DestroyCertificateRequest(request);
if (validity)
CERT_DestroyValidity(validity);
// unnecessary, since these are allocated in the cert's arena.
//SECITEM_FreeItem(&der, PR_FALSE);
//SECITEM_FreeItem(&signed_der, PR_FALSE);
if (cert)
CERT_DestroyCertificate(cert);
return result_cert;
}
MOCK_IMPL(tor_x509_cert_impl_t *,
tor_tls_create_certificate,(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
const char *cname,
const char *cname_sign,
unsigned int cert_lifetime))
{
tor_assert(rsa);
tor_assert(rsa_sign);
tor_assert(cname);
tor_assert(cname_sign);
char *cname_rfc_1485 = NULL, *cname_sign_rfc_1485 = NULL;
CERTName *subject_dn = NULL, *issuer_dn = NULL;
time_t start_time;
time_t end_time;
CERTCertificate *result = NULL;
tor_asprintf(&cname_rfc_1485, "CN=%s", cname);
tor_asprintf(&cname_sign_rfc_1485, "CN=%s", cname_sign);
subject_dn = CERT_AsciiToName(cname_rfc_1485);
issuer_dn = CERT_AsciiToName(cname_sign_rfc_1485);
if (!subject_dn || !issuer_dn)
goto err;
tor_tls_pick_certificate_lifetime(time(NULL), cert_lifetime,
&start_time, &end_time);
result = tor_tls_create_certificate_internal(rsa,
rsa_sign,
subject_dn,
issuer_dn,
start_time,
end_time);
err:
tor_free(cname_rfc_1485);
tor_free(cname_sign_rfc_1485);
if (subject_dn)
CERT_DestroyName(subject_dn);
if (issuer_dn)
CERT_DestroyName(issuer_dn);
return result;
}
/** 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(cert->cert);
tor_assert(encoded_out);
tor_assert(size_out);
const SECItem *item = &cert->cert->derCert;
*encoded_out = item->data;
*size_out = (size_t)item->len;
}
void
tor_x509_cert_impl_free_(tor_x509_cert_impl_t *cert)
{
if (cert)
CERT_DestroyCertificate(cert);
}
tor_x509_cert_impl_t *
tor_x509_cert_impl_dup_(tor_x509_cert_impl_t *cert)
{
if (cert)
return CERT_DupCertificate(cert);
else
return NULL;
}
/**
* As tor_x509_cert_decode, but return the NSS certificate type
*/
static tor_x509_cert_impl_t *
tor_x509_cert_decode_internal(const uint8_t *certificate,
int certificate_len)
{
tor_assert(certificate);
if (certificate_len > INT_MAX)
return NULL;
SECItem der = { .type = siBuffer,
.data = (unsigned char *)certificate,
.len = certificate_len };
CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
tor_assert(certdb);
return CERT_NewTempCertificate(certdb,
&der,
NULL /* nickname */,
PR_FALSE, /* isPerm */
PR_TRUE /* CopyDER */);
}
tor_x509_cert_t *
tor_x509_cert_decode(const uint8_t *certificate,
size_t certificate_len)
{
CERTCertificate *cert = tor_x509_cert_decode_internal(certificate,
(int)certificate_len);
if (! cert) {
crypto_nss_log_errors(LOG_INFO, "decoding certificate");
return NULL;
}
tor_x509_cert_t *newcert = tor_x509_cert_new(cert);
return newcert;
}
crypto_pk_t *
tor_tls_cert_get_key(tor_x509_cert_t *cert)
{
tor_assert(cert);
CERTSubjectPublicKeyInfo *spki = &cert->cert->subjectPublicKeyInfo;
SECKEYPublicKey *pub = SECKEY_ExtractPublicKey(spki); // we own this pointer
if (pub == NULL)
return NULL;
if (SECKEY_GetPublicKeyType(pub) != rsaKey) {
SECKEY_DestroyPublicKey(pub);
return NULL;
}
return crypto_pk_new_from_nss_pubkey(pub);
}
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)
{
int result = 0;
tor_assert(cert);
tor_assert(signing_cert);
SECKEYPublicKey *pk = CERT_ExtractPublicKey(signing_cert->cert);
if (pk == NULL) {
log_fn(severity, LD_CRYPTO,
"Invalid certificate: could not extract issuer key");
goto fail;
}
SECStatus s = CERT_VerifySignedDataWithPublicKey(&cert->cert->signatureWrap,
pk, NULL);
if (s != SECSuccess) {
log_fn(severity, LD_CRYPTO,
"Invalid certificate: could not validate signature.");
goto fail;
}
if (tor_x509_check_cert_lifetime_internal(severity,
cert->cert,
now,
TOR_X509_PAST_SLOP,
TOR_X509_FUTURE_SLOP) < 0)
goto fail;
if (check_rsa_1024) {
/* We require that this is a 1024-bit RSA key, for legacy reasons .:p */
if (SECKEY_GetPublicKeyType(pk) != rsaKey ||
SECKEY_PublicKeyStrengthInBits(pk) != 1024) {
log_fn(severity, LD_CRYPTO, "Invalid certificate: Key is not RSA1024.");
goto fail;
}
} else {
/* We require that this key is at least minimally strong. */
unsigned min_bits = (SECKEY_GetPublicKeyType(pk) == ecKey) ? 128: 1024;
if (SECKEY_PublicKeyStrengthInBits(pk) < min_bits) {
log_fn(severity, LD_CRYPTO, "Invalid certificate: Key is too weak.");
goto fail;
}
}
/* The certificate is valid. */
result = 1;
fail:
if (pk)
SECKEY_DestroyPublicKey(pk);
return result;
}
static void
log_cert_lifetime(int severity,
const char *status,
time_t now,
PRTime notBefore,
PRTime notAfter)
{
log_fn(severity, LD_GENERAL,
"Certificate %s. Either their clock is set wrong, or your clock "
"is incorrect.", status);
char nowbuf[ISO_TIME_LEN+1];
char nbbuf[ISO_TIME_LEN+1];
char nabuf[ISO_TIME_LEN+1];
format_iso_time(nowbuf, now);
format_iso_time(nbbuf, notBefore / PRTIME_PER_SEC);
format_iso_time(nabuf, notAfter / PRTIME_PER_SEC);
log_fn(severity, LD_GENERAL,
"(The certificate is valid from %s until %s. Your time is %s.)",
nbbuf, nabuf, nowbuf);
}
int
tor_x509_check_cert_lifetime_internal(int severity,
const tor_x509_cert_impl_t *cert,
time_t now,
int past_tolerance,
int future_tolerance)
{
tor_assert(cert);
PRTime notBefore=0, notAfter=0;
int64_t t;
SECStatus r = CERT_GetCertTimes(cert, &notBefore, &notAfter);
if (r != SECSuccess) {
log_fn(severity, LD_CRYPTO,
"Couldn't get validity times from certificate");
return -1;
}
t = ((int64_t)now) + future_tolerance;
t *= PRTIME_PER_SEC;
if (notBefore > t) {
log_cert_lifetime(severity, "not yet valid", now,
notBefore, notAfter);
return -1;
}
t = ((int64_t)now) - past_tolerance;
t *= PRTIME_PER_SEC;
if (notAfter < t) {
log_cert_lifetime(severity, "already expired", now,
notBefore, notAfter);
return -1;
}
return 0;
}
#ifdef TOR_UNIT_TESTS
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)
{
tor_assert(inp);
tor_assert(signing_key);
PRTime notBefore=0, notAfter=0;
SECStatus r = CERT_GetCertTimes(inp->cert, &notBefore, &notAfter);
if (r != SECSuccess)
return NULL;
time_t start_time = notBefore / PRTIME_PER_SEC;
if (new_expiration_time < start_time) {
/* This prevents an NSS error. */
start_time = new_expiration_time - 10;
}
crypto_pk_t *subject_key = tor_tls_cert_get_key((tor_x509_cert_t *)inp);
if (!subject_key)
return NULL;
CERTCertificate *newcert;
newcert = tor_tls_create_certificate_internal(subject_key,
signing_key,
&inp->cert->subject,
&inp->cert->issuer,
start_time,
new_expiration_time);
crypto_pk_free(subject_key);
return newcert ? tor_x509_cert_new(newcert) : NULL;
}
#endif
+461
View File
@@ -0,0 +1,461 @@
/* 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 x509_openssl.c
* \brief Wrapper functions to present a consistent interface to
* X.509 functions from OpenSSL.
**/
#define TOR_X509_PRIVATE
#include "lib/tls/x509.h"
#include "lib/tls/x509_internal.h"
#include "lib/tls/tortls.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/crypt_ops/compat_openssl.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/err.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
ENABLE_GCC_WARNING(redundant-decls)
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/ctime/di_ops.h"
#include "lib/encoding/time_fmt.h"
#include <stdlib.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
/** 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(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();
time_t now = time(NULL);
tor_tls_pick_certificate_lifetime(now, cert_lifetime,
&start_time, &end_time);
tor_assert(rsa);
tor_assert(cname);
tor_assert(rsa_sign);
tor_assert(cname_sign);
if (!(sign_pkey = crypto_pk_get_openssl_evp_pkey_(rsa_sign,1)))
goto error;
if (!(pkey = crypto_pk_get_openssl_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
}
/** Set the 'encoded' and 'encoded_len' fields of "cert" from cert->cert. */
int
tor_x509_cert_set_cached_der_encoding(tor_x509_cert_t *cert)
{
unsigned char *buf = NULL;
int length = i2d_X509(cert->cert, &buf);
if (length <= 0 || buf == NULL) {
return -1;
}
cert->encoded_len = (size_t) length;
cert->encoded = tor_malloc(length);
memcpy(cert->encoded, buf, length);
OPENSSL_free(buf);
return 0;
}
void
tor_x509_cert_impl_free_(tor_x509_cert_impl_t *cert)
{
if (cert)
X509_free(cert);
}
tor_x509_cert_impl_t *
tor_x509_cert_impl_dup_(tor_x509_cert_impl_t *cert)
{
if (cert)
return X509_dup(cert);
else
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;
}
/** 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;
}
/**
* 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_openssl_rsa_(rsa);
EVP_PKEY_free(pkey);
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 (tor_x509_check_cert_lifetime_internal(severity, cert->cert, now,
TOR_X509_PAST_SLOP,
TOR_X509_FUTURE_SLOP) < 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;
} else {
log_fn(severity, LD_CRYPTO, "Invalid certificate: Key is not RSA1024.");
}
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;
}
/** 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: 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. */
int
tor_x509_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_openssl_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) */
+1
View File
@@ -172,6 +172,7 @@ pub fn main() {
cfg.from_cflags("TOR_ZLIB_LIBS");
cfg.from_cflags("TOR_LIB_MATH");
cfg.from_cflags("NSS_LIBS");
cfg.from_cflags("TOR_OPENSSL_LIBS");
cfg.from_cflags("TOR_LIBEVENT_LIBS");
cfg.from_cflags("TOR_LIB_WS32");
+11 -3
View File
@@ -13,11 +13,14 @@
#include "core/or/or.h"
#include "core/crypto/onion_tap.h"
#include "core/crypto/relay_crypto.h"
#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/obj_mac.h>
#endif
#include "core/or/circuitlist.h"
#include "app/config/config.h"
@@ -33,6 +36,7 @@
#include "core/or/or_circuit_st.h"
#include "lib/crypt_ops/digestset.h"
#include "lib/crypt_ops/crypto_init.h"
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
static uint64_t nanostart;
@@ -579,6 +583,7 @@ bench_dh(void)
" %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
}
#ifdef ENABLE_OPENSSL
static void
bench_ecdh_impl(int nid, const char *name)
{
@@ -628,6 +633,7 @@ bench_ecdh_p224(void)
{
bench_ecdh_impl(NID_secp224r1, "P-224");
}
#endif
typedef void (*bench_fn)(void);
@@ -651,8 +657,11 @@ static struct benchmark_t benchmarks[] = {
ENT(cell_aes),
ENT(cell_ops),
ENT(dh),
#ifdef ENABLE_OPENSSL
ENT(ecdh_p256),
ENT(ecdh_p224),
#endif
{NULL,NULL,0}
};
@@ -680,9 +689,9 @@ main(int argc, const char **argv)
tor_threads_init();
tor_compress_init();
init_logging(1);
if (argc == 4 && !strcmp(argv[1], "diff")) {
init_logging(1);
const int N = 200;
char *f1 = read_file_to_str(argv[2], RFTS_BIN, NULL);
char *f2 = read_file_to_str(argv[3], RFTS_BIN, NULL);
@@ -718,13 +727,12 @@ main(int argc, const char **argv)
reset_perftime();
if (crypto_seed_rng() < 0) {
if (crypto_global_init(0, NULL, NULL) < 0) {
printf("Couldn't seed RNG; exiting.\n");
return 1;
}
init_protocol_warning_severity_level();
crypto_init_siphash_key();
options = options_new();
init_logging(1);
options->command = CMD_RUN_UNITTESTS;
+10 -5
View File
@@ -7,8 +7,8 @@
#include "app/config/config.h"
#include "test/fuzz/fuzzing.h"
#include "lib/compress/compress.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_init.h"
static or_options_t *mock_options = NULL;
static const or_options_t *
@@ -96,15 +96,20 @@ global_init(void)
{
tor_threads_init();
tor_compress_init();
{
struct sipkey sipkey = { 1337, 7331 };
siphash_set_global_key(&sipkey);
}
/* Initialise logging first */
init_logging(1);
configure_backtrace_handler(get_version());
if (crypto_global_init(0, NULL, NULL) < 0)
abort();
{
struct sipkey sipkey = { 1337, 7331 };
siphash_unset_global_key();
siphash_set_global_key(&sipkey);
}
/* set up the options. */
mock_options = tor_malloc_zero(sizeof(or_options_t));
MOCK(get_options, mock_get_options);
+2 -2
View File
@@ -5,12 +5,12 @@ FUZZING_CPPFLAGS = \
FUZZING_CFLAGS = \
$(AM_CFLAGS) $(TEST_CFLAGS)
FUZZING_LDFLAG = \
@TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
@TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@
FUZZING_LIBS = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ \
+23 -12
View File
@@ -118,7 +118,6 @@ src_test_test_SOURCES += \
src/test/test_controller_events.c \
src/test/test_crypto.c \
src/test/test_crypto_ope.c \
src/test/test_crypto_openssl.c \
src/test/test_data.c \
src/test/test_dir.c \
src/test/test_dir_common.c \
@@ -151,6 +150,7 @@ src_test_test_SOURCES += \
src/test/test_oom.c \
src/test/test_oos.c \
src/test/test_options.c \
src/test/test_pem.c \
src/test/test_periodic_event.c \
src/test/test_policy.c \
src/test/test_procmon.c \
@@ -178,11 +178,21 @@ src_test_test_SOURCES += \
src/test/test_util_format.c \
src/test/test_util_process.c \
src/test/test_voting_schedule.c \
src/test/test_x509.c \
src/test/test_helpers.c \
src/test/test_dns.c \
src/test/testing_common.c \
src/test/testing_rsakeys.c \
src/ext/tinytest.c
if USE_NSS
# ...
else
src_test_test_SOURCES += \
src/test/test_crypto_openssl.c \
src/test/test_tortls_openssl.c
endif
endif
src_test_test_slow_SOURCES =
@@ -226,13 +236,13 @@ src_test_test_switch_id_LDADD = \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_test_LDADD = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
@@ -249,23 +259,23 @@ src_test_test_memwipe_LDADD = $(src_test_test_LDADD)
# successfully with the libraries built with them.
src_test_test_memwipe_LDFLAGS = $(src_test_test_LDFLAGS) @CFLAGS_BUGTRAP@
src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_bench_LDADD = \
$(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_test_workqueue_LDADD = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
@@ -277,7 +287,7 @@ src_test_test_timers_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
@TOR_LZMA_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
@@ -291,6 +301,7 @@ noinst_HEADERS+= \
src/test/test_helpers.h \
src/test/test_dir_common.h \
src/test/test_connection.h \
src/test/test_tortls.h \
src/test/test_descriptors.inc \
src/test/example_extrainfo.inc \
src/test/failing_routerdescs.inc \
@@ -302,22 +313,22 @@ noinst_HEADERS+= \
noinst_PROGRAMS+= src/test/test-ntor-cl
noinst_PROGRAMS+= src/test/test-hs-ntor-cl
src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c
src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_test_test_ntor_cl_LDADD = \
$(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_LZMA_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
src_test_test_hs_ntor_cl_SOURCES = src/test/test_hs_ntor_cl.c
src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_test_test_hs_ntor_cl_LDADD = \
$(TOR_INTERNAL_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
+19 -18
View File
@@ -33,7 +33,7 @@ void mock_dump_saved_logs(void);
#define assert_log_predicate(predicate, failure_msg) \
do { \
if (!(predicate)) { \
tt_fail_msg((failure_msg)); \
TT_FAIL(failure_msg); \
mock_dump_saved_logs(); \
TT_EXIT_TEST_FUNCTION; \
} \
@@ -41,74 +41,75 @@ void mock_dump_saved_logs(void);
#define expect_log_msg(str) \
assert_log_predicate(mock_saved_log_has_message(str), \
"expected log to contain " # str);
("expected log to contain \"%s\"", str));
#define expect_log_msg_containing(str) \
assert_log_predicate(mock_saved_log_has_message_containing(str), \
"expected log to contain " # str);
("expected log to contain \"%s\"", str));
#define expect_log_msg_not_containing(str) \
assert_log_predicate(mock_saved_log_has_message_not_containing(str), \
"expected log to not contain " # str);
("expected log to not contain \"%s\"", str));
#define expect_log_msg_containing_either(str1, str2) \
assert_log_predicate(mock_saved_log_has_message_containing(str1) || \
mock_saved_log_has_message_containing(str2), \
"expected log to contain " # str1 " or " # str2);
("expected log to contain \"%s\" or \"%s\"", str1, str2));
#define expect_log_msg_containing_either3(str1, str2, str3) \
assert_log_predicate(mock_saved_log_has_message_containing(str1) || \
mock_saved_log_has_message_containing(str2) || \
mock_saved_log_has_message_containing(str3), \
"expected log to contain " # str1 " or " # str2 \
" or " # str3);
("expected log to contain \"%s\" or \"%s\" or \"%s\"", \
str1, str2, str3))
#define expect_log_msg_containing_either4(str1, str2, str3, str4) \
assert_log_predicate(mock_saved_log_has_message_containing(str1) || \
mock_saved_log_has_message_containing(str2) || \
mock_saved_log_has_message_containing(str3) || \
mock_saved_log_has_message_containing(str4), \
"expected log to contain " # str1 " or " # str2 \
" or " # str3 " or " # str4);
("expected log to contain \"%s\" or \"%s\" or \"%s\" or \"%s\"", \
str1, str2, str3, str4))
#define expect_single_log_msg(str) \
do { \
\
assert_log_predicate(mock_saved_log_has_message_containing(str) && \
mock_saved_log_n_entries() == 1, \
"expected log to contain exactly 1 message " # str); \
("expected log to contain exactly 1 message \"%s\"", \
str)); \
} while (0);
#define expect_single_log_msg_containing(str) \
do { \
assert_log_predicate(mock_saved_log_has_message_containing(str)&& \
mock_saved_log_n_entries() == 1 , \
"expected log to contain 1 message, containing " # str); \
("expected log to contain 1 message, containing \"%s\"",\
str)); \
} while (0);
#define expect_no_log_msg(str) \
assert_log_predicate(!mock_saved_log_has_message(str), \
"expected log to not contain " # str);
("expected log to not contain \"%s\"",str));
#define expect_no_log_msg_containing(str) \
assert_log_predicate(!mock_saved_log_has_message_containing(str), \
"expected log to not contain " # str);
("expected log to not contain \"%s\"", str));
#define expect_log_severity(severity) \
assert_log_predicate(mock_saved_log_has_severity(severity), \
"expected log to contain severity " # severity);
("expected log to contain severity " # severity));
#define expect_no_log_severity(severity) \
assert_log_predicate(!mock_saved_log_has_severity(severity), \
"expected log to not contain severity " # severity);
("expected log to not contain severity " # severity));
#define expect_log_entry() \
assert_log_predicate(mock_saved_log_has_entry(), \
"expected log to contain entries");
("expected log to contain entries"));
#define expect_no_log_entry() \
assert_log_predicate(!mock_saved_log_has_entry(), \
"expected log to not contain entries");
("expected log to not contain entries"));
#endif /* !defined(TOR_LOG_TEST_HELPERS_H) */
+5
View File
@@ -9,6 +9,7 @@
#include "lib/evloop/compat_libevent.h"
#include "lib/evloop/timers.h"
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/log/util_bug.h"
#include "lib/time/compat_time.h"
@@ -62,6 +63,10 @@ main(int argc, char **argv)
memset(&cfg, 0, sizeof(cfg));
tor_libevent_initialize(&cfg);
timers_initialize();
init_logging(1);
if (crypto_global_init(0, NULL, NULL) < 0)
return 1;
int i;
int ret;
+7
View File
@@ -860,7 +860,10 @@ struct testgroup_t testgroups[] = {
{ "control/event/", controller_event_tests },
{ "crypto/", crypto_tests },
{ "crypto/ope/", crypto_ope_tests },
#ifdef ENABLE_OPENSSL
{ "crypto/openssl/", crypto_openssl_tests },
#endif
{ "crypto/pem/", pem_tests },
{ "dir/", dir_tests },
{ "dir_handle_get/", dir_handle_get_tests },
{ "dir/md/", microdesc_tests },
@@ -912,6 +915,10 @@ struct testgroup_t testgroups[] = {
{ "status/" , status_tests },
{ "storagedir/", storagedir_tests },
{ "tortls/", tortls_tests },
#ifndef ENABLE_NSS
{ "tortls/openssl/", tortls_openssl_tests },
#endif
{ "tortls/x509/", x509_tests },
{ "util/", util_tests },
{ "util/format/", util_format_tests },
{ "util/logging/", logging_tests },
+3
View File
@@ -234,6 +234,7 @@ extern struct testcase_t nodelist_tests[];
extern struct testcase_t oom_tests[];
extern struct testcase_t oos_tests[];
extern struct testcase_t options_tests[];
extern struct testcase_t pem_tests[];
extern struct testcase_t periodic_event_tests[];
extern struct testcase_t policy_tests[];
extern struct testcase_t procmon_tests[];
@@ -256,6 +257,7 @@ extern struct testcase_t socks_tests[];
extern struct testcase_t status_tests[];
extern struct testcase_t thread_tests[];
extern struct testcase_t tortls_tests[];
extern struct testcase_t tortls_openssl_tests[];
extern struct testcase_t util_tests[];
extern struct testcase_t util_format_tests[];
extern struct testcase_t util_process_tests[];
@@ -263,6 +265,7 @@ extern struct testcase_t voting_schedule_tests[];
extern struct testcase_t dns_tests[];
extern struct testcase_t handle_tests[];
extern struct testcase_t sr_tests[];
extern struct testcase_t x509_tests[];
extern struct testcase_t slow_crypto_tests[];
extern struct testcase_t slow_util_tests[];
+1 -1
View File
@@ -161,7 +161,7 @@ test_add_onion_helper_keyarg_v2(void *arg)
/* Test loading a RSA1024 key. */
tor_free(err_msg);
pk1 = pk_generate(0);
tt_int_op(0, OP_EQ, crypto_pk_base64_encode(pk1, &encoded));
tt_int_op(0, OP_EQ, crypto_pk_base64_encode_private(pk1, &encoded));
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
&pk, &hs_version, &err_msg);
+122 -5
View File
@@ -16,7 +16,9 @@
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_hkdf.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_init.h"
#include "ed25519_vectors.inc"
#include "test/log_test_helpers.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
@@ -25,6 +27,13 @@
#include <unistd.h>
#endif
#if defined(ENABLE_OPENSSL)
#include "lib/crypt_ops/compat_openssl.h"
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/dh.h>
ENABLE_GCC_WARNING(redundant-decls)
#endif
/** Run unit tests for Diffie-Hellman functionality. */
static void
test_crypto_dh(void *arg)
@@ -37,6 +46,11 @@ test_crypto_dh(void *arg)
char s1[DH1024_KEY_LEN];
char s2[DH1024_KEY_LEN];
ssize_t s1len, s2len;
#ifdef ENABLE_OPENSSL
crypto_dh_t *dh3 = NULL;
DH *dh4 = NULL;
BIGNUM *pubkey_tmp = NULL;
#endif
(void)arg;
tt_int_op(crypto_dh_get_bytes(dh1),OP_EQ, DH1024_KEY_LEN);
@@ -91,6 +105,10 @@ test_crypto_dh(void *arg)
s1len = crypto_dh_compute_secret(LOG_WARN, dh1, "\x02", 1, s1, 50);
tt_int_op(50, OP_EQ, s1len);
/* 2 a second time is still okay, though weird. */
s1len = crypto_dh_compute_secret(LOG_WARN, dh1, "\x02", 1, s1, 50);
tt_int_op(50, OP_EQ, s1len);
const char P[] =
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
@@ -157,16 +175,59 @@ test_crypto_dh(void *arg)
tt_int_op(s1len, OP_EQ, -1);
}
#if defined(ENABLE_OPENSSL)
{
/* Make sure that our crypto library can handshake with openssl. */
dh3 = crypto_dh_new(DH_TYPE_TLS);
tt_assert(!crypto_dh_get_public(dh3, p1, DH1024_KEY_LEN));
dh4 = crypto_dh_new_openssl_tls();
tt_assert(DH_generate_key(dh4));
const BIGNUM *pk=NULL;
#ifdef OPENSSL_1_1_API
const BIGNUM *sk=NULL;
DH_get0_key(dh4, &pk, &sk);
#else
pk = dh4->pub_key;
#endif
tt_assert(pk);
tt_int_op(BN_num_bytes(pk), OP_LE, DH1024_KEY_LEN);
tt_int_op(BN_num_bytes(pk), OP_GT, 0);
memset(p2, 0, sizeof(p2));
/* right-pad. */
BN_bn2bin(pk, (unsigned char *)(p2+DH1024_KEY_LEN-BN_num_bytes(pk)));
s1len = crypto_dh_handshake(LOG_WARN, dh3, p2, DH1024_KEY_LEN,
(unsigned char *)s1, sizeof(s1));
pubkey_tmp = BN_bin2bn((unsigned char *)p1, DH1024_KEY_LEN, NULL);
s2len = DH_compute_key((unsigned char *)s2, pubkey_tmp, dh4);
tt_int_op(s1len, OP_EQ, s2len);
tt_int_op(s1len, OP_GT, 0);
tt_mem_op(s1, OP_EQ, s2, s1len);
}
#endif
done:
crypto_dh_free(dh1);
crypto_dh_free(dh2);
crypto_dh_free(dh1_dup);
#ifdef ENABLE_OPENSSL
crypto_dh_free(dh3);
if (dh4)
DH_free(dh4);
if (pubkey_tmp)
BN_free(pubkey_tmp);
#endif
}
static void
test_crypto_openssl_version(void *arg)
{
(void)arg;
#ifdef ENABLE_NSS
tt_skip();
#else
const char *version = crypto_openssl_get_version_str();
const char *h_version = crypto_openssl_get_header_version_str();
tt_assert(version);
@@ -186,6 +247,7 @@ test_crypto_openssl_version(void *arg)
tt_int_op(a, OP_GE, 0);
tt_int_op(b, OP_GE, 0);
tt_int_op(c, OP_GE, 0);
#endif
done:
;
@@ -1363,22 +1425,22 @@ test_crypto_pk_base64(void *arg)
/* Test Base64 encoding a key. */
pk1 = pk_generate(0);
tt_assert(pk1);
tt_int_op(0, OP_EQ, crypto_pk_base64_encode(pk1, &encoded));
tt_int_op(0, OP_EQ, crypto_pk_base64_encode_private(pk1, &encoded));
tt_assert(encoded);
/* Test decoding a valid key. */
pk2 = crypto_pk_base64_decode(encoded, strlen(encoded));
pk2 = crypto_pk_base64_decode_private(encoded, strlen(encoded));
tt_assert(pk2);
tt_int_op(crypto_pk_cmp_keys(pk1, pk2), OP_EQ, 0);
crypto_pk_free(pk2);
/* Test decoding a invalid key (not Base64). */
static const char *invalid_b64 = "The key is in another castle!";
pk2 = crypto_pk_base64_decode(invalid_b64, strlen(invalid_b64));
pk2 = crypto_pk_base64_decode_private(invalid_b64, strlen(invalid_b64));
tt_ptr_op(pk2, OP_EQ, NULL);
/* Test decoding a truncated Base64 blob. */
pk2 = crypto_pk_base64_decode(encoded, strlen(encoded)/2);
pk2 = crypto_pk_base64_decode_private(encoded, strlen(encoded)/2);
tt_ptr_op(pk2, OP_EQ, NULL);
done:
@@ -1427,6 +1489,58 @@ test_crypto_pk_pem_encrypted(void *arg)
done:
crypto_pk_free(pk);
}
static void
test_crypto_pk_invalid_private_key(void *arg)
{
(void)arg;
/* Here is a simple invalid private key: it was produced by making
* a regular private key, and then adding 2 to the modulus. */
const char pem[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpQIBAAKCAQEAskRyZrs+YAukvBmZlgo6/rCxyKF2xyUk073ap+2CgRUnSfGG\n"
"mflHlzqVq7tpH50DafpS+fFAbaEaNV/ac20QG0rUZi38HTB4qURWOu6n0Bws6E4l\n"
"UX/AkvDlWnuYH0pHHi2c3DGNFjwoJpjKuUTk+cRffVR8X3Kjr62SUDUaBNW0Kecz\n"
"3SYLbmgmZI16dFZ+g9sNM3znXZbhvb33WwPqpZSSPs37cPgF7eS6mAw/gUMx6zfE\n"
"HRmUnOQSzUdS05rvc/hsiCLhiIZ8hgfkD07XnTT1Ds8DwE55k7BUWY2wvwWCNLsH\n"
"qtqAxTr615XdkMxVkYgImpqPybarpfNYhFqkOwIDAQABAoIBACPC3VxEdbfYvhxJ\n"
"2mih9sG++nswAN7kUaX0cRe86rAwaShJPmJHApiQ1ROVTfpciiHJaLnhLraPWe2Z\n"
"I/6Bw3hmI4O399p3Lc1u+wlpdNqnvE6B1rSptx0DHE9xecvVH70rE0uM2Su7t6Y+\n"
"gnR2IKUGQs2mlCilm7aTUEWs0WJkkl4CG1dyxItuOSdNBjOEzXimJyiB10jEBFsp\n"
"SZeCF2FZ7AJbck5CVC42+oTsiDbZrHTHOn7v26rFGdONeHD1wOI1v7JwHFpCB923\n"
"aEHBzsPbMeq7DWG1rjzCYpcXHhTDBDBWSia4SEhyr2Nl7m7qxWWWwR+x4dqAj3rD\n"
"HeTmos0CgYEA6uf1CLpjPpOs5IaW1DQI8dJA/xFEAC/6GVgq4nFOGHZrm8G3L5o+\n"
"qvtQNMpDs2naWuZpqROFqv24o01DykHygR72GlPIY6uvmmf5tvJLoGnbFUay33L4\n"
"7b9dkNhuEIBNPzVDie0pgS77WgaPbYkVv5fnDwgPuVnkqfakEt7Pz2MCgYEAwkZ5\n"
"R1wLuTQEA2Poo6Gf4L8Bg6yNYI46LHDqDIs818iYLjtcnEEvbPfaoKNpOn7s7s4O\n"
"Pc+4HnT1aIQs0IKVLRTp+5a/9wfOkPZnobWOUHZk9UzBL3Hc1uy/qhp93iE3tSzx\n"
"v0O1pvR+hr3guTCZx8wZnDvaMgG3hlyPnVlHdrMCgYEAzQQxGbMC1ySv6quEjCP2\n"
"AogMbhE1lixJTUFj/EoDbNo9xKznIkauly/Lqqc1OysRhfA/G2+MY9YZBX1zwtyX\n"
"uBW7mPKynDrFgi9pBECnvJNmwET57Ic9ttIj6Tzbos83nAjyrzgr1zGX8dRz7ZeN\n"
"QbBj2vygLJbGOYinXkjUeh0CgYEAhN5aF9n2EqZmkEMGWtMxWy6HRJ0A3Cap1rcq\n"
"+4VHCXWhzwy+XAeg/e/N0MuyLlWcif7XcqLcE8h+BwtO8xQ8HmcNWApUJAls12wO\n"
"mGRpftJaXgIupdpD5aJpu1b++qrRRNIGTH9sf1D8L/8w8LcylZkbcuTkaAsQj45C\n"
"kqT64U0CgYEAq47IKS6xc3CDc17BqExR6t+1yRe+4ml+z1zcVbfUKony4pGvl1yo\n"
"rk0IYDN5Vd8h5xtXrkPdX9h+ywmohnelDKsayEuE+opyqEpSU4/96Bb22RZUoucb\n"
"LWkV5gZx5hFnDFtEd4vadMIiY4jVv/3JqiZDKwMVBJKlHRXJEEmIEBk=\n"
"-----END RSA PRIVATE KEY-----\n";
crypto_pk_t *pk = NULL;
pk = crypto_pk_new();
setup_capture_of_logs(LOG_WARN);
tt_int_op(-1, OP_EQ,
crypto_pk_read_private_key_from_string(pk, pem, strlen(pem)));
#ifdef ENABLE_NSS
expect_single_log_msg_containing("received bad data");
#else
expect_single_log_msg_containing("while checking RSA key");
#endif
done:
teardown_capture_of_logs();
crypto_pk_free(pk);
}
#ifdef HAVE_TRUNCATE
#define do_truncate truncate
#else
@@ -1462,7 +1576,8 @@ test_crypto_digests(void *arg)
(void)arg;
k = crypto_pk_new();
tt_assert(k);
r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_3, -1);
r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_3,
strlen(AUTHORITY_SIGNKEY_3));
tt_assert(!r);
r = crypto_pk_get_digest(k, digest);
@@ -3047,6 +3162,8 @@ struct testcase_t crypto_tests[] = {
{ "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL },
{ "pk_base64", test_crypto_pk_base64, TT_FORK, NULL, NULL },
{ "pk_pem_encrypted", test_crypto_pk_pem_encrypted, TT_FORK, NULL, NULL },
{ "pk_invalid_private_key", test_crypto_pk_invalid_private_key, 0,
NULL, NULL },
CRYPTO_LEGACY(digests),
{ "digest_names", test_crypto_digest_names, 0, NULL, NULL },
{ "sha3", test_crypto_sha3, TT_FORK, NULL, NULL},
+3 -1
View File
@@ -7,9 +7,11 @@
#define CRYPTO_OPE_PRIVATE
#include "lib/cc/compat_compiler.h"
#include "lib/crypt_ops/crypto_ope.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/encoding/binascii.h"
#include "lib/malloc/malloc.h"
#include "test/test.h"
#include "tinytest.h"
+2
View File
@@ -18,7 +18,9 @@
#include <libscrypt.h>
#endif
#ifdef ENABLE_OPENSSL
#include <openssl/evp.h>
#endif
/** Run unit tests for our secret-to-key passphrase hashing functionality. */
static void
+1 -1
View File
@@ -2102,6 +2102,7 @@ test_dir_handle_get_status_vote_d(void* data)
clear_dir_servers();
dirvote_free_all();
routerlist_free_all();
}
static void
@@ -2638,4 +2639,3 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(parse_accept_encoding, 0),
END_OF_TESTCASES
};
+1 -1
View File
@@ -21,7 +21,7 @@
#include "test/hs_test_helpers.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "core/or/channeltls.h"
#include "feature/dircache/directory.h"
+6 -1
View File
@@ -14,10 +14,11 @@
#define ONION_NTOR_PRIVATE
#include "core/or/or.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_init.h"
#include "core/crypto/hs_ntor.h"
#include "core/crypto/onion_ntor.h"
@@ -240,7 +241,11 @@ main(int argc, char **argv)
return 1;
}
init_logging(1);
curve25519_init();
if (crypto_global_init(0, NULL, NULL) < 0)
return 1;
if (!strcmp(argv[1], "client1")) {
return client1(argc, argv);
} else if (!strcmp(argv[1], "server1")) {
+1 -1
View File
@@ -2,7 +2,7 @@
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "core/or/or.h"
#include "test/test.h"
+27 -7
View File
@@ -24,7 +24,9 @@
#include "core/or/or_handshake_state_st.h"
#include "core/or/var_cell_st.h"
#define TOR_X509_PRIVATE
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
@@ -793,11 +795,26 @@ CERTS_FAIL(bad_rsa_id_cert, /*ed25519*/
{
require_failure_message = "legacy RSA ID certificate was not valid";
certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 1);
uint8_t *body = certs_cell_cert_getarray_body(cert);
ssize_t body_len = certs_cell_cert_getlen_body(cert);
/* Frob a byte in the signature */
body[body_len - 13] ^= 7;
uint8_t *body;
/* Frob a byte in the signature, after making a new cert. (NSS won't let
* us just frob the old cert, since it will see that the issuer & serial
* number are the same, which will make it fail at an earlier stage than
* signature verification.) */
const tor_x509_cert_t *idc;
tor_x509_cert_t *newc;
tor_tls_get_my_certs(1, NULL, &idc);
time_t new_end = time(NULL) + 86400 * 10;
newc = tor_x509_cert_replace_expiration(idc, new_end, d->key2);
const uint8_t *encoded;
size_t encoded_len;
tor_x509_cert_get_der(newc, &encoded, &encoded_len);
certs_cell_cert_setlen_body(cert, encoded_len);
certs_cell_cert_set_cert_len(cert, encoded_len);
body = certs_cell_cert_getarray_body(cert);
memcpy(body, encoded, encoded_len);
body[encoded_len - 13] ^= 7;
REENCODE();
tor_x509_cert_free(newc);
})
CERTS_FAIL(expired_rsa_id, /* both */
{
@@ -809,9 +826,12 @@ CERTS_FAIL(expired_rsa_id, /* both */
tor_x509_cert_t *newc;
time_t new_end = time(NULL) - 86400 * 10;
newc = tor_x509_cert_replace_expiration(idc, new_end, d->key2);
certs_cell_cert_setlen_body(cert, newc->encoded_len);
memcpy(certs_cell_cert_getarray_body(cert),
newc->encoded, newc->encoded_len);
const uint8_t *encoded;
size_t encoded_len;
tor_x509_cert_get_der(newc, &encoded, &encoded_len);
certs_cell_cert_setlen_body(cert, encoded_len);
certs_cell_cert_set_cert_len(cert, encoded_len);
memcpy(certs_cell_cert_getarray_body(cert), encoded, encoded_len);
REENCODE();
tor_x509_cert_free(newc);
})
+6 -2
View File
@@ -7,8 +7,9 @@
#define ONION_NTOR_PRIVATE
#include "core/or/or.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_init.h"
#include "core/crypto/onion_ntor.h"
#define N_ARGS(n) STMT_BEGIN { \
@@ -153,7 +154,11 @@ main(int argc, char **argv)
return 1;
}
init_logging(1);
curve25519_init();
if (crypto_global_init(0, NULL, NULL) < 0)
return 1;
if (!strcmp(argv[1], "client1")) {
return client1(argc, argv);
} else if (!strcmp(argv[1], "server1")) {
@@ -165,4 +170,3 @@ main(int argc, char **argv)
return 1;
}
}
+122
View File
@@ -0,0 +1,122 @@
/* 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 */
#include "orconfig.h"
#include "lib/encoding/pem.h"
#include "lib/cc/compat_compiler.h"
#include "lib/malloc/malloc.h"
#include "test/test.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static const char example_pre[] =
"Lest you get the wrong impression, we wombats "
"are not in the habit of tunneling madly about, without any supplies "
"or even a map."; /* -- Ursula Vernon, _Digger_ */
static const char expected[] =
"-----BEGIN WOMBAT QUOTE-----\n"
"TGVzdCB5b3UgZ2V0IHRoZSB3cm9uZyBpbXByZXNzaW9uLCB3ZSB3b21iYXRzIGFy\n"
"ZSBub3QgaW4gdGhlIGhhYml0IG9mIHR1bm5lbGluZyBtYWRseSBhYm91dCwgd2l0\n"
"aG91dCBhbnkgc3VwcGxpZXMgb3IgZXZlbiBhIG1hcC4=\n"
"-----END WOMBAT QUOTE-----\n";
static void
test_crypto_pem_encode(void *arg)
{
(void)arg;
char buf[4096];
int n = (int) pem_encoded_size(strlen(example_pre), "WOMBAT QUOTE");
int n2 = pem_encode(buf, sizeof(buf),
(const unsigned char *)example_pre, strlen(example_pre),
"WOMBAT QUOTE");
tt_int_op(strlen(buf)+1, OP_EQ, n);
tt_int_op(n2, OP_EQ, 0);
tt_str_op(buf, OP_EQ, expected);
/* Now make sure it succeeds if the buffer is exactly the length we want. */
memset(buf, 0, sizeof(buf));
n2 = pem_encode(buf, n, (const unsigned char *)example_pre,
strlen(example_pre), "WOMBAT QUOTE");
tt_int_op(n2, OP_EQ, 0);
tt_str_op(buf, OP_EQ, expected);
/* Make sure it fails if the buffer is too short. */
memset(buf, 0, sizeof(buf));
n2 = pem_encode(buf, n - 1, (const unsigned char *)example_pre,
strlen(example_pre), "WOMBAT QUOTE");
tt_int_op(n2, OP_EQ, -1);
done:
;
}
static void
test_crypto_pem_decode(void *arg)
{
(void)arg;
unsigned char buf[4096];
/* Try a straightforward decoding. */
int n = pem_decode(buf, sizeof(buf),
expected, strlen(expected),
"WOMBAT QUOTE");
tt_int_op(n, OP_EQ, strlen(example_pre));
tt_mem_op(buf, OP_EQ, example_pre, n);
/* Succeed if the buffer is exactly the right size. */
memset(buf, 0xff, sizeof(buf));
n = pem_decode(buf, strlen(example_pre),
expected, strlen(expected),
"WOMBAT QUOTE");
tt_int_op(n, OP_EQ, strlen(example_pre));
tt_mem_op(buf, OP_EQ, example_pre, n);
tt_int_op(buf[n], OP_EQ, 0xff);
/* Verify that it fails if the buffer is too small. */
memset(buf, 0xff, sizeof(buf));
n = pem_decode(buf, strlen(example_pre) - 1,
expected, strlen(expected),
"WOMBAT QUOTE");
tt_int_op(n, OP_EQ, -1);
/* Verify that it fails with an incorrect tag. */
memset(buf, 0xff, sizeof(buf));
n = pem_decode(buf, sizeof(buf),
expected, strlen(expected),
"QUOKKA VOTE");
tt_int_op(n, OP_EQ, -1);
/* Try truncated buffers of different sizes. */
size_t i;
for (i = 0; i <= strlen(expected); ++i) {
char *truncated = tor_memdup(expected, i);
n = pem_decode(buf, sizeof(buf),
truncated, i,
"WOMBAT QUOTE");
tor_free(truncated);
if (i < strlen(expected) - 1) {
tt_int_op(n, OP_EQ, -1);
} else {
tt_int_op(n, OP_EQ, strlen(example_pre));
}
}
done:
;
}
struct testcase_t pem_tests[] = {
{ "encode", test_crypto_pem_encode, 0, NULL, NULL },
{ "decode", test_crypto_pem_decode, 0, NULL, NULL },
END_OF_TESTCASES
};
+1 -1
View File
@@ -9,7 +9,7 @@
#include "core/mainloop/main.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_edge.h"
+2
View File
@@ -56,6 +56,8 @@ NS(router_get_my_routerinfo)(void)
&mock_routerinfo->onion_pkey_len);
mock_routerinfo->bandwidthrate = 9001;
mock_routerinfo->bandwidthburst = 9002;
crypto_pk_free(ident_key);
crypto_pk_free(tap_key);
}
return mock_routerinfo;
+1 -1
View File
@@ -9,7 +9,7 @@
#include "app/config/config.h"
#include "feature/relay/router.h"
#include "feature/relay/routerkeys.h"
#include "lib/crypt_ops/crypto.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_format.h"
#include "feature/nodelist/torcert.h"
#include "test/test.h"
+1 -1
View File
@@ -1318,7 +1318,7 @@ test_keep_commit(void *arg)
expect_log_msg_containing("doesn't match the commit value.");
expect_log_msg_containing("has an invalid reveal value.");
assert_log_predicate(mock_saved_log_n_entries() == 2,
"expected 2 log entries");
("expected 2 log entries"));
teardown_capture_of_logs();
memcpy(commit->hashed_reveal, place_holder.hashed_reveal,
sizeof(commit->hashed_reveal));
+275 -2592
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
/* Copyright (c) 2010-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TEST_TORTLS_H
#define TEST_TORTLS_H
tor_x509_cert_impl_t *read_cert_from(const char *str);
extern const char *notCompletelyValidCertString;
extern const char *validCertString;
extern const char *caCertString;
#endif

Some files were not shown because too many files have changed in this diff Show More