You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

出现错误时,SSL_shutdown与SSL_free的调用时机及场景疑问

OpenSSL中SSL_shutdown的调用时机与错误场景处理

问题背景

OpenSSL官方的TLS服务器示例中存在一段未做完整错误检查的代码(如下),其中不管SSL操作是否成功都调用了SSL_shutdown和SSL_free,现明确两个核心问题:

  1. SSL_shutdown的正确调用时机是什么?
  2. 若SSL_set_fd或SSL_accept出现错误,是否仍需调用SSL_shutdown?

示例代码:

while(1) {
    struct sockaddr_in addr;
    unsigned int len = sizeof(addr);
    SSL *ssl;
    const char reply[] = "test\n";

    int client = accept(sock, (struct sockaddr*)&addr, &len);
    if (client < 0) {
        perror("Unable to accept");
        exit(EXIT_FAILURE);
    }

    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, client);

    if (SSL_accept(ssl) <= 0) {
        ERR_print_errors_fp(stderr);
    } else {
        SSL_write(ssl, reply, strlen(reply));
    }

    SSL_shutdown(ssl);
    SSL_free(ssl);
    close(client);
}

问题解答

1. SSL_shutdown的正确调用时机

SSL_shutdown的作用是优雅关闭已成功建立的TLS会话:它会触发TLS层的双向关闭流程(向对方发送close_notify告警,并等待对方的回应),确保双方都能妥善终止加密会话,避免数据截断或残留的加密上下文资源泄漏。

只有当TLS会话已成功建立(即SSL_accept/SSL_connect返回成功),且完成了所有预期的数据交互时,才需要调用SSL_shutdown来完成优雅关闭。

2. 错误场景下是否需要调用SSL_shutdown

分不同错误场景判断:

  • SSL_new调用失败(ssl为空):此时未创建任何有效的SSL对象,直接跳过所有SSL相关操作,关闭客户端socket即可。
  • SSL_set_fd调用失败:SSL对象已创建,但尚未与客户端socket绑定成功,TLS会话完全未初始化,无需调用SSL_shutdown,直接调用SSL_free释放SSL对象,再关闭socket。
  • SSL_accept调用失败:
    • 如果失败发生在TLS握手完全未建立阶段(比如握手初始步骤就失败,没有任何有效TLS消息交互):无需调用SSL_shutdown,直接释放SSL对象并关闭socket。
    • 如果握手过程中已交换部分TLS消息(比如对方已发送close_notify):可以尝试调用一次SSL_shutdown,但如果调用失败也无需处理——因为SSL_free会自动清理SSL对象的所有资源,SSL_shutdown只是优雅关闭的可选步骤,而非强制要求。

对示例代码的修正建议

示例代码的核心问题是未检查SSL_new的返回值,且无条件调用SSL_shutdown,正确的处理逻辑应补充错误检查:

while(1) {
    struct sockaddr_in addr;
    unsigned int len = sizeof(addr);
    SSL *ssl = NULL;
    const char reply[] = "test\n";

    int client = accept(sock, (struct sockaddr*)&addr, &len);
    if (client < 0) {
        perror("Unable to accept");
        exit(EXIT_FAILURE);
    }

    ssl = SSL_new(ctx);
    if (ssl == NULL) {
        perror("SSL_new failed");
        close(client);
        continue;
    }

    if (SSL_set_fd(ssl, client) != 1) {
        ERR_print_errors_fp(stderr);
        SSL_free(ssl);
        close(client);
        continue;
    }

    int accept_ret = SSL_accept(ssl);
    if (accept_ret <= 0) {
        ERR_print_errors_fp(stderr);
        // 仅在握手部分完成时尝试shutdown,否则直接释放
        if (accept_ret == SSL_ERROR_WANT_READ || accept_ret == SSL_ERROR_WANT_WRITE) {
            (void)SSL_shutdown(ssl);
        }
    } else {
        SSL_write(ssl, reply, strlen(reply));
        // 会话正常建立,调用shutdown优雅关闭
        (void)SSL_shutdown(ssl);
    }

    SSL_free(ssl);
    close(client);
}

内容的提问来源于stack exchange,提问作者spraff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 19:25:26