C++ OpenSSL客户端未发送客户端证书

C++ OpenSSL客户端未发送客户端证书,c++,ssl,network-programming,openssl,client-side,C++,Ssl,Network Programming,Openssl,Client Side,我正在努力解决一个客户端证书问题,希望这里有人能帮助我。我正在使用boost asio开发一个客户机/服务器对,但我会尽量不具体。我在windows上使用openssl 1.0.1e 基本上,我希望通过使用客户端证书进行客户端身份验证。服务器应只接受具有由我自己的CA签名的证书的客户端。因此,我已设置了一个自签名CA。这又颁发了两个证书。一个用于客户端,一个用于服务器。双方均由CA签署。 我已经做了很多次了,我相信我已经做到了 我的服务器端也可以正常工作。它要求客户端证书,如果我使用的是s_客户

我正在努力解决一个客户端证书问题,希望这里有人能帮助我。我正在使用boost asio开发一个客户机/服务器对,但我会尽量不具体。我在windows上使用openssl 1.0.1e

基本上,我希望通过使用客户端证书进行客户端身份验证。服务器应只接受具有由我自己的CA签名的证书的客户端。因此,我已设置了一个自签名CA。这又颁发了两个证书。一个用于客户端,一个用于服务器。双方均由CA签署。 我已经做了很多次了,我相信我已经做到了

我的服务器端也可以正常工作。它要求客户端证书,如果我使用的是s_客户端并提供这些证书,一切正常。另外,如果我正在使用浏览器,并将我的根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
$ 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
我使用这个s_服务器作为调试工具,但在我的真实服务器上也会发生同样的事情。 s_客户端可以使用相同的证书正常工作。此外,如果我在服务器中禁用“-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
}

。。。握手完成并传输数据。

您不应同时使用SSL\u CTX\u use\u certificate\u chain\u file()和SSL\u CTX\u use\u certificate\u file(),因为SSL\u CTX\u use\u certificate\u chain\u file()会尝试加载包含客户端证书的链,而不仅仅是CA链。发件人:

SSL_CTX_use_certificate_chain_file()将证书链从文件加载到CTX中。证书必须采用PEM格式,并且必须从主体证书(实际的客户端或服务器证书)开始排序,然后是中间CA证书(如果适用),最后是最高级别(根)CA

我认为您可以只使用SSL\u CTX\u use\u certificate\u file()和SSL\u CTX\u use\u PrivateKey\u file(),因为客户端并不太关心CA链。

我认为您需要在服务器端调用。这将设置要与客户端证书请求一起发送的证书颁发机构列表


如果证书与服务器发送的CA列表不匹配,即使请求了证书,客户端也不会发送它的证书。

好吧,在经历了许多痛苦之后,OpenSSL的Dave Thompson找到了答案

原因是我的ssl代码在从OpenSSL上下文创建套接字对象(ssl*)之后调用了OpenSSL上下文中的所有这些函数。这意味着所有这些函数实际上什么都没做或者做了错事

我所要做的就是:

1。调用SSL\u使用\u证书\u文件

res=SSL\u使用证书文件(SSL,“testclient.crt”,SSL\u文件类型\u PEM);

如果(res不幸的是,我已经尝试了我能想到的所有组合。包括这一个。无效。看起来客户端不会信任自己的客户端证书,也不会发送证书。如果我使用此组合,客户端根本不会发送证书,如果我使用链文件,它看起来会发送根CA而不是自己的。如果它发送根CACA,这是因为您正在调用SSL_CTX_use_certificate_chain_file(),其中仅包含CA证书。您能否尝试将仅包含客户端证书的文件传递给SSL_CTX_use_certificate_chain_file()?谢谢大家的意见!非常感谢!@Remi:当我这样做时,客户端不发送任何证书。这是我描述的第一个案例。顺便说一句,如果链文件只包含ca证书,情况也是如此。我知道,这是不明智的,但我还是想试试。是的。这已经完成了。它已经发送了。不幸的是,我的问题出在客户端上。我使用openssl的_服务器调试我自己的客户端。所以我自己的服务器在这里并不重要。只要假设它正常,我就无法连接到s_服务器测试工具。我必须假设它正确地说出了它的协议。抱歉,我忽略了这一点。我假设你检查了非常明显的东西,比如cor的密钥文件rect one?在您的s_客户端命令行中,它是private/testclient.key,在代码中它只是“testclient.key”。我的(工作)代码与您的操作完全相同,除了我执行SSL_CTX_check_private_key以验证它是否与证书匹配,并且我安装了一个密码回调以“解锁”私钥:SSL\u CTX\u set\u default\u passwd\u cb。不用担心,谢谢您的任何输入。我在这里完全搞砸了。至于证书,唉,我做了。一遍又一遍地检查它们,区分文件等等。命令行差异的原因只是我用我可以发布在这里的证书名替换了一个“可疑的秘密”证书名;-)我确信他们是对的。SSL\u CTX\u check\u private\u密钥返回true。空密码密钥需要密码回调吗?
$ 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
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
}