我一直在试验 SafeNet (Aladdin) eToken 和 Java 8 的 PKCS11 接口。我注意到,当我调试以下代码片段时,它会起作用。如果我在没有调试器的情况下运行它,我会遇到异常。我引入了人为的延迟,突然它在没有调试器的情况下工作。这让我相信我的代码中存在竞争条件。有没有更好的方法来做到这一点?或者这是否特定于我的令牌?或者这是基于 debian 的系统的 Java 8 x64 中的一个新错误?
public class CertificteRequestTest {
public static void main(String[] args) throws Exception{
KeyStore keyStore = getPKCS11Keys();
PrivateKey privateKey = (PrivateKey)keyStore.getKey("onekey",null);
PublicKey publicKey = ((KeyStore.PrivateKeyEntry)keyStore.getEntry("onekey",null)).getCertificate().getPublicKey();
X500Principal principal = new X500Principal("CN=onesubject");
PKCS10CertificationRequestBuilder builder
= new JcaPKCS10CertificationRequestBuilder(principal,publicKey);
ContentSigner signer
= new JcaContentSignerBuilder("SHA256withRSA").build(privateKey);
/* Removing this causes the Signer to think the token is not logged in */
Thread.sleep(1000);
PKCS10CertificationRequest csr = builder.build(signer);
PEMWriter writer = new PEMWriter(new PrintWriter(System.out));
writer.writeObject(csr);
writer.close();
}
public static KeyStore getPKCS11Keys() throws KeyStoreException {
SunPKCS11 provider = new SunPKCS11ProviderFactory()
.withDescription("PKCS11TestProvider - libeToken 8")
.withName("PKCS11TestProvider")
.withLibrary("/lib64/libeToken.so.8").build();
Security.addProvider(provider);
KeyStore.CallbackHandlerProtection pinHandler
= new KeyStore.CallbackHandlerProtection(new TextCallbackHandler());
return KeyStore.Builder.newInstance("PKCS11",provider,pinHandler).getKeyStore();
}
}
抛出的异常似乎表明我没有登录令牌,但我已经登录了。输入错误的 PIN 会导致登录尝试失败。
$ java ... com.test.CertificteRequestTest
PKCS11 Token [SunPKCS11-PKCS11TestProvider] Password:
Exception in thread "main" java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_USER_NOT_LOGGED_IN
at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:588)
at java.security.Signature$Delegate.engineSign(Signature.java:1162)
at java.security.Signature.sign(Signature.java:554)
at org.bouncycastle.operator.jcajce.JcaContentSignerBuilder$SignatureOutputStream.getSignature(Unknown Source)
at org.bouncycastle.operator.jcajce.JcaContentSignerBuilder$1.getSignature(Unknown Source)
at org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder.build(Unknown Source)
...
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_USER_NOT_LOGGED_IN
at sun.security.pkcs11.wrapper.PKCS11.C_Sign(Native Method)
at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:579)
安装人工延迟后,这是成功运行的结果:
$ java ... com.test.CertificteRequestTest
PKCS11 Token [SunPKCS11-PKCS11TestProvider] Password:
-----BEGIN CERTIFICATE REQUEST-----
MIICW...
-----END CERTIFICATE REQUEST-----