Browser doesn't apply client certificate: 403.7 - ssl

I'm trying to set up client certificate authentication. I was able to generate a CA-, server- and client-certificate. As long as I use Fiddler everything works as expected. However, as soon as I start using a browser it doesn't work anymore (HTTP Error 403.7 - Forbidden).
Of course I imported the client certificate in the Personal store and I made sure Client Certificate Negotiation is enabled.
I also tried openssl s_client -connect 127.0.0.1:443 -state -debug but I couldn't really make sense of the result... The only thing what's weird is that my CA doesn't show up in the Acceptable client certificate CA names section.
Anything else I could try?
Update:
I think it doesn't matter but my server certificate is set up for 127.0.0.1. Therefore I'm using https://127.0.0.1/... in my browsers.
Update2:
Using Wireshark I noticed that my servers' response depends on the client:
Fiddler (OK):
Client Hello
Server Hello, Certificate, Server Hello Done
Browser (Not OK):
Client Hello
Server Hello, Change Cipher Spec, Encrypted Handshake Message
Update3:
After enabling clientcertnegotiation the server response is different but still doesn't work:
Server Hello, Certificate
Certificate Request
Certificate, Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
My self-signed CA doesn't seem to be in the Distinguished Names list...
Update4:
SSL Settings: Checked Require SSL and Client certificates set as Required. Client cert shows up in Personal and the intended purpose is Client Authentication.

I finally found the issue and a workaround:
As mentioned in Update3, Distinguished Names doesn't contain my CA. This is because Distinguished Names has a limit of 2^14 bytes (16384 bytes). Because I do have a lot of CA installed on my machine my CA simply didn't make it in. The TLS standard would allow to send multiple messages but unfortunately Windows doesn't support this!
As mentioned here you have a few possibilities. The simplest one is this:
At your server add a DWORD (not QWORD!) value called SendTrustedIssuerList in your registry under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL and set it to 0. This will prevent your server from sending a list at all, letting the client choose from any installed client certificate.
Unfortunately I couldn't see any traces in the Event Viewer (as reported elsewhere). Therefore the issue wasn't easy to spot (I had to use Wireshark in order to check Distinguished Names).

Use the Accept option instead of the Require option of the "Client certificates" feature.
In IIS Manager, locate the Web application for which you want to change the SSL setting.
In Features View, double-click SSL Settings.
On the SSL Settings page, select the Accept option under Client certificates.
In the Actions pane, click Apply.
More info here

Client certificate should be imported in CurrentUser\My store with private key (i.e. p12 or pfx file usually).
CA certificate should be in LocalMachine\Root store so that IIS trusts all certificates issued by the CA and the CA is trusted for every user on the computer.
CRL issued by the CA should be either available through URL (specified in every end entity certificate that CA issued) or imported in LocalMachine\My store.
NOTE: openssl doesn't use windows certificate store so this will have no efect on openssl s_client -connect 127.0.0.1:443 -state

Related

Self signed cert in chain from only some servers

I have multiple Intel NUCs out in the field that I use for displaying digital signage. Out of the thousands I have in the field, a couple complain with this error:
SSL certificate problem: self signed certificate in certificate chain. More details here: http://curl.haxx.se/docs/sslcerts.html, curl performs SSL certificate verification by default, using a "bundle" of Certificate Authority (CA) public keys (CA certs). If the default bundle file isn't adequate, you can specify an alternate file using the --cacert option. If this HTTPS server uses a certificate signed by a CA represented in the bundle, the certificate verification probably failed due to a problem with the certificate (it might be expired, or the name might not match the domain name in the URL). If you'd like to turn off curl's verification of the certificate, use the -k (or --insecure) option.
I've confirmed that the cert is not expired, and the domain name matches
These units are running on Debian 7
Could the network they are on cause this issue with some sort of firewall setting?
When you visit the website what certificate is shown in the web browser? In your curl bundle is that the same certificate which is supposed to be used for SSL encryption? I'd guess no. CA will sign your cert.pem so that web browsers will show your green lock thereby authenticating your website. You most likely have an issue on the back end with the configuration of your curl bundle. You need to make sure that your server is using the CA cert not a self signed certificate like ssl-cert-snakeoil.pem for example.
Essentially your website should be using a static IPv4 address. As far as a network firewall stopping an SSL handshake from happening that may be possible, I have seen it happen on specific ports for example port 22 for ssh connections may be blocked at the network gateway for inbound traffic on a client side computer attempting a connection to a server. The SYN/ACK https://tools.ietf.org/rfc/rfc793.txt TCP handshake may time out in that type of network fire wall situation. However since you are getting an explicit response from your server about a self signed cert a firewall issue does not seem to be the problem.

Using self-signed SSL certificate works, but CA signed certificate results in handshake alert failure 40 in response to client hello

