Electroneum
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. More...
 
 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. More...
 
 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
 True if host can be verified using this configuration WITHOUT system "root" CAs. More...
 
bool has_fingerprint (boost::asio::ssl::verify_context &ctx) const
 Search against internal fingerprints. Always false if behavior() != user_certificate_check. More...
 
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.

◆ 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)),
276  auth(),
279 {
280  std::sort(fingerprints_.begin(), fingerprints_.end());
281 }
ssl_authentication_t auth
Definition: net_ssl.h:80
Verify peer via specific (non-chain) certificate(s) only.
const T & move(const T &t)
Definition: gtest-port.h:1317
ssl_verification_t verification
Definition: net_ssl.h:82

◆ ssl_options_t() [3/4]

epee::net_utils::ssl_options_t::ssl_options_t ( const ssl_options_t )
default

◆ ssl_options_t() [4/4]

epee::net_utils::ssl_options_t::ssl_options_t ( ssl_options_t &&  )
default

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)
Definition: misc_log_ex.h:173
bool create_rsa_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
Definition: net_ssl.cpp:122
void use_ssl_certificate(boost::asio::ssl::context &ssl_context) const
Load private_key_path and certificate_path into ssl_context.
Definition: net_ssl.cpp:376
std::string certificate_path
Certificate used for authentication to peer.
Definition: net_ssl.h:63
Verify peer via system ca only (do not inspect user certificates)
Verify peer via specific (possibly chain) certificate(s) only.
ssl_authentication_t auth
Definition: net_ssl.h:80
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
Definition: zmq.h:98
Verify peer via specific (non-chain) certificate(s) only.
bool create_ec_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
ssl_verification_t verification
Definition: net_ssl.h:82
std::string private_key_path
Private key used for authentication.
Definition: net_ssl.h:62
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 }
#define MERROR(x)
Definition: misc_log_ex.h:73
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
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
Definition: zmq.h:101
#define MDEBUG(x)
Definition: misc_log_ex.h:76
Verify peer via system ca only (do not inspect user certificates)
#define MWARNING(x)
Definition: misc_log_ex.h:74
ssl_verification_t verification
Definition: net_ssl.h:82
Here is the call graph for this function:
Here is the caller 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 }
#define MERROR(x)
Definition: misc_log_ex.h:73
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

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 }
Verify peer via system ca only (do not inspect user certificates)
Verify peer via specific (possibly chain) certificate(s) only.
Verify peer via specific (non-chain) certificate(s) only.
ssl_verification_t verification
Definition: net_ssl.h:82

◆ 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

◆ operator=() [2/2]

ssl_options_t& epee::net_utils::ssl_options_t::operator= ( ssl_options_t &&  )
default

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: