20#include <xrpl/basics/contract.h>
21#include <xrpl/basics/make_SSLContext.h>
23#include <boost/asio/ssl/context.hpp>
24#include <boost/asio/ssl/verify_mode.hpp>
25#include <boost/system/detail/error_code.hpp>
26#include <boost/system/detail/generic_category.hpp>
27#include <openssl/asn1.h>
28#include <openssl/bn.h>
29#include <openssl/evp.h>
30#include <openssl/objects.h>
31#include <openssl/ossl_typ.h>
32#include <openssl/pem.h>
33#include <openssl/rsa.h>
34#include <openssl/ssl.h>
35#include <openssl/x509.h>
36#include <openssl/x509v3.h>
80 "-----BEGIN DH PARAMETERS-----\n"
81 "MIIBCAKCAQEApKSWfR7LKy0VoZ/SDCObCvJ5HKX2J93RJ+QN8kJwHh+uuA8G+t8Q\n"
82 "MDRjL5HanlV/sKN9HXqBc7eqHmmbqYwIXKUt9MUZTLNheguddxVlc2IjdP5i9Ps8\n"
83 "l7su8tnP0l1JvC6Rfv3epRsEAw/ZW/lC2IwkQPpOmvnENQhQ6TgrUzcGkv4Bn0X6\n"
84 "pxrDSBpZ+45oehGCUAtcbY8b02vu8zPFoxqo6V/+MIszGzldlik5bVqrJpVF6E8C\n"
85 "tRqHjj6KuDbPbjc+pRGvwx/BSO3SULxmYu9J1NOk090MU1CMt6IJY7TpEc9Xrac9\n"
86 "9yqY3xXZID240RRcaJ25+U4lszFPqP+CEwIBAg==\n"
87 "-----END DH PARAMETERS-----";
108 using namespace openssl;
110 static auto defaultRSA = []() {
111 BIGNUM* bn = BN_new();
112 BN_set_word(bn, RSA_F4);
114 auto rsa = RSA_new();
127 static auto defaultEphemeralPrivateKey = []() {
128 auto pkey = EVP_PKEY_new();
135 if (RSA_up_ref(defaultRSA) != 1)
137 "EVP_PKEY_assign_RSA: incrementing reference count failed");
139 if (!EVP_PKEY_assign_RSA(pkey, defaultRSA))
145 static auto defaultCert = []() {
146 auto x509 = X509_new();
154 X509_set_version(x509, 2);
160 auto const ts =
std::time(
nullptr) - (25 * 60 * 60);
163 buf,
sizeof(buf) - 1,
"%y%m%d000000Z",
std::gmtime(&ts));
167 if (ASN1_TIME_set_string_X509(X509_get_notBefore(x509), buf) != 1)
168 LogicError(
"Unable to set certificate validity date");
171 X509_gmtime_adj(X509_get_notAfter(x509), 2 * 365 * 24 * 60 * 60);
174 if (
auto b = BN_new(); b !=
nullptr)
176 if (BN_rand(b, 128, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
178 if (
auto a = ASN1_INTEGER_new(); a !=
nullptr)
180 if (BN_to_ASN1_INTEGER(b, a))
181 X509_set_serialNumber(x509, a);
183 ASN1_INTEGER_free(a);
194 X509V3_set_ctx_nodb(&ctx);
195 X509V3_set_ctx(&ctx, x509, x509,
nullptr,
nullptr, 0);
197 if (
auto ext = X509V3_EXT_conf_nid(
198 nullptr, &ctx, NID_basic_constraints,
"critical,CA:FALSE"))
200 X509_add_ext(x509, ext, -1);
201 X509_EXTENSION_free(ext);
204 if (
auto ext = X509V3_EXT_conf_nid(
208 "critical,serverAuth,clientAuth"))
210 X509_add_ext(x509, ext, -1);
211 X509_EXTENSION_free(ext);
214 if (
auto ext = X509V3_EXT_conf_nid(
215 nullptr, &ctx, NID_key_usage,
"critical,digitalSignature"))
217 X509_add_ext(x509, ext, -1);
218 X509_EXTENSION_free(ext);
221 if (
auto ext = X509V3_EXT_conf_nid(
222 nullptr, &ctx, NID_subject_key_identifier,
"hash"))
224 X509_add_ext(x509, ext, -1);
225 X509_EXTENSION_free(ext);
230 X509_set_pubkey(x509, defaultEphemeralPrivateKey);
232 if (!X509_sign(x509, defaultEphemeralPrivateKey, EVP_sha256()))
238 SSL_CTX*
const ctx = context.native_handle();
240 if (SSL_CTX_use_certificate(ctx, defaultCert) <= 0)
243 if (SSL_CTX_use_PrivateKey(ctx, defaultEphemeralPrivateKey) <= 0)
249 boost::asio::ssl::context& context,
254 auto fmt_error = [](boost::system::error_code ec) ->
std::string {
255 return " [" +
std::to_string(ec.value()) +
": " + ec.message() +
"]";
258 SSL_CTX*
const ssl = context.native_handle();
260 bool cert_set =
false;
262 if (!cert_file.
empty())
264 boost::system::error_code ec;
266 context.use_certificate_file(
267 cert_file, boost::asio::ssl::context::pem, ec);
270 LogicError(
"Problem with SSL certificate file" + fmt_error(ec));
275 if (!chain_file.
empty())
278 FILE* f = fopen(chain_file.
c_str(),
"r");
283 "Problem opening SSL chain file" +
284 fmt_error(boost::system::error_code(
285 errno, boost::system::generic_category())));
292 X509*
const x = PEM_read_X509(f,
nullptr,
nullptr,
nullptr);
299 if (SSL_CTX_use_certificate(ssl, x) != 1)
301 "Problem retrieving SSL certificate from chain "
306 else if (SSL_CTX_add_extra_chain_cert(ssl, x) != 1)
309 LogicError(
"Problem adding SSL chain certificate.");
320 "Reading the SSL chain file generated an exception: ") +
325 if (!key_file.
empty())
327 boost::system::error_code ec;
329 context.use_private_key_file(
330 key_file, boost::asio::ssl::context::pem, ec);
335 "Problem using the SSL private key file" + fmt_error(ec));
339 if (SSL_CTX_check_private_key(ssl) != 1)
341 LogicError(
"Invalid key in SSL private key file.");
348 auto c = std::make_shared<boost::asio::ssl::context>(
349 boost::asio::ssl::context::sslv23);
352 boost::asio::ssl::context::default_workarounds |
353 boost::asio::ssl::context::no_sslv2 |
354 boost::asio::ssl::context::no_sslv3 |
355 boost::asio::ssl::context::no_tlsv1 |
356 boost::asio::ssl::context::no_tlsv1_1 |
357 boost::asio::ssl::context::single_dh_use |
358 boost::asio::ssl::context::no_compression);
360 if (cipherList.
empty())
364 SSL_CTX_set_cipher_list(c->native_handle(), cipherList.
c_str());
374 SSL_CTX_set_options(c->native_handle(), SSL_OP_NO_RENEGOTIATION);
390 context->set_verify_mode(boost::asio::ssl::verify_none);
std::shared_ptr< boost::asio::ssl::context > get_context(std::string cipherList)
static void initAnonymous(boost::asio::ssl::context &context)
static void initAuthenticated(boost::asio::ssl::context &context, std::string const &key_file, std::string const &cert_file, std::string const &chain_file)
std::string const defaultCipherList
The default list of ciphers we accept over TLS.
int defaultRSAKeyBits
The default strength of self-signed RSA certifices.
static constexpr char const defaultDH[]
The default DH parameters.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::shared_ptr< boost::asio::ssl::context > make_SSLContext(std::string const &cipherList)
Create a self-signed SSL context that allows anonymous Diffie Hellman.
std::shared_ptr< boost::asio::ssl::context > make_SSLContextAuthed(std::string const &keyFile, std::string const &certFile, std::string const &chainFile, std::string const &cipherList)
Create an authenticated SSL context using the specified files.
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.