繁体   English   中英

证书验证在与boost :: asio和OpenSSL的客户端服务器通信中失败

[英]Certificate verify failed in client server communication with boost::asio and OpenSSL

我正在为此编写简单的回显服务器和客户端,以作为通过boost :: asioOpenSSL进行加密网络通信的概念证明。 我希望双方都使用自签名证书进行身份验证。 我对双方使用相同的私钥,并从中生成了两个证书。 但是,当我尝试在双方之间建立安全通信时,在握手阶段会出现以下错误:

证书验证失败

首先,我使用以下命令生成了私钥和服务器证书:

openssl req -x509 -newkey rsa:2048 -keyout private_key.pem -out certificate.pem -days 365 -nodes

然后我为客户端生成了其他证书

 openssl req -newkey rsa:2048 -nodes -keyout private_key.pem -x509 -days 365 -out client_certificate.pem

服务器中OpenSSL上下文的初始化为:

...
, m_sslContext(ssl::context::sslv23)
...
m_sslContext.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert);
m_sslContext.use_private_key_file(options.privateKeyFile, ssl::context::pem);
m_sslContext.use_certificate_file(options.certificateFile, ssl::context::pem);
...

在客户端中是:

...
, m_sslContext(ssl::context::sslv23)
...
 m_sslContext.set_verify_mode(ssl::verify_peer);
 m_sslContext.use_private_key_file(options.privateKeyFile, ssl::context::pem);
 m_sslContext.use_certificate_file(options.certificateFile, ssl::context::pem);
...

服务器的完整代码在这里:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <string>
#include <thread>
#include <atomic>
#include <cstdint>

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>

#include <boost/program_options.hpp>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>

#include <io_service_pool.hpp>

using namespace std;
using namespace boost::asio;
using namespace boost::system;

namespace po = boost::program_options;
namespace logging = boost::log;

#define CHECK_FOR_ERROR(err) \
    if (err) \
    { \
        BOOST_LOG_TRIVIAL(error) << err.message() << endl; \
        return; \
    }

namespace std
{

ostream& operator<<(ostream& ostr, const boost::asio::streambuf& buffer)
{
    for (size_t i = 0; i < buffer.size(); ++i)
    {
        ostr << hex << (unsigned short) buffer_cast<const char*>(buffer.data())[i] << " ";
    }
    return ostr;
}

} // std namespace

struct Statistics
{
    atomic<uint32_t> connectionsAccepted;
    atomic<uint32_t> requestsReceived;
    atomic<uint32_t> responsesSent;
    atomic<uint64_t> dataReceived;
    atomic<uint64_t> dataSent;

}; // Statistics struct

Statistics g_statistics;

class TCPConnection : public enable_shared_from_this<TCPConnection>
{
public:
    using SSLSocket = ssl::stream<ip::tcp::socket>;
    using Ptr = shared_ptr<TCPConnection>;

    static Ptr create(io_service& ioService, ssl::context& sslContext)
    {
        return TCPConnection::Ptr(new TCPConnection(ioService, sslContext));
    }

    SSLSocket::lowest_layer_type& socket()
    {
        return m_socket.lowest_layer();
    }

    void start()
    {
        ip::tcp::no_delay noDelay(true);
        socket().set_option(noDelay);

        auto remoteAddress = socket().remote_endpoint().address().to_string();
        BOOST_LOG_TRIVIAL(debug) << "Incoming connection from: " << remoteAddress;

        g_statistics.connectionsAccepted++;

        auto self(shared_from_this());

        m_socket.async_handshake(ssl::stream_base::server, [self, remoteAddress](const error_code& err)
        {
            CHECK_FOR_ERROR(err)

            BOOST_LOG_TRIVIAL(debug) << "Handshake with " << remoteAddress << " succeeded.";

            async_read_until(self->m_socket, self->m_buffer, '\0',
                             [self, remoteAddress](const error_code& err, size_t bytesTransfered)
            {
                CHECK_FOR_ERROR(err)
                BOOST_LOG_TRIVIAL(debug) << "Received " << bytesTransfered << " bytes from " << remoteAddress;
                BOOST_LOG_TRIVIAL(trace) << "Data: " << self->m_buffer;

                g_statistics.requestsReceived++;
                g_statistics.dataReceived += bytesTransfered;

                async_write(self->m_socket, self->m_buffer,
                            [self, remoteAddress](const error_code& err, size_t bytesTransfered)
                {
                    CHECK_FOR_ERROR(err)
                    BOOST_LOG_TRIVIAL(debug) << "Sent " << dec << bytesTransfered << " bytes to " << remoteAddress;

                    g_statistics.responsesSent++;
                    g_statistics.dataSent += bytesTransfered;
                });
            });
        });
    }

private:
    TCPConnection(io_service& ioService, ssl::context& sslContext)
        : m_socket(ioService, sslContext)
    {
    }

private:
    SSLSocket m_socket;
    boost::asio::streambuf m_buffer;

}; // TCPConnection class

struct ProgramOptions
{
    unsigned port         = 0;
    unsigned threadsCount = 0;
    string privateKeyFile;
    string certificateFile;

}; // ProgramOptions struct

class Server
{
public:
    Server(const ProgramOptions& options)
        : m_ioServicePool(options.threadsCount)
        , m_acceptor(m_ioServicePool.getIOService(),
                     ip::tcp::endpoint(ip::tcp::v4(), options.port))
        , m_signals(m_ioServicePool.getIOService())
        , m_sslContext(ssl::context::sslv23)
    {
        m_acceptor.set_option(ip::tcp::acceptor::reuse_address(true));

        m_signals.add(SIGINT);
        m_signals.add(SIGTERM);
        m_signals.add(SIGQUIT);
        m_signals.async_wait([this](const error_code& err, int signalNumber)
        {
           if (err)
           {
               BOOST_LOG_TRIVIAL(error) << err.message();
           }

           BOOST_LOG_TRIVIAL(debug) << "Received signal: " << signalNumber;

           BOOST_LOG_TRIVIAL(info) << "Statistics:";
           BOOST_LOG_TRIVIAL(info) << "Connections accepted: " << g_statistics.connectionsAccepted;
           BOOST_LOG_TRIVIAL(info) << "Requests received: " << g_statistics.requestsReceived;
           BOOST_LOG_TRIVIAL(info) << "Responses sent: " << g_statistics.responsesSent;
           BOOST_LOG_TRIVIAL(info) << "Data received: " << g_statistics.dataReceived << " bytes.";
           BOOST_LOG_TRIVIAL(info) << "Data sent: " << g_statistics.dataSent << " bytes.";

           m_ioServicePool.stop();
        });

        m_sslContext.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert);
        m_sslContext.use_private_key_file(options.privateKeyFile, ssl::context::pem);
        m_sslContext.use_certificate_file(options.certificateFile, ssl::context::pem);

        startAccept();
    }

    void run()
    {
        BOOST_LOG_TRIVIAL(info) << "Server started!";
        m_ioServicePool.run();
    }

private:
    void startAccept()
    {
        auto conn = TCPConnection::create(m_ioServicePool.getIOService(), m_sslContext);

        m_acceptor.async_accept(conn->socket(), [this, conn](const error_code& err)
        {
           CHECK_FOR_ERROR(err)
           conn->start();

           startAccept();
        });
    }

private:
    IOServicePool m_ioServicePool;
    ip::tcp::acceptor m_acceptor;
    signal_set m_signals;
    ssl::context m_sslContext;

}; // Server class

#undef CHECK_FOR_ERROR

#define SET_SEVERITY_FILTER(svrt) \
    logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::svrt);

void setLoggerSeverity(const string& loggerSeverity,
                       const po::options_description& options)
{
    if ("trace" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(trace)
    }
    else if ("debug" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(debug)
    }
    else if ("info" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(info)
    }
    else if ("warning" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(warning)
    }
    else if ("error" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(error)
    }
    else if ("fatal" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(fatal)
    }
    else
    {
        cerr << "Error: Invalid logger severity: " << loggerSeverity << endl << endl;
        cerr << options << endl;
        exit(1);
    }
}

#undef SET_SEVERITY_FILTER

void readProgramOptions(int argc, char* argv[], ProgramOptions& options)
{
    string configFileName;
    string loggerSeverity;

    po::options_description genericOptions("Generic options");
    genericOptions.add_options()
        ("help,h", "Produce help message.")
        ("config,c", po::value<string>(&configFileName),
         "Name of a file of a configuration.");

    po::options_description configOptions("Configuration");
    configOptions.add_options()
        ("port,p", po::value<unsigned>(&options.port), "Port on which the server listens.")
        ("threads_count,t", po::value<unsigned>(&options.threadsCount)->default_value(0),
         "Number of server threads. 0 for to use hardware threads count.")
        ("private_key_file,r", po::value<string>(&options.privateKeyFile)->default_value("private_key.pem"),
         "Server private key file name.")
        ("certificate_file,e", po::value<string>(&options.certificateFile)->default_value("certificate.pem"),
         "Server certificate file name.")
        ("log_severity,l", po::value<string>(&loggerSeverity)->default_value("info"),
         "Minimum severity of the log messages: [trace, debug, info, warning, error, fatal]");

    po::options_description commandLineOptions("Allowed options");
    commandLineOptions.add(genericOptions).add(configOptions);

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, commandLineOptions), vm);
    po::notify(vm);

    if (vm.count("config"))
    {
        ifstream configFile(configFileName);
        if (!configFile)
        {
            cerr << "Error: Can not open config file: " << configFileName << endl;
            exit(1);
        }
        else
        {
            po::store(po::parse_config_file(configFile, configOptions), vm);
            po::notify(vm);
        }
    }

    if (vm.count("help"))
    {
        cout << commandLineOptions << endl;
        exit(1);
    }

    if (0 == options.threadsCount)
    {
        options.threadsCount = thread::hardware_concurrency();
    }

    if (!vm.count("port"))
    {
        cerr << "Error: Must specify port on which the server listens!" << endl << endl;
        cerr << commandLineOptions << endl;
        exit(1);
    }

    setLoggerSeverity(loggerSeverity, commandLineOptions);

    BOOST_LOG_TRIVIAL(info) << "Configuration:";
    BOOST_LOG_TRIVIAL(info) << "Listening port: " << options.port;
    BOOST_LOG_TRIVIAL(info) << "Worker threads count: " << options.threadsCount;
    BOOST_LOG_TRIVIAL(info) << "Private key file name: " << options.privateKeyFile;
    BOOST_LOG_TRIVIAL(info) << "Certificate file name: " << options.certificateFile;
}

int main(int argc, char* argv[])
{
    try
    {
        ProgramOptions programOptions;
        readProgramOptions(argc, argv, programOptions);

        Server server(programOptions);
        server.run();
    }
    catch (const exception& e)
    {
        BOOST_LOG_TRIVIAL(fatal) << e.what();;
    }
    catch (...)
    {
        BOOST_LOG_TRIVIAL(fatal) << "Unknown error!!!" << endl;
    }

    return 0;
}

客户端代码在这里:

#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <atomic>
#include <cstdint>

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>

#include <boost/program_options.hpp>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>

#include <io_service_pool.hpp>
#include <speed_limiter.hpp>

using namespace std;
using namespace boost::asio;
using namespace boost::system;

namespace po = boost::program_options;
namespace logging = boost::log;

#define CHECK_FOR_ERROR(err) \
    if (err) \
    { \
        BOOST_LOG_TRIVIAL(error) << err.message() << endl; \
        return; \
    }

namespace std
{

ostream& operator<<(ostream& ostr, const boost::asio::streambuf& buffer)
{
    for (size_t i = 0; i < buffer.size(); ++i)
    {
        ostr << hex << (unsigned short) buffer_cast<const char*>(buffer.data())[i] << " ";
    }
    return ostr;
}

} // std namespace

string generateRandomData(size_t size)
{
     static random_device randomDevice;
     static default_random_engine randomEngine(randomDevice());
     static uniform_int_distribution<unsigned char> randomByte(1, 255);

     string data;
     data.reserve(size);

     for (size_t i = 0; i < size - 1; ++i)
     {
         data += randomByte(randomEngine);
     }
     data += '\0';

     return data;
}

