I am struggling with a client certificate issue and hope someone here can help me. I am developing a client / server pair using boost asio, but I will try to be non-specific. I am in windows and using openssl 1.0.1e
Basically, I want to have client authentication using client certificates. The server should only accept clients that have a certificate signed by my own CA. So I installed a self-signed CA. This issued two more certificates. One for the client and one for the server. Both signed a CA. I have done this quite a few times, and I'm sure I got it.
My server side also works great. It requests client certificates, and if I use s_client and give these certificates, everything works. Also, if I use a browser and have my root CA installed as trusted, then I import client certificates.
The only thing I can not get is the libssl client. It always fails during a handshake, and as far as I can see, it will not send a client certificate:
$ 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 use this s_server as a debugging tool, but the same thing happens against my real server. s_client will work with the same certificates. In addition, if I disable "-Verify" on the server, the connection will work. So it really seems that the client refuses to send his certficate. What could be the reason for this?
Since I use 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 also tried to get around asio and directly access the SSL context, 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 do not see differences in behavior. It is worth mentioning that I am using a very old boost 1.43 asio, which I canβt update, but I believe that all the corresponding calls more or less directly access OpenSSL anyway, and the server works fine with this version, so I think that I can exclude it.
If I start to force the client and server to certain versions, the error messages change, but it never works and still always works with the s_client test. It is currently installed in TLSv1
If I switch it to TLSv1, for example, there is more chatter between the client and the server, and in the end I get an 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 found an older error entry posted on the openssl mailing list that referenced this. Apparently the wrong CRLF in the handshake, which was fixed two years ago. Or that?
I debugged this for almost a week, and I was really stuck. Does anyone have a suggestion on what to try? I have no ideas ...
Cheers, Stephan
PS: Here is what came out of the s_server debugging above 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
... the handshake ends and data is transmitted.