Background
I have a .NET console application client that consumes a Java RESTful Service with TLS Client Authentication enabled (aka Mutual Authentication).
It should be the reverse of this SSL Socket between .Net and Java with client authentication
Problem
I am always getting this error: Could not establish trust relationship for the SSL/TLS secure channel
I have no idea how to configure this correctly both on the client and server.
Steps Performed
The .NET console application is already including the CA, intermediate, and server certificates but the same error is being thrown.
I provided the server a Certificate Signing Request (CSR).
The server signed and provided a signed certificate back to me. The signed certificate is being included in the communications between the client and the server. However, the same error is being thrown.
Can anyone enlighten me on how to get a successful handshake?
This has been resolved.
Here are the steps:
Create a Certificate Signing Request (CSR).
Have the CSR signed by the server.
Get the signed certificate.
Include the signed certificate in the HTTP request.
Make sure to put the Self-Signed CA Certificate in the Local Computer's Trusted Root CA store.
Troubleshooting steps in order (do not skip if a certain step is not successful):
Test with HTTP
Test with HTTPS (one-way authentication)
Test with HTTPS (mutual authentication)
Related
I am a newbie when it comes to SSL. So I could use some expertise here regarding my situation.
I have a Java based web app that makes SSL API calls. The API and web app, both are hosted in the same server (myserver), and web app makes API calls. Now for testing purpose, we created a self signed certificate with the local domain name and server name (myserver.mydomain.local) and added to the cacerts. SSL handlshake works as desired.
But now, our client is using a CA certificate which they imported to cacerts. And during the SSL handshake, the web app client complains that the certificate issued by the
CN=abc-dns.com,OU=Root Certificate, OU=WASFarmLLLCell01, OU=WASFarmLLLCellManager01, O=IBM, C=US is not trusted; where abc-dns.com is the server name where the API is hosted through Web Sphere.
Do they need to add a self signed certificate in the trust store with the server name abc-dns.com in it to resolve the SSL handshake? Any tips will be greatly appreciated.
The public key from abc-dns.com needs to be added to the truststore of the server that is throwing the handshake exception. There are multiple ways of doing that, here's one:
https://www.ibm.com/support/knowledgecenter/SSEQTP_9.0.5/com.ibm.websphere.base.doc/ae/usec_sslretrievesignercert.html
As per my understanding,
In case of Client Authentication,
Server request the certificate from the client and then after the certificate verification handshake happens.
I just want to know, what does Server do in the certificate verification:
1) It only verifies that the certificate is valid i.e. the user is the true owner of the certificate.
2) It verifies user is the true owner of the certificate and also check the authentication and authorization.
So 1 or 2 ?
In the simple ways my question is : SSLAuthentication is part of handshake or is something which comes into picture after handshake ?
It is up to the peers if the full validation of the certificates is done before the handshake on the wire is finished or not. Usually server certificate validation is done before the handshake if finished and client certificate validation is done at least partially.
But especially in the case of client certificates it might be that the web application running at the server has additional requirements, for example that the certificate is not only signed by a specific CA but that the subject matches an existing use found in the database and maybe that the fingerprint of the certificate is as stored in the database. In this case the verification is usually only completed after the TLS handshake is finished since only then the web application specific logic is executed.
... what does Server do in the certificate verification: 1) It only verifies that the certificate is valid i.e. the user is the true owner of the certificate. 2) It verifies user is the true owner of the certificate and also check the authentication and authorization.
It is checked inside the TLS handshake that the client owns the private key to the public key in the certificate. It is commonly also checked that the certificate is signed by a trusted CA, although there might be scenarios where this check is not done and instead it is checked after the handshake that the certificate has the expected fingerprint. Authorization is usually not checked inside the TLS handshake since the TLS stack has usually no idea yet what kind of resource gets accessed and if the specific user authenticated by the certificate is authorized to access this resource.
I am using Spring Security to authenticate using an x.509 certificate, and it works only when the client certificate which is configured in the browser key-store is present in server trust-store.
How it is working currently:
I have configured the SSL client authentication as optional (server.ssl.client-auth=want , like in this post)
I have configured a server trust-store that contains all client certificates. If the certificate presented by the client is in the trust-store, the mutual SSL connection is created.
When I have the client certificate(s) present in the server-side trust-store, Firefox opens a popup with my client-side certificate(s), which I can choose and the mutual SSL connection is established.
I have configured Spring Security to extract the username from the SubjectDN of the client certificate and check it against a UserDetailsService. If a UserDetails object is returned for that username, the authentication process completes successfully
The problem is that if I remove the client-certificate from the server-side trust-store, Firefox doesn't open this popup anymore, and only a one-way SSL connection is made. Even if the Root CA cert is present in the server trust-store.
What I want:
store in the server trust-store only the certificate of a Root Certificate Authority
allow mutual SSL connection when the client presents a certificate issued by the Root CA in the server trust-store (even if the client certificate isn't present in the server trust-store)
I am also intrigued by two resources on the internet. In this tutorial on Baeldung, it says that all client certificates must be stored in the server trust-store for X.509 auth to work (which confirms my experience).
You must remember that for each user that should be verified by the server, its own certificate needs to be installed in the configured truststore. For small applications with only a few clients, this may perhaps be practicable, with an increasing number of clients it may lead to complex key-management for users.
However, this tutorial by #robinhowlett says that
The client will present its certificate in its keystore to the server, and the server will validate the client certificate’s chain using the CA certificate in the server’s truststore.
This is basically what I want to achieve, but am not able to.
Bottom line: did someone manage to store one or more Root CA certificates in the server trust-store and use client certificates issued by these Root CAs to authenticate via X.509 mutual SSL handshake in Spring Security?
I am using Spring Boot 1.5.2.RELEASE (spring-security-web 4.2.2.RELEASE). I have tested my working SSL authentication with Firefox 53.
I found my problem - I was modifying the trust-store (removing the client cert and leaving only the CA cert) while the server was up (Tomcat, in my case). But the trust-store is kept in memory and gets read only once, when the JVM is initialized (details on this ServerFault post). So trust-store changes are not being read during runtime by Tomcat.
So the answer is simple: yes, if only CA certs are present in the trust-store, during the SSL handshake the server communicates to the browser it wants client certificates issued by the trusted CAs and then the browser prompts the user to select a certificate that is issued by a trusted CA (if such a cert is present in the browser keystore).
However, if a CA is added dynamically to the server trust-store while the server is up and running, it won't be detected. The new CA will only be recognized after the server reboots (and the JVM is re-initialized).
I have written a RestFul web service running on tomcat server and a jersey 2.x rest client for interacting with the service.
The client authentication is being carried out by the method of Certificate-Based Mutual Authentication. I have configured CA certificates at server and I have a client certificate in .PEM format which I am feeding to the java client in Base64 encoded format as
base64encodedCert = new String(Files.readAllBytes(Paths.get("path/to/cert_for_clientA.base64")));
// ClientBuilder
// Client initialization
Response response = target.request().header("X-AUTH-TOKEN", base64encodedCert).accept(MediaType.APPLICATION_XML).get();
The authentication is a custom-token based type i.e.
header("X-AUTH-TOKEN", base64encodedCert).
But this authentication was not working (HTTP error 500?). So I imported the
same client certificate into servers truststore.jks using the keytool -import command and re-deployed the application and the client was successfully authenticated.
The issue is I have to update my server's truststore.jks each time a new client certificate is issued , which isn't the ideal way of doing it.
So , I was wondering if there is a way to avoid such repetitive updates in server's truststore and doing onetime setup for client certificate authentication.
**This is a project on my organizations workspace , we have our own PKI infra for issuing certificates not sure if that is going to make a difference
If so, How do you set certificate for authentication, what files do you need? is it .pfx? How would you install that in browser? Been stuck trying to test 2 way ssl through browser. I have a webservice, and trying to connect always returns certification authentication failed.
Expanding on nickrak's answer. 2-way SSL means that the client trusts the webservice, and that the webservice trusts/authenticates the client.
On the webservice side:
Add the client's CA cert into the webservice's trusted certificates. The "CN" in the webservice server certificate must match the URL of the webservice. The webservice server certificate must not be expired. The webservice may choose to do further authentication based on the client certificate...for example, is the client certificate in a "whitelist" of authorized clients. Perhaps the webservice has multiple levels of access, so the client certificate is checked to determine how much access to give the client.
On the client side:
The CA that signed the webservice server certificate will need to be added to the client's trusted certificate list. In a browser, this will be in the "Trusted Root Certification Authorities" section (IE, Chrome) or "Authorities" section (Firefox). The extensions for these certificates are usually .der, .cer, .crt, or .pem. Also, the client's own private key/certificate combination need to be added to the client browser. This will be in the "Personal" section (IE, Chrome) or "Your Certificates" (Firefox). The extensions for these keystores are usually .p12 or .pfx.
Add the client's CA's public certificate to the Trusted Root Certificate Store.
Add the client's public and private key to the browser's Personal Certificate Store. (usually a pfx, but might also be a der/pem/crt/cer.)
Navigate to page requiring certificate
Optionally, depending on browser: select the certificate you want to use for this connection.
Hopefully, success.