So far, I've used openssl, sslyze, keystore utilities, and some of the standard Windows diagnostics commands to try and characterize this problem. The summary is that as soon as I attempt to use a keystore that has the CA signed certificate in it, I get an immediate handshake failure 40 after the client hello. The connection never gets as far as a server hello with the CA cert in place.
On the same machine (Windows Server 2012), if I use a self signed certificate, the connection works as expected.
Openssl shows the handshake failure with the CA certificate in place.
sslyze shows all ciphers rejected with either no ciphers available or TLS / Alert handshake failure.
The fact that this is successful with a self-signed certificate tends to indicate that the "basics" are there, that the client and server have the necessary ciphers and so on to connect, and that server.xml is configured properly.
There were no error messages when importing the certificates, and everything seems to be configured correctly with the CA certs based on keytool checks. There are no error messages given during server start to indicate any problems processing the certificate.
Is there something I should be looking more closely at in regards to the keystore with the CA cert that could cause this complete rejection of the client hello? How would a different keystore or CA certs within aaffect the earliest steps of the handshake?
Thank you for information provided.
I assume that you are talking about a server side certificate and a server side key store, since the error happens at a state where no client certificates are yet involved. If the server is able to send the self-signed certificate to the client, but is not able to send the CA signed certificate to the client, then it must be something wrong with the certificate you are trying to send or that the certificate can not be used together with the ciphers offered by the client.
Since the problem is obviously on the server side you should first check all logs written on the server side for hints what the error might be. Typical problems are non-existing files, wrong files, password protected client key w/o providing a password or that the key does not belong to the certificate.

How does web browser understand which x509 certificate it should send to server?

I'm trying to create web application with client certificates, generated programmatically. My main problem is following: I've added generated .p12 keystore to my web browser, but it doesn't send certificate to the server.
How does browser understand which x509 certificate it should use? And is it possible to debug SSL in Chrome of Firefox?
SSL/TLS server sends Certificate Request message (see RFC 4346 for TLS 1.1 or others). In this message there is only certificate type and acceptable certificate authorities names, so server doesn't tell anything about particular certificate.
The possible reason is that your certificate of invalid type (i.e. DSA instead of RSA but key exchange algorithm depends on client RSA certificate), or server requests certificate of different certificate authority.

How to determine a server's list of CA certificates that it will accept from client?

According to https://wiki.jasig.org/display/CASUM/X.509+Certificates,
After the Server sends the certificate that identifies itself, it then can then send a list of names of Certificate Authorities from which it is willing to accept certificates.
I am wondering how to determine what this list is, and how to modify it.
The reason I am asking is that I am getting an infinite redirect between my server and my client after successful validation (i.e., the ticket stage), and I think it has to do with the CAS server not recognizing the CAS client's certificate (the client's certificate is self-signed).
If you want to see what this list is, you can use OpenSSL:
echo "" | openssl s_client -connect your.server:port
This will show various messages regarding the handshake, including the certificates and the list of CAs in the CertificateRequest message.
Ultimately, it's determined by the active X509TrustManager's getAcceptedIssuers() method. By default, this will be the list of Subject DNs of all your trust anchors (that is, the Subject DNs of all the certificates in your trust store).
Your client certificate will have to be verified by the server. This is normally done during the handshake by the trust manager, which (unless tweaked) will build a chain to a known CA (or at least known cert if it's the user cert itself) in the trust store.
Adding your self-signed certificate to your trust store should be sufficient. It doesn't have to be the cacerts file bundled with the JVM, you could make a copy of it and use the trust store settings of Apache Tomcat's connector to set it up.

SSL client certificate needs special contents?

I have a server with an SSL certificate and clients with SSL cetificates, all are signed by the same CA, and the CA is trusted on the server and clients as a root authority.
However none of the clients I have tried (iphone, chrome, explorer) will send the client certificate when the server requests it, even though they all verify the server certificate fine. They all claim not to have the certificate.
When I look at the client certificate in the certificate/profile/store they all claim it is verified and legit, and all the certificates verify fine using openssl etc.
Does an SSL client certificate need a specific name or other details so that client browsers will know when to use it? Kinda of like how a server certificate has to specify the exact domain as the name on the certificate?
The server is an apache2.2 server, but I don't think its a problem on the servers end.
Client certificates must have appropriate Key Usage and Extended Key Usage extensions set. What is "appropriate" in your case, I don't know for sure but the number of variants in Key Usage is small and you can check various values yourself.
You surely haven't forgot about the private key which should be accessible on the client side, have you?
There's a summary of the key usage and extended key usage extensions to use in this document:
http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html
(Although it is for NSS, it should apply to other products.)
You could also check whether the list of accepted CAs sent by the server is configured properly. This can be seen using openssl s_client -connect the.host.name:443, for example.