【发布时间】:2016-01-27 17:14:48
【问题描述】:
我在 C# 中使用 OpenSSL 时遇到了一个奇怪的问题。
事实:我已经为C# 编写了一个包装器,它工作得很好,它可以连接到其他SSL 服务器,或者接受来自SSL 客户端的连接。我的包装器只使用内存 BIO。每当我将MEM BIO 连接到套接字握手成功的任何类型套接字的输入和输出时,数据传输工作,所以问题不在包装器中。
我用这个包装器制作了两个程序,一个客户端和一个服务器,它们建立了 ssl 会话,当我尝试将数据从服务器发送到客户端(或相反的方式)并且另一端回显它时由于某种原因,发送方的数据流量非常慢(即使在本地环回中最大 20kB/s,如果我尝试以更高的速度发送,例如在 SSL_read() 中抽取更多数据,那么使用 TCP 上的 TLS 会有巨大的延迟,使用 DTLS在 UDP 上,有时会有 75% 的数据包丢失),所以我决定使用包装器对 OpenSSL 进行基准测试,因为某些方法或错误的参数可能会减慢运行速度。
我的想法是在一个程序中初始化两个 SSL 上下文,一个客户端和一个服务器,将它们的 Memory BIO 相互连接(RX-TX TX-RX),然后开始握手。
我就是不能让他们成功握手!
在 Clienthello 之后使用 DTLS1,服务器开始以 4 个数据包(3x256 字节 + 145)响应 Serverhello 和 Cert 数据,但在第一个数据包之后客户端会发出警报:
After writing to CLIENT (packet: 2): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370:
After writing to CLIENT (packet: 3): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370:
After writing to CLIENT (packet: 4): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370:
After writing to CLIENT (packet: 5): 22016:error:14102044:SSL routines:dtls1_read_bytes:internal error:.\ssl\d1_pkt.c:1370:
两个会话之间的数据包流如下:
Client -> 178 -> Server
Server -> 256 -> Client
Server -> 256 -> Client
Server -> 256 -> Client
Server -> 145 -> Client
Client -> 15 -> Server
我已经用Wireshark 分析了这些数据包(在文件转储之后),一切似乎都很好(这个分析不是上面的数据包,而是同样的问题再现):
http://reset.tor.hu/ssl/sima/programom_dtls1.txt
在这之后我得到更多的错误:
After writing to SERVER (packet: 5): 22016:error:141020E5:SSL routines:dtls1_read_bytes:ssl handshake failure:.\ssl\d1_pkt.c:819:
Before writing to SERVER (packet: 6): 22016:error:140FD10F:SSL routines:DTLS1_GET_MESSAGE_FRAGMENT:bad length:.\ssl\d1_both.c:892:
After writing to SERVER (packet: 6): 22016:error:14102417:SSL routines:dtls1_read_bytes:sslv3 alert illegal parameter:.\ssl\d1_pkt.c:1200:SSL alert number 47
22016:error:141020E5:SSL routines:dtls1_read_bytes:ssl handshake failure:.\ssl\d1_pkt.c:819:
我唯一可用的想法是调试这个问题,以便在从 BIO 读取数据包之后以及在另一个会话中将它们写入 BIO 之前将数据包转储到文件中,但我发现没有任何区别字节比较后的内容,包序也OK。
文件转储在这里:http://reset.tor.hu/ssl/y/direct_bio_error/
我只是无法想象可能是什么问题,因为他们从来没有完成握手而没有失败,所以我决定在这个程序中添加两个 UDP 套接字,并将这些套接字连接到 BIO 并相互连接,并且毫不奇怪,握手是第一次成功。
文件转储在这里:http://reset.tor.hu/ssl/y/socket_ok/
可见,文件内容或数据包序列没有任何区别。
那他们为什么不使用 BIO 的直接连接?!
您可以在此视频中看到程序产生错误和正常工作:https://www.youtube.com/watch?v=4crbSz6JMMY
我唯一的想法是 C# 出于某种原因在当时混合了方法调用,但我没有使用任何线程!非托管代码调用回调来读取 BIO,我将 BIO 读取到我的缓冲区,我调用另一个方法将缓冲区写入 BIO 并在非托管代码中调用 SSL_read(),以使用 BIO 中的数据。而这恰恰相反。如果我没有使用缓冲区,而是使用套接字,它正在工作。套接字可以做什么使它工作?
我什至尝试将 Thread.Sleep(100) 放在 BIO 写作之间,但没有帮助,实际上超过 140ms OpenSSL 崩溃了(但使用套接字它甚至可以在 1000 毫秒内工作,更奇怪)。
直接 BIO 和慢速交通问题可能是什么问题和解决方案?
感谢您提前回答!
【问题讨论】:
标签: c# sockets ssl openssl handshake