openssl_operation.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. //
  2. // openssl_operation.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
  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. #ifndef BOOST_ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
  11. #define BOOST_ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <boost/function.hpp>
  18. #include <boost/assert.hpp>
  19. #include <boost/bind.hpp>
  20. #include <boost/asio/detail/pop_options.hpp>
  21. #include <boost/asio/buffer.hpp>
  22. #include <boost/asio/placeholders.hpp>
  23. #include <boost/asio/write.hpp>
  24. #include <boost/asio/detail/socket_ops.hpp>
  25. #include <boost/asio/ssl/detail/openssl_types.hpp>
  26. namespace boost {
  27. namespace asio {
  28. namespace ssl {
  29. namespace detail {
  30. typedef boost::function<int (::SSL*)> ssl_primitive_func;
  31. typedef boost::function<void (const boost::system::error_code&, int)>
  32. user_handler_func;
  33. // Network send_/recv buffer implementation
  34. //
  35. //
  36. class net_buffer
  37. {
  38. static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare
  39. unsigned char buf_[NET_BUF_SIZE];
  40. unsigned char* data_start_;
  41. unsigned char* data_end_;
  42. public:
  43. net_buffer()
  44. {
  45. data_start_ = data_end_ = buf_;
  46. }
  47. unsigned char* get_unused_start() { return data_end_; }
  48. unsigned char* get_data_start() { return data_start_; }
  49. size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); }
  50. size_t get_data_len() { return (data_end_ - data_start_); }
  51. void data_added(size_t count)
  52. {
  53. data_end_ += count;
  54. data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)?
  55. (buf_ + NET_BUF_SIZE):
  56. data_end_;
  57. }
  58. void data_removed(size_t count)
  59. {
  60. data_start_ += count;
  61. if (data_start_ >= data_end_) reset();
  62. }
  63. void reset() { data_start_ = buf_; data_end_ = buf_; }
  64. bool has_data() { return (data_start_ < data_end_); }
  65. }; // class net_buffer
  66. //
  67. // Operation class
  68. //
  69. //
  70. template <typename Stream>
  71. class openssl_operation
  72. {
  73. public:
  74. // Constructor for asynchronous operations
  75. openssl_operation(ssl_primitive_func primitive,
  76. Stream& socket,
  77. net_buffer& recv_buf,
  78. SSL* session,
  79. BIO* ssl_bio,
  80. user_handler_func handler,
  81. boost::asio::io_service::strand& strand
  82. )
  83. : primitive_(primitive)
  84. , user_handler_(handler)
  85. , strand_(&strand)
  86. , recv_buf_(recv_buf)
  87. , socket_(socket)
  88. , ssl_bio_(ssl_bio)
  89. , session_(session)
  90. {
  91. write_ = boost::bind(
  92. &openssl_operation::do_async_write,
  93. this, boost::arg<1>(), boost::arg<2>()
  94. );
  95. read_ = boost::bind(
  96. &openssl_operation::do_async_read,
  97. this
  98. );
  99. handler_= boost::bind(
  100. &openssl_operation::async_user_handler,
  101. this, boost::arg<1>(), boost::arg<2>()
  102. );
  103. }
  104. // Constructor for synchronous operations
  105. openssl_operation(ssl_primitive_func primitive,
  106. Stream& socket,
  107. net_buffer& recv_buf,
  108. SSL* session,
  109. BIO* ssl_bio)
  110. : primitive_(primitive)
  111. , strand_(0)
  112. , recv_buf_(recv_buf)
  113. , socket_(socket)
  114. , ssl_bio_(ssl_bio)
  115. , session_(session)
  116. {
  117. write_ = boost::bind(
  118. &openssl_operation::do_sync_write,
  119. this, boost::arg<1>(), boost::arg<2>()
  120. );
  121. read_ = boost::bind(
  122. &openssl_operation::do_sync_read,
  123. this
  124. );
  125. handler_ = boost::bind(
  126. &openssl_operation::sync_user_handler,
  127. this, boost::arg<1>(), boost::arg<2>()
  128. );
  129. }
  130. // Start operation
  131. // In case of asynchronous it returns 0, in sync mode returns success code
  132. // or throws an error...
  133. int start()
  134. {
  135. int rc = primitive_( session_ );
  136. bool is_operation_done = (rc > 0);
  137. // For connect/accept/shutdown, the operation
  138. // is done, when return code is 1
  139. // for write, it is done, when is retcode > 0
  140. // for read, is is done when retcode > 0
  141. int error_code = !is_operation_done ?
  142. ::SSL_get_error( session_, rc ) :
  143. 0;
  144. int sys_error_code = ERR_get_error();
  145. if (error_code == SSL_ERROR_SSL)
  146. return handler_(boost::system::error_code(
  147. error_code, boost::asio::error::get_ssl_category()), rc);
  148. bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
  149. bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
  150. ::BIO_ctrl_pending( ssl_bio_ ));
  151. bool is_shut_down_received =
  152. ((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) ==
  153. SSL_RECEIVED_SHUTDOWN);
  154. bool is_shut_down_sent =
  155. ((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
  156. SSL_SENT_SHUTDOWN);
  157. if (is_shut_down_sent && is_shut_down_received && is_operation_done && !is_write_needed)
  158. // SSL connection is shut down cleanly
  159. return handler_(boost::system::error_code(), 1);
  160. if (is_shut_down_received && !is_operation_done)
  161. // Shutdown has been requested, while we were reading or writing...
  162. // abort our action...
  163. return handler_(boost::asio::error::shut_down, 0);
  164. if (!is_operation_done && !is_read_needed && !is_write_needed
  165. && !is_shut_down_sent)
  166. {
  167. // The operation has failed... It is not completed and does
  168. // not want network communication nor does want to send shutdown out...
  169. if (error_code == SSL_ERROR_SYSCALL)
  170. {
  171. return handler_(boost::system::error_code(
  172. sys_error_code, boost::asio::error::system_category), rc);
  173. }
  174. else
  175. {
  176. return handler_(boost::system::error_code(
  177. error_code, boost::asio::error::get_ssl_category()), rc);
  178. }
  179. }
  180. if (!is_operation_done && !is_write_needed)
  181. {
  182. // We may have left over data that we can pass to SSL immediately
  183. if (recv_buf_.get_data_len() > 0)
  184. {
  185. // Pass the buffered data to SSL
  186. int written = ::BIO_write
  187. (
  188. ssl_bio_,
  189. recv_buf_.get_data_start(),
  190. recv_buf_.get_data_len()
  191. );
  192. if (written > 0)
  193. {
  194. recv_buf_.data_removed(written);
  195. }
  196. else if (written < 0)
  197. {
  198. if (!BIO_should_retry(ssl_bio_))
  199. {
  200. // Some serios error with BIO....
  201. return handler_(boost::asio::error::no_recovery, 0);
  202. }
  203. }
  204. return start();
  205. }
  206. else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
  207. {
  208. return read_();
  209. }
  210. }
  211. // Continue with operation, flush any SSL data out to network...
  212. return write_(is_operation_done, rc);
  213. }
  214. // Private implementation
  215. private:
  216. typedef boost::function<int (const boost::system::error_code&, int)>
  217. int_handler_func;
  218. typedef boost::function<int (bool, int)> write_func;
  219. typedef boost::function<int ()> read_func;
  220. ssl_primitive_func primitive_;
  221. user_handler_func user_handler_;
  222. boost::asio::io_service::strand* strand_;
  223. write_func write_;
  224. read_func read_;
  225. int_handler_func handler_;
  226. net_buffer send_buf_; // buffers for network IO
  227. // The recv buffer is owned by the stream, not the operation, since there can
  228. // be left over bytes after passing the data up to the application, and these
  229. // bytes need to be kept around for the next read operation issued by the
  230. // application.
  231. net_buffer& recv_buf_;
  232. Stream& socket_;
  233. BIO* ssl_bio_;
  234. SSL* session_;
  235. //
  236. int sync_user_handler(const boost::system::error_code& error, int rc)
  237. {
  238. if (!error)
  239. return rc;
  240. throw boost::system::system_error(error);
  241. }
  242. int async_user_handler(boost::system::error_code error, int rc)
  243. {
  244. if (rc < 0)
  245. {
  246. if (!error)
  247. error = boost::asio::error::no_recovery;
  248. rc = 0;
  249. }
  250. user_handler_(error, rc);
  251. return 0;
  252. }
  253. // Writes bytes asynchronously from SSL to NET
  254. int do_async_write(bool is_operation_done, int rc)
  255. {
  256. int len = ::BIO_ctrl_pending( ssl_bio_ );
  257. if ( len )
  258. {
  259. // There is something to write into net, do it...
  260. len = (int)send_buf_.get_unused_len() > len?
  261. len:
  262. send_buf_.get_unused_len();
  263. if (len == 0)
  264. {
  265. // In case our send buffer is full, we have just to wait until
  266. // previous send to complete...
  267. return 0;
  268. }
  269. // Read outgoing data from bio
  270. len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
  271. if (len > 0)
  272. {
  273. unsigned char *data_start = send_buf_.get_unused_start();
  274. send_buf_.data_added(len);
  275. BOOST_ASSERT(strand_);
  276. boost::asio::async_write
  277. (
  278. socket_,
  279. boost::asio::buffer(data_start, len),
  280. strand_->wrap
  281. (
  282. boost::bind
  283. (
  284. &openssl_operation::async_write_handler,
  285. this,
  286. is_operation_done,
  287. rc,
  288. boost::asio::placeholders::error,
  289. boost::asio::placeholders::bytes_transferred
  290. )
  291. )
  292. );
  293. return 0;
  294. }
  295. else if (!BIO_should_retry(ssl_bio_))
  296. {
  297. // Seems like fatal error
  298. // reading from SSL BIO has failed...
  299. handler_(boost::asio::error::no_recovery, 0);
  300. return 0;
  301. }
  302. }
  303. if (is_operation_done)
  304. {
  305. // Finish the operation, with success
  306. handler_(boost::system::error_code(), rc);
  307. return 0;
  308. }
  309. // OPeration is not done and writing to net has been made...
  310. // start operation again
  311. start();
  312. return 0;
  313. }
  314. void async_write_handler(bool is_operation_done, int rc,
  315. const boost::system::error_code& error, size_t bytes_sent)
  316. {
  317. if (!error)
  318. {
  319. // Remove data from send buffer
  320. send_buf_.data_removed(bytes_sent);
  321. if (is_operation_done)
  322. handler_(boost::system::error_code(), rc);
  323. else
  324. // Since the operation was not completed, try it again...
  325. start();
  326. }
  327. else
  328. handler_(error, rc);
  329. }
  330. int do_async_read()
  331. {
  332. // Wait for new data
  333. BOOST_ASSERT(strand_);
  334. socket_.async_read_some
  335. (
  336. boost::asio::buffer(recv_buf_.get_unused_start(),
  337. recv_buf_.get_unused_len()),
  338. strand_->wrap
  339. (
  340. boost::bind
  341. (
  342. &openssl_operation::async_read_handler,
  343. this,
  344. boost::asio::placeholders::error,
  345. boost::asio::placeholders::bytes_transferred
  346. )
  347. )
  348. );
  349. return 0;
  350. }
  351. void async_read_handler(const boost::system::error_code& error,
  352. size_t bytes_recvd)
  353. {
  354. if (!error)
  355. {
  356. recv_buf_.data_added(bytes_recvd);
  357. // Pass the received data to SSL
  358. int written = ::BIO_write
  359. (
  360. ssl_bio_,
  361. recv_buf_.get_data_start(),
  362. recv_buf_.get_data_len()
  363. );
  364. if (written > 0)
  365. {
  366. recv_buf_.data_removed(written);
  367. }
  368. else if (written < 0)
  369. {
  370. if (!BIO_should_retry(ssl_bio_))
  371. {
  372. // Some serios error with BIO....
  373. handler_(boost::asio::error::no_recovery, 0);
  374. return;
  375. }
  376. }
  377. // and try the SSL primitive again
  378. start();
  379. }
  380. else
  381. {
  382. // Error in network level...
  383. // SSL can't continue either...
  384. handler_(error, 0);
  385. }
  386. }
  387. // Syncronous functions...
  388. int do_sync_write(bool is_operation_done, int rc)
  389. {
  390. int len = ::BIO_ctrl_pending( ssl_bio_ );
  391. if ( len )
  392. {
  393. // There is something to write into net, do it...
  394. len = (int)send_buf_.get_unused_len() > len?
  395. len:
  396. send_buf_.get_unused_len();
  397. // Read outgoing data from bio
  398. len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
  399. if (len > 0)
  400. {
  401. size_t sent_len = boost::asio::write(
  402. socket_,
  403. boost::asio::buffer(send_buf_.get_unused_start(), len)
  404. );
  405. send_buf_.data_added(len);
  406. send_buf_.data_removed(sent_len);
  407. }
  408. else if (!BIO_should_retry(ssl_bio_))
  409. {
  410. // Seems like fatal error
  411. // reading from SSL BIO has failed...
  412. throw boost::system::system_error(boost::asio::error::no_recovery);
  413. }
  414. }
  415. if (is_operation_done)
  416. // Finish the operation, with success
  417. return rc;
  418. // Operation is not finished, start again.
  419. return start();
  420. }
  421. int do_sync_read()
  422. {
  423. size_t len = socket_.read_some
  424. (
  425. boost::asio::buffer(recv_buf_.get_unused_start(),
  426. recv_buf_.get_unused_len())
  427. );
  428. // Write data to ssl
  429. recv_buf_.data_added(len);
  430. // Pass the received data to SSL
  431. int written = ::BIO_write
  432. (
  433. ssl_bio_,
  434. recv_buf_.get_data_start(),
  435. recv_buf_.get_data_len()
  436. );
  437. if (written > 0)
  438. {
  439. recv_buf_.data_removed(written);
  440. }
  441. else if (written < 0)
  442. {
  443. if (!BIO_should_retry(ssl_bio_))
  444. {
  445. // Some serios error with BIO....
  446. throw boost::system::system_error(boost::asio::error::no_recovery);
  447. }
  448. }
  449. // Try the operation again
  450. return start();
  451. }
  452. }; // class openssl_operation
  453. } // namespace detail
  454. } // namespace ssl
  455. } // namespace asio
  456. } // namespace boost
  457. #include <boost/asio/detail/pop_options.hpp>
  458. #endif // BOOST_ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP