如何重用 OpenSSL 上下文以避免 BIO 及其自身的重新分配?

How to reuse OpenSSL context to avoid reallocations of BIO and itself?

我想为新连接的客户端重置和使用之前断开连接的客户端的 SSL 上下文,避免重新分配。

项目中使用 OpenSSL 只是为了加密和 TLS 协议支持,网络是手动控制的。客户端 class 有一个指向加密后端的指针,如下所示:

class Security
{
    SSL* ctx;
    BIO* R;
    BIO* W;

    int status(int n) const;

public:
    Security();
    ~Security();
    bool init(SSL_CTX* config);
    // other stuff...
};

客户端每次连接都会调用init方法,这里我想重置上下文而不重新分配:

bool Security::init(SSL_CTX* config)
{
    if (!R)
    {
        R = BIO_new(BIO_s_mem());
        if (!R)
            return false;
    }
    else BIO_reset(R);

    if (!W)
    {
        W = BIO_new(BIO_s_mem());
        if (!W)
            return false;
    }
    else BIO_reset(W);
    
    if (!ctx)
    {
        ctx = SSL_new(config);
        if (!ctx)
            return false;
    }
    else SSL_clear(ctx);

    SSL_set_bio(ctx, R, W);
    SSL_set_accept_state(ctx);

    return true;
}

SSL_CTX 在初始化时接收下一个选项:

// Force to use TLS 1.3 only
SSL_CTX_set_options(config,
            | SSL_OP_ALL
            | SSL_OP_NO_SSLv2
            | SSL_OP_NO_SSLv3
            | SSL_OP_NO_TLSv1
            | SSL_OP_NO_TLSv1_1
            | SSL_OP_NO_TLSv1_2
            | SSL_OP_NO_TICKET
            | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);

这种方式只有第一个连接是好的。它关闭后,下一个将尝试重用此安全上下文——由于协议错误,它将被丢弃,因为前一个会话的配置仍然存在。 所以 SSL_clear 没有像我预期的那样工作,并且 SSL_free/SSL_new 不仅会导致 SSL 上下文的重新分配,还会导致两个 BIO 的重新分配。当服务器在高负载下工作时,这些重新分配是非常不需要的。 如何完全重置 SSL 上下文?

您可能找不到该问题的答案,因为即使手册也无法推荐重新分配的替代方案。您可能需要考虑使用池内存进行分配,尽管这是一个单独的问题和答案。以下是手册页的相关警告:

SSL_clear() resets the SSL object to allow for another connection. The reset operation however keeps several settings of the last sessions (some of these settings were made automatically during the last handshake). It only makes sense for a new connection with the exact same peer that shares these settings, and may fail if that peer changes its settings between connections. Use the sequence SSL_get_session(3); SSL_new(3); SSL_set_session(3); SSL_free(3) instead to avoid such failures (or simply SSL_free(3); SSL_new(3) if session reuse is not desired).

OpenSSL manpage online