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

Python 3.11与MicroPython 1.20 TLS通信失败:无共享密码套件

Python 3.11与MicroPython 1.20 TLS通信无共用密码套件问题排查与解决方案

问题背景

我尝试在两台设备间传输文本:一台为Python 3.11服务器,另一台为MicroPython 1.20客户端。两台设备均有独立密钥,服务器持有服务器证书,密钥通过以下命令生成:

openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout server-key.pem -out server-cert.pem

按MicroPython文档要求,我将服务器证书转换为DER格式:

openssl.exe x509 -in server-cert.pem -out server-cert.der -outform DER

MicroPython客户端代码

# main.py -- put your code here!
import usocket as socket
import ussl as ssl

# 服务器IP地址和端口
server_ip = '192.168.178.67'
server_port = 2002
server_address = (server_ip, server_port)
server_ca = "/flash/cert/server-cert-test.der"
server_key = "/flash/cert/server-key.pem"

# 建立与服务器的连接
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(server_address)

# 建立SSL连接
ssl_context = ssl.wrap_socket(client_socket, cert=(server_ca, server_key))

# 发送数据
ssl_context.write("Hallo, Server!".encode('utf-8'))

# 接收并解码响应
response = ssl_context.read(1024)
print("服务器响应:", response.decode('utf-8'))

# 关闭连接
ssl_context.close()
client_socket.close()

Python 3.11服务器代码

from socket import socket
from ssl import wrap_socket

def main():
    server_certfile = "server-cert.pem"
    server_keyfile = "server-key.pem"

    s = socket()
    s.bind(('192.168.178.67', 2002))
    s.listen(5)
    wrap_socket(s.accept()[0], 'server-key.pem', 'server-cert.pem', True)

if __name__ == "__main__":
    main()

报错信息

经Wireshark分析,MicroPython客户端发送Client Hello并支持TLS1.2,但双方无法协商出共用密码套件,报错如下:

Python端报错:

ssl.SSLError: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:992)

MicroPython端报错:

OSError: (-30592, 'MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE')

Wireshark抓包数据

6768    11:49:56,791402 192.168.178.126 192.168.178.67  TCP 60  55778 → 2002 [SYN] Seq=0 Win=6400 Len=0 MSS=800
6769    11:49:56,791478 192.168.178.67  192.168.178.126 TCP 58  2002 → 55778 [SYN, ACK] Seq=0 Ack=1 Win=64800 Len=0 MSS=1460
6770    11:49:56,791810 192.168.178.126 192.168.178.67  TCP 60  55778 → 2002 [ACK] Seq=1 Ack=1 Win=6400 Len=0
6771    11:49:57,118967 192.168.178.126 192.168.178.67  TLSv1.2 176 Client Hello
6772    11:49:57,119175 192.168.178.67  192.168.178.126 TLSv1.2 61  Alert (Level: Fatal, Description: Handshake Failure)
6773    11:49:57,119284 192.168.178.67  192.168.178.126 TCP 54  2002 → 55778 [FIN, ACK] Seq=8 Ack=123 Win=64678 Len=0
6774    11:49:57,119367 192.168.178.126 192.168.178.67  TCP 60  55778 → 2002 [ACK] Seq=123 Ack=9 Win=6392 Len=0

问题询问

我已尝试更换证书和密钥、调整wrap_socket实现方式,但问题仍存在。请问是代码实现有误,还是目前Python与MicroPython无法实现安全通信?求可行实现方案。

补充:TLS握手Client Hello显示的支持密码套件见附图。


可行解决方案

1. 修正客户端SSL配置错误

MicroPython客户端中,ssl.wrap_socket的cert参数用于客户端证书认证,而验证服务器证书应使用ca_certs参数。当前代码错误地将服务器证书和客户端密钥传给了cert,导致配置逻辑混乱。修正后的客户端SSL配置:

# 仅验证服务器证书(单向认证)
ssl_context = ssl.wrap_socket(client_socket, ca_certs=server_ca)

# 如需双向认证(服务器验证客户端身份),需准备客户端专属证书和密钥
# client_cert = "/flash/cert/client-cert.pem"
# client_key = "/flash/cert/client-key.pem"
# ssl_context = ssl.wrap_socket(client_socket, ca_certs=server_ca, cert=(client_cert, client_key))

2. 服务器端显式指定兼容密码套件

Python标准库默认启用的密码套件与MicroPython(基于mbedTLS)支持的套件可能无重叠,需根据Client Hello中的套件列表,在服务器端显式启用双方兼容的套件。修正后的服务器代码:

from socket import socket
import ssl

def main():
    server_certfile = "server-cert.pem"
    server_keyfile = "server-key.pem"

    s = socket()
    s.bind(('192.168.178.67', 2002))
    s.listen(5)
    
    conn, addr = s.accept()
    # 创建TLS服务器上下文,指定兼容协议版本
    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ssl_context.load_cert_chain(certfile=server_certfile, keyfile=server_keyfile)
    # 根据MicroPython支持的套件调整,示例为常见兼容套件
    ssl_context.set_ciphers('AES128-SHA256:ECDHE-RSA-AES128-GCM-SHA256')
    ssl_conn = ssl_context.wrap_socket(conn, server_side=True)
    
    # 处理通信逻辑
    data = ssl_conn.recv(1024)
    print("收到客户端数据:", data.decode('utf-8'))
    ssl_conn.sendall("Hallo, Client!".encode('utf-8'))
    
    ssl_conn.close()
    conn.close()

if __name__ == "__main__":
    main()

3. 确保证书密钥算法兼容

MicroPython的mbedTLS对1024位RSA密钥支持有限(部分环境已禁用),建议重新生成2048位RSA证书:

openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout server-key.pem -out server-cert.pem

4. 匹配Client Hello中的密码套件

查看Wireshark抓包中Client Hello的密码套件列表,将服务器端set_ciphers的参数调整为包含这些套件(注意OpenSSL与mbedTLS的套件名称对应关系,比如mbedTLS的TLS_RSA_WITH_AES_128_CBC_SHA256对应OpenSSL的AES128-SHA256)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 23:34:52