Boost Asio SSL not able to receive data for 2nd time onwards (1st time OK)
Asked Answered
C

3

6

I'm working on Boost Asio and Boost Beast for simple RESTful server. For normal HTTP and TCP socket, it works perfectly. I put it under load test with JMeter, everything works fine.

I tried to add the SSL socket. I set the 'ssl::context' and also called the 'async_handshake()' - additional steps for SSL compared to normal socket. It works for the first time only. Client can connected with me (server) and I also able to receive the data via 'boost::beast::http::async_read()'.

Because this is RESTful, so the connection will drop after the request & respond. I call 'SSL_Socket.shutdown()' and follow by 'SSL_Socket.lowest_layer().close()' to close the SSL socket.

When the next incoming request, the client able to connect with me (server). I called 'SSL_Socket.async_handshake()' and then follow by 'boost::beast::http::async_read()'. But this time I not able to receive any data. But the connection is successfully established.

Anyone has any clue what i missed?

Thank you very much!

Consort answered 5/6, 2018 at 6:45 Comment(2)
I also notice an error when i attempt to shutdown the SSL socket. the ec return 'stream truncated'. I changed the 'SSL_Socket.shutdown()' to 'SSL_Socket.async_shutdown()'. The error still happened. Anyone know how to get rip of this error? Thanks.Consort
Do the Beast SSL example servers (such as http-server-sync-ssl or http-server-async-ssl) have this problem? Please try building and testing those examples.Mcmichael
C
2

If you want to reuse the stream instance, you need to manipulate SSL_Socket.native_handle() with openssl lib function. After ssl shutdown, use SSL_clear() before start a new ssl handshake.

please read(pay attention to warnings) link for detail

SSL_clear() resets the SSL object to allow for another connection. The reset operation however keeps several settings of the last sessions (some of these settings were made automatically during the last handshake) .........

WARNINGS

SSL_clear() resets the SSL object to allow for another connection. The reset operation however keeps several settings of the last sessions (some of these settings were made automatically during the last handshake). It only makes sense for a new connection with the exact same peer that shares these settings, and may fail if that peer changes its settings between connections. Use the sequence SSL_get_session(3); SSL_new(3); SSL_set_session(3); SSL_free(3) instead to avoid such failures (or simply SSL_free(3); SSL_new(3) if session reuse is not desired).

In regard to ssl shutdown issue, link explain how boost asio ssl shutdown work.

In Boost.Asio, the shutdown() operation is considered complete upon error or if the party has sent and received a close_notify message.

If you look at boost.asio (1.68) source code boost\asio\ssl\detail\impl\engine.ipp, it shows how boost.asio do ssl shutdown and stream_truncated happens when there is data to be read or ssl shutdown expected from peer not received.

int engine::do_shutdown(void*, std::size_t)
{
  int result = ::SSL_shutdown(ssl_);
  if (result == 0)
    result = ::SSL_shutdown(ssl_);
  return result; 
} 
const boost::system::error_code& engine::map_error_code(
    boost::system::error_code& ec) const
......
// If there's data yet to be read, it's an error.
if (BIO_wpending(ext_bio_))
{
    ec = boost::asio::ssl::error::stream_truncated;
    return ec;
}
......
// Otherwise, the peer should have negotiated a proper shutdown.
if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
{
    ec = boost::asio::ssl::error::stream_truncated;
}
}

Also you can see boost.asio ssl shutdown routine may call openssl SSL_shutdown() twice if first return 0, openssl document allows it but advice call SSL_read() to do a bidirectional shutdown if first SSL_shutdown() returns 0.

Read link for details.

Clarendon answered 12/12, 2018 at 18:8 Comment(0)
T
1

I had a similar issue, the 2nd time onward my asynchonous accept always failed with session id uninitialized.

I solved this problem calling SSL_CTX_set_session_id_context on context or setting context cache mode with SSL_SESS_CACHE_OFF and SSL_OP_NO_TICKET on context options.

This is my cents to someone else's problem.

Tildi answered 4/12, 2018 at 2:49 Comment(1)
example how to set the options: c++ net::ssl::context ctx (net::ssl::context::tls_server); ctx.set_options (SSL_SESS_CACHE_OFF | SSL_OP_NO_TICKET); Nolan
C
0

I managed to resolve the problem by switching 'ssl::stream' socket to 'boost::optional' and then added 'SSL_Socket.emplace(io_context, oSSLContext)' each time the socket is shutdown and closed.

Big credit to sehe at 'Can't implement boost::asio::ssl::stream<boost::asio::ip::tcp::socket> reconnect to server'. His statement "the purest solution would be to not reuse the stream/socket objects" rocks! Save my time.

Thanks.

Consort answered 6/6, 2018 at 6:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.