tls shape-up

This commit is contained in:
miodragpop
2020-11-03 16:08:31 +01:00
parent a7e65e6a94
commit 3ae6205a9b
7 changed files with 132 additions and 749 deletions

View File

@@ -15,6 +15,8 @@
using namespace std; using namespace std;
namespace hush namespace hush
{ {
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 // 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) // it is OK to hard code it (or as an alternative to read it from a file)
@@ -56,13 +58,15 @@ static WOLFSSL_DH *get_dh2048(void)
WOLFSSL_DH *dh = wolfSSL_DH_new(); WOLFSSL_DH *dh = wolfSSL_DH_new();
if (dh == NULL) if (dh == NULL) {
return NULL; return NULL;
}
if (wc_DhSetKey((DhKey*)dh->internal, dhp_2048, sizeof(dhp_2048), dhg_2048, sizeof(dhg_2048)) != 0) { if (wc_DhSetKey((DhKey*)dh->internal, dhp_2048, sizeof(dhp_2048), dhg_2048, sizeof(dhg_2048)) != 0) {
wolfSSL_DH_free(dh); wolfSSL_DH_free(dh);
return NULL; return NULL;
} }
return dh; return dh;
} }
@@ -74,93 +78,11 @@ DH *tmp_dh_callback(WOLFSSL *ssl, int is_export, int keylength)
return get_dh2048(); return get_dh2048();
} }
/** if 'tls' debug category is enabled, collect info about certificates relevant to the passed context and print them on logs */
static void dumpCertificateDebugInfo(int preverify_ok, WOLFSSL_X509_STORE_CTX* chainContext)
{
if (!LogAcceptCategory("tls")) {
return;
}
char buf[256] = {};
WOLFSSL_X509 *cert;
int err, depth;
cert = wolfSSL_X509_STORE_CTX_get_current_cert(chainContext);
err = wolfSSL_X509_STORE_CTX_get_error(chainContext);
depth = wolfSSL_X509_STORE_CTX_get_error_depth(chainContext);
LogPrintf("TLS: %s: %s():%d - preverify_ok=%d, errCode=%d, depth=%d\n",
__FILE__, __func__, __LINE__, preverify_ok, err, depth);
// is not useful checking preverify_ok because, after the chain root verification, it is set accordingly
// to the return value of this callback, and we choose to always return 1
if (err != X509_V_OK ) {
LogPrintf("TLS: %s: %s():%d - Certificate Verification ERROR=%d: [%s] at chain depth=%d\n",
__FILE__, __func__, __LINE__, err, wolfSSL_X509_verify_cert_error_string(err), depth);
if (cert && err == X509_V_ERR_CERT_HAS_EXPIRED) {
char time_buf[MAX_TIME_STRING_SZ];
ASN1_TIME * at = wolfSSL_X509_get_notAfter(cert);
if (wolfSSL_ASN1_TIME_to_string(at, time_buf, sizeof(time_buf)) != NULL) {
LogPrintf("TLS: %s: %s():%d - expired on=%s\n",
__FILE__, __func__, __LINE__, buf);
}
}
} else if (cert) {
wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(cert), buf, 256);
LogPrintf("TLS: %s: %s():%d - subj name=%s\n",
__FILE__, __func__, __LINE__, buf);
wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_issuer_name(cert), buf, 256);
LogPrintf("TLS: %s: %s():%d - issuer name=%s\n",
__FILE__, __func__, __LINE__, buf);
char time_buf[MAX_TIME_STRING_SZ];
WOLFSSL_ASN1_TIME * at = wolfSSL_X509_get_notAfter(cert);
if (wolfSSL_ASN1_TIME_to_string(at, time_buf, sizeof(time_buf)) != NULL) {
LogPrintf("TLS: %s: %s():%d - expiring on=%s\n",
__FILE__, __func__, __LINE__, buf);
}
} else {
// should never happen
LogPrintf("TLS: %s: %s():%d - invalid cert/err\n", __FILE__, __func__, __LINE__);
}
}
/**
* @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, WOLFSSL_X509_STORE_CTX* chainContext)
{
dumpCertificateDebugInfo(preverify_ok, chainContext);
/* The return value controls the strategy of the further verification process. If it returns 0
* the verification process is immediately stopped with "verification failed" state.
* If SSL_VERIFY_PEER has been set in set_verify, a verification failure alert is sent to the peer and the TLS/SSL
* handshake is terminated.
* If it returns 1, the verification process is continued.
* Here we choose to continue the verification process by returning 1 and to leave the optional cert
* verification if we call ValidatePeerCertificate().
*/
return 1;
}
/**
* @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, WOLFSSL* ssl, int timeoutSec, unsigned long& err_code) int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL* ssl, int timeoutSec, unsigned long& err_code)
{ {
int retOp = 0; int retOp = 0;
err_code = 0; err_code = 0;
char err_buffer[1024];
while (true) while (true)
{ {
@@ -173,9 +95,9 @@ int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL*
retOp = wolfSSL_connect(ssl); retOp = wolfSSL_connect(ssl);
if (retOp == 0) { if (retOp == 0) {
err_code = wolfSSL_ERR_get_error(); err_code = wolfSSL_ERR_get_error();
const char* error_str = wolfSSL_ERR_error_string(err_code, NULL); const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_CONNECT err: %s\n", LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_CONNECT err: %s\n",
__FILE__, __func__, __LINE__, error_str); __FILE__, __func__, __LINE__, err_buffer);
return -1; return -1;
} }
} }
@@ -186,9 +108,9 @@ int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL*
retOp = wolfSSL_accept(ssl); retOp = wolfSSL_accept(ssl);
if (retOp == 0) { if (retOp == 0) {
err_code = wolfSSL_ERR_get_error(); err_code = wolfSSL_ERR_get_error();
const char* error_str = wolfSSL_ERR_error_string(err_code, NULL); const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_ACCEPT err: %s\n", LogPrint("tls", "TLS: WARNING: %s: %s():%d - SSL_ACCEPT err: %s\n",
__FILE__, __func__, __LINE__, error_str); __FILE__, __func__, __LINE__, err_buffer);
return -1; return -1;
} }
} }
@@ -239,10 +161,10 @@ int TLSManager::waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL*
if (sslErr != WOLFSSL_ERROR_WANT_READ && sslErr != WOLFSSL_ERROR_WANT_WRITE) { if (sslErr != WOLFSSL_ERROR_WANT_READ && sslErr != WOLFSSL_ERROR_WANT_WRITE) {
err_code = wolfSSL_ERR_get_error(); err_code = wolfSSL_ERR_get_error();
const char* error_str = wolfSSL_ERR_error_string(err_code, NULL); 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", 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__, __FILE__, __func__, __LINE__,
eRoutine, sslErr, retOp, errno, wolfSSL_ERR_GET_LIB(err_code), ERR_GET_FUNC(err_code), wolfSSL_ERR_GET_REASON(err_code), error_str); 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; retOp = -1;
break; break;
} }
@@ -302,6 +224,7 @@ WOLFSSL* TLSManager::connect(SOCKET hSocket, const CAddress& addrConnect, unsign
LogPrint("tls", "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());
err_code = 0; err_code = 0;
char err_buffer[1024];
WOLFSSL* ssl = NULL; WOLFSSL* ssl = NULL;
bool bConnectedTLS = false; bool bConnectedTLS = false;
@@ -317,9 +240,9 @@ WOLFSSL* TLSManager::connect(SOCKET hSocket, const CAddress& addrConnect, unsign
else else
{ {
err_code = wolfSSL_ERR_get_error(); err_code = wolfSSL_ERR_get_error();
const char* error_str = wolfSSL_ERR_error_string(err_code, NULL); const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
LogPrint("tls", "TLS: %s: %s():%d - SSL_new failed err: %s\n", LogPrint("tls", "TLS: %s: %s():%d - SSL_new failed err: %s\n",
__FILE__, __func__, __LINE__, error_str); __FILE__, __func__, __LINE__, err_buffer);
} }
if (bConnectedTLS) { if (bConnectedTLS) {
@@ -346,22 +269,21 @@ WOLFSSL* TLSManager::connect(SOCKET hSocket, const CAddress& addrConnect, unsign
* @param trustedDirs trusted directories * @param trustedDirs trusted directories
* @return WOLSSL_CTX* returns the context. * @return WOLSSL_CTX* returns the context.
*/ */
WOLFSSL_CTX* TLSManager::initCtx( WOLFSSL_CTX* TLSManager::initCtx(TLSContextType ctxType)
TLSContextType ctxType,
const boost::filesystem::path& privateKeyFile,
const boost::filesystem::path& certificateFile,
const std::vector<boost::filesystem::path>& trustedDirs)
{ {
LogPrintf("TLS: %s: %s():%d - Initializing %s context\n", LogPrintf("TLS: %s: %s():%d - Initializing %s context\n",
__FILE__, __func__, __LINE__, ctxType == SERVER_CONTEXT ? "server" : "client"); __FILE__, __func__, __LINE__, ctxType == SERVER_CONTEXT ? "server" : "client");
if (!boost::filesystem::exists(privateKeyFile) || !boost::filesystem::exists(certificateFile)) { if (!mykey || !mycert) {
return NULL; return NULL;
} }
bool bInitialized = false; bool bInitialized = false;
WOLFSSL_CTX* tlsCtx = NULL; WOLFSSL_CTX* tlsCtx = NULL;
byte *pem;
int plen = 0;
if ((tlsCtx = wolfSSL_CTX_new(ctxType == SERVER_CONTEXT ? wolfTLSv1_3_server_method() : wolfTLSv1_3_client_method()))) { 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); wolfSSL_CTX_set_mode(tlsCtx, SSL_MODE_AUTO_RETRY);
@@ -389,53 +311,40 @@ WOLFSSL_CTX* TLSManager::initCtx(
LogPrintf("%s: Setting preferred cipher failed !!!\n", __func__); LogPrintf("%s: Setting preferred cipher failed !!!\n", __func__);
} }
} }
// TLSv1.3 has ephemeral Diffie-Hellman as the only key exchange mechanism, so that perfect forward secrecy is ensured.
if (ctxType == SERVER_CONTEXT) { if (ctxType == SERVER_CONTEXT) {
// amongst the Cl/Srv mutually-acceptable set, pick the one that the server prefers most instead of the one that // In case server and client prefered ciphers are different, server preference has priority
// the client prefers most
wolfSSL_CTX_set_options(tlsCtx, SSL_OP_CIPHER_SERVER_PREFERENCE); wolfSSL_CTX_set_options(tlsCtx, SSL_OP_CIPHER_SERVER_PREFERENCE);
LogPrintf("TLS: %s: %s():%d - setting dh callback\n", __FILE__, __func__, __LINE__); LogPrintf("TLS: %s: %s():%d - setting dh callback\n", __FILE__, __func__, __LINE__);
SSL_CTX_set_tmp_dh_callback(tlsCtx, tmp_dh_callback); 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);
// Fix for Secure Client-Initiated Renegotiation DoS threat: WOLFSSL_EC_KEY *ec_key = NULL;
// In WolfSSL library renegotiation is disabled by default build config
// Support for TLSv1.3 should be the only one compiled ec_key = wolfSSL_EVP_PKEY_get0_EC_KEY(mykey);
// ./configure --disable-oldtls --disable-tlsv12
int rootCertsNum = LoadDefaultRootCertificates(tlsCtx); if (ec_key != NULL && wolfSSL_PEM_write_mem_ECPrivateKey(ec_key, NULL, NULL, 0, &pem, &plen)) {
int trustedPathsNum = 0; if (wolfSSL_CTX_use_certificate(tlsCtx, mycert) > 0) {
if (wolfSSL_CTX_use_PrivateKey_buffer(tlsCtx, pem, plen, SSL_FILETYPE_PEM) > 0) {
for (boost::filesystem::path trustedDir : trustedDirs)
{ free(pem);
if (wolfSSL_CTX_load_verify_locations(tlsCtx, NULL, trustedDir.string().c_str()) == 1) {
trustedPathsNum++; 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__);
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__);
}
wolfSSL_CTX_set_verify(tlsCtx, WOLFSSL_VERIFY_PEER, tlsCertVerificationCallback);
if (wolfSSL_CTX_use_certificate_file(tlsCtx, certificateFile.string().c_str(), WOLFSSL_FILETYPE_PEM) > 0) {
if (wolfSSL_CTX_use_PrivateKey_file(tlsCtx, privateKeyFile.string().c_str(), WOLFSSL_FILETYPE_PEM) > 0) {
if (wolfSSL_CTX_check_private_key(tlsCtx)) {
bInitialized = true;
} else { } 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 { } else {
LogPrintf("TLS: ERROR: %s: %s: failed to use privateKey file\n", __FILE__, __func__); 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 use certificate file\n", __FILE__, __func__);
wolfSSL_ERR_dump_errors_fp(stderr);
} }
} else { } else {
LogPrintf("TLS: ERROR: %s: %s: failed to create TLS context\n", __FILE__, __func__); LogPrintf("TLS: ERROR: %s: %s: failed to create TLS context\n", __FILE__, __func__);
@@ -451,42 +360,65 @@ WOLFSSL_CTX* TLSManager::initCtx(
return tlsCtx; return tlsCtx;
} }
/** /**
* @brief load the certificate credentials from file. * @brief generates certificate credentials.
* *
* @return true returns true is successful. * @return true returns true is successful.
* @return false returns false if an error has occured. * @return false returns false if an error has occured.
*/ */
bool TLSManager::prepareCredentials() bool TLSManager::prepareCredentials()
{ {
boost::filesystem::path mykey = NULL;
defaultKeyPath(GetDataDir() / TLS_KEY_FILE_NAME), mycert = NULL;
defaultCertPath(GetDataDir() / TLS_CERT_FILE_NAME);
CredentialsStatus credStatus = // Generating key and the self-signed certificate for it
VerifyCredentials( //
boost::filesystem::path(GetArg("-tlskeypath", defaultKeyPath.string())), mykey = GenerateEcKey();
boost::filesystem::path(GetArg("-tlscertpath", defaultCertPath.string())), if (mykey) {
GetArg("-tlskeypwd", "")); mycert = GenerateCertificate(mykey);
if (mycert) {
bool bPrepared = (credStatus == credOk); if (CheckKeyCert()) {
LogPrintStr("TLS: New private key and self-signed certificate were generated successfully\n");
if (!bPrepared) {
if (!mapArgs.count("-tlskeypath") && !mapArgs.count("-tlscertpath")) { return true;
// 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", ""));
} }
//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 * @brief accept a TLS connection
* *
@@ -500,6 +432,7 @@ WOLFSSL* TLSManager::accept(SOCKET hSocket, const CAddress& addr, unsigned long&
LogPrint("tls", "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());
err_code = 0; err_code = 0;
char err_buffer[1024];
WOLFSSL* ssl = NULL; WOLFSSL* ssl = NULL;
bool bAcceptedTLS = false; bool bAcceptedTLS = false;
@@ -515,9 +448,9 @@ WOLFSSL* TLSManager::accept(SOCKET hSocket, const CAddress& addr, unsigned long&
else else
{ {
err_code = wolfSSL_ERR_get_error(); err_code = wolfSSL_ERR_get_error();
const char* error_str = wolfSSL_ERR_error_string(err_code, NULL); const char* error_str = wolfSSL_ERR_error_string(err_code, err_buffer);
LogPrint("tls", "TLS: %s: %s():%d - SSL_new failed err: %s\n", LogPrint("tls", "TLS: %s: %s():%d - SSL_new failed err: %s\n",
__FILE__, __func__, __LINE__, error_str); __FILE__, __func__, __LINE__, err_buffer);
} }
if (bAcceptedTLS) { if (bAcceptedTLS) {
@@ -541,6 +474,7 @@ WOLFSSL* TLSManager::accept(SOCKET hSocket, const CAddress& addr, unsigned long&
return ssl; return ssl;
} }
/** /**
* @brief Determines whether a string exists in the non-TLS address pool. * @brief Determines whether a string exists in the non-TLS address pool.
* *
@@ -555,6 +489,7 @@ bool TLSManager::isNonTLSAddr(const string& strAddr, const vector<NODE_ADDR>& vP
LOCK(cs); LOCK(cs);
return (find(vPool.begin(), vPool.end(), NODE_ADDR(strAddr)) != vPool.end()); return (find(vPool.begin(), vPool.end(), NODE_ADDR(strAddr)) != vPool.end());
} }
/** /**
* @brief Removes non-TLS node addresses based on timeout. * @brief Removes non-TLS node addresses based on timeout.
* *
@@ -702,8 +637,10 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds
if (lockSend) if (lockSend)
SocketSendData(pnode); SocketSendData(pnode);
} }
return 0; return 0;
} }
/** /**
* @brief Initialization of the server and client contexts * @brief Initialization of the server and client contexts
* *
@@ -714,40 +651,17 @@ bool TLSManager::initialize()
{ {
bool bInitializationStatus = false; bool bInitializationStatus = false;
// Initialization routines for the OpenSSL library // Initialization routines for the WolfSSL library
// //
wolfSSL_load_error_strings(); wolfSSL_load_error_strings();
wolfSSL_ERR_load_crypto_strings(); wolfSSL_ERR_load_crypto_strings();
wolfSSL_library_init(); wolfSSL_library_init();
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 of the server and client contexts // 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("tls", "TLS: contexts are initialized\n"); LogPrint("tls", "TLS: contexts are initialized\n");
bInitializationStatus = true; bInitializationStatus = true;

View File

@@ -40,25 +40,21 @@ bool operator==(const _NODE_ADDR b) const
class TLSManager class TLSManager
{ {
public: public:
/* This is set as a custom error number which is not an error in OpenSSL protocol. /* This is set as a custom error number which is not an error in SSL protocol.
A true (not null) OpenSSL error returned by ERR_get_error() consists of a library number, A true (not null) SSL error returned by ERR_get_error() consists of a library number,
function code and reason code. */ function code and reason code. */
static const long SELECT_TIMEDOUT = 0xFFFFFFFF; static const long SELECT_TIMEDOUT = 0xFFFFFFFF;
int waitFor(SSLConnectionRoutine eRoutine, SOCKET hSocket, WOLFSSL* ssl, int timeoutSec, unsigned long& err_code); 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* connect(SOCKET hSocket, const CAddress& addrConnect, unsigned long& err_code);
WOLFSSL_CTX* initCtx( WOLFSSL_CTX* initCtx(TLSContextType ctxType);
TLSContextType ctxType, bool prepareCredentials();
const boost::filesystem::path& privateKeyFile, WOLFSSL* accept(SOCKET hSocket, const CAddress& addr, unsigned long& err_code);
const boost::filesystem::path& certificateFile, bool isNonTLSAddr(const string& strAddr, const vector<NODE_ADDR>& vPool, CCriticalSection& cs);
const std::vector<boost::filesystem::path>& trustedDirs); void cleanNonTLSPool(std::vector<NODE_ADDR>& vPool, CCriticalSection& cs);
int threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fdsetSend, fd_set& fdsetError);
bool prepareCredentials(); bool initialize();
WOLFSSL* accept(SOCKET hSocket, const CAddress& addr, unsigned long& err_code); bool CheckKeyCert();
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();
}; };
} }

View File

@@ -8,96 +8,14 @@
#include <wolfssl/options.h> #include <wolfssl/options.h>
#include <wolfssl/ssl.h> #include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/rsa.h>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include "../util.h" #include "../util.h"
#include "utiltls.h" #include "utiltls.h"
namespace hush { 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')
// obsolete since we use EC instead of RSA
static WOLFSSL_EVP_PKEY* GenerateRsaKey(int bits, WOLFSSL_BN_ULONG uPublicKey)
{
WOLFSSL_EVP_PKEY *evpPrivKey = NULL;
WOLFSSL_BIGNUM *pubKey = wolfSSL_BN_new();
if (pubKey) {
if (wolfSSL_BN_set_word(pubKey, uPublicKey)) {
WOLFSSL_RSA *privKey = wolfSSL_RSA_new();
if (privKey) {
if (wolfSSL_RAND_poll() && wolfSSL_RSA_generate_key_ex(privKey, bits, pubKey, NULL)) {
if ((evpPrivKey = wolfSSL_EVP_PKEY_new())) {
if (!wolfSSL_EVP_PKEY_assign_RSA(evpPrivKey, privKey)) {
wolfSSL_EVP_PKEY_free(evpPrivKey);
evpPrivKey = NULL;
}
}
}
if(!evpPrivKey) {
wolfSSL_RSA_free(privKey);
}
}
}
wolfSSL_BN_free(pubKey);
}
return evpPrivKey;
}
// Generates EC keypair // Generates EC keypair
// //
static WOLFSSL_EVP_PKEY* GenerateEcKey(int nid = NID_X9_62_prime256v1) WOLFSSL_EVP_PKEY* GenerateEcKey(int nid)
{ {
WOLFSSL_EVP_PKEY *evpPrivKey = NULL; WOLFSSL_EVP_PKEY *evpPrivKey = NULL;
WOLFSSL_EC_KEY *privKey = wolfSSL_EC_KEY_new_by_curve_name(nid); WOLFSSL_EC_KEY *privKey = wolfSSL_EC_KEY_new_by_curve_name(nid);
@@ -114,6 +32,7 @@ static WOLFSSL_EVP_PKEY* GenerateEcKey(int nid = NID_X9_62_prime256v1)
if(!evpPrivKey) { if(!evpPrivKey) {
wolfSSL_EC_KEY_free(privKey); wolfSSL_EC_KEY_free(privKey);
evpPrivKey = NULL;
} }
} }
@@ -122,7 +41,7 @@ static WOLFSSL_EVP_PKEY* GenerateEcKey(int nid = NID_X9_62_prime256v1)
// Generates certificate for a specified public key using a corresponding private key (both of them should be specified in the 'keypair'). // Generates certificate for a specified public key using a corresponding private key (both of them should be specified in the 'keypair').
// //
static WOLFSSL_X509* GenerateCertificate(WOLFSSL_EVP_PKEY *keypair) WOLFSSL_X509* GenerateCertificate(WOLFSSL_EVP_PKEY *keypair)
{ {
if (!keypair) { if (!keypair) {
return NULL; return NULL;
@@ -149,381 +68,8 @@ static WOLFSSL_X509* GenerateCertificate(WOLFSSL_EVP_PKEY *keypair)
cert = NULL; cert = NULL;
} }
} }
return cert; return cert;
} }
// Stores key to file, specified by the 'filePath'
//
static bool StoreKey(WOLFSSL_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)
{
WOLFSSL_EC_KEY *ec_key = NULL;
ec_key = wolfSSL_EVP_PKEY_get0_EC_KEY(key);
if (ec_key != NULL)
{
const WOLFSSL_EVP_CIPHER* pCipher = NULL;
if (passphrase.length() && (pCipher = wolfSSL_EVP_aes_256_cbc()))
bStored = wolfSSL_PEM_write_ECPrivateKey(keyfd, ec_key, pCipher, NULL, 0, NULL, (void*)passphrase.c_str());
else
bStored = wolfSSL_PEM_write_ECPrivateKey(keyfd, ec_key, NULL, NULL, 0, NULL, NULL);
}
fclose(keyfd);
}
return bStored;
}
// Stores certificate to file, specified by the 'filePath'
//
static bool StoreCertificate(WOLFSSL_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 = wolfSSL_PEM_write_X509(certfd, cert);
fclose(certfd);
}
return bStored;
}
// Loads key from file, specified by the 'filePath'
//
static WOLFSSL_EVP_PKEY* old_LoadKey(const boost::filesystem::path &filePath, const std::string &passphrase)
{
if (!boost::filesystem::exists(filePath))
return NULL;
WOLFSSL_EVP_PKEY *key = wolfSSL_EVP_PKEY_new();
FILE *keyfd = fopen(filePath.string().c_str(), "rb");
if (keyfd)
{
key = wolfSSL_PEM_read_PrivateKey(keyfd, NULL, NULL, passphrase.length() ? (void*)passphrase.c_str() : NULL);
fclose(keyfd);
}
return key;
}
// Loads key from file, specified by the 'filePath'
//
static WOLFSSL_EVP_PKEY* LoadKey(const boost::filesystem::path &filePath, const std::string &passphrase)
{
if (!boost::filesystem::exists(filePath))
return NULL;
WOLFSSL_EVP_PKEY *key = NULL;
FILE *keyfd = fopen(filePath.string().c_str(), "rb");
byte der[4096];
byte pem[4096];
WOLFSSL_EC_KEY *ecKey;
ecKey = wolfSSL_EC_KEY_new();
word32 idx = 0;
if (keyfd)
{
int fileSz = fread(pem, 1, 4096, keyfd);
fclose(keyfd);
if (fileSz > 0)
{
if (ecKey)
{
int derSz = wc_KeyPemToDer(pem, fileSz, der, 4096, passphrase.c_str());
int ret_decode = wc_EccPrivateKeyDecode(der, &idx, (ecc_key*)ecKey->internal, derSz);
if (ret_decode == 0)
{
if (key = wolfSSL_EVP_PKEY_new())
{
wolfSSL_EVP_PKEY_assign_EC_KEY(key, ecKey);
}
}
}
}
}
return key;
}
// Loads certificate from file, specified by the 'filePath'
//
static WOLFSSL_X509* LoadCertificate(const boost::filesystem::path &filePath)
{
if (!boost::filesystem::exists(filePath))
return NULL;
WOLFSSL_X509 *cert = NULL;
FILE *certfd = fopen(filePath.string().c_str(), "rb");
if (certfd)
{
cert = wolfSSL_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(WOLFSSL_EVP_PKEY *key, WOLFSSL_X509 *cert)
{
if (!key || !cert)
return false;
if (wolfSSL_X509_verify(cert, key) == WOLFSSL_SUCCESS)
{
return true;
}
LogPrintf("Loaded key and certificate do not match, delete them to generate new credentials!!!\n");
return false;
}
// Checks the correctness of a private-public key pair and the validity of a certificate using public key from key pair
//
static bool CheckCredentials(WOLFSSL_EVP_PKEY *key, WOLFSSL_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 (wolfSSL_EVP_PKEY_base_id(key))
{
case EVP_PKEY_RSA:
case EVP_PKEY_RSA2:
{
WOLFSSL_RSA *rsaKey = wolfSSL_EVP_PKEY_get1_RSA(key);
if (rsaKey)
{
bIsOk = (wc_CheckRsaKey((RsaKey*)rsaKey->internal) == 0);
wolfSSL_RSA_free(rsaKey);
}
break;
}
case EVP_PKEY_EC:
{
WOLFSSL_EC_KEY *eccKey = wolfSSL_EVP_PKEY_get1_EC_KEY(key);
if (eccKey)
{
bIsOk = (wc_ecc_check_key((ecc_key*)eccKey->internal) == 0);
wolfSSL_EC_KEY_free(eccKey);
}
break;
}
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;
WOLFSSL_EVP_PKEY *key = NULL;
WOLFSSL_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) {
wolfSSL_EVP_PKEY_free(key);
}
if (cert) {
wolfSSL_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;
WOLFSSL_EVP_PKEY *key = NULL;
WOLFSSL_X509 *cert = NULL;
// Generating key and the self-signed certificate for it
//
//key = GenerateRsaKey(TLS_RSA_KEY_SIZE, RSA_F4);
//key = GenerateEcKey(NID_secp256k1);
key = GenerateEcKey();
if (key)
{
cert = GenerateCertificate(key);
if (cert)
{
bool bKey = StoreKey(key, keyPath, passphrase);
bool bCert = StoreCertificate(cert, certPath);
if ( bKey && bCert )
{
bGenerated = true;
LogPrintStr("TLS: New private key and self-signed certificate were generated successfully\n");
}
wolfSSL_X509_free(cert);
}
wolfSSL_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(WOLFSSL *ssl)
{
if (!ssl)
return false;
bool bIsOk = false;
WOLFSSL_X509 *cert = wolfSSL_get_peer_certificate (ssl);
if (cert) {
long errCode = wolfSSL_get_verify_result(ssl);
if (errCode != X509_V_OK)
{
LogPrint("tls", "TLS: %s: %s():%d - Certificate Verification ERROR=%d: [%s]\n",
__FILE__, __func__, __LINE__, errCode, wolfSSL_X509_verify_cert_error_string(errCode));
} else {
bIsOk = true;
char buf[256];
wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(cert), buf, 256);
LogPrint("tls", "TLS: %s: %s():%d - subj name=%s\n",
__FILE__, __func__, __LINE__, buf);
wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_issuer_name(cert), buf, 256);
LogPrint("tls", "TLS: %s: %s():%d - issuer name=%s\n",
__FILE__, __func__, __LINE__, buf);
}
wolfSSL_X509_free(cert);
} else {
LogPrint("tls", "TLS: %s: %s():%d - WARNING: Peer does not have certificate\n",
__FILE__, __func__, __LINE__);
}
return bIsOk;
}
// Check if a given context is set up with a cert that can be validated by this context
//
bool ValidateCertificate(WOLFSSL_CTX *ssl_ctx)
{
if (!ssl_ctx) {
return false;
}
bool bIsOk = false;
WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(ssl_ctx);
if (store) {
WOLFSSL_X509_STORE_CTX *ctx = wolfSSL_X509_STORE_CTX_new();
if (ctx) {
bIsOk = (wolfSSL_X509_verify_cert(ctx) == WOLFSSL_SUCCESS);
wolfSSL_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;
// Check and set all possible standard default directories
for (const char *dir : defaultTrustedDirs)
{
fs::path defaultDir(dir);
if (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(WOLFSSL_CTX *ctx)
{
if (!ctx) {
return 0;
}
int certsLoaded = 0;
// Certificate text buffer 'defaultRootCerts' is a C string with certificates in PEM format
WOLFSSL_BIO *memBuf = wolfSSL_BIO_new_mem_buf(defaultRootCerts, -1);
if (memBuf) {
WOLFSSL_X509 *cert = NULL;
while ((cert = wolfSSL_PEM_read_bio_X509(memBuf, NULL, 0, NULL)))
{
if (wolfSSL_X509_STORE_add_cert(wolfSSL_CTX_get_cert_store(ctx), cert) > 0) {
certsLoaded++;
}
wolfSSL_X509_free(cert);
}
wolfSSL_BIO_free(memBuf);
}
return certsLoaded;
}
} }

View File

@@ -6,51 +6,13 @@
#ifndef UTILTLS_H #ifndef UTILTLS_H
#define UTILTLS_H #define UTILTLS_H
#include <boost/filesystem/path.hpp>
namespace hush { 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 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; WOLFSSL_X509* GenerateCertificate(WOLFSSL_EVP_PKEY *keypair);
// 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(WOLFSSL *ssl);
// Check if a given context is set up with a cert that can be validated by this context
//
bool ValidateCertificate(WOLFSSL_CTX *ssl_ctx);
// Creates the list of available 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(WOLFSSL_CTX *ctx);
} }

View File

@@ -72,7 +72,7 @@ using namespace hush;
#if defined(USE_TLS) && !defined(TLS1_3_VERSION) #if defined(USE_TLS) && !defined(TLS1_3_VERSION)
// minimum secure protocol is 1.3 // minimum secure protocol is 1.3
// TLS1_3_VERSION is defined in openssl/tls1.h // TLS1_3_VERSION is defined in openssl/tls1.h
#error "ERROR: Your OpenSSL version does not support TLS v1.3" #error "ERROR: Your WolfSSL version does not support TLS v1.3"
#endif #endif
@@ -138,8 +138,8 @@ static boost::condition_variable messageHandlerCondition;
static CNodeSignals g_signals; static CNodeSignals g_signals;
CNodeSignals& GetNodeSignals() { return g_signals; } CNodeSignals& GetNodeSignals() { return g_signals; }
// OpenSSL server and client contexts // WolfSSL server and client contexts
SSL_CTX *tls_ctx_server, *tls_ctx_client; WOLFSSL_CTX *tls_ctx_server, *tls_ctx_client;
static bool operator==(_NODE_ADDR a, _NODE_ADDR b) static bool operator==(_NODE_ADDR a, _NODE_ADDR b)
{ {
@@ -442,7 +442,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
addrman.Attempt(addrConnect); addrman.Attempt(addrConnect);
SSL *ssl = NULL; WOLFSSL *ssl = NULL;
#ifdef USE_TLS #ifdef USE_TLS
/* TCP connection is ready. Do client side SSL. */ /* TCP connection is ready. Do client side SSL. */
@@ -509,19 +509,6 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
} }
} }
// certificate validation is disabled by default
if (CNode::GetTlsValidate())
{
if (ssl && !ValidatePeerCertificate(ssl))
{
LogPrintf ("TLS: ERROR: Wrong server certificate from %s. Connection will be closed.\n", addrConnect.ToString());
SSL_shutdown(ssl);
CloseSocket(hSocket);
SSL_free(ssl);
return NULL;
}
}
#endif // USE_TLS #endif // USE_TLS
// Add node // Add node
@@ -569,7 +556,7 @@ void CNode::CloseSocketDisconnect()
{ {
unsigned long err_code = 0; unsigned long err_code = 0;
tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code); tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code);
SSL_free(ssl); wolfSSL_free(ssl);
ssl = NULL; ssl = NULL;
} }
CloseSocket(hSocket); CloseSocket(hSocket);
@@ -747,7 +734,6 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
{ {
LOCK(cs_hSocket); LOCK(cs_hSocket);
stats.fTLSEstablished = (ssl != NULL) && (wolfSSL_is_init_finished(ssl) == 1); stats.fTLSEstablished = (ssl != NULL) && (wolfSSL_is_init_finished(ssl) == 1);
stats.fTLSVerified = (ssl != NULL) && ValidatePeerCertificate(ssl);
} }
} }
@@ -863,9 +849,9 @@ void SocketSendData(CNode *pnode)
if (bIsSSL) if (bIsSSL)
{ {
ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread wolfSSL_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); nBytes = wolfSSL_write(pnode->ssl, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset);
nRet = SSL_get_error(pnode->ssl, nBytes); nRet = wolfSSL_get_error(pnode->ssl, nBytes);
} }
else else
{ {
@@ -893,9 +879,9 @@ void SocketSendData(CNode *pnode)
// //
if (bIsSSL) 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)); LogPrintf("ERROR: SSL_write %s; closing connection\n", wolfSSL_ERR_error_string(nRet, NULL));
pnode->CloseSocketDisconnect(); pnode->CloseSocketDisconnect();
} }
else else
@@ -1194,7 +1180,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
#endif #endif
SSL *ssl = NULL; WOLFSSL *ssl = NULL;
SetSocketNonBlocking(hSocket, true); SetSocketNonBlocking(hSocket, true);
@@ -1260,20 +1246,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
return; return;
} }
} }
// certificate validation is disabled by default
if (CNode::GetTlsValidate())
{
if (ssl && !ValidatePeerCertificate(ssl))
{
LogPrintf ("TLS: ERROR: Wrong client certificate from %s. Connection will be closed.\n", addr.ToString());
SSL_shutdown(ssl);
CloseSocket(hSocket);
SSL_free(ssl);
return;
}
}
#endif // USE_TLS #endif // USE_TLS
CNode* pnode = new CNode(hSocket, addr, "", true, ssl); CNode* pnode = new CNode(hSocket, addr, "", true, ssl);
@@ -2090,7 +2063,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!tlsmanager.prepareCredentials()) 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; return;
} }
@@ -2388,7 +2361,7 @@ bool CAddrDB::Read(CAddrMan& addr)
unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*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), ssSend(SER_NETWORK, INIT_PROTO_VERSION),
addrKnown(5000, 0.001), addrKnown(5000, 0.001),
setInventoryKnown(SendBufferSize() / 1000) setInventoryKnown(SendBufferSize() / 1000)
@@ -2500,7 +2473,7 @@ CNode::~CNode()
unsigned long err_code = 0; unsigned long err_code = 0;
tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code); tlsmanager.waitFor(SSL_SHUTDOWN, hSocket, ssl, (DEFAULT_CONNECT_TIMEOUT / 1000), err_code);
SSL_free(ssl); wolfSSL_free(ssl);
ssl = NULL; ssl = NULL;
} }

View File

@@ -104,12 +104,6 @@ X509 *generate_x509(EVP_PKEY *pkey);
bool write_to_disk(EVP_PKEY *pkey, X509 *x509); bool write_to_disk(EVP_PKEY *pkey, X509 *x509);
void configure_context(SSL_CTX *ctx, bool server_side); void configure_context(SSL_CTX *ctx, bool server_side);
// 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; typedef int NodeId;
class CNodeStats; class CNodeStats;

View File

@@ -994,8 +994,6 @@ std::string LicenseInfo()
FormatParagraph(_("This is experimental software!!!")) + "\n" + FormatParagraph(_("This is experimental software!!!")) + "\n" +
"\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" + 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"; "\n";
} }