2

I'm getting this error when I try to create a JKS file, write it to disk, then run keytool to convert it to a P12. The reason I'm going this route is because I cannot get a P12 that works for iOS in code (not a crypto person). There was enough code out there to create a JKS. To create my end credential, I'm doing this:

public X509Certificate buildEndEntityCert(PublicKey entityKey, PrivateKey caKey, X509Certificate caCert, String clientName)
        throws Exception {
    String name = "CN=" + clientName;
    X509v3CertificateBuilder certBldr = new JcaX509v3CertificateBuilder(
            caCert.getSubjectX500Principal(),
            BigInteger.ONE,
            new Date(System.currentTimeMillis()),
            new Date(System.currentTimeMillis() + VALIDITY_PERIOD),
            new X500Principal(name),
            entityKey);

    JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();

    certBldr.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert))
            .addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(entityKey))
            .addExtension(Extension.basicConstraints, false, new BasicConstraints(false))
            .addExtension(Extension.keyUsage, false, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.nonRepudiation))
            .addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth));

    ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(caKey);

    return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBldr.build(signer));
}

I call that method and create the JKS like this:

KeyPair endPair = generateRSAKeyPair(2048);
X509Certificate endCert = buildEndEntityCert(endPair.getPublic(), intermediateCredential.getPrivateKey(), intermediateCredential.getCertificate(), clientName);  // intermediateCredential and rootCredential are properties of this class that get loaded when the app starts up
X500PrivateCredential endCredential = new X500PrivateCredential(endCert, endPair.getPrivate(), clientName);

KeyStore store = KeyStore.getInstance("JKS");
store.load(null, null);
store.setKeyEntry(clientName, endCredential.getPrivateKey(), "secret".toCharArray(),
        new Certificate[]{
                endCredential.getCertificate(),
                intermediateCredential.getCertificate(),
                rootCredential.getCertificate()
        });
store.store(new FileOutputStream(clientName + ".jks"), "secret".toCharArray());

Then when I run keytool from ProcessBuilder:

"C:\\Program Files\\Java\\jdk1.7.0_80\\bin\\keytool",     
                "-importkeystore",
                "-srckeystore",
                clientName + ".jks",
                "-destkeystore",
                clientName + ".p12",
                "-srcstoretype", "JKS",
                "-deststoretype", "PKCS12",
                "-deststorepass",
                clientName,
                "-srcalias",
                clientName,
                "-destalias",
                clientName

I get:

Problem importing entry for alias CLIENT_NAME: java.security.KeyStoreException: Key protection algorithm not found: java.security.KeyStoreException: Certificate chain is not validate.

I tried searching for this but did not find much info. What does this mean or am I am doing something wrong?

halfer
  • 19,824
  • 17
  • 99
  • 186
Crystal
  • 28,460
  • 62
  • 219
  • 393
  • 1
    You've used a KPA that is available in BouncyCastle but not in JSSE, and the keytool only uses JSSE. Find a compatible KPA. – user207421 Oct 13 '17 at 23:59
  • @EJP sorry for the dumb question, but what is KPA? I got most of that code from a tutorial – Crystal Oct 14 '17 at 00:16
  • Key Protection Algorithm, as mentioned in the error message. – user207421 Oct 14 '17 at 01:02
  • @EJP: I don't see how; posted code uses BCprov to create the _cert_, but autoselect for KeyStore JKS -- and BCprov doesn't provide JKS, only SUN does. Did you really mean JSSE specifically, or JCE? Historically SunJSSE provides PKCS12 but not JKS; I don't know if this changes in j9 when pkcs12 becomes 'preferred'. – dave_thompson_085 Oct 14 '17 at 11:34
  • (0) From code it's just as easy to write P12 as JKS, as I showed [on your previous Q](https://stackoverflow.com/questions/46657809/cannot-open-pkcs12-store-because-of-password) (1) have you changed your JRE/lib/security/java.security file, or does anything in your code configure a provider other than the Sun/Oracle ones and BC? (2) if you do this more than once, issuing multiple certs from the same CA with the same serial is a very bad idea (3) extkeyusage=clientauth means SSL/TLS client which _only_ signs so keyusage other than digSign is useless ... – dave_thompson_085 Oct 14 '17 at 11:42
  • ... (4) your command doesn't include -srcstorepass which means keytool will prompt for it, but you don't indicate how you handle that prompting (5) your command does specify -deststorepass clientName which is presumably not secret (a bad idea) and different from the key password (a worse idea) (6) there's no need to specify -srcalias and -destalias for a file with only one entry. ... but none of those explain the quite weird error you got. If the problem occurs with a throwaway key can you post that file somewhere readable? – dave_thompson_085 Oct 14 '17 at 11:51

3 Answers3

4

I have the same exception, trying to programatically fill a key store.

I tracked the problem down to sun.security.pkcs12.PKCS12KeyStore

In method setKeyEntry

            if (chain != null) {
                // validate cert-chain
                if ((chain.length > 1) && (!validateChain(chain)))
                   throw new KeyStoreException("Certificate chain is " +
                                            "not valid");

Method validateChain

private boolean validateChain(Certificate[] certChain)
{
    for (int i = 0; i < certChain.length-1; i++) {
        X500Principal issuerDN =
            ((X509Certificate)certChain[i]).getIssuerX500Principal();
        X500Principal subjectDN =
            ((X509Certificate)certChain[i+1]).getSubjectX500Principal();
        if (!(issuerDN.equals(subjectDN)))
            return false;
    }


    // Check for loops in the chain. If there are repeated certs,
    // the Set of certs in the chain will contain fewer certs than
    // the chain
    Set<Certificate> set = new HashSet<>(Arrays.asList(certChain));
    return set.size() == certChain.length;
}

So check for intermediateCredential and rootCredential.

jm009
  • 61
  • 3
  • Had this problem too. It turned out that my DN was in reverse order. Fixed it using this other thread on SO. https://stackoverflow.com/questions/7567837/attributes-reversed-in-certificate-subject-and-issuer – Wytze Feb 17 '21 at 21:20
0

I would like you to the following steps (suppose the name of the jks file is abc.jks)

  1. Paste the abc.jks file in the bin folder of java where keytool.exe file is present (e.g. C:\Program Files (x86)\Java\jre1.8.0_121\bin)
  2. Run this command keytool -keystore abc.jks -list -v and enter the password
  3. Now you will need to check the following content in it A. Entry type (It should be private, if it is not a then you don't have the key) B. Certificate chain (It should be 3, if it is one then you need to import the CA certificates)

you can confirm the same in the image enter image description here

You can use the this command to convert the jks to pfx keytool -importkeystore -srckeystore abc.jks -srcstoretype jks -destkeystore xyz.pfx -deststoretype pkcs12 (I will recommend to paste the abc.jks in the bin folder of java) at the end you need to change the extension to P12

  • OP showed code with `store.setKeyEntry()`, there's no possibility they have the trustedCert-vs-privateKey mistake. – dave_thompson_085 Oct 14 '17 at 11:37
  • @dave_thompson_085, I have not mentioned that the error is related to privateKey vs trustedCert. I just wanted the user to confirm the chain length and the Entry type. He can also check the Alias name if he runs the command – rodriguesf53 Oct 16 '17 at 06:10
0

For me the order how I added the was the issue, By maintaining "leaf-> intermediate-> root" order everything was working fine

M. Gopal
  • 404
  • 4
  • 17