cpprestsdk https 握手有什么问题

What's wrong with the cpprestsdk https handshake

我申请了ssl,但效果并不理想。用wireshark查看,server端和client端没有key变化。

可以沟通,但不尽如人意。服务器是 Linux,客户端正在使用 Chrome。 我知道正常的ssl通信报文是

"客户端密钥交换、密码更改规范、加密握手消息"

"服务器问候,证书,服务器密钥交换,服务器问候完成"。但是我看不见。

代码

#include <iostream>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;

int main(){
    http_listener_config listen_config;
    listen_config.set_ssl_context_callback([](boost::asio::ssl::context &ctx)
    {

        ctx.set_options(
            boost::asio::ssl::context::default_workarounds
            | boost::asio::ssl::context::no_sslv2
            | boost::asio::ssl::context::no_tlsv1
            | boost::asio::ssl::context::no_tlsv1_1
            | boost::asio::ssl::context::single_dh_use);
        ctx.set_password_callback([](std::size_t max_length, boost::asio::ssl::context::password_purpose purpose)
        {
           return "password";
        });
        ctx.use_certificate_chain_file("rootca.crt");
        ctx.use_private_key_file("rootca.key", boost::asio::ssl::context::pem);
        ctx.use_tmp_dh_file("dh2048.pem");
    });


    listen_config.set_timeout(utility::seconds(10));
    http_listener listener(U("https://0.0.0.0:10022"), listen_config);        //Server URL, Port .
        listener.support(methods::GET, [](http_request req){
        auto j = json::value::object();
        auto path = req.request_uri().path();
        std::cout << path << std::endl;
        j[U("one")] = json::value::string(U("asdfasefasdfaefasdfasefasdfefasefasefaqf3wfsefasdfasefasdfzsfzdfaesfzsefzsdfzsef"));
        req.reply(status_codes::OK, j);                     
        });
    
    listener.open().then([&listener](){std::cout << (U("\n start!!\n"));}).wait();    //Server open
    while(true);
    listener.close();
    return 0;
    
}

客户端连接服务器时的数据包。

这段代码有问题吗?或者这是正常的吗?

不,这不行:

做一个

openssl s_client -connect :10022 -debug -showcerts -state

演出

CONNECTED(00000005)
write to 0x5614f8b23690 [0x5614f8b33620] (311 bytes => 311 (0x137))
0000 - 16 03 01 01 32 01 00 01-2e 03 03 79 fe 76 37 2b   ....2......y.v7+
0010 - 9f bf e7 62 51 34 7d 4a-00 5e 1f ed 55 64 61 e1   ...bQ4}J.^..Uda.
0020 - 44 ce a0 c0 31 eb 3a b0-80 78 87 20 70 c4 1f 56   D...1.:..x. p..V
0030 - 62 da 74 b7 d7 6a 31 50-0c 8c 90 46 23 c6 59 13   b.t..j1P...F#.Y.
0040 - 17 6c 67 8f e3 9a 85 77-ab 6e c2 a3 00 3e 13 02   .lg....w.n...>..
0050 - 13 03 13 01 c0 2c c0 30-00 9f cc a9 cc a8 cc aa   .....,.0........
0060 - c0 2b c0 2f 00 9e c0 24-c0 28 00 6b c0 23 c0 27   .+./...$.(.k.#.'
0070 - 00 67 c0 0a c0 14 00 39-c0 09 c0 13 00 33 00 9d   .g.....9.....3..
0080 - 00 9c 00 3d 00 3c 00 35-00 2f 00 ff 01 00 00 a7   ...=.<.5./......
0090 - 00 00 00 0e 00 0c 00 00-09 6c 6f 63 61 6c 68 6f   .........localho
00a0 - 73 74 00 0b 00 04 03 00-01 02 00 0a 00 0c 00 0a   st..............
00b0 - 00 1d 00 17 00 1e 00 19-00 18 00 23 00 00 00 16   ...........#....
00c0 - 00 00 00 17 00 00 00 0d-00 30 00 2e 04 03 05 03   .........0......
00d0 - 06 03 08 07 08 08 08 09-08 0a 08 0b 08 04 08 05   ................
00e0 - 08 06 04 01 05 01 06 01-03 03 02 03 03 01 02 01   ................
00f0 - 03 02 02 02 04 02 05 02-06 02 00 2b 00 09 08 03   ...........+....
0100 - 04 03 03 03 02 03 01 00-2d 00 02 01 01 00 33 00   ........-.....3.
0110 - 26 00 24 00 1d 00 20 a1-ab 9c 0d 7e e9 80 84 ba   &.$... ....~....
0120 - 0a 5a 71 20 7d 59 cd d9-24 9c de 9a 05 9d a2 78   .Zq }Y..$......x
0130 - 0d 0d 79 a1 3b 65 58                              ..y.;eX
read from 0x5614f8b23690 [0x5614f8b2a313] (5 bytes => 0 (0x0))
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 311 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
read from 0x5614f8b23690 [0x5614f8b18d80] (8192 bytes => 0 (0x0))

