Skip to content
Advertisement

Need to add certificate from txt file in runtime

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);

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.

Advertisement