diff --git a/.github/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md similarity index 96% rename from .github/ISSUE_TEMPLATE.md rename to ISSUE_TEMPLATE.md index c1ad8ec1e..c3bdf6474 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -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 diff --git a/README.md b/README.md index 95c8999fe..a4cbed8c1 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ![Logo](doc/hush/hush.png "Logo") -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 diff --git a/configure.ac b/configure.ac index bd51c7fcc..148b2920a 100644 --- a/configure.ac +++ b/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]) diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 91ff1c0f1..ae2b07bd3 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -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 diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk deleted file mode 100644 index 6f939f0fa..000000000 --- a/depends/packages/openssl.mk +++ /dev/null @@ -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 diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 9c76166af..3dd823772 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -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 diff --git a/depends/packages/wolfssl.mk b/depends/packages/wolfssl.mk new file mode 100644 index 000000000..e0e73d7f6 --- /dev/null +++ b/depends/packages/wolfssl.mk @@ -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 + diff --git a/doc/dnsseed-policy.md b/doc/dnsseed-policy.md index 4d08ec024..554158b17 100644 --- a/doc/dnsseed-policy.md +++ b/doc/dnsseed-policy.md @@ -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. diff --git a/doc/payment-api.md b/doc/payment-api.md index b7b054a46..cd632c144 100644 --- a/doc/payment-api.md +++ b/doc/payment-api.md @@ -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
| [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 diff --git a/doc/security-warnings.md b/doc/security-warnings.md index 66797444b..52f046343 100644 --- a/doc/security-warnings.md +++ b/doc/security-warnings.md @@ -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 -------------------------------------------------- - -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. +## Block Chain Reorganization: Major Differences -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). +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". -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! diff --git a/src/cc/import.cpp b/src/cc/import.cpp index 4a1978e8d..27fafdc68 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -19,7 +19,7 @@ #include "crosschain.h" #include "primitives/transaction.h" #include "cc/CCinclude.h" -#include +#include #include "cc/CCtokens.h" #include "key_io.h" diff --git a/src/clientversion.h b/src/clientversion.h index b0df8cc3e..0a066c7ec 100644 --- a/src/clientversion.h +++ b/src/clientversion.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 diff --git a/src/hush/tlsmanager.cpp b/src/hush/tlsmanager.cpp index 55c0d0d54..d978bb7e7 100644 --- a/src/hush/tlsmanager.cpp +++ b/src/hush/tlsmanager.cpp @@ -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 -#include -#include -#include "utiltls.h" - -#include -#include -#include "../util.h" -#include "../protocol.h" +#include +#include +#include +#include #include #include #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) +{ + 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; +} + +DH *tmp_dh_callback(WOLFSSL *ssl, int is_export, int keylength) { - return 1; + 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(); } -/** - * @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) + +int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL* ssl, int timeoutSec, unsigned long& err_code) { - int nErr = 0; - ERR_clear_error(); // clear the error queue + 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& 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); + // 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 { + 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); - 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; + 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: private key does not match the certificate public key\n", __FILE__, __func__); + LogPrintf("TLS: ERROR: %s: %s: failed to use private key file\n", __FILE__, __func__); } - } else - LogPrintf("TLS: ERROR: %s: %s: failed to use privateKey file\n", __FILE__, __func__); - } else { - LogPrintf("TLS: ERROR: %s: %s: failed to use certificate file\n", __FILE__, __func__); - ERR_print_errors_fp(stderr); + } 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); - - 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", "")); + mykey = NULL; + mycert = NULL; + + // 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 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; } - return bPrepared; + 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& 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& 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 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__); diff --git a/src/hush/tlsmanager.h b/src/hush/tlsmanager.h index ef677631e..01edbe98a 100644 --- a/src/hush/tlsmanager.h +++ b/src/hush/tlsmanager.h @@ -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 -#include -#include -#include "utiltls.h" +#include +#include #include "tlsenums.h" #include #include #include "../util.h" -#include "../protocol.h" #include "../net.h" #include "sync.h" #include @@ -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& 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& vPool, CCriticalSection& cs); - void cleanNonTLSPool(std::vector& 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& vPool, CCriticalSection& cs); + void cleanNonTLSPool(std::vector& vPool, CCriticalSection& cs); + int threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fdsetSend, fd_set& fdsetError); + bool initialize(); + bool CheckKeyCert(); }; } diff --git a/src/hush/utiltls.cpp b/src/hush/utiltls.cpp index 48fb9cc50..1f0ea6564 100644 --- a/src/hush/utiltls.cpp +++ b/src/hush/utiltls.cpp @@ -6,98 +6,34 @@ #include #include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" +#include +#include +#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) -{ - 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* GenerateEcKey(int nid) +{ + 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; -} - -// 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 GetDefaultTrustedDirectories() -{ - namespace fs = boost::filesystem; - std::vector 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; + return cert; } -// 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; -} } diff --git a/src/hush/utiltls.h b/src/hush/utiltls.h index 44581aa5a..495c112cb 100644 --- a/src/hush/utiltls.h +++ b/src/hush/utiltls.h @@ -6,51 +6,13 @@ #ifndef UTILTLS_H #define UTILTLS_H -#include 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 - -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 GetDefaultTrustedDirectories(); +WOLFSSL_EVP_PKEY* GenerateEcKey(int nid = NID_X9_62_prime256v1); -// 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); } diff --git a/src/init.cpp b/src/init.cpp index 1dde8781e..4612be9ef 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -77,7 +77,8 @@ #include #include #include -#include +#include +#include #include #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=:", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); strUsage += HelpMessageOpt("-torpassword=", _("Tor control port password (default: empty)")); strUsage += HelpMessageOpt("-tls=