我正在尝试使用爱沙尼亚身份证在java程序中进行SSL客户端身份验证。这适用于针对银行网站和测试服务器(nginx或openssl s_server)的Chrome / Firefox。
但是,我的Java客户端(okhttp)适用于本地密钥库,并在尝试使用ID卡时失败。我把它归结为这个测试用例,它重现了我在调试器和日志记录中看到的问题(-Djavax.net.debug = ssl:handshake)。
我可以与卡通信,例如我可以打印出相同密钥的证书。我正在Mac OSX上搭载DigiDoc3 Client。
我可以看到似乎导致密钥被忽略的异常
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<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("\n\n" + p.getName());
Set<Provider.Service> services = p.getServices();
for (Provider.Service s : services) {
System.out.println(s.getType() + " " + s.getAlgorithm());
}
}
}
}
与此同时,我也提出了支持请求。
答案 0 :(得分:1)
AFAIK属性仅在您在PKCS#11模块中创建对象时才有意义,而智能卡则不然。尝试使用OpenSC中的pkcs11-spy来查看模块要求的类型,而不是模块实现的。
另一种选择是使用较低层的PKCS#11方法(C_ *),这样可以更好地控制PKCS#11的细节。
答案 1 :(得分:0)
完全基于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
答案 2 :(得分:0)
val config = "--name=OpenSC\nlibrary=/Library/OpenSC/lib/opensc-pkcs11.so\nslot=$slot\n"
// May fail with ProviderException with root cause like
// sun.security.pkcs11.wrapper.PKCS11Exception: CKR_SLOT_ID_INVALID
val pkcs11 = Security.getProvider("SunPKCS11").configure(config)
Security.addProvider(pkcs11)
val callbackHandler = ConsoleCallbackHandler
val builderList: List<KeyStore.Builder> = Arrays.asList(
KeyStore.Builder.newInstance("PKCS11", null, KeyStore.CallbackHandlerProtection(callbackHandler))
// Example if you want to combine multiple keystore types
// KeyStore.Builder.newInstance("PKCS12", null, File("keystore.p12"), PasswordProtection("rosebud".toCharArray()))
)
val keyManagerFactory = KeyManagerFactory.getInstance("NewSunX509")
keyManagerFactory.init(KeyStoreBuilderParameters(builderList))
val keyManager = keyManagerFactory.keyManagers[0] as X509ExtendedKeyManager