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

如何获取通信对等端的OpenSSL版本以适配SSL_shutdown逻辑?

区分OpenSSL版本并适配Shutdown逻辑的解决方案

一、区分发送端OpenSSL版本的可行方法

由于SSL->client_version无法区分(大概率是双方协商使用了相同的TLS版本,比如TLS 1.2),可以通过解析TLS握手包的扩展字段来判断:

1. 检查ClientHello中的psk_key_exchange_modes扩展

OpenSSL 3.0及以上版本会在ClientHello中添加psk_key_exchange_modes扩展(扩展类型0x002D),而OpenSSL 1.0.2不支持该扩展。可以通过OpenSSL提供的SSL_get0_client_hello接口获取ClientHello数据并解析:

#include <openssl/ssl.h>
#include <arpa/inet.h>

int is_sender_openssl3(SSL *ssl) {
    const unsigned char *ch_data;
    size_t ch_len;
    if (SSL_get0_client_hello(ssl, &ch_data, &ch_len) != 1) {
        return 0; // 握手未完成或获取失败,默认按旧版本处理
    }

    // 跳过ClientHello固定头部,直接定位到扩展区域
    const unsigned char *p = ch_data + 43;
    uint16_t total_ext_len = ntohs(*(uint16_t *)p);
    p += 2;

    while (total_ext_len > 0) {
        if (p + 4 > ch_data + ch_len) break; // 防止越界

        uint16_t ext_type = ntohs(*(uint16_t *)p);
        uint16_t ext_data_len = ntohs(*(uint16_t *)(p + 2));

        if (ext_type == 0x002D) { // 匹配psk_key_exchange_modes扩展
            return 1;
        }

        size_t ext_total_size = 4 + ext_data_len;
        p += ext_total_size;
        total_ext_len -= ext_total_size;
    }
    return 0;
}

2. 备选方案:检查协商后的密码套件

OpenSSL 3.0支持部分OpenSSL 1.0.2不支持的现代密码套件(如TLS_AES_256_GCM_SHA384),如果双方协商使用了这类套件,可直接判定为OpenSSL 3.0发送端:

#include <string.h>

int is_sender_openssl3_by_cipher(SSL *ssl) {
    const char *cipher = SSL_get_cipher(ssl);
    if (cipher == NULL) return 0;
    // 检查是否为3.0新增的密码套件
    return strstr(cipher, "AES-GCM-SHA384") != NULL || strstr(cipher, "CHACHA20-POLY1305") != NULL;
}

注意:该方案仅适用于双方协商使用现代套件的场景,若发送端强制使用旧套件则失效。

二、适配不同版本的Shutdown逻辑

根据判定结果分支处理资源释放与shutdown顺序:

// 假设已通过上述方法获取is_openssl3标识
SSL *ssl = ...; // 已建立的SSL连接
SSL_CTX *ctx = ...; // 对应的SSL上下文

if (is_sender_openssl3(ssl)) {
    // OpenSSL 3.0发送端:先执行shutdown再释放资源
    SSL_shutdown(ssl);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
} else {
    // OpenSSL 1.0.2发送端:沿用旧代码逻辑
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    SSL_shutdown(ssl);
}

三、关键注意事项

  • 必须在TLS握手完成后调用版本判定函数,否则无法获取完整的ClientHello数据。
  • 对于OpenSSL 1.0.2发送端,SSL_free后调用SSL_shutdown的行为依赖旧版本的内存管理逻辑,需确保测试环境与生产环境的OpenSSL 1.0.2版本一致。
  • 若发送端是服务端(而非客户端),则需解析ServerHello的扩展字段,逻辑类似,仅需将SSL_get0_client_hello替换为SSL_get0_server_hello。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 02:37:48