Merge branch 'dev' into duke
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
This issue tracker is only for technical issues related to hushd
|
||||
|
||||
General Hush questions and/or support requests and are best directed to [Discord](https://myhush.org/discord)
|
||||
General Hush questions and/or support requests and are best directed to [Telegram](https://hush.is/telegram_support)
|
||||
|
||||
### Describe the issue
|
||||
|
||||
37
README.md
37
README.md
@@ -4,8 +4,8 @@
|
||||
|
||||

|
||||
|
||||
HUSH (originally Zdash) is a code fork of [ZCash](https://z.cash/) which has
|
||||
it's own genesis block. It is not a fork of another network. Based on
|
||||
HUSH (originally Zdash) is a source code fork of [ZCash](https://z.cash/) and has
|
||||
it's own genesis block. It is not a chain fork of another coin. Based on
|
||||
Bitcoin's code, it intends to offer a far higher standard of privacy through a
|
||||
sophisticated zero-knowledge proving scheme that preserves confidentiality of
|
||||
transaction metadata.
|
||||
@@ -17,10 +17,12 @@ or more once the blockchain has reached a significant size.
|
||||
|
||||
**HUSH is unfinished and highly experimental.** Use at your own risk!
|
||||
|
||||
## Discord
|
||||
## Telegram
|
||||
|
||||
Please feel free to join us on Discord at https://myhush.org/discord
|
||||
There are many channels, some you might enjoy are #general, #support and #mining.
|
||||
Please feel free to join us on Telegram :
|
||||
* Main group: https://hush.is/telegram
|
||||
* Support group: https://hush.is/telegram_support
|
||||
* Mining group: https://hush.is/telegram_support
|
||||
|
||||
## Claiming Funds From Old Hush Wallets
|
||||
|
||||
@@ -43,7 +45,7 @@ with `t1` and now they begin with `R`.
|
||||
To see what an old HUSH v2 address looks like on the new chain, this online tool
|
||||
can be used: https://dexstats.info/addressconverter.php
|
||||
|
||||
or this command line tool: https://github.com/MyHush/hush3/blob/duke/contrib/convert_address.py
|
||||
or this command line tool: https://git.hush.is/hush/hush3/src/master/contrib/convert_address.py
|
||||
|
||||
|
||||
### Using an old wallet.dat
|
||||
@@ -94,31 +96,10 @@ You can also transport funds one address at a time via private keys.
|
||||
Agama Desktop Wallet WIF-to-WIF Tool can convert between old HUSH and new HUSH3
|
||||
private keys.
|
||||
|
||||
### Web Wallet Seed Phrase
|
||||
|
||||
Nothing needs to be done, and if you use the Hush web wallet with a seed phrase,
|
||||
you can unlock your new funds on the new Hush mainnet with the same seedphrase.
|
||||
|
||||
This web wallet is hosted on a best-effort basis to give newcomers an easy way
|
||||
to make addresses for mining and other uses. Please heed this advice to keep
|
||||
your funds safe:
|
||||
|
||||
* DO NOT USE FOR LARGE AMOUNTS, use a full node or light wallet
|
||||
* ALWAYS ACCESS VIA https://
|
||||
* DO NOT USE FROM PUBLIC WIFI
|
||||
* DO NOT USE ON A COMPUTER OTHER PEOPLE USE
|
||||
* BACK UP YOUR SEED PHRASE (multiple paper copies)
|
||||
|
||||
Even if you follow all those rules, due to web wallets relying on DNS and IP
|
||||
addresss, there are still potential attacks. You have been warned: https://wallet.myhush.org
|
||||
|
||||
The source code for the Hush web wallet is here: https://github.com/MyHush/myhushwallet
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
See [INSTALL.md](https://github.com/MyHush/hush3/blob/master/INSTALL.md).
|
||||
See [INSTALL.md](https://git.hush.is/hush/hush3/src/branch/master/INSTALL.md)
|
||||
|
||||
|
||||
License
|
||||
|
||||
20
configure.ac
20
configure.ac
@@ -1,14 +1,14 @@
|
||||
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
||||
AC_PREREQ([2.60])
|
||||
define(_CLIENT_VERSION_MAJOR, 3)
|
||||
define(_CLIENT_VERSION_MINOR, 5)
|
||||
define(_CLIENT_VERSION_REVISION, 2)
|
||||
define(_CLIENT_VERSION_MINOR, 6)
|
||||
define(_CLIENT_VERSION_REVISION, 0)
|
||||
define(_CLIENT_VERSION_BUILD, 50)
|
||||
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
|
||||
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
|
||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||
define(_COPYRIGHT_YEAR, 2020)
|
||||
AC_INIT([Hush],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_SUFFIX(_ZC_BUILD_VAL)],[https://github.com/MyHush/hush3],[hush])
|
||||
AC_INIT([Hush],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_SUFFIX(_ZC_BUILD_VAL)],[https://git.hush.is/hush/hush3],[hush])
|
||||
AC_CONFIG_SRCDIR([src/main.cpp])
|
||||
AC_CONFIG_HEADERS([src/config/bitcoin-config.h])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
@@ -664,8 +664,8 @@ if test x$use_pkgconfig = xyes; then
|
||||
m4_ifdef(
|
||||
[PKG_CHECK_MODULES],
|
||||
[
|
||||
PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)])
|
||||
PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)])
|
||||
PKG_CHECK_MODULES([SSL], [wolfssl],, [AC_MSG_ERROR(WolfSSL not found.)])
|
||||
PKG_CHECK_MODULES([CRYPTO], [wolfssl],,[AC_MSG_ERROR(libcrypto not found.)])
|
||||
if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then
|
||||
PKG_CHECK_MODULES([EVENT], [libevent],, [AC_MSG_ERROR(libevent not found.)])
|
||||
if test x$TARGET_OS != xwindows; then
|
||||
@@ -688,11 +688,11 @@ else
|
||||
# BUG: Fix this:
|
||||
echo 'BUG: configure does not yet check for the following dependencies if pkg-config is not on the system: libcrypto++, gmp'
|
||||
|
||||
AC_CHECK_HEADER([openssl/crypto.h],,AC_MSG_ERROR(libcrypto headers missing))
|
||||
AC_CHECK_LIB([crypto], [main],CRYPTO_LIBS=-lcrypto, AC_MSG_ERROR(libcrypto missing))
|
||||
AC_CHECK_HEADER([wolfssl/wolfcrypt/sha512.h],,AC_MSG_ERROR(libwolfssl headers missing))
|
||||
AC_CHECK_LIB([wolfssl], [wc_InitSha512],CRYPTO_LIBS=-lwolfssl, AC_MSG_ERROR(libwolfssl missing))
|
||||
|
||||
AC_CHECK_HEADER([openssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),)
|
||||
AC_CHECK_LIB([ssl], [main],SSL_LIBS=-lssl, AC_MSG_ERROR(libssl missing))
|
||||
AC_CHECK_HEADER([wolfssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),)
|
||||
AC_CHECK_LIB([wolfssl], [main],SSL_LIBS=-lwolfssl, AC_MSG_ERROR(libwolfssl missing))
|
||||
|
||||
if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then
|
||||
AC_CHECK_HEADER([event2/event.h],, AC_MSG_ERROR(libevent headers missing),)
|
||||
@@ -764,7 +764,7 @@ AX_CHECK_COMPILE_FLAG([-fwrapv],[CXXFLAGS="$CXXFLAGS -fwrapv"])
|
||||
AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing],[CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wno-builtin-declaration-mismatch],[CXXFLAGS="$CXXFLAGS -Wno-builtin-declaration-mismatch"],,[[$CXXFLAG_WERROR]])
|
||||
|
||||
LIBZCASH_LIBS="-lgmp -lgmpxx $BOOST_SYSTEM_LIB -lcrypto -lsodium $RUST_LIBS"
|
||||
LIBZCASH_LIBS="-lgmp -lgmpxx $BOOST_SYSTEM_LIB -lwolfssl -lsodium $RUST_LIBS"
|
||||
|
||||
AC_MSG_CHECKING([whether to build komodod])
|
||||
AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes])
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package=libcurl
|
||||
$(package)_version=7.67.0
|
||||
$(package)_dependencies=openssl
|
||||
$(package)_dependencies=wolfssl
|
||||
$(package)_download_path=https://curl.haxx.se/download
|
||||
$(package)_file_name=curl-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=52af3361cf806330b88b4fe6f483b6844209d47ae196ac46da4de59bb361ab02
|
||||
$(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) --host=$(host)
|
||||
$(package)_config_opts_mingw32=--enable-mingw --disable-shared --enable-static --prefix=$(host_prefix) --host=x86_64-w64-mingw32
|
||||
$(package)_config_opts_darwin=--disable-shared --enable-static --prefix=$(host_prefix)
|
||||
$(package)_config_opts_linux=--disable-shared --enable-static --with-wolfssl --without-ssl --prefix=$(host_prefix) --host=$(host)
|
||||
$(package)_config_opts_mingw32=--enable-mingw --disable-shared --enable-static --with-wolfssl --without-ssl --prefix=$(host_prefix) --host=x86_64-w64-mingw32
|
||||
$(package)_config_opts_darwin=--disable-shared --enable-static --with-wolfssl --without-ssl --prefix=$(host_prefix)
|
||||
$(package)_cflags_darwin=-mmacosx-version-min=10.9
|
||||
$(package)_conf_tool=./configure
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
package=openssl
|
||||
$(package)_version=1.1.1h
|
||||
$(package)_download_path=https://www.openssl.org/source
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=5c9ca8774bd7b03e5784f26ae9e9e6d749c9da2438545077e6b3d755a06595d9
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
|
||||
$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl
|
||||
$(package)_config_opts+=no-afalgeng
|
||||
$(package)_config_opts+=no-asm
|
||||
$(package)_config_opts+=no-async
|
||||
$(package)_config_opts+=no-bf
|
||||
$(package)_config_opts+=no-blake2
|
||||
$(package)_config_opts+=no-camellia
|
||||
#$(package)_config_opts+=no-capieng
|
||||
$(package)_config_opts+=no-cast
|
||||
#$(package)_config_opts+=no-chacha
|
||||
$(package)_config_opts+=no-cmac
|
||||
$(package)_config_opts+=no-cms
|
||||
#$(package)_config_opts+=no-comp
|
||||
$(package)_config_opts+=no-crypto-mdebug
|
||||
$(package)_config_opts+=no-crypto-mdebug-backtrace
|
||||
#$(package)_config_opts+=no-ct
|
||||
#$(package)_config_opts+=no-des
|
||||
$(package)_config_opts+=no-dgram
|
||||
#$(package)_config_opts+=no-dsa
|
||||
$(package)_config_opts+=no-dso
|
||||
$(package)_config_opts+=no-dtls
|
||||
$(package)_config_opts+=no-dtls1
|
||||
$(package)_config_opts+=no-dtls1-method
|
||||
$(package)_config_opts+=no-dynamic-engine
|
||||
#$(package)_config_opts+=no-ec2m
|
||||
#$(package)_config_opts+=no-ec_nistp_64_gcc_128
|
||||
$(package)_config_opts+=no-egd
|
||||
$(package)_config_opts+=no-engine
|
||||
#$(package)_config_opts+=no-err
|
||||
$(package)_config_opts+=no-gost
|
||||
$(package)_config_opts+=no-heartbeats
|
||||
#$(package)_config_opts+=no-idea
|
||||
$(package)_config_opts+=no-md2
|
||||
$(package)_config_opts+=no-md4
|
||||
$(package)_config_opts+=no-mdc2
|
||||
$(package)_config_opts+=no-multiblock
|
||||
$(package)_config_opts+=no-nextprotoneg
|
||||
$(package)_config_opts+=no-ocb
|
||||
#$(package)_config_opts+=no-ocsp
|
||||
#$(package)_config_opts+=no-poly1305
|
||||
#$(package)_config_opts+=no-posix-io
|
||||
$(package)_config_opts+=no-psk
|
||||
$(package)_config_opts+=no-rc2
|
||||
$(package)_config_opts+=no-rc4
|
||||
$(package)_config_opts+=no-rc5
|
||||
$(package)_config_opts+=no-rdrand
|
||||
$(package)_config_opts+=no-rfc3779
|
||||
$(package)_config_opts+=no-rmd160
|
||||
$(package)_config_opts+=no-scrypt
|
||||
$(package)_config_opts+=no-sctp
|
||||
$(package)_config_opts+=no-seed
|
||||
$(package)_config_opts+=no-shared
|
||||
#$(package)_config_opts+=no-sock
|
||||
$(package)_config_opts+=no-srp
|
||||
$(package)_config_opts+=no-srtp
|
||||
$(package)_config_opts+=no-ssl
|
||||
$(package)_config_opts+=no-ssl3
|
||||
$(package)_config_opts+=no-ssl3-method
|
||||
$(package)_config_opts+=no-ssl-trace
|
||||
#$(package)_config_opts+=no-stdio
|
||||
#$(package)_config_opts+=no-tls
|
||||
#$(package)_config_opts+=no-tls1
|
||||
#$(package)_config_opts+=no-tls1-method
|
||||
$(package)_config_opts+=no-ts
|
||||
$(package)_config_opts+=no-ui
|
||||
$(package)_config_opts+=no-unit-test
|
||||
$(package)_config_opts+=no-weak-ssl-ciphers
|
||||
$(package)_config_opts+=no-whirlpool
|
||||
#$(package)_config_opts+=no-zlib
|
||||
#$(package)_config_opts+=no-zlib-dynamic
|
||||
$(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags)
|
||||
$(package)_config_opts+=-DPURIFY
|
||||
$(package)_config_opts_linux=-fPIC -Wa,--noexecstack
|
||||
$(package)_config_opts_x86_64_linux=linux-x86_64
|
||||
$(package)_config_opts_i686_linux=linux-generic32
|
||||
$(package)_config_opts_arm_linux=linux-generic32
|
||||
$(package)_config_opts_aarch64_linux=linux-generic64
|
||||
$(package)_config_opts_mipsel_linux=linux-generic32
|
||||
$(package)_config_opts_mips_linux=linux-generic32
|
||||
$(package)_config_opts_powerpc_linux=linux-generic32
|
||||
$(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc
|
||||
$(package)_config_opts_x86_64_mingw32=mingw64
|
||||
$(package)_config_opts_i686_mingw32=mingw
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
sed -i.old 's/built on: $$$$date/built on: date not available/' util/mkbuildinf.pl && \
|
||||
sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./Configure $($(package)_config_opts)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) -j1 build_libs libcrypto.pc libssl.pc openssl.pc
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) -j1 install_sw
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm -rf share bin etc
|
||||
endef
|
||||
@@ -39,8 +39,8 @@ native_packages := native_ccache
|
||||
wallet_packages=bdb
|
||||
|
||||
ifeq ($(host_os),linux)
|
||||
packages := boost openssl libevent zeromq $(zcash_packages) googletest libcurl #googlemock
|
||||
packages := boost wolfssl libevent zeromq $(zcash_packages) googletest libcurl #googlemock
|
||||
else
|
||||
packages := boost openssl libevent zeromq $(zcash_packages) libcurl googletest #googlemock
|
||||
packages := boost wolfssl libevent zeromq $(zcash_packages) libcurl googletest #googlemock
|
||||
endif
|
||||
|
||||
|
||||
47
depends/packages/wolfssl.mk
Normal file
47
depends/packages/wolfssl.mk
Normal file
@@ -0,0 +1,47 @@
|
||||
package=wolfssl
|
||||
$(package)_version=4.5.0
|
||||
$(package)_download_path=https://github.com/wolfSSL/wolfssl/archive
|
||||
$(package)_download_file=v$($(package)_version)-stable.tar.gz
|
||||
$(package)_file_name=wolfssl-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=7de62300ce14daa0051bfefc7c4d6302f96cabc768b6ae49eda77523b118250c
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
|
||||
$(package)_config_opts=--prefix=$(host_prefix)
|
||||
$(package)_config_opts+=--host=$(host)
|
||||
$(package)_config_opts+=--enable-static
|
||||
$(package)_config_opts+=--disable-shared
|
||||
$(package)_config_opts+=--disable-examples
|
||||
$(package)_config_opts+=--disable-crypttests
|
||||
$(package)_config_opts+=--enable-keygen
|
||||
$(package)_config_opts+=--enable-certgen
|
||||
$(package)_config_opts+=--enable-enckeys
|
||||
$(package)_config_opts+=--enable-opensslall
|
||||
$(package)_config_opts+=--enable-opensslextra
|
||||
$(package)_config_opts+=--enable-harden
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cd $($(package)_build_subdir); ./autogen.sh
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./configure $($(package)_config_opts)
|
||||
endef
|
||||
|
||||
#define $(package)_config_cmds
|
||||
# $($(package)_autoconf)
|
||||
#endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) -j1 src/libwolfssl.la
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-includeHEADERS install-nobase_includeHEADERS install-pkgconfigDATA
|
||||
endef
|
||||
|
||||
#define $(package)_postprocess_cmds
|
||||
# rm -rf bin share
|
||||
#endef
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Expectations for DNS Seed operators
|
||||
====================================
|
||||
# Expectations for DNS Seed operators
|
||||
|
||||
Hush attempts to minimize the level of trust in DNS seeds,
|
||||
but DNS seeds still pose a small amount of risk for the network.
|
||||
@@ -43,12 +42,12 @@ related to the DNS seed operation.
|
||||
|
||||
If these expectations cannot be satisfied the operator should discontinue
|
||||
providing services and contact the active Hush development team as well as
|
||||
creating an issue in the [Hush Github repository](https://github.com/MyHush/hush3).
|
||||
creating an issue in the [Hush Git repository](https://git.hush.is./hush/hush3).
|
||||
|
||||
Behavior outside of these expectations may be reasonable in some
|
||||
situations but should be discussed in public in advance.
|
||||
|
||||
See also
|
||||
----------
|
||||
- [hush-seeder](https://github.com/MyHush/hush-seeder) is a reference
|
||||
- [hush-seeder](https://git.hush.is/hush/hush-seeder) is a reference
|
||||
implementation of a DNS seed.
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
## Overview
|
||||
|
||||
Hush extends the Bitcoin Core API with new RPC calls to support private Hush payments.
|
||||
Hush extends the Bitcoin Core API with new RPC calls to support private Hush payments involving shielded addresses (zaddrs).
|
||||
|
||||
Hush payments make use of two address formats:
|
||||
|
||||
* taddr - an address for transparent funds (just like a Bitcoin address, value stored in UTXOs)
|
||||
* zaddr - an address for private funds (value stored in objects called notes)
|
||||
|
||||
When transferring funds from one taddr to another taddr, you can use either the existing Bitcoin RPC calls or the new Hush RPC calls.
|
||||
As of Block 340000, taddrs cannot be recipients of transactions, they can only mine new coinbase funds, which must then be sent to a zaddr.
|
||||
|
||||
When a transfer involves zaddrs, you must use the new Hush RPC calls.
|
||||
When a transfer involves zaddrs, you must use the new Hush RPC calls, such as `z_sendmany`.
|
||||
|
||||
|
||||
## Compatibility with Bitcoin Core
|
||||
@@ -111,7 +111,7 @@ z_listoperationids <br>| [state] | Return a list of operationids for all operati
|
||||
|
||||
## Asynchronous RPC call Error Codes
|
||||
|
||||
Hush error codes are defined in https://github.com/zcash/zcash/blob/master/src/rpcprotocol.h
|
||||
Hush error codes are defined in https://git.hush.is/hush/hush3/src/branch/master/src/rpc/protocol.h
|
||||
|
||||
### z_sendmany error codes
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Security Warnings
|
||||
====================
|
||||
#Security Warnings
|
||||
|
||||
Security Audits
|
||||
--------------
|
||||
## Security Audits
|
||||
|
||||
Hush has not been subjected to a formal third-party security review! But the
|
||||
Zcash source code has. For security
|
||||
@@ -14,17 +12,13 @@ to our own code, such as audits on ZecWallet that apply to SilentDragon.
|
||||
Hush also reports many new bugs and issues to upstream Zcash and many other
|
||||
Zcash Protocol coins.
|
||||
|
||||
Additionally, Hush itself finds many CVE's and things-that-should-be-CVE's
|
||||
in Zcash internals. Since Zcash community treats Hush people so poorly, we
|
||||
keep these bugs and fixes to ourselves. If you want to know some of them,
|
||||
let us know and bring your wallet.
|
||||
|
||||
x86-64 Linux Only
|
||||
-----------------------
|
||||
|
||||
There are [known bugs](https://github.com/scipr-lab/libsnark/issues/26) which
|
||||
make proving keys generated on 64-bit systems unusable on 32-bit and big-endian
|
||||
systems. It's unclear if a warning will be issued in this case, or if the
|
||||
proving system will be silently compromised.
|
||||
|
||||
Wallet Encryption
|
||||
-----------------
|
||||
## Wallet Encryption
|
||||
|
||||
Wallet encryption is disabled, for several reasons:
|
||||
|
||||
@@ -51,12 +45,11 @@ You should use full-disk encryption (or encryption of your home directory) to
|
||||
protect your wallet at rest, and should assume (even unprivileged) users who are
|
||||
running on your OS can read your wallet.dat file.
|
||||
|
||||
Side-Channel Attacks
|
||||
--------------------
|
||||
## Side-Channel Attacks
|
||||
|
||||
This implementation of Hush is not resistant to side-channel attacks. You
|
||||
should assume (even unprivileged) users who are running on the hardware, or who
|
||||
are physically near the hardware, that your `zcashd` process is running on will
|
||||
are physically near the hardware, that your `hushd` process is running on will
|
||||
be able to:
|
||||
|
||||
- Determine the values of your secret spending keys, as well as which notes you
|
||||
@@ -74,29 +67,23 @@ You should ensure no other users have the ability to execute code (even
|
||||
unprivileged) on the hardware your `hushd` process runs on until these
|
||||
vulnerabilities are fully analyzed and fixed.
|
||||
|
||||
REST Interface
|
||||
--------------
|
||||
## REST Interface
|
||||
|
||||
The REST interface is a feature inherited from upstream Bitcoin. By default,
|
||||
it is disabled. We do not recommend you enable it until it has undergone a
|
||||
security review.
|
||||
|
||||
RPC Interface
|
||||
---------------
|
||||
## RPC Interface
|
||||
|
||||
Users should choose a strong RPC password. If no RPC username and password are set, hush will not start and will print an error message with a suggestion for a strong random password. If the client knows the RPC password, they have at least full access to the node. In addition, certain RPC commands can be misused to overwrite files and/or take over the account that is running hushd. (In the future we may restrict these commands, but full node access – including the ability to spend from and export keys held by the wallet – would still be possible unless wallet methods are disabled.)
|
||||
|
||||
Users should also refrain from changing the default setting that only allows RPC connections from localhost. Allowing connections from remote hosts would enable a MITM to execute arbitrary RPC commands, which could lead to compromise of the account running hushd and loss of funds. For multi-user services that use one or more hushd instances on the backend, the parameters passed in by users should be controlled to prevent confused-deputy attacks which could spend from any keys held by that zcashd.
|
||||
|
||||
Block Chain Reorganization: Major Differences
|
||||
-------------------------------------------------
|
||||
## Block Chain Reorganization: Major Differences
|
||||
|
||||
Users should be aware of new behavior in Hush that differs significantly from Bitcoin: in the case of a block chain reorganization, Bitcoin's coinbase maturity rule helps to ensure that any reorganization shorter than the maturity interval will not invalidate any of the rolled-back transactions. Hush keeps Bitcoin's 100-block maturity interval for generation transactions, but because JoinSplits must be anchored within a block, this provides more limited protection against transactions becoming invalidated. In the case of a block chain reorganization for Hush, all JoinSplits which were anchored within the reorganization interval and any transactions that depend on them will become invalid, rolling back transactions and reverting funds to the original owner. The transaction rebroadcast mechanism inherited from Bitcoin will not successfully rebroadcast transactions depending on invalidated JoinSplits if the anchor needs to change. The creator of an invalidated JoinSplit, as well as the creators of all transactions dependent on it, must rebroadcast the transactions themselves.
|
||||
Hush has Delayed-Proof-of-Work, which drastically improves the Zcash rule-of-thumb of "re-organize 100 blocks to crash all ZEC full nodes in the world".
|
||||
|
||||
Receivers of funds from a JoinSplit can mitigate the risk of relying on funds received from transactions that may be rolled back by using a higher minconf (minimum number of confirmations).
|
||||
|
||||
Logging z_* RPC calls
|
||||
---------------------
|
||||
## Logging z_* RPC calls
|
||||
|
||||
The option `-debug=zrpc` covers logging of the z_* calls. This will reveal information about private notes which you might prefer not to disclose. For example, when calling `z_sendmany` to create a shielded transaction, input notes are consumed and new output notes are created.
|
||||
|
||||
@@ -104,12 +91,10 @@ The option `-debug=zrpcunsafe` covers logging of sensitive information in z_* ca
|
||||
|
||||
Private spending keys for z addresses are never logged.
|
||||
|
||||
Potentially-Missing Required Modifications
|
||||
------------------------------------------
|
||||
## Potentially-Missing Required Modifications
|
||||
|
||||
In addition to potential mistakes in code we added to Bitcoin Core, Zcash
|
||||
and Komodo and
|
||||
potential mistakes in our modifications to Bitcoin Core, Zcash and Komodo, it is also possible
|
||||
and Komodo and potential mistakes in our modifications to Bitcoin Core, Zcash and Komodo, it is also possible
|
||||
that there were potential changes we were supposed to make to Bitcoin Core, Zcash and Komodo but
|
||||
didn't, either because we didn't even consider making those changes or have not found out about
|
||||
them. Submitting Github issues is highly appreciated!
|
||||
them. Patches Welcome!
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "crosschain.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "cc/CCinclude.h"
|
||||
#include <openssl/sha.h>
|
||||
#include <wolfssl/wolfcrypt/sha.h>
|
||||
#include "cc/CCtokens.h"
|
||||
|
||||
#include "key_io.h"
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
|
||||
// Must be kept in sync with configure.ac !
|
||||
#define CLIENT_VERSION_MAJOR 3
|
||||
#define CLIENT_VERSION_MINOR 5
|
||||
#define CLIENT_VERSION_REVISION 1
|
||||
#define CLIENT_VERSION_MINOR 6
|
||||
#define CLIENT_VERSION_REVISION 0
|
||||
#define CLIENT_VERSION_BUILD 50
|
||||
|
||||
//! Set to true for release, false for prerelease or test build
|
||||
|
||||
@@ -1,79 +1,171 @@
|
||||
// Copyright (c) 2019-2020 The Hush developers
|
||||
// Distributed under the GPLv3 software license, see the accompanying
|
||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include "utiltls.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include "../util.h"
|
||||
#include "../protocol.h"
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/openssl/dh.h>
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "tlsmanager.h"
|
||||
#include "utiltls.h"
|
||||
|
||||
using namespace std;
|
||||
namespace hush
|
||||
{
|
||||
/**
|
||||
* @brief If verify_callback always returns 1, the TLS/SSL handshake will not be terminated with respect to verification failures and the connection will be established.
|
||||
*
|
||||
* @param preverify_ok
|
||||
* @param chainContext
|
||||
* @return int
|
||||
*/
|
||||
int tlsCertVerificationCallback(int preverify_ok, X509_STORE_CTX* chainContext)
|
||||
static WOLFSSL_EVP_PKEY *mykey;
|
||||
static WOLFSSL_X509 *mycert;
|
||||
|
||||
// this is the 'dh crypto environment' to be shared between two peers and it is meant to be public, therefore
|
||||
// it is OK to hard code it (or as an alternative to read it from a file)
|
||||
// ----
|
||||
// generated via: openssl dhparam -C 2048
|
||||
static WOLFSSL_DH *get_dh2048(void)
|
||||
{
|
||||
return 1;
|
||||
static unsigned char dhp_2048[] = {
|
||||
0xFF, 0x4A, 0xA8, 0x6C, 0x68, 0xD4, 0x4C, 0x41, 0x73, 0x8D,
|
||||
0xD8, 0x14, 0x57, 0xF9, 0x1C, 0x35, 0x72, 0x5F, 0xCD, 0x24,
|
||||
0xCB, 0xD1, 0x77, 0x30, 0xC2, 0x9A, 0x69, 0x01, 0xCF, 0x01,
|
||||
0xDE, 0xD4, 0x67, 0xD4, 0xEE, 0x9A, 0x03, 0x1C, 0x27, 0x42,
|
||||
0x06, 0x3D, 0x1D, 0x91, 0x27, 0xCF, 0x1C, 0x17, 0xB3, 0xDC,
|
||||
0x9F, 0x6F, 0x12, 0xC8, 0x03, 0x5C, 0x01, 0xF3, 0x27, 0x7F,
|
||||
0x34, 0x58, 0xAE, 0xB9, 0xA7, 0xA9, 0xCE, 0x5E, 0x25, 0x7D,
|
||||
0x46, 0x84, 0xDD, 0xEE, 0x55, 0xFB, 0xEA, 0x1C, 0xCD, 0x9B,
|
||||
0x96, 0xC4, 0x22, 0x8C, 0x33, 0x8B, 0xC7, 0xE6, 0xCC, 0x4C,
|
||||
0x77, 0x1B, 0x7A, 0x46, 0xDE, 0x33, 0xAD, 0xBB, 0xFD, 0x2D,
|
||||
0xAD, 0x26, 0xE1, 0x27, 0x48, 0x94, 0xA3, 0x59, 0xC5, 0x10,
|
||||
0x5A, 0x86, 0x71, 0x8D, 0xAA, 0x15, 0x8B, 0xB2, 0xCB, 0x70,
|
||||
0xBE, 0x1F, 0x17, 0xBD, 0xEB, 0x51, 0xB1, 0x76, 0x0E, 0x24,
|
||||
0x43, 0xAA, 0x06, 0xC0, 0x97, 0x01, 0x25, 0x52, 0x30, 0x7A,
|
||||
0x56, 0x92, 0x3D, 0x8A, 0x3A, 0xBC, 0xFA, 0x98, 0x51, 0x04,
|
||||
0x1D, 0x9B, 0x05, 0xB8, 0x84, 0x8C, 0x2F, 0x7A, 0x94, 0x1E,
|
||||
0xAA, 0x51, 0xF2, 0x5D, 0x48, 0x50, 0x58, 0x8D, 0x7E, 0xBA,
|
||||
0xD3, 0xCC, 0xF2, 0x92, 0x28, 0xB1, 0x1C, 0x4B, 0x50, 0x10,
|
||||
0xFA, 0x7E, 0xDF, 0x8D, 0x23, 0x1C, 0x8C, 0x65, 0xE3, 0x86,
|
||||
0x16, 0x67, 0x88, 0x9E, 0xFC, 0x8B, 0xC8, 0x55, 0x38, 0x6E,
|
||||
0x79, 0x06, 0x6A, 0x6D, 0x72, 0x75, 0xA6, 0xAC, 0x77, 0x98,
|
||||
0xDD, 0xB2, 0x0B, 0xAA, 0x48, 0x54, 0xA9, 0x07, 0x7E, 0x8C,
|
||||
0x4C, 0x39, 0x08, 0x26, 0x6D, 0x53, 0xC2, 0xDF, 0xE2, 0xF0,
|
||||
0xD6, 0x8A, 0x4F, 0xB5, 0x7A, 0x32, 0xEE, 0x93, 0x0E, 0x2A,
|
||||
0x81, 0x2F, 0x3B, 0x1E, 0xE6, 0x38, 0xF8, 0x3C, 0xF5, 0x84,
|
||||
0xB4, 0xFB, 0x92, 0x12, 0x28, 0xA3
|
||||
};
|
||||
static unsigned char dhg_2048[] = {
|
||||
0x02
|
||||
};
|
||||
|
||||
WOLFSSL_DH *dh = wolfSSL_DH_new();
|
||||
|
||||
if (dh == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wc_DhSetKey((DhKey*)dh->internal, dhp_2048, sizeof(dhp_2048), dhg_2048, sizeof(dhg_2048)) != 0) {
|
||||
wolfSSL_DH_free(dh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dh;
|
||||
}
|
||||
/**
|
||||
* @brief Wait for a given SSL connection event.
|
||||
*
|
||||
* @param eRoutine a SSLConnectionRoutine value which determines the type of the event.
|
||||
* @param hSocket
|
||||
* @param ssl pointer to an SSL instance.
|
||||
* @param timeoutSec timeout in seconds.
|
||||
* @return int returns nError corresponding to the connection event.
|
||||
*/
|
||||
int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, SSL* ssl, int timeoutSec)
|
||||
|
||||
DH *tmp_dh_callback(WOLFSSL *ssl, int is_export, int keylength)
|
||||
{
|
||||
int nErr = 0;
|
||||
ERR_clear_error(); // clear the error queue
|
||||
LogPrint("tls", "TLS: %s: %s():%d - Using Diffie-Hellman param for PFS: is_export=%d, keylength=%d\n",
|
||||
__FILE__, __func__, __LINE__, is_export, keylength);
|
||||
|
||||
return get_dh2048();
|
||||
}
|
||||
|
||||
int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL* ssl, int timeoutSec, unsigned long& err_code)
|
||||
{
|
||||
int retOp = 0;
|
||||
err_code = 0;
|
||||
char err_buffer[1024];
|
||||
|
||||
while (true)
|
||||
{
|
||||
// clear the current thread's error queue
|
||||
wolfSSL_ERR_clear_error();
|
||||
|
||||
while (true) {
|
||||
switch (eRoutine) {
|
||||
case SSL_CONNECT:
|
||||
nErr = SSL_connect(ssl);
|
||||
case SSL_CONNECT:
|
||||
{
|
||||
retOp = wolfSSL_connect(ssl);
|
||||
if (retOp == 0) {
|
||||
err_code = wolfSSL_ERR_get_error();
|
||||
const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
|
||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_CONNECT err: %s\n",
|
||||
__FILE__, __func__, __LINE__, err_buffer);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SSL_ACCEPT:
|
||||
nErr = SSL_accept(ssl);
|
||||
|
||||
case SSL_ACCEPT:
|
||||
{
|
||||
retOp = wolfSSL_accept(ssl);
|
||||
if (retOp == 0) {
|
||||
err_code = wolfSSL_ERR_get_error();
|
||||
const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
|
||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_ACCEPT err: %s\n",
|
||||
__FILE__, __func__, __LINE__, err_buffer);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SSL_SHUTDOWN:
|
||||
nErr = SSL_shutdown(ssl);
|
||||
|
||||
case SSL_SHUTDOWN:
|
||||
{
|
||||
if (hSocket != INVALID_SOCKET) {
|
||||
std::string disconnectedPeer("no info");
|
||||
struct sockaddr_in addr;
|
||||
socklen_t serv_len = sizeof(addr);
|
||||
int ret = getpeername(hSocket, (struct sockaddr *)&addr, &serv_len);
|
||||
if (ret == 0) {
|
||||
disconnectedPeer = std::string(inet_ntoa(addr.sin_addr)) + ":" + std::to_string(ntohs(addr.sin_port));
|
||||
}
|
||||
LogPrint("tls", "TLS: shutting down fd=%d, peer=%s\n", hSocket, disconnectedPeer);
|
||||
}
|
||||
retOp = wolfSSL_shutdown(ssl);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (eRoutine == SSL_SHUTDOWN) {
|
||||
if (nErr >= 0)
|
||||
if (retOp == 0) {
|
||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_SHUTDOWN: The close_notify was sent but the peer did not send it back yet.\n",
|
||||
__FILE__, __func__, __LINE__);
|
||||
// do not call SSL_get_error() because it may misleadingly indicate an error even though no error occurred.
|
||||
break;
|
||||
} else if (retOp == 1) {
|
||||
LogPrint("tls", "TLS: %s: %s():%d - SSL_SHUTDOWN completed\n", __FILE__, __func__, __LINE__);
|
||||
break;
|
||||
} else {
|
||||
LogPrint("tls", "TLS: %s: %s():%d - SSL_SHUTDOWN failed\n", __FILE__, __func__, __LINE__);
|
||||
// the error will be read afterwards
|
||||
}
|
||||
} else {
|
||||
if (nErr == 1)
|
||||
if (retOp == 1) {
|
||||
LogPrint("tls", "TLS: %s: %s():%d - %s completed\n", __FILE__, __func__, __LINE__,
|
||||
eRoutine == SSL_CONNECT ? "SSL_CONNECT" : "SSL_ACCEPT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int sslErr = SSL_get_error(ssl, nErr);
|
||||
int sslErr = wolfSSL_get_error(ssl, retOp);
|
||||
|
||||
if (sslErr != SSL_ERROR_WANT_READ && sslErr != SSL_ERROR_WANT_WRITE) {
|
||||
LogPrint("net", "TLS: WARNING: %s: %s: ssl_err_code: %s; errno: %s\n", __FILE__, __func__, ERR_error_string(sslErr, NULL), strerror(errno));
|
||||
nErr = -1;
|
||||
if (sslErr != WOLFSSL_ERROR_WANT_READ && sslErr != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
err_code = wolfSSL_ERR_get_error();
|
||||
const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
|
||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - routine(%d), sslErr[0x%x], retOp[%d], errno[0x%x], lib[0x%x], func[0x%x], reas[0x%x]-> err: %s\n",
|
||||
__FILE__, __func__, __LINE__,
|
||||
eRoutine, sslErr, retOp, errno, wolfSSL_ERR_GET_LIB(err_code), ERR_GET_FUNC(err_code), wolfSSL_ERR_GET_REASON(err_code), err_buffer);
|
||||
retOp = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -83,66 +175,89 @@ int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, SSL* ssl,
|
||||
|
||||
struct timeval timeout = {timeoutSec, 0};
|
||||
|
||||
if (sslErr == SSL_ERROR_WANT_READ) {
|
||||
if (sslErr == WOLFSSL_ERROR_WANT_READ) {
|
||||
int result = select(hSocket + 1, &socketSet, NULL, NULL, &timeout);
|
||||
if (result == 0) {
|
||||
LogPrint("net", "TLS: ERROR: %s: %s: WANT_READ timeout\n", __FILE__, __func__);
|
||||
nErr = -1;
|
||||
LogPrint("tls", "TLS: ERROR: %s: %s():%d - WANT_READ timeout on %s\n", __FILE__, __func__, __LINE__,
|
||||
(eRoutine == SSL_CONNECT ? "SSL_CONNECT" :
|
||||
(eRoutine == SSL_ACCEPT ? "SSL_ACCEPT" : "SSL_SHUTDOWN" )));
|
||||
err_code = SELECT_TIMEDOUT;
|
||||
retOp = -1;
|
||||
break;
|
||||
} else if (result == -1) {
|
||||
LogPrint("net", "TLS: ERROR: %s: %s: WANT_READ ssl_err_code: %s; errno: %s\n", __FILE__, __func__, ERR_error_string(sslErr, NULL), strerror(errno));
|
||||
nErr = -1;
|
||||
LogPrint("tls", "TLS: ERROR: %s: %s: WANT_READ ssl_err_code: 0x%x; errno: %s\n",
|
||||
__FILE__, __func__, sslErr, strerror(errno));
|
||||
retOp = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int result = select(hSocket + 1, NULL, &socketSet, NULL, &timeout);
|
||||
if (result == 0) {
|
||||
LogPrint("net", "TLS: ERROR: %s: %s: WANT_WRITE timeout\n", __FILE__, __func__);
|
||||
nErr = -1;
|
||||
LogPrint("tls", "TLS: ERROR: %s: %s():%d - WANT_WRITE timeout on %s\n", __FILE__, __func__, __LINE__,
|
||||
(eRoutine == SSL_CONNECT ? "SSL_CONNECT" :
|
||||
(eRoutine == SSL_ACCEPT ? "SSL_ACCEPT" : "SSL_SHUTDOWN" )));
|
||||
err_code = SELECT_TIMEDOUT;
|
||||
retOp = -1;
|
||||
break;
|
||||
} else if (result == -1) {
|
||||
LogPrint("net", "TLS: ERROR: %s: %s: WANT_WRITE ssl_err_code: %s; errno: %s\n", __FILE__, __func__, ERR_error_string(sslErr, NULL), strerror(errno));
|
||||
nErr = -1;
|
||||
LogPrint("tls", "TLS: ERROR: %s: %s: WANT_WRITE ssl_err_code: 0x%x; errno: %s\n",
|
||||
__FILE__, __func__, sslErr, strerror(errno));
|
||||
retOp = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nErr;
|
||||
return retOp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief establish TLS connection to an address
|
||||
*
|
||||
* @param hSocket socket
|
||||
* @param addrConnect the outgoing address
|
||||
* @param tls_ctx_client TLS Client context
|
||||
* @return SSL* returns a ssl* if successful, otherwise returns NULL.
|
||||
* @return WOLFSSL* returns a ssl* if successful, otherwise returns NULL.
|
||||
*/
|
||||
SSL* TLSManager::connect(SOCKET hSocket, const CAddress& addrConnect)
|
||||
WOLFSSL* TLSManager::connect(SOCKET hSocket, const CAddress& addrConnect, unsigned long& err_code)
|
||||
{
|
||||
LogPrint("net", "TLS: establishing connection tid=%X peerid=%s\n", pthread_self(), addrConnect.ToString());
|
||||
LogPrint("tls", "TLS: establishing connection (tid = %X), (peerid = %s)\n", pthread_self(), addrConnect.ToString());
|
||||
|
||||
SSL* ssl = NULL;
|
||||
err_code = 0;
|
||||
char err_buffer[1024];
|
||||
WOLFSSL* ssl = NULL;
|
||||
bool bConnectedTLS = false;
|
||||
|
||||
if ((ssl = SSL_new(tls_ctx_client))) {
|
||||
if (SSL_set_fd(ssl, hSocket)) {
|
||||
if (TLSManager::waitFor(SSL_CONNECT, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000)) == 1)
|
||||
|
||||
if ((ssl = wolfSSL_new(tls_ctx_client))) {
|
||||
if (wolfSSL_set_fd(ssl, hSocket)) {
|
||||
int ret = TLSManager::waitFor(SSL_CONNECT, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code);
|
||||
if (ret == 1)
|
||||
{
|
||||
bConnectedTLS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = wolfSSL_ERR_get_error();
|
||||
const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
|
||||
LogPrint("tls", "TLS: %s: %s():%d - SSL_new failed err: %s\n",
|
||||
__FILE__, __func__, __LINE__, err_buffer);
|
||||
}
|
||||
|
||||
if (bConnectedTLS) {
|
||||
LogPrintf("TLS: connection to %s has been established. Using cipher: %s\n", addrConnect.ToString(), SSL_get_cipher(ssl));
|
||||
LogPrintf("TLS: connection to %s has been established (tlsv = %s 0x%04x / ssl = %s 0x%x ). Using cipher: %s\n",
|
||||
addrConnect.ToString(), wolfSSL_get_version(ssl), wolfSSL_version(ssl), wolfSSL_OpenSSL_version(), wolfSSL_lib_version_hex(), wolfSSL_get_cipher_name(ssl));
|
||||
} else {
|
||||
LogPrintf("TLS: %s: TLS connection to %s failed\n", __func__, addrConnect.ToString());
|
||||
LogPrintf("TLS: %s: %s():%d - TLS connection to %s failed (err_code 0x%X)\n",
|
||||
__FILE__, __func__, __LINE__, addrConnect.ToString(), err_code);
|
||||
|
||||
if (ssl) {
|
||||
SSL_free(ssl);
|
||||
wolfSSL_free(ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ssl;
|
||||
}
|
||||
/**
|
||||
@@ -152,49 +267,84 @@ SSL* TLSManager::connect(SOCKET hSocket, const CAddress& addrConnect)
|
||||
* @param privateKeyFile private key file path
|
||||
* @param certificateFile certificate key file path
|
||||
* @param trustedDirs trusted directories
|
||||
* @return SSL_CTX* returns the context.
|
||||
* @return WOLSSL_CTX* returns the context.
|
||||
*/
|
||||
SSL_CTX* TLSManager::initCtx(
|
||||
TLSContextType ctxType,
|
||||
const boost::filesystem::path& privateKeyFile,
|
||||
const boost::filesystem::path& certificateFile,
|
||||
const std::vector<boost::filesystem::path>& trustedDirs)
|
||||
WOLFSSL_CTX* TLSManager::initCtx(TLSContextType ctxType)
|
||||
{
|
||||
if (!boost::filesystem::exists(privateKeyFile) ||
|
||||
!boost::filesystem::exists(certificateFile))
|
||||
return NULL;
|
||||
LogPrintf("TLS: %s: %s():%d - Initializing %s context\n",
|
||||
__FILE__, __func__, __LINE__, ctxType == SERVER_CONTEXT ? "server" : "client");
|
||||
|
||||
if (!mykey || !mycert) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool bInitialized = false;
|
||||
SSL_CTX* tlsCtx = NULL;
|
||||
WOLFSSL_CTX* tlsCtx = NULL;
|
||||
|
||||
if ((tlsCtx = SSL_CTX_new(ctxType == SERVER_CONTEXT ? TLS_server_method() : TLS_client_method()))) {
|
||||
SSL_CTX_set_mode(tlsCtx, SSL_MODE_AUTO_RETRY);
|
||||
byte *pem;
|
||||
int plen = 0;
|
||||
|
||||
int rootCertsNum = LoadDefaultRootCertificates(tlsCtx);
|
||||
int trustedPathsNum = 0;
|
||||
if ((tlsCtx = wolfSSL_CTX_new(ctxType == SERVER_CONTEXT ? wolfTLSv1_3_server_method() : wolfTLSv1_3_client_method()))) {
|
||||
wolfSSL_CTX_set_mode(tlsCtx, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
for (boost::filesystem::path trustedDir : trustedDirs) {
|
||||
if (SSL_CTX_load_verify_locations(tlsCtx, NULL, trustedDir.string().c_str()) == 1)
|
||||
trustedPathsNum++;
|
||||
// Disable TLS < 1.3 ... imho redundant, because v1.3 is required via method
|
||||
int ret = wolfSSL_CTX_set_min_proto_version(tlsCtx, TLS1_3_VERSION);
|
||||
if (ret == 0) {
|
||||
LogPrintf("TLS: WARNING: %s: %s():%d - failed to set min TLS version\n", __FILE__, __func__, __LINE__);
|
||||
}
|
||||
|
||||
if (rootCertsNum == 0 && trustedPathsNum == 0)
|
||||
LogPrintf("TLS: WARNING: %s: %s: failed to set up verified certificates. It will be impossible to verify peer certificates. \n", __FILE__, __func__);
|
||||
LogPrintf("TLS: %s: %s():%d - setting cipher list\n", __FILE__, __func__, __LINE__);
|
||||
|
||||
SSL_CTX_set_verify(tlsCtx, SSL_VERIFY_PEER, tlsCertVerificationCallback);
|
||||
|
||||
if (SSL_CTX_use_certificate_file(tlsCtx, certificateFile.string().c_str(), SSL_FILETYPE_PEM) > 0) {
|
||||
if (SSL_CTX_use_PrivateKey_file(tlsCtx, privateKeyFile.string().c_str(), SSL_FILETYPE_PEM) > 0) {
|
||||
if (SSL_CTX_check_private_key(tlsCtx)) {
|
||||
bInitialized = true;
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: private key does not match the certificate public key\n", __FILE__, __func__);
|
||||
}
|
||||
} else
|
||||
LogPrintf("TLS: ERROR: %s: %s: failed to use privateKey file\n", __FILE__, __func__);
|
||||
// Default TLSv1.3 cipher list is "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
|
||||
// Nodes will randomly choose to prefer first cipher or the second, to create diversity on the network
|
||||
// and not be in the situation where all nodes have the same list so the first is always used
|
||||
if(GetRand(100) > 50) {
|
||||
if (wolfSSL_CTX_set_cipher_list(tlsCtx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256")) {
|
||||
LogPrintf("%s: Preferring TLS_AES256-GCM-SHA384\n", __func__);
|
||||
} else {
|
||||
LogPrintf("%s: Setting preferred cipher failed !!!\n", __func__);
|
||||
}
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: failed to use certificate file\n", __FILE__, __func__);
|
||||
ERR_print_errors_fp(stderr);
|
||||
if (wolfSSL_CTX_set_cipher_list(tlsCtx, "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384")) {
|
||||
LogPrintf("%s: Preferring TLS_AES256-GCM-SHA384\n", __func__);
|
||||
} else {
|
||||
LogPrintf("%s: Setting preferred cipher failed !!!\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxType == SERVER_CONTEXT) {
|
||||
// In case server and client prefered ciphers are different, server preference has priority
|
||||
wolfSSL_CTX_set_options(tlsCtx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
|
||||
LogPrintf("TLS: %s: %s():%d - setting dh callback\n", __FILE__, __func__, __LINE__);
|
||||
SSL_CTX_set_tmp_dh_callback(tlsCtx, tmp_dh_callback);
|
||||
}
|
||||
|
||||
// No certificate verification, all should be self-signed
|
||||
wolfSSL_CTX_set_verify(tlsCtx, WOLFSSL_VERIFY_NONE, NULL);
|
||||
|
||||
WOLFSSL_EC_KEY *ec_key = NULL;
|
||||
|
||||
ec_key = wolfSSL_EVP_PKEY_get0_EC_KEY(mykey);
|
||||
|
||||
if (ec_key != NULL && wolfSSL_PEM_write_mem_ECPrivateKey(ec_key, NULL, NULL, 0, &pem, &plen)) {
|
||||
if (wolfSSL_CTX_use_certificate(tlsCtx, mycert) > 0) {
|
||||
if (wolfSSL_CTX_use_PrivateKey_buffer(tlsCtx, pem, plen, SSL_FILETYPE_PEM) > 0) {
|
||||
|
||||
free(pem);
|
||||
|
||||
if (wolfSSL_CTX_check_private_key(tlsCtx)) {
|
||||
bInitialized = true;
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: private key does not match the certificate public key\n", __FILE__, __func__);
|
||||
}
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: failed to use private key file\n", __FILE__, __func__);
|
||||
}
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: failed to use certificate file\n", __FILE__, __func__);
|
||||
wolfSSL_ERR_dump_errors_fp(stderr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: failed to create TLS context\n", __FILE__, __func__);
|
||||
@@ -202,97 +352,119 @@ SSL_CTX* TLSManager::initCtx(
|
||||
|
||||
if (!bInitialized) {
|
||||
if (tlsCtx) {
|
||||
SSL_CTX_free(tlsCtx);
|
||||
wolfSSL_CTX_free(tlsCtx);
|
||||
tlsCtx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX_set_cipher_list(tlsCtx, ""); // removes all <= TLS1.2 ciphers
|
||||
// default is "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
|
||||
// Nodes will randomly choose to prefer one suite or the other, to create diversity on the network
|
||||
// and not be in the situation where all nodes have the same list so the first is always used
|
||||
if(GetRand(100) > 50) {
|
||||
LogPrintf("%s: Preferring TLS_AES256-GCM-SHA384\n", __func__);
|
||||
SSL_CTX_set_ciphersuites(tlsCtx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256");
|
||||
} else {
|
||||
LogPrintf("%s: Preferring TLS_CHACHA20-POLY1305\n", __func__);
|
||||
SSL_CTX_set_ciphersuites(tlsCtx, "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384");
|
||||
}
|
||||
|
||||
/*
|
||||
STACK_OF(SSL_CIPHER) *sk = SSL_CTX_get_ciphers(tlsCtx);
|
||||
for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++)
|
||||
{
|
||||
const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i);
|
||||
LogPrintf("%s: AVAILABLE CIPHER %s\n", __func__, SSL_CIPHER_get_name(c));
|
||||
}
|
||||
*/
|
||||
|
||||
return tlsCtx;
|
||||
}
|
||||
/**
|
||||
* @brief load the certificate credentials from file.
|
||||
* @brief generates certificate credentials.
|
||||
*
|
||||
* @return true returns true is successful.
|
||||
* @return false returns false if an error has occured.
|
||||
*/
|
||||
bool TLSManager::prepareCredentials()
|
||||
{
|
||||
boost::filesystem::path
|
||||
defaultKeyPath(GetDataDir() / TLS_KEY_FILE_NAME),
|
||||
defaultCertPath(GetDataDir() / TLS_CERT_FILE_NAME);
|
||||
mykey = NULL;
|
||||
mycert = NULL;
|
||||
|
||||
CredentialsStatus credStatus =
|
||||
VerifyCredentials(
|
||||
boost::filesystem::path(GetArg("-tlskeypath", defaultKeyPath.string())),
|
||||
boost::filesystem::path(GetArg("-tlscertpath", defaultCertPath.string())),
|
||||
GetArg("-tlskeypwd", ""));
|
||||
|
||||
bool bPrepared = (credStatus == credOk);
|
||||
|
||||
if (!bPrepared) {
|
||||
if (!mapArgs.count("-tlskeypath") && !mapArgs.count("-tlscertpath")) {
|
||||
// Default paths were used
|
||||
|
||||
if (credStatus == credAbsent) {
|
||||
// Generate new credentials (key and self-signed certificate on it) only if credentials were absent previously
|
||||
//
|
||||
bPrepared = GenerateCredentials(
|
||||
defaultKeyPath,
|
||||
defaultCertPath,
|
||||
GetArg("-tlskeypwd", ""));
|
||||
// Generating key and the self-signed certificate for it
|
||||
//
|
||||
mykey = GenerateEcKey();
|
||||
if (mykey) {
|
||||
mycert = GenerateCertificate(mykey);
|
||||
if (mycert) {
|
||||
if (CheckKeyCert()) {
|
||||
LogPrintStr("TLS: New private key and self-signed certificate were generated successfully\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
//wolfSSL_X509_free(mycert);
|
||||
}
|
||||
//wolfSSL_EVP_PKEY_free(mykey);
|
||||
}
|
||||
|
||||
return bPrepared;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TLSManager::CheckKeyCert()
|
||||
{
|
||||
if (!mykey) {
|
||||
LogPrintf("Key is not generated!!!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mycert) {
|
||||
LogPrintf("Certificate is not generated!!!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
WOLFSSL_EC_KEY *eccKey = wolfSSL_EVP_PKEY_get1_EC_KEY(mykey);
|
||||
if (eccKey && wc_ecc_check_key((ecc_key*)eccKey->internal) == 0) {
|
||||
wolfSSL_EC_KEY_free(eccKey);
|
||||
} else {
|
||||
LogPrintf("Generated ECC key check failed!!!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wolfSSL_X509_verify(mycert, mykey) == WOLFSSL_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LogPrintf("Generated key and certificate do not match!!!\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief accept a TLS connection
|
||||
*
|
||||
* @param hSocket the TLS socket.
|
||||
* @param addr incoming address.
|
||||
* @param tls_ctx_server TLS server context.
|
||||
* @return SSL* returns pointer to the ssl object if successful, otherwise returns NULL
|
||||
* @return WOLFSSL* returns pointer to the ssl object if successful, otherwise returns NULL
|
||||
*/
|
||||
SSL* TLSManager::accept(SOCKET hSocket, const CAddress& addr)
|
||||
WOLFSSL* TLSManager::accept(SOCKET hSocket, const CAddress& addr, unsigned long& err_code)
|
||||
{
|
||||
LogPrint("net", "TLS: accepting connection from %s (tid = %X)\n", addr.ToString(), pthread_self());
|
||||
LogPrint("tls", "TLS: accepting connection from %s (tid = %X)\n", addr.ToString(), pthread_self());
|
||||
|
||||
SSL* ssl = NULL;
|
||||
err_code = 0;
|
||||
char err_buffer[1024];
|
||||
WOLFSSL* ssl = NULL;
|
||||
bool bAcceptedTLS = false;
|
||||
|
||||
if ((ssl = SSL_new(tls_ctx_server))) {
|
||||
if (SSL_set_fd(ssl, hSocket)) {
|
||||
if (TLSManager::waitFor(SSL_ACCEPT, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000)) == 1)
|
||||
if ((ssl = wolfSSL_new(tls_ctx_server))) {
|
||||
if (wolfSSL_set_fd(ssl, hSocket)) {
|
||||
int ret = TLSManager::waitFor(SSL_ACCEPT, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code);
|
||||
if (ret == 1)
|
||||
{
|
||||
bAcceptedTLS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_code = wolfSSL_ERR_get_error();
|
||||
const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
|
||||
LogPrint("tls", "TLS: %s: %s():%d - SSL_new failed err: %s\n",
|
||||
__FILE__, __func__, __LINE__, err_buffer);
|
||||
}
|
||||
|
||||
if (bAcceptedTLS) {
|
||||
LogPrintf("TLS: connection from %s has been accepted. Using cipher: %s\n", addr.ToString(), SSL_get_cipher(ssl));
|
||||
LogPrintf("TLS: connection from %s has been accepted (tlsv = %s 0x%04x / ssl = %s 0x%x ). Using cipher: %s\n",
|
||||
addr.ToString(), wolfSSL_get_version(ssl), wolfSSL_version(ssl), wolfSSL_OpenSSL_version(), wolfSSL_lib_version_hex(), wolfSSL_get_cipher(ssl));
|
||||
|
||||
WOLFSSL_STACK *sk = wolfSSL_get_ciphers_compat(ssl);
|
||||
for (int i = 0; i < wolfSSL_sk_SSL_CIPHER_num(sk); i++) {
|
||||
const WOLFSSL_CIPHER *c = wolfSSL_sk_SSL_CIPHER_value(sk, i);
|
||||
LogPrint("tls", "TLS: supporting cipher: %s\n", wolfSSL_CIPHER_get_name(c));
|
||||
}
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: TLS connection from %s failed\n", __FILE__, __func__, addr.ToString());
|
||||
LogPrintf("TLS: %s: %s():%d - TLS connection from %s failed (err_code 0x%X)\n",
|
||||
__FILE__, __func__, __LINE__, addr.ToString(), err_code);
|
||||
|
||||
if (ssl) {
|
||||
SSL_free(ssl);
|
||||
@@ -302,6 +474,7 @@ SSL* TLSManager::accept(SOCKET hSocket, const CAddress& addr)
|
||||
|
||||
return ssl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines whether a string exists in the non-TLS address pool.
|
||||
*
|
||||
@@ -316,6 +489,7 @@ bool TLSManager::isNonTLSAddr(const string& strAddr, const vector<NODE_ADDR>& vP
|
||||
LOCK(cs);
|
||||
return (find(vPool.begin(), vPool.end(), NODE_ADDR(strAddr)) != vPool.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes non-TLS node addresses based on timeout.
|
||||
*
|
||||
@@ -331,7 +505,7 @@ void TLSManager::cleanNonTLSPool(std::vector<NODE_ADDR>& vPool, CCriticalSection
|
||||
BOOST_FOREACH (NODE_ADDR nodeAddr, vPool) {
|
||||
if ((GetTimeMillis() - nodeAddr.time) >= 900000) {
|
||||
vDeleted.push_back(nodeAddr);
|
||||
LogPrint("net", "TLS: Node %s is deleted from the non-TLS pool\n", nodeAddr.ipAddr);
|
||||
LogPrint("tls", "TLS: Node %s is deleted from the non-TLS pool\n", nodeAddr.ipAddr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,16 +560,16 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds
|
||||
LOCK(pnode->cs_hSocket);
|
||||
|
||||
if (pnode->hSocket == INVALID_SOCKET) {
|
||||
LogPrint("net", "Receive: connection with %s is already closed\n", pnode->addr.ToString());
|
||||
LogPrint("tls", "Receive: connection with %s is already closed\n", pnode->addr.ToString());
|
||||
return -1;
|
||||
}
|
||||
|
||||
bIsSSL = (pnode->ssl != NULL);
|
||||
|
||||
if (bIsSSL) {
|
||||
ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread
|
||||
nBytes = SSL_read(pnode->ssl, pchBuf, sizeof(pchBuf));
|
||||
nRet = SSL_get_error(pnode->ssl, nBytes);
|
||||
wolfSSL_ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread
|
||||
nBytes = wolfSSL_read(pnode->ssl, pchBuf, sizeof(pchBuf));
|
||||
nRet = wolfSSL_get_error(pnode->ssl, nBytes);
|
||||
} else {
|
||||
nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
||||
nRet = WSAGetLastError();
|
||||
@@ -409,20 +583,35 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds
|
||||
pnode->nRecvBytes += nBytes;
|
||||
pnode->RecordBytesRecv(nBytes);
|
||||
} else if (nBytes == 0) {
|
||||
|
||||
if (bIsSSL) {
|
||||
unsigned long error = ERR_get_error();
|
||||
const char* error_str = ERR_error_string(error, NULL);
|
||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_read err: %s\n",
|
||||
__FILE__, __func__, __LINE__, error_str);
|
||||
}
|
||||
// socket closed gracefully (peer disconnected)
|
||||
//
|
||||
if (!pnode->fDisconnect)
|
||||
LogPrint("net", "socket closed (%s)\n", pnode->addr.ToString());
|
||||
LogPrint("tls", "socket closed (%s)\n", pnode->addr.ToString());
|
||||
pnode->CloseSocketDisconnect();
|
||||
|
||||
|
||||
} else if (nBytes < 0) {
|
||||
// error
|
||||
//
|
||||
if (bIsSSL) {
|
||||
if (nRet != SSL_ERROR_WANT_READ && nRet != SSL_ERROR_WANT_WRITE) // SSL_read() operation has to be repeated because of SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE (https://wiki.openssl.org/index.php/Manual:SSL_read(3)#NOTES)
|
||||
if (nRet != WOLFSSL_ERROR_WANT_READ && nRet != WOLFSSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
if (!pnode->fDisconnect)
|
||||
LogPrintf("ERROR: SSL_read %s\n", ERR_error_string(nRet, NULL));
|
||||
LogPrintf("TSL: ERROR: SSL_read %s\n", ERR_error_string(nRet, NULL));
|
||||
pnode->CloseSocketDisconnect();
|
||||
|
||||
unsigned long error = ERR_get_error();
|
||||
const char* error_str = ERR_error_string(error, NULL);
|
||||
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_read - code[0x%x], err: %s\n",
|
||||
__FILE__, __func__, __LINE__, nRet, error_str);
|
||||
|
||||
} else {
|
||||
// preventive measure from exhausting CPU usage
|
||||
//
|
||||
@@ -431,7 +620,7 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds
|
||||
} else {
|
||||
if (nRet != WSAEWOULDBLOCK && nRet != WSAEMSGSIZE && nRet != WSAEINTR && nRet != WSAEINPROGRESS) {
|
||||
if (!pnode->fDisconnect)
|
||||
LogPrintf("ERROR: socket recv %s\n", NetworkErrorString(nRet));
|
||||
LogPrintf("TSL: ERROR: socket recv %s\n", NetworkErrorString(nRet));
|
||||
pnode->CloseSocketDisconnect();
|
||||
}
|
||||
}
|
||||
@@ -448,8 +637,10 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds
|
||||
if (lockSend)
|
||||
SocketSendData(pnode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialization of the server and client contexts
|
||||
*
|
||||
@@ -460,44 +651,23 @@ bool TLSManager::initialize()
|
||||
{
|
||||
bool bInitializationStatus = false;
|
||||
|
||||
// Initialization routines for the OpenSSL library
|
||||
SSL_load_error_strings();
|
||||
ERR_load_crypto_strings();
|
||||
OpenSSL_add_ssl_algorithms(); // OpenSSL_add_ssl_algorithms() always returns "1", so it is safe to discard the return value.
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
fs::path certFile = GetArg("-tlscertpath", "");
|
||||
if (!fs::exists(certFile))
|
||||
certFile = (GetDataDir() / TLS_CERT_FILE_NAME);
|
||||
|
||||
fs::path privKeyFile = GetArg("-tlskeypath", "");
|
||||
if (!fs::exists(privKeyFile)) {
|
||||
privKeyFile = (GetDataDir() / TLS_KEY_FILE_NAME);
|
||||
}
|
||||
|
||||
std::vector<fs::path> trustedDirs;
|
||||
fs::path trustedDir = GetArg("-tlstrustdir", "");
|
||||
if (fs::exists(trustedDir)) {
|
||||
// Use only the specified trusted directory
|
||||
trustedDirs.push_back(trustedDir);
|
||||
} else {
|
||||
// If specified directory can't be used, then setting the default trusted directories
|
||||
trustedDirs = GetDefaultTrustedDirectories();
|
||||
}
|
||||
|
||||
for (fs::path dir : trustedDirs)
|
||||
LogPrintf("TLS: trusted directory '%s' will be used\n", dir.string().c_str());
|
||||
// Initialization routines for the WolfSSL library
|
||||
//
|
||||
wolfSSL_load_error_strings();
|
||||
wolfSSL_ERR_load_crypto_strings();
|
||||
wolfSSL_library_init();
|
||||
|
||||
// Initialization of the server and client contexts
|
||||
if ((tls_ctx_server = TLSManager::initCtx(SERVER_CONTEXT, privKeyFile, certFile, trustedDirs)))
|
||||
//
|
||||
if ((tls_ctx_server = TLSManager::initCtx(SERVER_CONTEXT)))
|
||||
{
|
||||
if ((tls_ctx_client = TLSManager::initCtx(CLIENT_CONTEXT, privKeyFile, certFile, trustedDirs)))
|
||||
if ((tls_ctx_client = TLSManager::initCtx(CLIENT_CONTEXT)))
|
||||
{
|
||||
LogPrint("net", "TLS: contexts are initialized\n");
|
||||
LogPrint("tls", "TLS: contexts are initialized\n");
|
||||
bInitializationStatus = true;
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: failed to initialize TLS client context\n", __FILE__, __func__);
|
||||
SSL_CTX_free (tls_ctx_server);
|
||||
wolfSSL_CTX_free (tls_ctx_server);
|
||||
}
|
||||
} else {
|
||||
LogPrintf("TLS: ERROR: %s: %s: failed to initialize TLS server context\n", __FILE__, __func__);
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
// Copyright (c) 2019-2020 The Hush developers
|
||||
// Distributed under the GPLv3 software license, see the accompanying
|
||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include "utiltls.h"
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include "tlsenums.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include "../util.h"
|
||||
#include "../protocol.h"
|
||||
#include "../net.h"
|
||||
#include "sync.h"
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@@ -43,19 +40,21 @@ bool operator==(const _NODE_ADDR b) const
|
||||
class TLSManager
|
||||
{
|
||||
public:
|
||||
int waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, SSL* ssl, int timeoutSec);
|
||||
SSL* connect(SOCKET hSocket, const CAddress& addrConnect);
|
||||
SSL_CTX* initCtx(
|
||||
TLSContextType ctxType,
|
||||
const boost::filesystem::path& privateKeyFile,
|
||||
const boost::filesystem::path& certificateFile,
|
||||
const std::vector<boost::filesystem::path>& trustedDirs);
|
||||
/* This is set as a custom error number which is not an error in SSL protocol.
|
||||
A true (not null) SSL error returned by ERR_get_error() consists of a library number,
|
||||
function code and reason code. */
|
||||
static const long SELECT_TIMEDOUT = 0xFFFFFFFF;
|
||||
|
||||
bool prepareCredentials();
|
||||
SSL* accept(SOCKET hSocket, const CAddress& addr);
|
||||
bool isNonTLSAddr(const string& strAddr, const vector<NODE_ADDR>& vPool, CCriticalSection& cs);
|
||||
void cleanNonTLSPool(std::vector<NODE_ADDR>& vPool, CCriticalSection& cs);
|
||||
int threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fdsetSend, fd_set& fdsetError);
|
||||
bool initialize();
|
||||
int waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL* ssl, int timeoutSec, unsigned long& err_code);
|
||||
|
||||
WOLFSSL* connect(SOCKET hSocket, const CAddress& addrConnect, unsigned long& err_code);
|
||||
WOLFSSL_CTX* initCtx(TLSContextType ctxType);
|
||||
bool prepareCredentials();
|
||||
WOLFSSL* accept(SOCKET hSocket, const CAddress& addr, unsigned long& err_code);
|
||||
bool isNonTLSAddr(const string& strAddr, const vector<NODE_ADDR>& vPool, CCriticalSection& cs);
|
||||
void cleanNonTLSPool(std::vector<NODE_ADDR>& vPool, CCriticalSection& cs);
|
||||
int threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fdsetSend, fd_set& fdsetError);
|
||||
bool initialize();
|
||||
bool CheckKeyCert();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,98 +6,34 @@
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
#include "util.h"
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include "../util.h"
|
||||
#include "utiltls.h"
|
||||
|
||||
namespace hush {
|
||||
|
||||
// Set of most common default trusted certificates directories used by OpenSSL
|
||||
static const char* defaultTrustedDirs[] =
|
||||
{
|
||||
#ifdef WIN32
|
||||
""
|
||||
#elif MAC_OSX
|
||||
"/System/Library/OpenSSL/certs"
|
||||
#else // Linux build
|
||||
"/etc/ssl/certs",
|
||||
"/usr/local/ssl/certs",
|
||||
"/usr/lib/ssl/certs",
|
||||
"/usr/share/ssl/certs",
|
||||
"/etc/pki/tls/certs",
|
||||
"/var/lib/ca-certificates"
|
||||
#endif
|
||||
};
|
||||
|
||||
// Default root certificates (PEM encoded)
|
||||
static const char defaultRootCerts[] =
|
||||
{
|
||||
// // Example of specifying a certificate
|
||||
// //
|
||||
// "-----BEGIN CERTIFICATE-----\n"
|
||||
// "MIIDYDCCAkigAwIBAgIJAJMakdoBYY67MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n"
|
||||
// "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n"
|
||||
// "aWRnaXRzIFB0eSBMdGQwHhcNMTcwODE0MTc0MTMyWhcNNDQxMjMwMTc0MTMyWjBF\n"
|
||||
// "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n"
|
||||
// "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
|
||||
// "CgKCAQEAzNV+SPRCKSEGlntfpCRMVSfz99NoEo3K1SRyw6GTSb1LNSTQCn1EsCSH\n"
|
||||
// "cVZTmyfjcTHpwz4aF14yw8lQC42f218AOsG1DV5suCaUXhSmZlajMkvEJVwfBOft\n"
|
||||
// "xpcqE1fA9wovXlnJLXVgyJGMc896S8tcbrCU/l/BsqKh5QX8N60MQ3w376nSGvVP\n"
|
||||
// "ussN8bVH3aKRwjhateqx1GRt0GPnM8/u7EkgF8Bc+m8WZYcUfkPC5Am2D0MO1HOA\n"
|
||||
// "u3IKxXZMs/fYd6nF5DZBwg+D23EP/V8oqenn8ilvrSORq5PguOl1QoDyY66PhmjN\n"
|
||||
// "L9c4Spxw8HXUDlrfuSQn2NJnw1XhdQIDAQABo1MwUTAdBgNVHQ4EFgQU/KD+n5Bz\n"
|
||||
// "QLbp09qKzwwyNwOQU4swHwYDVR0jBBgwFoAU/KD+n5BzQLbp09qKzwwyNwOQU4sw\n"
|
||||
// "DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVtprBxZD6O+WNYUM\n"
|
||||
// "ksdKiVVoszEJXlt7wajuaPBPK/K3buxE9FLVxS+LiH1PUhPCc6V28guyKWwn109/\n"
|
||||
// "4WnO51LQjygvd7SaePlbiO7iIatkOk4oETJQZ+tEJ7fv/NITY/GQUfgPNkANmPPz\n"
|
||||
// "Mz9I6He8XhIpO6NGuDG+74aR1RhvR3PWJJYT0QpL0STVR4qTc/HfnymF5XnnjOYZ\n"
|
||||
// "mwzT8jXX5dhLYwJmyPBS+uv+oa1quM/FitA63N9anYtRBiPaBtund9Ikjat1hM0h\n"
|
||||
// "neo2tz7Mfsgjb0aiORtiyaH2OetvwR0QuCSVPnknkfGWPDINdUdkgKyA1PX58Smw\n"
|
||||
// "vaXEcw==\n"
|
||||
// "-----END CERTIFICATE-----"
|
||||
|
||||
""
|
||||
};
|
||||
|
||||
// Generates RSA keypair (a private key of 'bits' length for a specified 'uPublicKey')
|
||||
// Generates EC keypair
|
||||
//
|
||||
static EVP_PKEY* GenerateRsaKey(int bits, BN_ULONG uPublicKey)
|
||||
WOLFSSL_EVP_PKEY* GenerateEcKey(int nid)
|
||||
{
|
||||
EVP_PKEY *evpPrivKey = NULL;
|
||||
|
||||
BIGNUM *pubKey = BN_new();
|
||||
if (pubKey)
|
||||
{
|
||||
if (BN_set_word(pubKey, uPublicKey))
|
||||
{
|
||||
RSA *privKey = RSA_new();
|
||||
if (privKey)
|
||||
{
|
||||
if (RAND_poll() && // The pseudo-random number generator must be seeded prior to calling RSA_generate_key_ex(). (https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key.html)
|
||||
RSA_generate_key_ex(privKey, bits, pubKey, NULL))
|
||||
{
|
||||
if ((evpPrivKey = EVP_PKEY_new()))
|
||||
{
|
||||
if (!EVP_PKEY_assign_RSA(evpPrivKey, privKey))
|
||||
{
|
||||
EVP_PKEY_free(evpPrivKey);
|
||||
evpPrivKey = NULL;
|
||||
}
|
||||
}
|
||||
WOLFSSL_EVP_PKEY *evpPrivKey = NULL;
|
||||
WOLFSSL_EC_KEY *privKey = wolfSSL_EC_KEY_new_by_curve_name(nid);
|
||||
if (privKey) {
|
||||
wolfSSL_EC_KEY_set_asn1_flag(privKey, OPENSSL_EC_NAMED_CURVE);
|
||||
if (wolfSSL_EC_KEY_generate_key(privKey)) {
|
||||
if ((evpPrivKey = wolfSSL_EVP_PKEY_new())) {
|
||||
if (!wolfSSL_EVP_PKEY_assign_EC_KEY(evpPrivKey, privKey)) {
|
||||
wolfSSL_EVP_PKEY_free(evpPrivKey);
|
||||
evpPrivKey = NULL;
|
||||
}
|
||||
|
||||
if(!evpPrivKey) // EVP_PKEY_assign_RSA uses the supplied key internally
|
||||
RSA_free(privKey);
|
||||
}
|
||||
}
|
||||
BN_free(pubKey);
|
||||
|
||||
if(!evpPrivKey) {
|
||||
wolfSSL_EC_KEY_free(privKey);
|
||||
evpPrivKey = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return evpPrivKey;
|
||||
@@ -105,391 +41,35 @@ static EVP_PKEY* GenerateRsaKey(int bits, BN_ULONG uPublicKey)
|
||||
|
||||
// Generates certificate for a specified public key using a corresponding private key (both of them should be specified in the 'keypair').
|
||||
//
|
||||
static X509* GenerateCertificate(EVP_PKEY *keypair)
|
||||
WOLFSSL_X509* GenerateCertificate(WOLFSSL_EVP_PKEY *keypair)
|
||||
{
|
||||
if (!keypair)
|
||||
if (!keypair) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
X509 *cert = X509_new();
|
||||
if (cert)
|
||||
{
|
||||
WOLFSSL_X509 *cert = wolfSSL_X509_new();
|
||||
if (cert) {
|
||||
bool bCertSigned = false;
|
||||
long sn = 0;
|
||||
|
||||
if (RAND_bytes((unsigned char*)&sn, sizeof sn) &&
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(cert), sn))
|
||||
{
|
||||
X509_gmtime_adj(X509_get_notBefore(cert), 0);
|
||||
X509_gmtime_adj(X509_get_notAfter(cert), (60 * 60 * 24 * CERT_VALIDITY_DAYS));
|
||||
|
||||
if (wolfSSL_RAND_bytes((unsigned char*)&sn, sizeof(sn)) &&wolfSSL_ASN1_INTEGER_set(wolfSSL_X509_get_serialNumber(cert), sn)) {
|
||||
wolfSSL_X509_gmtime_adj(wolfSSL_X509_get_notBefore(cert), 0);
|
||||
wolfSSL_X509_gmtime_adj(wolfSSL_X509_get_notAfter(cert), (60 * 60 * 24 * CERT_VALIDITY_DAYS));
|
||||
|
||||
// setting a public key from the keypair
|
||||
if (X509_set_pubkey(cert, keypair))
|
||||
{
|
||||
X509_NAME *subjectName = X509_get_subject_name(cert);
|
||||
if (subjectName)
|
||||
{
|
||||
// an issuer name is the same as a subject name, due to certificate is self-signed
|
||||
if (X509_set_issuer_name(cert, subjectName))
|
||||
{
|
||||
// private key from keypair is used; signature will be set inside of the cert
|
||||
bCertSigned = X509_sign(cert, keypair, EVP_sha512());
|
||||
}
|
||||
}
|
||||
if (wolfSSL_X509_set_pubkey(cert, keypair)) {
|
||||
// private key from keypair is used; signature will be set inside of the cert
|
||||
bCertSigned = wolfSSL_X509_sign(cert, keypair, wolfSSL_EVP_sha512());
|
||||
}
|
||||
}
|
||||
|
||||
if (!bCertSigned)
|
||||
{
|
||||
X509_free(cert);
|
||||
if (!bCertSigned) {
|
||||
wolfSSL_X509_free(cert);
|
||||
cert = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
// Stores key to file, specified by the 'filePath'
|
||||
//
|
||||
static bool StoreKey(EVP_PKEY *key, const boost::filesystem::path &filePath, const std::string &passphrase)
|
||||
{
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
bool bStored = false;
|
||||
|
||||
FILE *keyfd = fopen(filePath.string().c_str(), "wb");
|
||||
if (keyfd)
|
||||
{
|
||||
const EVP_CIPHER* pCipher = NULL;
|
||||
|
||||
if (passphrase.length() && (pCipher = EVP_aes_256_cbc()))
|
||||
bStored = PEM_write_PrivateKey(keyfd, key, pCipher, NULL, 0, NULL, (void*)passphrase.c_str());
|
||||
else
|
||||
bStored = PEM_write_PrivateKey(keyfd, key, NULL, NULL, 0, NULL, NULL);
|
||||
|
||||
fclose(keyfd);
|
||||
}
|
||||
|
||||
return bStored;
|
||||
}
|
||||
|
||||
// Stores certificate to file, specified by the 'filePath'
|
||||
//
|
||||
static bool StoreCertificate(X509 *cert, const boost::filesystem::path &filePath)
|
||||
{
|
||||
if (!cert)
|
||||
return false;
|
||||
|
||||
bool bStored = false;
|
||||
|
||||
FILE *certfd = fopen(filePath.string().c_str(), "wb");
|
||||
if (certfd)
|
||||
{
|
||||
bStored = PEM_write_X509(certfd, cert);
|
||||
fclose(certfd);
|
||||
}
|
||||
|
||||
return bStored;
|
||||
}
|
||||
|
||||
// Loads key from file, specified by the 'filePath'
|
||||
//
|
||||
static EVP_PKEY* LoadKey(const boost::filesystem::path &filePath, const std::string &passphrase)
|
||||
{
|
||||
if (!boost::filesystem::exists(filePath))
|
||||
return NULL;
|
||||
|
||||
EVP_PKEY *key = NULL;
|
||||
FILE *keyfd = fopen(filePath.string().c_str(), "rb");
|
||||
if (keyfd)
|
||||
{
|
||||
key = PEM_read_PrivateKey(keyfd, NULL, NULL, passphrase.length() ? (void*)passphrase.c_str() : NULL);
|
||||
fclose(keyfd);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
// Loads certificate from file, specified by the 'filePath'
|
||||
//
|
||||
static X509* LoadCertificate(const boost::filesystem::path &filePath)
|
||||
{
|
||||
if (!boost::filesystem::exists(filePath))
|
||||
return NULL;
|
||||
|
||||
X509 *cert = NULL;
|
||||
FILE *certfd = fopen(filePath.string().c_str(), "rb");
|
||||
if (certfd)
|
||||
{
|
||||
cert = PEM_read_X509(certfd, NULL, NULL, NULL);
|
||||
fclose(certfd);
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
// Verifies if the private key in 'key' matches the public key in 'cert'
|
||||
// (Signs random bytes on 'key' and verifies signature correctness on public key from 'cert')
|
||||
//
|
||||
static bool IsMatching(EVP_PKEY *key, X509 *cert)
|
||||
{
|
||||
if (!key || !cert)
|
||||
return false;
|
||||
|
||||
bool bIsMatching = false;
|
||||
|
||||
EVP_PKEY_CTX *ctxSign = EVP_PKEY_CTX_new(key, NULL);
|
||||
if (ctxSign)
|
||||
{
|
||||
if (EVP_PKEY_sign_init(ctxSign) == 1 &&
|
||||
EVP_PKEY_CTX_set_signature_md(ctxSign, EVP_sha512()) > 0)
|
||||
{
|
||||
unsigned char digest[SHA512_DIGEST_LENGTH] = { 0 };
|
||||
size_t digestSize = sizeof digest, signatureSize = 0;
|
||||
|
||||
if (RAND_bytes((unsigned char*)&digest, digestSize) && // set random bytes as a digest
|
||||
EVP_PKEY_sign(ctxSign, NULL, &signatureSize, digest, digestSize) == 1) // determine buffer length
|
||||
{
|
||||
unsigned char *signature = (unsigned char*)OPENSSL_malloc(signatureSize);
|
||||
if (signature)
|
||||
{
|
||||
if (EVP_PKEY_sign(ctxSign, signature, &signatureSize, digest, digestSize) == 1)
|
||||
{
|
||||
EVP_PKEY *pubkey = X509_get_pubkey(cert);
|
||||
if (pubkey)
|
||||
{
|
||||
EVP_PKEY_CTX *ctxVerif = EVP_PKEY_CTX_new(pubkey, NULL);
|
||||
if (ctxVerif)
|
||||
{
|
||||
if (EVP_PKEY_verify_init(ctxVerif) == 1 &&
|
||||
EVP_PKEY_CTX_set_signature_md(ctxVerif, EVP_sha512()) > 0)
|
||||
{
|
||||
bIsMatching = (EVP_PKEY_verify(ctxVerif, signature, signatureSize, digest, digestSize) == 1);
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctxVerif);
|
||||
}
|
||||
EVP_PKEY_free(pubkey);
|
||||
}
|
||||
}
|
||||
OPENSSL_free(signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctxSign);
|
||||
}
|
||||
|
||||
return bIsMatching;
|
||||
}
|
||||
|
||||
// Checks the correctness of a private-public key pair and the validity of a certificate using public key from key pair
|
||||
//
|
||||
static bool CheckCredentials(EVP_PKEY *key, X509 *cert)
|
||||
{
|
||||
if (!key || !cert)
|
||||
return false;
|
||||
|
||||
bool bIsOk = false;
|
||||
|
||||
// Validating the correctness of a private-public key pair, depending on a key type
|
||||
//
|
||||
switch (EVP_PKEY_base_id(key))
|
||||
{
|
||||
case EVP_PKEY_RSA:
|
||||
case EVP_PKEY_RSA2:
|
||||
{
|
||||
RSA *rsaKey = EVP_PKEY_get1_RSA(key);
|
||||
if (rsaKey)
|
||||
{
|
||||
bIsOk = (RSA_check_key(rsaKey) == 1);
|
||||
RSA_free(rsaKey);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Currently only RSA keys are supported.
|
||||
// Other key types can be added here in further.
|
||||
|
||||
default:
|
||||
bIsOk = false;
|
||||
}
|
||||
|
||||
// Verifying if the private key matches the public key in certificate
|
||||
if (bIsOk)
|
||||
bIsOk = IsMatching(key, cert);
|
||||
|
||||
return bIsOk;
|
||||
}
|
||||
|
||||
// Verifies credentials (a private key, a certificate for public key and a correspondence between the private and the public key)
|
||||
//
|
||||
CredentialsStatus VerifyCredentials(
|
||||
const boost::filesystem::path &keyPath,
|
||||
const boost::filesystem::path &certPath,
|
||||
const std::string &passphrase)
|
||||
{
|
||||
CredentialsStatus status = credAbsent;
|
||||
|
||||
EVP_PKEY *key = NULL;
|
||||
X509 *cert = NULL;
|
||||
|
||||
key = LoadKey(keyPath, passphrase);
|
||||
cert = LoadCertificate(certPath);
|
||||
|
||||
if (key && cert)
|
||||
status = CheckCredentials(key, cert) ? credOk : credNonConsistent;
|
||||
else if (!key && !cert)
|
||||
status = credAbsent;
|
||||
else
|
||||
status = credPartiallyAbsent;
|
||||
|
||||
if (key)
|
||||
EVP_PKEY_free(key);
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
|
||||
return status;
|
||||
return cert;
|
||||
}
|
||||
|
||||
// Generates public key pair and the self-signed certificate for it, and then stores them by the specified paths 'keyPath' and 'certPath' respectively.
|
||||
//
|
||||
bool GenerateCredentials(
|
||||
const boost::filesystem::path &keyPath,
|
||||
const boost::filesystem::path &certPath,
|
||||
const std::string &passphrase)
|
||||
{
|
||||
bool bGenerated = false;
|
||||
|
||||
EVP_PKEY *key = NULL;
|
||||
X509 *cert = NULL;
|
||||
|
||||
// Generating RSA key and the self-signed certificate for it
|
||||
//
|
||||
key = GenerateRsaKey(TLS_RSA_KEY_SIZE, RSA_F4);
|
||||
if (key)
|
||||
{
|
||||
cert = GenerateCertificate(key);
|
||||
if (cert)
|
||||
{
|
||||
if (StoreKey(key, keyPath, passphrase) &&
|
||||
StoreCertificate(cert, certPath))
|
||||
{
|
||||
bGenerated = true;
|
||||
LogPrintStr("TLS: New private key and self-signed certificate were generated successfully\n");
|
||||
}
|
||||
|
||||
X509_free(cert);
|
||||
}
|
||||
EVP_PKEY_free(key);
|
||||
}
|
||||
|
||||
return bGenerated;
|
||||
}
|
||||
|
||||
// Checks if certificate of a peer is valid (by internal means of the TLS protocol)
|
||||
//
|
||||
// Validates peer certificate using a chain of CA certificates.
|
||||
// If some of intermediate CA certificates are absent in the trusted certificates store, then validation status will be 'false')
|
||||
//
|
||||
bool ValidatePeerCertificate(SSL *ssl)
|
||||
{
|
||||
if (!ssl)
|
||||
return false;
|
||||
|
||||
bool bIsOk = false;
|
||||
|
||||
X509 *cert = SSL_get_peer_certificate (ssl);
|
||||
if (cert)
|
||||
{
|
||||
// NOTE: SSL_get_verify_result() is only useful in connection with SSL_get_peer_certificate (https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_verify_result.html)
|
||||
//
|
||||
bIsOk = (SSL_get_verify_result(ssl) == X509_V_OK);
|
||||
X509_free(cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint("net", "TLS: Peer does not have certificate\n");
|
||||
bIsOk = false;
|
||||
}
|
||||
return bIsOk;
|
||||
}
|
||||
|
||||
// Check if a given context is set up with a cert that can be validated by this context
|
||||
//
|
||||
bool ValidateCertificate(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
if (!ssl_ctx)
|
||||
return false;
|
||||
|
||||
bool bIsOk = false;
|
||||
|
||||
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
|
||||
|
||||
if (store)
|
||||
{
|
||||
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
|
||||
if (ctx)
|
||||
{
|
||||
if (X509_STORE_CTX_init(ctx, store, SSL_CTX_get0_certificate(ssl_ctx), NULL) == 1)
|
||||
bIsOk = X509_verify_cert(ctx) == 1;
|
||||
|
||||
X509_STORE_CTX_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
return bIsOk;
|
||||
}
|
||||
|
||||
// Creates the list of available OpenSSL default directories for trusted certificates storage
|
||||
//
|
||||
std::vector<boost::filesystem::path> GetDefaultTrustedDirectories()
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
std::vector<fs::path> defaultDirectoriesList;
|
||||
|
||||
// Default certificates directory specified in OpenSSL build
|
||||
fs::path libDefaultDir = X509_get_default_cert_dir();
|
||||
|
||||
if (fs::exists(libDefaultDir))
|
||||
defaultDirectoriesList.push_back(libDefaultDir);
|
||||
|
||||
// Check and set all possible standard default directories
|
||||
for (const char *dir : defaultTrustedDirs)
|
||||
{
|
||||
fs::path defaultDir(dir);
|
||||
|
||||
if (defaultDir != libDefaultDir &&
|
||||
fs::exists(defaultDir))
|
||||
defaultDirectoriesList.push_back(defaultDir);
|
||||
}
|
||||
|
||||
return defaultDirectoriesList;
|
||||
}
|
||||
|
||||
// Loads default root certificates (placed in the 'defaultRootCerts') into the specified context.
|
||||
// Returns the number of loaded certificates.
|
||||
//
|
||||
int LoadDefaultRootCertificates(SSL_CTX *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return 0;
|
||||
|
||||
int certsLoaded = 0;
|
||||
|
||||
// Certificate text buffer 'defaultRootCerts' is a C string with certificates in PEM format
|
||||
BIO *memBuf = BIO_new_mem_buf(defaultRootCerts, -1);
|
||||
if (memBuf)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
while ((cert = PEM_read_bio_X509(memBuf, NULL, 0, NULL)))
|
||||
{
|
||||
if (X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert) > 0)
|
||||
certsLoaded++;
|
||||
|
||||
X509_free(cert);
|
||||
}
|
||||
BIO_free(memBuf);
|
||||
}
|
||||
|
||||
return certsLoaded;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,51 +6,13 @@
|
||||
#ifndef UTILTLS_H
|
||||
#define UTILTLS_H
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
namespace hush {
|
||||
|
||||
#define TLS_KEY_FILE_NAME "key.pem" // default name of a private key
|
||||
#define TLS_CERT_FILE_NAME "cert.pem" // default name of a certificate
|
||||
|
||||
#define CERT_VALIDITY_DAYS (365 * 10) // period of validity, in days, for a self-signed certificate
|
||||
|
||||
#define TLS_RSA_KEY_SIZE 2048 // size of a private RSA key, in bits, that will be generated, if no other key is specified
|
||||
WOLFSSL_EVP_PKEY* GenerateEcKey(int nid = NID_X9_62_prime256v1);
|
||||
|
||||
typedef enum {credOk, credNonConsistent, credAbsent, credPartiallyAbsent} CredentialsStatus;
|
||||
|
||||
// Verifies credentials (a private key, a certificate for public key and a correspondence between the private and the public key)
|
||||
//
|
||||
CredentialsStatus VerifyCredentials(
|
||||
const boost::filesystem::path &keyPath,
|
||||
const boost::filesystem::path &certPath,
|
||||
const std::string &passphrase);
|
||||
|
||||
// Generates public key pair and the self-signed certificate for it, and then stores them by the specified paths 'keyPath' and 'certPath' respectively.
|
||||
//
|
||||
bool GenerateCredentials(
|
||||
const boost::filesystem::path &keyPath,
|
||||
const boost::filesystem::path &certPath,
|
||||
const std::string &passphrase);
|
||||
|
||||
// Checks if certificate of a peer is valid (by internal means of the TLS protocol)
|
||||
//
|
||||
// Validates peer certificate using a chain of CA certificates.
|
||||
// If some of intermediate CA certificates are absent in the trusted certificates store, then validation status will be 'false')
|
||||
//
|
||||
bool ValidatePeerCertificate(SSL *ssl);
|
||||
|
||||
// Check if a given context is set up with a cert that can be validated by this context
|
||||
//
|
||||
bool ValidateCertificate(SSL_CTX *ssl_ctx);
|
||||
|
||||
// Creates the list of available OpenSSL default directories for trusted certificates storage
|
||||
//
|
||||
std::vector<boost::filesystem::path> GetDefaultTrustedDirectories();
|
||||
|
||||
// Loads default root certificates (placed in the 'defaultRootCerts') into the specified context.
|
||||
// Returns the number of loaded certificates.
|
||||
//
|
||||
int LoadDefaultRootCertificates(SSL_CTX *ctx);
|
||||
WOLFSSL_X509* GenerateCertificate(WOLFSSL_EVP_PKEY *keypair);
|
||||
|
||||
}
|
||||
|
||||
|
||||
15
src/init.cpp
15
src/init.cpp
@@ -77,7 +77,8 @@
|
||||
#include <boost/interprocess/sync/file_lock.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <chrono>
|
||||
#include <openssl/crypto.h>
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <thread>
|
||||
|
||||
#if ENABLE_ZMQ
|
||||
@@ -296,6 +297,7 @@ void Shutdown()
|
||||
//pzcashParams = NULL;
|
||||
globalVerifyHandle.reset();
|
||||
ECC_Stop();
|
||||
CNode::NetCleanup();
|
||||
LogPrintf("%s: done\n", __func__);
|
||||
}
|
||||
|
||||
@@ -431,6 +433,8 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
|
||||
strUsage += HelpMessageOpt("-torpassword=<pass>", _("Tor control port password (default: empty)"));
|
||||
strUsage += HelpMessageOpt("-tls=<option>", _("Specify TLS usage (default: 1 => enabled and preferred, yet compatible); other options are -tls=0 to disable TLS and -tls=only to enforce it"));
|
||||
strUsage += HelpMessageOpt("-tlsfallbacknontls=<0 or 1>", _("If a TLS connection fails, the next connection attempt of the same peer (based on IP address) takes place without TLS (default: 1)"));
|
||||
strUsage += HelpMessageOpt("-tlsvalidate=<0 or 1>", _("Connect to peers only with valid certificates (default: 0)"));
|
||||
strUsage += HelpMessageOpt("-tlskeypath=<path>", _("Full path to a private key"));
|
||||
strUsage += HelpMessageOpt("-tlskeypwd=<password>", _("Password for a private key encryption (default: not set, i.e. private key will be stored unencrypted)"));
|
||||
strUsage += HelpMessageOpt("-tlscertpath=<path>", _("Full path to a certificate"));
|
||||
@@ -493,8 +497,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
|
||||
strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)");
|
||||
}
|
||||
string debugCategories = "addrman, alert, bench, coindb, db, deletetx, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, "
|
||||
"rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these
|
||||
string debugCategories = "addrman, alert, bench, coindb, db, deletetx, estimatefee, http, libevent, lock, mempool, net, tls, partitioncheck, pow, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these
|
||||
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
|
||||
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + _("<category> can be:") + " " + debugCategories + ".");
|
||||
strUsage += HelpMessageOpt("-experimentalfeatures", _("Enable use of experimental features"));
|
||||
@@ -756,7 +759,7 @@ void NoParamsShutdown(void)
|
||||
LogPrintf("Could not find valid Sapling params anywhere! Exiting...");
|
||||
uiInterface.ThreadSafeMessageBox(strprintf(
|
||||
_("Cannot find the Sapling network parameters! Something is very wrong.\n"
|
||||
"Please join our Discord for help: https://myhush.org/discord/")),
|
||||
"Please join our Telegram for help: https://hush.is/telegram_support")),
|
||||
"", CClientUIInterface::MSG_ERROR);
|
||||
StartShutdown();
|
||||
return;
|
||||
@@ -768,7 +771,7 @@ void CorruptParamsShutdown(void)
|
||||
LogPrintf("We detected corrupt Sapling params! Exiting...");
|
||||
uiInterface.ThreadSafeMessageBox(strprintf(
|
||||
_("Corrupt Sapling network parameters were detected! Something is very wrong.\n"
|
||||
"Please join our Discord for help: https://myhush.org/discord/")),
|
||||
"Please join our Telegram for help: https://hush.is/telegram_support")),
|
||||
"", CClientUIInterface::MSG_ERROR);
|
||||
StartShutdown();
|
||||
return;
|
||||
@@ -1433,7 +1436,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
|
||||
if (fPrintToDebugLog)
|
||||
OpenDebugLog();
|
||||
LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
|
||||
LogPrintf("Using WolfSSL version %s\n", wolfSSL_lib_version());
|
||||
#ifdef ENABLE_WALLET
|
||||
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
|
||||
#endif
|
||||
|
||||
388
src/net.cpp
388
src/net.cpp
@@ -44,9 +44,8 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <hush/tlsmanager.cpp>
|
||||
using namespace hush;
|
||||
|
||||
@@ -69,7 +68,13 @@ using namespace hush;
|
||||
#endif
|
||||
|
||||
#define USE_TLS
|
||||
#define COMPAT_NON_TLS // enables compatibility with nodes, that still doesn't support TLS connections
|
||||
|
||||
#if defined(USE_TLS) && !defined(TLS1_3_VERSION)
|
||||
// minimum secure protocol is 1.3
|
||||
// TLS1_3_VERSION is defined in openssl/tls1.h
|
||||
#error "ERROR: Your WolfSSL version does not support TLS v1.3"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -133,8 +138,8 @@ static boost::condition_variable messageHandlerCondition;
|
||||
static CNodeSignals g_signals;
|
||||
CNodeSignals& GetNodeSignals() { return g_signals; }
|
||||
|
||||
// OpenSSL server and client contexts
|
||||
SSL_CTX *tls_ctx_server, *tls_ctx_client;
|
||||
// WolfSSL server and client contexts
|
||||
WOLFSSL_CTX *tls_ctx_server, *tls_ctx_client;
|
||||
|
||||
static bool operator==(_NODE_ADDR a, _NODE_ADDR b)
|
||||
{
|
||||
@@ -359,6 +364,9 @@ void AddressCurrentlyConnected(const CService& addr)
|
||||
}
|
||||
|
||||
|
||||
CNode::eTlsOption CNode::tlsFallbackNonTls = CNode::eTlsOption::FALLBACK_UNSET;
|
||||
CNode::eTlsOption CNode::tlsValidate = CNode::eTlsOption::FALLBACK_UNSET;
|
||||
|
||||
uint64_t CNode::nTotalBytesRecv = 0;
|
||||
uint64_t CNode::nTotalBytesSent = 0;
|
||||
CCriticalSection CNode::cs_totalBytesRecv;
|
||||
@@ -434,55 +442,73 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
|
||||
|
||||
addrman.Attempt(addrConnect);
|
||||
|
||||
SSL *ssl = NULL;
|
||||
|
||||
WOLFSSL *ssl = NULL;
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* TCP connection is ready. Do client side SSL. */
|
||||
#ifdef COMPAT_NON_TLS
|
||||
if (CNode::GetTlsFallbackNonTls())
|
||||
{
|
||||
LOCK(cs_vNonTLSNodesOutbound);
|
||||
|
||||
NODE_ADDR nodeAddr(addrConnect.ToStringIP());
|
||||
|
||||
bool bUseTLS = ((GetBoolArg("-tls", true) || GetArg("-tls", "") == "only") && find(vNonTLSNodesOutbound.begin(),
|
||||
vNonTLSNodesOutbound.end(),
|
||||
nodeAddr) == vNonTLSNodesOutbound.end());
|
||||
|
||||
if (bUseTLS)
|
||||
{
|
||||
ssl = tlsmanager.connect(hSocket, addrConnect);
|
||||
if (!ssl)
|
||||
LOCK(cs_vNonTLSNodesOutbound);
|
||||
|
||||
LogPrint("tls", "%s():%d - handling connection to %s\n", __func__, __LINE__, addrConnect.ToString());
|
||||
|
||||
NODE_ADDR nodeAddr(addrConnect.ToStringIP());
|
||||
|
||||
bool bUseTLS = ((GetBoolArg("-tls", true) || GetArg("-tls", "") == "only")
|
||||
&& find(vNonTLSNodesOutbound.begin(),
|
||||
vNonTLSNodesOutbound.end(),
|
||||
nodeAddr) == vNonTLSNodesOutbound.end());
|
||||
unsigned long err_code = 0;
|
||||
if (bUseTLS)
|
||||
{
|
||||
if (GetArg("-tls", "") != "only")
|
||||
ssl = tlsmanager.connect(hSocket, addrConnect, err_code);
|
||||
if (!ssl)
|
||||
{
|
||||
// Further reconnection will be made in non-TLS (unencrypted) mode if mandatory tls is not set
|
||||
vNonTLSNodesOutbound.push_back(NODE_ADDR(addrConnect.ToStringIP(), GetTimeMillis()));
|
||||
if (err_code == TLSManager::SELECT_TIMEDOUT)
|
||||
{
|
||||
// can fail for timeout in select on fd, that is not a ssl error and we should not
|
||||
// consider this node as non TLS
|
||||
LogPrint("tls", "%s():%d - Connection to %s timedout\n",
|
||||
__func__, __LINE__, addrConnect.ToStringIP());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Further reconnection will be made in non-TLS (unencrypted) mode
|
||||
vNonTLSNodesOutbound.push_back(NODE_ADDR(addrConnect.ToStringIP(), GetTimeMillis()));
|
||||
LogPrint("tls", "%s():%d - err_code %x, adding connection to %s vNonTLSNodesOutbound list (sz=%d)\n",
|
||||
__func__, __LINE__, err_code, addrConnect.ToStringIP(), vNonTLSNodesOutbound.size());
|
||||
}
|
||||
CloseSocket(hSocket);
|
||||
return NULL;
|
||||
}
|
||||
CloseSocket(hSocket);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrintf ("Connection to %s will be unencrypted\n", addrConnect.ToString());
|
||||
|
||||
vNonTLSNodesOutbound.erase(
|
||||
remove(
|
||||
vNonTLSNodesOutbound.begin(),
|
||||
vNonTLSNodesOutbound.end(),
|
||||
nodeAddr),
|
||||
vNonTLSNodesOutbound.end());
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long err_code = 0;
|
||||
ssl = tlsmanager.connect(hSocket, addrConnect, err_code);
|
||||
if(!ssl)
|
||||
{
|
||||
LogPrintf ("Connection to %s will be unencrypted\n", addrConnect.ToString());
|
||||
|
||||
vNonTLSNodesOutbound.erase(
|
||||
remove(
|
||||
vNonTLSNodesOutbound.begin(),
|
||||
vNonTLSNodesOutbound.end(),
|
||||
nodeAddr),
|
||||
vNonTLSNodesOutbound.end());
|
||||
LogPrint("tls", "%s():%d - err_code %x, connection to %s failed)\n",
|
||||
__func__, __LINE__, err_code, addrConnect.ToStringIP());
|
||||
CloseSocket(hSocket);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
ssl = TLSManager::connect(hSocket, addrConnect);
|
||||
if(!ssl)
|
||||
{
|
||||
CloseSocket(hSocket);
|
||||
return NULL;
|
||||
}
|
||||
#endif // COMPAT_NON_TLS
|
||||
|
||||
|
||||
#endif // USE_TLS
|
||||
|
||||
// Add node
|
||||
@@ -509,15 +535,15 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
|
||||
void CNode::CloseSocketDisconnect()
|
||||
{
|
||||
fDisconnect = true;
|
||||
|
||||
|
||||
{
|
||||
LOCK(cs_hSocket);
|
||||
|
||||
if (hSocket != INVALID_SOCKET)
|
||||
{
|
||||
|
||||
if (hSocket != INVALID_SOCKET)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogPrint("net", "disconnecting peer=%d\n", id);
|
||||
LogPrint("net", "disconnecting peer=%d\n", id);
|
||||
}
|
||||
catch(std::bad_alloc&)
|
||||
{
|
||||
@@ -528,13 +554,13 @@ void CNode::CloseSocketDisconnect()
|
||||
|
||||
if (ssl)
|
||||
{
|
||||
|
||||
tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000));
|
||||
SSL_free(ssl);
|
||||
unsigned long err_code = 0;
|
||||
tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code);
|
||||
wolfSSL_free(ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
CloseSocket(hSocket);
|
||||
}
|
||||
CloseSocket(hSocket);
|
||||
}
|
||||
}
|
||||
|
||||
// in case this fails, we'll empty the recv buffer when the CNode is deleted
|
||||
@@ -707,7 +733,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
|
||||
// If ssl != NULL it means TLS connection was established successfully
|
||||
{
|
||||
LOCK(cs_hSocket);
|
||||
stats.fTLSEstablished = (ssl != NULL) && (SSL_get_state(ssl) == TLS_ST_OK);
|
||||
stats.fTLSEstablished = (ssl != NULL) && (wolfSSL_is_init_finished(ssl) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,20 +838,20 @@ void SocketSendData(CNode *pnode)
|
||||
int nBytes = 0, nRet = 0;
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
|
||||
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
{
|
||||
LogPrint("net", "Send: connection with %s is already closed\n", pnode->addr.ToString());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
bIsSSL = (pnode->ssl != NULL);
|
||||
|
||||
|
||||
if (bIsSSL)
|
||||
{
|
||||
ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread
|
||||
nBytes = SSL_write(pnode->ssl, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset);
|
||||
nRet = SSL_get_error(pnode->ssl, nBytes);
|
||||
wolfSSL_ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread
|
||||
nBytes = wolfSSL_write(pnode->ssl, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset);
|
||||
nRet = wolfSSL_get_error(pnode->ssl, nBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -853,18 +879,18 @@ void SocketSendData(CNode *pnode)
|
||||
//
|
||||
if (bIsSSL)
|
||||
{
|
||||
if (nRet != SSL_ERROR_WANT_READ && nRet != SSL_ERROR_WANT_WRITE)
|
||||
if (nRet != WOLFSSL_ERROR_WANT_READ && nRet != WOLFSSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
LogPrintf("ERROR: SSL_write %s; closing connection\n", ERR_error_string(nRet, NULL));
|
||||
pnode->CloseSocketDisconnect();
|
||||
}
|
||||
LogPrintf("ERROR: SSL_write %s; closing connection\n", wolfSSL_ERR_error_string(nRet, NULL));
|
||||
pnode->CloseSocketDisconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
// preventive measure from exhausting CPU usage
|
||||
//
|
||||
MilliSleep(1); // 1 msec
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nRet != WSAEWOULDBLOCK && nRet != WSAEMSGSIZE && nRet != WSAEINTR && nRet != WSAEINPROGRESS)
|
||||
@@ -1154,30 +1180,42 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
|
||||
#endif
|
||||
|
||||
SSL *ssl = NULL;
|
||||
|
||||
WOLFSSL *ssl = NULL;
|
||||
|
||||
SetSocketNonBlocking(hSocket, true);
|
||||
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* TCP connection is ready. Do server side SSL. */
|
||||
#ifdef COMPAT_NON_TLS
|
||||
if (CNode::GetTlsFallbackNonTls())
|
||||
{
|
||||
LOCK(cs_vNonTLSNodesInbound);
|
||||
|
||||
LogPrint("tls", "%s():%d - handling connection from %s\n", __func__, __LINE__, addr.ToString());
|
||||
|
||||
NODE_ADDR nodeAddr(addr.ToStringIP());
|
||||
|
||||
bool bUseTLS = ((GetBoolArg("-tls", true) || GetArg("-tls", "") == "only") && find(vNonTLSNodesInbound.begin(),
|
||||
|
||||
bool bUseTLS = ((GetBoolArg("-tls", true) || GetArg("-tls", "") == "only")
|
||||
&& find(vNonTLSNodesInbound.begin(),
|
||||
vNonTLSNodesInbound.end(),
|
||||
nodeAddr) == vNonTLSNodesInbound.end());
|
||||
unsigned long err_code = 0;
|
||||
if (bUseTLS)
|
||||
{
|
||||
ssl = tlsmanager.accept( hSocket, addr);
|
||||
ssl = tlsmanager.accept( hSocket, addr, err_code);
|
||||
if(!ssl)
|
||||
{
|
||||
if (GetArg("-tls", "") != "only")
|
||||
if (err_code == TLSManager::SELECT_TIMEDOUT)
|
||||
{
|
||||
// Further reconnection will be made in non-TLS (unencrypted) mode if mandatory tls is not set
|
||||
// can fail also for timeout in select on fd, that is not a ssl error and we should not
|
||||
// consider this node as non TLS
|
||||
LogPrint("tls", "%s():%d - Connection from %s timedout\n", __func__, __LINE__, addr.ToStringIP());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Further reconnection will be made in non-TLS (unencrypted) mode
|
||||
vNonTLSNodesInbound.push_back(NODE_ADDR(addr.ToStringIP(), GetTimeMillis()));
|
||||
LogPrint("tls", "%s():%d - err_code %x, adding connection from %s vNonTLSNodesInbound list (sz=%d)\n",
|
||||
__func__, __LINE__, err_code, addr.ToStringIP(), vNonTLSNodesInbound.size());
|
||||
}
|
||||
CloseSocket(hSocket);
|
||||
return;
|
||||
@@ -1185,8 +1223,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrintf ("TLS: Connection from %s will be unencrypted\n", addr.ToString());
|
||||
|
||||
LogPrintf ("TLS: Connection from %s will be unencrypted\n", addr.ToStringIP());
|
||||
|
||||
vNonTLSNodesInbound.erase(
|
||||
remove(
|
||||
vNonTLSNodesInbound.begin(),
|
||||
@@ -1196,14 +1234,19 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
vNonTLSNodesInbound.end());
|
||||
}
|
||||
}
|
||||
#else
|
||||
ssl = TLSManager::accept( hSocket, addr);
|
||||
if(!ssl)
|
||||
else
|
||||
{
|
||||
CloseSocket(hSocket);
|
||||
return;
|
||||
unsigned long err_code = 0;
|
||||
ssl = tlsmanager.accept( hSocket, addr, err_code);
|
||||
if(!ssl)
|
||||
{
|
||||
LogPrint("tls", "%s():%d - err_code %x, failure accepting connection from %s\n",
|
||||
__func__, __LINE__, err_code, addr.ToStringIP());
|
||||
CloseSocket(hSocket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // COMPAT_NON_TLS
|
||||
|
||||
#endif // USE_TLS
|
||||
|
||||
CNode* pnode = new CNode(hSocket, addr, "", true, ssl);
|
||||
@@ -1218,7 +1261,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_TLS) && defined(COMPAT_NON_TLS)
|
||||
#if defined(USE_TLS)
|
||||
void ThreadNonTLSPoolsCleaner()
|
||||
{
|
||||
while (true)
|
||||
@@ -1228,7 +1271,9 @@ void ThreadNonTLSPoolsCleaner()
|
||||
MilliSleep(DEFAULT_CONNECT_TIMEOUT); // sleep and sleep_for are interruption points, which will throw boost::thread_interrupted
|
||||
}
|
||||
}
|
||||
#endif // USE_TLS && COMPAT_NON_TLS
|
||||
|
||||
#endif // USE_TLS
|
||||
|
||||
|
||||
void ThreadSocketHandler()
|
||||
{
|
||||
@@ -1325,9 +1370,10 @@ void ThreadSocketHandler()
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
|
||||
|
||||
FD_SET(pnode->hSocket, &fdsetError);
|
||||
hSocketMax = max(hSocketMax, pnode->hSocket);
|
||||
have_fds = true;
|
||||
@@ -1347,6 +1393,7 @@ void ThreadSocketHandler()
|
||||
// * We send some data.
|
||||
// * We wait for data to be received (and disconnect after timeout).
|
||||
// * We process a message in the buffer (message handler thread).
|
||||
|
||||
{
|
||||
TRY_LOCK(pnode->cs_vSend, lockSend);
|
||||
if (lockSend && !pnode->vSendMsg.empty()) {
|
||||
@@ -1407,8 +1454,9 @@ void ThreadSocketHandler()
|
||||
{
|
||||
boost::this_thread::interruption_point();
|
||||
|
||||
if (tlsmanager.threadSocketHandler(pnode,fdsetRecv,fdsetSend,fdsetError)==-1)
|
||||
if (tlsmanager.threadSocketHandler(pnode,fdsetRecv,fdsetSend,fdsetError)==-1){
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Inactivity checking
|
||||
@@ -1538,6 +1586,7 @@ void ThreadOpenConnections()
|
||||
{
|
||||
CAddress addr;
|
||||
OpenNetworkConnection(addr, NULL, strAddr.c_str());
|
||||
|
||||
for (int i = 0; i < 10 && i < nLoop; i++)
|
||||
{
|
||||
MilliSleep(500);
|
||||
@@ -1721,30 +1770,32 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
|
||||
return false;
|
||||
} else if (FindNode(std::string(pszDest)))
|
||||
return false;
|
||||
|
||||
|
||||
CNode* pnode = ConnectNode(addrConnect, pszDest);
|
||||
boost::this_thread::interruption_point();
|
||||
|
||||
#if defined(USE_TLS) && defined(COMPAT_NON_TLS)
|
||||
|
||||
if (!pnode)
|
||||
|
||||
#if defined(USE_TLS)
|
||||
if (CNode::GetTlsFallbackNonTls())
|
||||
{
|
||||
string strDest;
|
||||
int port;
|
||||
|
||||
if (!pszDest)
|
||||
strDest = addrConnect.ToStringIP();
|
||||
else
|
||||
SplitHostPort(string(pszDest), port, strDest);
|
||||
|
||||
if (tlsmanager.isNonTLSAddr(strDest, vNonTLSNodesOutbound, cs_vNonTLSNodesOutbound))
|
||||
if (!pnode)
|
||||
{
|
||||
// Attempt to reconnect in non-TLS mode
|
||||
pnode = ConnectNode(addrConnect, pszDest);
|
||||
boost::this_thread::interruption_point();
|
||||
string strDest;
|
||||
int port;
|
||||
|
||||
if (!pszDest)
|
||||
strDest = addrConnect.ToStringIP();
|
||||
else
|
||||
SplitHostPort(string(pszDest), port, strDest);
|
||||
|
||||
if (tlsmanager.isNonTLSAddr(strDest, vNonTLSNodesOutbound, cs_vNonTLSNodesOutbound))
|
||||
{
|
||||
// Attempt to reconnect in non-TLS mode
|
||||
pnode = ConnectNode(addrConnect, pszDest);
|
||||
boost::this_thread::interruption_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
if (!pnode)
|
||||
@@ -1836,6 +1887,7 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste
|
||||
// Create socket for listening for incoming connections
|
||||
struct sockaddr_storage sockaddr;
|
||||
socklen_t len = sizeof(sockaddr);
|
||||
|
||||
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
|
||||
{
|
||||
strError = strprintf("Error: Bind address family for %s not supported", addrBind.ToString());
|
||||
@@ -2008,13 +2060,13 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
Discover(threadGroup);
|
||||
|
||||
#ifdef USE_TLS
|
||||
|
||||
|
||||
if (!tlsmanager.prepareCredentials())
|
||||
{
|
||||
LogPrintf("TLS: ERROR: %s: %s: Credentials weren't loaded. Node can't be started.\n", __FILE__, __func__);
|
||||
LogPrintf("TLS: ERROR: %s: %s: Credentials weren't generated. Node can't be started.\n", __FILE__, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!tlsmanager.initialize())
|
||||
{
|
||||
LogPrintf("TLS: ERROR: %s: %s: TLS initialization failed. Node can't be started.\n", __FILE__, __func__);
|
||||
@@ -2051,11 +2103,14 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
// Process messages
|
||||
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
|
||||
|
||||
#if defined(USE_TLS) && defined(COMPAT_NON_TLS)
|
||||
// Clean pools of addresses for non-TLS connections
|
||||
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "poolscleaner", &ThreadNonTLSPoolsCleaner));
|
||||
#if defined(USE_TLS)
|
||||
if (CNode::GetTlsFallbackNonTls())
|
||||
{
|
||||
// Clean pools of addresses for non-TLS connections
|
||||
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "poolscleaner", &ThreadNonTLSPoolsCleaner));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Dump network addresses
|
||||
scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL);
|
||||
}
|
||||
@@ -2076,42 +2131,34 @@ bool StopNode()
|
||||
return true;
|
||||
}
|
||||
|
||||
static class CNetCleanup
|
||||
void CNode::NetCleanup()
|
||||
{
|
||||
public:
|
||||
CNetCleanup() {}
|
||||
// Close sockets
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
pnode->CloseSocketDisconnect();
|
||||
BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
|
||||
if (hListenSocket.socket != INVALID_SOCKET)
|
||||
if (!CloseSocket(hListenSocket.socket))
|
||||
LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
|
||||
|
||||
~CNetCleanup()
|
||||
{
|
||||
// Close sockets
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
if (pnode->hSocket != INVALID_SOCKET)
|
||||
CloseSocket(pnode->hSocket);
|
||||
BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
|
||||
if (hListenSocket.socket != INVALID_SOCKET)
|
||||
if (!CloseSocket(hListenSocket.socket))
|
||||
LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
|
||||
// clean up some globals (to help leak detection)
|
||||
BOOST_FOREACH(CNode *pnode, vNodes)
|
||||
delete pnode;
|
||||
BOOST_FOREACH(CNode *pnode, vNodesDisconnected)
|
||||
delete pnode;
|
||||
vNodes.clear();
|
||||
vNodesDisconnected.clear();
|
||||
vhListenSocket.clear();
|
||||
delete semOutbound;
|
||||
semOutbound = NULL;
|
||||
delete pnodeLocalHost;
|
||||
pnodeLocalHost = NULL;
|
||||
|
||||
// clean up some globals (to help leak detection)
|
||||
BOOST_FOREACH(CNode *pnode, vNodes)
|
||||
delete pnode;
|
||||
BOOST_FOREACH(CNode *pnode, vNodesDisconnected)
|
||||
delete pnode;
|
||||
vNodes.clear();
|
||||
vNodesDisconnected.clear();
|
||||
vhListenSocket.clear();
|
||||
delete semOutbound;
|
||||
semOutbound = NULL;
|
||||
delete pnodeLocalHost;
|
||||
pnodeLocalHost = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Shutdown Windows Sockets
|
||||
WSACleanup();
|
||||
#ifdef WIN32
|
||||
// Shutdown Windows Sockets
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
instance_of_cnetcleanup;
|
||||
|
||||
void RelayTransaction(const CTransaction& tx)
|
||||
{
|
||||
@@ -2314,7 +2361,7 @@ bool CAddrDB::Read(CAddrMan& addr)
|
||||
unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
|
||||
unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
|
||||
|
||||
CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn, SSL *sslIn) :
|
||||
CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn, WOLFSSL *sslIn) :
|
||||
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
|
||||
addrKnown(5000, 0.001),
|
||||
setInventoryKnown(SendBufferSize() / 1000)
|
||||
@@ -2372,22 +2419,65 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
|
||||
GetNodeSignals().InitializeNode(GetId(), this);
|
||||
}
|
||||
|
||||
bool CNode::GetTlsFallbackNonTls()
|
||||
{
|
||||
if (tlsFallbackNonTls == eTlsOption::FALLBACK_UNSET)
|
||||
{
|
||||
// one time only setting of static class attribute
|
||||
if ( GetArg("-tls", "") != "only" )
|
||||
{
|
||||
LogPrint("tls", "%s():%d - Non-TLS connections will be used in case of failure of TLS\n",
|
||||
__func__, __LINE__);
|
||||
tlsFallbackNonTls = eTlsOption::FALLBACK_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint("tls", "%s():%d - Non-TLS connections will NOT be used in case of failure of TLS\n",
|
||||
__func__, __LINE__);
|
||||
tlsFallbackNonTls = eTlsOption::FALLBACK_FALSE;
|
||||
}
|
||||
}
|
||||
return (tlsFallbackNonTls == eTlsOption::FALLBACK_TRUE);
|
||||
}
|
||||
|
||||
bool CNode::GetTlsValidate()
|
||||
{
|
||||
if (tlsValidate == eTlsOption::FALLBACK_UNSET)
|
||||
{
|
||||
// one time only setting of static class attribute
|
||||
if ( GetBoolArg("-tlsvalidate", false))
|
||||
{
|
||||
LogPrint("tls", "%s():%d - TLS certificates will be validated\n",
|
||||
__func__, __LINE__);
|
||||
tlsValidate = eTlsOption::FALLBACK_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint("tls", "%s():%d - TLS certificates will NOT be validated\n",
|
||||
__func__, __LINE__);
|
||||
tlsValidate = eTlsOption::FALLBACK_FALSE;
|
||||
}
|
||||
}
|
||||
return (tlsValidate == eTlsOption::FALLBACK_TRUE);
|
||||
}
|
||||
|
||||
CNode::~CNode()
|
||||
{
|
||||
// No need to make a lock on cs_hSocket, because before deletion CNode object is removed from the vNodes vector, so any other thread hasn't access to it.
|
||||
// Removal is synchronized with read and write routines, so all of them will be completed to this moment.
|
||||
|
||||
|
||||
if (hSocket != INVALID_SOCKET)
|
||||
{
|
||||
if (ssl)
|
||||
{
|
||||
tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000));
|
||||
|
||||
SSL_free(ssl);
|
||||
unsigned long err_code = 0;
|
||||
tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code);
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
|
||||
CloseSocket(hSocket);
|
||||
|
||||
CloseSocket(hSocket);
|
||||
}
|
||||
|
||||
if (pfilter)
|
||||
|
||||
32
src/net.h
32
src/net.h
@@ -46,9 +46,9 @@
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/signals2/signal.hpp>
|
||||
|
||||
// Enable OpenSSL Support for Hush
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
// Enable WolfSSL Support for Hush
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
class CAddrMan;
|
||||
class CBlockIndex;
|
||||
@@ -103,14 +103,6 @@ EVP_PKEY *generate_key();
|
||||
X509 *generate_x509(EVP_PKEY *pkey);
|
||||
bool write_to_disk(EVP_PKEY *pkey, X509 *x509);
|
||||
void configure_context(SSL_CTX *ctx, bool server_side);
|
||||
static boost::filesystem::path tlsKeyPath;
|
||||
static boost::filesystem::path tlsCertPath;
|
||||
|
||||
// OpenSSL related variables for metrics.cpp
|
||||
static std::string routingsecrecy;
|
||||
static std::string cipherdescription;
|
||||
static std::string securitylevel;
|
||||
static std::string validationdescription;
|
||||
|
||||
typedef int NodeId;
|
||||
|
||||
@@ -214,6 +206,7 @@ public:
|
||||
NodeId nodeid;
|
||||
uint64_t nServices;
|
||||
bool fTLSEstablished;
|
||||
bool fTLSVerified;
|
||||
int64_t nLastSend;
|
||||
int64_t nLastRecv;
|
||||
int64_t nTimeConnected;
|
||||
@@ -359,6 +352,14 @@ protected:
|
||||
// Basic fuzz-testing
|
||||
void Fuzz(int nChance); // modifies ssSend
|
||||
|
||||
enum class eTlsOption {
|
||||
FALLBACK_UNSET = 0,
|
||||
FALLBACK_FALSE = 1,
|
||||
FALLBACK_TRUE = 2
|
||||
};
|
||||
static eTlsOption tlsFallbackNonTls;
|
||||
static eTlsOption tlsValidate;
|
||||
|
||||
public:
|
||||
uint256 hashContinue;
|
||||
int nStartingHeight;
|
||||
@@ -459,7 +460,7 @@ public:
|
||||
if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) {
|
||||
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
|
||||
vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr;
|
||||
} else {
|
||||
} else {
|
||||
vAddrToSend.push_back(addr);
|
||||
}
|
||||
}
|
||||
@@ -693,6 +694,13 @@ public:
|
||||
|
||||
static uint64_t GetTotalBytesRecv();
|
||||
static uint64_t GetTotalBytesSent();
|
||||
|
||||
// resource deallocation on cleanup, called at node shutdown
|
||||
static void NetCleanup();
|
||||
|
||||
// returns the value of the tlsfallbacknontls and tlsvalidate flags set at zend startup (see init.cpp)
|
||||
static bool GetTlsFallbackNonTls();
|
||||
static bool GetTlsValidate();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -3,11 +3,33 @@
|
||||
// Distributed under the GPLv3 software license, see the accompanying
|
||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
|
||||
#include "cleanse.h"
|
||||
#include <support/cleanse.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <Windows.h> // For SecureZeroMemory.
|
||||
#endif
|
||||
|
||||
void memory_cleanse(void *ptr, size_t len)
|
||||
{
|
||||
OPENSSL_cleanse(ptr, len);
|
||||
#if defined(_MSC_VER)
|
||||
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
|
||||
SecureZeroMemory(ptr, len);
|
||||
#else
|
||||
std::memset(ptr, 0, len);
|
||||
|
||||
/* Memory barrier that scares the compiler away from optimizing out the memset.
|
||||
*
|
||||
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
|
||||
* in BoringSSL (ISC License):
|
||||
* As best as we can tell, this is sufficient to break any optimisations that
|
||||
* might try to eliminate "superfluous" memsets.
|
||||
* This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
|
||||
* is pretty efficient because the compiler can still implement the memset() efficiently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
__asm__ __volatile__("" : : "r"(ptr) : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/** Secure overwrite a buffer (possibly containing secret data) with zero-bytes. The write
|
||||
* operation will not be optimized out by the compiler. */
|
||||
void memory_cleanse(void *ptr, size_t len);
|
||||
|
||||
#endif // BITCOIN_SUPPORT_CLEANSE_H
|
||||
|
||||
45
src/util.cpp
45
src/util.cpp
@@ -101,8 +101,6 @@
|
||||
#include <boost/program_options/detail/config_file.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/conf.h>
|
||||
|
||||
// Work around clang compilation problem in Boost 1.46:
|
||||
// /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
|
||||
@@ -133,47 +131,6 @@ bool fLogIPs = DEFAULT_LOGIPS;
|
||||
std::atomic<bool> fReopenDebugLog(false);
|
||||
CTranslationInterface translationInterface;
|
||||
|
||||
/** Init OpenSSL library multithreading support */
|
||||
static CCriticalSection** ppmutexOpenSSL;
|
||||
void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
|
||||
{
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
|
||||
} else {
|
||||
LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Init
|
||||
static class CInit
|
||||
{
|
||||
public:
|
||||
CInit()
|
||||
{
|
||||
// Init OpenSSL library multithreading support
|
||||
ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*));
|
||||
for (int i = 0; i < CRYPTO_num_locks(); i++)
|
||||
ppmutexOpenSSL[i] = new CCriticalSection();
|
||||
CRYPTO_set_locking_callback(locking_callback);
|
||||
|
||||
// OpenSSL can optionally load a config file which lists optional loadable modules and engines.
|
||||
// We don't use them so we don't require the config. However some of our libs may call functions
|
||||
// which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
|
||||
// or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
|
||||
// that the config appears to have been loaded and there are no modules/engines available.
|
||||
OPENSSL_no_config();
|
||||
}
|
||||
~CInit()
|
||||
{
|
||||
// Shutdown OpenSSL library multithreading support
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (int i = 0; i < CRYPTO_num_locks(); i++)
|
||||
delete ppmutexOpenSSL[i];
|
||||
OPENSSL_free(ppmutexOpenSSL);
|
||||
}
|
||||
}
|
||||
instance_of_cinit;
|
||||
|
||||
/**
|
||||
* LogPrintf() has been broken a couple of times now
|
||||
* by well-meaning people adding mutexes in the most straightforward way.
|
||||
@@ -1037,8 +994,6 @@ std::string LicenseInfo()
|
||||
FormatParagraph(_("This is experimental software!!!")) + "\n" +
|
||||
"\n" +
|
||||
FormatParagraph(_("Distributed under the GPLv3 software license, see the accompanying file COPYING or <https://www.gnu.org/licenses/gpl-3.0.en.html>.")) + "\n" +
|
||||
"\n" +
|
||||
FormatParagraph(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young.")) +
|
||||
"\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <wolfssl/openssl/aes.h>
|
||||
#include <wolfssl/openssl/evp.h>
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user