]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/ssl/detail/impl/engine.ipp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / asio / ssl / detail / impl / engine.ipp
CommitLineData
7c673cae
FG
1//
2// ssl/detail/impl/engine.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
1e59de90 5// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7c673cae
FG
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
12#define BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
b32b8144
FG
20#include <boost/asio/detail/throw_error.hpp>
21#include <boost/asio/error.hpp>
22#include <boost/asio/ssl/detail/engine.hpp>
23#include <boost/asio/ssl/error.hpp>
24#include <boost/asio/ssl/verify_context.hpp>
7c673cae
FG
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace ssl {
31namespace detail {
32
7c673cae
FG
33engine::engine(SSL_CTX* context)
34 : ssl_(::SSL_new(context))
35{
36 if (!ssl_)
37 {
38 boost::system::error_code ec(
39 static_cast<int>(::ERR_get_error()),
40 boost::asio::error::get_ssl_category());
41 boost::asio::detail::throw_error(ec, "engine");
42 }
43
b32b8144 44#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
7c673cae 45 accept_mutex().init();
b32b8144 46#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
7c673cae
FG
47
48 ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);
49 ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
50#if defined(SSL_MODE_RELEASE_BUFFERS)
51 ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS);
52#endif // defined(SSL_MODE_RELEASE_BUFFERS)
53
54 ::BIO* int_bio = 0;
55 ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0);
56 ::SSL_set_bio(ssl_, int_bio, int_bio);
57}
58
1e59de90
TL
59engine::engine(SSL* ssl_impl)
60 : ssl_(ssl_impl)
61{
62#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
63 accept_mutex().init();
64#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
65
66 ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);
67 ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
68#if defined(SSL_MODE_RELEASE_BUFFERS)
69 ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS);
70#endif // defined(SSL_MODE_RELEASE_BUFFERS)
71
72 ::BIO* int_bio = 0;
73 ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0);
74 ::SSL_set_bio(ssl_, int_bio, int_bio);
75}
76
20effc67
TL
77#if defined(BOOST_ASIO_HAS_MOVE)
78engine::engine(engine&& other) BOOST_ASIO_NOEXCEPT
79 : ssl_(other.ssl_),
80 ext_bio_(other.ext_bio_)
81{
82 other.ssl_ = 0;
83 other.ext_bio_ = 0;
84}
85#endif // defined(BOOST_ASIO_HAS_MOVE)
86
7c673cae
FG
87engine::~engine()
88{
20effc67 89 if (ssl_ && SSL_get_app_data(ssl_))
7c673cae
FG
90 {
91 delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
92 SSL_set_app_data(ssl_, 0);
93 }
94
20effc67
TL
95 if (ext_bio_)
96 ::BIO_free(ext_bio_);
97
98 if (ssl_)
99 ::SSL_free(ssl_);
7c673cae
FG
100}
101
1e59de90
TL
102#if defined(BOOST_ASIO_HAS_MOVE)
103engine& engine::operator=(engine&& other) BOOST_ASIO_NOEXCEPT
104{
105 if (this != &other)
106 {
107 ssl_ = other.ssl_;
108 ext_bio_ = other.ext_bio_;
109 other.ssl_ = 0;
110 other.ext_bio_ = 0;
111 }
112 return *this;
113}
114#endif // defined(BOOST_ASIO_HAS_MOVE)
115
7c673cae
FG
116SSL* engine::native_handle()
117{
118 return ssl_;
119}
120
121boost::system::error_code engine::set_verify_mode(
122 verify_mode v, boost::system::error_code& ec)
123{
124 ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_));
125
126 ec = boost::system::error_code();
127 return ec;
128}
129
130boost::system::error_code engine::set_verify_depth(
131 int depth, boost::system::error_code& ec)
132{
133 ::SSL_set_verify_depth(ssl_, depth);
134
135 ec = boost::system::error_code();
136 return ec;
137}
138
139boost::system::error_code engine::set_verify_callback(
140 verify_callback_base* callback, boost::system::error_code& ec)
141{
142 if (SSL_get_app_data(ssl_))
143 delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
144
145 SSL_set_app_data(ssl_, callback);
146
147 ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_),
148 &engine::verify_callback_function);
149
150 ec = boost::system::error_code();
151 return ec;
152}
153
154int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
155{
156 if (ctx)
157 {
158 if (SSL* ssl = static_cast<SSL*>(
159 ::X509_STORE_CTX_get_ex_data(
160 ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
161 {
162 if (SSL_get_app_data(ssl))
163 {
164 verify_callback_base* callback =
165 static_cast<verify_callback_base*>(
166 SSL_get_app_data(ssl));
167
168 verify_context verify_ctx(ctx);
169 return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
170 }
171 }
172 }
173
174 return 0;
175}
176
177engine::want engine::handshake(
178 stream_base::handshake_type type, boost::system::error_code& ec)
179{
180 return perform((type == boost::asio::ssl::stream_base::client)
181 ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);
182}
183
184engine::want engine::shutdown(boost::system::error_code& ec)
185{
186 return perform(&engine::do_shutdown, 0, 0, ec, 0);
187}
188
189engine::want engine::write(const boost::asio::const_buffer& data,
190 boost::system::error_code& ec, std::size_t& bytes_transferred)
191{
b32b8144 192 if (data.size() == 0)
7c673cae
FG
193 {
194 ec = boost::system::error_code();
195 return engine::want_nothing;
196 }
197
198 return perform(&engine::do_write,
b32b8144
FG
199 const_cast<void*>(data.data()),
200 data.size(), ec, &bytes_transferred);
7c673cae
FG
201}
202
203engine::want engine::read(const boost::asio::mutable_buffer& data,
204 boost::system::error_code& ec, std::size_t& bytes_transferred)
205{
b32b8144 206 if (data.size() == 0)
7c673cae
FG
207 {
208 ec = boost::system::error_code();
209 return engine::want_nothing;
210 }
211
b32b8144
FG
212 return perform(&engine::do_read, data.data(),
213 data.size(), ec, &bytes_transferred);
7c673cae
FG
214}
215
b32b8144 216boost::asio::mutable_buffer engine::get_output(
7c673cae
FG
217 const boost::asio::mutable_buffer& data)
218{
219 int length = ::BIO_read(ext_bio_,
b32b8144 220 data.data(), static_cast<int>(data.size()));
7c673cae
FG
221
222 return boost::asio::buffer(data,
223 length > 0 ? static_cast<std::size_t>(length) : 0);
224}
225
226boost::asio::const_buffer engine::put_input(
227 const boost::asio::const_buffer& data)
228{
229 int length = ::BIO_write(ext_bio_,
b32b8144 230 data.data(), static_cast<int>(data.size()));
7c673cae
FG
231
232 return boost::asio::buffer(data +
233 (length > 0 ? static_cast<std::size_t>(length) : 0));
234}
235
236const boost::system::error_code& engine::map_error_code(
237 boost::system::error_code& ec) const
238{
239 // We only want to map the error::eof code.
240 if (ec != boost::asio::error::eof)
241 return ec;
242
243 // If there's data yet to be read, it's an error.
244 if (BIO_wpending(ext_bio_))
245 {
246 ec = boost::asio::ssl::error::stream_truncated;
247 return ec;
248 }
249
250 // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the
251 // underlying transport is passed through.
252#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
b32b8144 253 if (SSL_version(ssl_) == SSL2_VERSION)
7c673cae
FG
254 return ec;
255#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
256
257 // Otherwise, the peer should have negotiated a proper shutdown.
258 if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
259 {
260 ec = boost::asio::ssl::error::stream_truncated;
261 }
262
263 return ec;
264}
265
b32b8144 266#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
7c673cae
FG
267boost::asio::detail::static_mutex& engine::accept_mutex()
268{
269 static boost::asio::detail::static_mutex mutex = BOOST_ASIO_STATIC_MUTEX_INIT;
270 return mutex;
271}
b32b8144 272#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
7c673cae
FG
273
274engine::want engine::perform(int (engine::* op)(void*, std::size_t),
275 void* data, std::size_t length, boost::system::error_code& ec,
276 std::size_t* bytes_transferred)
277{
278 std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_);
279 ::ERR_clear_error();
280 int result = (this->*op)(data, length);
281 int ssl_error = ::SSL_get_error(ssl_, result);
282 int sys_error = static_cast<int>(::ERR_get_error());
283 std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_);
284
285 if (ssl_error == SSL_ERROR_SSL)
286 {
287 ec = boost::system::error_code(sys_error,
288 boost::asio::error::get_ssl_category());
92f5a8d4
TL
289 return pending_output_after > pending_output_before
290 ? want_output : want_nothing;
7c673cae
FG
291 }
292
293 if (ssl_error == SSL_ERROR_SYSCALL)
294 {
92f5a8d4
TL
295 if (sys_error == 0)
296 {
297 ec = boost::asio::ssl::error::unspecified_system_error;
298 }
299 else
300 {
301 ec = boost::system::error_code(sys_error,
302 boost::asio::error::get_ssl_category());
303 }
304 return pending_output_after > pending_output_before
305 ? want_output : want_nothing;
7c673cae
FG
306 }
307
308 if (result > 0 && bytes_transferred)
309 *bytes_transferred = static_cast<std::size_t>(result);
310
311 if (ssl_error == SSL_ERROR_WANT_WRITE)
312 {
313 ec = boost::system::error_code();
314 return want_output_and_retry;
315 }
316 else if (pending_output_after > pending_output_before)
317 {
318 ec = boost::system::error_code();
319 return result > 0 ? want_output : want_output_and_retry;
320 }
321 else if (ssl_error == SSL_ERROR_WANT_READ)
322 {
323 ec = boost::system::error_code();
324 return want_input_and_retry;
325 }
92f5a8d4 326 else if (ssl_error == SSL_ERROR_ZERO_RETURN)
7c673cae
FG
327 {
328 ec = boost::asio::error::eof;
329 return want_nothing;
330 }
92f5a8d4 331 else if (ssl_error == SSL_ERROR_NONE)
7c673cae
FG
332 {
333 ec = boost::system::error_code();
334 return want_nothing;
335 }
92f5a8d4
TL
336 else
337 {
338 ec = boost::asio::ssl::error::unexpected_result;
339 return want_nothing;
340 }
7c673cae
FG
341}
342
343int engine::do_accept(void*, std::size_t)
344{
b32b8144 345#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
7c673cae 346 boost::asio::detail::static_mutex::scoped_lock lock(accept_mutex());
b32b8144 347#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)
7c673cae
FG
348 return ::SSL_accept(ssl_);
349}
350
351int engine::do_connect(void*, std::size_t)
352{
353 return ::SSL_connect(ssl_);
354}
355
356int engine::do_shutdown(void*, std::size_t)
357{
358 int result = ::SSL_shutdown(ssl_);
359 if (result == 0)
360 result = ::SSL_shutdown(ssl_);
361 return result;
362}
363
364int engine::do_read(void* data, std::size_t length)
365{
366 return ::SSL_read(ssl_, data,
367 length < INT_MAX ? static_cast<int>(length) : INT_MAX);
368}
369
370int engine::do_write(void* data, std::size_t length)
371{
372 return ::SSL_write(ssl_, data,
373 length < INT_MAX ? static_cast<int>(length) : INT_MAX);
374}
375
7c673cae
FG
376} // namespace detail
377} // namespace ssl
378} // namespace asio
379} // namespace boost
380
381#include <boost/asio/detail/pop_options.hpp>
382
383#endif // BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP