I extracted a Key and its certification chain from a JKS, and now I'm trying to add this key to the Windows Keystore using Java.
To load my JKS I did the following:
String jksPath = "D:\\mykeystore.jks";
KeyStore keystore = KeyStore.getInstance("JKS");
FileInputStream fIn = new FileInputStream(jksPath);
keystore.load(fIn, "12345678".toCharArray());
Then I get the key and the certification chain:
Key key = keystore.getKey("res1", "12345678".toCharArray());
Certificate[] cchain = keystore.getCertificateChain("res1");
So far so good, then I try to add this key to my Windows Keystore:
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
ks.setKeyEntry("myKey", key, "12345678".toCharArray(), cchain);
And BOOM:
Exception in thread "main" java.lang.ClassCastException: [Ljava.security.cert.Certificate; cannot be cast to [Ljava.security.cert.X509Certificate;
at sun.security.mscapi.KeyStore.engineSetKeyEntry(KeyStore.java:402)
at sun.security.mscapi.KeyStore$MY.engineSetKeyEntry(KeyStore.java:62)
at java.security.KeyStore.setKeyEntry(KeyStore.java:909)
Exception thrown due to the setKeyEntry call.
P.S: when I use the same syntaxe on a JKS type of Keystore no exception is thrown.
It seems there's a clumsy bit of java code in the implementation of sun.security.mscapi.KeyStore.engineSetKeyEntry(). It tries to convert an array of Certificates ("[Ljava.security.cert.Certificate", notice the prefix in the class name) to an array of X509Certificates (" [Ljava.security.cert.X509Certificate"), which is not something java ever allows you to do with a simple cast expression (e.g. see discussion of a similar mistake).
All I did in a similar situation is to pass the certificate array to the keyStore.setKeyEntry() method call as a X509Certificate array, rather than a simple Certificate array.
Related
Using java Keystore class.
InputStream keystoreStream = new FileInputStream(strKeystorePath);
KeyStore keystore = KeyStore.getInstance("JCEKS");
keystore.load(keystoreStream, strTrustStorePwd.toCharArray());
Key key = keystore.getKey(strAliasName, strTrustStorePwd.toCharArray());
The load() method is throwing keytool error:
java.io.IOException: Keystore was tampered with, or password was incorrect.
But when : use
InputStream keystoreStream = new FileInputStream(strKeystorePath);
KeyStore keystore = KeyStore.getInstance("JCEKS");
keystore.load(keystoreStream, null);
Key key = keystore.getKey(strAliasName, strTrustStorePwd.toCharArray());
it is working fine. Please see that the same passwords are used by load and getKey methods.
When the load() and getKey methods are used with passwords , the load() method is throwing error, but when load() is used with null password and getKey with same password, it is working.
JCEKS, like JKS, uses the store-level password (only) for integrity-checking the entire store; if you call .load(instream,null) it does not check integrity but still loads the contents -- or tries to: if the data has in fact been tampered with or damaged the load may fail in any number of ways, or appear to succeed but cause other problems later; but if the data is correct it does load. (Note this is not necessarily true of other keystore types, like PKCS11.)
The certificates in either JCEKS or JKS are unencrypted, and can be accessed without any (further) password. The privatekeys (if any) are individually password-encrypted, and to a access a privatekey you need to supply the correct key-level password, which can be the same as the store password or different. It is usually less confusing to make the key password(s) the same as the store password, and less confusing is usually desirable, but it is not required.
You apparently have a JCEKS whose store password differs from the value you know, but containing a key whose password matches that value. If you want to change this, after .load(instream,null) re-write it with .store(outstream,desiredpassword).
This question already has answers here:
How to avoid installing "Unlimited Strength" JCE policy files when deploying an application?
(11 answers)
Closed 4 years ago.
I am following the examples of this whitepaper
I made a method that signes the PDF using directly the KeyStore and it works great. the method signs the PDF correctly with no errors whatsoever
Now in the next example, the method is modified to use a .p12 file, and I have that method like this:
public void signp12() throws...
{
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance("pkcs12", provider.getName());
ks.load(new FileInputStream(PRIVATE), PASSWORD);
String alias = (String) ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain = ks.getCertificateChain(alias);
Proveedor app = new Proveedor();
app.firmar(SRC, String.format(DEST, 1), chain, pk, DigestAlgorithms.SHA256, provider.getName(), MakeSignature.CryptoStandard.CMS, "test1", "bla bla", PdfSignatureAppearance.NOT_CERTIFIED);
}
The method throws this exception
exception unwrapping private key - java.security.InvalidKeyException: Illegal key size
java.io.IOException
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.unwrapKey(Unknown Source)
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineLoad(Unknown Source)
at java.security.KeyStore.load(KeyStore.java:1445)
I read in this link that It can be a problem with the JavaSecurity, so I have tested the maxlengh with int maxKeyLength = Cipher.getMaxAllowedKeyLength("SHA");
And I got that the maximun length is 128.
I followed then the instructions to copy the local_policy.jar and US_export_policy.jar extracted from this file to the C:\Program Files (x86)\Java\jre6\lib\security then I recompile , I try again and get the same error and I also got the same maxlenght.
Any ideas of what is happening and how can I solve it?
I am using windows7 and JDK8
I solve it using this solution
Basically the answer where the poster makes a refelction method to remove al restrictions
I have created a pkcs12 file having a private key entry without any password.
I am able to access the p12 file using keytool utility without providing any password.
The same I am not able to to programmatically.
When I am trying like below
if( keyStore.isKeyEntry(KEYSTORE_ALIAS)) {
key = (PrivateKey) keyStore.getKey(KEYSTORE_ALIAS,new char[0]);
}
I am getting the below exception
Caused by: javax.crypto.BadPaddingException: Given final block not
properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.PKCS12PBECipherCore.implDoFinal(PKCS12PBECipherCore.java:355)
at com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndDESede.engineDoFinal(PKCS12PBECipherCore.java:387)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at sun.security.pkcs12.PKCS12KeyStore.engineGetKey(PKCS12KeyStore.java:266)
... 2 more
key = (PrivateKey) keyStore.getKey(KEYSTORE_ALIAS,new char[0]);
That's not the correct way to specify no key. Here you are specifying a zero-length key. It isn't the same thing. Try this:
key = (PrivateKey) keyStore.getKey(KEYSTORE_ALIAS, null);
I am working with digital certificate and digital signature. We got pfx file from the vendor. We convert this pfx file to java key store and used it to create the digital signature using java program. Now the vendor has etoken hardware. They give me cer file in place pf pfx. I converted cer to jks java key store and used it in my program... My program told me that private key is not there. I have found that there is no private key with cer file. I have talked to vendor about this he told me private key can not be extracted from the etoken.. you must directly access the etoken through program to get the private key. Can anybody tell me how do i access etoken programetically. Is there any java api which is used to access etoken directly. Help me....
Private key can be extracted using PKCS11.
To extract Private key from eToken in java, you need to pass config file to sun.security.pkcs11.SunPKCS11 instance.
Config file must have following properties:
name=<Name of Etoken>
slot=<slot number for etoken>
library=<path of the pckcs11 library(dll) for that etoken>
Following is sample code to extract private key using eToken
PrivateKey privateKey = null;
char password[] = "1234".toCharArray();
Provider userProvider = new sun.security.pkcs11.SunPKCS11("D:\\config.cfg");
ks = KeyStore.getInstance("PKCS11", userProvider);
ks.load(null, password);
Enumeration e = ks.aliases();
String alias=null;
while (e.hasMoreElements())
{
alias = (String) e.nextElement();
privateKey = (PrivateKey) ks.getKey(alias, password);
}
Here's my code as below:
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
String path = "<pfx file>";
char[] pass = "<password>".toCharArray();
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance("pkcs12", provider.getName());
ks.load(new FileInputStream(path), pass);
String alias = (String) ks.aliases().nextElement(); /* alias='CCA India 2011\u0000'*/
PrivateKey pk = (PrivateKey) ks.getKey(alias, pass);/* returns null */
Certificate[] chain = ks.getCertificateChain(alias);/* returns null */
X509Certificate last = (X509Certificate) chain[chain.length - 1];
System.out.println(last.getNotBefore());
System.out.println(last.getNotAfter());
}
The alias that is returned back has a \u0000 at the end of it. I am not sure what to make of it. Is that the reason why pk and chain is null? I tried to trim the alias to no avail.
I am able to import this certificate into the microsoft keystore. Meaning I am able to see it in the Internet Explorer .. Certificates. I am able to use it to sign documents on Adobe Reader. So there is no issue the pfx file. Just not able to work with it in java.
I have JCE installed as well.
I am quite sure the alias is your problem. We had similar problems with upper and lower case letters. Some Providers are case sensitive (I think BC for example) some are not (I think the sun providers) and I am not sure if they support special characters.
Have you tried the Sun "SunJSSE" Provider? It should be used by default if you do not specify BC and he supports PKCS#12. I think the provider is also a bit lenient in regards to the alias than bc. If nothing helps I would try to change the alias of the entry, maybe some microsoft tool can do this if they support this alias.