C++ Boost Beast错误:尝试连接到wss服务器时,sslv3警报证书错误

C++ Boost Beast错误:尝试连接到wss服务器时,sslv3警报证书错误,c++,wss,boost-beast,C++,Wss,Boost Beast,我使用以下代码使用C++中的Boost.Beast库创建WSS服务器: #include <iostream> #include <boost/beast/core.hpp> #include <boost/beast/ssl.hpp> #include <boost/beast/websocket.hpp> #include <boost/beast/websocket/ssl.hpp> #include <boost/asio

我使用以下代码使用C++中的Boost.Beast库创建WSS服务器:

#include <iostream>
#include <boost/beast/core.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <string>
#include <thread>

namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
namespace ssl = boost::asio::ssl;       // from <boost/asio/ssl.hpp>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>


void
load_server_certificate(boost::asio::ssl::context& ctx)
{

    std::string const cert =
            "-----BEGIN CERTIFICATE-----\n"
            "MIIDaDCCAlCgAwIBAgIJAO8vBu8i8exWMA0GCSqGSIb3DQEBCwUAMEkxCzAJBgNV\n"
            "BAYTAlVTMQswCQYDVQQIDAJDQTEtMCsGA1UEBwwkTG9zIEFuZ2VsZXNPPUJlYXN0\n"
            "Q049d3d3LmV4YW1wbGUuY29tMB4XDTE3MDUwMzE4MzkxMloXDTQ0MDkxODE4Mzkx\n"
            "MlowSTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMS0wKwYDVQQHDCRMb3MgQW5n\n"
            "ZWxlc089QmVhc3RDTj13d3cuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n"
            "A4IBDwAwggEKAoIBAQDJ7BRKFO8fqmsEXw8v9YOVXyrQVsVbjSSGEs4Vzs4cJgcF\n"
            "xqGitbnLIrOgiJpRAPLy5MNcAXE1strVGfdEf7xMYSZ/4wOrxUyVw/Ltgsft8m7b\n"
            "Fu8TsCzO6XrxpnVtWk506YZ7ToTa5UjHfBi2+pWTxbpN12UhiZNUcrRsqTFW+6fO\n"
            "9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wWKIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBp\n"
            "yY8anC8u4LPbmgW0/U31PH0rRVfGcBbZsAoQw5Tc5dnb6N2GEIbq3ehSfdDHGnrv\n"
            "enu2tOK9Qx6GEzXh3sekZkxcgh+NlIxCNxu//Dk9AgMBAAGjUzBRMB0GA1UdDgQW\n"
            "BBTZh0N9Ne1OD7GBGJYz4PNESHuXezAfBgNVHSMEGDAWgBTZh0N9Ne1OD7GBGJYz\n"
            "4PNESHuXezAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmTJVT\n"
            "LH5Cru1vXtzb3N9dyolcVH82xFVwPewArchgq+CEkajOU9bnzCqvhM4CryBb4cUs\n"
            "gqXWp85hAh55uBOqXb2yyESEleMCJEiVTwm/m26FdONvEGptsiCmF5Gxi0YRtn8N\n"
            "V+KhrQaAyLrLdPYI7TrwAOisq2I1cD0mt+xgwuv/654Rl3IhOMx+fKWKJ9qLAiaE\n"
            "fQyshjlPP9mYVxWOxqctUdQ8UnsUKKGEUcVrA08i1OAnVKlPFjKBvk+r7jpsTPcr\n"
            "9pWXTO9JrYMML7d+XRSZA1n3856OqZDX4403+9FnXCvfcLZLLKTBvwwFgEFGpzjK\n"
            "UEVbkhd5qstF6qWK\n"
            "-----END CERTIFICATE-----\n";

    std::string const key =
            "-----BEGIN PRIVATE KEY-----\n"
            "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJ7BRKFO8fqmsE\n"
            "Xw8v9YOVXyrQVsVbjSSGEs4Vzs4cJgcFxqGitbnLIrOgiJpRAPLy5MNcAXE1strV\n"
            "GfdEf7xMYSZ/4wOrxUyVw/Ltgsft8m7bFu8TsCzO6XrxpnVtWk506YZ7ToTa5UjH\n"
            "fBi2+pWTxbpN12UhiZNUcrRsqTFW+6fO9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wW\n"
            "KIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBpyY8anC8u4LPbmgW0/U31PH0rRVfGcBbZ\n"
            "sAoQw5Tc5dnb6N2GEIbq3ehSfdDHGnrvenu2tOK9Qx6GEzXh3sekZkxcgh+NlIxC\n"
            "Nxu//Dk9AgMBAAECggEBAK1gV8uETg4SdfE67f9v/5uyK0DYQH1ro4C7hNiUycTB\n"
            "oiYDd6YOA4m4MiQVJuuGtRR5+IR3eI1zFRMFSJs4UqYChNwqQGys7CVsKpplQOW+\n"
            "1BCqkH2HN/Ix5662Dv3mHJemLCKUON77IJKoq0/xuZ04mc9csykox6grFWB3pjXY\n"
            "OEn9U8pt5KNldWfpfAZ7xu9WfyvthGXlhfwKEetOuHfAQv7FF6s25UIEU6Hmnwp9\n"
            "VmYp2twfMGdztz/gfFjKOGxf92RG+FMSkyAPq/vhyB7oQWxa+vdBn6BSdsfn27Qs\n"
            "bTvXrGe4FYcbuw4WkAKTljZX7TUegkXiwFoSps0jegECgYEA7o5AcRTZVUmmSs8W\n"
            "PUHn89UEuDAMFVk7grG1bg8exLQSpugCykcqXt1WNrqB7x6nB+dbVANWNhSmhgCg\n"
            "VrV941vbx8ketqZ9YInSbGPWIU/tss3r8Yx2Ct3mQpvpGC6iGHzEc/NHJP8Efvh/\n"
            "CcUWmLjLGJYYeP5oNu5cncC3fXUCgYEA2LANATm0A6sFVGe3sSLO9un1brA4zlZE\n"
            "Hjd3KOZnMPt73B426qUOcw5B2wIS8GJsUES0P94pKg83oyzmoUV9vJpJLjHA4qmL\n"
            "CDAd6CjAmE5ea4dFdZwDDS8F9FntJMdPQJA9vq+JaeS+k7ds3+7oiNe+RUIHR1Sz\n"
            "VEAKh3Xw66kCgYB7KO/2Mchesu5qku2tZJhHF4QfP5cNcos511uO3bmJ3ln+16uR\n"
            "GRqz7Vu0V6f7dvzPJM/O2QYqV5D9f9dHzN2YgvU9+QSlUeFK9PyxPv3vJt/WP1//\n"
            "zf+nbpaRbwLxnCnNsKSQJFpnrE166/pSZfFbmZQpNlyeIuJU8czZGQTifQKBgHXe\n"
            "/pQGEZhVNab+bHwdFTxXdDzr+1qyrodJYLaM7uFES9InVXQ6qSuJO+WosSi2QXlA\n"
            "hlSfwwCwGnHXAPYFWSp5Owm34tbpp0mi8wHQ+UNgjhgsE2qwnTBUvgZ3zHpPORtD\n"
            "23KZBkTmO40bIEyIJ1IZGdWO32q79nkEBTY+v/lRAoGBAI1rbouFYPBrTYQ9kcjt\n"
            "1yfu4JF5MvO9JrHQ9tOwkqDmNCWx9xWXbgydsn/eFtuUMULWsG3lNjfst/Esb8ch\n"
            "k5cZd6pdJZa4/vhEwrYYSuEjMCnRb0lUsm7TsHxQrUd6Fi/mUuFU/haC0o0chLq7\n"
            "pVOUFq5mW8p0zbtfHbjkgxyF\n"
            "-----END PRIVATE KEY-----\n";

    std::string const dh =
            "-----BEGIN DH PARAMETERS-----\n"
            "MIIBCAKCAQEArzQc5mpm0Fs8yahDeySj31JZlwEphUdZ9StM2D8+Fo7TMduGtSi+\n"
            "/HRWVwHcTFAgrxVdm+dl474mOUqqaz4MpzIb6+6OVfWHbQJmXPepZKyu4LgUPvY/\n"
            "4q3/iDMjIS0fLOu/bLuObwU5ccZmDgfhmz1GanRlTQOiYRty3FiOATWZBRh6uv4u\n"
            "tff4A9Bm3V9tLx9S6djq31w31Gl7OQhryodW28kc16t9TvO1BzcV3HjRPwpe701X\n"
            "oEEZdnZWANkkpR/m/pfgdmGPU66S2sXMHgsliViQWpDCYeehrvFRHEdR9NV+XJfC\n"
            "QMUk26jPTIVTLfXmmwU0u8vUkpR7LQKkwwIBAg==\n"
            "-----END DH PARAMETERS-----\n";

    ctx.set_password_callback(
            [](std::size_t,
               boost::asio::ssl::context_base::password_purpose)
            {
                return "test";
            });

    ctx.set_options(
            boost::asio::ssl::context::default_workarounds |
            boost::asio::ssl::context::no_sslv2 |
            boost::asio::ssl::context::single_dh_use);

    ctx.use_certificate_chain(
            boost::asio::buffer(cert.data(), cert.size()));

    ctx.use_private_key(
            boost::asio::buffer(key.data(), key.size()),
            boost::asio::ssl::context::file_format::pem);

    ctx.use_tmp_dh(
            boost::asio::buffer(dh.data(), dh.size()));
}

