I am using OpenSSL API for C++. Communication is between an embedded linux device (SSL server) and Windows software (SSL client).
I want to ensure that the intended server and client will only speak to one another. I have generated a root key for the server, along with the following:
- Root CA (used by client to authorize server)
- server certificate
- server private key
My SSL connection works fine when only authorizing the server certificate during handshaking.
However, I also want to verify client authenticity, so I generated another root key for the client, along with the following:
- Root CA (used by server to authorize client)
- client certificate
- client private key
Using the code below, my server fails to accept the client connection due to the following error:
724428760:error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned:s3_srvr.c:3291:
Here is my server code related to SSL certificates:
bool SSLServer::loadCertificates(const char * sCertFile,
const char * sKeyFile,
const char * sCAFile)
{
// set server certificate
if (SSL_CTX_use_certificate_file(_pCTX, sCertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
return false;
}
// set the private key
if (SSL_CTX_use_PrivateKey_file(_pCTX, sKeyFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
return false;
}
// verify private key
if (!SSL_CTX_check_private_key(_pCTX))
{
qWarning() << "Private key does not match the public certificate.";
return false;
}
SSL_CTX_set_verify(_pCTX, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
// load the trusted client CA certificate into context
if (SSL_CTX_load_verify_locations(_pCTX, sCAFile, NULL) != 1)
{
ERR_print_errors_fp(stderr);
return false;
}
// allow this CA to be sent to the client during handshake
STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(sCAFile);
if (NULL == list)
{
qWarning() << "Failed to load SSL client CA file.";
return false;
}
SSL_CTX_set_client_CA_list(_pCTX, list);
SSL_CTX_set_verify_depth(_pCTX, 1);
return true;
}
And here is my client code:
bool SSLClient::LoadCertificates(const char * sCAFile,
const char * sClientCertFile,
const char * sClientKeyFile)
{
ASSERT(NULL != sCAFile && NULL != sClientCertFile && NULL != sClientKeyFile);
// load RSA CA certificate into context to let client verify server's authenticity
// (will be used with server certificate and private key)
if (!SSL_CTX_load_verify_locations(_pCTX, sCAFile, NULL))
{
ERR_print_errors_fp(stderr);
return false;
}
// load client certificate into context to let server verify client's authenticity
// (will be used with server's RSA CA certificate)
if (SSL_CTX_use_certificate_file(_pCTX, sClientCertFile, SSL_FILETYPE_PEM) != 1)
{
ERR_print_errors_fp(stderr);
return false;
}
// load client certificate private key into context
if (SSL_CTX_use_PrivateKey_file(_pCTX, sClientKeyFile, SSL_FILETYPE_PEM) != 1)
{
ERR_print_errors_fp(stderr);
return false;
}
// verify that client cert and private key match
if (!SSL_CTX_check_private_key(_pCTX))
{
OutputDebugString("Private key does not match the certificate public key\n");
return false;
}
// require server certificate verification
SSL_CTX_set_verify(_pCTX, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_verify_depth(_pCTX, 1);
return true;
}
Again, it works completely fine if I remove the code related to verifying client certificate. Am I missing something, or doing something completely wrong?
The error message is misleading. While it says that the client did not return any certificates it happens also, if the client sends a certificate which the server can not validate. Please make sure, that the certificate sent by the client can actually be verified against the servers
sCAFile
.Working copy of your code along with certificates: http://files.webfile.ru/567c28b8973091cbdad036f3e43e989b
Exactly your problem can be reproduced if generate certificates just hitting 'enter' answering questions. You'll got 'self-signed' certificate without any intention to make it. Problem exactly like OpenSSL - error 18 at 0 depth lookup:self signed certificate When snooping ssl problems you should use not wireshark but ssldump.