使用OpenSSL库(C语言)如何在psk_server_cb阶段获取选定加密套件?
获取PSK服务器回调中的选定加密套件
我之前也碰到过一模一样的问题——在psk_server_cb阶段需要拿到加密套件来生成PSK,但SSL_get_current_cipher()因为会话还没完全建立总是返回NULL。下面是两种可行的解决方案,按推荐程度排序:
方法一:利用握手回调+SSL ex_data存储(推荐,兼容性好)
这个方法的核心是在**握手流程中更早的阶段(加密套件已选定但PSK回调未触发时)**捕获加密套件信息,然后存储到SSL对象的扩展数据中,供PSK回调使用:
注册SSL ex_data索引:
首先为SSL对象创建一个专属的扩展数据索引,用来存储加密套件指针:static int ssl_cipher_exdata_idx = -1; // 在程序初始化时调用一次 void init_exdata_index() { ssl_cipher_exdata_idx = SSL_get_ex_new_index(0, "selected_cipher", NULL, NULL, NULL); if (ssl_cipher_exdata_idx == -1) { // 处理索引注册失败的错误逻辑 } }设置握手回调函数:
注册一个握手回调,当握手进入SSL_ST_ACCEPT状态时,加密套件已经选定,此时可以安全获取并存储:int handshake_callback(SSL *ssl, int where, int ret) { if ((where & SSL_ST_ACCEPT) && ret == 1) { const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); if (cipher != NULL) { SSL_set_ex_data(ssl, ssl_cipher_exdata_idx, (void*)cipher); } } return ret; } // 在创建SSL_CTX时绑定回调 SSL_CTX_set_handshake_callback(ctx, handshake_callback);在psk_server_cb中获取加密套件:
现在在PSK回调里,直接从ex_data中取出之前存储的加密套件:unsigned int psk_server_cb(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { const SSL_CIPHER *selected_cipher = SSL_get_ex_data(ssl, ssl_cipher_exdata_idx); if (selected_cipher != NULL) { const char *cipher_name = SSL_CIPHER_get_name(selected_cipher); // 在这里使用cipher_name生成对应的PSK // ... } // 处理PSK生成和身份返回的逻辑 // ... }
方法二:直接访问SSL内部结构(不推荐,兼容性差)
如果你的OpenSSL版本固定(比如1.1.0或某一特定版本),可以直接访问SSL对象的内部字段来获取选定的加密套件,但这种方法会因为OpenSSL版本更新而失效,仅作为应急方案:
// 仅适用于特定OpenSSL版本,示例为1.1.0+ #include <openssl/ssl.h> #include <openssl/ssl3.h> unsigned int psk_server_cb(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { #ifdef OPENSSL_VERSION_NUMBER >= 0x10100000L const SSL_CIPHER *cipher = ssl->s3->tmp.new_cipher; #else // 旧版本可能需要访问不同的字段,比如ssl->session->cipher const SSL_CIPHER *cipher = ssl->session->cipher; #endif if (cipher != NULL) { // 使用加密套件生成PSK } // ... }
注意:这种方法完全依赖OpenSSL的内部实现,升级库后大概率会出现崩溃或逻辑错误,所以优先选择方法一。
关键说明
psk_server_cb触发时,服务器已经完成了加密套件的选定(从ClientHello的候选列表中选出),只是会话还没完成握手,所以SSL_get_current_cipher()还未被初始化,但握手回调的SSL_ST_ACCEPT阶段已经可以拿到这个信息。- 确保ex_data索引只初始化一次,避免重复注册导致错误。
内容的提问来源于stack exchange,提问作者Tommy
相关产品推荐
相关产品推荐