struct Statistics
{
    atomic<uint32_t> connectionsEstablished;
    atomic<uint32_t> requestsSent;
    atomic<uint32_t> responsesReceived;
    atomic<uint64_t> dataSent;
    atomic<uint64_t> dataReceived;

}; // Statistics struct

Statistics g_statistics;

void printStatistics()
{
    BOOST_LOG_TRIVIAL(info) << "Statistics:";
    BOOST_LOG_TRIVIAL(info) << "Connections established: " << g_statistics.connectionsEstablished;
    BOOST_LOG_TRIVIAL(info) << "Requests sent: " << g_statistics.requestsSent;
    BOOST_LOG_TRIVIAL(info) << "Responses received: " << g_statistics.requestsSent;
    BOOST_LOG_TRIVIAL(info) << "Data sent: " << g_statistics.dataSent << " bytes.";
    BOOST_LOG_TRIVIAL(info) << "Data received: " << g_statistics.dataReceived << " bytes.";
}

class TCPConnection : public enable_shared_from_this<TCPConnection>
{
public:
    using SSLSocket = ssl::stream<ip::tcp::socket>;
    using Ptr = shared_ptr<TCPConnection>;

    static Ptr create(io_service& ioService, ssl::context& sslContext)
    {
        return TCPConnection::Ptr(new TCPConnection(ioService, sslContext));
    }

    SSLSocket::lowest_layer_type& socket()
    {
        return m_socket.lowest_layer();
    }

    void setSendData(const std::string& data)
    {
        ostream stream(&m_writeBuffer);
        stream.write(data.data(), data.size());
    }

    void startConnect(ip::tcp::resolver::iterator endpointIter)
    {
        if (endpointIter != ip::tcp::resolver::iterator())
        {
            BOOST_LOG_TRIVIAL(debug) << "Trying " << endpointIter->endpoint() << " ...";

            auto self(shared_from_this());

            socket().async_connect(endpointIter->endpoint(), [self, endpointIter](const error_code& err) mutable
            {
                if (!err)
                {
                    ip::tcp::no_delay noDelay(true);
                    self->socket().set_option(noDelay);

                    auto endpoint = endpointIter->endpoint();

                    BOOST_LOG_TRIVIAL(debug) << "Connected to " << endpoint;

                    g_statistics.connectionsEstablished++;

                    self->m_socket.async_handshake(ssl::stream_base::client, [self, endpoint](const error_code& err)
                    {
                        CHECK_FOR_ERROR(err)

                        BOOST_LOG_TRIVIAL(debug) << "Handshake with " << endpoint << " succeeded.";

                        async_write(self->m_socket, self->m_writeBuffer,
                                    [self, endpoint](const error_code& err, size_t bytesTransfered)
                        {
                            CHECK_FOR_ERROR(err)
                            BOOST_LOG_TRIVIAL(debug) << "Sent " << bytesTransfered << " bytes to " << endpoint;

                            g_statistics.requestsSent++;
                            g_statistics.dataSent += bytesTransfered;

                            async_read_until(self->m_socket, self->m_readBuffer, '\0',
                                       [self, endpoint](const error_code& err, size_t bytesTransfered)
                            {
                                CHECK_FOR_ERROR(err)
                                BOOST_LOG_TRIVIAL(debug) << "Received " << bytesTransfered
                                                         << " bytes from " << endpoint;
                                BOOST_LOG_TRIVIAL(trace) << "Data: " << self->m_readBuffer;

                                g_statistics.responsesReceived++;
                                g_statistics.dataReceived += bytesTransfered;
                            });
                        });
                    });
                }
                else
                {
                    BOOST_LOG_TRIVIAL(error) << err.message();
                    self->startConnect(++endpointIter);
                }
            });
        }
        else
        {
            BOOST_LOG_TRIVIAL(warning) << "There are no more endpoints to try. Shut down the client.";
            socket().close();
        }
    }

private:
    TCPConnection(io_service& ioService, ssl::context& sslContext)
        : m_socket(ioService, sslContext)
    {
    }

private:
    SSLSocket m_socket;
    boost::asio::streambuf m_writeBuffer;
    boost::asio::streambuf m_readBuffer;

}; // TCPConnection class

