Electroneum
Loading...
Searching...
No Matches
epee::net_utils::ssl_options_t Class Reference

#include <net_ssl.h>

Collaboration diagram for epee::net_utils::ssl_options_t:

Public Member Functions

 ssl_options_t (ssl_support_t support)
 Verification is set to system ca unless SSL is disabled.
 ssl_options_t (std::vector< std::vector< std::uint8_t > > fingerprints, std::string ca_path)
 Provide user fingerprints and/or ca path. Enables SSL and user_certificate verification.
 ssl_options_t (const ssl_options_t &)=default
 ssl_options_t (ssl_options_t &&)=default
ssl_options_toperator= (const ssl_options_t &)=default
ssl_options_toperator= (ssl_options_t &&)=default
 operator bool () const noexcept
bool has_strong_verification (boost::string_ref host) const noexcept
 \retrurn True if host can be verified using this configuration WITHOUT system "root" CAs.
bool has_fingerprint (boost::asio::ssl::verify_context &ctx) const
 Search against internal fingerprints. Always false if behavior() != user_certificate_check.
boost::asio::ssl::context create_context () const
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

Public Attributes

std::string ca_path
ssl_authentication_t auth
ssl_support_t support
ssl_verification_t verification

Detailed Description

Note
verification != disabled && support == disabled is currently "allowed" via public interface but obviously invalid configuation.

Definition at line 73 of file net_ssl.h.

Constructor & Destructor Documentation

◆ ssl_options_t() [1/4]

epee::net_utils::ssl_options_t::ssl_options_t ( ssl_support_t support)
inline

Verification is set to system ca unless SSL is disabled.

Definition at line 85 of file net_ssl.h.

86 : fingerprints_(),
87 ca_path(),
88 auth(),
91 {}
ssl_verification_t verification
Definition net_ssl.h:82
ssl_authentication_t auth
Definition net_ssl.h:80
@ none
Do not verify peer.
Definition net_ssl.h:54
@ system_ca
Verify peer via system ca only (do not inspect user certificates).
Definition net_ssl.h:55
Here is the caller graph for this function:

◆ ssl_options_t() [2/4]

epee::net_utils::ssl_options_t::ssl_options_t ( std::vector< std::vector< std::uint8_t > > fingerprints,
std::string ca_path )

Provide user fingerprints and/or ca path. Enables SSL and user_certificate verification.

Definition at line 273 of file net_ssl.cpp.

274 : fingerprints_(std::move(fingerprints)),
275 ca_path(std::move(ca_path)),
276 auth(),
279{
280 std::sort(fingerprints_.begin(), fingerprints_.end());
281}
@ user_certificates
Verify peer via specific (non-chain) certificate(s) only.
Definition net_ssl.h:56

◆ ssl_options_t() [3/4]

epee::net_utils::ssl_options_t::ssl_options_t ( const ssl_options_t & )
default
Here is the call graph for this function:

◆ ssl_options_t() [4/4]

epee::net_utils::ssl_options_t::ssl_options_t ( ssl_options_t && )
default
Here is the call graph for this function:

Member Function Documentation

◆ create_context()

boost::asio::ssl::context epee::net_utils::ssl_options_t::create_context ( ) const

Definition at line 283 of file net_ssl.cpp.

