使用带有非阻塞套接字的libev时出现OpenSSL读取客户端证书错误

使用带有非阻塞套接字的libev时出现OpenSSL读取客户端证书错误,openssl,libev,Openssl,Libev,我花了一些时间搜索互联网站,寻找更好的方法来分析和调试我的问题,但似乎找不到解决方案。所以我想我应该问一下 简单地说。我正在尝试创建一个非阻塞ssl转发代理。代理的服务器部分使用自签名服务器证书,我使用自己的CA证书对其进行了签名。如果有关系的话,我用的是libev。我首先成功地创建了一个未加密的代理(它盲目地转发web流量),现在我正在尝试向它添加SSL:) 我在让客户端连接到代理服务器时遇到问题。我尝试了wget和ssl的_客户端作为测试客户端,因为我想进行一些自动化测试 ssl服务器设置(

我花了一些时间搜索互联网站,寻找更好的方法来分析和调试我的问题,但似乎找不到解决方案。所以我想我应该问一下

简单地说。我正在尝试创建一个非阻塞ssl转发代理。代理的服务器部分使用自签名服务器证书,我使用自己的CA证书对其进行了签名。如果有关系的话,我用的是libev。我首先成功地创建了一个未加密的代理(它盲目地转发web流量),现在我正在尝试向它添加SSL:)

我在让客户端连接到代理服务器时遇到问题。我尝试了wget和ssl的_客户端作为测试客户端,因为我想进行一些自动化测试

ssl服务器设置(此代码在EV_读取事件上从libev watcher侦听套接字accept_handler()调用):

libev循环设置为:

loop = ev_default_loop(EVFLAG_AUTO);
我有计时器之类的东西来检查关机标志以及其他家务活动

My client_handshake()主函数本质上如下所示:

int t = SSL_accept(client_ssl);
if (t == 1) { // SSL_ERROR_NONE
    end_client_handshake(...);
} else {
    int err = SSL_get_error(client_ssl, t);
    if (err == SSL_ERROR_WANT_READ) {
        ev_io_stop(loop, &ev_w_ch);
        ev_io_start(loop, &ev_r_ch);
    }
    else if (err == SSL_ERROR_WANT_WRITE) {
        ev_io_stop(loop, &ev_r_ch);
        ev_io_start(loop, &ev_w_ch);
    }
    else ...
}
在client_info_cb()中,我在进行过程中打印出内部SSL状态,并从print()函数中获得以下信息:

client_info_cb: 8193: SSLv3 read client hello A
client_info_cb: 8193: SSLv3 write server hello A
client_info_cb: 8193: SSLv3 write certificate A
client_info_cb: 8193: SSLv3 write server done A
client_info_cb: 8193: SSLv3 flush data
client_info_cb: 8194: SSLv3 read client certificate A
client_info_cb: 8194: SSLv3 read client certificate A
这就是它悬挂的地方。我尝试修改client_handshake()函数,以便在检测到SSL_ERROR_WANT_READ(这是SSL_get_ERROR()在上面的第二条“READ client certificate A”消息后返回的)时,围绕SSL_accept()循环(1){}

这只会让我陷入无限循环(),不断调用SSL_accept()

我假设SSL状态机需要一些它无法获取的附加信息。起初我认为我需要继续从套接字读取数据,但这不起作用

此外,我还不明白为什么我的代理试图读取客户机证书,因为我已经明确指定我不想验证上面的客户机证书(SSL\u verify\u NONE);除非我误解了这个功能的目的

如果有人对此有任何见解,我将不胜感激。或者可能是调试此问题的更好方法。strace()对此毫无用处,而且我从wget或s_客户端都没有收到任何好的返回/错误消息

我尝试在SSL的状态机中设置alert_回调和msg_回调,但这并没有给我比info回调更多的信息

在这一点上,我不确定这是一个套接字问题,还是一个SSL问题,或者是什么

edit1:我想指出,在accept_handler()中,我首先通过ssl连接到服务器,以便在完成accept()之前验证我代理的主机的证书。如果我颠倒操作顺序,在继续连接()之前先接受(),它就会工作

edit2:我试着查看s_客户端和代理之间的tcpdump输出。在写入客户端信息cb中引用的服务器数据和刷新数据之后,客户端发送“客户端密钥交换”、“更改密码规范”和“加密完成消息”。但是ssl状态机正在寻找客户端证书

