Before I go to the main question, I do want to state my understanding on Keystore and TrustStores:
1) Keystore - Details of key (private key) using which I would do my authentication as a server
2) Truststore - The list of root/interm CAs and other signed Certificates from different domains which I trust.
I am trying to establish an inter-server authentication and data exchange mechanism. All my servers has FQDN format as myserverX.mydomain.net where X is the index e.g. myserver1.mydomain.net. If my understanding on keystore and truststore is correct, when myserver1 is requesting data from myserver2, it's myserver1 who is client and myserver2 is server.
In this way:
1) myserver1 needs to trust myserver2 so myserver2 public key certificate should be imported into the truststore in `myserver1'.
2) The above will also be true when 'myserver1' is server and myserver2 is client - except now myserver1 public key certificate should be imported into myserver2 truststore.
Am I actually getting things right here? Or is there any fundamental mistake I am making? My intention was to try it out with self-signed certificate, and then, get a proper root CA signed certificate for my servers. But I would be grateful if someone can explain if I am making any wrong assumptions here.
Note - I am going to use Java keytool and JKS-type keystore (with default symmetric key algo and size) and I will use either -certreq and -gencert or -selfcert to generate a self signed certificate for my test.
You have it right but if you use CA-signed certificates the import step is not needed. CAs are already trusted, by definition, and therefore so are the certificates they sign. So your test is pointless.
Related
Refer http://java-buddy.blogspot.com/2016/07/java-example-of-ssl-server-and-client.html
So I have tried the same procedure of running the client and server code by passing the keystore to server and truststore for client as suggested in the above blog link.
Question 1> So i have used the same keystore at server as a truststore at client, which was generated by command 'keytool -genkey -alias signFiles -keystore examplestore'. Whats going on here ?. How does the client pick the Trusted CA from that examplestore(which is keystore for server but truststore for client) file or more appropriately how does the keystore act as truststore and what does that file exactly consist of ?.
So what i know is,
the keystore has public and private key pair along with the cert.
for cuurent scenario its not yet a signed cert by a CA.
Question 2> So we need to create that .crt file and get it signed by the CA and then again embed it within the keyStore. Embedding the crt file means importing .Is this correct understanding? What does it mean by self signing the cert ?
Does the command 'keytool -genkey -alias signFiles -keystore examplestore'
create a self signed cert ?
I also tried appending keystore for client and truststore for server which refers the same file generated by command 'keytool -genkey -alias signFiles1 -keystore examplestore1', in the arguments while running respective code. And the code ran successfully.
I also tried playing with the arguments like changing the truststore of server to something that doesn't verify the keystore of client. But still the code worked.
But the code threw following exception "javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown" when i tried changing the truststore of client that doesn't verify the server keystore.
PRIME QUESTION:
Question 3> Does this mean that its not triggering mutual authentication and if so, how to make it trigger ? And does it SUPPORT mutual authentication
in first place ?
First of all, let's clarify a few points:
A JKS file consists of entries where each entry is either a PrivateKeyEntry or trustedCertEntry. (There are other types for symmetric keys, yes, but let's forget about them while talking about public key cryptography.)
When you run genkey, you are generating a private key entry. It contains both private & public key, as you guess.
You can export only public key from a private key entry, and then import it into another JKS, which turns out to be a trusted cert entry this time, since it only contains public key.
Every generated certificate is initially self-signed. It's not self-signed only if another private key entry (of a CA) is used to sign it. A trusted cert entry may be either self-signed or CA-signed. Root CA certificates are always self-signed though.
Using a JKS as truststore means you are trusting the entries in it, whether they are self-signed or CA signed. You can create your own CA, import its public key to a JKS file and use it as your truststore. This means that you trust only the certificates that are signed (directly or indirectly) by your CA. (Indirectly means there are intermediate certificates that are signed by your CA and used again for signing other certificates.)
Now for your questions,
Q1
As stated above, using keystore as truststore means "trust the entries in it", so it works. No need to be signed by another party (i.e. CA).
Q2
"Embedding the crt file means importing .Is this correct understanding?"
Yes.
"Does the command 'keytool -genkey -alias signFiles -keystore examplestore' create a self signed cert ?"
Yes.
Regarding your trials with different keystore & truststore configurations: In a typical SSL setup, only the server has a private key and presents its certificate. Only the client verifies the server, not vice versa. If the servers were configured to ask for certificates (it's possible to do that), then you would have to select your private key while browsing https sites. It is quite uncommon to verify clients. That's why, both providing a keystore to the client and a truststore to the server has no effect. It fails only if you give an invalid truststore to the client.
Q3
SSL supports mutual authentication, yes. Check here for a good answer.
I have a Java SSL server application and I am able to communicate with its client counterpart using a self-signed certificate and key pair. This is done on my development machine.
Now, the time has come to launch the application on a live server and I have obtained my SSL certificate from an authority (LE).
I can export the signed certificate and import it into a Bouncy Castle keystore for my Android client. However, one thing got me thinking. If the certificate expires it means I'd have to update the application each time. I do not want to do this and it feels like too much work.
I was reading this page and they mentioned (Section Keys for SSL, item number 3) that simply having the CA certificate is enough to establish a connection.
[Optionally] Export the public key certificate of your private key and
distribute it to the SSL parties that will interact with you. (see
section "Export public key certificate from a keystore") If you are
using a certificate from a Certificate Authority then it will be
enough for others to have only the certificate of the Certificate
Authority itself.
I wanted to know how secure this is and what implications are there (if any).
The idea is to avoid recompiling the client application each time the certificate is renewed.
Thanks.
From what I gather, only your client is authenticating your server and not the other way around. This is one way authentication since only one of the two parties is authenticating the other. I could be wrong and you might be doing mutual authentication, but we'll get to that. First let's just consider the simpler case.
In order for your client to authenticate your server, the server needs an SSL certificate with a private key which it seems like you have. This certificate was signed by a CA certificate, which was probably signed by a Root certificate. In order for your client to trust your server, it needs a list of CA certificates which the client trusts to sign an ssl certificate. This list of certificates is your trust store. Your trust store should have the root and the CA certificate for the trusted CA.
If your server's SSL certificate expires, you will need to get a new certificate for your server. If your new certificate was signed by the same CA which signed your old certificate, the client will continue to trust your server without any updates. However, if your new certificate was signed by a CA which is unknown to your client (i.e. the CA certificate is not in the trust store), you will need to update the client's trust store with the CA and root certificates of the new certificate.
This describes one way authentication. However if your application requires mutual authentication, in addition to your client authenticating your server, your server will also need to authenticate your client. The process is exactly the same but in reverse. The client will also need an ssl certificate and the server will also need a trust store with the Root/CA certificates which signed the client's certificate. The same rules apply as when the server authenticates the client. So, if the client's ssl certificate expires and the new certificate is not known to the server's trust store, the trust store must be updated with the new CA's certificate.
One way to get around having to manually update your trust store is to automatically get new trust stores with CAs you trust. This is what your browser does. However, you will still need to update your application if a new certificate is needed.
What are the exact steps done by server and client to place a ssl certificate mechanism in a webservice call? Who(client/server/both) will generate .keystore,.p7b/.cer files? I have googled a lot but couldn't find the answer to it.
In my case, i am the client running a java application which consumes a soap webservice call. I have a .p7b file given by WebService provider. I know where to place the files(.keystore, .cer) and how to use it in the application.
But, my questions are
Do i need to generate keystore file or should i get it from
webservice provider? If i need to generate, how? Do i need private
key/passphrase?
I need a .cer file, so how can i use keytool to convert .p7b to .cer
file?
Thank you for your help in advance.
It looks like you're calling a web service where the HTTP connection is protected by TLS/SSL using X509 certificates. That means the server has set up a keystore with those certificates as well as the corresponding private keys. When you call the web service, the server will retrieve from its keystore the certificate used for the trust establishment (that is, to protect the TLS connection to the web service) and sends it to the client. When the client receives the response from the server it will check the trust of that certificate. Now we have two scenarios:
If the server uses a self-signed certificate (can be used for developments and testing, but not in production), then the client won't recognize it as trusted because it's not stored in the client's truststore. By default, in a Java environment, the truststore is searched (by order) in the following two locations: $JAVA_HOME/lib/security/jssecacerts and $JAVA_HOME/lib/security/cacerts. A custom truststore can also be used by running the client with -Djavax.net.ssl.trustStore and -Djavax.net.ssl.trustStorePassword or by using a custom TrustManager. As such, if the server self-signed certificate is not stored in one of these locations, the secure connection will fail. So the client will have to import the certificate into its truststore. To circumvent the import of self-signed certificates into the client's truststore, you can create a custom X509TrustManager as stated here.
If the server uses a certificate signed by one of the recognized root CA authorities, then it'll be validated automagically because those CA's certificates are already installed in Java's default truststore. As such, the trusted TLS connection will be successful.
In the case where the server does not require client authentication the process is over (this is what happens when you connect to most HTTPS websites via browser).
If the server requires client authentication, then the client will need to provide its own certificate from its keystore to the server, and the server will need to have it installed in its truststore. The web service provider must provide to the client the specification for the certificate profile that the client should use.
Here you can find a good clarification to the keystore vs truststore terminology.
By default in Java environments, keystores and truststores are JKS files.
So you're saying you have a .p7b file provided by the web service provider. Quoting from this page:
PKCS#7/P7B Format
The PKCS#7 or P7B format is usually stored in Base64 ASCII format and has a file extention of .p7b or .p7c. P7B certificates contain "-----BEGIN PKCS7-----" and "-----END PKCS7-----" statements. A P7B file only contains certificates and chain certificates, not the private key. Several platforms support P7B files including Microsoft Windows and Java Tomcat.
So that P7B file contains the server certificate or certificate chain (more on this here).
I believe you're in a no-client-auth scenario. Therefore, you won't need your own keystore. You'll only need to import the server's certificate (P7B file) into the truststore you're using. You can directly import a P7B file without converting it to CER format:
keytool -import -trustcacerts -alias web_service -keystore my_truststore.jks -file web_service.p7b
In the case you still want a CER formatted certificate, you can convert from P7B to CER like this (to answer to your 2nd question):
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer
If in fact client authentication is needed, then you'll need to create your keystore with your private key and public certificate and provide it to the connection by either the -Djavax.net.ssl.keyStore and -Djavax.net.ssl.keyStorePassword parameters or through a KeyManager. The same workflow previously explained applies now in the opposite direction.
I've a task to write a communicator with PKI. I think about implementation (in Java)of X.509 certificate - I mean SSL/TLS to allow for data/message confidentiality, and message authentication codes for message integrity. All about these I've read in some literature and it's all theoretical. I'm not sure if I think properly. Could anyone, who good understand idea of PKI, give me any advice (for example website where it's good explanation of implementation PKI)?
As ntoskrnl commented, this is hard to do exactly right, even by the experts.
Here is a basic high-level look at the PKI you will need for an SSL connection:
A CA root key and corresponding self-signed certificate.
An intermediate CA key and certificate signed by the CA root key (this
is optional).
A server identity key and certificate signed by either
the intermediate CA or the CA root.
A client identity key and certificate signed by some CA that the server trusts. For your
academic work, you may want this CA to be the same as the one you created. The client identity is only needed if you want to have 2-way (mutual) SSL, where the server authenticates the client.
A web service that is running on something like Tomcat that can be configured for SSL. On the server side, the identity would point to the server key certificate. For 2-way SSL, there would also be a list or keystore of trusted CA certs on the server. Unless a client's certificate was signed by one of those trusted CAs, the server would not allow the client to connect.
On the client side, you would also need a list or keystore of trusted CA certs, and the server's certificate would have to be signed by one of those CAs. The client ID key and certificate and trust keystore would be used by Java when establishing an SSL connection. If you search Stack Overflow, you should find plenty of Java SSL connection examples.
To create the PKI, OpenSSL is a good tool to use. Here is one helpful website:
https://pki-tutorial.readthedocs.org/en/latest/simple/index.html
For a key and its corresponding certificate, you first create a private key, then create a certificate signing request (CSR). The CSR is then signed by a CA key, and becomes a certificate. The certificate contains the public key that corresponds to the private key used to create the CSR.
For MAC, there's a Java example of HMAC here: HMAC-SHA1: How to do it properly in Java?
I'm trying to set up a test environment for our application that uses X.509 client authentication over HTTPS in Tomcat 6.0. The servlet code is expecting to get a certificate chain as an array of X509Certificate objects using the javax.servlet.request.X509Certificate of the servlet request. However, this array only contains a single item (the client certificate), where I'm expecting it to have two (the client certificate and the root CA certificate that signed it).
Here's what I've done so far:
Generate a self-signed CA certificate using openssl.
Import the CA certificate as a trusted root certificate into a newly create Java keystore.
Configure the Tomcat HTTPS connector to require client authentication using the keystore created in step 2 as the truststore:
clientAuth="true"
truststoreFile="<path_to_truststore>"
Generate a new client certificate using openssl and sign it with the CA certificate.
Start Tomcat.
Install the client certificate in Chrome and navigate to my server's homepage. Stepping through the code in debug, I can see that the array returned as the javax.servlet.request.X509Certificate attribute only has the client certificate.
I know that Tomcat is picking up the root CA certificate from the truststore because when I delete it from the truststore, I get an SSL connection error. It's just not making it into the servlet request like the documentation says it should. Am I missing any additional configuration here? Perhaps Tomcat (or Java or JSSE) is expecting some additional X509 V3 extensions or something?
Any help is appreciated!
EDIT
Looks like my setup is legit, and this falls into the category of unusual but expected behavior due to a simplified test environment. In an enterprise scenario it's unlikely that the root certificate authority is going to be directly signing client certificates for individual users. Clearly when this code was written and tested, there was at least one intermediate CA involved in the trust chain.
What your are seeing is what is expected: Chrome is not sending the CA.
During the TSL Handshake when authenticating the client, the server will send a list of acceptable CAs as part of its CertificateRequest Message (RFC), the browser will then present a Certificate signed by one of these CAs.
ADD
btw, a great way of debugging an SSL connection client side is to use the fantastic openssl tools
openssl s_client -connect ssl.server.com:443
or for SSLV3 only servers
openssl s_client -connect ssl.server.com:443 -ssl3
This will print (among other things) the list of acceptable CAs.
To debug the server side add this to the JVM command line -Djavax.net.debug=ssl
The identity keystore should contain the cert signed by the CA ; not the self-signed cert. The CA root should be in the truststore.
Also, what is the purpose of step 4 ?