我使用zeromq和openssl来编写我的服务器和客户端 .
握手成功后,当客户端再次向服务器发送消息时,服务器中的ssl_read()返回-1,ssl_get_erro()返回SSL_ERROR_SYSCALL,
当服务器再次收到消息时,这种情况会重复 . 我找不到原因 . 我需要BIO_flush()吗?我真的很感激你,甚至只是给我一些灵感来解决这个问题 .
好吧,我的程序太复杂了,无法显示 . 我被要求将ssl添加到rpcz以提高其安全性(我不知道rpcz是否足够流行,大多数人都知道 . 在我看来,它结合了zeromq,protobuf和rpc来实现远程过程调用) . 所以有很多代码片段,我认为通过在这里展示它们不会有任何帮助 .
我想提供更多细节 .
握手成功后,服务器尝试使用这样的方法解密收到的数据
`{
//.......
bio_write();
//.......
ssl_read();
}`
事实证明,bio_write()已成功通过返回数据将数据写入bio,但ssl_read()始终返回-1 . 所以我使用ssl_get_error()来检查错误号,它返回SSL_ERROR_SYSCALL,并且对于接收的下一个数据,它返回SSL_ERROR_WANT_READ .
希望有人可以帮助解释为什么ssl_read返回这些代码?我认为如果ssl连接没有成功握手,ssl_write()不会返回正数 . 所以问题可能不是ssl连接 .
再次添加一些细节
void TLSZmq::ssl_decrypt()
{
//........
ERR_clear_error();
int rc = BIO_write(rbio,zmq_to_ssl->data(),zmq_to_ssl->size());
ERR_get_error();
check_ssl_err(rc); //written by myself
//.........
ERR_clear_error();
aread = SSL_read(ssl_,buffer,BUFFERSIZE);
ERR_get_error();
check_ssl_err(rc); //written by myself
//..........
}
void TLSZmq::check_ssl_err(int rc)
{
//...................
int err = SSL_get_error(ssl_, rc);
if (err == SSL_ERROR_NONE)
{
std::cout<<"SSL_ERROR_NONE:"<<SSL_ERROR_NONE<<std::endl;
}
else if (err == SSL_ERROR_WANT_READ )
{
std::cout<<"SSL_ERROR_WANT_READ:"<<SSL_ERROR_WANT_READ<<std::endl;
}
else if (SSL_ERROR_SYSCALL)
{
std::cout<<"SSL_ERROR_SYSCALL:"<<SSL_ERROR_SYSCALL<<std::endl;
}
//.....................
}
我不确定这是检查错误堆栈的正确方法 . 当出现SSL_ERROR_SYSCALL时,ERR_get_error()返回一个奇怪的数字,如336130315,当出现SSL_ERROR_WANT_READ时,ERR_get_error()返回0 .
我还测试过握手后解密过程使用的ssl连接(SSL * ssl)与握手时使用的连接相同 .
呃......我们正在谈论openssl对吗? rc获取openssl的BIO_write()函数的返回值 . 附:我使用zeromq socket发送消息,我已经指出了 . 我很迷惑 . 获得errno或调用perror()是否有意义?
非常感谢您抽出时间阅读本文 .
1 回答
SSL连接不是可以独立使用的解密功能和加密功能 . 如果你想要一个块或流密码,你可以使用OpenSSL代码获得一些 . 但是你不能以这种方式使用SSL .
可以使用BIO对来允许SSL在TCP之外的传输层上操作 . 但是你必须复制TCP的语义 - 它很复杂,代码看起来与你上面的代码完全不同 . (例如,TCP允许在任何时间向任一方向传输 . 您不会复制它 . 设计为在TCP之上分层的SSL,要求您复制它以便在其他传输上工作 . )
如果你想要一个流密码,只需使用一个密码 .