rippled
HTTPClientSSLContext.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2019 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED
21 #define RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED
22 
23 #include <ripple/basics/Log.h>
24 #include <ripple/basics/contract.h>
25 #include <ripple/core/Config.h>
26 #include <ripple/net/RegisterSSLCerts.h>
27 #include <boost/asio.hpp>
28 #include <boost/asio/ip/tcp.hpp>
29 #include <boost/asio/ssl.hpp>
30 #include <boost/format.hpp>
31 
32 namespace ripple {
33 
35 {
36 public:
38  Config const& config,
40  boost::asio::ssl::context_base::method method =
41  boost::asio::ssl::context::sslv23)
42  : ssl_context_{method}, j_(j), verify_{config.SSL_VERIFY}
43  {
44  boost::system::error_code ec;
45 
46  if (config.SSL_VERIFY_FILE.empty())
47  {
49 
50  if (ec && config.SSL_VERIFY_DIR.empty())
51  Throw<std::runtime_error>(boost::str(
52  boost::format("Failed to set_default_verify_paths: %s") %
53  ec.message()));
54  }
55  else
56  {
57  ssl_context_.load_verify_file(config.SSL_VERIFY_FILE);
58  }
59 
60  if (!config.SSL_VERIFY_DIR.empty())
61  {
62  ssl_context_.add_verify_path(config.SSL_VERIFY_DIR, ec);
63 
64  if (ec)
65  Throw<std::runtime_error>(boost::str(
66  boost::format("Failed to add verify path: %s") %
67  ec.message()));
68  }
69  }
70 
71  boost::asio::ssl::context&
73  {
74  return ssl_context_;
75  }
76 
77  bool
78  sslVerify() const
79  {
80  return verify_;
81  }
82 
95  template <
96  class T,
97  class = std::enable_if_t<
99  T,
100  boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>::
101  value ||
102  std::is_same<
103  T,
104  boost::asio::ssl::stream<boost::asio::ip::tcp::socket&>>::
105  value>>
106  boost::system::error_code
107  preConnectVerify(T& strm, std::string const& host)
108  {
109  boost::system::error_code ec;
110  if (!SSL_set_tlsext_host_name(strm.native_handle(), host.c_str()))
111  {
112  ec.assign(
113  static_cast<int>(::ERR_get_error()),
114  boost::asio::error::get_ssl_category());
115  }
116  else if (!sslVerify())
117  {
118  strm.set_verify_mode(boost::asio::ssl::verify_none, ec);
119  }
120  return ec;
121  }
122 
123  template <
124  class T,
125  class = std::enable_if_t<
126  std::is_same<
127  T,
128  boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>::
129  value ||
130  std::is_same<
131  T,
132  boost::asio::ssl::stream<boost::asio::ip::tcp::socket&>>::
133  value>>
141  boost::system::error_code
142  postConnectVerify(T& strm, std::string const& host)
143  {
144  boost::system::error_code ec;
145 
146  if (sslVerify())
147  {
148  strm.set_verify_mode(boost::asio::ssl::verify_peer, ec);
149  if (!ec)
150  {
151  strm.set_verify_callback(
152  std::bind(
154  host,
155  std::placeholders::_1,
156  std::placeholders::_2,
157  j_),
158  ec);
159  }
160  }
161 
162  return ec;
163  }
164 
174  static bool
176  std::string const& domain,
177  bool preverified,
178  boost::asio::ssl::verify_context& ctx,
179  beast::Journal j)
180  {
181  if (boost::asio::ssl::rfc2818_verification(domain)(preverified, ctx))
182  return true;
183 
184  JLOG(j.warn()) << "Outbound SSL connection to " << domain
185  << " fails certificate verification";
186  return false;
187  }
188 
189 private:
190  boost::asio::ssl::context ssl_context_;
192  const bool verify_;
193 };
194 
195 } // namespace ripple
196 
197 #endif
ripple::HTTPClientSSLContext::rfc2818_verify
static bool rfc2818_verify(std::string const &domain, bool preverified, boost::asio::ssl::verify_context &ctx, beast::Journal j)
callback invoked for name verification - just passes through to the asio rfc2818 implementation.
Definition: HTTPClientSSLContext.h:175
std::is_same
std::bind
T bind(T... args)
ripple::registerSSLCerts
void registerSSLCerts(boost::asio::ssl::context &ctx, boost::system::error_code &ec, beast::Journal j)
Register default SSL certificates.
Definition: RegisterSSLCerts.cpp:35
ripple::HTTPClientSSLContext::sslVerify
bool sslVerify() const
Definition: HTTPClientSSLContext.h:78
std::string
STL class.
ripple::HTTPClientSSLContext::verify_
const bool verify_
Definition: HTTPClientSSLContext.h:192
ripple::HTTPClientSSLContext::context
boost::asio::ssl::context & context()
Definition: HTTPClientSSLContext.h:72
ripple::HTTPClientSSLContext::j_
const beast::Journal j_
Definition: HTTPClientSSLContext.h:191
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::HTTPClientSSLContext::preConnectVerify
boost::system::error_code preConnectVerify(T &strm, std::string const &host)
invoked before connect/async_connect on an ssl stream to setup name verification.
Definition: HTTPClientSSLContext.h:107
ripple::HTTPClientSSLContext::ssl_context_
boost::asio::ssl::context ssl_context_
Definition: HTTPClientSSLContext.h:190
std::enable_if_t
ripple::Config
Definition: Config.h:89
std::string::c_str
T c_str(T... args)
ripple::HTTPClientSSLContext::postConnectVerify
boost::system::error_code postConnectVerify(T &strm, std::string const &host)
invoked after connect/async_connect but before sending data on an ssl stream - to setup name verifica...
Definition: HTTPClientSSLContext.h:142
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::HTTPClientSSLContext::HTTPClientSSLContext
HTTPClientSSLContext(Config const &config, beast::Journal j, boost::asio::ssl::context_base::method method=boost::asio::ssl::context::sslv23)
Definition: HTTPClientSSLContext.h:37
ripple::HTTPClientSSLContext
Definition: HTTPClientSSLContext.h:34
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29