--> Client Key Exchange
write to 0x9547a78 [0x9592e90] (523 bytes => 523 (0x20B))
0000 - 16 03 01 02 06 10 00 02-02 02 00 be 51 c7 3d 77   ............Q.=w
0010 - 5a b3 9e 28 81 f4 4e b5-63 ce ce 0b 19 f3 85 64   Z..(..N.c......d
0020 - 29 0e e8 22 83 b8 60 a6-54 e3 7a 62 b3 37 d8 04   ).."..`.T.zb.7..
0030 - 6c f1 8e ff 50 44 ed cc-7b 08 61 0c 16 88 f4 61   l...PD..{.a....a
0040 - 7b 8d f2 1e 04 1d 74 3d-cc ee a4 93 d3 bb 90 ee   {.....t=........
<snip>
--> Change Cipher Spec
write to 0x9547a78 [0x9592e90] (6 bytes => 6 (0x6))
0000 - 14 03 01 00 01 01
--> Finished Message                                 ......
write to 0x9547a78 [0x9592e90] (53 bytes => 53 (0x35))
0000 - 16 03 01 00 30 9a 88 8b-14 d6 d1 f1 f7 d8 0d ac   ....0...........
0010 - 38 cd 54 78 26 85 7b 11-c8 e9 db 8d a2 0c 6a a8   8.Tx&.{.......j.
0020 - d4 e7 d4 ad 5d 7a 6d 47-eb f9 5f 2c f6 ca 6a 1f   ....]zmG.._,..j.
0030 - 17 a6 58 25 41                                    ..X%A
-->客户端密钥交换
写入0x9547a78[0x9592e90](523字节=>523(0x20B))
0000-16 03 01 02 06 10 00 02-02 02 00 be 51 c7 3d 77………Q.=w
0010-5a b3 9e 28 81 f4 4e b5-63 ce 0b 19 f3 85 64 Z.(…N.c.…d.)
0020-29 0e e8 22 83 b8 60 a6-54 e3 7a 62 b3 37 d8 04)“...T.zb.7。。
0030-6c f1 8e ff 50 44 ed cc-7b 08 61 0c 16 88 f4 61 l…PD..{
0040-7b 8d f2 1e 04 1d 74 3d cc ee a4 93 d3 bb 90 ee{…..t=。。。。。。。。
-->更改密码规范
写入0x9547a78[0x9592e90](6字节=>6(0x6))
0000 - 14 03 01 00 01 01
-->已完成消息。。。。。。
写入0x9547a78[0x9592e90](53字节=>53(0x35))
0000-16 03 01 00 30 9a 88 8b-14 d6 d1 f1 f7 d8 0d ac….0。。。。。。。。。。。
0010-38 cd 54 78 26 85 7b 11-c8 e9 db 8d a2 0c 6a a8.Tx和{…….j。
0020-d4 e7 d4 ad 5d 7a 6d 47 eb f9 5f 2c f6 ca 6a 1f….]zmG。
0030-17 a6 58 25 41..X%A

可能您遇到了一些会话缓存问题(默认情况下已启用,并且“编辑1”指向该问题),您是否试图向客户端提供来自服务器的伪造证书?可能内部缓存按证书名称存储,并且它试图恢复服务器会话

尝试使用
SSL\u CTX\u set\u session\u cache\u mode
SSL\u SESS\u cache\u off
选项关闭缓存


关于“编辑2”客户端密钥交换阶段不涉及发送客户端证书,它发送用于所选密码系统的密码(或不发送任何密码)(如果所选密码不需要密码,它可以发送空的客户端交换)首先将et设置为非阻塞模式

int fd_nonblock(int client_fd)
{
    int flags = fcntl(client_fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    return fcntl(client_fd, F_SETFL, flags);
}

感谢您将我指向会话缓存模式。我很快尝试将客户端和服务器ctx都设置为SSL SESS cache OFF,但没有任何效果。我知道客户端密钥交换没有发送证书。我刚才说的是客户端的SSL状态机(请参阅上面的客户端信息)似乎要读取客户端证书,但我验证了s_客户端只发送客户端密钥交换。那里似乎存在断开连接。再仔细想想,每个SSL状态(一个用于client2proxy,一个用于proxy2server)它有自己独特的会话,所以我不确定缓存在SSL状态中究竟是如何成为一个问题。除非OpenSSL在具有多个不同模式的SSL状态(accept vs connect)方面存在某种问题。是的,我正在尝试为来自的伪造证书提供服务
int fd_nonblock(int client_fd)
{
    int flags = fcntl(client_fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    return fcntl(client_fd, F_SETFL, flags);
}