AIOSMTPD服务器无法配置TLSContext兼容TLS1.1问题排查
问题原因分析
出现NO_PROTOCOLS_AVAILABLE错误的核心原因有三点:
SSL上下文Purpose配置错误
服务器端创建SSL上下文时误用了ssl.Purpose.CLIENT_AUTH——该配置用于客户端验证服务器证书的场景,而SMTP服务器需要使用ssl.Purpose.SERVER_AUTH(服务器向客户端提供身份证书),错误的Purpose会导致上下文默认配置与服务器需求不匹配。错误的Options设置
代码中错误地将PROTOCOL_TLSv1、PROTOCOL_TLSv1_1等常量赋值给context.options。这些是创建SSLContext实例的协议类型标识,并非options的合法位掩码选项(options仅接受OP_*开头的常量,比如OP_NO_SSLv2)。这种错误赋值会破坏SSL上下文的协议支持配置,导致TLS1.1等协议被意外禁用。Python 3.10+默认禁用老旧TLS版本
Python 3.10及以上版本出于安全考虑,默认禁用了TLS1.0和TLS1.1。即使显式设置minimum_version,也需要确保密码套件兼容且未被系统/全局SSL配置进一步限制。
解决方案及修正代码
修正后的服务器代码
from aiosmtpd.controller import Controller from aiosmtpd.smtp import SMTP from aiosmtpd.handlers import Debugging import ssl, signal class CustomController(Controller): def factory(self): # 服务器端必须使用SERVER_AUTH类型的上下文 context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) # 设置兼容TLS1.1的密码套件,保留MEDIUM级别套件(TLS1.1依赖此类套件) context.set_ciphers('HIGH:MEDIUM:!LOW:!DHE:!aNULL') context.set_ecdh_curve("secp384r1") # 仅禁用SSLv2/SSLv3,不要添加PROTOCOL_*到options中 context.options |= ssl.OP_NO_SSLv2 context.options |= ssl.OP_NO_SSLv3 # 明确设置支持的TLS版本范围 context.minimum_version = ssl.TLSVersion.TLSv1_1 context.maximum_version = ssl.TLSVersion.TLSv1_3 base_path = '/etc/letsencrypt/live/smtp.server.com' context.load_cert_chain( '{}/fullchain.pem'.format(base_path), '{}/privkey.pem'.format(base_path) ) return SMTP( handler=self.handler, ident="Welcome.", tls_context=context, ) if __name__ == '__main__': controller = CustomController(Debugging(), hostname="localhost", port=2525) controller.start() print("Daemon started. Waiting for SIGINT or SIGQUIT to quit.") sig = signal.sigwait([signal.SIGINT, signal.SIGQUIT]) print("Quitting SMTP Daemon") controller.stop()
关键修正点说明
- 将
ssl.Purpose.CLIENT_AUTH改为ssl.Purpose.SERVER_AUTH,匹配SMTP服务器的角色定位。 - 删除所有
context.options |= ssl.PROTOCOL_TLSv*的错误代码,仅保留SSLv2/3的禁用配置。 - 调整密码套件,确保包含TLS1.1支持的MEDIUM级套件,同时排除不安全的空套件。
- 若无需兼容TLS1.0,直接将
minimum_version设为ssl.TLSVersion.TLSv1_1,进一步缩小支持范围。
额外注意事项
- 如果系统OpenSSL配置默认禁用了TLS1.1,需修改
/etc/ssl/openssl.cnf(或对应路径),移除MinProtocol中的限制,或添加TLSv1.1到允许列表。 - Python 3.12对老旧TLS版本限制更严格,需确保测试环境的OpenSSL版本支持TLS1.1(OpenSSL 1.0.1及以上版本支持,但部分发行版可能默认禁用)。
内容的提问来源于stack exchange,提问作者Cyril N.
相关产品推荐
相关产品推荐

