OpenSSL客户端不发送客户端证书 [英] OpenSSL client not sending client certificate

查看:736
本文介绍了OpenSSL客户端不发送客户端证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到客户端证书问题,希望有人能帮助我。我使用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 - 验证5
验证深度为5,必须返回证书
设置辅助ctx参数
使用默认的temp DH参数
使用默认的temp ECDH参数
ACCEPT
SSL_accept:before / accept初始化
SSL_accept:SSLv3读客户端hello A
SSL_accept:SSLv3写服务器hello A
SSL_accept:SSLv3写证书A
SSL_accept:SSLv3写密钥交换A
SSL_accept:SSLv3写证书请求A
SSL_accept:SSLv3刷新数据
SSL3警报读取:警告:无证书
SSL3警报写入:fatal:握手失败
SSL_accept:错误在SSLv3中读取客户端证书B
SSL_accept:SSLv3读取客户端证书B中的错误
2675716:错误:140890C7:SSL例程:SSL3_GET_CLIENT_CERTIFICATE:peer未返回
证书:s3_srvr.c:3193 :
ACCEPT



我使用这个s_server作为调试工具,同样的事情发生。
s_client将与相同的证书正常工作。此外,如果我禁用服务器中的-Verify连接工作。所以它真的似乎只是客户拒绝发送它的certficate。这可能是什么原因?



由于我使用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);

我也试图绕过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
}

我看不到任何行为的差异。应该提到的是,我使用一个非常老的boost 1.43 asio,我不能更新,但我想所有相关的调用或多或少直接对OpenSSL反正和服务器工作正常版本,所以我想我可以排除。 / p>

如果我开始强制客户端和服务器到特定版本,错误消息更改,但它从来不工作,仍然总是与s_client测试。目前设置为TLSv1



如果我切换到TLSv1例如客户端和服务器之间有更多的聊天,最终我得到错误:

  ... 
SSL_accept:SSLv3读取客户端密钥交换A
<< TLS 1.0 ChangeCipherSpec [length 0001]
01
<< TLS 1.0握手[长度0010],完成
14 00 00 0c f4 71 28 4d ab e3 dd f2 46 e8 8b ed
>>> TLS 1.0警报[长度0002],致命unexpected_message
02 0a
SSL3警报写入:fatal:unexpected_message
SSL_accept:SSLv3读取证书失败验证B
2675716:错误:140880AE: SSL例程:SSL3_GET_CERT_VERIFY:缺少verify
消息:s3_srvr.c:2951:
2675716:错误:140940E5:SSL例程:SSL3_READ_BYTES:ssl握手失败:s3_pkt.c:989:
ACCEPT

我发现在openssl邮件列表上发布了一个较老的bug条目。显然一个错误的CRLF在握手,已经固定两年前。还是有吗?



我已经调试了将近一个星期了,我真的卡住了。有没有人有什么建议试试?我的想法...



干杯,
Stephan



以上s_server调试输出将与s_client和相同的certficate:

  $ openssl s_client -CAfile ca.crt -cert testclient .crt -key private / testclient.key -verify 2 -connect myhost:8887 

ACCEPT
SSL_accept:before / accept初始化
SSL_accept:SSLv3读取客户端hello A
SSL_accept:SSLv3写服务器hello A
SSL_accept:SSLv3写证书A
SSL_accept:SSLv3写密钥交换A
SSL_accept:SSLv3写证书请求A
SSL接受:SSLv3刷新数据
depth = 1 C = DE,//进一步信息
验证返回:1
depth = 0 C = DE,//更多信息
验证返回:1
SSL_accept :SSLv3读取客户端证书A
SSL_accept:SSLv3读取客户端密钥交换A
SSL_accept:SSLv3读取证书验证A
SSL_accept:SSLv3读取完成A
SSL_accept:SSLv3写入会话票证
SSL_accept:SSLv3 write change cipher spec A
SSL_accept:SSLv3 write finished A
SSL_accept:SSLv3 flush data
ACCEPT

解决方案

好的,经过很多痛苦,答案是由OpenSSL的Dave Thompson发现的。



原因是我的ssl代码在OpenSSL上下文中调用所有这些函数套接字对象(SSL *)是从它创建的。这意味着所有这些功能几乎没有什么或错误的事情。



我所要做的只是:



调用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
}

(注意缺少 CTX



2。调用CTX函数



在创建套接字之前根据上下文调用CTX函数。因为asio似乎鼓励在之后创建上下文和套接字(就像我在初始化器列表中一样)。调用只是无用的。



SSL上下文或asio等)封装SSL使用,并且从它创建的每个套接字将共享它的属性。



感谢你们的建议。


I am struggling with a client certificate problem and hope somebody here can help me. I'm developing a client/server pair using boost asio but I'll try to be unspecific. I'm on windows and using openssl 1.0.1e

Basically, I want to have client authentication by using client certificates. The server shall only accept clients that have a certificate signed by my own CA. So I have setup a self signed CA. This has issued two more certificates. One for the client and one for the server. Both signed by the CA. I have done that quite a few times now and I am confident that I got it.

My server side also works fine. It requests client certificates and if I'm using s_client and give those certs everything works. Also if I'm using a browser and have my root CA installed as trusted and then import the client certs.

The only thing that I can't get to work is the libssl client. It always fails during the handshake and as far as I can see it will not send the client certficate:

$ 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

I'm using this s_server as debugging tool but against my real server the same thing occurs. s_client will work fine with the same certificates. Also, if I disable "-Verify" in the server the connection works. So it really seems just the client refusing to send it's certficate. What can be the reason for that?

Since I'm using boost asio as an SSL wrapper the code looks like this:

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 );

I have also tried to bypass asio and access the SSL context directly by saying:

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
}

I can't see any difference in behavior. It should be mentioned that I am using a very old boost 1.43 asio which I cannot update but I suppose all relevant calls go more or less directly to OpenSSL anyway and the server works fine with that version so I think I can rule that out.

If I start forcing client and server to specific versions, the error messages change but it never works and still always works with the s_client test. Currently it is set to TLSv1

If I switch it to TLSv1 for example there is more chatter between client and server and eventually I get the error:

...
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

I have found an older bug entry posted on the openssl mailing list that refereed to this. Apparently a wrong CRLF in the handshake that has been fixed two yrs ago. Or has it?

I have been debugging this for almost a week now and I'm really stuck. Does anyone have a suggestion on what to try? I'm out of ideas...

Cheers, Stephan

PS: Here is what the above s_server debug out would be with s_client and the same certficate:

$ 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

... handshake completes and data is transferred.

解决方案

All right, after much suffering, the answer has been found by Dave Thompson of OpenSSL.

The reason was that my ssl code called all those functions on the OpenSSL context after the socket object (SSL*) was created from it. Which means all those functions did practically nothing or the wrong thing.

All I had to do was either:

1. Call 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
}

(notice the missing CTX)

2. Call the CTX functions

Call the CTX functions upon the context before the socket was created. As asio seemingly encourages to create the context and socket right afterwards (as I did in the initializer list) the calls were all but useless.

The SSL context (in lib OpenSSL or asio alike) encapsulates the SSL usage and each socket created from it will share it's properties.

Thank you guys for your suggestions.

这篇关于OpenSSL客户端不发送客户端证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