certificate mechanism between webservice provider and consumer - java

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.

Related

Does this code support Mutual authentication and if yes how to trigger it?

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.

SSLHandshakeException: PKIX path building failed with Unable to find certificate chain

I am trying to Connect SSRS ReportServer with HTTPS Protocol from Java Client it's giving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: java.security.cert.CertPathBuilderException: Unable to find certificate chain
But I have added the certificate in Java Keystore, It the keystore the certificate is showing with the defined alias name.
But Same SSRS Request call is working with HTTP Protocol.
Note: We are using a wildcard certificate from Go-Daddy for secure communication
Can you verify that the certificate is added to 'Java Truststore' and not Keystore (although both have .jks extension).
Have a look at this https://docs.oracle.com/cd/E19830-01/819-4712/ablqw/index.html
Keystore file, keystore.jks, contains the Application Server’s certificate, including its private key
Truststore file, cacerts.jks, contains the Application Server’s trusted certificates
When you got your certificate, there should have been a p7b (possibly) included with it.
Essentially, when GoDaddy issues a certificate, they are not issued from the root directly.
Most likely you have one issued from an intermediate authority.
You can get the intermediate certificates at https://ssl-ccp.godaddy.com/repository?origin=CALLISTO
The certificate chain needs to be appended to the actual certificate and imported on the server.
The PEM file containing the cert being imported should look like:
<actual certificate>
<intermediate certificate>
[<intermediate certificate> ...]
After that you shouldn't have a need to do anything else on the client.
EDIT
After re-reading my answer, I realized there may be a little bit of vagueness with regard to the process. So in efforts to bring this more full cycle here we go.
Generate keypair / self-signed certificate as say PKCS#12 container.
Create PKCS#10 certificate signing request to send to GoDaddy of above certificate.
GoDaddy returns signed X.509 Certificate (typically with instructions on how to install it).
Taking the certificate (assuming PEM format) and concatenate the issuance chain from https://ssl-ccp.godaddy.com/repository?origin=CALLISTO and import that back into the PKCS#12 from step 1.
Assign the PKCS#12 as the TLS certificate store on the SSRS server.

Can't get X509 root certificate from client in Tomcat

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 ?

Using HttpClient with SSL and certificates

While I've been familiar with HTTPS and the concept of SSL, I have recently begun some development and found I am a little confused.
The requirement was that I write a small Java application that runs on a machine attached to a scanner. When a document is scanned this is picked up and the file (usually PDF) sent over the internet to our application server that will then process it. I've written the application using Apache Commons libraries and HTTPClient.
The second requirement was to connect over SSL, requiring a certificate. Following guidance on the HTTPclient page I am using AuthSSLProtocolSocketFactory from the contributions page.
The constructor can take a keystore, keystore password, truststore and truststore password. As an initial test our DBA enabled SSL on one of our development webservers and provided me with a .p12 file which when I imported into IE allows me to connect successfully.
I am a bit confused between keystores and truststores and what steps I need to take using the keytool. I tried importing the p12 into a keystore file but get the error:
keytool error: java.lang.Exception: Input not an X.509 certificate
I followed a suggestion of importing the p12 into Internet Explorer and exporting as a .cer which I can then successfully import into a keystore. When I supply this as a keystore argument of the AuthSSLProtocolSocketFactory I get a meaningless errror, but if I try it as a truststore it seems like it reads it fine but ultimately I get
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
I am unsure if I have missed some steps, I am misunderstanding SSL and mutual authentication altogether or this is mis-configuration on the server side.
Can anyone provide suggestions or point me towards resources that might help me figure this out please?
The keystore holds your private keys and associated certificates. The truststore hold the certificates that you trust and that can therefore be used for certificate path building and verification.
Here are some links that may be useful:
java.lang.Exception: Input not an X.509 certificate
Import private key and certificate into Java Key Store
Configuring Keystores and Truststores
make sure your certificate file does not have anything before and after these.
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

Java web service over https - How to add a self-signed certificate into a client api?

I have a "Hello World" web service created with axis2. I would like to write a client api which could use this service over https with a self-signed certificate. I have a self-signed certificate myCertificate.cer and a keystore containing it.
Here is my client API :
public class MyApi{
public Object callMyService(){
Axis2TestStub stub = new Axis2TestStub(
"https://localhost:8443/axis2/services/Axis2Test");
System.setProperty("javax.net.ssl.trustStore",
"src/main/resources/myKeystore.jks")
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Hello request = new Hello();
request.setMot("World");
HelloResponse response = stub.hello(request);
Object mot = response.get_return();
return mot;
It works but I would like to use myCertificate.cer and not a keystore containing it. Does someone know how to do that? I tried to override https protocol with no success :
HttpSecureProtocol myHttpsProtocol = new HttpSecureProtocol();
myHttpsProtocol .setCheckHostname(false);
myHttpsProtocol .addTrustMaterial(new TrustMaterial("myCertificate.cer"));
Protocol customHttps = new Protocol("https",
(ProtocolSocketFactory) myHttpsProtocol , 8443);
Protocol.registerProtocol("https", customHttps);
I would like to write a client api which could use this service over https with a self-signed certificate. I have a self-signed certificate myCertificate.cer and a keystore containing it.
The server key store do contain the server's self-signed certificate and private key and is used by the server to sign messages and to return credentials to the client.
On the client-side, you need to import the server certificate into the client trust store (and generally, you don't want the private key in the client trust store so you extract a stand-alone certificate file i.e. without the private key and then you import that server certificate in the trust store).
It works but I would like to use myCertificate.cer and not a keystore containing it.
It's not a key store but a trust store and adding the certificate to the client trust store is required because self-signed certificates are not signed by a root CA and are not trusted by default. So you need to create a chain of trust.
Now, you can maybe distribute the trust store in the JAR of the client API. This approach is discussed in this thread (the biggest problem being that you'll have to redistribute the JAR when the server certificate expires). Personally, I don't really like this solution.
IMHO, the good solution if you want to skip the trust store stuff would be to buy a real certificate from a widely-known certificate vendor for which you already have root CA certificates in the trust store (like Verisign, Thawte).
I would just add the certificate to the cacerts file of the JDK running your app. If you do this then you won't have to do anything else. The code you have above wouldn't be required. You add the certificate to the keystore by running a command similar to below:
C:/<jdk-version/bin/keytool -import -alias myalias -file mycert.crt -keystore C:/<jdk-version>/jre/lib/security/cacerts

Categories