From 2ef53be3e3e8244f70d2071b3c6a2e1d5a07b711 Mon Sep 17 00:00:00 2001 From: Efetobore Akpoguma Date: Tue, 28 Jan 2025 09:20:59 -0500 Subject: [PATCH 1/2] checks if the certificate file exists and fails with a clearer exception --- .../src/main/java/net/jsign/KeyStoreType.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java index fddbf5d1..6f559ea8 100644 --- a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java +++ b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java @@ -18,6 +18,7 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.net.UnknownServiceException; import java.nio.ByteBuffer; @@ -700,16 +701,21 @@ static KeyStoreType of(File path) { } } - private static Function getCertificateStore(KeyStoreBuilder params) { + private static Function getCertificateStore(KeyStoreBuilder params) throws RuntimeException { return alias -> { if (alias == null || alias.isEmpty()) { return null; } + File certificateFile = params.certfile(); try { - return CertificateUtils.loadCertificateChain(params.certfile()); - } catch (IOException | CertificateException e) { - throw new RuntimeException("Failed to load the certificate from " + params.certfile(), e); + if (!certificateFile.exists()) { + throw new FileNotFoundException("The certfile '" + certificateFile + "' could not be found"); + } + return CertificateUtils.loadCertificateChain(certificateFile); + } + catch (IOException | CertificateException e) { + throw new RuntimeException("Failed to load the certificate from '" + certificateFile + "'", e); } }; } From aabeac8622bda3ea1581efc352af8b59cd4d11fb Mon Sep 17 00:00:00 2001 From: Efetobore Akpoguma Date: Tue, 28 Jan 2025 16:55:40 -0500 Subject: [PATCH 2/2] modified the configArg to contain a comma-separated list the configArg can be null, contain just the keystore or contain both the keystore and certfile. --- .../java/net/jsign/jca/JsignJcaProvider.java | 39 +++++++++++++++--- .../net/jsign/jca/JsignJcaProviderTest.java | 40 +++++++++++++++++++ 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/jsign-crypto/src/main/java/net/jsign/jca/JsignJcaProvider.java b/jsign-crypto/src/main/java/net/jsign/jca/JsignJcaProvider.java index 0c3adfa3..f822e7b7 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/JsignJcaProvider.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/JsignJcaProvider.java @@ -63,13 +63,14 @@ public class JsignJcaProvider extends Provider { private String keystore; + private String certfile; public JsignJcaProvider() { super("Jsign", 1.0, "Jsign security provider"); AccessController.doPrivileged((PrivilegedAction) () -> { for (KeyStoreType type : KeyStoreType.values()) { - putService(new ProviderService(this, "KeyStore", type.name(), JsignJcaKeyStore.class.getName(), () -> new JsignJcaKeyStore(type, keystore))); + putService(new ProviderService(this, "KeyStore", type.name(), JsignJcaKeyStore.class.getName(), () -> new JsignJcaKeyStore(type, keystore, certfile))); } for (String alg : new String[]{"RSA", "ECDSA"}) { for (DigestAlgorithm digest : DigestAlgorithm.values()) { @@ -83,26 +84,54 @@ public JsignJcaProvider() { }); } + /** + * Creates a new JsignJcaProvider with the specified configuration. + * + * @param configArg the configuration argument. + * This should be the keystore and optionally the certificate file. + * The format is "keystore[,certfile]". + */ public JsignJcaProvider(String configArg) { this(); configure(configArg); } - public Provider configure(String configArg) throws InvalidParameterException { - this.keystore = configArg; + /** + * Configures the provider with the specified keystore. + * + * @param configArg the keystore and optionally, the certificate file. + * The format is "keystore[,certfile]". + */ + public Provider configure(final String configArg) throws InvalidParameterException { + if (configArg != null) { + final String[] config = configArg.split(","); + this.keystore = config[0].trim(); + + if (config.length == 2) { + this.certfile = config[1].trim(); + } + } return this; } + public String getKeystore() { + return keystore; + } + + public String getCertFile() { + return certfile; + } + static class JsignJcaKeyStore extends AbstractKeyStoreSpi { private KeyStoreBuilder builder = new KeyStoreBuilder(); private KeyStore keystore; - public JsignJcaKeyStore(KeyStoreType type, String keystore) { + public JsignJcaKeyStore(final KeyStoreType type, final String keystore, final String certfile) { builder.storetype(type); builder.keystore(keystore); - builder.certfile(""); + builder.certfile(certfile); } private KeyStore getKeyStore() throws KeyStoreException { diff --git a/jsign-crypto/src/test/java/net/jsign/jca/JsignJcaProviderTest.java b/jsign-crypto/src/test/java/net/jsign/jca/JsignJcaProviderTest.java index 46d3eaca..706630d8 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/JsignJcaProviderTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/JsignJcaProviderTest.java @@ -66,6 +66,46 @@ public void testKeyStoreSigningService() throws Exception { assertNotNull("Signature", signature.sign()); } + @Test + public void testJcaProviderWithKeyStoreAndCertFile() { + // Arrange + final String keystoreName = "/projects/projName/location/geoLocation/keyRings/keyRingName"; + final String certFile = "/path/to/certfile"; + + // Act + final JsignJcaProvider provider = new JsignJcaProvider(keystoreName + "," + certFile); + + // Assert + assertEquals(keystoreName, provider.getKeystore()); + assertEquals(certFile, provider.getCertFile()); + } + + @Test + public void testJcaProviderWithKeyStore() { + // Arrange + final String keystoreName = "/projects/projName/location/geoLocation/keyRings/keyRingName"; + + // Act + final JsignJcaProvider provider = new JsignJcaProvider(keystoreName); + + // Assert + assertEquals(keystoreName, provider.getKeystore()); + assertNull("certfile is not null", provider.getCertFile()); + } + + @Test + public void testJcaProviderWithNullConfigArg() { + // Arrange + final JsignJcaProvider provider = new JsignJcaProvider(); + + // Act + provider.configure(null); + + // Assert + assertNull("keystore is not null", provider.getKeystore()); + assertNull("certfile is not null", provider.getCertFile()); + } + @Test public void testKeyStorePKCS11() throws Exception { YubikeyTest.assumeYubikey();