284{
285 boost::asio::ssl::context ssl_context{boost::asio::ssl::context::tlsv12};
286 if (!bool(*this))
287 return ssl_context;
288
289 // only allow tls v1.2 and up
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);
295
296 // only allow a select handful of tls v1.3 and v1.2 ciphers to be used
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");
298
299 // set options on the SSL context for added security
300 SSL_CTX *ctx = ssl_context.native_handle();
301 CHECK_AND_ASSERT_THROW_MES(ctx, "Failed to get SSL context");
302 SSL_CTX_clear_options(ctx, SSL_OP_LEGACY_SERVER_CONNECT); // SSL_CTX_SET_OPTIONS(3)
303 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); // https://stackoverflow.com/questions/22378442
304#ifdef SSL_OP_NO_TICKET
305 SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); // https://stackoverflow.com/questions/22378442
306#endif
307#ifdef SSL_OP_NO_RENEGOTIATION
308 SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
309#endif
310#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
311 SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
312#endif
313#ifdef SSL_OP_NO_COMPRESSION
314 SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
315#endif
316#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
317 SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
318#endif
319 SSL_CTX_set_ecdh_auto(ctx, 1);
320
321 switch (verification)
322 {
324 ssl_context.set_default_verify_paths();
325 break;
327 ssl_context.set_verify_depth(0);
328 /* fallthrough */
330 if (!ca_path.empty())
331 {
332 const boost::system::error_code err = load_ca_file(ssl_context, ca_path);
333 if (err)
334 throw boost::system::system_error{err, "Failed to load user CA file at " + ca_path};
335 }
336 break;
337 default:
338 break;
339 }
340
341 CHECK_AND_ASSERT_THROW_MES(auth.private_key_path.empty() == auth.certificate_path.empty(), "private key and certificate must be either both given or both empty");
342 if (auth.private_key_path.empty())
343 {
344 EVP_PKEY *pkey;
345 X509 *cert;
346 bool ok = false;
347
348#ifdef USE_EXTRA_EC_CERT
349 CHECK_AND_ASSERT_THROW_MES(create_ec_ssl_certificate(pkey, cert, NID_secp256k1), "Failed to create certificate");
350 CHECK_AND_ASSERT_THROW_MES(SSL_CTX_use_certificate(ctx, cert), "Failed to use generated certificate");
351 if (!SSL_CTX_use_PrivateKey(ctx, pkey))
352 MERROR("Failed to use generated EC private key for " << NID_secp256k1);
353 else
354 ok = true;
355 X509_free(cert);
356 EVP_PKEY_free(pkey);
357#endif
358
359 CHECK_AND_ASSERT_THROW_MES(create_rsa_ssl_certificate(pkey, cert), "Failed to create certificate");
360 CHECK_AND_ASSERT_THROW_MES(SSL_CTX_use_certificate(ctx, cert), "Failed to use generated certificate");
361 if (!SSL_CTX_use_PrivateKey(ctx, pkey))
362 MERROR("Failed to use generated RSA private key for RSA");
363 else
364 ok = true;
365 X509_free(cert);
366 EVP_PKEY_free(pkey);
367
368 CHECK_AND_ASSERT_THROW_MES(ok, "Failed to use any generated certificate");
369 }
370 else
371 auth.use_ssl_certificate(ssl_context);
372
373 return ssl_context;
374}
#define MERROR(x)
Definition misc_log_ex.h:73
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
@ user_ca
Verify peer via specific (possibly chain) certificate(s) only.
Definition net_ssl.h:57
bool create_rsa_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
Definition net_ssl.cpp:122
bool create_ec_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handshake()

bool epee::net_utils::ssl_options_t::handshake ( boost::asio::ssl::stream< boost::asio::ip::tcp::socket > & socket,
boost::asio::ssl::stream_base::handshake_type type,
const std::string & host = {} ) const
Note
If this->support == autodetect && this->verification != none, then the handshake will not fail when peer verification fails. The assumption is that a re-connect will be attempted, so a warning is logged instead of failure.
It is strongly encouraged that clients using system_ca verification provide a non-empty host for rfc2818 verification.
Parameters
socketUsed in SSL handshake and verification
typeClient or server
hostThis parameter is only used when type == client && !host.empty(). The value is sent to the server for situations where multiple hostnames are being handled by a server. If verification == system_ca the client also does a rfc2818 check to ensure that the server certificate is to the provided hostname.
Returns
True if the SSL handshake completes with peer verification settings.

Definition at line 459 of file net_ssl.cpp.

