Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Java Secure Socket Extension (JSSE): multiple key entries in keystore when initializing KeyManagerFactory instance

71 views
Skip to first unread message

Perro

unread,
Feb 19, 2004, 9:47:07 AM2/19/04
to
Is it possible to have multiple key entries in the keystore used by the
KeyManagerFactory when using the reference implementation?
(SunJSSE included in J2SE 1.4.2)

I'm using keystore type "jks".
I call the init method of my KeyManagerFactory instance with the
appropriate KeyStore instance and the password of a specific key
in that keystore as parameters. This only works when all key entries
are protected by the same password. Otherwise I get the following
exception:

java.security.UnrecoverableKeyException: Cannot recover key
at sun.security.provider.KeyProtector.recover(KeyProtector.java:301)
at sun.security.provider.JavaKeyStore.engineGetKey(JavaKeyStore.java:103)
at java.security.KeyStore.getKey(KeyStore.java:289)
at com.sun.net.ssl.internal.ssl.X509KeyManagerImpl.<init>(DashoA6275)
at com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl.engineInit(DashoA6275)
at javax.net.ssl.KeyManagerFactory.init(DashoA6275)
at client.SSLClient.main(SSLClient.java:24)

Is there a way to somehow select a specific key entry in the keystore
when initializing the KeyManagerFactory instance or to have arbitrary
key entries in your keystore.

bigroddy

unread,
Jul 30, 2004, 7:11:42 AM7/30/04
to
Hello,

I know that's really bad. The API states that you have to init the
KeyManangerFactory like that "init(KeyStore ks, char[] password)" and the
password in use have to be the one for all keys with the same certificate
chain. And there is no way to select a specific key to use.

I've made a "big workaround" creating my one KeyManager class and skipping
the usage of the Jsse KeyManagerFactory.

And that's the way:
1. KeyManager class

public class OwnKeyManager
implements X509KeyManager
{
/** The parent X509KeyManager */
private final X509KeyManager mManager;
/** The KeyStore this KeyManager uses */
private final KeyStore mKeyStore;
private final String mKeyAlias;
private final String mKeyPassword;


/**
* Constructor.
*
* @param parent the parent X509KeyManager
* @param keystore the KeyStore in use
* @param keyAlias the alias for key in use
* @param keyPassword the password used for alias
*/
public OwnKeyManager (
X509KeyManager parent, KeyStore keystore,
String keyAlias, String keyPassword)
{
mManager = parent;
mKeyStore = keystore;
mKeyAlias = keyAlias;
mKeyPassword = keyPassword;
}

/**
* Gets the one alias set in constructor.
* Currently, keyType and issuers are both ignored.
*
* @param keyType the type of private key
* @param issuers the CA certificates we are narrowing
* @return the client aliases
*/
public String[] getClientAliases (
String keyType, Principal[] issuers)
{
return new String[] {mKeyAlias};
}

/**
* Gets the list of server aliases for the SSLServerSockets. Not used.
*
* @param keyType the type of private key
* @param issuers the CA certificates we are narrowing
* @return the server aliases
*/
public String[] getServerAliases (
String keyType, Principal[] issuers)
{
return mManager.getServerAliases(keyType, issuers);
}

/**
* Gets the Certificate chain for a particular alias.
*
* @param alias the client alias
* @return the CertificateChain value
*/
public X509Certificate[] getCertificateChain (
String alias)
{
assertAlias(alias);
Certificate[] chain = null;
try
{
chain = mKeyStore.getCertificateChain(alias);
}
catch (KeyStoreException kse)
{
final OwnRuntimeException cre
= new OwnRuntimeException(RteErrorCode.INTERNAL_ERROR,
kse);
cre.setTechnicalDescription(
"Unable to obtain certificate chain for alias "
+ "<" + alias + ">");
throw cre;
}
final X509Certificate[] certChain = new
X509Certificate[chain.length];
for (int i = 0; i < chain.length; i++)
{
certChain[i] = (X509Certificate) chain[i];
}
return certChain;
}

/**
* Gets the Private Key for a particular alias.
*
* @param alias the client alias
* @return the PrivateKey
*/
public PrivateKey getPrivateKey (String alias)
{
assertAlias(alias);
try
{
return (PrivateKey) mKeyStore.getKey(
alias, mKeyPassword.toCharArray());
}
catch (GeneralSecurityException gse)
{
final OwnRuntimeException cre
= new OwnRuntimeException(RteErrorCode.INTERNAL_ERROR,
gse);
cre.setTechnicalDescription(
"Unable to obtain private key for alias "
+ "<" + alias + ">");
throw cre;
}
}

/**
* Gets the alias set in constructor.
*
* @see
javax.net.ssl.X509KeyManager#chooseClientAlias(java.lang.String[],
java.security.Principal[], java.net.Socket)
*/
public String chooseClientAlias (
String[] keyType, Principal[] issuers, Socket socket)
{
return mKeyAlias;
}

/**
* Choose the server alias for the SSLServerSockets.
* This is not used.
* @see
javax.net.ssl.X509KeyManager#chooseServerAlias(java.lang.String,
java.security.Principal[], java.net.Socket)
*/
public String chooseServerAlias (
String keyType, Principal[] issuers, Socket socket)
{
return mManager.chooseServerAlias(keyType, issuers, socket);
}

/**
* Asserts that the given alias is the one set for constructor.
* @param alias the alias to assert
*/
private void assertAlias (String alias)
{
if (!alias.equals(mKeyAlias))
{
final OwnRuntimeException cre
= new OwnRuntimeException(RteErrorCode.INTERNAL_ERROR);
cre.setTechnicalDescription(
"Unexpected alias <" + alias + ">");
throw cre;
}
}
}

This OwnKeyManager returns a specific key for callback "chooseClientAlias"
and the private key you want in "getPrivateKey".

2. Use the OwnKeyManager to init SSLContext
Init the SSLContext like that:
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(getKeyManagers(), getTrustManagers(), null);

and set the TrustManager the normal way:
private TrustManager[] getTrustManagers ()
throws GeneralSecurityException
{
final TrustManagerFactory tmf
= TrustManagerFactory.getInstance(mFactoryName);
tmf.init(mKeyStore);
return tmf.getTrustManagers();
}

and here's the trick ...set the KeyManagers like here:
private KeyManager[] getKeyManagers ()
throws GeneralSecurityException
{
final OwnKeyManager manager
= new OwnKeyManager(null, mKeyStore, mKeyAlias,
mKeyPassword);
final KeyManager[] managers = {manager};
return managers;
}

This works only on client side cause we have not set a KeyManager used
inside OwnKeyManager.chooseServerAlias etc.

ok.
hope that works for you.

Rod.

bigroddy

unread,
Jul 30, 2004, 7:14:21 AM7/30/04
to
0 new messages