kaikramer / keystore-explorer

KeyStore Explorer is a free GUI replacement for the Java command-line utilities keytool and jarsigner.
https://keystore-explorer.org/
GNU General Public License v3.0
1.62k stars 265 forks source link

KDB support #251

Open dast835 opened 3 years ago

dast835 commented 3 years ago

KeystoreExplorer is great tool for JKS. But there is also KDB format for keystore.... And using ikeyman is realy hard. Is it possibile to add support for KDB format in KE?

kaikramer commented 3 years ago

AFAIK KDB is a proprietary IBM format. I personally have no experience at all with KDB files. Not sure how hard it would be to add support for KDB to KSE. If someone who has more experience with IBM formats is willing to do this, I am open for a PR.

jpstotz commented 1 year ago

It seems like IBM Java provides a JCE provider that implements iKeyMan KDB file support: https://help.hcltechsw.com/sametime/10.0/config/config__add_cmskdb_support_ikeyman_utility_ssl.html

Therefore if an IBM Java is installed it may be possible to load this provider (located in a JAR file named ibmcmsprovider.jar) into a non-IBM Java runtime that is executing KSE and thus provide KDB support from within KSE.

Alternatively this Java keytore implementation could be used to get an understanding of the KDB file format and a KSE re-implementation.

Edit: The idea was good, unfortunately the IBMCMSKS implementation bases on IBM proprietary classes like com.ibm.misc.BASE64Decoder (a clone of sun.misc.BASE64Encoder?) and com.ibm.security.util.DerOutputStream. So it would be necessary to implement (or load?) some additional auxiliary classes to make it work with just the ibmcmsprovider.jar file.

My current test code is:

File jarFile = new File("ibmcmsprovider.jar");
URL jarURL = jarFile.toURI().toURL();
URLClassLoader cl = new URLClassLoader(new URL[] { jarURL });
Class<?> providerClass = cl.loadClass("com.ibm.security.cmskeystore.CMSProvider");
Provider p = (Provider) providerClass.getConstructor().newInstance();

KeyStore ks = KeyStore.getInstance("IBMCMSKS", p);
System.out.println(ks.getType());

ks.load(null, new char[0]);

ks.store(new FileOutputStream("test.kdb"), new char[0]);
jpstotz commented 1 year ago

I finally figured it out. From IBM JRE/JDK two jar files are required: ibmcmsprovider.jar and ibmpkcs.jar. You you load these two JAR files into a standard OpenJDK JRE, KDB support seem to work.

It seems like the KDB KeyStore implementation has additional restrictions like empty passwords are disallowed when calling load or store (char array of size 0 or null as password).

So my final code is this:

File dir = new File(path to IBM JRE);
File jarFile1 = new File(dir, "lib/ext/ibmcmsprovider.jar");
File jarFile2 = new File(dir, "lib/ibmpkcs.jar");
URLClassLoader cl = new URLClassLoader(new URL[] { jarFile1.toURI().toURL(), jarFile2.toURI().toURL() });
Class<?> providerClass = cl.loadClass("com.ibm.security.cmskeystore.CMSProvider");
Provider p = (Provider) providerClass.getConstructor().newInstance();
KeyStore ks = KeyStore.getInstance("IBMCMSKS", p);
char[] password ="password".toCharArray(); 
ks.load(null, password);
ks.store(new FileOutputStream("test.kdb"), password);

I took the JAR files from ibm-java-sdk-8.0-7.16-x86_64 which I extracted using 7zip.

kaikramer commented 1 year ago

Nice! Now the big question is: How to integrate this into KSE? Because bundling those jars with the KSE distribution is impossible due to license restrictions.

Maybe it is time to think about a general solution for adding proprietary JCE providers. There is a feature request for supporting Luna HSMs. Other HSM manufacturers offer JCE providers as well. Those might simply work in KSE without additional code adjustments.

I could imagine a directory called "providers" where the user can add 3rd party JCE providers.

jpstotz commented 1 year ago

@kaikramer But in addition to the JAR files you still need to know the class name of the provider and the KeyStore type name(s). So an configuration file (JSON, YAML, ??) is necessary. May be also the necessary JAR files could be configured in such a file as well. This way KSE would not automatically load all JAR files in the providers directory but only those that are referenced in provider config files.

kaikramer commented 1 year ago

@jpstotz Yes, and there might be additional settings necessary for certain providers as well (like system properties, environment variables, mappings of algorithm names).