struct ProgramOptions
{
    string serverIP;
    string privateKeyFile;
    string certificateFile;
    unsigned serverPort        = 0;
    unsigned requestSize       = 0;
    unsigned threadsCount      = 0;
    unsigned totalRequests     = 0;
    unsigned requestsPerSecond = 0;

}; // ProgramOptions struct

class Client
{
public:
    Client(const ProgramOptions& options)
        : m_requestSize(options.requestSize)
        , m_totalRequests(options.totalRequests)
        , m_requestsPerSecond(options.requestsPerSecond)
        , m_ioServicePool(options.threadsCount)
        , m_resolver(m_ioServicePool.getIOService())
        , m_sslContext(ssl::context::sslv23)

    {
        ip::tcp::resolver::query query(options.serverIP, to_string(options.serverPort));

        m_resolver.async_resolve(query, [this](const error_code& err, ip::tcp::resolver::iterator endpointIter)
        {
            CHECK_FOR_ERROR(err)

            m_dispatcherThread = thread([this, endpointIter]()
            {
                SpeedLimiter<> speedLimiter(m_requestsPerSecond);

                for (unsigned i = 0; i < m_totalRequests; ++i)
                {
                    auto conn = TCPConnection::create(m_ioServicePool.getIOService(), m_sslContext);
                    conn->setSendData(generateRandomData(m_requestSize));

                    conn->startConnect(endpointIter);

                    if (m_requestsPerSecond != 0)
                        speedLimiter.limit();
                }

                this_thread::sleep_for(chrono::seconds(1));
                m_ioServicePool.stop();
            });
        });

        m_sslContext.set_verify_mode(ssl::verify_peer);
        m_sslContext.use_private_key_file(options.privateKeyFile, ssl::context::pem);
        m_sslContext.use_certificate_file(options.certificateFile, ssl::context::pem);
    }

    ~Client()
    {
        m_dispatcherThread.join();
    }

    void run()
    {
        BOOST_LOG_TRIVIAL(info) << "Client started!";
        m_ioServicePool.run();
    }

private:
    unsigned m_requestSize;
    unsigned m_totalRequests;
    unsigned m_requestsPerSecond;

    IOServicePool m_ioServicePool;
    ip::tcp::resolver m_resolver;
    thread m_dispatcherThread;
    ssl::context m_sslContext;

}; // Client class

#define SET_SEVERITY_FILTER(svrt) \
    logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::svrt);

void setLoggerSeverity(const string& loggerSeverity,
                       const po::options_description& options)
{
    if ("trace" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(trace)
    }
    else if ("debug" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(debug)
    }
    else if ("info" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(info)
    }
    else if ("warning" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(warning)
    }
    else if ("error" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(error)
    }
    else if ("fatal" == loggerSeverity)
    {
        SET_SEVERITY_FILTER(fatal)
    }
    else
    {
        cerr << "Error: Invalid logger severity: " << loggerSeverity << endl << endl;
        cerr << options << endl;
        exit(1);
    }
}

#undef SET_SEVERITY_FILTER

