OpenSSL client does not send client certificate

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.

+6
source share
3 answers

Well, after much suffering, the answer was found by Dave Thompson from OpenSSL.

The reason was because my ssl code called all these functions in the OpenSSL context after the socket object (SSL *) was created from it. This means that all these functions did practically nothing or something was wrong.

I could only:

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 } 

(note the missing CTX)

2. Call CTX Functions

Call CTX functions in context before creating the socket. Since asio seems to be encouraging context and socket creation immediately afterwards (as in the initializer list), the calls were almost useless.

The SSL context (in OpenSSL lib or asio similar) encapsulates the use of SSL, and each socket created from it will share its properties.

Thanks guys for your suggestions.

+2
source

You should not use SSL_CTX_use_certificate_chain_file () and SSL_CTX_use_certificate_file () since SSL_CTX_use_certificate_chain_file () is trying to download the chain, including the client certificate, and not just the CA chain. From SSL_CTX_use_certificate (3) :

SSL_CTX_use_certificate_chain_file () loads the certificate chain from a file into ctx. Certificates must be in PEM format and must be sorted starting with the subject certificate (the actual client or server certificate), followed by intermediate CA certificates, if applicable, and end at the highest level (root) CA.

I think you should be fine using only SSL_CTX_use_certificate_file () and SSL_CTX_use_PrivateKey_file (), as the client still doesn't care about the CA chain.

+1
source

I think you need to call SSL_CTX_set_client_CA_list on the server side. This sets up a list of certificate authority to send along with the client certificate request.

The client will not send its certificate, even if it was requested, if the certificate does not match this CA list sent by the server.

+1
source

Source: https://habr.com/ru/post/946957/


All Articles