Register / Login  |  Desktop view  |  Jump to bottom of page

General Issues » Evaluation

Author: Anonymous, Visitor
27/06/2007 04:24:55
I'm trying to use JCAPI to get the certificates out of the Microsoft Certificate Store and use them for client authentication to a Apache server.


Security.addProvider(new JCAPIProvider());
JCAPIProperties.setLogging(true);
JCAPIProperties.getInstance().setPrivateKeyExportable(true);
KeyStore jks = KeyStore.getInstance("msks", "JCAPI");
jks.load(null, null);

KeyStore ks2 = KeyStore.getInstance("msks", "JCAPI");
ks2.load(null, null);
JCAPIProperties.getInstance().setExclusiveMSCertStore(ks2,"Root");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(jks, null);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks2);
SecureRandom sr = SecureRandom.getInstance("RNG", "JCAPI");
sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);

URLConnection con = url.openConnection();
((HttpsURLConnection)con).setSSLSocketFactory(sc.getSocketFactory());
((HttpsURLConnection)con).setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
return true;
}
});


When I do this i get-

Exception in thread "main" com.pheox.jcapi.JCAPIJNIRuntimeException: Exception raised in JCAPI.DLL:
JCAPIKeyStore_getKey() - Could not acquire a key container handle.
Keyset does not exist

Error code: 0x80090016
at com.pheox.jcapi.CoreKeyStoreJNI.getKey(Native Method)
at com.pheox.jcapi.j.f(Unknown Source)
at com.pheox.jcapi.JCAPIKeyStore.engineGetKey(Unknown Source)
at java.security.KeyStore.getKey(KeyStore.java:763)
at com.sun.net.ssl.internal.ssl.SunX509KeyManagerImpl.<init>(SunX509KeyManagerImpl.java:113)
at com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl$SunX509.engineInit(KeyManagerFactoryImpl.java:4
at javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:239)
at syncadd.net.URLConnectionFactory.getCertificateURLConnection(URLConnectionFactory.java:122)
at syncadd.net.URLConnectionFactory.getCertificateURLConnection(URLConnectionFactory.java:89)
at syncadd.crypto.Card.run(Card.java:64)
at syncadd.crypto.Card.main(Card.java:101)


This exception happens on
kmf.init(jks, null);


If I get rid of the
JCAPIProperties.getInstance().setPrivateKeyExportable(true);
I get a little farther, but then I end up with-

... no IV used for this cipher
main, SEND TLSv1 ALERT: fatal, description = handshake_failure
main, WRITE: TLSv1 Alert, length = 2
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Error signing certificate verify

