Client has given 2 certificates in ‘.txt’ format and I need to add these certificates during runtime while invoking the SOAP service. Unable to add ‘.txt’ format files as i am getting like ‘Invalid Format’. Certificates have “—–BEGIN CERTIFICATE—–” and “—–END CERTIFICATE—–” headers at the top and bottom of the txt file, so it’s PEM type file (I assume). Any help/suggestion would be appreciable.
Getting below exception ::
Exception in thread "main" java.io.IOException: Invalid keystore format
Using below code..
public KeyManagerFactory getKeyManagerFactory() throws UnrecoverableKeyException, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException { InputStream inputStream = null; KeyStore ts = null; KeyManagerFactory keyManagerFactory = null; try { ts = KeyStore.getInstance("JKS"); inputStream = this.getClass().getClassLoader().getResourceAsStream("publicCert.txt"); ts.load(inputStream, null); keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(ts, null); } catch (Exception e) { throw e; } finally { try { inputStream.close(); } catch (Exception e) { throw e; } } return keyManagerFactory; }
After getting the answer, used below code and it’s working
rootInterIS = new FileInputStream("rootIntermediaryCertificate.txt"); domainIS = new FileInputStream("domainCertificate.txt"); keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(null); CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); X509Certificate rootInterCert = (X509Certificate) certFactory.generateCertificate(rootInterIS); X509Certificate domainCert = (X509Certificate) certFactory.generateCertificate(domainIS); keystore.setCertificateEntry("domainCertificate", domainCert); keystore.setCertificateEntry("rootInterCe", rootInterrtificateCert); trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keystore);
Advertisement
Answer
PEM format consists of a line ----BEGIN x-----
for one or more words x
, one or more lines of base64 containing data with an internal structure matching x
, and a matching END
line. While someone could create a bogus file with correct BEGIN/END lines but wrong base64, unless they’re actively trying to cause you trouble a file that looks like you describe most likely is a PEM certificate.
A certificate (in PEM format) is not a keystore and in particular not JKS. Java supports several different keystore formats, none of which is PEM and none of which is limited to certificates. Use KeyStore.getInstance(type)
only to read a keystore, which you don’t have; use CertificateFactory.getInstance("X.509")
to read a certificate file (actually in either PEM or binary aka DER, but at the moment you only care about the former).
In SSL/TLS the KeyManager
is used only for a certificate(s) that authenticates (proves) your own identity with a privatekey, which you don’t have. Putting a certificate without privatekey as you have in a KeyManager
will be totally useless and ineffective. If someone has given you only a cert(s) not privatekey to connect to their system, that should be a cert(s) to authenticate their system, not yours; ask the supplier or look at the file(s) to confirm this. Given Java, you can use keytool -printcert -file $file
to see the details of a cert.
You need to put that cert(s) in the TrustManager
instead. Note both KeyManager
and TrustManager
use KeyStore
objects, but in different ways for different purposes. So you create an in-memory empty KeyStore
(do .getInstance(type)
then .load(null)
), add the cert from above to it as a ‘trusted’ cert, and pass that to the TrustManagerFactory
, and then use the resulting TrustManager
in your SSLContext
etc.