diff --git a/src/base/tools/String.h b/src/base/tools/String.h index d5f0e84..ef6f17f 100644 --- a/src/base/tools/String.h +++ b/src/base/tools/String.h @@ -25,7 +25,6 @@ #define XMRIG_STRING_H -#include #include #include diff --git a/src/proxy/tls/TlsConfig.cpp b/src/proxy/tls/TlsConfig.cpp index 2ad9a7b..d7aee6f 100644 --- a/src/proxy/tls/TlsConfig.cpp +++ b/src/proxy/tls/TlsConfig.cpp @@ -27,15 +27,28 @@ #include "rapidjson/document.h" -xmrig::TlsConfig::TlsConfig() +xmrig::TlsConfig::TlsConfig() : + m_protocols(0) { } -xmrig::TlsConfig::TlsConfig(const rapidjson::Value &object) +/** + * "cert" load TLS certificate chain from file. + * "cert_key" load TLS private key from file. + * "ciphers" set list of available ciphers (TLSv1.2 and below). + * "ciphersuites" set list of available TLSv1.3 ciphersuites. + * "dhparam" load DH parameters for DHE ciphers from file. + */ +xmrig::TlsConfig::TlsConfig(const rapidjson::Value &object) : + m_protocols(0) { + setProtocols(object["protocols"]); setCert(object["cert"].GetString()); - setKey(object["key"].GetString()); + setKey(object["cert_key"].GetString()); + setCiphers(object["ciphers"].GetString()); + setCipherSuites(object["ciphersuites"].GetString()); + setDH(object["dhparam"].GetString()); } @@ -51,8 +64,70 @@ rapidjson::Value xmrig::TlsConfig::toJSON(rapidjson::Document &doc) const auto &allocator = doc.GetAllocator(); Value obj(kObjectType); - obj.AddMember("cert", m_cert.toJSON(), allocator); - obj.AddMember("key", m_key.toJSON(), allocator); + if (m_protocols > 0) { + Value protocols(kArrayType); + + if (m_protocols & TLSv1) { + protocols.PushBack("TLSv1", allocator); + } + + if (m_protocols & TLSv1_1) { + protocols.PushBack("TLSv1.1", allocator); + } + + if (m_protocols & TLSv1_2) { + protocols.PushBack("TLSv1.2", allocator); + } + + if (m_protocols & TLSv1_3) { + protocols.PushBack("TLSv1.3", allocator); + } + + obj.AddMember("protocols", protocols, allocator); + } + else { + obj.AddMember("protocols", kNullType, allocator); + } + + obj.AddMember("cert", m_cert.toJSON(), allocator); + obj.AddMember("cert_key", m_key.toJSON(), allocator); + obj.AddMember("ciphers", m_ciphers.toJSON(), allocator); + obj.AddMember("ciphersuites", m_cipherSuites.toJSON(), allocator); + obj.AddMember("dhparam", m_dhparam.toJSON(), allocator); return obj; } + + +void xmrig::TlsConfig::setProtocols(const rapidjson::Value &protocols) +{ + m_protocols = 0; + + if (protocols.IsUint()) { + return setProtocols(protocols.GetUint()); + } + + if (!protocols.IsArray()) { + return; + } + + for (const rapidjson::Value &value : protocols.GetArray()) { + const char *protocol = value.GetString(); + if (protocol == nullptr) { + continue; + } + + if (strcmp(protocol, "TLSv1") == 0) { + m_protocols |= TLSv1; + } + else if (strcmp(protocol, "TLSv1.1") == 0) { + m_protocols |= TLSv1_1; + } + else if (strcmp(protocol, "TLSv1.2") == 0) { + m_protocols |= TLSv1_2; + } + else if (strcmp(protocol, "TLSv1.3") == 0) { + m_protocols |= TLSv1_3; + } + } +} diff --git a/src/proxy/tls/TlsConfig.h b/src/proxy/tls/TlsConfig.h index 6a12a2b..f67e1ed 100644 --- a/src/proxy/tls/TlsConfig.h +++ b/src/proxy/tls/TlsConfig.h @@ -36,20 +36,40 @@ namespace xmrig { class TlsConfig { public: + enum Versions { + TLSv1 = 1, + TLSv1_1 = 2, + TLSv1_2 = 4, + TLSv1_3 = 8 + }; + TlsConfig(); TlsConfig(const rapidjson::Value &object); ~TlsConfig(); - inline bool isValid() const { return !m_cert.isEmpty() && !m_key.isEmpty(); } - inline const char *cert() const { return m_cert.data(); } - inline const char *key() const { return m_key.data(); } - inline void setCert(const char *cert) { m_cert = cert; } - inline void setKey(const char *key) { m_key = key; } + inline bool isValid() const { return !m_cert.isEmpty() && !m_key.isEmpty(); } + inline const char *cert() const { return m_cert.data(); } + inline const char *ciphers() const { return m_ciphers.isEmpty() ? nullptr : m_ciphers.data(); } + inline const char *cipherSuites() const { return m_cipherSuites.isEmpty() ? nullptr : m_cipherSuites.data(); } + inline const char *dhparam() const { return m_dhparam.isEmpty() ? nullptr : m_dhparam.data(); } + inline const char *key() const { return m_key.data(); } + inline uint32_t protocols() const { return m_protocols; } + inline void setCert(const char *cert) { m_cert = cert; } + inline void setCiphers(const char *ciphers) { m_ciphers = ciphers; } + inline void setCipherSuites(const char *ciphers) { m_cipherSuites = ciphers; } + inline void setDH(const char *dhparam) { m_dhparam = dhparam; } + inline void setKey(const char *key) { m_key = key; } + inline void setProtocols(uint32_t protocols) { m_protocols = protocols; } rapidjson::Value toJSON(rapidjson::Document &doc) const; + void setProtocols(const rapidjson::Value &protocols); private: + uint32_t m_protocols; String m_cert; + String m_ciphers; + String m_cipherSuites; + String m_dhparam; String m_key; }; diff --git a/src/proxy/tls/TlsContext.cpp b/src/proxy/tls/TlsContext.cpp index 9b81701..0ff3fd7 100644 --- a/src/proxy/tls/TlsContext.cpp +++ b/src/proxy/tls/TlsContext.cpp @@ -60,18 +60,125 @@ bool xmrig::TlsContext::load(const TlsConfig &config) } if (SSL_CTX_use_certificate_chain_file(m_ctx, config.cert()) <= 0) { - LOG_ERR("Failed to load certificate chain file \"%s\"", config.cert()); + LOG_ERR("SSL_CTX_use_certificate_chain_file(\"%s\") failed.", config.cert()); return false; } if (SSL_CTX_use_PrivateKey_file(m_ctx, config.key(), SSL_FILETYPE_PEM) <= 0) { - LOG_ERR("Failed to load private key file \"%s\"", config.key()); + LOG_ERR("SSL_CTX_use_PrivateKey_file(\"%s\") failed.", config.key()); return false; } SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + SSL_CTX_set_options(m_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); + +# if OPENSSL_VERSION_NUMBER >= 0x1010100fL + SSL_CTX_set_max_early_data(m_ctx, 0); +# endif + + setProtocols(config.protocols()); + + return setCiphers(config.ciphers()) && setCipherSuites(config.cipherSuites()) && setDH(config.dhparam()); +} + + +bool xmrig::TlsContext::setCiphers(const char *ciphers) +{ + if (ciphers == nullptr || SSL_CTX_set_cipher_list(m_ctx, ciphers) == 1) { + return true; + } + + LOG_ERR("SSL_CTX_set_cipher_list(\"%s\") failed.", ciphers); return true; } + + +bool xmrig::TlsContext::setCipherSuites(const char *ciphersuites) +{ + if (ciphersuites == nullptr) { + return true; + } + +# if OPENSSL_VERSION_NUMBER >= 0x1010100fL + if (SSL_CTX_set_ciphersuites(m_ctx, ciphersuites) == 1) { + return true; + } +# endif + + LOG_ERR("SSL_CTX_set_ciphersuites(\"%s\") failed.", ciphersuites); + + return false; +} + + +bool xmrig::TlsContext::setDH(const char *dhparam) +{ + if (dhparam == nullptr) { + return true; + } + + BIO *bio = BIO_new_file(dhparam, "r"); + if (bio == nullptr) { + LOG_ERR("BIO_new_file(\"%s\") failed.", dhparam); + + return false; + } + + DH *dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr); + if (dh == nullptr) { + LOG_ERR("PEM_read_bio_DHparams(\"%s\") failed.", dhparam); + + BIO_free(bio); + + return false; + } + + const int rc = SSL_CTX_set_tmp_dh(m_ctx, dh); + + DH_free(dh); + BIO_free(bio); + + if (rc == 0) { + LOG_ERR("SSL_CTX_set_tmp_dh(\"%s\") failed.", dhparam); + + return false; + } + + return true; +} + + +void xmrig::TlsContext::setProtocols(uint32_t protocols) +{ + if (protocols == 0) { + return; + } + + if (!(protocols & TlsConfig::TLSv1)) { + SSL_CTX_set_options(m_ctx, SSL_OP_NO_TLSv1); + } + +# ifdef SSL_OP_NO_TLSv1_1 + SSL_CTX_clear_options(m_ctx, SSL_OP_NO_TLSv1_1); + if (!(protocols & TlsConfig::TLSv1_1)) { + SSL_CTX_set_options(m_ctx, SSL_OP_NO_TLSv1_1); + } +# endif + +# ifdef SSL_OP_NO_TLSv1_2 + SSL_CTX_clear_options(m_ctx, SSL_OP_NO_TLSv1_2); + if (!(protocols & TlsConfig::TLSv1_2)) { + SSL_CTX_set_options(m_ctx, SSL_OP_NO_TLSv1_2); + } +# endif + +# ifdef SSL_OP_NO_TLSv1_3 + SSL_CTX_clear_options(m_ctx, SSL_OP_NO_TLSv1_3); + if (!(protocols & TlsConfig::TLSv1_3)) { + SSL_CTX_set_options(m_ctx, SSL_OP_NO_TLSv1_3); + } +# endif +} diff --git a/src/proxy/tls/TlsContext.h b/src/proxy/tls/TlsContext.h index d158a89..638a500 100644 --- a/src/proxy/tls/TlsContext.h +++ b/src/proxy/tls/TlsContext.h @@ -26,6 +26,9 @@ #define XMRIG_TLSCONTEXT_H +#include + + typedef struct ssl_ctx_st SSL_CTX; @@ -46,6 +49,11 @@ public: inline SSL_CTX *ctx() const { return m_ctx; } private: + bool setCiphers(const char *ciphers); + bool setCipherSuites(const char *ciphersuites); + bool setDH(const char *dhparam); + void setProtocols(uint32_t protocols); + SSL_CTX *m_ctx; };