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
}
我申请了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
}