Search code examples
javabouncycastlekeystoreprivate-keypublic-key

Java Key Store always ends up with null aliases


I've been trying on this for a couple of days and I'm hopelessly stuck. To fully understand how java key store works, i've been trying to create my own keystore, put some stuff inside it, then retrieve them from another program.

Here's my keystore generator :

{

    //generate a X509 certificate
    Security.addProvider(new BouncyCastleProvider());
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC");
    X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream("certificate.cer"));

    LOGGER.debug("BouncyCastle provider & X509 certificate added.");

    //generate a private & a public key
    KeyPair keyPair = generateRSAKeyPair();
    RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
    RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic();

    //generate a keystore
    KeyStore ks = KeyStore.getInstance("PKCS12");
    char[] keyStorePassword = "keystore_password".toCharArray();
    ks.load(null, keyStorePassword);
    try (FileOutputStream fos = new FileOutputStream("TestKeyStore.jks")) {
        ks.store(fos, keyStorePassword);
    }

    ks.load(new FileInputStream("TestKeyStore.jks"), keyStorePassword);

    //Symmetric key
    SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
    KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry((secretKey));
    KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(keyStorePassword);
    ks.setEntry("symmetric_key", secretKeyEntry, protectionParameter);

    //Asymmetric key
    X509Certificate[] x509Certificates = new X509Certificate[1];
    x509Certificates[0] = certificate;
    ks.setKeyEntry("asymmetric key", priv, keyStorePassword, x509Certificates);

    //certificate
    ks.setCertificateEntry("test_certif", certificate);

    Key key = ks.getKey("symmetric_key", keyStorePassword);
    System.out.println("I have this symmetric key : " + key);
    X509Certificate certificate1 = (X509Certificate) ks.getCertificate("test_certif");
    System.out.println("I have this certificate : " + certificate1);

    System.out.println(ks.aliases().nextElement());


    LOGGER.debug("all went well");
}

As you probably noticed, it's not all polished: my goal for now is only to put some stuff inside the keystore. But the point here, from the last System.out.println(ks.aliases().nextElement());, is just to see there is indeed something inside the keystore. And this is working just fine, it gives back symmetric_key.

Now, from the same folder is another class that is supposed to read from that keystore.

Note: there is no issue regarding the file (I've tested by moving its localization) so it can't be that.

KeyStore ks = KeyStore.getInstance("PKCS12");
        char[] keyStorePassword = "keystore_password".toCharArray();
        ks.load(new FileInputStream("TestKeyStore.jks"), keyStorePassword);
        System.out.println(ks.containsAlias("symmetric_key"));

This always gets me: false

If I try this: System.out.println(ks.aliases());, it's always null

If I try this:

if (!keystore.aliases().hasMoreElements()) {
    System.out.println("nothing inside the keystore");
}

it gives me back nothing inside the keystore.

Even though it's not the case in the generator.

Any clue? Thank you


Solution

  • The problem is that you are setting the entries after writing the keystore.

    If you move:

    try (FileOutputStream fos = new FileOutputStream("TestKeyStore.jks")) {
        ks.store(fos, keyStorePassword);
    }
    

    Till after this line:

    ks.setCertificateEntry("test_certif", certificate);
    

    Everything should work fine.

    Bellow you have an working example with some code removed for clarity:

    public static void main(String[] args) throws Exception{
    
        final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        final KeyPair keyPair = keyGen.genKeyPair();
    
        RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
    
        //generate a keystore
        KeyStore ks = KeyStore.getInstance("PKCS12");
        char[] keyStorePassword = PASSWORD;
        ks.load(null, keyStorePassword);
    
        X509Certificate[] chain = {generateCertificate("cn=Unknown", keyPair, 365, "SHA256withRSA")};
    
        // saving one keypair in keystore object
        ks.setKeyEntry("asymmetric key", keyPair.getPrivate(), keyStorePassword, chain);
    
        //Symmetric key
        SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
        KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry((secretKey));
        KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(keyStorePassword);
        // saving symmetric key in keystore object
        ks.setEntry("symmetric_key", secretKeyEntry, protectionParameter);
    
        // Saving our keystore object into the filesystem
        try (FileOutputStream fos = new FileOutputStream("TestKeyStore.p12")) {
            ks.store(fos, keyStorePassword);
        }
    

    // The rest of the code }

    The reason why it works in the method that saves the keystore is because the changed keystore is still in memory, but not on the filesystem. Also, since you are creating a PKCS12 keystore, I would avoid the .jks extension and go for something like .pkcs12.