所以我得到了 none-安全后备。事实证明,未处理的异常会导致真正的退化行为。添加一些异常处理显示:

ERROR: use_certificate_chain_file: No such file or directory

当然可以。添加这些:

NOTE: It seems unlikely that you'd actually use a rootca for the sever. Maybe change the name of the file to reflect what it contains, or reconsider the cert you use for a server purpose.

        ctx.set_password_callback(
            [](std::size_t /*max_length*/,
               ssl::context::password_purpose /*purpose*/) {
                return "test";
            });
        ctx.use_certificate_chain_file("server.pem");
        ctx.use_private_key_file("server.pem", ssl::context::pem);
        ctx.use_tmp_dh_file("dh2048.pem");

Note, I used the key/dh params from the boost SSL samples, so the passphrase is test

现在,一个简单的 GET 请求可以工作,再次使用 s_client 或使用类似 wget:

的东西
wget --no-check-certificate https://localhost:10022/ -O - -q
{"one":"asdfasefasdfaefasdfasefasdfefasefasefaqf3wfsefasdfasefasdfzsfzdfaesfzsefzsdfzsef"}

总结

我的假设是您也陷入了不处理错误的陷阱。我认为库的“失败打开”模式是一个潜在的安全问题——尽管 ssl::context 的所有这些参数可能已经有效地要求了。


作为参考,我最后测试的完整代码:

#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <iostream>

using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
namespace net = boost::asio;
namespace ssl = net::ssl;

int main() {
    http_listener_config listen_config;
    listen_config.set_ssl_context_callback([](ssl::context& ctx) {
        try {
            std::clog << "set_ssl_context_callback" << std::endl;
            ctx.set_options(ssl::context::default_workarounds |
                            ssl::context::no_sslv2 | ssl::context::no_tlsv1 |
                            ssl::context::no_tlsv1_1 |
                            ssl::context::single_dh_use);
            ctx.set_password_callback(
                [](std::size_t /*max_length*/,
                   ssl::context::password_purpose /*purpose*/) {
                    return "test";
                });
            ctx.use_certificate_chain_file("server.pem");
            ctx.use_private_key_file("server.pem", ssl::context::pem);
            ctx.use_tmp_dh_file("dh2048.pem");
            std::clog << "leave set_ssl_context_callback" << std::endl;
        } catch (std::exception const& e) {
            std::clog << "ERROR: " << e.what() << "\n";
        }
    });

    listen_config.set_timeout(utility::seconds(10));
    http_listener listener(U("https://localhost:10022"),
                           listen_config); // Server URL, Port .

    listener.support(methods::GET, [](http_request req) {
        std::clog << "enter handler" << std::endl;
        auto j = json::value::object();
        auto path = req.request_uri().path();
        std::clog << path << std::endl;
        j[U("one")] =
            json::value::string(U("asdfasefasdfaefasdfasefasdfefasefasefaqf3wfs"
                                  "efasdfasefasdfzsfzdfaesfzsefzsdfzsef"));
        req.reply(status_codes::OK, j).wait();
        std::clog << "leave handler" << std::endl;
    });

    listener.open()
        .then([&listener] { std::clog << (U("\n start!!\n")); })
        .wait(); // Server open
    while (true)
        ;
    listener.close(); // huh
}