4

我的问题似乎源于这样一个事实,即openssl 没有像服务器名称指示(SNI)这样的回调继续传递样式,但我正试图强制其中一个。

我想避免在读取客户端 SSL hello 时阻塞工作线程,并避免在等待服务器 ssl 握手完成时拒绝返回 SNI 回调时阻塞工作线程(这样我就可以重新签署服务器证书)。

对于使用openssl 包装器的asiobsaed 重新签名 SSL 代理。boost::asio::ssl::stream

SSL_CTX_set_tlsext_servername_*在与客户端进行 SSL 协商期间,我使用助手来获取回调。

目前请确保我在 aboost::asio::spawn上的 lambda 中使用协程和握手strand。我使用服务器名称指示回调(适当地包装),以便我可以在服务器握手期间阻止客户端握手,但不会阻止工作线程(协同程序将暂停。

boost::asio::spawn(strand_, [=](boost::asio::yield_context yield){
  boost::system::error_code ec;
  boost::system::error_code ec_server;

  sni_callback = [=,&ec](std::string server_name) {
    server_->ssl_connection->ssl_socket.async_handshake(boost::asio::ssl::stream_base::client, yield[ec_server]);
    /* Todo: sign the server certificate and replace the ssl_socket SSL_CTX here */
  };

  ssl_connection->ssl_socket.handshake(boost::asio::ssl:stream_base::server, ec);

  if (! ec) ec = ec_server;

  handler(ec);
});

但我意识到与客户端的 ssl 握手会阻止它完成的工作线程。

我尝试与客户进行异步握手:

  ssl_connection->ssl_socket.async_handshake(boost::asio::ssl:stream_base::server, yield[ec]);

但是在 SNI 处理程序包装期间,程序在 yield 中出现了段错误。

毫无疑问,这是因为非阻塞握手不会调用协程上的 SNI 处理程序——它可以做到这一点的唯一方法(不阻塞工作线程)是如果它的所有内部处理程序都在协程上调用,但是我知道它使用内部链来完成自己的工作。

加载所有共享库符号(即使对于 libstdc++ 等),堆栈跟踪是:

.#0  0x000000000000000c in ?? ()
.#1  0x00007f8200000000 in ?? ()
.#2  0x00007f829e15043d in CRYPTO_free (str=0x7f828c054640) at mem.c:401
.#3  0x00007f829e1faba5 in ASN1_primitive_free (pval=<optimized out>, it=<optimized out>) at tasn_fre.c:261
.#4  0x00007f828c052250 in ?? ()
.#5  0x0000000000000005 in ?? ()
.#6  0x00007f828c0524f0 in ?? ()
.#7  0x0000000000000005 in ?? ()
.#8  0x00007f829d30c560 in ?? ()
.#9  0x00007f829d30c710 in ?? ()
.#10 0x000000000000000c in ?? ()
.#11 0x00007f828c0180b4 in ?? ()
.#12 0x00007f829e15043d in CRYPTO_free (str=0x7f828c052250) at mem.c:401
.#13 0x00007f829e1eb2cf in EVP_PKEY_CTX_free (ctx=<optimized out>) at pmeth_lib.c:381
.#14 0x00007f829e1de1e2 in EVP_MD_CTX_cleanup (ctx=0x7f829d30c590) at digest.c:394
.#15 0x00007f829e5041c1 in tls1_PRF (digest_mask=262400, seed1=0x7f829e5213fb, seed1_len=15, seed2=0x7f829d30c720, seed2_len=-1639094656, seed3=0x0, 
seed3_len=-1657747584, seed4=0x23635fe, seed4_len=-1657747600, sec=0x7f82a0035df0 "\321\365M\236\202\177", slen=<optimized out>, out1=0x7f82a0035178 "d\356@", 
out2=0x7f82a0038508 "", olen=4247053, seed5_len=0, seed5=0x0) at t1_enc.c:272
.#16 0x00007f829e4dbb18 in ?? () from /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0
.#17 0x00007f829d30c780 in ?? ()
.#18 0x00000000023635fe in ?? ()
.#19 0x00007f829d30c770 in ?? ()
.#20 0x00007f82a0035df0 in ?? ()
.#21 0x0000000000000000 in ?? ()

我希望这是清除故障期间的堆栈跟踪。

要在同一个协程上调用 SNI 处理程序,我认为我需要使所有 ssl::stream 中间回调发生在该协程上。有没有直接的方法可以做到这一点?

我想知道 boost::ssl 是否可以在它自己的链中调用它的处理程序,但仍然在协程堆栈上,这是唯一的解决方法,但我不知道带有处理程序的 asio_handler_invoke 业务是否有足够的魔力来导致这种情况发生,即使这是可能的。如何嵌套 asio_handler_invoke 以在协程(本身为 strand-y)和通过内部链上运行。

我还应该在示例的最后一行中使用 asio_invoke_handler 吗?

4

0 回答 0