I am in the following situation. I need to set up a 2-way integration with an external system. The admin of the external system required me to send two CSRs, one to be used to generate a client certificate, the other to generate a server certificate. They sent me the corresponding certificates. I set up the channel me->they with success (i.e.: I can invoke their service supplying my client certificate), but I can't set up the inverse channel correctly (i.e.: I can't make my Apache accept their client certificate without complaining).

Together with my server certificate (let's call it my-server.pem) they also sent me their own client certificate (let's call it their-client.pem). This certificate (their-client.pem) is emitted by a "self-signed" CA, that is a CA that is not among those well-known CAs already available in my Linux system. I don't have this certificate and I was not yet able to get it from the external system admins (they are reluctant... let's put aside any comment on this please... >-|)

This is how I set up my VirtualHost in Apache:

SSLEngine on
SSLCertificateFile /path/to/my-server.pem
SSLCertificateKeyFile /path/to/my-server-secret-key.key
SSLVerifyClient require
SSLCACertificateFile /path/to/their-client.pem
SSLVerifyDepth 0

Since I don't have the CA certificate and since it's perfectly fine for me to say "just trust that client certificate, nobody else!", I put the client certificate itself as the SSLCACertificateFile, as suggested in the answer to: https://security.stackexchange.com/questions/36069/use-client-certificate-using-self-signed-ca-while-using-web-certificate-of-a-pub

However, this doesn't seem to work. The error they see on their side is:

javax.net.ssl.SSLException: Received fatal alert: unknown_ca

After enabling the SSL log and setting it to debug, what I see on my side is:

[ssl:debug] [pid 3396] ssl_engine_kernel.c(1381): [client <their-ip>:41474] AH02275: Certificate Verification, depth 1, CRL checking mode: none [subject: CN=Test CA,OU=Foo,O=Bar,C=it / issuer: CN=Test CA,OU=Foo,O=Bar,C=it / serial: 1BFE / notbefore: Dec  6 15:22:45 2010 GMT / notafter: Dec  6 15:21:52 2020 GMT]
[ssl:info] [pid 3396] [client <their-IP>:41474] AH02276: Certificate Verification: Error (19): self signed certificate in certificate chain [subject: CN=Test CA,OU=Foo,O=Bar,C=it / issuer: CN=Test CA,OU=Foo,O=Bar,C=it / serial: 1BFE / notbefore: Dec  6 15:22:45 2010 GMT / notafter: Dec  6 15:21:52 2020 GMT]
[ssl:info] [pid 3396] [client <their-IP>:41474] AH02008: SSL library error 1 in handshake (server my-server.com:443)
[ssl:info] [pid 3396] SSL Library Error: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
[ssl:info] [pid 3396] [client <their-IP>:41474] AH01998: Connection closed to child 54 with abortive shutdown (server my-server.com:443)

In other words, it's still trying to validate the dummy CA of the client certificate. I also tried to change SSLVerifyDepth to 1, with no luck (same error). If I disable the client certificate request (by changing the SSLVerifyClient value), the invocation goes fine, but I don't think it's the correct way to go.

A very similar question is: How can I make apache request a client SSL certificate without needing to verify it against a known CA?

However I'm not sure I understand the accepted solution. First of all, the client certificate I must validate is not self-signed (it's issued by an unknown CA).

Secondly, from what I understand from Apache/mod_ssl documentation, SSLVerifyCLient optional_no_ca actually disables strong client certificate authentication, because it makes it optional.

Third, the possibility to create a fake certificate with the same DN of the missing root CA certificate sounds like a workaround for forcing the client to send its client certificate, but in my case I don't think my problem is the client not sending me the certificate, but rather the Apache inability to fully validate it correctly.

Any suggestion on this topic would be very helpful.


Your error message clearly shows the cause right here: "depth 1". You've set SSLVerifyDepth 0 which per manual means that:

self-signed client certificates are accepted only

To check if client cert is as expected, and without the chain validation, try something like this:

SSLVerify none
SSLRequire (   %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd."  and %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/  )
| improve this answer | |
  • Interesting, you mean that SSLRequire directive is honoured even if SSLVerify is none? However, this just makes a requirement on the organization and remote address of the client, not on the actual whole certificate. This may be enough in many contexts, but it is not what I wanted. At that time I saw there's also a SSLRequire directive to match the whole certificate, but I read many people had trouble with it. – Mauro Molinari Jan 5 '17 at 8:05
  • 1
    Yes SSLRequire can be customized, this is just a quick example. Don't want "trouble"? Maybe don't ask questions about discouraged troublesome configs :) – kubanczyk Jan 5 '17 at 10:57

I really hate responses that suggest alternatives that don't actually answer the question but... if you don't want to (or can't because they won't provide it) accept their CA for their cert, then you should issue them the cert from your own CA. This would fix the problem of not only them not providing signer cert, but would also prevent you from having to trust a strange CA.

| improve this answer | |

This is for Apache 2.4.

# Unchanged:
SSLEngine on
SSLCertificateFile /path/to/my-server.pem
SSLCertificateKeyFile /path/to/my-server-secret-key.key
SSLCACertificateFile /path/to/their-client.pem
SSLVerifyDepth 0

# Changed:
SSLVerifyClient optional_no_ca
Require expr "%{SSL_CLIENT_I_DN_CN} -eq 'www.example.com'"

Also answered in How can I make apache request a client SSL certificate without needing to verify it against a known CA?

| improve this answer | |

I'm not an expert on Apache but from the certificate point of view if they don't want to supply you with the public key of their root CA simply ask them to get their client certificat from a well know CA instead of their own CA. For example, StartSSL offer free 1 year certificate. You're building a nightmare because the partner doesn't understand how it work. Another way is to install your own CA (Linux) https://jamielinux.com/docs/openssl-certificate-authority/ (Windows) http://datacenteroverlords.com/2012/03/01/creating-your-own-ssl-certificate-authority/ and ask them to provide you with a CSR to replace (their-client.pem)

| improve this answer | |
  • After some pressure and solicits, they finally sent me the root CAs certificates and I was able to make the client certificate authentication work correctly. Unfortunately, this "partner" is actually a big company that manages a government system, so it's quite hard (impossible?) to request a customised configuration (like the change of CAs...). I leave the question open, though, because it's hard to believe there's no way to bypass the whole chain verification in Apache (even if it's not the best way to go). – Mauro Molinari Sep 19 '15 at 19:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.