void nano::rpc_secure::load_certs (boost::asio::ssl::context & context_a) { // This is called if the key is password protected context_a.set_password_callback ( [this](std::size_t, boost::asio::ssl::context_base::password_purpose) { return config.secure.server_key_passphrase; }); // The following two options disables the session cache and enables stateless session resumption. // This is necessary because of the way the RPC server abruptly terminate connections. SSL_CTX_set_session_cache_mode (context_a.native_handle (), SSL_SESS_CACHE_OFF); SSL_CTX_set_options (context_a.native_handle (), SSL_OP_NO_TICKET); context_a.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); context_a.use_certificate_chain_file (config.secure.server_cert_path); context_a.use_private_key_file (config.secure.server_key_path, boost::asio::ssl::context::pem); context_a.use_tmp_dh_file (config.secure.server_dh_path); // Verify client certificates? if (config.secure.client_certs_path.size () > 0) { context_a.set_verify_mode (boost::asio::ssl::verify_fail_if_no_peer_cert | boost::asio::ssl::verify_peer); context_a.add_verify_path (config.secure.client_certs_path); context_a.set_verify_callback ([this](auto preverified, auto & ctx) { return this->on_verify_certificate (preverified, ctx); }); } }
void SslContextInitializer::SetCipherList_(boost::asio::ssl::context& context) { AnsiString cipher_list = Configuration::Instance()->GetSslCipherList(); cipher_list.Replace("\r", ""); cipher_list.Replace("\n", ""); cipher_list.Replace(" ", ""); if (cipher_list.Trim().IsEmpty()) return; // Asio does not expose cipher list. Access underlaying layer (OpenSSL) directly. SSL_CTX* ssl = context.native_handle(); int result = SSL_CTX_set_cipher_list(ssl, cipher_list.c_str()); if (result == 0) { // Unable to set the SSL cipher list. Collect the error code from OpenSSL so that // we can include that in the error message we log. int errorCode = ERR_get_error(); const int bufferSize = 150; AnsiString message; ERR_error_string_n(errorCode, message.GetBuffer(bufferSize), bufferSize); ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5511, "SslContextInitializer::SetCipherList_", Formatter::Format("Failed to set SSL ciphers. Message: {0}", message)); } }
// 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::single_dh_use); SSL_CTX_set_tmp_dh_callback ( m_context.native_handle (), tmp_dh_handler); }
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 SslContextInitializer::EnableEllipticCurveCrypto_(boost::asio::ssl::context& context) { SSL_CTX* ssl = context.native_handle(); EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (!ecdh) { ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5511, "SslContextInitializer::SetCipherList_", "Failed to enable TLS EC"); return; } int set_tmp_ecdhResult = SSL_CTX_set_tmp_ecdh(ssl, ecdh); if (set_tmp_ecdhResult != 1) { ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5511, "SslContextInitializer::SetCipherList_", Formatter::Format("Failed to enable TLS EC. SSL_CTX_set_tmp_ecdh returend {0}", set_tmp_ecdhResult)); } EC_KEY_free(ecdh); }
void SslContextInitializer::SetContextOptions_(boost::asio::ssl::context& context) { bool sslv30 = Configuration::Instance()->GetSslVersionEnabled(SslVersion30); bool tlsv10 = Configuration::Instance()->GetSslVersionEnabled(TlsVersion10); bool tlsv11 = Configuration::Instance()->GetSslVersionEnabled(TlsVersion11); bool tlsv12 = Configuration::Instance()->GetSslVersionEnabled(TlsVersion12); int options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_ECDH_USE; if (!sslv30) options = options | SSL_OP_NO_SSLv3; if (!tlsv10) options = options | SSL_OP_NO_TLSv1; if (!tlsv11) options = options | SSL_OP_NO_TLSv1_1; if (!tlsv12) options = options | SSL_OP_NO_TLSv1_2; SSL_CTX* ssl = context.native_handle(); SSL_CTX_set_options(ssl, options); }
void SslContextInitializer::SetCipherList_(boost::asio::ssl::context& context) { AnsiString cipher_list = Configuration::Instance()->GetSslCipherList(); cipher_list.Replace("\r", ""); cipher_list.Replace("\n", ""); cipher_list.Replace(" ", ""); if (cipher_list.Trim().IsEmpty()) return; // Asio does not expose cipher list. Access underlaying layer (OpenSSL) directly. SSL_CTX* ssl = context.native_handle(); int result = SSL_CTX_set_cipher_list(ssl, cipher_list.c_str()); if (result == 0) { ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5511,"SslContextInitializer::SetCipherList_", "Failed to set SSL ciphers"); } }
void 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 error; m_context.use_certificate_file ( cert_file, boost::asio::ssl::context::pem, error); if (error) { beast::FatalError ("Problem with SSL certificate file.", __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 ("Problem opening SSL chain file.", __FILE__, __LINE__); } try { for (;;) { X509* const x = PEM_read_X509 (f, NULL, NULL, NULL); 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.", __FILE__, __LINE__); } } fclose (f); } catch (...) { fclose (f); beast::FatalError ("Reading the SSL chain file generated an exception.", __FILE__, __LINE__); } } if (! key_file.empty ()) { boost::system::error_code error; m_context.use_private_key_file (key_file, boost::asio::ssl::context::pem, error); if (error) { beast::FatalError ("Problem using the SSL private key file.", __FILE__, __LINE__); } } if (SSL_CTX_check_private_key (ssl) != 1) { beast::FatalError ("Invalid key in SSL private key file.", __FILE__, __LINE__); } }