我正在使用BIO内存接口来通过SCTP实现TLS。
因此,在客户端,在发送应用程序数据时,SSL_write()
api加密数据并将数据写入关联的write BIO接口。
然后使用BIO_read()
调用将BIO接口中的数据读取到输出缓冲区,然后
使用sctp_sendmsg()
api发送到套接字。
同样在服务器端,同时从套接字读取数据sctp_recvmsg()
api从套接字读取加密的消息块,BIO_write()
api将其写入读取的BIO缓冲区,然后SSL_read()
api解密从BIO读取的数据。
我感兴趣的情况是在客户端完成第1步和第2步,在执行第3步时,我从套接字获得了EAGAIN。因此,无论我从BIO缓冲区读取了什么数据,我都会对其进行清理,并在一段时间后要求应用程序重新发送数据。
现在,当我执行此操作时,稍后在客户端执行第1、2和3步时,在服务器端,openssl发现它收到的记录具有bad_record_mac并关闭连接。
从谷歌搜索开始,我发现一种可能的情况是TLS数据包是否乱序,因为MAC编码依赖于先前编码的数据包,并且TLS需要以相同的顺序传送数据包。因此,当我清理EAGAIN上的数据时,我丢弃了一个SSL数据包,然后发送了下一个乱序的数据包(此处不够清晰)?
只是为了确保我的假设,每当套接字返回EAGAIN时,我都要进行代码更改以无限期等待直到套接字可写,然后一切正常,并且在服务器端我看不到任何bad_record_mac。
有人可以通过EAGAIN处理帮助我吗?我迫不及待地想解决这个问题,还有其他解决方法吗?
最佳答案
...我从插座上得到一个EAGAIN。因此,无论我从BIO缓冲区读取了什么数据,我都会对其进行清理,并在一段时间后要求应用程序重新发送数据。
如果套接字上出现EAGAIN,则应稍后再尝试发送相同的加密数据。
相反,您要做的是丢弃加密的数据,然后要求应用程序再次发送相同的纯数据。这意味着这些数据将再次被加密。但是,使用SSL加密普通数据还包括SSL帧的序列号,并且此序列号与您丢弃的最后一个SSL帧的序列号不同。
因此,如果您丢弃了完整的SSL帧,则尝试发送带有下一个序列号的新SSL帧,该序列号与预期的序列号不匹配。如果您已经成功发送了之前的SSL帧的一部分,而其余的全部消失了,那么您发送的新数据将被视为之前的帧的一部分,这意味着该帧的HMAC将不匹配。
因此,不要丢弃加密的数据,而是尝试重新发送这些数据,而不是让上层重新发送纯数据。