Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if X509 certificate is already in the Java Trust Store programatically?

I am developing a client GUI that accepts self signed server certificates and adds them to the trust store just like any browser would do. The problem is that my client application asks for the certificate every time it is started, in other words it does not remember that the certificate is already in the trust store. How do I implement this? This is how I am writing my trust store files:

 public void WriteTrustStore(String alias, X509Certificate c){
    char[] password = "changeit".toCharArray();
    char SEP = File.separatorChar;
    keystoreFile = new File(System.getProperty("java.home")
            + SEP + "lib" + SEP + "security" + SEP + "cacerts");
    try {
        setTrustStore(trustStore);
        FileInputStream in = new FileInputStream(keystoreFile);
        trustStore.load(in, password);
        in.close();
        trustStore.setCertificateEntry(alias, c);
        FileOutputStream out = new FileOutputStream(keystoreFile);
        trustStore.store(out, password);
        out.close();
    } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
        e.printStackTrace();
    }
}

Then I have another method where I am initializing my SSL Context and also creating dynamic alias names by doing something like:

string alias = getHostname() + "-" + getPortname();

In the end I have an alias name like:

"myhost-5001"

And then I call the WriteTrustStore(alias,certificate) method.

But in the next execution run of the program if I try to find the certificate with this alias name, I always end up getting a Null Pointer Exception.

I know that a truststore file has a property like:

trustStore.containsAlias(alias)

I tried,

if(trustStore.containsAlias(alias) == false){
     WriteTrustStore(alias, (X509Certificate) cert)
     }
     else {
           System.out.Println("Certificate already in trust store!");
     }

But still I get a Null-Pointer exception. And also I know that the certificate with alias name myhost-5001 is in the Java trust store, I crossed checked using keytool and portecle.

Thanks for your help!

like image 750
agenthost Avatar asked Oct 20 '22 05:10

agenthost


1 Answers

I figured it out, there are two ways this can be done.

First Method

I found this here: Check for trusted certificates, where you enumerate over aliases like this:

Enumeration en = keystore.aliases();
String ALIAS = "" ;

X509Certificate signingcert = null;

while (en.hasMoreElements())
{
    X509Certificate storecert = null;
    String ali = (String)en.nextElement() ;
    if(keystore.isCertificateEntry(ali))
     {
        storecert = (X509Certificate)keystore.getCertificate(ali);
        if( (storecert.getIssuerDN().getName()).equals(issuerdn))
        {
         try{
            System.out.println("Found matching issuer DN cert in keystore:\r\nChecking signature on cert ...") ;
            cert.verify(storecert.getPublicKey()) ;
            System.out.println("Signature verified on certificate") ;
            signingcert = storecert;
            break;
          }
         catch(Exception exc){
            System.out.println("Failed to verify signature on certificate with matching cert DN");
          }             
        }           
    }
    else
     if(keystore.isKeyEntry(ali))
        System.out.println(ali + "   **** key entry ****");
}

Second Method

Just create a duplicate certificate that looks in the trust store for a certificate with the alias name you are passing.

X509Certificate DuplicateCert = (X509Certificate) trustStore.getCertificate(alias);

First method is safer because you are also looking at the Issuer DN but takes longer, second method is simple and shorter.

Second method works like a charm for me, you can find the complete GUI code review here and see how I am using it: JAX-WS client SSL code review

like image 97
agenthost Avatar answered Nov 01 '22 07:11

agenthost