Huckle
Huckle

Reputation: 1940

Race Condition in Java 8 PKCS11 KeyStore

I've been experimenting with an SafeNet (Aladdin) eToken and Java 8's PKCS11 interface. I noticed that when I was debugging the following code snippet it would work. If I ran it without the debugger I got an exception. I introduced an artificial delay and suddenly it worked without the debugger. This leads me to believe there is a race condition in my code. Is there a better way to be doing this? Or is this specific to my token? Or is this a new bug in Java 8 x64 for debian based systems?

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();
  }
}

The exception that is thrown seems to indicate that I've not logged into the token, but I have done so. Entering the wrong PIN results in a failed login attempt.

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

With the artificial delay installed this is the result of a successful run:

$ java ... com.test.CertificteRequestTest
PKCS11 Token [SunPKCS11-PKCS11TestProvider] Password:
-----BEGIN CERTIFICATE REQUEST-----
MIICW...
-----END CERTIFICATE REQUEST-----

Upvotes: 2

Views: 1784

Answers (0)

Related Questions