4
votes

I'm trying to store a Private key and it certificate chain in a keystore and I'm getting the following error: private key algorithm does not match algorithm of public key in end entity certificate (at index 0)

This is how I generate the keypair:

public GenerateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {

    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    //Generating and ECDSA KeyPair
    ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime239v3");
    KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");

    g.initialize(ecSpec, new SecureRandom());

    KeyPair keygen = g.generateKeyPair();

    //Setting the ECDSA KeyGen
    this.keygen = keygen;
}

This is the method I use to generate the X509Certificate:

public static X509Certificate GetCertificate_v3(KeyPair keygen, Date startDate, Date expiryDate, 
        String serial,  String Certification_Aut_Id) throws InvalidKeyException, SecurityException, SignatureException{

    X509V3CertificateGenerator v3CertGen =  new X509V3CertificateGenerator();
    v3CertGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
    v3CertGen.setIssuerDN(new X509Principal("CN=" + Certification_Aut_Id + ", O=o, L=L, ST=il, C= c"));
    v3CertGen.setNotBefore(startDate);
    v3CertGen.setNotAfter(expiryDate);
    v3CertGen.setSubjectDN(new X509Principal("CN=" + Certification_Aut_Id + ", O=o, L=L, ST=il, C= c"));
    v3CertGen.setPublicKey(keygen.getPublic());
    v3CertGen.setSignatureAlgorithm("SHA256withECDSA");
    X509Certificate cert = v3CertGen.generateX509Certificate(keygen.getPrivate());

    return cert;

}

And the code use to store the keypair is:

public static void storeKeypair(String KSpwd, String PKpwd, String KSname, X509Certificate certificate, 
        KeyPair keygen, String alias, String temp_local) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException{

    //Before a keystore can be accessed, it must be loaded.
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        // get user password and file input stream
        char[] KSpassword = KSpwd.toCharArray();
        FileInputStream fis = new java.io.FileInputStream(KSname);
        ks.load(fis, KSpassword);
        fis.close();

        //writing the X509Certificate in a .cer file
        FileOutputStream fos1 = new FileOutputStream(temp_local + alias + ".cer");
        fos1.write( certificate.getEncoded() );
        fos1.flush();
        fos1.close();

    // Load the certificate chain (in X.509 DER encoding).
        FileInputStream certificateStream = new FileInputStream(temp_local + alias + ".cer");
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Certificate[] chain = {};
        chain = certificateFactory.generateCertificates(certificateStream).toArray(chain);

    // save my private key & certificate chain
        char[] PKpassword = PKpwd.toCharArray();
        ks.setEntry(alias, new KeyStore.PrivateKeyEntry(keygen.getPrivate(), chain),
                    new KeyStore.PasswordProtection(PKpassword)
                );

    //Store the KeyStore
     // Write out the keystore
        FileOutputStream fos = new FileOutputStream(KSname);
        ks.store(fos, KSpassword);
        fos.close();
}

The error generated is:

Exception in thread "main" java.lang.IllegalArgumentException: private key algorithm does not match algorithm of public key in end entity certificate (at index 0)
at java.security.KeyStore$PrivateKeyEntry.<init>(KeyStore.java:408)
at SDSGeneration.keyStore.storeKeypair(keyStore.java:65)
at FinalTest.main(FinalTest.java:70)
2
Hi guys, please really need help, can't move foward in my project without resolving this problem - Yvon Fanfe
I have tried to debug an i've got the following informations: private key algorithm : ECDSA - Entity certificate public key algoritm : SHA256WITHECDSA. I think the problem is because the two don't match, how can i make them match or someone cant provide me a Certificate generation code wich modify the Algorithm name to match with the private key name? - Yvon Fanfe
I bumped into this problem as well. It's the Bouncy Castle implementation that will match id-ecPublicKey OID from the public key with "EC" while your private key algorithm is "ECDSA", thus leading to the error. I've hacked into Bouncy Castle and modified the hard-coded value to "ECDSA", however I still have some problems. Also, openssl doesn't read the private key correctly, I don't know why. - Daniele Ricci
what is the error given by openssl? - Yvon Fanfe

2 Answers

0
votes

I faced the same problem when using the Web Crypto API. My problem was that I was using the key pair instead of the derived secret key to encrypt the messages.

You can find a complete example here

0
votes

I ran into this problem while generating VAPID keys to enable Web Push. I wanted to store the generated keys into a java keystore which requires you to have a certificate for a private key.

Changing the algorithm from ECDSA to EC made things work. Afaik EC is the algorithm to generate the key while ECDSA is a signature algorithm for EC keys.

public static KeyPair generateVapidKeyPair() throws CryptoException {
    try {
        ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime256v1");
        KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC");
        g.initialize(ecSpec, new SecureRandom());
        return g.generateKeyPair();
    } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException ex) {
        throw new CryptoException("Could not generate VAPID keypair", ex);
    }
}

After that I sign the key with the SHA256withECDSA algorithm and generate a certificate with BC. This is largely the same as with RSA so I will omit that part of the code. After that I'm able to store and retrieve the keys from the keystore (programatically with BC as provider) without any problems.