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

TLS握手失败:PyOpenSSL与OpenSSL/嵌入式设备通信异常排查

PyOpenSSL与原生OpenSSL/嵌入式设备TLS1.3 PSK通信失败排查与修复

问题场景

需要编写基于pytest的Python测试用例验证Windows PC与嵌入式目标板的TLS通信,先通过原生OpenSSL完成验证:

  • 服务端执行:openssl s_server -accept 49152 -nocert -psk 1a2b3c4d
  • 客户端执行:openssl s_client -port 49152 -psk 1a2b3c4d -tls1_3
    嵌入式设备作为TLS1.3客户端可正常连接该原生OpenSSL服务端,但用PyOpenSSL实现的服务端/客户端,与原生OpenSSL或嵌入式设备通信时均失败:客户端发送Client Hello后,服务端返回致命警报:

Alert Message
Level: Fatal (2)
Description: Illegal Parameter (47)

失败组合包括:

  1. Windows原生OpenSSL服务端 ↔ PyOpenSSL客户端
  2. Windows原生OpenSSL客户端 ↔ PyOpenSSL服务端

使用Python 3.10.2,PyOpenSSL服务端代码如下:

from OpenSSL import SSL
from socket import socket, AF_INET, SOCK_STREAM
from openssl_psk import patch_context

patch_context()

server_addr = '127.0.0.1'
server_port = 49152

psk_value : str = '1a2b3c4d'
PSK_MAP = {b'Client_identity': psk_value}

if __name__ == "__main__":

    def server_callback(conn_2, client_identity):
        return PSK_MAP[client_identity]

    ctx = SSL.Context(SSL.TLS_METHOD)
    ctx.set_options(SSL.OP_NO_TLSv1_1 | SSL.OP_NO_TLSv1)
    ctx.set_verify(SSL.VERIFY_NONE)
    ctx.use_psk_identity_hint('Client_identity')     # seems not to be necessary in server
    ctx.set_psk_server_callback(server_callback)

    sock = socket(AF_INET, SOCK_STREAM)
    conn_1 = SSL.Connection(ctx, sock)
    conn_1.bind((server_addr, server_port))
    ctx.set_cipher_list(b"AES128-GCM-SHA256")
    conn_1.listen(1)

    while True:
        print('\tWaiting for client to connect...\r\n')
        newsocket, fromaddr = conn_1.accept()
        print ('Server accepted a socket-request')
        conn_2 = SSL.Connection(ctx, newsocket)
        conn_2.set_accept_state()
        conn_2.do_handshake()

        # bla bla

问题根源

  1. PSK值格式不匹配:原生OpenSSL的-psk参数接受十六进制字符串,会自动解码为字节流;但代码中直接返回字符串'1a2b3c4d',而非对应的字节值,导致PSK验证失败。
  2. TLS版本配置模糊:SSL.TLS_METHOD默认包含多版本协议,即使禁用了TLS1.0/1.1,仍可能存在协商歧义,需明确指定TLS1.3专用的上下文方法。
  3. 密码套件配置时机错误:在绑定套接字后才调用ctx.set_cipher_list,此时上下文配置已生效,修改不会作用到后续连接。另外,TLS1.3的密码套件命名格式与旧版本不同(需前缀TLS_)。
  4. 参数类型错误:use_psk_identity_hint需传入字节类型参数,代码中传入字符串会导致编码不兼容。

修复后的服务端代码

from OpenSSL import SSL
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
from openssl_psk import patch_context

patch_context()

server_addr = '127.0.0.1'
server_port = 49152

# 将十六进制PSK字符串转换为字节流
psk_value = bytes.fromhex('1a2b3c4d')
PSK_MAP = {b'Client_identity': psk_value}

if __name__ == "__main__":

    def server_callback(conn, client_identity):
        # 增加容错,避免未知身份导致崩溃
        return PSK_MAP.get(client_identity, b'')

    # 明确使用TLS1.3服务器专用上下文
    ctx = SSL.Context(SSL.TLS_SERVER_METHOD)
    # 禁用所有旧版本TLS协议,仅保留TLS1.3
    ctx.set_options(SSL.OP_NO_TLSv1 | SSL.OP_NO_TLSv1_1 | SSL.OP_NO_TLSv1_2)
    ctx.set_verify(SSL.VERIFY_NONE)
    # 传入字节类型的身份提示
    ctx.use_psk_identity_hint(b'Client_identity')
    ctx.set_psk_server_callback(server_callback)
    
    # 在创建套接字前设置TLS1.3兼容的密码套件
    ctx.set_cipher_list(b"TLS_AES_128_GCM_SHA256")

    sock = socket(AF_INET, SOCK_STREAM)
    # 开启地址复用,避免端口占用问题
    sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    conn_1 = SSL.Connection(ctx, sock)
    conn_1.bind((server_addr, server_port))
    conn_1.listen(1)

    while True:
        print('\tWaiting for client to connect...\r\n')
        newsocket, fromaddr = conn_1.accept()
        print(f'Server accepted connection from {fromaddr}')
        conn_2 = SSL.Connection(ctx, newsocket)
        conn_2.set_accept_state()
        try:
            conn_2.do_handshake()
            print("TLS handshake successful!")
            # 后续通信逻辑
        except SSL.Error as e:
            print(f"Handshake failed: {e}")
            conn_2.shutdown()
            conn_2.close()

额外提示

  • 客户端代码需同步修改:使用SSL.TLS_CLIENT_METHOD,将PSK值转为字节,禁用旧协议,配置正确的TLS1.3密码套件。
  • 确保PyOpenSSL依赖的OpenSSL版本与你编译的原生OpenSSL版本一致,版本差异可能导致协议协商失败。
  • 嵌入式设备的PSK配置需与服务端完全匹配:身份标识为Client_identity,PSK值为十六进制1a2b3c4d对应的字节流。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 09:02:06