460{
461 socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
462
463 /* Using system-wide CA store for client verification is funky - there is
464 no expected hostname for server to verify against. If server doesn't have
465 specific whitelisted certificates for client, don't require client to
466 send certificate at all. */
467 const bool no_verification = verification == ssl_verification_t::none ||
468 (type == boost::asio::ssl::stream_base::server && fingerprints_.empty() && ca_path.empty());
469
470 /* According to OpenSSL documentation (and SSL specifications), server must
471 always send certificate unless "anonymous" cipher mode is used which are
472 disabled by default. Either way, the certificate is never inspected. */
473 if (no_verification)
474 socket.set_verify_mode(boost::asio::ssl::verify_none);
475 else
476 {
477 socket.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
478
479 // in case server is doing "virtual" domains, set hostname
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());
483
484 socket.set_verify_callback([&](const bool preverified, boost::asio::ssl::verify_context &ctx)
485 {
486 // preverified means it passed system or user CA check. System CA is never loaded
487 // when fingerprints are whitelisted.
488 const bool verified = preverified &&
489 (verification != ssl_verification_t::system_ca || host.empty() || boost::asio::ssl::rfc2818_verification(host)(preverified, ctx));
490
491 if (!verified && !has_fingerprint(ctx))
492 {
493 // autodetect will reconnect without SSL - warn and keep connection encrypted
495 {
496 MERROR("SSL certificate is not in the allowed list, connection droppped");
497 return false;
498 }
499 MWARNING("SSL peer has not been verified");
500 }
501 return true;
502 });
503 }
504
505 boost::system::error_code ec;
506 socket.handshake(type, ec);
507 if (ec)
508 {
509 MERROR("SSL handshake failed, connection dropped: " << ec.message());
510 return false;
511 }
512 MDEBUG("SSL handshake success");
513 return true;
514}
bool has_fingerprint(boost::asio::ssl::verify_context &ctx) const
Search against internal fingerprints. Always false if behavior() != user_certificate_check.
Definition net_ssl.cpp:421
#define MWARNING(x)
Definition misc_log_ex.h:74
#define MDEBUG(x)
Definition misc_log_ex.h:76
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
Definition zmq.h:101
Here is the call graph for this function:

◆ has_fingerprint()

bool epee::net_utils::ssl_options_t::has_fingerprint ( boost::asio::ssl::verify_context & ctx) const

Search against internal fingerprints. Always false if behavior() != user_certificate_check.

Definition at line 421 of file net_ssl.cpp.

422{
423 // can we check the certificate against a list of fingerprints?
424 if (!fingerprints_.empty()) {
425 X509_STORE_CTX *sctx = ctx.native_handle();
426 if (!sctx)
427 {
428 MERROR("Error getting verify_context handle");
429 return false;
430 }
431
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)))
435 {
436 MERROR("No certificate found in verify_context");
437 return false;
438 }
439
440 // buffer for the certificate digest and the size of the result
441 std::vector<uint8_t> digest(EVP_MAX_MD_SIZE);
442 unsigned int size{ 0 };
443
444 // create the digest from the certificate
445 if (!X509_digest(cert, EVP_sha256(), digest.data(), &size)) {
446 MERROR("Failed to create certificate fingerprint");
447 return false;
448 }
449
450 // strip unnecessary bytes from the digest
451 digest.resize(size);
452
453 return std::binary_search(fingerprints_.begin(), fingerprints_.end(), digest);
454 }
455
456 return false;
457}
Here is the caller graph for this function:

◆ has_strong_verification()

bool epee::net_utils::ssl_options_t::has_strong_verification ( boost::string_ref host) const
noexcept

\retrurn True if host can be verified using this configuration WITHOUT system "root" CAs.

Definition at line 402 of file net_ssl.cpp.

403{
404 // onion and i2p addresses contain information about the server cert
405 // which both authenticates and encrypts
406 if (host.ends_with(".onion") || host.ends_with(".i2p"))
407 return true;
408 switch (verification)
409 {
410 default:
413 return false;
416 break;
417 }
418 return true;
419}

◆ operator bool()

epee::net_utils::ssl_options_t::operator bool ( ) const
inlineexplicitnoexcept
Returns
False iff ssl is disabled, otherwise true.

Definition at line 103 of file net_ssl.h.

◆ operator=() [1/2]

ssl_options_t & epee::net_utils::ssl_options_t::operator= ( const ssl_options_t & )
default
Here is the call graph for this function:

◆ operator=() [2/2]

ssl_options_t & epee::net_utils::ssl_options_t::operator= ( ssl_options_t && )
default
Here is the call graph for this function:

Member Data Documentation

◆ auth

ssl_authentication_t epee::net_utils::ssl_options_t::auth

Definition at line 80 of file net_ssl.h.

◆ ca_path

std::string epee::net_utils::ssl_options_t::ca_path

Definition at line 79 of file net_ssl.h.

◆ support

ssl_support_t epee::net_utils::ssl_options_t::support

Definition at line 81 of file net_ssl.h.

◆ verification

ssl_verification_t epee::net_utils::ssl_options_t::verification

Definition at line 82 of file net_ssl.h.


The documentation for this class was generated from the following files:
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/contrib/epee/include/net/net_ssl.h
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/contrib/epee/src/net_ssl.cpp