30 #include <boost/asio/ssl.hpp> 31 #include <openssl/ssl.h> 32 #include <openssl/pem.h> 36 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 37 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "net.ssl" 45 struct openssl_bio_free
47 void operator()(BIO* ptr)
const noexcept
52 using openssl_bio = std::unique_ptr<BIO, openssl_bio_free>;
54 struct openssl_pkey_free
56 void operator()(EVP_PKEY* ptr)
const noexcept
61 using openssl_pkey = std::unique_ptr<EVP_PKEY, openssl_pkey_free>;
63 struct openssl_rsa_free
65 void operator()(RSA* ptr)
const noexcept
70 using openssl_rsa = std::unique_ptr<RSA, openssl_rsa_free>;
72 struct openssl_bignum_free
74 void operator()(BIGNUM* ptr)
const noexcept
79 using openssl_bignum = std::unique_ptr<BIGNUM, openssl_bignum_free>;
81 struct openssl_ec_key_free
83 void operator()(EC_KEY* ptr)
const noexcept
88 using openssl_ec_key = std::unique_ptr<EC_KEY, openssl_ec_key_free>;
90 struct openssl_group_free
92 void operator()(EC_GROUP* ptr)
const noexcept
97 using openssl_group = std::unique_ptr<EC_GROUP, openssl_group_free>;
101 SSL_CTX*
const ssl_ctx = ctx.native_handle();
102 if (ssl_ctx ==
nullptr)
103 return {boost::asio::error::invalid_argument};
105 if (!SSL_CTX_load_verify_locations(ssl_ctx, path.c_str(),
nullptr))
107 return boost::system::error_code{
108 int(::ERR_get_error()), boost::asio::error::get_ssl_category()
111 return boost::system::error_code{};
124 MGINFO(
"Generating SSL certificate");
125 pkey = EVP_PKEY_new();
128 MERROR(
"Failed to create new private key");
132 openssl_pkey pkey_deleter{pkey};
133 openssl_rsa rsa{RSA_new()};
136 MERROR(
"Error allocating RSA private key");
140 openssl_bignum exponent{BN_new()};
143 MERROR(
"Error allocating exponent");
147 BN_set_word(exponent.get(), RSA_F4);
149 if (RSA_generate_key_ex(rsa.get(), 4096, exponent.get(),
nullptr) != 1)
151 MERROR(
"Error generating RSA private key");
155 if (EVP_PKEY_assign_RSA(pkey, rsa.get()) <= 0)
157 MERROR(
"Error assigning RSA private key");
167 MERROR(
"Failed to create new X509 certificate");
170 ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
171 X509_gmtime_adj(X509_get_notBefore(cert), 0);
172 X509_gmtime_adj(X509_get_notAfter(cert), 3600 * 24 * 182);
173 if (!X509_set_pubkey(cert, pkey))
175 MERROR(
"Error setting pubkey on certificate");
179 X509_NAME *
name = X509_get_subject_name(cert);
180 X509_set_issuer_name(cert,
name);
182 if (X509_sign(cert, pkey, EVP_sha256()) == 0)
184 MERROR(
"Error signing certificate");
188 (void)pkey_deleter.release();
194 MGINFO(
"Generating SSL certificate");
195 pkey = EVP_PKEY_new();
198 MERROR(
"Failed to create new private key");
202 openssl_pkey pkey_deleter{pkey};
203 openssl_ec_key ec_key{EC_KEY_new()};
206 MERROR(
"Error allocating EC private key");
210 EC_GROUP *group = EC_GROUP_new_by_curve_name(type);
213 MERROR(
"Error getting EC group " << type);
216 openssl_group group_deleter{group};
218 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
219 EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
221 if (!EC_GROUP_check(group, NULL))
223 MERROR(
"Group failed check: " << ERR_reason_error_string(ERR_get_error()));
226 if (EC_KEY_set_group(ec_key.get(), group) != 1)
228 MERROR(
"Error setting EC group");
231 if (EC_KEY_generate_key(ec_key.get()) != 1)
233 MERROR(
"Error generating EC private key");
236 if (EVP_PKEY_assign_EC_KEY(pkey, ec_key.get()) <= 0)
238 MERROR(
"Error assigning EC private key");
243 (void)ec_key.release();
248 MERROR(
"Failed to create new X509 certificate");
251 ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
252 X509_gmtime_adj(X509_get_notBefore(cert), 0);
253 X509_gmtime_adj(X509_get_notAfter(cert), 3600 * 24 * 182);
254 if (!X509_set_pubkey(cert, pkey))
256 MERROR(
"Error setting pubkey on certificate");
260 X509_NAME *
name = X509_get_subject_name(cert);
261 X509_set_issuer_name(cert,
name);
263 if (X509_sign(cert, pkey, EVP_sha256()) == 0)
265 MERROR(
"Error signing certificate");
269 (void)pkey_deleter.release();
274 : fingerprints_(
std::
move(fingerprints)),
280 std::sort(fingerprints_.begin(), fingerprints_.end());
290 ssl_context.set_options(boost::asio::ssl::context::default_workarounds);
291 ssl_context.set_options(boost::asio::ssl::context::no_sslv2);
292 ssl_context.set_options(boost::asio::ssl::context::no_sslv3);
293 ssl_context.set_options(boost::asio::ssl::context::no_tlsv1);
294 ssl_context.set_options(boost::asio::ssl::context::no_tlsv1_1);
297 SSL_CTX_set_cipher_list(ssl_context.native_handle(),
"ECDHE-ECDSA-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256");
300 SSL_CTX *ctx = ssl_context.native_handle();
302 SSL_CTX_clear_options(ctx, SSL_OP_LEGACY_SERVER_CONNECT);
303 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
304 #ifdef SSL_OP_NO_TICKET 305 SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
307 #ifdef SSL_OP_NO_RENEGOTIATION 308 SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
310 #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 311 SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
313 #ifdef SSL_OP_NO_COMPRESSION 314 SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
316 #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE 317 SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
319 SSL_CTX_set_ecdh_auto(ctx, 1);
324 ssl_context.set_default_verify_paths();
327 ssl_context.set_verify_depth(0);
332 const boost::system::error_code err = load_ca_file(ssl_context,
ca_path);
334 throw boost::system::system_error{err,
"Failed to load user CA file at " +
ca_path};
348 #ifdef USE_EXTRA_EC_CERT 351 if (!SSL_CTX_use_PrivateKey(ctx, pkey))
352 MERROR(
"Failed to use generated EC private key for " << NID_secp256k1);
361 if (!SSL_CTX_use_PrivateKey(ctx, pkey))
362 MERROR(
"Failed to use generated RSA private key for RSA");
378 ssl_context.use_private_key_file(
private_key_path, boost::asio::ssl::context::pem);
382 bool is_ssl(
const unsigned char *data,
size_t len)
388 MDEBUG(
"SSL detection buffer, " << len <<
" bytes: " 389 << (
unsigned)(
unsigned char)data[0] <<
" " << (
unsigned)(
unsigned char)data[1] <<
" " 390 << (
unsigned)(
unsigned char)data[2] <<
" " << (
unsigned)(
unsigned char)data[3] <<
" " 391 << (
unsigned)(
unsigned char)data[4] <<
" " << (
unsigned)(
unsigned char)data[5] <<
" " 392 << (
unsigned)(
unsigned char)data[6] <<
" " << (
unsigned)(
unsigned char)data[7] <<
" " 393 << (
unsigned)(
unsigned char)data[8]);
397 if (data[6] == 0 && data[3]*256 + data[4] == data[7]*256 + data[8] + 4)
406 if (host.ends_with(
".onion") || host.ends_with(
".i2p"))
408 switch (verification)
424 if (!fingerprints_.empty()) {
425 X509_STORE_CTX *sctx = ctx.native_handle();
428 MERROR(
"Error getting verify_context handle");
432 X509* cert =
nullptr;
433 const STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(sctx);
434 if (!chain || sk_X509_num(chain) < 1 || !(cert = sk_X509_value(chain, 0)))
436 MERROR(
"No certificate found in verify_context");
441 std::vector<uint8_t> digest(EVP_MAX_MD_SIZE);
442 unsigned int size{ 0 };
445 if (!X509_digest(cert, EVP_sha256(), digest.data(), &size)) {
446 MERROR(
"Failed to create certificate fingerprint");
453 return std::binary_search(fingerprints_.begin(), fingerprints_.end(), digest);
461 socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(
true));
468 (type == boost::asio::ssl::stream_base::server && fingerprints_.empty() &&
ca_path.empty());
474 socket.set_verify_mode(boost::asio::ssl::verify_none);
477 socket.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
480 SSL*
const ssl_ctx =
socket.native_handle();
481 if (type == boost::asio::ssl::stream_base::client && !host.empty() && ssl_ctx)
482 SSL_set_tlsext_host_name(ssl_ctx, host.c_str());
484 socket.set_verify_callback([&](
const bool preverified, boost::asio::ssl::verify_context &ctx)
488 const bool verified = preverified &&
496 MERROR(
"SSL certificate is not in the allowed list, connection droppped");
499 MWARNING(
"SSL peer has not been verified");
505 boost::system::error_code ec;
506 socket.handshake(type, ec);
509 MERROR(
"SSL handshake failed, connection dropped: " << ec.message());
512 MDEBUG(
"SSL handshake success");
520 else if (s ==
"disabled")
522 else if (s ==
"autodetect")
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s)
constexpr size_t get_ssl_magic_size()
ssl_options_t(ssl_support_t support)
Verification is set to system ca unless SSL is disabled.
bool has_fingerprint(boost::asio::ssl::verify_context &ctx) const
Search against internal fingerprints. Always false if behavior() != user_certificate_check.
bool create_rsa_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
void use_ssl_certificate(boost::asio::ssl::context &ssl_context) const
Load private_key_path and certificate_path into ssl_context.
std::string certificate_path
Certificate used for authentication to peer.
Verify peer via system ca only (do not inspect user certificates)
bool is_ssl(const unsigned char *data, size_t len)
Verify peer via specific (possibly chain) certificate(s) only.
ssl_authentication_t auth
bool handshake(boost::asio::ssl::stream< boost::asio::ip::tcp::socket > &socket, boost::asio::ssl::stream_base::handshake_type type, const std::string &host={}) const
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
Verify peer via specific (non-chain) certificate(s) only.
bool create_ec_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
const T & move(const T &t)
ssl_verification_t verification
bool has_strong_verification(boost::string_ref host) const noexcept
True if host can be verified using this configuration WITHOUT system "root" CAs.
std::string private_key_path
Private key used for authentication.
boost::asio::ssl::context create_context() const