0
votes

I am trying to retrieve a X509Certificate which is already stored in the KeyStore using a alias and password. But I often get a null pointer exception while retrieving the private key that used to sign the certificate. It sometimes works and sometimes it doesn't. A little help will be appriciated. Thank you!

In the following code, i tried removing the condition to check whether it is PrivateKey instance or not. It doesn't work.

public X509Certificate generateCertificate(String userId, char[] password, KeyPair newKeyPair, String algorithm) throws Exception
{
    KeyPair groupManagerKeyPair = LoadKeyPair(gmPath, "EC");
    PrivateKey gmPrivateKey = groupManagerKeyPair.getPrivate();
    String dn = "CN="+userId;
    //char[] password = user.getPassword().toCharArray();
    String alias = userId;

    X509CertInfo info = new X509CertInfo();
    Date from = new Date();
    Date to = new Date(from.getTime() + 365 * 86400000l);
    CertificateValidity interval = new CertificateValidity(from, to);
    BigInteger sn = new BigInteger(64, new SecureRandom());
    X500Name owner = new X500Name(dn);

    info.set(X509CertInfo.VALIDITY, interval);
    info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
    info.set(X509CertInfo.SUBJECT, owner);
    info.set(X509CertInfo.ISSUER, owner);
    info.set(X509CertInfo.KEY, new CertificateX509Key((PublicKey) newKeyPair.getPublic()));
    info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V1));
    AlgorithmId algo = new AlgorithmId(AlgorithmId.sha256WithECDSA_oid);
    info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

    // Sign the cert to identify the algorithm that's used.
    X509CertImpl cert = new X509CertImpl(info);
    cert.sign(gmPrivateKey, algorithm);
    X509Certificate[] certificateChain = new X509Certificate[1];
    certificateChain[0] = cert;
    System.out.println("cert::"+cert);
    //save certificate into keyStore
    saveCertificateInKeyStore(alias, password, gmPrivateKey, certificateChain);

    // Update the algorithm, and resign.
    /*algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
        info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
        cert = new X509CertImpl(info);
        cert.sign(privkey, algorithm);*/
    return cert;
}



public void storeKeyAndCertificateChain(String alias, char[] password, Key key, X509Certificate[] chain) throws Exception{
    String keystore = "D:\\testkeys.jks";
    KeyStore keyStore=KeyStore.getInstance("jks");
    keyStore.load(null,null);
    keyStore.setKeyEntry(alias, key, password, chain);
    keyStore.store(new FileOutputStream(keystore),password);
}




public X509Certificate loadAndDisplayChain(String alias,char[] password) throws Exception{
    //Reload the keystore
    String keystore = "D:\\testkeys.jks";
    KeyStore keyStore=KeyStore.getInstance("jks");
    keyStore.load(new FileInputStream(keystore),password);

    Key key=keyStore.getKey(alias, password);
    X509Certificate x509Certificate = null;
    if(key instanceof PrivateKey){
        System.out.println("Get private key : ");
        System.out.println(key.toString());

        Certificate[] certs=keyStore.getCertificateChain(alias);
        System.out.println("Certificate chain length : "+certs.length);
        for(Certificate cert:certs){
            System.out.println(cert.toString());
            if(certs.length == 1)
                x509Certificate = (X509Certificate) cert;
        }
    }else{
        System.out.println("Key is not private key");
    }
    return x509Certificate;
}


I expect that it should load the certificate using the parameters.. alias and password.
1

1 Answers

0
votes

Just to be clear - in normal scenario you should use X509Certificate instance to init the SSLContext with your KeyStore using KeyManager from KeyManagerFactory and so on...

But lets say you need to check something. All you need to do is just make sure your KeyStore is initialized:

private String keystoreType = "JKS_or_PKCS12";
private String keystoreName = "path_to_keystore";
private String keystorePassword = "your_password";

@Bean
public KeyStore keyStore() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
    KeyStore keyStore = KeyStore.getInstance(keystoreType);
    try (InputStream keyStoreStream = new FileInputStream(keystoreName)) {
        keyStore.load(keyStoreStream, keystorePassword.toCharArray());
    }
    return keyStore;
}

And to get your X509Certificate instance:

public X509Certificate[] x509Certificates(KeyStore keyStore) throws KeyStoreException {
    Enumeration<String> aliases = keyStore.aliases();
    List<X509Certificate> trustedIssuers = new ArrayList<>();
    while (aliases.hasMoreElements()) {
        trustedIssuers.add((X509Certificate) keyStore.getCertificate(aliases.nextElement()));
    }
    return trustedIssuers.toArray(new X509Certificate[0]);
}

To get your private key:

public PrivateKey getPrivateKey(KeyStore keyStore, String keystorePassword, String alias) 
        throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException {
    KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,
            new KeyStore.PasswordProtection(keystorePassword.toCharArray()));
    return privateKeyEntry.getPrivateKey();
}