diff --git a/rippled-example.cfg b/rippled-example.cfg index aef2e0899..10aaf08db 100644 --- a/rippled-example.cfg +++ b/rippled-example.cfg @@ -109,12 +109,12 @@ # Specify the filename holding the SSL key in PEM format. # # [websocket_ssl_cert]: -# If you only need a single certificate with no intermediaries, -# Specify the path to the cert file in PEM format. +# Specify the path to the SSL certificate file in PEM format. +# This is not needed if the chain includes it. # # [websocket_ssl_chain]: # If you need a certificate chain, specify the path to the certificate chain here. -# The path must include the end certificate. +# The chain may include the end certificate. # # [validation_seed]: # To perform validation, this section should contain either a validation seed or key. diff --git a/src/cpp/ripple/PeerDoor.cpp b/src/cpp/ripple/PeerDoor.cpp index 97ddc1c2c..6230c3175 100644 --- a/src/cpp/ripple/PeerDoor.cpp +++ b/src/cpp/ripple/PeerDoor.cpp @@ -59,4 +59,68 @@ void PeerDoor::handleConnect(Peer::pointer new_connection, startListening(); } +void initSSLContext(boost::asio::ssl::context& context, + std::string key_file, std::string cert_file, std::string chain_file) +{ + SSL_CTX* sslContext = context.native_handle(); + + context.set_options(boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::single_dh_use); + + bool cert_set = false; + + if (!cert_file.empty()) + { + boost::system::error_code error; + context.use_certificate_file(cert_file, boost::asio::ssl::context::pem, error); + if (error) + throw std::runtime_error("Unable to use certificate file"); + cert_set = true; + } + + if (!chain_file.empty()) + { + FILE *f = fopen(chain_file.c_str(), "r"); + if (!f) + throw std::runtime_error("Unable to open chain file"); + try + { + while (true) + { + X509 *x = PEM_read_X509(f, NULL, NULL, NULL); + if (x == NULL) + break; + if (!cert_set) + { + if (SSL_CTX_use_certificate(sslContext, x) != 1) + throw std::runtime_error("Unable to get certificate from chain file"); + cert_set = true; + } + else if (SSL_CTX_add_extra_chain_cert(sslContext, x) != 1) + { + X509_free(x); + throw std::runtime_error("Unable to add chain certificate"); + } + } + } + catch (...) + { + fclose(f); + throw; + } + } + + if (!key_file.empty()) + { + boost::system::error_code error; + context.use_private_key_file(key_file, boost::asio::ssl::context::pem, error); + if (error) + throw std::runtime_error("Unable to use private key file"); + } + + if (SSL_CTX_check_private_key(sslContext) != 1) + throw std::runtime_error("Private key not valid"); +} + // vim:ts=4 diff --git a/src/cpp/ripple/WSHandler.h b/src/cpp/ripple/WSHandler.h index ffe3d8c49..ba9839290 100644 --- a/src/cpp/ripple/WSHandler.h +++ b/src/cpp/ripple/WSHandler.h @@ -5,6 +5,9 @@ #include "Config.h" #include "Log.h" +extern void initSSLContext(boost::asio::ssl::context& context, + std::string key_file, std::string cert_file, std::string chain_file); + template class WSConnection; @@ -134,49 +137,8 @@ public: // create a tls context, init, and return. boost::shared_ptr context(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1)); try { - context->set_options(boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::single_dh_use); -// context->set_password_callback(boost::bind(&type::get_password, this)); - if (!theConfig.WEBSOCKET_SSL_CERT.empty()) - { - boost::system::error_code error; - context->use_certificate_file(theConfig.WEBSOCKET_SSL_CERT, boost::asio::ssl::context::pem, error); - if (error) - { - Log(lsFATAL) << "Unable to set certificate: " << error; - assert(false); - } - else Log(lsINFO) << "cert set"; - } - if (!theConfig.WEBSOCKET_SSL_CHAIN.empty()) - { - boost::system::error_code error; - context->use_certificate_chain_file(theConfig.WEBSOCKET_SSL_CHAIN, error); - if (error) - { - Log(lsFATAL) << "Unable to set certificate chain: " << error; - assert(false); - } - else Log(lsINFO) << "chain set"; - } - if (!theConfig.WEBSOCKET_SSL_KEY.empty()) - { - boost::system::error_code error; - context->use_private_key_file(theConfig.WEBSOCKET_SSL_KEY, boost::asio::ssl::context::pem, error); - if (error) - { - Log(lsFATAL) << "Unable to set private key: " << error; - assert(false); - } - else Log(lsINFO) << "key set"; - } - if (SSL_CTX_check_private_key(context->native_handle()) != 1) - { - Log(lsFATAL) << "private key not valid"; - assert(false); - } - //context->use_tmp_dh_file("../../src/ssl/dh512.pem"); + initSSLContext(*context, theConfig.WEBSOCKET_SSL_KEY, + theConfig.WEBSOCKET_SSL_CERT, theConfig.WEBSOCKET_SSL_CHAIN); } catch (std::exception& e) { std::cout << e.what() << std::endl; }