c++ Boost asio error: no shared cipher

本小妞迷上赌 提交于 2019-12-08 02:13:51

问题


I am currently setting a RESTful API with boost asio.

Connecting from a client works fine via HTTP. But if I try to connect via HTTPS I get an error on the server side: "no shared cipher". The error seems to come from the openssl implementation, but I have no idea what to make of it. My first guess would be that that no cypher algorithm is set, but I cannot see how this can be done in asio.

This is what I put in the code and where the error occurs:

auto acceptHandler = boost::bind(&self::onAccept, this, connection,
                                 boost::asio::placeholders::error);
connection->async_accept(m_acceptor, acceptHandler);

m_sslContext.set_options(
        context::default_workarounds | context::no_sslv2 | context::single_dh_use);
m_sslContext.use_certificate_file(filename, context::pem);
m_sslContext.use_private_key_file(filename, context::pem);

Anyone ever had this before or got it working?


回答1:


I got same error when feed unconfigured boost::asio::ssl::context object to boost::asio::ssl::stream object constructor, which then used as resulted socket of accepting:

server()
    : m_acceptor(/*args*/)
    , m_context(boost::asio::ssl::context::tlsv1_server)
    , m_stream(m_io_service, m_context)
{
    // `m_context` configuring, BUT `m_stream` is unaffected
    m_acceptor.async_accept(m_stream.lowest_layer(), accept_result_handler);
}
// run somewhere `m_io_service.run()`, or other processor of `async` operations.

And after actual accept connection and process handshake on it the handshake handler receive boost::system::error_code with value 336109761 and message no shared cipher.

So first create and configure boost::asio::ssl::context and then construct boost::asio::ssl::stream with it:

typedef boost::asio::ip::tcp::socket socket_type;
typedef boost::asio::ssl::stream<socket_type> stream_type;

std::shared_ptr<stream_type> m_stream;

server()
    : m_acceptor(/*args*/)
    , m_context(boost::asio::ssl::context::tlsv1_server)
{
    // `m_context` configuring
    m_stream = std::make_shared<stream_type>(m_io_service, m_context);
    m_acceptor.async_accept(m_stream->lowest_layer(), accept_result_handler);
}

And don't forget create new stream for each new connection, context can be the same.




回答2:


I had the same problem and solved it this way.You have to generate a private key and a certificate file for your server. Here is the procedure to do so :

// Generate a new ssl private key :
$openssl genrsa -out privkey.pem 1024

// Create a certificate signing request using your new key
$openssl req -new -key privkey.pem -out certreq.csr

// Self-sign your CSR with your own private key:
$openssl x509 -req -days 3650 -in certreq.csr -signkey privkey.pem -out newcert.pem

// Install the signed certificate and private key for use by an ssl server
// This allows you to use a single file for certificate and private key
$( openssl x509 -in newcert.pem; cat privkey.pem ) > server.pem

// If you use a dh temp file :
$openssl dhparam -outform PEM -out dh512.pem 512

Then, copy the server.pem and dh512.pem files in your server execution directory.

If you use the tmp dh file you also have to add this line of code m_sslContext.use_tmp_dh_file("dh512.pem");




回答3:


As @asiocity points out, the essential part is to fully configure the ssl::context before initialising the ssl::stream.

It is hard to initialise them both in an initialiser list while still deferring the ssl::stream until the ssl::context is fully configured.

One way I use is to subclass the ssl::context and override the constructor so that it can be fully configured in the initializer list, before the ssl::stream is initialised.

e.g.

class server_context : public boost::asio::ssl::context {
  public: server_context(boost::asio::ssl::context::method m, std::string certfile);
};

...

server_context::server_context(boost::asio::ssl::context::method m, std::string certfile)
: boost::asio::ssl::context(m)
{
  use_private_key_file(certfile);
  use_certificate_chain_file(certfile);
}

...

class myclass {
  private:
    server_context : ssl_context_;
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> stream_;
  public:
    myclass(boost::asio::ip::tcp::socket&, std::string certfile);

...

myclass::myclass(std::string certfile) 
: ssl_context_(boost::asio::ssl::context::sslv23, certfile),
  stream_(socket, ssl_context_) 
{
  ...
}

However that seems a lot of work to avoid a shared_ptr

I'm wishing/hoping for some constructor-mixin/template trick that would allow me to do this with just a custom initializer list rather than a subclass.



来源:https://stackoverflow.com/questions/12217346/c-boost-asio-error-no-shared-cipher

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!