for a PKI client I need to obtain both non-repudiation and digital signature certificates. I have implemented this code to obtain those certificates:
keyStore.load(null, null);
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keyStore.isKeyEntry(alias)) {
java.security.cert.Certificate certificate = keyStore.getCertificate(alias);
}
}
the problem is that both digital and non repudiation certificates have the same alias. so when I call keystore.getCertificate the system will always return the first result, although in the certmgr.msc window I can see that there are 2 certificates exist and the LOOP block executes two time, but the system will always return duplicate result from the first certificate. How I can solve this problem?
You cannot really have two different entries with the same alias. But this is how you can get list of all first level certificates from the key store as a list
List<Certificate> certificates = new ArrayList<Certificate>();
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Certificate certificate = keyStore.getCertificate(alias);
if (certificate != null) {
certificates.add(certificate);
}
}
Since you're talking about certmgr.msc and using keyStore.load(null, null), I presume you're using the WINDOWS-ROOT or WINDOWS-MY keystore, from the SunMSCAPI provider.
Unfortunately, there is an issue with this provider because it can re-used the same alias for multiple entries, thereby making it difficult or impossible to access some certificates.
The alias used by this keystore is in fact the "friendly name" of the certificate (in the MS-CAPI terminology). While the friendly name doesn't need to be unique in the Windows certificate store, the alias name needs to be.
Presumably, because you seem talking about two distinct certificates for the same entity but with different purposes, they're likely to use the same friendly name by default.
Once way to work around this problem is to identify your certificates with different friendly names in the Windows store: in certmgr.msc, select the certificate, right-click, choose "Properties" and change its "Friendly Name".
If you have two distinct certificates (for different key usages or any other reason) that have unique friendly names, they should show up with different alias names in your KeyStore then.
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).
The doc states:
"You will always need this password in order to access the keystore entry containing that key."
http://docs.oracle.com/javase/tutorial/security/toolsign/step3.html
But whatever keypasswd I set I can export the certificate without it, and the resulting file are all binary equal.
Why don't we need to specify the keypasswd to export the certificate?
The exported certificate is a PUBLIC KEY so it doesn't require password (Is not meant to be protected) what you actually protect is a KEYSTORE (Combination of public + private keys) that's why keytool doesn't require password for export public keys...
I have a keystore.jks file with multiple certificate including public and private key.
now i want to know how to export all public key certificate into new file all-public-cert.crt file.
This "all-public-cert.crt" file contain only certificate (public key only) . should not contain any private key in this file.
after this i would like to ready this "all-public-cert.crt" file via java code and validate public and private key using challenge response.
kindly guide me or suggest me some reference document or url.
Note : i am able to use any tool like openssl or keytool.
Thanks & Regards,
Gaurav Paliwal
Normally a keystore i.e., your keystore.jks contains private keys and the corresponding X.509 certificates. But the X.509 certificates do NOT include a private key, as you falsely assumed:
I have a keystore.jks file with multiple certificate including public and private key
This "all-public-cert.crt" file contain only certificate (public key only) . should not contain any private key in this file.
This means that your X.509 certificates do only contain public key information, no private key information.
In order to fetch a certificate form your keystore (leaving the error handling aside):
String keystorePath = ....
InputStream is = new FileInputStream(new File(keystorePath));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(is, "keystorePassword".toCharArray());
Enumeration e = ks.aliases();
Set<Certificate> certs = new HashSet<Certificate>();
while (e.hasMoreElements()) {
Certificate cert = ks.getCertificate((String) enumeration.nextElement());
certs.add(cert);
}
Now you have all certificates in your certs Set. But why do you need to put them all into the all-public-cert.crt.
1.) First you cannot put multiple certificates in one file, and hope that the one file can be used the "normal" way (e.g. double click to open it, import it into other applications, ..). The file will be garbage and can only be read from e.g., your application
2.) Therefore the file extension should not be .crt, it should be .myExportedCertificates or something like that.
I think you just want to store the certificates on the file system in order to use them afterwards. In this case simply use this code (error handling is your job):
String pathToStoreTheCerts = ...
File path = new File(pathToStoreTheCerts);
OutputStream os = null;
for (X509Certificate cert : certs) {
File certFile = new File(path, cert.getSubjectX500Principal().getName() + ".crt");
os = new FileOutputStream(certFile);
os.write(cert.getEncoded());
os.flush();
}
os.close();
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.
I've a KeyManager array and I need to get all aliases from it. So I was going to call the method String[] getClientAliases(String keyType, Principal[] issuers) of X509KeyManager interface where I put null for issuers but I don't know what I should put as keyType, since I've any information about that.
Just for information, I'm doing that to build a KeyStore object from KeyManager[] array. After getting all aliases, for each alias I call getCertificateChain and getPrivateKey, before put both results as en entry in the keyStore. Maybe you know other ways to do that.
The key types are listed in the Java™ Cryptography Architecture
Standard Algorithm Name Documentation, in a table towards the end ("Additional JSSE Standard Names"): RSA, DSA, DH_RSA, DH_DSA, EC, EC_EC and EC_RSA.
Note that you might be able to get instances of PrivateKey this way, and re-construct some instance of KeyStore, but you might not be able to save that keystore with the content of the private key in all cases. PrivateKey is a class representing a private key, with method allowing it to be used as such. It doesn't necessarily contain the private key material, for example if this is a private key obtained from a PKCS#11 hardware token.