Converted PFX SSL cert throwing SSLHandshakeException? - java

I was given a PFX "wildcard" SSL certificate (I believe its a VeriSign cert) for *.ourdomain.example.org. I then used this answer to help me convert the PFX into a JKS keystore entry and add it to a JKS keystore. When I run keytool -list -keystore mykeys.jks I see:
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
<my key's long GUUID>, May 1, 2014, PrivateKeyEntry,
Certificate fingerprint (SHA1): <cert's fingerprint>
So I know the converted PFX cert is in there. But at runtime, when JNDI is using SSL to establish a connection to my AD server (over LDAPS), I am seeing the following exception:
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
I'm wondering if something got botched in the conversion from PFX to JKS. I'm pretty sure nothing else is wrong with the SSL cert, because I was using a self-signed cert before using this PFX and my browser was giving me the typical "I do not trust this certificate" warning. After I added the converted PFX and restarted my app, those warnings went away. Any ideas as to what could be going on here?

Firstly, in many cases, you don't need to convert from PKCS#12 (PFX) to JKS, many applications will let you set the keystore type to PKCS12 (instead of the default JKS), which will allow you to use your PFX file directly.
It looks like you're mixing up the usage of trust store and key store here (see this question).
Having a keystore with a certificate and its PrivateKeyEntry (here, coming from a PKCS#12 file) is normally used as a "keystore keystore" (as opposed to a keystore used as a truststore). This would normally be used for the certificate you present to your clients as a server, or the client certificate you use when connecting to a server that requests one.
Here, the "PKIX path building failed" exceptions means that your Java application doesn't trust the remote certificate it is connecting to. Presumably, your AD server has nothing to do with this JKS keystore. Rather, your server that uses your keystore is also a client to that AD server, and it cannot trust the AD server certificate.
You don't say how you've configured your application. Perhaps you've used your keystore for both the keystore and truststore settings (effectively preventing the use of the CA certificates bundled with the default JRE truststore), or perhaps your AD certificate is self-signed or not issued by a CA that is part of the default truststore. If the latter is the case, simply import the AD certificate (just the certificate, not the certificate and its private key) into the trust store (you can either do this into the JRE's cacert file or make a copy of it and use that using the javax.net.ssl.trustStore and related system properties).

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.

certificate mechanism between webservice provider and consumer

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.

Cannot create my own test certificate authority that Firefox will accept

I am following these steps to go though creating a basic CA and a server certificate that has been signed by the CA. I imported the CA cert into cacerts in the JDK and created a single entry JKS keystore containing the server's certificate. I get this error in Firefox:
Cannot communicate securely with peer: no common encryption algorithm(s).
(Error code: ssl_error_no_cypher_overlap)

How to add fingerprint to keystore

I had the following exception while writing to a SSL socket
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
It seems like the certificate of the target server is not trusted. I tested my implementation on a windows 7 machine, jdk7 and tomcat7 with no problem. The Exception is thrown on ubuntu 10 LTS with openJDK 6 and tomcat7. I got the sha1 and md5 fingerprint of the sockets target server. Am I right that the certificat of the server I am trying to stream to is not trustet on my ubuntu server? can I can the fingerprint to the tomcats keystore? If so, how do I do this?
It's not the fingerprint that you need to add to your trust store, but the actual certificate.
You can add the server certificate itself or add one of the CA certificates in the chain (if you wish to trust the all the certificates from that CA, not just that particular server).
To find out what the certificate is, you can use OpenSSL:
openssl s_client -showcerts -connect your.host.name:443
(Replace the host name and 443 by the actual ports you're using.)
The blocks between --BEGIN/END CERT...-- are the certificates in PEM format. You can check their content using openssl x509 -text -noout (and pasting each block there).
Save the certificate you want to import into a plain text file (e.g. certificate.pem). You should only import certificates that you trust. There's a certain leap of faith here. (You might want to connect with your browser and check whether the key material matches, for example.)
To import into your truststore use:
keytool -importcert -keystore truststore.jks -file certificate.pem
(You may need to specify an alias wit -alias some_name_you_choose.)
If you want this to affect your default truststore, replace truststore.jks with the path to lib/security/cacerts in your Java home directory (the default password should be changeit).
Since the target server seems to come from a well-known CA anyway (and it works with some versions of the JRE), the easiest fix is certainly to update your cacerts file manually, taking a copy from a JRE with which it works. After all, as the JSSE Reference Guide says:
IMPORTANT NOTE: The JDK ships with a limited number of trusted root
certificates in the /lib/security/cacerts file. As
documented in keytool, it is your responsibility to maintain (that is,
add/remove) the certificates contained in this file if you use this
file as a truststore.
Depending on the certificate configuration of the servers you contact,
you may need to add additional root certificate(s). Obtain the needed
specific root certificate(s) from the appropriate vendor.
It turns out it's certainly a problem with the certificate chain order (which is incorrect on this site), as shown by Qualys SSL Labs tester.

Categories