Java SSL客户端未选择智能卡密钥

我正在尝试使用爱沙尼亚身份证在java程序中进行SSL客户端身份validation。 这适用于针对银行网站和测试服务器(nginx或openssl s_server)的Chrome / Firefox。

但是,我的Java客户端(okhttp)适用于本地密钥库,并在尝试使用ID卡时失败。 我把它归结为这个测试用例,它重现了我在调试器和日志记录中看到的问题(-Djavax.net.debug = ssl:handshake)。

我可以与卡通信,例如我可以打印出相同密钥的证书。 我正在Mac OSX上搭载DigiDoc3客户端 。

我可以看到似乎导致密钥被忽略的exception

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) 

测试程序输出

 1.0.Authentication ssl: KeyMgr: choosing key: Authentication (verified: OK) null null 

测试代码

 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=OpenSC\nlibrary=/Applications/qdigidocclient.app/Contents/MacOS/esteid-pkcs11.so\nslotListIndex=" + 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 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("\n\n" + p.getName()); Set services = p.getServices(); for (Provider.Service s : services) { System.out.println(s.getType() + " " + s.getAlgorithm()); } } } } 

与此同时,我也提出了支持请求。

AFAIK属性仅在您在PKCS#11模块中创建对象时才有意义,而智能卡则不然。 尝试使用OpenSC中的pkcs11-spy来查看模块要求的类型和未实现的属性。

另一种选择是使用较低层的PKCS#11方法(C_ *),这可以更好地控制PKCS#11的细节。

完全基于Martin的回答,从源代码构建https://github.com/OpenSC/OpenSC并安装OpenSC-0.15.0.dmg给出了第一次工作的替代驱动程序。 我没有使用pkcs11-spy,因为它只是第一次工作。

 String config = "name=OpenSC\n" + "library=/Library/OpenSC/lib/opensc-pkcs11.so\n"; 

我能够测试openssl

 $ openssl s_server -verify 20 -key key.pem -cert cert.pem -accept 44330 -no_ssl3 -dhparam dhparam.pem -www 

哪位回应了

 --- 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