From da8ceed07e93a91645bb20ee3fc625194a2ed71e Mon Sep 17 00:00:00 2001 From: Josh Juran Date: Tue, 14 Oct 2014 01:25:30 -0700 Subject: [PATCH] RippleSSLContext.cpp cleanup. * These cleanups precede work on RIPD-108. --- src/ripple/common/impl/RippleSSLContext.cpp | 515 ++++++++++---------- 1 file changed, 268 insertions(+), 247 deletions(-) diff --git a/src/ripple/common/impl/RippleSSLContext.cpp b/src/ripple/common/impl/RippleSSLContext.cpp index cfbf6c157..9d518e70a 100644 --- a/src/ripple/common/impl/RippleSSLContext.cpp +++ b/src/ripple/common/impl/RippleSSLContext.cpp @@ -62,296 +62,317 @@ public: return DHparams_dup (getDH (key_length)); } - static bool disallowRenegotiation (SSL const* ssl, bool isNew) - { - // Do not allow a connection to renegotiate - // more than once every 4 minutes + static bool disallowRenegotiation (SSL const* ssl, bool isNew); - static beast::static_initializer static_data; - - auto& sd (static_data.get ()); - std::lock_guard lock (sd.lock); - auto const expired (sd.set.clock().now() - std::chrono::minutes (4)); - - // Remove expired entries - for (auto iter (sd.set.chronological.begin ()); - (iter != sd.set.chronological.end ()) && (iter.when () <= expired); - iter = sd.set.chronological.begin ()) - { - sd.set.erase (iter); - } - - auto iter = sd.set.find (ssl); - if (iter != sd.set.end ()) - { - if (! isNew) - { - // This is a renegotiation and the last negotiation was recent - return true; - } - - sd.set.touch (iter); - } - else - { - sd.set.emplace (ssl); - } - - return false; - } - - static void info_handler (SSL const* ssl, int event, int) - { - if ((ssl->s3) && (event & SSL_CB_HANDSHAKE_START)) - { - if (disallowRenegotiation (ssl, SSL_in_before (ssl))) - ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; - } - } + static void info_handler (SSL const* ssl, int event, int); // Pretty prints an error message std::string error_message (std::string const& what, - boost::system::error_code const& ec) - { - std::stringstream ss; - ss << - what << ": " << - ec.message() << - " (" << ec.value() << ")"; - return ss.str(); - } + boost::system::error_code const& ec); //-------------------------------------------------------------------------- - static std::string getRawDHParams (int keySize) - { - std::string params; - - // Original code provided the 512-bit keySize parameters - // when 1024 bits were requested so we will do the same. - if (keySize == 1024) - keySize = 512; - - switch (keySize) - { - case 512: - { - // These are the DH parameters that OpenCoin has chosen for Ripple - // - std::uint8_t const raw [] = { - 0x30, 0x46, 0x02, 0x41, 0x00, 0x98, 0x15, 0xd2, 0xd0, 0x08, 0x32, 0xda, - 0xaa, 0xac, 0xc4, 0x71, 0xa3, 0x1b, 0x11, 0xf0, 0x6c, 0x62, 0xb2, 0x35, - 0x8a, 0x10, 0x92, 0xc6, 0x0a, 0xa3, 0x84, 0x7e, 0xaf, 0x17, 0x29, 0x0b, - 0x70, 0xef, 0x07, 0x4f, 0xfc, 0x9d, 0x6d, 0x87, 0x99, 0x19, 0x09, 0x5b, - 0x6e, 0xdb, 0x57, 0x72, 0x4a, 0x7e, 0xcd, 0xaf, 0xbd, 0x3a, 0x97, 0x55, - 0x51, 0x77, 0x5a, 0x34, 0x7c, 0xe8, 0xc5, 0x71, 0x63, 0x02, 0x01, 0x02 - }; - - params.resize (sizeof (raw)); - std::copy (raw, raw + sizeof (raw), params.begin ()); - } - break; - }; - - return params; - } + static std::string getRawDHParams (int keySize); //-------------------------------------------------------------------------- // Does common initialization for all but the bare context type. - void initCommon () - { - m_context.set_options ( - boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::no_sslv3 | - boost::asio::ssl::context::single_dh_use); - - SSL_CTX_set_tmp_dh_callback ( - m_context.native_handle (), - tmp_dh_handler); - - SSL_CTX_set_info_callback ( - m_context.native_handle (), - info_handler); - } + void initCommon (); //-------------------------------------------------------------------------- - void initAnonymous (std::string const& cipherList) - { - initCommon (); - - int const result = SSL_CTX_set_cipher_list ( - m_context.native_handle (), - cipherList.c_str ()); - - if (result != 1) - beast::FatalError ("invalid cipher list", __FILE__, __LINE__); - } + void initAnonymous (std::string const& cipherList); //-------------------------------------------------------------------------- void initAuthenticated ( - std::string key_file, std::string cert_file, std::string chain_file) + std::string key_file, std::string cert_file, std::string chain_file); + + //-------------------------------------------------------------------------- + + static DH* getDH (int keyLength); +}; + +bool RippleSSLContextImp::disallowRenegotiation (SSL const* ssl, bool isNew) +{ + // Do not allow a connection to renegotiate + // more than once every 4 minutes + + static beast::static_initializer static_data; + + auto& sd (static_data.get ()); + std::lock_guard lock (sd.lock); + auto const expired (sd.set.clock().now() - std::chrono::minutes (4)); + + // Remove expired entries + for (auto iter (sd.set.chronological.begin ()); + (iter != sd.set.chronological.end ()) && (iter.when () <= expired); + iter = sd.set.chronological.begin ()) { - initCommon (); + sd.set.erase (iter); + } - SSL_CTX* const ssl = m_context.native_handle (); - - bool cert_set = false; - - if (! cert_file.empty ()) + auto iter = sd.set.find (ssl); + if (iter != sd.set.end ()) + { + if (! isNew) { - boost::system::error_code ec; - - m_context.use_certificate_file ( - cert_file, boost::asio::ssl::context::pem, ec); - - if (ec) - { - beast::FatalError (error_message ( - "Problem with SSL certificate file.", ec).c_str(), - __FILE__, __LINE__); - } - - cert_set = true; + // This is a renegotiation and the last negotiation was recent + return true; } - if (! chain_file.empty ()) + sd.set.touch (iter); + } + else + { + sd.set.emplace (ssl); + } + + return false; +} + +void RippleSSLContextImp::info_handler (SSL const* ssl, int event, int) +{ + if ((ssl->s3) && (event & SSL_CB_HANDSHAKE_START)) + { + if (disallowRenegotiation (ssl, SSL_in_before (ssl))) + ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; + } +} + +std::string RippleSSLContextImp::error_message (std::string const& what, + boost::system::error_code const& ec) +{ + std::stringstream ss; + ss << + what << ": " << + ec.message() << + " (" << ec.value() << ")"; + return ss.str(); +} + +std::string RippleSSLContextImp::getRawDHParams (int keySize) +{ + std::string params; + + // Original code provided the 512-bit keySize parameters + // when 1024 bits were requested so we will do the same. + if (keySize == 1024) + keySize = 512; + + switch (keySize) + { + case 512: { - // VFALCO Replace fopen() with RAII - FILE* f = fopen (chain_file.c_str (), "r"); + // These are the DH parameters that OpenCoin has chosen for Ripple + // + std::uint8_t const raw [] = { + 0x30, 0x46, 0x02, 0x41, 0x00, 0x98, 0x15, 0xd2, 0xd0, 0x08, 0x32, 0xda, + 0xaa, 0xac, 0xc4, 0x71, 0xa3, 0x1b, 0x11, 0xf0, 0x6c, 0x62, 0xb2, 0x35, + 0x8a, 0x10, 0x92, 0xc6, 0x0a, 0xa3, 0x84, 0x7e, 0xaf, 0x17, 0x29, 0x0b, + 0x70, 0xef, 0x07, 0x4f, 0xfc, 0x9d, 0x6d, 0x87, 0x99, 0x19, 0x09, 0x5b, + 0x6e, 0xdb, 0x57, 0x72, 0x4a, 0x7e, 0xcd, 0xaf, 0xbd, 0x3a, 0x97, 0x55, + 0x51, 0x77, 0x5a, 0x34, 0x7c, 0xe8, 0xc5, 0x71, 0x63, 0x02, 0x01, 0x02 + }; - if (!f) - { - beast::FatalError (error_message ( - "Problem opening SSL chain file.", boost::system::error_code (errno, - boost::system::generic_category())).c_str(), - __FILE__, __LINE__); - } + params.resize (sizeof (raw)); + std::copy (raw, raw + sizeof (raw), params.begin ()); + } + break; + }; - try + return params; +} + +void RippleSSLContextImp::initCommon () +{ + m_context.set_options ( + boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::no_sslv3 | + boost::asio::ssl::context::single_dh_use); + + SSL_CTX_set_tmp_dh_callback ( + m_context.native_handle (), + tmp_dh_handler); + + SSL_CTX_set_info_callback ( + m_context.native_handle (), + info_handler); +} + +void RippleSSLContextImp::initAnonymous (std::string const& cipherList) +{ + initCommon (); + + int const result = SSL_CTX_set_cipher_list ( + m_context.native_handle (), + cipherList.c_str ()); + + if (result != 1) + beast::FatalError ("invalid cipher list", __FILE__, __LINE__); +} + +void RippleSSLContextImp::initAuthenticated ( + std::string key_file, std::string cert_file, std::string chain_file) +{ + initCommon (); + + SSL_CTX* const ssl = m_context.native_handle (); + + bool cert_set = false; + + if (! cert_file.empty ()) + { + boost::system::error_code ec; + + m_context.use_certificate_file ( + cert_file, boost::asio::ssl::context::pem, ec); + + if (ec) + { + beast::FatalError (error_message ( + "Problem with SSL certificate file.", ec).c_str(), + __FILE__, __LINE__); + } + + cert_set = true; + } + + if (! chain_file.empty ()) + { + // VFALCO Replace fopen() with RAII + FILE* f = fopen (chain_file.c_str (), "r"); + + if (!f) + { + beast::FatalError (error_message ( + "Problem opening SSL chain file.", boost::system::error_code (errno, + boost::system::generic_category())).c_str(), + __FILE__, __LINE__); + } + + try + { + for (;;) { - for (;;) + X509* const x = PEM_read_X509 (f, nullptr, nullptr, nullptr); + + if (x == nullptr) + break; + + if (! cert_set) { - X509* const x = PEM_read_X509 (f, nullptr, nullptr, nullptr); - - if (x == nullptr) - break; - - if (! cert_set) - { - if (SSL_CTX_use_certificate (ssl, x) != 1) - beast::FatalError ("Problem retrieving SSL certificate from chain file.", - __FILE__, __LINE__); - - cert_set = true; - } - else if (SSL_CTX_add_extra_chain_cert (ssl, x) != 1) - { - X509_free (x); - beast::FatalError ("Problem adding SSL chain certificate.", + if (SSL_CTX_use_certificate (ssl, x) != 1) + beast::FatalError ("Problem retrieving SSL certificate from chain file.", __FILE__, __LINE__); - } + + cert_set = true; } + else if (SSL_CTX_add_extra_chain_cert (ssl, x) != 1) + { + X509_free (x); + beast::FatalError ("Problem adding SSL chain certificate.", + __FILE__, __LINE__); + } + } - fclose (f); - } - catch (...) - { - fclose (f); - beast::FatalError ("Reading the SSL chain file generated an exception.", - __FILE__, __LINE__); - } + fclose (f); } - - if (! key_file.empty ()) + catch (...) { - boost::system::error_code ec; - - m_context.use_private_key_file (key_file, - boost::asio::ssl::context::pem, ec); - - if (ec) - { - beast::FatalError (error_message ( - "Problem using the SSL private key file.", ec).c_str(), - __FILE__, __LINE__); - } - } - - if (SSL_CTX_check_private_key (ssl) != 1) - { - beast::FatalError ("Invalid key in SSL private key file.", + fclose (f); + beast::FatalError ("Reading the SSL chain file generated an exception.", __FILE__, __LINE__); } } - //-------------------------------------------------------------------------- - - // A simple RAII container for a DH - // - struct ScopedDHPointer + if (! key_file.empty ()) { - // Construct from an existing DH - // - explicit ScopedDHPointer (DH* dh) - : m_dh (dh) + boost::system::error_code ec; + + m_context.use_private_key_file (key_file, + boost::asio::ssl::context::pem, ec); + + if (ec) { + beast::FatalError (error_message ( + "Problem using the SSL private key file.", ec).c_str(), + __FILE__, __LINE__); } - - // Construct from raw DH params - // - explicit ScopedDHPointer (std::string const& params) - { - auto const* p ( - reinterpret_cast (¶ms [0])); - m_dh = d2i_DHparams (nullptr, &p, params.size ()); - if (m_dh == nullptr) - beast::FatalError ("d2i_DHparams returned nullptr.", - __FILE__, __LINE__); - } - - ~ScopedDHPointer () - { - if (m_dh != nullptr) - DH_free (m_dh); - } - - operator DH* () const - { - return get (); - } - - DH* get () const - { - return m_dh; - } - - private: - DH* m_dh; - }; - - //-------------------------------------------------------------------------- - - static DH* getDH (int keyLength) - { - if (keyLength == 512 || keyLength == 1024) - { - static ScopedDHPointer dh512 (getRawDHParams (keyLength)); - - return dh512.get (); - } - else - { - beast::FatalError ("unsupported key length", __FILE__, __LINE__); - } - - return nullptr; } + + if (SSL_CTX_check_private_key (ssl) != 1) + { + beast::FatalError ("Invalid key in SSL private key file.", + __FILE__, __LINE__); + } +} + +// A simple RAII container for a DH +// +class ScopedDHPointer +{ +private: + ScopedDHPointer (ScopedDHPointer const&) = delete; + ScopedDHPointer& operator= (ScopedDHPointer const&) = delete; + +public: + // Construct from an existing DH + // + explicit ScopedDHPointer (DH* dh) + : m_dh (dh) + { + } + + // Construct from raw DH params + // + explicit ScopedDHPointer (std::string const& params) + { + auto const* p ( + reinterpret_cast (¶ms [0])); + m_dh = d2i_DHparams (nullptr, &p, params.size ()); + if (m_dh == nullptr) + beast::FatalError ("d2i_DHparams returned nullptr.", + __FILE__, __LINE__); + } + + ~ScopedDHPointer () + { + if (m_dh != nullptr) + DH_free (m_dh); + } + + operator DH* () const + { + return get (); + } + + DH* get () const + { + return m_dh; + } + +private: + DH* m_dh; }; +DH* RippleSSLContextImp::getDH (int keyLength) +{ + if (keyLength == 512 || keyLength == 1024) + { + static ScopedDHPointer dh512 (getRawDHParams (keyLength)); + + return dh512.get (); + } + else + { + beast::FatalError ("unsupported key length", __FILE__, __LINE__); + } + + return nullptr; +} + //------------------------------------------------------------------------------ RippleSSLContext::RippleSSLContext (ContextType& context)