8 c++ ssl openssl network-programming client-side
我正在努力解决客户端证书问题,并希望有人可以帮助我.我正在使用boost asio开发客户端/服务器对,但我会尝试非特定.我在Windows上并使用openssl 1.0.1e
基本上,我想通过使用客户端证书进行客户端身份验证.服务器只接受拥有由我自己的CA签名的证书的客户端.所以我设置了一个自签名的CA. 这已经发出了两个证书.一个用于客户端,一个用于服务器.两者均由CA签署.我现在做了很多次,我相信我得到了它.
我的服务器端也正常.它会请求客户端证书,如果我使用s_client并提供这些证书,一切正常.此外,如果我使用浏览器并将我的根CA安装为受信任,然后导入客户端证书.
我唯一无法工作的是libssl客户端.它在握手期间总是失败,据我所知,它不会发送客户端证书:
$ openssl.exe s_server -servername localhost -bugs -CAfile myca.crt -cert server.crt
-cert2 server.crt -key private/server.key -key2 private/server.key -accept 8887 -www
-state -Verify 5
verify depth is 5, must return a certificate
Setting secondary ctx parameters
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT
SSL_accept:before/accept initialization
SSL_accept:SSLv3 read client hello A
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write key exchange A
SSL_accept:SSLv3 write certificate request A
SSL_accept:SSLv3 flush data
SSL3 alert read:warning:no certificate
SSL3 alert write:fatal:handshake failure
SSL_accept:error in SSLv3 read client certificate B
SSL_accept:error in SSLv3 read client certificate B
2675716:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a
certificate:s3_srvr.c:3193:
ACCEPT
Run Code Online (Sandbox Code Playgroud)
我正在使用这个s_server作为调试工具,但是对于我的真实服务器,同样的事情发生了.s_client可以使用相同的证书正常工作.此外,如果我在服务器中禁用"-Verify"连接工作.所以看起来只是客户拒绝发送它的证书.可能是什么原因?
由于我使用boost asio作为SSL包装器,因此代码如下所示:
m_ssl_context.set_verify_mode( asio::ssl::context::verify_peer );
m_ssl_context.load_verify_file( "myca.crt" );
m_ssl_context.use_certificate_file( "testclient.crt", asio::ssl::context::pem );
m_ssl_context.use_private_key_file( "testclient.key", asio::ssl::context::pem );
Run Code Online (Sandbox Code Playgroud)
我还尝试绕过asio并直接访问SSL上下文:
SSL_CTX *ctx = m_ssl_context.impl();
SSL *ssl = m_ssl_socket.impl()->ssl;
int res = 0;
res = SSL_CTX_use_certificate_chain_file(ctx, "myca.crt");
if (res <= 0) {
// handle error
}
res = SSL_CTX_use_certificate_file(ctx, "testclient.crt", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
res = SSL_CTX_use_PrivateKey_file(ctx, "testclient.key", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
Run Code Online (Sandbox Code Playgroud)
我看不出行为有什么不同.应该提到的是,我使用的是一个非常旧的boost 1.43 asio,我无法更新,但我认为所有相关的调用或多或少直接与OpenSSL相关,并且服务器可以正常使用该版本,所以我想我可以排除这一点.
如果我开始强制客户端和服务器到特定版本,错误消息会更改但它永远不会工作,并且仍然始终与s_client测试一起使用.目前它被设置为TLSv1
如果我将它切换到TLSv1,例如客户端和服务器之间有更多的聊天,最终我得到错误:
...
SSL_accept:SSLv3 read client key exchange A
<<< TLS 1.0 ChangeCipherSpec [length 0001]
01
<<< TLS 1.0 Handshake [length 0010], Finished
14 00 00 0c f4 71 28 4d ab e3 dd f2 46 e8 8b ed
>>> TLS 1.0 Alert [length 0002], fatal unexpected_message
02 0a
SSL3 alert write:fatal:unexpected_message
SSL_accept:failed in SSLv3 read certificate verify B
2675716:error:140880AE:SSL routines:SSL3_GET_CERT_VERIFY:missing verify
message:s3_srvr.c:2951:
2675716:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:989:
ACCEPT
Run Code Online (Sandbox Code Playgroud)
我在openssl邮件列表上发现了一个较旧的bug条目,该条目对此有所了解.显然是两年前修复过的握手中错误的CRLF.还是有吗?
我已经调试了近一个星期了,我真的被卡住了.有没有人建议尝试什么?我没有想法......
干杯,斯蒂芬
PS:以上s_server调试出来的是s_client和相同的证书:
$ openssl s_client -CAfile ca.crt -cert testclient.crt -key private/testclient.key -verify 2 -connect myhost:8887
ACCEPT
SSL_accept:before/accept initialization
SSL_accept:SSLv3 read client hello A
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write key exchange A
SSL_accept:SSLv3 write certificate request A
SSL_accept:SSLv3 flush data
depth=1 C = DE, // further info
verify return:1
depth=0 C = DE, // further info
verify return:1
SSL_accept:SSLv3 read client certificate A
SSL_accept:SSLv3 read client key exchange A
SSL_accept:SSLv3 read certificate verify A
SSL_accept:SSLv3 read finished A
SSL_accept:SSLv3 write session ticket A
SSL_accept:SSLv3 write change cipher spec A
SSL_accept:SSLv3 write finished A
SSL_accept:SSLv3 flush data
ACCEPT
Run Code Online (Sandbox Code Playgroud)
...握手完成并传输数据.
小智 7
好吧,经过千辛万苦,OpenSSL 的 Dave Thompson 找到了答案。
原因是我的 ssl 代码在创建套接字对象 (SSL*) 后调用了 OpenSSL 上下文上的所有这些函数。这意味着所有这些功能实际上什么也没做或做了错误的事情。
我所要做的就是:
1.调用SSL_use_certificate_file
res = SSL_use_certificate_file(ssl, "testclient.crt", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
res = SSL_use_PrivateKey_file(ssl, "testclient.key", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
Run Code Online (Sandbox Code Playgroud)
(注意缺少CTX)
2. 调用CTX函数
在创建套接字之前根据上下文调用 CTX 函数。由于 asio 似乎鼓励事后立即创建上下文和套接字(就像我在初始化列表中所做的那样),这些调用几乎毫无用处。
SSL 上下文(在 lib OpenSSL 或 asio 等中)封装了 SSL 的使用,并且从它创建的每个套接字将共享它的属性。
谢谢你们的建议。