97 static auto kDefaultRsa = []() {
98 BIGNUM* bn = BN_new();
99 BN_set_word(bn, RSA_F4);
101 auto rsa = RSA_new();
114 static auto kDefaultEphemeralPrivateKey = []() {
115 auto pkey = EVP_PKEY_new();
122 if (RSA_up_ref(kDefaultRsa) != 1)
123 logicError(
"EVP_PKEY_assign_RSA: incrementing reference count failed");
125 if (!EVP_PKEY_assign_RSA(pkey, kDefaultRsa))
131 static auto kDefaultCert = []() {
132 auto x509 = X509_new();
140 X509_set_version(x509, 2);
146 auto const ts =
std::time(
nullptr) - (25 * 60 * 60);
152 if (ASN1_TIME_set_string_X509(X509_get_notBefore(x509), buf) != 1)
153 logicError(
"Unable to set certificate validity date");
156 X509_gmtime_adj(X509_get_notAfter(x509), 2 * 365 * 24 * 60 * 60);
159 if (
auto b = BN_new(); b !=
nullptr)
161 if (BN_rand(b, 128, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
163 if (
auto a = ASN1_INTEGER_new(); a !=
nullptr)
165 if (BN_to_ASN1_INTEGER(b, a))
166 X509_set_serialNumber(x509, a);
168 ASN1_INTEGER_free(a);
179 X509V3_set_ctx_nodb(&ctx);
180 X509V3_set_ctx(&ctx, x509, x509,
nullptr,
nullptr, 0);
183 X509V3_EXT_conf_nid(
nullptr, &ctx, NID_basic_constraints,
"critical,CA:FALSE"))
185 X509_add_ext(x509, ext, -1);
186 X509_EXTENSION_free(ext);
189 if (
auto ext = X509V3_EXT_conf_nid(
190 nullptr, &ctx, NID_ext_key_usage,
"critical,serverAuth,clientAuth"))
192 X509_add_ext(x509, ext, -1);
193 X509_EXTENSION_free(ext);
197 X509V3_EXT_conf_nid(
nullptr, &ctx, NID_key_usage,
"critical,digitalSignature"))
199 X509_add_ext(x509, ext, -1);
200 X509_EXTENSION_free(ext);
203 if (
auto ext = X509V3_EXT_conf_nid(
nullptr, &ctx, NID_subject_key_identifier,
"hash"))
205 X509_add_ext(x509, ext, -1);
206 X509_EXTENSION_free(ext);
211 X509_set_pubkey(x509, kDefaultEphemeralPrivateKey);
213 if (!X509_sign(x509, kDefaultEphemeralPrivateKey, EVP_sha256()))
219 SSL_CTX*
const ctx = context.native_handle();
221 if (SSL_CTX_use_certificate(ctx, kDefaultCert) <= 0)
224 if (SSL_CTX_use_PrivateKey(ctx, kDefaultEphemeralPrivateKey) <= 0)
230 boost::asio::ssl::context& context,
235 auto fmtError = [](boost::system::error_code ec) ->
std::string {
236 return " [" +
std::to_string(ec.value()) +
": " + ec.message() +
"]";
239 SSL_CTX*
const ssl = context.native_handle();
241 bool certSet =
false;
243 if (!certFile.
empty())
245 boost::system::error_code ec;
248 context.use_certificate_file(certFile, boost::asio::ssl::context::pem, ec);
251 logicError(
"Problem with SSL certificate file" + fmtError(ec));
256 if (!chainFile.
empty())
259 FILE* f = fopen(chainFile.
c_str(),
"r");
264 "Problem opening SSL chain file" +
265 fmtError(boost::system::error_code(errno, boost::system::generic_category())));
272 X509*
const x = PEM_read_X509(f,
nullptr,
nullptr,
nullptr);
279 if (SSL_CTX_use_certificate(ssl, x) != 1)
282 "Problem retrieving SSL certificate from chain "
288 else if (SSL_CTX_add_extra_chain_cert(ssl, x) != 1)
291 logicError(
"Problem adding SSL chain certificate.");
301 std::string(
"Reading the SSL chain file generated an exception: ") + ex.
what());
305 if (!keyFile.
empty())
307 boost::system::error_code ec;
310 context.use_private_key_file(keyFile, boost::asio::ssl::context::pem, ec);
314 logicError(
"Problem using the SSL private key file" + fmtError(ec));
318 if (SSL_CTX_check_private_key(ssl) != 1)
320 logicError(
"Invalid key in SSL private key file.");
330 boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 |
331 boost::asio::ssl::context::no_sslv3 | boost::asio::ssl::context::no_tlsv1 |
332 boost::asio::ssl::context::no_tlsv1_1 | boost::asio::ssl::context::single_dh_use |
333 boost::asio::ssl::context::no_compression);
335 if (cipherList.
empty())
338 if (
auto result = SSL_CTX_set_cipher_list(c->native_handle(), cipherList.
c_str()); result != 1)
347 SSL_CTX_set_options(c->native_handle(), SSL_OP_NO_RENEGOTIATION);