diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp index d58e7299..319bb4dd 100644 --- a/src/base/net/http/HttpClient.cpp +++ b/src/base/net/http/HttpClient.cpp @@ -79,6 +79,7 @@ private: xmrig::HttpClient::HttpClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) : HttpContext(HTTP_RESPONSE, listener), + m_quiet(false), m_port(0) { this->method = method; diff --git a/src/base/net/http/HttpClient.h b/src/base/net/http/HttpClient.h index e9866483..c5dfc43d 100644 --- a/src/base/net/http/HttpClient.h +++ b/src/base/net/http/HttpClient.h @@ -57,10 +57,11 @@ protected: virtual void read(const char *data, size_t size); virtual void write(const std::string &header); + bool m_quiet; + private: static void onConnect(uv_connect_t *req, int status); - bool m_quiet; Dns *m_dns; uint16_t m_port; }; diff --git a/src/base/net/http/HttpsClient.cpp b/src/base/net/http/HttpsClient.cpp index ff103a34..2c287330 100644 --- a/src/base/net/http/HttpsClient.cpp +++ b/src/base/net/http/HttpsClient.cpp @@ -29,15 +29,22 @@ #include +#include "base/io/log/Log.h" #include "base/net/http/HttpsClient.h" -#include "base/tools/String.h" +#include "base/tools/Buffer.h" -xmrig::HttpsClient::HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) : +#ifdef _MSC_VER +# define strncasecmp(x,y,z) _strnicmp(x,y,z) +#endif + + +xmrig::HttpsClient::HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint) : HttpClient(method, url, listener, data, size), m_ready(false), m_buf(), - m_ssl(nullptr) + m_ssl(nullptr), + m_fp(fingerprint) { m_ctx = SSL_CTX_new(SSLv23_method()); assert(m_ctx != nullptr); @@ -64,6 +71,18 @@ xmrig::HttpsClient::~HttpsClient() } +const char *xmrig::HttpsClient::fingerprint() const +{ + return m_ready ? m_fingerprint : nullptr; +} + + +const char *xmrig::HttpsClient::version() const +{ + return m_ready ? SSL_get_version(m_ssl) : nullptr; +} + + void xmrig::HttpsClient::handshake() { m_ssl = SSL_new(m_ctx); @@ -118,13 +137,52 @@ void xmrig::HttpsClient::read(const char *data, size_t size) void xmrig::HttpsClient::write(const std::string &header) { SSL_write(m_ssl, (header + body).c_str(), header.size() + body.size()); + body.clear(); + flush(); } -bool xmrig::HttpsClient::verify(X509 *cert) const +bool xmrig::HttpsClient::verify(X509 *cert) { - return cert != nullptr; + if (cert == nullptr) { + return false; + } + + if (!verifyFingerprint(cert)) { + if (!m_quiet) { + LOG_ERR("[%s:%d] Failed to verify server certificate fingerprint", host().data(), port()); + + if (strlen(m_fingerprint) == 64 && !m_fp.isNull()) { + LOG_ERR("\"%s\" was given", m_fingerprint); + LOG_ERR("\"%s\" was configured", m_fp.data()); + } + } + + return false; + } + + return true; +} + + +bool xmrig::HttpsClient::verifyFingerprint(X509 *cert) +{ + const EVP_MD *digest = EVP_get_digestbyname("sha256"); + if (digest == nullptr) { + return false; + } + + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int dlen; + + if (X509_digest(cert, digest, md, &dlen) != 1) { + return false; + } + + Buffer::toHex(md, 32, m_fingerprint); + + return m_fp.isNull() || strncasecmp(m_fingerprint, m_fp.data(), 64) == 0; } @@ -139,7 +197,7 @@ void xmrig::HttpsClient::flush() bool result = false; if (uv_is_writable(stream())) { - result = uv_try_write(stream(), &buf, 1) == buf.len; + result = uv_try_write(stream(), &buf, 1) == static_cast(buf.len); if (!result) { close(UV_EIO); diff --git a/src/base/net/http/HttpsClient.h b/src/base/net/http/HttpsClient.h index 76b90c66..c6a22809 100644 --- a/src/base/net/http/HttpsClient.h +++ b/src/base/net/http/HttpsClient.h @@ -35,6 +35,7 @@ typedef struct x509_st X509; #include "base/net/http/HttpClient.h" +#include "base/tools/String.h" namespace xmrig { @@ -43,24 +44,30 @@ namespace xmrig { class HttpsClient : public HttpClient { public: - HttpsClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0); + HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint); ~HttpsClient() override; + const char *fingerprint() const; + const char *version() const; + protected: void handshake() override; void read(const char *data, size_t size) override; void write(const std::string &header) override; private: - bool verify(X509 *cert) const; + bool verify(X509 *cert); + bool verifyFingerprint(X509 *cert); void flush(); BIO *m_readBio; BIO *m_writeBio; bool m_ready; char m_buf[1024 * 2]; + char m_fingerprint[32 * 2 + 8]; SSL *m_ssl; SSL_CTX *m_ctx; + String m_fp; }; diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index a5aef54d..251c5fd5 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -72,19 +72,11 @@ bool xmrig::DaemonClient::disconnect() bool xmrig::DaemonClient::isTLS() const { +# ifdef XMRIG_FEATURE_TLS + return m_pool.isTLS(); +# else return false; -} - - -const char *xmrig::DaemonClient::tlsFingerprint() const -{ - return nullptr; -} - - -const char *xmrig::DaemonClient::tlsVersion() const -{ - return nullptr; +# endif } @@ -145,6 +137,11 @@ void xmrig::DaemonClient::onHttpData(const HttpData &data) m_ip = static_cast(data).ip().c_str(); + if (isTLS()) { + m_tlsVersion = static_cast(data).version(); + m_tlsFingerprint = static_cast(data).fingerprint(); + } + rapidjson::Document doc; if (doc.Parse(data.body.c_str()).HasParseError()) { if (!isQuiet()) { @@ -294,7 +291,7 @@ void xmrig::DaemonClient::send(int method, const char *url, const char *data, si HttpClient *client; # ifdef XMRIG_FEATURE_TLS if (m_pool.isTLS()) { - client = new HttpsClient(method, url, this, data, size); + client = new HttpsClient(method, url, this, data, size, m_pool.fingerprint()); } else # endif diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h index 740af6d0..f9438f67 100644 --- a/src/base/net/stratum/DaemonClient.h +++ b/src/base/net/stratum/DaemonClient.h @@ -44,8 +44,6 @@ public: protected: bool disconnect() override; bool isTLS() const override; - const char *tlsFingerprint() const override; - const char *tlsVersion() const override; int64_t submit(const JobResult &result) override; void connect() override; void connect(const Pool &pool) override; @@ -55,6 +53,8 @@ protected: inline bool hasExtension(Extension) const noexcept override { return false; } inline const char *mode() const override { return "daemon"; } + inline const char *tlsFingerprint() const override { return m_tlsFingerprint; } + inline const char *tlsVersion() const override { return m_tlsVersion; } inline void deleteLater() override { delete this; } inline void tick(uint64_t) override {} @@ -68,6 +68,8 @@ private: void setState(SocketState state); String m_blocktemplate; + String m_tlsFingerprint; + String m_tlsVersion; Timer *m_timer; };