I’m trying to use an Estonian ID card for SSL client authentication in a java program. This works in Chrome/Firefox against both banking sites and test servers (nginx or openssl s_server).
However my Java client (okhttp) works fine for a local keystore and fails when trying to use the ID card. I’ve boiled it down to this test case which reproduces the problem I see in a debugger and with logging (-Djavax.net.debug=ssl:handshake).
I can communicate with the card, e.g. I can print out the certificates for the same key. I’m piggybacking on the DigiDoc3 Client on Mac OSX.
I can see the exception that seems to cause the key to be ignored
sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ATTRIBUTE_TYPE_INVALID at sun.security.pkcs11.wrapper.PKCS11.C_GetAttributeValue(Native Method) at sun.security.pkcs11.P11Key.getAttributes(P11Key.java:275) at sun.security.pkcs11.P11Key.privateKey(P11Key.java:330) at sun.security.pkcs11.P11KeyStore.loadPkey(P11KeyStore.java:1311) at sun.security.pkcs11.P11KeyStore.engineGetEntry(P11KeyStore.java:943) at java.security.KeyStore.getEntry(KeyStore.java:1521) at sun.security.ssl.X509KeyManagerImpl.getEntry(X509KeyManagerImpl.java:276) at sun.security.ssl.X509KeyManagerImpl.getCertificateChain(X509KeyManagerImpl.java:107) at com.baulsupp.oksocial.TestMain.main(TestMain.java:37)
Test program output
1.0.Authentication ssl: KeyMgr: choosing key: Authentication (verified: OK) null null
Test code
package com.baulsupp.oksocial; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Provider; import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Enumeration; import java.util.Set; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.X509ExtendedKeyManager; public class TestMain { public static void main(String[] args) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException { System.setProperty("javax.net.debug", "all"); char[] password = System.getenv().get("PW").toCharArray();//System.console().readPassword("PW: "); X509ExtendedKeyManager km = (X509ExtendedKeyManager) getKeyManagers(password, 0)[0]; String alias = km.chooseClientAlias(new String[] {"RSA"}, null, null); System.out.println(alias); X509Certificate[] chain = km.getCertificateChain(alias); System.out.println(chain); PrivateKey key = km.getPrivateKey(alias); System.out.println(key); } public static KeyManager[] getKeyManagers(char[] password, int slot) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException { //Security.removeProvider("IAIK"); //Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); //Security.addProvider(provider); String config = "name=OpenSCnlibrary=/Applications/qdigidocclient.app/Contents/MacOS/esteid-pkcs11.sonslotListIndex=" + slot; sun.security.pkcs11.SunPKCS11 pkcs11 = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(config.getBytes())); Security.addProvider(pkcs11); //debugProviders(); KeyStore keystore = KeyStore.getInstance("PKCS11", pkcs11); keystore.load(null, password); //debugKeys(keystore); KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); kmf.init(keystore, null); return kmf.getKeyManagers(); } public static void debugKeys(KeyStore keystore) throws KeyStoreException { Enumeration<String> aliases = keystore.aliases(); while (aliases.hasMoreElements()) { String s = aliases.nextElement(); Certificate k = keystore.getCertificate(s); System.out.println(k); } } public static void debugProviders() { Provider[] providers = Security.getProviders(); for (Provider p : providers) { System.out.println("nn" + p.getName()); Set<Provider.Service> services = p.getServices(); for (Provider.Service s : services) { System.out.println(s.getType() + " " + s.getAlgorithm()); } } } }
In the mean time I’ve put in a support request as well.
Advertisement
Answer
Based solely on Martin’s answer, building https://github.com/OpenSC/OpenSC from source and installing OpenSC-0.15.0.dmg gave an alternative driver that worked first time. I didn’t use the pkcs11-spy because it just worked first time.
String config = "name=OpenSCn" + "library=/Library/OpenSC/lib/opensc-pkcs11.son";
I was able to test against openssl
$ openssl s_server -verify 20 -key key.pem -cert cert.pem -accept 44330 -no_ssl3 -dhparam dhparam.pem -www
Which responded with
--- Client certificate Certificate: Data: Version: 3 (0x2) Serial Number: xxxxxxxxx Signature Algorithm: sha256WithRSAEncryption Issuer: C=EE, O=AS Sertifitseerimiskeskus, CN=ESTEID-SK 2011/emailAddress=pki@sk.ee Validity Not Before: Jul 15 09:51:27 20xx GMT Not After : Jul 13 20:59:59 20xx GMT Subject: C=EE, O=ESTEID, OU=authentication, CN=SCHIMKE,YURI,xxxxxxxx, SN=SCHIMKE, GN=YURI/serialNumber=xxxxxxxx