From b07ec5c3f20a6b3b77a32aaa39a56f756f8585a1 Mon Sep 17 00:00:00 2001 From: Emmanuel Bourg Date: Mon, 10 Jun 2024 13:20:24 +0200 Subject: [PATCH] Fix the CKR_USER_NOT_LOGGED_IN error when signing more than one file with the YUBIKEY storetype --- README.md | 1 + .../src/test/java/net/jsign/JsignCLITest.java | 2 +- .../src/main/java/net/jsign/SignerHelper.java | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cbd5007c..3f6955fb 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ See https://ebourg.github.io/jsign for more information. * The value of the `storetype` parameter is now case insensitive * The Azure Key Vault account no longer needs the permission to list the keys when signing with jarsigner * On Windows the YubiKey library path is automatically added to the PATH of the command line tool +* Signing more than one file with the `YUBIKEY` storetype no longer triggers a `CKR_USER_NOT_LOGGED_IN` error * API changes: * The keystore builder and the JCA provider are now in a separate `jsign-crypto` module * The PEFile class has been refactored to keep only the methods related to signing diff --git a/jsign-cli/src/test/java/net/jsign/JsignCLITest.java b/jsign-cli/src/test/java/net/jsign/JsignCLITest.java index b213346d..67bc793e 100644 --- a/jsign-cli/src/test/java/net/jsign/JsignCLITest.java +++ b/jsign-cli/src/test/java/net/jsign/JsignCLITest.java @@ -371,7 +371,7 @@ public void testSigningEncryptedPEM() throws Exception { public void testSigningWithYubikey() throws Exception { Assume.assumeTrue("No Yubikey detected", YubiKey.isPresent()); - cli.execute("--storetype=YUBIKEY", "--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "--storepass=123456", "" + targetFile); + cli.execute("--storetype=YUBIKEY", "--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "--storepass=123456", "--alias=X.509 Certificate for Digital Signature", "" + targetFile, "" + targetFile); } @Test diff --git a/jsign-core/src/main/java/net/jsign/SignerHelper.java b/jsign-core/src/main/java/net/jsign/SignerHelper.java index 6f8d2d23..c5ad2334 100644 --- a/jsign-core/src/main/java/net/jsign/SignerHelper.java +++ b/jsign-core/src/main/java/net/jsign/SignerHelper.java @@ -30,6 +30,7 @@ import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Files; +import java.security.AuthProvider; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.PrivateKey; @@ -41,6 +42,9 @@ import java.util.List; import java.util.Set; import java.util.logging.Logger; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.LoginException; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.cms.ContentInfo; @@ -433,6 +437,23 @@ public void sign(File file) throws SignerException { signer = build(); } + // logout and login again to avoid the CKR_USER_NOT_LOGGED_IN error with the Yubikey PKCS#11 provider + Provider provider = ksparams.provider(); + if (provider instanceof AuthProvider) { + try { + ((AuthProvider) provider).logout(); + ((AuthProvider) provider).login(null, callbacks -> { + for (Callback callback : callbacks) { + if (callback instanceof PasswordCallback) { + ((PasswordCallback) callback).setPassword(ksparams.storepass().toCharArray()); + } + } + }); + } catch (LoginException e) { + // ignore the CKR_USER_NOT_LOGGED_IN error thrown when the user isn't logged in + } + } + log.info("Adding Authenticode signature to " + file); signer.sign(signable);