at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:449)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:817)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1029)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1056)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1040)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:405)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:170)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:981)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at syncadd.crypto.Card.run(Card.java:70)
at syncadd.crypto.Card.main(Card.java:101)
Caused by: java.security.InvalidKeyException: Modulus is missing
at sun.security.rsa.RSAKeyFactory.checkKey(RSAKeyFactory.java:112)
at sun.security.rsa.RSAKeyFactory.toRSAKey(RSAKeyFactory.java:76)
at com.sun.crypto.provider.RSACipher.engineGetKeySize(DashoA13*..)
at javax.crypto.Cipher.b(DashoA13*..)
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at java.security.Signature$CipherAdapter.engineInitSign(Signature.java:1202)
at java.security.Signature$Delegate.init(Signature.java:1076)
at java.security.Signature$Delegate.chooseProvider(Signature.java:1033)
at java.security.Signature$Delegate.engineInitSign(Signature.java:1106)
at java.security.Signature.initSign(Signature.java:49
at com.sun.net.ssl.internal.ssl.RSASignature.engineInitSign(RSASignature.java:10
at java.security.Signature$Delegate.engineInitSign(Signature.java:1104)
at java.security.Signature.initSign(Signature.java:49
at com.sun.net.ssl.internal.ssl.HandshakeMessage$CertificateVerify.<init>(HandshakeMessage.java:1213)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:715)
... 13 more


Any ideas?

Author: tommy, Visitor
27/06/2007 18:17:47
Hi,

Your error:

Caused by: java.security.InvalidKeyException: Modulus is missing


That error is typical to get when SUN's JSSE implementation is trying to use the private key for signing operation, but it fails since the key does not contain the private key data. Shortly it means that your private key is not exportable at all. Either your private key is stored on a hardware token, or you have imported your key into MS CAPI's container with export restrictions.

In any case, JSSE do require the data of the private key in order to successfully perform its signing operation. You can solve your issue in numerous ways, please read the following thread for advice:
http://pheox.com/posts/list/18.page

Regards,
Tommy

Author: Anonymous, Visitor
28/06/2007 06:37:24
I'm slowly starting to understand this.

So I'm trying to check to see if the Private Key is exportable from the card, but I don't think I'm doing something right. This is what I do, and it always tells me that I have no exportable keys. But it also never asks me for a pin.


Security.addProvider(new JCAPIProvider());
String keyEntryStore = JCAPIProperties.getInstance().getMSKeyEntryStoreName();
JCAPIProperties.getInstance().setMSCertStoreNames(new String[]{keyEntryStore});
JCAPIUtil.addPKCS11CSP("ActivCard", "acpkcs211.dll");
JCAPIProperties.getInstance().setPrivateKeyExportable(true);
KeyStore jks = KeyStore.getInstance("msks", "JCAPI");
jks.load(null, null);

String alias = null;
RSAPrivateKey privateKey = null;

for(java.util.Enumeration e = jks.aliases(); e.hasMoreElements(); )
{
alias = (String)e.nextElement();
if(jks.isKeyEntry(alias))
{
privateKey = (RSAPrivateKey)jks.getKey(alias, null);
if(privateKey instanceof RSAPrivateCrtKey)
break; //Ok, key found.
else
privateKey = null;
}
}
if(privateKey == null)
System.out.println("Sorry, no exportable RSA private key was found.");
else {
System.out.println("Exportable RSA key found!");
System.out.println("Alias: " + alias);
System.out.println("Key: " + privateKey);
}




When I try to access the card through a PKCS11 KeyStore, it asks me for a pin.


StringBuffer sb = new StringBuffer();
sb.append("name=ActivCard\n");
sb.append("library=c:\\Windows\\System32\\acpkcs211.dll\n");
ByteArrayInputStream bais = new ByteArrayInputStream(sb.toString().getBytes());
Provider p = new SunPKCS11(bais);
Security.addProvider(p);
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, null);


So I think I'm doing something wrong making JCAPI work with PKCS11. Any ideas?

Author: tommy, Visitor
28/06/2007 17:19:03
Hi,

There's nothing wrong with your test code. When using JCAPI, the PIN code is only required when the (non-exportable) private key is actually accessed for signing or decryption operations. In this case when you call jks.getKey(alias, null);, JCAPI will first check if the private key is exportable, and if it's not exportable then JCAPI will return a handle (in a JCAPIRSAPrivateKey instance which implements the RSAPrivateKey interface) to the key i.e JCAPI is not accessing your private during the getKey() operation.

Please note that if you're going to use JCAPI together with SUN's own implementation of trust- and key managers, then your private key must be exportable since they assume that a private key instance passed to them contains its raw private key data, they simply do not know the meaning of a key handle. SUN has also recognized this problem and thus implemented support for this in Java 6, but their solution seem to be hard coded to their own MS CAPI provider. If you want to use JCAPI with non-exportable private keys and SUN's key- and trust managers, then you'll have to wait for the JCAPI v2.0 release.

In your current situation, there are five solutions available for you (as mentioned in the thread I pointed out in my previous reply):

1. You can use the JCAPI SSL plugin which contains and uses its own trust- and key managers. Unfortunately it uses SUN's own PKCS#11 provider beneath and will thus require Java 5 or higher.
2. Use SUN's PKCS#11 provider directly and choose your own key- and trust managers. This of course will as well require Java 5 or higher.
3. Use SUN's new MS CAPI provider in (introduced in Java 6) which might solve your issue.
4. Make your private key exportable i.e import it into MS CAPI instead of your hardware token.
5. Wait for JCAPI v2.0.

Regards,
Tommy




Register / Login  |  Desktop view  |  Jump to top of page