如何获取通信对等端的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
相关产品推荐
相关产品推荐