// Echoes back all received WebSocket messages
void
do_session(tcp::socket socket, ssl::context& ctx)
{
    try
    {
        // Construct the websocket stream around the socket
        websocket::stream<beast::ssl_stream<tcp::socket&>> ws{socket, ctx};

        // Perform the SSL handshake

        ws.next_layer().handshake(ssl::stream_base::server);


        // Set a decorator to change the Server of the handshake

        ws.set_option(websocket::stream_base::decorator(
                [](websocket::response_type& res)
                {
                    res.set(http::field::server,
                            std::string(BOOST_BEAST_VERSION_STRING) +
                            " websocket-server-sync-ssl");
                }));

        // Accept the websocket handshake
        ws.accept();
        // my_stream is a beast::websocket::stream


        for(;;)
        {
            // This buffer will hold the incoming message
            beast::flat_buffer buffer;

            // Read a message
            ws.read(buffer);

            // Echo the message back
            ws.text(ws.got_text());
            std::cout << "Received: " << beast::buffers_to_string(buffer.data()) << std::endl;
            ws.write(buffer.data());
        }
    }
    catch(beast::system_error const& se)
    {
        // This indicates that the session was closed
        if(se.code() != websocket::error::closed)
            std::cerr << "Error: " << se.code().message() << std::endl;
    }
    catch(std::exception const& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}



int main(int argc, char* argv[])
{
    try
    {
        // Check command line arguments.
        if (argc != 3)
        {
            std::cerr <<
                      "Usage: websocket-server-sync-ssl <address> <port>\n" <<
                      "Example:\n" <<
                      "    websocket-server-sync-ssl 0.0.0.0 8080\n";
            return EXIT_FAILURE;
        }
        auto host = argv[1];
        auto const address = net::ip::make_address(argv[1]);
        auto const port = static_cast<unsigned short>(std::atoi(argv[2]));

        // The io_context is required for all I/O
        net::io_context ioc{1};

        // The SSL context is required, and holds certificates
        //ssl::context ctx{ssl::context::tlsv13};

        ssl::context ctx{ssl::context::tlsv12};

        // This holds the self-signed certificate used by the server
        load_server_certificate(ctx);

        // The acceptor receives incoming connections
        tcp::acceptor acceptor{ioc, {address, port}};
        for(;;)
        {
            // This will receive the new connection
            tcp::socket socket{ioc};

            // Block until we get a connection
            acceptor.accept(socket);

            // Launch the session, transferring ownership of the socket
            std::thread(
                    &do_session,
                    std::move(socket),
                    std::ref(ctx)).detach();
        }
    }
    catch (const std::exception& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
命名空间beast=boost::beast;//从…起
命名空间http=beast::http;//从…起
命名空间websocket=beast::websocket;//从…起
名称空间net=boost::asio;//从…起
名称空间ssl=boost::asio::ssl;//从…起
使用tcp=boost::asio::ip::tcp;//从…起
无效的
加载服务器证书(boost::asio::ssl::context&ctx)
{
字符串常量证书=
“----开始证书------\n”
“MIIDaDCCAlCgAwIBAgIJAO8vBu8i8exWMA0GCSqGSIb3DQEBCwUAMEkxCzAJBgNV\n”
“BAYTAlVTMQswCQYDVQQIDAJDQTEtMCsGA1UEBwwkTG9zIEFuZ2VsZXNPPUJlYXN0\n”
“Q049D3LMV4YW1WBGUY29TMB4XDTE3MDUWMZE4MZKXMLOXDTQ0MDKXODE4MZKX\n”
“MLOWSTELMAKGA1UEBHMCVMXCZAJBGNVBAGMAKNBMS0WKWYDVQHDCRMB3MGQW5N\n”
“ZWXLC089QMVHC3RDTJ13D3CUZXHBXBSS5JB20WGGEIMA0GCSQGSIB3DQEBAQUA\n”
“A4IBDwAwggEKAoIBAQDJ7BRKFO8fqmsEXw8v9YOVXyrQVsVbjSSGEs4Vzs4cJgcF\n”
“xqgitbnlirogijpraply5mncaxe1srvgfdef7xmysz/4wOrxUyVw/Ltgsft8m7b\n”
“Fu8TsCzO6XrxpnVtWk506YZ7ToTa5UjHfBi2+PWTXBPN12UHIZNUCRRSQSTFW+6fO\n”
“9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wWKIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBp\n”
“yY8anC8u4LPbmgW0/U31PH0rRVfGcBbZsAoQw5Tc5dnb6N2GEIbq3ehSfdDHGnrv\n”
“enu2tOK9Qx6GEzXh3sekZkxcgh+NlIxCNxu//dk9agmbagjuzbrmb0ga1udgqw\n”
“BBTZH0N9NE1OD7GBGJZ4PNESHUXEZAFBGNVHSMEGDAWGBTZH0N9NE1OD7GBGJYZ\n”
“4PNESHUXEZAPBGNVHRMBAF8EBTADAKH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmTJVT\n”
“LH5Cru1vXtzb3N9dyolcVH82xFVwPewArchgq+CEkajOU9bnzCqvhM4CryBb4cUs\n”
“gqXWp85hAh55uBOqXb2yyESEleMCJEiVTwm/m26FdONvEGptsiCmF5Gxi0YRtn8N\n”
“V+KhrQaAyLrLdPYI7TrwAOisq2I1cD0mt+xgwuv/654Rl3IhOMx+FKWKJ9QLAIEE\n”
“FQYSHJLPP9MYVxWOxQCTUDQ8UNKKGEUCVRA08I1ANVKLPFJKBVK+r7jpsTPcr\n”
“9pWXTO9JrYMML7d+XRSZA1n3856OqZDX4403+9FNxCvfclLKTBvwfggefGpzjk\n”
“UEVbkhd5qstF6qWK\n”
“----结束证书------\n”;
字符串常量键=
“----开始私钥------\n”
“miievgibadanbkkqhkig9w0baqefaascbkgwggskageaaoibaqdj7brkfo8fqmse\n”
“XW8V9YOVxYRQVSVBJSSGES4VZS4CJGCFxQGITBNLROGIJJPRAPLY5MNCAXE1STRV\n”
“GfdEf7xMYSZ/4wOrxUyVw/Ltgsft8m7bFu8TsCzO6XrxpnVtWk506YZ7ToTa5UjH\n”
“fBi2+PWTXBPN12UHIZNUCRRSQSTFW+6fO9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wW\n”
“KIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBpyY8anC8u4LPbmgW0/U31PH0rRVfGcBbZ\n”
“SAOQW5TC5DNB6N2GEIBQ3EHSFDDHGNRVENU2TOK9QX6GEZXH3SEKZKCGH+NlIxC\n”
“Nxu//Dk9AgMBAAECggEBAK1gV8uETg4SdfE67f9v/5uyK0DYQH1ro4C7hNiUycTB\n”
“OIYDD6YOA4MIQVJUUGTRR5+IR3EI1ZFRMFSSJS4UQYCHNWQGYS7CVSKPPLQOW+\n”
“1BCKH2HN/IX5662DV3MHjemlckun77IJKOQ0/xuZ04mc9csykox6grFWB3pjXY\n”
“OEn9U8pt5KNldWfpfAZ7xu9WfyvthGXlhfwKEetOuHfAQv7FF6s25UIEU6Hmnwp9\n”
“VMYP2TWFMGDZZ/GFFJKOG0XF92RG+FMSkyAPq/vhyB7oQWxa+vdBn6BSdsfn27Qs\n”
“BTVxRGE4FYCBUWKKTLJZX7TUEGKXIWFOSPS0JEGECGYEA7O5ACRTZVUMMS8W\n”
“PUHn89UEuDAMFVk7grG1bg8exLQSpugCykcqXt1WNrqB7x6nB+dbVANWNhSmhgCg\n”
“VrV941vbx8ketqZ9YInSbGPWIU/tss3r8Yx2Ct3mQpvpGC6iGHzEc/NHJP8Efvh/\n”
“CCUWMLJLGJYYEP5ONU5NCC3FXUCGYEA2LANTM0A6SFVGE3SSLO9UN1BRA4ZLZE\n”
“HJD3KOZNMTP73B426QUOCW5B2 WIS8GJSUES0P94PKG83OYZMOUV9VJPJLJHA4QML\n”
“CDAD6CJAME5EA4DFZWDDS8F9FNTJMDPQJA9VQ+JaeS+k7ds3+7oiNe+RUIHR1Sz\n”
“VEAKh3Xw66kCgYB7KO/2MCHESU5QKU2TZJHF4QFP5CNCOS511UO3BMJ3LN+16uR\n”
“GRqz7Vu0V6f7dvzPJM/O2QYqV5D9f9dHzN2YgvU9+QSlUeFK9PyxPv3vJt/WP1/\n”
“zf+nbpaRbwLxnCnNsKSQJFpnrE166/PSZFFBMZQPNLYEUJU8CZGQTIFQKBGHXE\n”
“/pQGEZhVNab+bHwdFTxXdDzr+1qyrodJYLaM7uFES9InVXQ6qSuJO+WosSi2QXlA\n”
“hlSfwwCwGnHXAPYFWSp5Owm34tbpp0mi8wHQ+UNGHGSE2QWNTBUVGZHPPORTD\n”
“23KZBkTmO40bIEyIJ1IZGdWO32q79nkEBTY+v/lRAoGBAI1rbouFYPBrTYQ9kcjt\n”
“1yfu4JF5MvO9JrHQ9tOwkqDmNCWx9xWXbgydsn/eFtuUMULWsG3lNjfst/Esb8ch\n”
“k5cZd6pdJZa4/vhEwrYYSuEjMCnRb0lUsm7TsHxQrUd6Fi/mUuFU/haC0o0chLq7\n”
“PVOUFQ5MW8P0ZBTFBJKGXYF\n”
“----结束私钥------\n”;
std::string const dh=
“----开始DH参数------\n”
“MIIBCAKCAQEArzQc5mpm0Fs8yahDeySj31JZlwEphUdZ9StM2D8+Fo7TMduGtSi+\n”
“/hrwvwhctfagraxvdm+dl474mouqaz4mpzib6+6OVfWHbQJmXPepZKyu4LgUPvY/\n”
“4q3/iDMjIS0fLOu/BLOUBWU5CCZMDGFHMZ1GANRLTQOIYRTY3FIOATWZBRH6UV4U\n”
“tff4A9Bm3V9tLx9S6djq31w31Gl7OQhryodW28kc16t9TvO1BzcV3HjRPwpe701X\n”
“OEZDNZWANKKPR/m/PFGDMGPU66S2SXMHGSLIVIIQWPDCYEEHRVRHERD9NV+XJfC\n”
“qmuk26jptivtlfxmmwu0u8vukpr7lqkkwibag==\n”
“----结束DH参数------\n”;
ctx.set\u密码\u回调(
[](标准:尺寸),
boost::asio::ssl::context\u base::password\u用途)
{
返回“测试”;
});
ctx.set_选项(
boost::asio::ssl::context::default\u解决方法|
boost::asio::ssl::context::no\u sslv2|
boost::asio::ssl::context::single_dh_use);
使用证书链(
boost::asio::buffer(cert.data(),cert.size());
ctx.use_private_密钥(
boost::asio::buffer(key.data(),key.size()),
boost::asio::ssl::context::file\u format::pem);
ctx.use_tmp_dh(
boost::asio::buffer(dh.data(),dh.size());
}
//回显所有接收到的WebSocket消息
无效的
do_会话(tcp::套接字、ssl::上下文和ctx)
{
尝试
{
//围绕套接字构造websocket流
websocket::流ws{socket,ctx};
//执行SSL握手
ws.next_layer().han
<script type="text/javascript">
let socket = new WebSocket("wss://127.0.0.1:8080");

socket.onopen = function(e) {
  alert("[open] Connection established");
  alert("Sending to server");
  socket.send("My name is John");
};

socket.onmessage = function(event) {
  alert(`[message] Data received from server: ${event.data}`);
};

socket.onclose = function(event) {
  if (event.wasClean) {
    alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
  } else {
    // e.g. server process killed or network down
    // event.code is usually 1006 in this case
    alert('[close] Connection died');
  }
};

socket.onerror = function(error) {
  alert(`[error] ${error.message}`);
};
</script>
./<compiled wss> 0.0.0.0 8080