void readProgramOptions(int argc, char* argv[], ProgramOptions& options)
{
    string configFileName;
    string loggerSeverity;

    po::options_description genericOptions("Generic options");
    genericOptions.add_options()
        ("help,h", "Produce help message.")
        ("config,c", po::value<string>(&configFileName),
         "Name of a file of a configuration.");

    po::options_description configOptions("Configuration");
    configOptions.add_options()
        ("ip,i", po::value<string>(&options.serverIP), "IP address of the server.")
        ("port,p", po::value<unsigned>(&options.serverPort), "Port number of the server.")
        ("threads_count,t", po::value<unsigned>(&options.threadsCount)->default_value(0),
         "Number of client threads. 0 for to use hardware threads count.")
        ("private_key_file,r", po::value<string>(&options.privateKeyFile)->default_value("private_key.pem"),
         "Client private key file name.")
        ("certificate_file,e", po::value<string>(&options.certificateFile)->default_value("certificate.pem"),
         "Client certificate file name.")
        ("request_size,m", po::value(&options.requestSize), "The size of the request in bytes.")
        ("total_requests,t", po::value(&options.totalRequests), "The total number of requests to be send.")
        ("requests_per_second,s", po::value(&options.requestsPerSecond)->default_value(0),
         "Speed in which requests are send. 0 for unlimited speed.")
        ("log_severity,l", po::value<string>(&loggerSeverity)->default_value("info"),
         "Minimum severity of the log messages: [trace, debug, info, warning, error, fatal]");

    po::options_description commandLineOptions("Allowed options");
    commandLineOptions.add(genericOptions).add(configOptions);

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, commandLineOptions), vm);
    po::notify(vm);

    if (vm.count("config"))
    {
        ifstream configFile(configFileName);
        if (!configFile)
        {
            cerr << "Error: Can not open config file: " << configFileName << endl;
            exit(1);
        }
        else
        {
            po::store(po::parse_config_file(configFile, configOptions), vm);
            po::notify(vm);
        }
    }

    if (vm.count("help"))
    {
        cout << commandLineOptions << endl;
        exit(1);
    }

    if (0 == options.threadsCount)
    {
        options.threadsCount = thread::hardware_concurrency();
    }

    if (!vm.count("ip"))
    {
        cerr << "Error: Must specify the IP address of the server!" << endl << endl;
        cerr << commandLineOptions << endl;
        exit(1);
    }

    if (!vm.count("port"))
    {
        cerr << "Error: Must specify port on which to connect!" << endl << endl;
        cerr << commandLineOptions << endl;
        exit(1);
    }

    if (!vm.count("request_size"))
    {
        cerr << "Error: Must specify bytes size of the request!" << endl << endl;
        cerr << commandLineOptions << endl;
        exit(1);
    }

    setLoggerSeverity(loggerSeverity, commandLineOptions);

    BOOST_LOG_TRIVIAL(info) << "Configuration:";
    BOOST_LOG_TRIVIAL(info) << "Server IP: " << options.serverIP;
    BOOST_LOG_TRIVIAL(info) << "Server port: " << options.serverPort;
    BOOST_LOG_TRIVIAL(info) << "Threads count: " << options.threadsCount;
    BOOST_LOG_TRIVIAL(info) << "Private key file name: " << options.privateKeyFile;
    BOOST_LOG_TRIVIAL(info) << "Certificate file name: " << options.certificateFile;
    BOOST_LOG_TRIVIAL(info) << "Request size: " << options.requestSize;
    BOOST_LOG_TRIVIAL(info) << "Total requests: " << options.totalRequests;
    BOOST_LOG_TRIVIAL(info) << "Requests per second: "
                            << (options.requestsPerSecond == 0 ? "unlimited" : to_string(options.requestsPerSecond));
}

int main(int argc, char* argv[])
{
    try
    {
        ProgramOptions programOptions;
        readProgramOptions(argc, argv, programOptions);

        Client client(programOptions);
        client.run();

        printStatistics();
    }
    catch (const exception& e)
    {
        BOOST_LOG_TRIVIAL(fatal) << e.what();;
    }
    catch (...)
    {
        BOOST_LOG_TRIVIAL(fatal) << "Unknown error!!!" << endl;
    }

    return 0;
}

use_certificate_file()use_private_key_file()允许您向对等方提供公共密钥并解密对等方返回的内容,但是它们不处理验证。 您应该使用add_certificate_authority()add_verify_path()load_verify_file()set_default_verify_paths()set_verify_callback()一个(或多个set_verify_callback()来配置信任验证。 看起来load_verify_file()可能是您想要的那个。

您似乎误以为私钥用于验证对等证书。 事实并非如此-密钥不用于验证签名,通常客户端和服务器私钥将不同。 CA证书用于验证对等证书。 在您的情况下,因为您使用的是自签名证书,所以CA证书和对等证书是相同的。 双方需要加载对方的证书进行验证。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM