【发布时间】:2022-06-30 23:29:23
【问题描述】:
我正在构建一个 EAP-TLS 身份验证客户端 (802.1X EAPOL)。到目前为止的要求只是 EAP-TLS。我正在使用 FreeRadius 服务器进行测试,它使用的是 TLS 1.1,所以这是我正在开发的传输版本。
因为这个请求者使用的是自定义的网络堆栈,并且在小型嵌入式设备上,我不能使用 OpenSSL 库,因为它们将所有握手作为黑盒套接字级别进行通信。此外,我发现的所有请求者都包含与 AAA 和 Authenticator 紧密交织的代码。我没有那么多空间来添加所有源(除了使支持更加困难)
不管怎样,一边学习一边自己动手学习是件好事。
所以,当我深入研究时,我看到的东西与 RFC 不一致或根本没有定义。
在向 WPA-Supplicant 邮寄有关尝试“自己动手”的问题之前,我首先想礼貌地问一个简单的问题:“这是提出技术问题的好地方,还是有其他资源”。我被礼貌地忽略了。所以我在这里发帖。
参考RFC 3579、3748、4346、5216等,我对服务器进行了MD5质询认证。成功理解 EAP、以太网数据包、片段等。
在 TLS 上,我已成功接收、组装和解析 TLS Server Hello 握手。 (RFC 5216 仅定义了 EAP 上的 TLS 标头,而 RFC 4346 解释了完整的 TLS 握手,但 EAP 使用了其中的一个子集。)由于我可以访问测试服务器证书和密钥,因此我还验证了使用公钥,它用私钥正确解密。
现在我正在尝试逐步构建完整的客户端握手,向消息中添加块。并找到我无法解决的问题。
下面,我指的是 RFC 4346 以获取以下 TLS 1.1 消息。
在第 4.3 节中,向量是用特定的“表示语言”定义的。使用 [] 表示固定的已知长度,使用 <..> 表示必须包含指示大小的前导值的变量长度。
第 7.4.7 节定义了客户端密钥交换。就我而言,它只是一个 RSA,因此是一个“EncryptedPreMasterSecret”。 7.4.7.1节定义了RSA的EncryptedPreMasterSecret,即版本号和随机数,共48个字节。
该定义并未声明这是一个可变向量。然而,如果来自 FreeRadius 的调试信息没有长度为两字节的主机顺序值,则它会拒绝它。
(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 似乎并不介意它是否丢失。
通过添加两个字节长度,我克服了这个失败。但是,我不喜欢它不符合我阅读的规范。
这是在我遗漏的其他地方描述的吗?
所以我似乎已经通过了 PremasterSecret,并继续处理证书验证消息。至于它,第 7.4.8 节定义了包含 MD5 和 SHA 哈希的证书验证,请参阅第 7.4.3 节。 7.4.3 中的定义定义了“签名”是什么,并没有声称这是一个变量向量。
事实上,第 7.4.3 节非常清楚地表明它是一个已知长度向量(即使用固定长度 [16] 和 [20])。然而,Wireshark 也需要一个两字节的标头,如果不存在则报告错误。
所以我把它加了两个字节头,Wireshark 很高兴。
但这仍然不符合规范。已知的最大长度为 36 字节,适合一个 8 位数字。因此,要求两个字节违反了 4.3 节中的规范:
The length will be in the form of a number consuming as many bytes as required to hold the vector’s specified maximum (ceiling) length.
但是,即使进行了更改,服务器仍在抱怨。
(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
服务器说“decrypt_error”。此验证消息是否应该加密?规范没有这么说。 Grepping服务器源,我无法在任何地方找到该短信。它被隐藏得很好,很难找到拒绝它的函数。
如果它应该被加密,使用什么密钥?客户端私钥还是服务器公钥?
再说一次,这是否在我遗漏的其他地方进行了描述?它没有在两个方面遵循规范(使用可变长度,两个字节就足够了)。
在第 7.4.9 节中,完成的消息是使用包含“[0..11]”的表示语言定义的,该描述在第 4 节的任何地方都没有定义。它是否是一个错字,意味着是一个可变长度向量 ?或者这里的 [0..11] 是什么意思?
下一个主要问题:
我是不是太难了?
是否有 OpenSSL 调用会简单地接受重新组装的 TLS 握手,并创建客户端握手回复,并将其填充到提供的缓冲区中?同样,因为嵌入式设备上的请求者客户端使用它自己的网络堆栈,所以我不能使用 OpenSSL 的内部套接字调用进行握手。
OpenSSL 文档在许多领域都缺乏,如果存在这样的 API,我也没有偶然发现它。
感谢您的任何回答和建议。
-斯科特
【问题讨论】:
标签: openssl freeradius tls1.1