EAPOL 802.1X下EAP-TLS客户端自定义实现TLS握手问题咨询
项目背景
- 开发目标:实现适配802.1X EAPOL的EAP-TLS认证客户端,当前版本仅支持EAP-TLS能力,对接运行TLS 1.1版本的FreeRadius服务器开展测试,客户端传输层适配版本为TLS 1.1。
- 自研原因:该supplicant运行在资源受限的小型嵌入式设备上,采用自定义网络栈:
- OpenSSL将完整TLS握手流程封装为套接字层面的黑盒通信逻辑,无法适配自定义网络栈场景
- 现有开源supplicant实现均与AAA、认证器模块深度耦合,代码体积超出嵌入式设备存储空间限制,同时会提升后续维护成本
因此最终选择自主实现EAP-TLS全流程。
- 当前进度:开发过程参考RFC 3579、3748、4346、5216等标准文档,已完成与服务器的MD5挑战认证流程,掌握EAP报文封装、以太网帧处理、EAP分片重组等逻辑;进入TLS流程开发阶段后,已完成TLS Server Hello握手报文的接收、组装与解析(RFC 5216仅定义EAP层之上的TLS报头,RFC 4346描述完整TLS握手流程,EAP-TLS仅使用TLS流程子集),同时借助测试服务器的证书与密钥,验证了公钥加密预主密钥、私钥解密流程可正常运行。
握手报文开发遇到的规范对齐问题
当前逐块构建客户端侧完整TLS握手报文时,遇到多处与RFC 4346(TLS 1.1核心规范)描述不一致的问题,具体如下:
1. Client Key Exchange报文长度字段冲突
RFC 4346第4.3节定义的协议表示语言规则明确:固定长度向量用[]标注,可变长度向量用<..>标注,且可变长度向量前必须携带对应长度的前缀字段。第7.4.7节定义RSA密钥交换场景下Client Key Exchange报文载荷为EncryptedPreMasterSecret,第7.4.7.1节明确该载荷为版本号加随机数,总长度固定48字节,未标注为可变向量。
实际测试现象:
- FreeRadius调试日志显示,若报文前不携带2字节长度字段,服务器会直接拒绝报文,报错如下:
(27) eap_tls: TLS-Client-Cert-X509v3-Basic-Constraints += "CA:FALSE" (27) eap_tls: TLS_accept: SSLv3/TLS read client certificate (27) eap_tls: <<< recv TLS 1.0 Handshake [length 0104], ClientKeyExchange (27) eap_tls: >>> send TLS 1.0 Alert [length 0002], fatal decode_error (27) eap_tls: ERROR: TLS Alert write:fatal:decode error tls: TLS_accept: Error in error (27) eap_tls: ERROR: Failed in __FUNCTION__ (SSL_read): error:1419F09F:SSL routines:tls_process_cke_rsa:length mismatch (27) eap_tls: ERROR: System call (I/O) error (-1) (27) eap_tls: ERROR: TLS receive handshake failed during operation (27) eap_tls: ERROR: [eaptls process] = fail
- Wireshark对缺失该2字节长度字段的报文不会报解析错误,手动添加2字节长度字段后可绕过FreeRadius的该报错。
该处理与规范描述不符,需确认该长度字段的要求是否定义在未查阅到的其他文档中。
2. Certificate Verify报文结构与加密规则疑问
处理Certificate Verify报文时,RFC 4346第7.4.8节定义该报文包含MD5和SHA哈希值,引用第7.4.3节的Signature结构定义;第7.4.3节明确Signature为固定长度向量,其中MD5哈希长度标注为[16]、SHA哈希长度标注为[20],未标注为可变向量。
实际测试现象:
- Wireshark要求签名字段前必须携带2字节长度头,否则报解析错误,添加该字段后Wireshark可正常解析。该逻辑与规范存在冲突:签名字段最大长度仅36字节,1字节即可承载所有合法长度值,按照第4.3节的表示语言规则,要求2字节长度头本身就不符合规范定义。
- 即使添加2字节长度头,服务器仍然返回报错,日志如下:
(13) eap_tls: TLS-Client-Cert-X509v3-Basic-Constraints += "CA:FALSE" (13) eap_tls: TLS_accept: SSLv3/TLS read client certificate (13) eap_tls: <<< recv TLS 1.0 Handshake [length 0106], ClientKeyExchange (13) eap_tls: TLS_accept: SSLv3/TLS read client key exchange (13) eap_tls: <<< recv TLS 1.0 Handshake [length 002a], CertificateVerify (13) eap_tls: >>> send TLS 1.0 Alert [length 0002], fatal decrypt_error (13) eap_tls: ERROR: TLS Alert write:fatal:decrypt error tls: TLS_accept: Error in error (13) eap_tls: ERROR: Failed in __FUNCTION__ (SSL_read) (13) eap_tls: ERROR: error:04091077:rsa routines:int_rsa_verify:wrong signature length (13) eap_tls: ERROR: error:1417B07B:SSL routines:tls_process_cert_verify:bad signature
需确认三个点:一是Certificate Verify报文是否需要加密,现有规范文本未提及该要求,检索FreeRadius源码也未找到对应报错的触发逻辑;二是如果确实需要加密,加密密钥应使用客户端私钥还是服务器公钥;三是相关要求是否定义在未查阅到的其他文档中。
3. Finished报文表示语言表述含义不明
RFC 4346第7.4.9节定义Finished报文时,表示语言中出现了[0..11]的写法,该写法未在文档第4节的表示语言规则中做任何说明,需确认该表述是否为可变长度向量<0..11>的笔误,以及其实际定义的报文结构。
其他咨询
是否存在可直接输入重组后TLS握手报文、在用户提供的缓冲区中生成客户端握手响应的OpenSSL API,无需依赖OpenSSL内置套接字接口,可适配使用自定义网络栈的嵌入式场景。
内容的提问来源于stack exchange,提问作者SpacemanScott

