OpenSSL客户端未发送客户端证书
OpenSSL client not sending client certificate
我正在努力解决客户端证书问题,希望这里有人能帮助我。我正在使用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
我使用这个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 );
我也试过绕过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,服务器在那个版本下工作得很好,所以我想我可以排除这种可能性。
如果我开始强制客户端和服务器到特定的版本,错误消息改变,但它从来没有工作,仍然总是与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
我在openssl邮件列表中找到了一个旧的bug条目,它提到了这个。显然,在握手中错误的CRLF已经在两年前修复了。是吗?
我已经调试这个差不多一个星期了,我真的卡住了。谁有什么建议吗?I'm out of ideas.
欢呼,Stephan
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
…握手完成,数据传输。
好了,经过一番磨难,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
}
(注意缺少CTX)
2。调用CTX函数
在创建套接字之前调用上下文的CTX函数。由于asio似乎鼓励之后立即创建上下文和套接字(就像我在初始化列表中所做的那样),这些调用几乎是无用的。
SSL上下文(类似于lib OpenSSL或asio)封装了SSL的使用,并且从它创建的每个套接字将共享它的属性。
谢谢大家的建议
您不应该同时使用SSL_CTX_use_certificate_chain_file()和SSL_CTX_use_certificate_file(),因为SSL_CTX_use_certificate_chain_file()试图加载包括客户端证书在内的链,而不仅仅是CA链。从SSL_CTX_use_certificate (3):
SSL_CTX_use_certificate_chain_file()将证书链从file加载到ctx。证书必须是PEM格式,并且必须排序,从主体的证书(实际的客户端或服务器证书)开始,然后是中间CA证书(如果适用),最后以最高级(根)CA结束。
我认为您应该只使用SSL_CTX_use_certificate_file()和SSL_CTX_use_PrivateKey_file(),因为客户端无论如何都不关心CA链。
我认为您需要在服务器端调用SSL_CTX_set_client_CA_list
。这将设置要与客户端证书请求一起发送的证书颁发机构列表。
客户端将不发送它的证书,即使一个被请求,如果证书与服务器发送的CA列表不匹配
- "unknown ca"自生成的 CA、证书和客户端/服务器
- OpenSSL TLS服务器-使用客户端证书白名单
- 打开 SSL 查询客户端证书
- 为什么 gRPC C++ 客户端在没有显式服务器的 SSL 证书的情况下无法工作,就像在示例中一样?
- 使用 WinInet 的客户端身份验证(证书 + 私钥)
- 证书验证在客户端服务器通信中使用boost :: asio和openssl失败
- 由于SSL3_GET_CLIENT_CERTIFICATE:未返回证书,验证 SSL 客户端真实性失败
- 如何在 OpenSSL 中使用 SSL 证书与 gsoap,使用 C++ 客户端/服务器
- Microsoft HTTP 服务器 API - 使用 SSL,如何要求客户端证书
- 什么是客户端证书,从哪里获取它,如何使用它连接到服务器?
- 使用WCF和gSOAP向服务器和客户端添加证书
- OpenSSL:服务器无法验证客户端证书
- OpenSSL客户端未发送客户端证书
- 如何使用boost::asio SSL验证客户端证书
- 验证SSL_get_peer_certificate返回的服务器证书的客户端程序
- 创建临时客户端证书(包括私钥)
- 在QWebSockets客户端检查SSL证书有效性的最佳实践
- 如何获取有关客户端证书的信息
- 使用OPENSSL(使用证书)进行客户端-服务器通信
- 将SSL客户端证书与IXMLHTTPRequest3一起使用