From a94e0c790e37a41cce03b649b2d737bc4c5b9951 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Fri, 7 Feb 2025 07:17:09 -0800 Subject: [PATCH 01/10] initial Venafi support --- .../src/main/java/net/jsign/JsignCLI.java | 3 +- .../src/main/java/net/jsign/KeyStoreType.java | 27 ++ .../java/net/jsign/jca/VenafiCredentials.java | 75 ++++ .../net/jsign/jca/VenafiSigningService.java | 218 ++++++++++ .../java/net/jsign/KeyStoreBuilderTest.java | 32 ++ .../net/jsign/jca/SigningServiceTest.java | 11 + .../net/jsign/jca/VenafiCredentialsTest.java | 73 ++++ .../jsign/jca/VenafiSigningServiceTest.java | 379 ++++++++++++++++++ .../services/venafi-authenticate.json | 5 + .../resources/services/venafi-keystore.json | 24 ++ .../test/resources/services/venafi-sign.json | 5 + .../src/main/java/net/jsign/JsignMojo.java | 2 +- .../share/bash-completion/completions/jsign | 2 +- 13 files changed, 853 insertions(+), 3 deletions(-) create mode 100644 jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java create mode 100644 jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java create mode 100644 jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java create mode 100644 jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java create mode 100644 jsign-crypto/src/test/resources/services/venafi-authenticate.json create mode 100644 jsign-crypto/src/test/resources/services/venafi-keystore.json create mode 100644 jsign-crypto/src/test/resources/services/venafi-sign.json diff --git a/jsign-cli/src/main/java/net/jsign/JsignCLI.java b/jsign-cli/src/main/java/net/jsign/JsignCLI.java index 9cb9c6a5..cf789215 100644 --- a/jsign-cli/src/main/java/net/jsign/JsignCLI.java +++ b/jsign-cli/src/main/java/net/jsign/JsignCLI.java @@ -96,7 +96,8 @@ public static void main(String... args) { + "- HASHICORPVAULT: HashiCorp Vault\n" + "- ORACLECLOUD: Oracle Cloud Key Management Service\n" + "- SIGNSERVER: Keyfactor SignServer\n" - + "- TRUSTEDSIGNING: Azure Trusted Signing\n").build()); + + "- TRUSTEDSIGNING: Azure Trusted Signing\n" + + "- VENAFI: Venafi CodeSign Protect\n").build()); options.addOption(Option.builder("a").hasArg().longOpt(PARAM_ALIAS).argName("NAME").desc("The alias of the certificate used for signing in the keystore").build()); options.addOption(Option.builder().hasArg().longOpt(PARAM_KEYPASS).argName("PASSWORD").desc("The password of the private key. When using a keystore, this parameter can be omitted if the keystore shares the same password").build()); options.addOption(Option.builder().hasArg().longOpt(PARAM_KEYFILE).argName("FILE").desc("The file containing the private key. PEM and PVK files are supported").type(File.class).build()); diff --git a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java index fddbf5d1..db5a3c53 100644 --- a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java +++ b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java @@ -51,6 +51,8 @@ import net.jsign.jca.SignServerCredentials; import net.jsign.jca.SignServerSigningService; import net.jsign.jca.SigningServiceJcaProvider; +import net.jsign.jca.VenafiSigningService; +import net.jsign.jca.VenafiCredentials; /** * Type of a keystore. @@ -560,6 +562,31 @@ Provider getProvider(KeyStoreBuilder params) { } }, + + VENAFI(false, false) { + @Override + void validate(KeyStoreBuilder params) { + if (params.storepass() == null || params.storepass().split("\\|").length > 2) { + throw new IllegalArgumentException("storepass " + params.parameterName() + " must specify the Venafi CodeSign Protect username/password: |"); + } + } + + @Override + Provider getProvider(KeyStoreBuilder params) { + String[] elements = params.storepass().split("\\|"); + String username = null; + String password = null; + if (elements.length == 2) { + username = elements[0]; + password = elements[1]; + } + + VenafiCredentials credentials = new VenafiCredentials(username, password, null, params.keypass()); + return new SigningServiceJcaProvider(new VenafiSigningService(params.keystore(), credentials)); + } + }, + + /** * Keyfactor SignServer. This keystore requires a Plain Signer worker, preferably configured to allow client-side * hashing (with the properties CLIENTSIDEHASHING or ALLOW_CLIENTSIDEHASHING_OVERRIDE set diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java new file mode 100644 index 00000000..26541f26 --- /dev/null +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java @@ -0,0 +1,75 @@ +/** + * Copyright 2025 Ivan Wallis + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.jsign.jca; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; + +import net.jsign.KeyStoreBuilder; + +/** + * Credentials for the Venafi CodeSign Protect. + * + * @since 7.0 + */ +public class VenafiCredentials { + + public String username; + public String password; + public KeyStore.Builder keystore; + public String sessionToken; + + public VenafiCredentials(String username, String password, String keystore, String storepass) { + this(username, password, new KeyStoreBuilder().keystore(keystore).storepass(storepass).builder()); + } + + public VenafiCredentials(String username, String password, KeyStore.Builder keystore) { + this.username = username; + this.password = password; + this.keystore = keystore; + } + + public String getSessionToken(String endpoint) throws IOException { + if (sessionToken == null) { + RESTClient client = new RESTClient(endpoint) + .errorHandler(response -> { + String errors = JsonWriter.format(response.get("Error")); + return errors; + }); + + Map request = new LinkedHashMap<>(); + request.put("client_id", "VenafiCodeSignClient"); + request.put("scope", "codesignclient"); + if (username != null && password != null) { + request.put("username", username); + request.put("password", password); + } + + Map response = client.post("/vedauth/authorize/oauth", JsonWriter.format(request)); + sessionToken = (String) response.get("access_token"); + } + + return sessionToken; + } +} diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java new file mode 100644 index 00000000..08d1c556 --- /dev/null +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -0,0 +1,218 @@ +/** + * Copyright 2025 Ivan Wallis + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.jsign.jca; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyStoreException; +import java.security.UnrecoverableKeyException; +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.ArrayList; +import java.util.Base64; +import java.util.LinkedHashMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.jsign.DigestAlgorithm; + +/** + * Signing service using the Venafi CodeSign Protect REST Service API. + * + * @since 7.0 + */ +public class VenafiSigningService implements SigningService { + + /** Cache of certificates indexed by alias */ + private final Map> certificates = new LinkedHashMap<>(); + + /** The API endpoint of the Venafi CodeSign Protect */ + private final String endpoint; + + private final RESTClient client; + + /** The credentials to authenticate with the service */ + private final VenafiCredentials credentials; + + /** The name of the Venafi CodeSign Protect certificate KeyId */ + private String KeyId; + + + /** Timeout in seconds for the signing operation */ + private long timeout = 60 * 60; // one hour + + /** Mapping between Java and OCI signing algorithms */ + private final Map algorithmMapping = new HashMap<>(); + { + algorithmMapping.put("SHA256withRSA", 64); + algorithmMapping.put("SHA384withRSA", 65); + algorithmMapping.put("SHA512withRSA", 66); + algorithmMapping.put("SHA256withECDSA", 4164); + algorithmMapping.put("SHA384withECDSA", 4165); + algorithmMapping.put("SHA512withECDSA", 4166); + } + + + /** + * Creates a new Venafi CodeSign Protect service. + * + * @param endpoint the Venafi API endpoint (for example https://demo.venafitpp.local/vedhsm/api/sign/) + * @param credentials the Venafi credentials + */ + public VenafiSigningService(String endpoint, VenafiCredentials credentials) { + this.endpoint = endpoint != null ? endpoint : "https://vh.venafilab.com"; + this.credentials = credentials; + this.client = new RESTClient(endpoint) + .authentication(conn -> conn.setRequestProperty("Authorization", "Bearer " + credentials.sessionToken)) + .errorHandler(response -> { + Map error = (Map) response.get("Error"); + return "Test"; + //Map error = (Map) response.get("Error"); + //return error.get("error_description"); + + }); + } + + void setTimeout(int timeout) { + this.timeout = timeout; + } + + @Override + public String getName() { + return "Venafi"; + } + + private void loadKeyStore(String alias) throws KeyStoreException { + if (certificates.isEmpty()) { + try { + Map request = new LinkedHashMap<>(); + request.put("EnvironmentFilter", new Integer[] { 0}); + request.put("ObjectTypeFilter", new Integer[] { 1}); + request.put("IncludeChains", true); + request.put("LabelFilter", new String[] { alias }); + + Map response = client.post("/vedhsm/api/getobjects", JsonWriter.format(request)); + + Object[] keys = (Object[]) response.get("Certificates"); + for (Object key : keys) { + String name = (String) ((Map) key).get("Label"); + KeyId = (String) ((Map) key).get("KeyId"); + certificates.put(name, (Map) key); + } + } catch (IOException e) { + throw new KeyStoreException("Unable to retrieve the Venafi keystore", e); + } + } + } + + @Override + public List aliases() throws KeyStoreException { + //loadKeyStore(); + return new ArrayList<>(certificates.keySet()); + } + + @Override + public Certificate[] getCertificateChain(String alias) throws KeyStoreException { + loadKeyStore(alias); + + Map key = certificates.get(alias); + if (key == null) { + throw new KeyStoreException("Unable to retrieve Venafi certificate '" + alias + "'"); + } + + Object[] certChain = (Object[]) key.get("Value"); + Certificate[] chain = new Certificate[certChain.length]; + + for (int i = 0; i < certChain.length; i++) { + byte[] data = decode((Object[]) certChain[i]); + + try { + chain[i] = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(data)); + } catch (CertificateException e) { + throw new KeyStoreException(e); + } + } + + return chain; + } + + @Override + public SigningServicePrivateKey getPrivateKey(String alias, char[] password) throws UnrecoverableKeyException { + try { + Certificate[] chain = getCertificateChain(alias); + String algorithm = chain[0].getPublicKey().getAlgorithm(); + return new SigningServicePrivateKey(alias, algorithm, this); + } catch (KeyStoreException k) { + throw new UnrecoverableKeyException(); + } + + } + + @Override + public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] data) throws GeneralSecurityException { + Integer clientMechanism = algorithmMapping.get(algorithm); + if (clientMechanism == null) { + throw new InvalidAlgorithmParameterException("Unsupported signing algorithm: " + clientMechanism); + } + + try { + DigestAlgorithm digestAlgorithm = DigestAlgorithm.getDefault(); + data = digestAlgorithm.getMessageDigest().digest(data); + + Map request = new HashMap<>(); + + Map clientInfo = new HashMap<>(); + clientInfo.put("ClientLibraryName", "jsign"); + clientInfo.put("ClientLibraryVersion", "7.0.0"); + + Map processInfo = new HashMap<>(); + clientInfo.put("Executable", "jsign"); + + request.put("ClientInfo", clientInfo); + request.put("ProcessInfo", processInfo); + request.put("KeyId", KeyId); + request.put("Data", Base64.getEncoder().encodeToString(data)); + request.put("ClientMechanism", clientMechanism); + request.put("Mechanism", 1); // RSA testing + + + Map response = client.post("/vedhsm/api/sign", JsonWriter.format(request)); + String status = (String) response.get("Error"); + if (status != null) { + throw new IOException("Signing operation failed: " + response.get("Error")); + } + String signature = (String) response.get("ResultData"); + return Base64.getDecoder().decode(signature); + + } catch (IOException e) { + throw new GeneralSecurityException(e); + } + } + + private byte[] decode(Object[] array) { + byte[] data = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + data[i] = ((Number) array[i]).byteValue(); + } + return data; + } +} diff --git a/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java b/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java index 7634a8a8..dcbcef69 100644 --- a/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java +++ b/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java @@ -305,6 +305,38 @@ public void testBuildGaraSign() throws Exception { assertNotNull("keystore", keystore); } + @Test + public void testBuildVenafi() throws Exception { + KeyStoreBuilder builder = new KeyStoreBuilder().storetype(VENAFI); + + Exception e = assertThrows(IllegalArgumentException.class, builder::build); + assertEquals("message", "storepass parameter must specify the Venafi username/password and/or the path to the keystore containing the TLS client certificate: |, , or ||", e.getMessage()); + + builder.storepass("username|password|keystore.p12|storepass"); + + e = assertThrows(IllegalArgumentException.class, builder::build); + assertEquals("message", "storepass parameter must specify the Venafi username/password and/or the path to the keystore containing the TLS client certificate: |, , or ||", e.getMessage()); + + builder.storepass("username|password"); + + KeyStore keystore = builder.build(); + assertNotNull("keystore", keystore); + + builder = new KeyStoreBuilder().storetype(VENAFI).keystore("https://api.garantir.io"); + builder.storepass("keystore.p12"); + + keystore = builder.build(); + assertNotNull("keystore", keystore); + + builder = new KeyStoreBuilder().storetype(VENAFI).keystore("https://api.garantir.io"); + builder.storepass("keystore.p12"); + builder.storepass("username|password|keystore.p12"); + builder.keypass("keypass"); + + keystore = builder.build(); + assertNotNull("keystore", keystore); + } + @Test public void testBuildSignServer() throws Exception { KeyStoreBuilder builder = new KeyStoreBuilder().storetype(SIGNSERVER); diff --git a/jsign-crypto/src/test/java/net/jsign/jca/SigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/SigningServiceTest.java index 830dfde9..bf1ff00b 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/SigningServiceTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/SigningServiceTest.java @@ -228,6 +228,17 @@ public void testGaraSignProvider() throws Exception { assertEquals("message", "Failed to authenticate with GaraSign: Error authenticating user", e.getCause().getMessage()); } + @Test + public void testVenafiProvider() throws Exception { + VenafiCredentials credentials = new VenafiCredentials("demo_user", "password", "target/test-classes/keystores/keystore.p12", "password"); + Provider provider = new SigningServiceJcaProvider(new VenafiSigningService(null, credentials)); + KeyStore keystore = KeyStore.getInstance("VENAFI", provider); + keystore.load(null, "".toCharArray()); + + Exception e = assertThrows(Exception.class, () -> testCustomProvider(provider, keystore, "windows_codesign", "")); + assertEquals("message", "Failed to authenticate with Venafi: Error authenticating user", e.getCause().getMessage()); + } + @Test public void testSignServerProvider() throws Exception { SignServerCredentials credentials = new SignServerCredentials("username", "password", "target/test-classes/keystores/keystore.p12", "password"); diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java new file mode 100644 index 00000000..66374e13 --- /dev/null +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java @@ -0,0 +1,73 @@ +/** + * Copyright 2025 Ivan Wallis + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.jsign.jca; + +import java.io.FileReader; +import java.io.IOException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static net.jadler.Jadler.*; +import static org.junit.Assert.*; + +public class VenafiCredentialsTest { + + @Before + public void setUp() { + initJadler().withDefaultResponseStatus(404); + } + + @After + public void tearDown() { + closeJadler(); + } + + @Test + public void testGetSessionToken() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .havingParameterEqualTo("api_version", "1.0") + .havingParameterEqualTo("username", "ebourg") + .havingParameterEqualTo("password", "123456") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/garasign-authenticate.json")); + + VenafiCredentials credentials = new VenafiCredentials("ebourg", "123456", null, null); + String sessionToken = credentials.getSessionToken("http://localhost:" + port()); + + assertEquals("session token", "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrdG11c2VyIiwibmJmIjoxNTIyMjgzNzU1LCJleHAiOjE1MjIzNzAxNTUsImVuY3J5cHRlZF9jbGFpbXMiOiJyV1Q1TlljWi83TFV1eTB3YlFnbDR5K08zbXJtS3RrOGFtdjFVSnpOYy8vM0JvaVkrai9RS0lYYTdJSGRicWIxUTVCaWNIQ2VMYWJRQjhzMWQ3ZjJBZDNKeVR6dlliS1gzVGloUThmY3RyZWRyQ21sTFZ2dDZMRFlrZ2IxbURibWVuQ1Z2VFNKbnlXWEplRzRPMGJUUXQwN1RqTHVRdGhPendQR0xXSGFhT0U1cWNSZUUzVjMzb0U0RzJ1R2duR25tSFJNZVFzUTgxQXU3bGp1c2FDR1J6enpwaTFhZmxBdHRCcjNsbThWYmdrV0VWQ3ZDNndjTlNHZXA3YzJnNG0yQzI2MzhzMml2K2hLOTFzPSJ9.kZ7ab16YLhDioc9BE0Xha9QgELXbU2GBze2x7XXALXw", sessionToken); + } + + @Test + public void testGetSessionTokenFailed() { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody("{\"requestId\": \"auth\", \"status\": \"FAILED\", \"message\": \"Error authenticating user\"}"); + + VenafiCredentials credentials = new VenafiCredentials("ebourg", "123456", null, null); + + Exception e = assertThrows(IOException.class, () -> credentials.getSessionToken("http://localhost:" + port())); + assertEquals("message", "Failed to authenticate with Venafi: Error authenticating user", e.getMessage()); + } +} diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java new file mode 100644 index 00000000..f2aaa7a5 --- /dev/null +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java @@ -0,0 +1,379 @@ +/** + * Copyright 2025 Ivan Wallis + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.jsign.jca; + +import java.io.FileReader; +import java.security.GeneralSecurityException; +import java.security.KeyStoreException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static net.jadler.Jadler.*; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +public class VenafiSigningServiceTest { + + @Before + public void setUp() { + initJadler().withDefaultResponseStatus(404); + } + + @After + public void tearDown() { + closeJadler(); + } + + @Test + public void testGetAliases() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .havingParameterEqualTo("api_version", "1.0") + .havingParameter("session_token") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + List aliases = service.aliases(); + + assertEquals("aliases", Arrays.asList("java_keystore_rsa_key", "java_keystore_ecdsa_key"), aliases); + } + + @Test + public void testGetCertificateChain() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .havingParameterEqualTo("api_version", "1.0") + .havingParameter("session_token") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + Certificate[] chain = service.getCertificateChain("java_keystore_rsa_key"); + assertNotNull("null chain", chain); + assertEquals("length", 3, chain.length); + assertEquals("subject 1", "CN=rsa_code_signer, OU=test, O=Garantir, L=San Diego, ST=CA, C=US", ((X509Certificate) chain[0]).getSubjectDN().getName()); + assertEquals("subject 2", "CN=intermediary_rsa_ca, OU=test, O=Garantir, L=San Diego, ST=CA, C=US", ((X509Certificate) chain[1]).getSubjectDN().getName()); + assertEquals("subject 3", "CN=root_rsa_ca, OU=test, O=Garantir, L=San Diego, ST=CA, C=US", ((X509Certificate) chain[2]).getSubjectDN().getName()); + } + + @Test + public void testGetCertificateChainWithInvalidAlias() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .havingParameter("session_token") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + + Exception e = assertThrows(KeyStoreException.class, () -> service.getCertificateChain("jsign")); + assertEquals("message", "Unable to retrieve Venafi certificate 'jsign'", e.getMessage()); + } + + @Test + public void testGetCertificateChainWithError() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody("{\"requestId\": \"keystore_request\", \"status\": \"FAILURE\", \"message\": \"Keystore not found\", \"sessionToken\": null}"); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + + Exception e = assertThrows(KeyStoreException.class, () -> service.getCertificateChain("java_keystore_rsa_key")); + assertEquals("message", "Unable to retrieve the Venafi keystore: Keystore not found", e.getMessage()); + } + + @Test + public void testGetCertificateChainWithHTTPError() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(502) + .withBody("Bad Gateway"); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + + Exception e = assertThrows(KeyStoreException.class, () -> service.getCertificateChain("java_keystore_rsa_key")); + assertEquals("message", "Unable to retrieve the Venafi keystore", e.getMessage()); + } + + @Test + public void testGetPrivateKey() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + + SigningServicePrivateKey key = service.getPrivateKey("java_keystore_rsa_key", null); + assertNotNull("null key", key); + assertEquals("id", "java_keystore_rsa_key", key.getId()); + assertEquals("algorithm", "RSA", key.getAlgorithm()); + } + + @Test + public void testGetPrivateKeyWithInvalidAlias() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + + Exception e = assertThrows(UnrecoverableKeyException.class, () -> service.getPrivateKey("jsign", null)); + assertEquals("message", "Unable to fetch Venafi private key for the certificate 'jsign'", e.getMessage()); + } + + @Test + public void testSignWithPolling() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/sign") + .havingParameterEqualTo("api_version", "1.0") + .havingParameter("session_token") + .havingParameter("data_to_sign") + .havingParameterEqualTo("key_name", "java_keystore_rsa_key") + .havingParameterEqualTo("signature_scheme", "SHA256withRSA") + .havingParameter("request_id", nullValue()) + .respond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}"); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/sign") + .havingParameterEqualTo("api_version", "1.0") + .havingParameter("session_token") + .havingParameter("data_to_sign", nullValue()) + .havingParameter("key_name", nullValue()) + .havingParameter("signature_scheme", nullValue()) + .havingParameterEqualTo("request_id", "60") + .respond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}") + .thenRespond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}") + .thenRespond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-sign.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); + + byte[] signature = service.sign(privateKey, "SHA256withRSA", "Hello".getBytes()); + + assertNotNull("null signature", signature); + assertEquals("length", 256, signature.length); + } + + @Test + public void testSignWithoutPolling() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/sign") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-sign.json")) + .thenRespond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"FAILED\", \"message\": \"Data to sign is missing\"}"); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); + + byte[] signature = service.sign(privateKey, "SHA256withRSA", "Hello".getBytes()); + + assertNotNull("null signature", signature); + assertEquals("length", 256, signature.length); + } + + @Test + public void testSignWithTimeout() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/sign") + .respond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}"); + + VenafiSigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + service.setTimeout(5); + SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); + + Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); + assertEquals("message", "java.io.IOException: Signing operation 60 timed out", e.getMessage()); + } + + @Test + public void testSignWithFailure() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/sign") + .respond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"FAILURE\", \"message\": \"Internal server error\"}"); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); + + Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); + assertEquals("message", "java.io.IOException: Signing operation failed: Internal server error", e.getMessage()); + } + + @Test + public void testSignWithPollingFailure() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/authenticate") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/keystore") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/sign") + .respond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}") + .thenRespond() + .withStatus(200) + .withBody("{\"requestId\": \"60\", \"status\": \"FAILURE\", \"message\": \"Internal server error\"}"); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); + + Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); + assertEquals("message", "java.io.IOException: Signing operation 60 failed: Internal server error", e.getMessage()); + } +} diff --git a/jsign-crypto/src/test/resources/services/venafi-authenticate.json b/jsign-crypto/src/test/resources/services/venafi-authenticate.json new file mode 100644 index 00000000..0adbfc4a --- /dev/null +++ b/jsign-crypto/src/test/resources/services/venafi-authenticate.json @@ -0,0 +1,5 @@ +{ + "sessionToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrdG11c2VyIiwibmJmIjoxNTIyMjgzNzU1LCJleHAiOjE1MjIzNzAxNTUsImVuY3J5cHRlZF9jbGFpbXMiOiJyV1Q1TlljWi83TFV1eTB3YlFnbDR5K08zbXJtS3RrOGFtdjFVSnpOYy8vM0JvaVkrai9RS0lYYTdJSGRicWIxUTVCaWNIQ2VMYWJRQjhzMWQ3ZjJBZDNKeVR6dlliS1gzVGloUThmY3RyZWRyQ21sTFZ2dDZMRFlrZ2IxbURibWVuQ1Z2VFNKbnlXWEplRzRPMGJUUXQwN1RqTHVRdGhPendQR0xXSGFhT0U1cWNSZUUzVjMzb0U0RzJ1R2duR25tSFJNZVFzUTgxQXU3bGp1c2FDR1J6enpwaTFhZmxBdHRCcjNsbThWYmdrV0VWQ3ZDNndjTlNHZXA3YzJnNG0yQzI2MzhzMml2K2hLOTFzPSJ9.kZ7ab16YLhDioc9BE0Xha9QgELXbU2GBze2x7XXALXw", + "requestId": "auth", + "status": "SUCCESS" +} diff --git a/jsign-crypto/src/test/resources/services/venafi-keystore.json b/jsign-crypto/src/test/resources/services/venafi-keystore.json new file mode 100644 index 00000000..285c2076 --- /dev/null +++ b/jsign-crypto/src/test/resources/services/venafi-keystore.json @@ -0,0 +1,24 @@ +{ + "keys": [ + { + "name": "java_keystore_rsa_key", + "algorithm": "RSA", + "certChain": [ + [48,-126,3,122,48,-126,2,98,-96,3,2,1,2,2,4,90,116,-44,123,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,48,110,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,28,48,26,6,3,85,4,3,12,19,105,110,116,101,114,109,101,100,105,97,114,121,95,114,115,97,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,49,52,52,48,90,23,13,50,56,48,50,48,50,50,49,49,52,52,48,90,48,106,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,24,48,22,6,3,85,4,3,12,15,114,115,97,95,99,111,100,101,95,115,105,103,110,101,114,48,-126,1,34,48,13,6,9,42,-122,72,-122,-9,13,1,1,1,5,0,3,-126,1,15,0,48,-126,1,10,2,-126,1,1,0,-19,-120,54,109,121,90,-92,6,46,-83,10,-67,-15,57,-17,18,-17,-29,-48,53,39,31,-47,-29,-26,30,-64,33,21,127,-25,77,-25,-18,72,-79,-103,-105,-73,67,57,-98,-94,-108,94,108,66,87,-17,-60,-24,42,114,-91,55,-8,-28,14,57,53,100,97,120,7,104,86,-50,-107,-51,-75,77,-16,-36,-123,-88,122,-71,70,4,110,63,-121,105,-70,29,-8,13,-123,-77,54,36,-9,-2,-44,10,-83,-48,92,-118,39,24,32,-8,10,80,90,73,107,-11,23,-63,81,-23,84,-102,23,-126,28,75,117,-39,64,83,37,97,-73,94,-40,-123,-94,122,-81,-81,-100,104,-69,22,6,13,-30,34,22,61,96,-3,16,-82,-17,79,-92,-39,-104,-107,56,-93,-19,-94,-87,49,32,113,100,30,119,91,-116,107,-67,-104,79,-84,-121,-119,33,-17,-104,10,-61,-101,-54,79,-81,-20,28,-12,-116,83,41,-98,-66,-100,57,-32,118,-122,-25,47,108,-58,-82,82,99,-62,24,-33,58,95,-56,-5,-74,-72,-58,-72,-80,2,-110,-5,-38,-30,-95,72,35,-54,-98,-95,-43,125,61,-40,33,126,85,-29,-51,88,-60,-21,110,-40,3,-96,-125,-111,1,26,84,-76,-56,125,21,46,-72,-19,97,24,105,2,3,1,0,1,-93,36,48,34,48,11,6,3,85,29,15,4,4,3,2,6,64,48,19,6,3,85,29,37,4,12,48,10,6,8,43,6,1,5,5,7,3,3,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,3,-126,1,1,0,76,-105,-58,-39,-8,16,-116,61,-106,11,-102,-73,-64,-22,118,-80,-92,-82,-77,-96,93,30,-59,-50,-96,-69,-7,55,-46,45,-42,-86,9,120,-6,-76,43,84,-123,-17,-81,-123,-30,108,-107,0,41,37,-25,68,-33,50,86,-120,12,87,106,-8,-60,-51,-41,11,10,-25,-60,61,100,-6,-6,25,55,-37,112,57,34,-71,46,-63,-29,-76,58,-80,-43,68,59,35,116,100,-76,-71,-28,-31,-64,-78,-16,100,-99,-13,6,113,-60,-110,-93,-64,83,42,-12,-72,-127,74,-13,53,-9,117,-42,10,69,69,95,20,-48,12,61,126,114,-20,-117,108,43,-2,28,-124,52,33,-49,-79,-31,-118,-24,-70,-87,-82,65,-56,-84,44,-108,-54,41,90,-94,88,-78,-24,127,-11,113,-125,52,80,19,-104,103,-16,45,29,13,-29,-25,-121,-32,75,89,37,-105,20,-79,36,-55,60,83,-11,-83,-4,54,-13,118,-119,37,60,-83,-33,-4,18,-99,-90,-114,27,81,89,35,77,-54,17,122,-105,112,-27,-62,113,39,97,-26,-127,94,-125,-97,-12,6,-128,109,-80,-98,-80,21,36,-58,23,-5,-79,93,109,103,-117,126,71,-42,61,-84,-126,-111,-127,65,12,-41,-124,-44,-12,10,67,29,83,94,64,24,-43], + [48,-126,4,114,48,-126,2,90,-96,3,2,1,2,2,4,90,116,-44,14,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,48,102,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,20,48,18,6,3,85,4,3,12,11,114,111,111,116,95,114,115,97,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,49,50,51,57,90,23,13,51,48,48,50,48,50,50,49,49,50,51,57,90,48,110,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,28,48,26,6,3,85,4,3,12,19,105,110,116,101,114,109,101,100,105,97,114,121,95,114,115,97,95,99,97,48,-126,1,34,48,13,6,9,42,-122,72,-122,-9,13,1,1,1,5,0,3,-126,1,15,0,48,-126,1,10,2,-126,1,1,0,-75,-97,-11,-55,15,67,-66,80,4,-77,27,90,66,-6,-42,52,4,-128,-62,88,75,-90,90,-92,11,-82,104,-74,-10,88,115,110,-127,59,-8,-116,12,62,-52,119,56,-10,-77,-112,-40,96,-92,19,122,62,60,-87,-19,82,40,13,108,-59,127,-12,55,-57,11,88,-88,82,66,58,-22,63,25,105,55,11,-90,-76,107,21,87,-81,-87,-20,-119,45,-8,-27,72,-23,-74,101,-58,126,20,-124,53,-108,-58,-112,53,34,-28,52,-71,-5,18,40,-101,113,-89,-63,-50,44,-61,70,-44,-5,-73,-70,-34,-122,25,32,93,-52,-120,63,108,102,61,-16,-19,-82,111,110,94,-57,53,-103,100,108,116,35,-125,-116,-124,-105,-78,-91,-49,41,29,39,-102,-76,-107,-110,14,-3,97,-74,-98,39,105,97,5,-120,-108,57,78,60,-102,10,-79,110,11,-124,-126,-12,-13,80,-125,27,36,-36,-121,99,31,-64,122,71,-87,-124,-41,119,-27,-40,89,-50,68,-41,67,-63,-5,73,-113,122,-9,-75,-78,-57,119,62,-109,87,-22,106,-81,-31,120,-120,-86,-38,-128,85,120,-28,8,-90,26,88,-19,118,92,-104,45,-27,-84,116,-26,-75,9,-23,33,24,-62,36,-11,67,-43,-86,-1,-4,58,3,-98,-101,2,3,1,0,1,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,0,48,11,6,3,85,29,15,4,4,3,2,1,70,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,3,-126,2,1,0,-127,44,-123,17,-65,29,91,-6,-37,107,72,109,103,40,16,3,-42,-31,51,-6,103,-11,-102,-81,33,32,30,-117,59,18,116,57,-59,-13,-123,50,80,125,64,98,-18,114,-28,-78,-98,-41,109,-106,14,-117,-92,94,17,-97,120,-115,5,66,98,75,-126,-59,-88,61,104,103,-119,-28,125,45,85,8,-26,42,-107,-25,-23,41,110,-18,1,-85,-7,-89,-96,19,-105,98,103,-58,-21,-116,-120,-8,-43,-4,29,92,112,75,32,-97,-94,107,-20,-67,46,-127,10,17,125,36,-96,-88,-27,19,53,112,-51,-9,90,-62,31,-66,47,77,-102,54,-64,-99,85,114,-39,4,120,-54,-92,3,-17,89,-19,109,-49,-40,117,-54,43,33,11,22,124,-21,-77,-51,-19,-98,58,2,-36,68,31,-123,-83,49,122,73,-35,-97,-108,-80,28,-88,-67,-47,32,-75,9,100,-108,-100,71,36,-80,-32,16,72,-20,96,-58,23,-68,127,-55,-126,107,-55,-126,-77,62,127,45,67,54,75,-103,-46,-34,14,49,-67,-30,-1,-75,81,71,-31,57,-87,-19,-98,-81,-127,119,98,118,57,-121,45,-1,56,-12,-20,-43,-26,75,-19,119,-75,-45,4,-41,-28,115,-47,-58,2,13,41,-103,-48,-59,-65,42,-47,-26,14,-46,-111,-72,-27,-108,-26,-57,-128,-54,109,127,39,86,105,93,46,-6,-9,72,-69,-44,6,70,13,-49,-112,47,127,125,-110,-110,-41,99,-59,63,-121,-85,-25,-4,44,-124,63,-123,-64,-15,-6,116,-96,-126,-102,-8,-73,-59,-105,89,94,-54,9,-71,-114,-38,-97,38,6,-72,67,42,119,66,-103,91,76,-55,84,-98,-6,124,113,-34,-6,-119,68,9,75,80,48,117,-74,-117,77,18,92,-46,-91,-19,99,48,-43,70,34,-72,100,-73,52,80,32,84,-59,-76,-32,-11,-41,103,54,8,-119,-122,117,82,-90,107,35,70,49,37,32,68,-34,-49,51,109,31,-24,-93,31,88,36,86,38,34,34,51,-100,12,3,87,22,47,76,-67,-29,108,-116,68,64,-37,-10,-84,-90,88,22,-77,-99,-111,6,123,16,-11,78,-64,-87,-124,60,44,-26,102,97,-121,127,-72,70,-98,-99,-114,-111,25,-65,-91,87,-116,-49,-57,-120,9,-61,7,-11,32,-55,-52,84,54,42,0,-108,83,97,-50,11,28,-81,-23,16,-127,98,63,74,-37,122,-69,38,95,-66,-28,9,-13,-42,78,-109,-67,-36,-2,-89,-21,105,35,-1,91,72,1,-68,70,61,77,-24,-127,65,125,-10,-23,48,-110,46,-4,-17,-67], + [48,-126,5,106,48,-126,3,82,-96,3,2,1,2,2,4,90,116,-45,-124,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,48,102,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,20,48,18,6,3,85,4,3,12,11,114,111,111,116,95,114,115,97,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,49,48,53,56,90,23,13,51,51,48,50,48,50,50,49,49,48,53,56,90,48,102,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,20,48,18,6,3,85,4,3,12,11,114,111,111,116,95,114,115,97,95,99,97,48,-126,2,34,48,13,6,9,42,-122,72,-122,-9,13,1,1,1,5,0,3,-126,2,15,0,48,-126,2,10,2,-126,2,1,0,-32,-47,55,118,87,70,113,108,-96,-81,-41,-125,-67,-123,-110,84,-11,-3,16,116,31,-16,-106,85,-124,115,-106,87,-53,-101,-11,15,82,-95,-99,100,77,-94,-83,-38,-55,-72,-50,27,50,-14,-49,-42,-128,-45,79,-25,-44,86,-43,-120,-34,-95,4,88,-31,-82,90,37,66,-73,-43,22,-61,-121,42,81,41,30,-47,37,-86,43,-93,-88,-117,46,29,-90,74,19,-28,-91,4,-31,94,-76,12,-1,-111,71,125,21,1,-106,-126,71,-84,25,-112,-70,-4,21,34,-25,24,119,-23,-98,73,-122,51,65,106,-110,48,49,-125,-101,-111,76,-119,-40,47,96,-78,27,-88,-17,-90,-95,47,-106,70,-41,-117,-55,-91,-35,124,-68,-113,-23,-83,5,95,-92,-4,29,-108,-103,-67,-104,-7,63,9,16,28,-101,120,61,60,91,113,117,83,-27,-64,-70,116,94,94,73,112,61,127,76,-56,-70,100,49,18,126,2,-4,66,-124,72,-127,64,74,-32,1,21,118,79,54,64,48,-1,-23,-76,-100,-3,74,91,97,14,-14,85,73,89,-72,101,51,-1,9,29,5,-26,120,-107,113,87,3,106,123,-121,60,-13,86,-95,84,-89,41,2,-40,90,122,-56,17,31,118,-78,-75,126,24,98,88,-122,-128,-50,50,-49,54,-64,-27,15,6,-104,-111,88,8,-66,-3,-33,-105,-69,-17,69,-33,119,26,-42,25,100,-6,32,18,-83,63,115,13,-68,124,91,-77,-13,98,32,-34,24,104,123,-64,-13,0,44,83,-127,15,53,88,-64,53,-124,20,10,84,-6,-28,-126,76,43,-112,117,-57,-77,-94,75,-68,-109,-54,-56,93,29,15,-102,-17,-50,-46,-74,113,-88,-60,-49,-67,-99,-28,-78,117,78,37,-51,26,-13,123,73,112,-82,-126,66,-19,-14,-89,-22,32,18,127,-20,5,112,43,94,112,75,-84,72,0,30,11,-6,-3,23,88,-51,-76,-24,101,101,-124,-16,-13,116,-46,93,21,-40,89,-53,-88,-45,58,85,-88,-31,-40,-49,119,52,-3,10,-126,-51,37,72,76,50,48,-55,-61,91,-111,-8,-63,62,-96,126,-77,89,-8,-72,-119,56,42,44,16,-11,99,-113,-64,-3,-2,81,-109,13,99,-31,67,-23,71,31,62,-112,81,102,72,51,-15,47,17,-80,-31,-57,-95,-20,95,29,-63,108,-127,-74,5,51,78,-5,-112,82,6,-87,-98,-127,65,-34,-14,-21,51,20,107,116,-127,-5,29,15,124,100,-61,-116,-81,-72,-28,-35,88,64,112,87,82,-113,-8,36,31,-43,91,-125,-62,-88,103,2,3,1,0,1,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,1,48,11,6,3,85,29,15,4,4,3,2,1,70,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,3,-126,2,1,0,77,81,109,-109,93,65,-125,49,-78,115,123,64,-37,10,47,28,55,120,115,94,47,76,5,-54,9,-17,127,115,32,-21,78,-23,58,-83,123,124,99,-35,-110,67,107,-12,-104,-73,-102,86,10,-60,-79,74,-39,21,-127,-100,-58,-118,-62,-7,-108,6,53,-55,-34,53,-117,114,18,70,25,-80,66,-30,-5,0,96,5,-39,-6,21,-25,105,-51,-101,-30,-105,70,56,-13,-43,-69,57,93,7,-62,71,-108,-89,11,37,-84,9,92,37,-76,20,38,15,-61,83,23,65,25,81,98,110,8,78,-16,27,-75,53,47,96,70,-112,-90,90,-60,-27,17,97,73,120,50,74,63,21,-20,-83,-127,85,-11,-26,47,-59,-96,-47,8,107,-38,8,70,-122,-23,-55,-86,-61,-88,-71,-51,21,-59,103,-91,-83,103,48,100,74,69,-9,-107,15,23,34,-40,-97,-98,-116,110,81,-65,97,-59,-12,-60,-124,-100,-116,34,-18,-117,-127,-105,-27,94,122,24,4,92,-126,-49,-107,58,-99,-47,-29,108,-26,124,-110,-86,-123,-101,24,-81,47,6,-114,-56,19,49,8,-54,-118,-87,-17,-71,83,-10,-2,-71,48,-95,-25,43,28,-27,45,119,-28,-36,39,-45,68,-91,73,122,-95,-46,-6,-111,-127,41,79,-23,-38,-78,-10,86,-56,23,-4,-67,96,-74,-37,-89,120,49,-66,94,63,-58,66,-84,-45,66,39,105,92,-3,-27,107,-62,83,-94,-74,-4,-126,103,-41,55,-56,-112,122,98,-118,-40,-1,-3,40,88,-75,-123,-106,91,25,67,-10,-28,16,-82,-101,30,82,49,73,24,-78,-49,-79,-11,-125,120,-80,-43,44,-31,-51,83,-63,-33,93,-79,-117,46,26,-38,45,-75,34,-92,-90,48,88,-92,-64,-68,60,27,-9,-99,76,-7,-53,-29,-117,64,65,-46,-94,-38,-31,78,-85,121,-84,106,89,81,13,-49,-40,36,-17,27,2,78,115,-41,45,71,114,99,12,23,-55,60,52,32,-79,-65,19,80,48,-41,52,-35,64,-20,109,-72,118,123,4,-66,-80,-84,-90,22,-119,107,107,31,46,-1,108,105,-73,18,55,20,104,90,-128,66,-61,112,47,45,-34,74,40,6,-37,93,85,100,56,-125,-88,-85,-1,102,48,-75,-46,21,80,94,11,-67,-31,-15,40,-74,-30,116,-127,-100,27,-12,-64,95,-121,-68,51,98,0,73,-115,-110,56,-64,-5,117,41,50,91,59,-100,6,124,63,-33,-23,-64,7,25,-40,36,41,-32,20,-72,-48,-82,-107,118,1,-102,71,105,-98,13,107,38,-103,95,-46,82] + ] + }, + { + "name": "java_keystore_ecdsa_key", + "algorithm": "EC", + "certChain": [ + [48,-126,1,-20,48,-126,1,-110,-96,3,2,1,2,2,4,90,116,-35,-49,48,10,6,8,42,-122,72,-50,61,4,3,2,48,109,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,27,48,25,6,3,85,4,3,12,18,105,110,116,101,114,109,101,100,105,97,114,121,95,101,99,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,53,52,48,56,90,23,13,50,56,48,50,48,50,50,49,53,52,48,56,90,48,105,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,23,48,21,6,3,85,4,3,12,14,101,99,95,99,111,100,101,95,115,105,103,110,101,114,48,89,48,19,6,7,42,-122,72,-50,61,2,1,6,8,42,-122,72,-50,61,3,1,7,3,66,0,4,57,-43,11,-123,49,-102,-107,-69,29,-24,29,45,-82,29,100,72,-96,1,-11,-30,31,115,-116,32,-98,-103,65,41,55,43,105,54,-70,60,-1,75,-61,60,115,77,-92,-67,-120,34,1,-66,62,-61,-32,-33,-77,67,127,71,113,113,-54,6,71,-6,9,-111,52,-69,-93,36,48,34,48,19,6,3,85,29,37,4,12,48,10,6,8,43,6,1,5,5,7,3,3,48,11,6,3,85,29,15,4,4,3,2,6,64,48,10,6,8,42,-122,72,-50,61,4,3,2,3,72,0,48,69,2,32,32,-32,54,-120,46,-49,-60,-29,109,83,89,-43,89,58,-43,-93,-112,-123,19,51,38,31,3,-110,-91,-73,-73,4,-29,77,-26,7,2,33,0,-58,-72,11,4,57,25,9,-60,117,-42,1,-17,-17,33,-3,-126,20,41,43,47,117,55,-60,-109,22,-54,18,97,112,-72,70,-101], + [48,-126,1,-28,48,-126,1,-118,-96,3,2,1,2,2,4,90,116,-35,113,48,10,6,8,42,-122,72,-50,61,4,3,2,48,101,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,19,48,17,6,3,85,4,3,12,10,114,111,111,116,95,101,99,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,53,50,51,56,90,23,13,51,48,48,50,48,50,50,49,53,50,51,56,90,48,109,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,27,48,25,6,3,85,4,3,12,18,105,110,116,101,114,109,101,100,105,97,114,121,95,101,99,95,99,97,48,89,48,19,6,7,42,-122,72,-50,61,2,1,6,8,42,-122,72,-50,61,3,1,7,3,66,0,4,-110,-4,127,36,-39,-31,13,-126,-41,121,-72,-68,61,12,53,-55,65,-53,-9,-15,55,22,-99,43,43,55,121,-65,-121,115,-91,-111,-30,-74,-46,76,110,54,-41,110,-113,-47,78,-105,48,77,-74,96,-19,-94,2,-49,-121,117,-69,-6,-15,66,-39,10,-30,-127,78,98,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,0,48,11,6,3,85,29,15,4,4,3,2,1,70,48,10,6,8,42,-122,72,-50,61,4,3,2,3,72,0,48,69,2,32,65,-49,-110,-57,-75,-17,-85,114,-74,7,-12,-25,-7,47,-91,-55,-71,21,-89,76,14,108,59,-40,-108,21,8,127,36,35,-92,-115,2,33,0,-40,37,-38,-61,-125,27,-14,-124,67,121,-100,80,-58,-114,66,108,101,-121,-24,-61,-99,-75,14,93,6,-84,58,-86,-74,-97,-16,59], + [48,-126,1,-36,48,-126,1,-126,-96,3,2,1,2,2,4,90,116,-35,27,48,10,6,8,42,-122,72,-50,61,4,3,2,48,101,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,19,48,17,6,3,85,4,3,12,10,114,111,111,116,95,101,99,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,53,49,49,49,90,23,13,51,51,48,50,48,50,50,49,53,49,49,49,90,48,101,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,19,48,17,6,3,85,4,3,12,10,114,111,111,116,95,101,99,95,99,97,48,89,48,19,6,7,42,-122,72,-50,61,2,1,6,8,42,-122,72,-50,61,3,1,7,3,66,0,4,-41,-63,7,35,10,-56,104,-41,94,3,57,-110,-17,-26,-12,124,-93,15,40,110,-94,103,-29,-16,83,15,-68,97,-28,22,-31,97,99,4,44,87,-60,-4,107,83,65,-66,33,-35,-29,44,73,32,-107,81,63,97,118,40,-82,68,25,-22,-34,112,44,-101,11,44,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,1,48,11,6,3,85,29,15,4,4,3,2,1,70,48,10,6,8,42,-122,72,-50,61,4,3,2,3,72,0,48,69,2,32,68,31,-79,94,-54,-46,-42,-12,-90,47,-81,3,65,67,109,82,-61,-98,98,107,63,118,44,-101,35,15,-32,72,42,69,-65,88,2,33,0,-11,-85,-104,-66,55,-120,-16,-112,-14,-119,-100,4,61,95,90,3,-117,-32,87,28,13,-64,-39,10,65,-117,59,-118,-59,79,-59,5] + ] + } + ], + "requestId": "keystore_request", + "status": "SUCCESS" +} diff --git a/jsign-crypto/src/test/resources/services/venafi-sign.json b/jsign-crypto/src/test/resources/services/venafi-sign.json new file mode 100644 index 00000000..5feea206 --- /dev/null +++ b/jsign-crypto/src/test/resources/services/venafi-sign.json @@ -0,0 +1,5 @@ +{ + "signature": [-79,-39,14,0,18,-6,27,-19,23,-33,41,113,20,35,124,36,-42,-97,-80,30,-63,123,15,-73,-88,97,-98,35,42,-60,20,-14,-104,33,-25,107,-4,60,-84,-17,-45,-110,-4,-112,46,-21,119,69,93,-37,10,5,-91,125,3,42,-102,122,103,114,66,18,16,-104,-65,108,40,-44,52,58,69,122,4,-65,111,-31,10,51,118,-31,92,-26,13,-86,-53,-108,63,121,86,-13,-59,-32,114,60,3,-122,-25,29,-22,104,-4,74,-106,-37,92,-78,-113,-44,60,-63,1,15,-37,-84,-9,58,-100,46,-119,-61,54,28,-53,25,82,107,100,19,35,66,-118,-121,-55,22,61,102,32,-102,-93,15,-18,-27,12,-36,72,-21,66,-76,-92,-89,-18,74,-64,43,43,19,0,78,9,46,84,-25,-65,126,-100,98,73,49,-4,-29,-7,65,97,-90,-57,60,27,-71,7,-40,-34,-55,20,7,-7,-124,-119,-81,-47,-61,-9,110,-115,-72,88,-59,-106,-79,67,-36,-101,-110,53,12,-114,72,0,107,84,116,-112,-19,84,38,35,-93,-15,67,3,-64,119,-24,17,-3,-19,-26,-101,-52,5,88,-107,-30,-65,14,-97,-10,121,4,-113,11,10,34,92,-16,33,-102,-110,2,-54,-6,-73,-4,-53,-45,68,119], + "requestId": "61", + "status": "SUCCESS" +} diff --git a/jsign-maven-plugin/src/main/java/net/jsign/JsignMojo.java b/jsign-maven-plugin/src/main/java/net/jsign/JsignMojo.java index c400d0cd..0a48c86f 100644 --- a/jsign-maven-plugin/src/main/java/net/jsign/JsignMojo.java +++ b/jsign-maven-plugin/src/main/java/net/jsign/JsignMojo.java @@ -90,7 +90,7 @@ public class JsignMojo extends AbstractMojo { /** * The type of the keystore (JKS, JCEKS, PKCS12, PKCS11, ETOKEN, NITROKEY, OPENPGP, OPENSC, PIV, YUBIKEY, AWS, - * AZUREKEYVAULT, DIGICERTONE, ESIGNER, GARASIGN, GOOGLECLOUD, HASHICORPVAULT, ORACLECLOUD, SIGNSERVER or TRUSTEDSIGNING). + * AZUREKEYVAULT, DIGICERTONE, ESIGNER, GARASIGN, GOOGLECLOUD, HASHICORPVAULT, ORACLECLOUD, SIGNSERVER, TRUSTEDSIGNING or VENAFI). */ @Parameter( property = "jsign.storetype" ) private String storetype; diff --git a/jsign/src/deb/data/usr/share/bash-completion/completions/jsign b/jsign/src/deb/data/usr/share/bash-completion/completions/jsign index 15a0ed2b..c5e145d5 100644 --- a/jsign/src/deb/data/usr/share/bash-completion/completions/jsign +++ b/jsign/src/deb/data/usr/share/bash-completion/completions/jsign @@ -42,7 +42,7 @@ _jsign() return 0 ;; --storetype) - COMPREPLY=( $( compgen -W 'JKS JCEKS PKCS12 PKCS11 AWS AZUREKEYVAULT DIGICERTONE ESIGNER ETOKEN GARASIGN GOOGLECLOUD HASHICORPVAULT ORACLECLOUD SIGNSERVER TRUSTEDSIGNING YUBIKEY NITROKEY OPENPGP OPENSC PIV' -- "$cur" ) ) + COMPREPLY=( $( compgen -W 'JKS JCEKS PKCS12 PKCS11 AWS AZUREKEYVAULT DIGICERTONE ESIGNER ETOKEN GARASIGN GOOGLECLOUD HASHICORPVAULT ORACLECLOUD SIGNSERVER VENAFI TRUSTEDSIGNING YUBIKEY NITROKEY OPENPGP OPENSC PIV' -- "$cur" ) ) return 0 ;; --storepass|-a|--alias|--keypass|-t|--tsaurl|-r|--tsretries|-w|--tsretrywait|-n|--name|-u|--url|--proxyUrl|--proxyUser|--proxyPass|--value) From 4b114e9b982fcd89a7d3e712210fc156c252b3cd Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Fri, 14 Feb 2025 13:21:43 -0800 Subject: [PATCH 02/10] initial venafi csp support Signed-off-by: Ivan Wallis --- .../src/main/java/net/jsign/KeyStoreType.java | 9 +- .../java/net/jsign/jca/VenafiCredentials.java | 5 +- .../net/jsign/jca/VenafiSigningService.java | 134 +++++--- .../net/jsign/jca/VenafiCredentialsTest.java | 73 ----- .../jsign/jca/VenafiSigningServiceTest.java | 289 ++---------------- 5 files changed, 117 insertions(+), 393 deletions(-) delete mode 100644 jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java diff --git a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java index 18fa4ab4..f3c663f8 100644 --- a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java +++ b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java @@ -582,8 +582,13 @@ Provider getProvider(KeyStoreBuilder params) { password = elements[1]; } - VenafiCredentials credentials = new VenafiCredentials(username, password, null, params.keypass()); - return new SigningServiceJcaProvider(new VenafiSigningService(params.keystore(), credentials)); + try { + VenafiCredentials credentials = new VenafiCredentials(username, password, null, params.keypass()); + return new SigningServiceJcaProvider(new VenafiSigningService(params.keystore(), credentials)); + } catch (IOException e) { + throw new IllegalStateException("Authentication failed with Venafi", e); + + } } }, diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java index 26541f26..a0f729be 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java @@ -53,10 +53,7 @@ public VenafiCredentials(String username, String password, KeyStore.Builder keys public String getSessionToken(String endpoint) throws IOException { if (sessionToken == null) { RESTClient client = new RESTClient(endpoint) - .errorHandler(response -> { - String errors = JsonWriter.format(response.get("Error")); - return errors; - }); + .errorHandler(response -> response.get("error") + ": " + response.get("error_description")); Map request = new LinkedHashMap<>(); request.put("client_id", "VenafiCodeSignClient"); diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index 08d1c556..de5363f0 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -32,6 +32,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.DLSequence; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1OutputStream; import net.jsign.DigestAlgorithm; @@ -56,11 +62,7 @@ public class VenafiSigningService implements SigningService { /** The name of the Venafi CodeSign Protect certificate KeyId */ private String KeyId; - - /** Timeout in seconds for the signing operation */ - private long timeout = 60 * 60; // one hour - - /** Mapping between Java and OCI signing algorithms */ + /** Mapping between Java and Venafi CodeSign Protect signing algorithms */ private final Map algorithmMapping = new HashMap<>(); { algorithmMapping.put("SHA256withRSA", 64); @@ -71,6 +73,21 @@ public class VenafiSigningService implements SigningService { algorithmMapping.put("SHA512withECDSA", 4166); } + /* Map ASN.1 DER prefix structures to MessageDigest Algorithm */ + + private final byte[] getHashPrefix(Integer mechanism) { + switch (mechanism) { + case 64: case 4164: + return new byte[]{0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; // SHA256 + case 65: case 4165: + return new byte[]{0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}; // SHA384 + case 66: case 4166: + return new byte[]{0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; // SHA512 + default: + return new byte[]{0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; // SHA256 + } + } + /** * Creates a new Venafi CodeSign Protect service. @@ -78,22 +95,17 @@ public class VenafiSigningService implements SigningService { * @param endpoint the Venafi API endpoint (for example https://demo.venafitpp.local/vedhsm/api/sign/) * @param credentials the Venafi credentials */ - public VenafiSigningService(String endpoint, VenafiCredentials credentials) { - this.endpoint = endpoint != null ? endpoint : "https://vh.venafilab.com"; + public VenafiSigningService(String endpoint, VenafiCredentials credentials) throws IOException { + if (!endpoint.startsWith("http")) { + endpoint = "https://" + endpoint; + } + this.endpoint = endpoint; this.credentials = credentials; + String token = credentials.getSessionToken(endpoint); this.client = new RESTClient(endpoint) - .authentication(conn -> conn.setRequestProperty("Authorization", "Bearer " + credentials.sessionToken)) - .errorHandler(response -> { - Map error = (Map) response.get("Error"); - return "Test"; - //Map error = (Map) response.get("Error"); - //return error.get("error_description"); - - }); - } - - void setTimeout(int timeout) { - this.timeout = timeout; + .authentication(conn -> conn.setRequestProperty("Authorization", "Bearer " + token )) + .errorHandler(response -> response.get("error") + ": " + response.get("error_description")); + } @Override @@ -119,40 +131,35 @@ private void loadKeyStore(String alias) throws KeyStoreException { certificates.put(name, (Map) key); } } catch (IOException e) { - throw new KeyStoreException("Unable to retrieve the Venafi keystore", e); + throw new KeyStoreException("Unable to retrieve the Venafi keystore with alias: " + alias, e); } } } @Override public List aliases() throws KeyStoreException { - //loadKeyStore(); return new ArrayList<>(certificates.keySet()); } @Override public Certificate[] getCertificateChain(String alias) throws KeyStoreException { - loadKeyStore(alias); - Map key = certificates.get(alias); - if (key == null) { - throw new KeyStoreException("Unable to retrieve Venafi certificate '" + alias + "'"); - } + try { + loadKeyStore(alias); - Object[] certChain = (Object[]) key.get("Value"); - Certificate[] chain = new Certificate[certChain.length]; + Map key = certificates.get(alias); + if (key == null) { + throw new KeyStoreException("Unable to retrieve Venafi certificate '" + alias + "'. Verify that the Project/Environment is a valid Certificate environment type."); + } - for (int i = 0; i < certChain.length; i++) { - byte[] data = decode((Object[]) certChain[i]); + String pem = (String) key.get("Value"); + Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(Base64.getDecoder().decode(pem))); - try { - chain[i] = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(data)); - } catch (CertificateException e) { - throw new KeyStoreException(e); - } + return new Certificate[]{certificate}; + } catch (CertificateException e) { + throw new KeyStoreException("Unable to retrieve Venafi certificate '" + alias + "'. Verify that the Project/Environment is a valid Certificate environment type.", e); } - return chain; } @Override @@ -160,15 +167,38 @@ public SigningServicePrivateKey getPrivateKey(String alias, char[] password) thr try { Certificate[] chain = getCertificateChain(alias); String algorithm = chain[0].getPublicKey().getAlgorithm(); + System.out.println("algorithm: " + algorithm); return new SigningServicePrivateKey(alias, algorithm, this); - } catch (KeyStoreException k) { - throw new UnrecoverableKeyException(); + } catch (KeyStoreException e) { + throw (UnrecoverableKeyException) new UnrecoverableKeyException().initCause(e); } } + public byte[] encodeASN1(byte[] sigBytes) throws IOException { + + // Split the sigbytes into r and s components + BigInteger r = new BigInteger(1, java.util.Arrays.copyOfRange(sigBytes, 0, sigBytes.length / 2)); + BigInteger s = new BigInteger(1, java.util.Arrays.copyOfRange(sigBytes, sigBytes.length / 2, sigBytes.length)); + + // Create an ASN1 sequence containing r and s + DLSequence components = new DLSequence(new ASN1Encodable[] { + new ASN1Integer(r), + new ASN1Integer(s) + }); + + // Marshal the components to ASN1 encoding + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ASN1OutputStream asn1OutputStream = ASN1OutputStream.create(byteArrayOutputStream); + asn1OutputStream.writeObject(components); + asn1OutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + @Override public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] data) throws GeneralSecurityException { + //System.out.println(algorithm); Integer clientMechanism = algorithmMapping.get(algorithm); if (clientMechanism == null) { throw new InvalidAlgorithmParameterException("Unsupported signing algorithm: " + clientMechanism); @@ -176,7 +206,14 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] try { DigestAlgorithm digestAlgorithm = DigestAlgorithm.getDefault(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + byte[] rsaPrefix = getHashPrefix(clientMechanism); + out.write(rsaPrefix); + data = digestAlgorithm.getMessageDigest().digest(data); + out.write(data); + byte[] arr_combined = out.toByteArray(); Map request = new HashMap<>(); @@ -190,10 +227,18 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] request.put("ClientInfo", clientInfo); request.put("ProcessInfo", processInfo); request.put("KeyId", KeyId); - request.put("Data", Base64.getEncoder().encodeToString(data)); + request.put("Data", Base64.getEncoder().encodeToString(arr_combined)); request.put("ClientMechanism", clientMechanism); - request.put("Mechanism", 1); // RSA testing - + switch (algorithm) { + case "SHA256withRSA": case "SHA384withRSA": case "SHA512withRSA": + request.put("Mechanism", 1); // RSA + break; + case "SHA256withECDSA": case "SHA384withECDSA": case "SHA512withECDSA": + request.put("Mechanism", 4161); // ECDSA + break; + default: + request.put("Mechanism", 1); // RSA + } Map response = client.post("/vedhsm/api/sign", JsonWriter.format(request)); String status = (String) response.get("Error"); @@ -201,7 +246,12 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] throw new IOException("Signing operation failed: " + response.get("Error")); } String signature = (String) response.get("ResultData"); - return Base64.getDecoder().decode(signature); + + if (algorithm.equals("SHA256withECDSA") || algorithm.equals("SHA384withECDSA") || algorithm.equals("SHA512withECDSA")) { + return encodeASN1(Base64.getDecoder().decode(signature)); + } else { + return Base64.getDecoder().decode(signature); + } } catch (IOException e) { throw new GeneralSecurityException(e); diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java deleted file mode 100644 index 66374e13..00000000 --- a/jsign-crypto/src/test/java/net/jsign/jca/VenafiCredentialsTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright 2025 Ivan Wallis - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.jsign.jca; - -import java.io.FileReader; -import java.io.IOException; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static net.jadler.Jadler.*; -import static org.junit.Assert.*; - -public class VenafiCredentialsTest { - - @Before - public void setUp() { - initJadler().withDefaultResponseStatus(404); - } - - @After - public void tearDown() { - closeJadler(); - } - - @Test - public void testGetSessionToken() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .havingParameterEqualTo("api_version", "1.0") - .havingParameterEqualTo("username", "ebourg") - .havingParameterEqualTo("password", "123456") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/garasign-authenticate.json")); - - VenafiCredentials credentials = new VenafiCredentials("ebourg", "123456", null, null); - String sessionToken = credentials.getSessionToken("http://localhost:" + port()); - - assertEquals("session token", "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrdG11c2VyIiwibmJmIjoxNTIyMjgzNzU1LCJleHAiOjE1MjIzNzAxNTUsImVuY3J5cHRlZF9jbGFpbXMiOiJyV1Q1TlljWi83TFV1eTB3YlFnbDR5K08zbXJtS3RrOGFtdjFVSnpOYy8vM0JvaVkrai9RS0lYYTdJSGRicWIxUTVCaWNIQ2VMYWJRQjhzMWQ3ZjJBZDNKeVR6dlliS1gzVGloUThmY3RyZWRyQ21sTFZ2dDZMRFlrZ2IxbURibWVuQ1Z2VFNKbnlXWEplRzRPMGJUUXQwN1RqTHVRdGhPendQR0xXSGFhT0U1cWNSZUUzVjMzb0U0RzJ1R2duR25tSFJNZVFzUTgxQXU3bGp1c2FDR1J6enpwaTFhZmxBdHRCcjNsbThWYmdrV0VWQ3ZDNndjTlNHZXA3YzJnNG0yQzI2MzhzMml2K2hLOTFzPSJ9.kZ7ab16YLhDioc9BE0Xha9QgELXbU2GBze2x7XXALXw", sessionToken); - } - - @Test - public void testGetSessionTokenFailed() { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody("{\"requestId\": \"auth\", \"status\": \"FAILED\", \"message\": \"Error authenticating user\"}"); - - VenafiCredentials credentials = new VenafiCredentials("ebourg", "123456", null, null); - - Exception e = assertThrows(IOException.class, () -> credentials.getSessionToken("http://localhost:" + port())); - assertEquals("message", "Failed to authenticate with Venafi: Error authenticating user", e.getMessage()); - } -} diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java index f2aaa7a5..fb5db523 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java @@ -47,65 +47,35 @@ public void tearDown() { @Test public void testGetAliases() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .havingParameterEqualTo("api_version", "1.0") - .havingParameter("session_token") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); List aliases = service.aliases(); - assertEquals("aliases", Arrays.asList("java_keystore_rsa_key", "java_keystore_ecdsa_key"), aliases); + assertEquals("aliases", Collections.emptyList(), aliases); } @Test public void testGetCertificateChain() throws Exception { onRequest() .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .havingParameterEqualTo("api_version", "1.0") - .havingParameter("session_token") + .havingPathEqualTo("/vedhsm/api/getobjects") + .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - Certificate[] chain = service.getCertificateChain("java_keystore_rsa_key"); + Certificate[] chain = service.getCertificateChain("project-test-cert"); assertNotNull("null chain", chain); - assertEquals("length", 3, chain.length); - assertEquals("subject 1", "CN=rsa_code_signer, OU=test, O=Garantir, L=San Diego, ST=CA, C=US", ((X509Certificate) chain[0]).getSubjectDN().getName()); - assertEquals("subject 2", "CN=intermediary_rsa_ca, OU=test, O=Garantir, L=San Diego, ST=CA, C=US", ((X509Certificate) chain[1]).getSubjectDN().getName()); - assertEquals("subject 3", "CN=root_rsa_ca, OU=test, O=Garantir, L=San Diego, ST=CA, C=US", ((X509Certificate) chain[2]).getSubjectDN().getName()); + assertEquals("length", 1, chain.length); + assertEquals("subject 1", "CN=test_signer, OU=test, O=Venafi, L=Salt Lake City, ST=UT, C=US", ((X509Certificate) chain[0]).getSubjectDN().getName()); } @Test public void testGetCertificateChainWithInvalidAlias() throws Exception { onRequest() .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .havingParameter("session_token") + .havingPathEqualTo("/vedhsm/api/getobjects") + .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); @@ -117,138 +87,17 @@ public void testGetCertificateChainWithInvalidAlias() throws Exception { } @Test - public void testGetCertificateChainWithError() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody("{\"requestId\": \"keystore_request\", \"status\": \"FAILURE\", \"message\": \"Keystore not found\", \"sessionToken\": null}"); - - SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - - Exception e = assertThrows(KeyStoreException.class, () -> service.getCertificateChain("java_keystore_rsa_key")); - assertEquals("message", "Unable to retrieve the Venafi keystore: Keystore not found", e.getMessage()); - } - - @Test - public void testGetCertificateChainWithHTTPError() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(502) - .withBody("Bad Gateway"); - - SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - - Exception e = assertThrows(KeyStoreException.class, () -> service.getCertificateChain("java_keystore_rsa_key")); - assertEquals("message", "Unable to retrieve the Venafi keystore", e.getMessage()); - } - - @Test - public void testGetPrivateKey() throws Exception { + public void testSign() throws Exception { onRequest() .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") + .havingPathEqualTo("/vedhsm/api/sign") + .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") .respond() .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - - SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - - SigningServicePrivateKey key = service.getPrivateKey("java_keystore_rsa_key", null); - assertNotNull("null key", key); - assertEquals("id", "java_keystore_rsa_key", key.getId()); - assertEquals("algorithm", "RSA", key.getAlgorithm()); - } - - @Test - public void testGetPrivateKeyWithInvalidAlias() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - - SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - - Exception e = assertThrows(UnrecoverableKeyException.class, () -> service.getPrivateKey("jsign", null)); - assertEquals("message", "Unable to fetch Venafi private key for the certificate 'jsign'", e.getMessage()); - } - - @Test - public void testSignWithPolling() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/sign") - .havingParameterEqualTo("api_version", "1.0") - .havingParameter("session_token") - .havingParameter("data_to_sign") - .havingParameterEqualTo("key_name", "java_keystore_rsa_key") - .havingParameterEqualTo("signature_scheme", "SHA256withRSA") - .havingParameter("request_id", nullValue()) - .respond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}"); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/sign") - .havingParameterEqualTo("api_version", "1.0") - .havingParameter("session_token") - .havingParameter("data_to_sign", nullValue()) - .havingParameter("key_name", nullValue()) - .havingParameter("signature_scheme", nullValue()) - .havingParameterEqualTo("request_id", "60") - .respond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}") - .thenRespond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}") - .thenRespond() - .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-sign.json")); SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); + SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-cert", null); byte[] signature = service.sign(privateKey, "SHA256withRSA", "Hello".getBytes()); @@ -256,124 +105,20 @@ public void testSignWithPolling() throws Exception { assertEquals("length", 256, signature.length); } - @Test - public void testSignWithoutPolling() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/sign") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-sign.json")) - .thenRespond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"FAILED\", \"message\": \"Data to sign is missing\"}"); - - SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); - - byte[] signature = service.sign(privateKey, "SHA256withRSA", "Hello".getBytes()); - - assertNotNull("null signature", signature); - assertEquals("length", 256, signature.length); - } - - @Test - public void testSignWithTimeout() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/sign") - .respond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}"); - - VenafiSigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - service.setTimeout(5); - SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); - - Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); - assertEquals("message", "java.io.IOException: Signing operation 60 timed out", e.getMessage()); - } - @Test public void testSignWithFailure() throws Exception { onRequest() .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/sign") - .respond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"FAILURE\", \"message\": \"Internal server error\"}"); - - SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); - - Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); - assertEquals("message", "java.io.IOException: Signing operation failed: Internal server error", e.getMessage()); - } - - @Test - public void testSignWithPollingFailure() throws Exception { - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/authenticate") + .havingPathEqualTo("/vedhsm/api/sign") + .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") .respond() .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-authenticate.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/keystore") - .respond() - .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-keystore.json")); - onRequest() - .havingMethodEqualTo("POST") - .havingPathEqualTo("/sign") - .respond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"IN_PROGRESS\", \"message\": \"Pending approvals\"}") - .thenRespond() - .withStatus(200) - .withBody("{\"requestId\": \"60\", \"status\": \"FAILURE\", \"message\": \"Internal server error\"}"); + .withBody(new FileReader("target/test-classes/services/venafi-sign-error.json")); SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - SigningServicePrivateKey privateKey = service.getPrivateKey("java_keystore_rsa_key", null); + SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-cert", null); Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); - assertEquals("message", "java.io.IOException: Signing operation 60 failed: Internal server error", e.getMessage()); + assertEquals("message", "java.io.IOException: Signing operation failed: Bad Request", e.getMessage()); } } From 35c3972228a3ade76027448986c2fea212d6a1c6 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Sat, 15 Feb 2025 07:36:06 -0800 Subject: [PATCH 03/10] venafi documentation --- docs/index.html | 18 ++++++++++++++++++ .../java/net/jsign/jca/VenafiCredentials.java | 2 +- .../net/jsign/jca/VenafiSigningService.java | 3 ++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/index.html b/docs/index.html index 9d7244cd..58d30470 100644 --- a/docs/index.html +++ b/docs/index.html @@ -234,6 +234,7 @@

Attributes

  • SIGNPATH: SignPath
  • SIGNSERVER: Keyfactor SignServer
  • TRUSTEDSIGNING: Azure Trusted Signing
  • +
  • VENAFI: Venafi CodeSign Protect
  • No, automatically detected for file based keystores. @@ -558,6 +559,7 @@

    Command Line Tool

    - SIGNPATH: SignPath - SIGNSERVER: Keyfactor SignServer - TRUSTEDSIGNING: Azure Trusted Signing + - VENAFI: Venafi CodeSign Protect -a,--alias <NAME> The alias of the certificate used for signing in the keystore --keypass <PASSWORD> The password of the private key. When using a keystore, this parameter can be omitted if the keystore shares the @@ -998,6 +1000,22 @@

    Signing with SignPath

    application.exe +

    Signing with Venafi CodeSign Protect

    + +

    Signing with Venafi CodeSign Protect requires version 23.1 or later +and requires a minimum scope of codesignclient as part of the default VenafiCodeSignClient API integration within the Trust Protection Platform. +The keystore parameter references the URL of the Venafi CodeSign Protect server. The storepass parameter represents +the Key User credential assigned to the CodeSign Protect project. The alias parameter is the certificate label which can be obtained from +the pkcs11config list command.

    + +
    + jsign --storetype VENAFI \
    +       --keystore https://example.tpp.local \
    +       --storepass "<username>|<password>" \
    +       --alias my-certificate-label \
    +       application.exe
    +
    +
    diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java index a0f729be..06c4ad7e 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java @@ -31,7 +31,7 @@ /** * Credentials for the Venafi CodeSign Protect. * - * @since 7.0 + * @since 7.2 */ public class VenafiCredentials { diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index de5363f0..a1c12ff6 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -44,7 +44,8 @@ /** * Signing service using the Venafi CodeSign Protect REST Service API. * - * @since 7.0 + * @since 7.2 + * @see Venafi CodeSign Protect REST API */ public class VenafiSigningService implements SigningService { From e18961cf9c76c13143f30cb52fe5310b3dd1d684 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Mon, 17 Feb 2025 20:34:17 -0800 Subject: [PATCH 04/10] fixes --- .../java/net/jsign/jca/VenafiCredentials.java | 2 +- .../net/jsign/jca/VenafiSigningService.java | 61 ++++++++++++------- .../java/net/jsign/KeyStoreBuilderTest.java | 23 +------ .../jsign/jca/VenafiSigningServiceTest.java | 1 + 4 files changed, 42 insertions(+), 45 deletions(-) diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java index 06c4ad7e..a65c0c06 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiCredentials.java @@ -1,4 +1,4 @@ -/** +/* * Copyright 2025 Ivan Wallis * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index a1c12ff6..96952b45 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -27,6 +27,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; import java.util.LinkedHashMap; import java.util.HashMap; @@ -38,6 +39,13 @@ import org.bouncycastle.asn1.DLSequence; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1OutputStream; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DEROctetString; import net.jsign.DigestAlgorithm; @@ -74,19 +82,31 @@ public class VenafiSigningService implements SigningService { algorithmMapping.put("SHA512withECDSA", 4166); } - /* Map ASN.1 DER prefix structures to MessageDigest Algorithm */ - - private final byte[] getHashPrefix(Integer mechanism) { - switch (mechanism) { - case 64: case 4164: - return new byte[]{0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; // SHA256 - case 65: case 4165: - return new byte[]{0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}; // SHA384 - case 66: case 4166: - return new byte[]{0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; // SHA512 - default: - return new byte[]{0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; // SHA256 + /* Add ASN.1 DER prefix to MessageDigest */ + + public static byte[] addASN1Prefix(DigestAlgorithm digestAlgorithm, byte[] hash) throws IOException { + ASN1EncodableVector v = new ASN1EncodableVector(); + System.out.println(digestAlgorithm.name()); + switch(digestAlgorithm.name()) { + case "SHA256": + v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1")); + case "SHA384": + v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.2")); + case "SHA512": + v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.3")); + default: + v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1")); } + + v.add(org.bouncycastle.asn1.DERNull.INSTANCE); + DERSequence algorithmIdentifier = new DERSequence(v); + + ASN1EncodableVector digestInfoVector = new ASN1EncodableVector(); + digestInfoVector.add(algorithmIdentifier); + digestInfoVector.add(new DEROctetString(hash)); + DERSequence digestInfo = new DERSequence(digestInfoVector); + + return digestInfo.getEncoded("DER"); } @@ -139,6 +159,7 @@ private void loadKeyStore(String alias) throws KeyStoreException { @Override public List aliases() throws KeyStoreException { + loadKeyStore(""); return new ArrayList<>(certificates.keySet()); } @@ -179,8 +200,8 @@ public SigningServicePrivateKey getPrivateKey(String alias, char[] password) thr public byte[] encodeASN1(byte[] sigBytes) throws IOException { // Split the sigbytes into r and s components - BigInteger r = new BigInteger(1, java.util.Arrays.copyOfRange(sigBytes, 0, sigBytes.length / 2)); - BigInteger s = new BigInteger(1, java.util.Arrays.copyOfRange(sigBytes, sigBytes.length / 2, sigBytes.length)); + BigInteger r = new BigInteger(1, Arrays.copyOfRange(sigBytes, 0, sigBytes.length / 2)); + BigInteger s = new BigInteger(1, Arrays.copyOfRange(sigBytes, sigBytes.length / 2, sigBytes.length)); // Create an ASN1 sequence containing r and s DLSequence components = new DLSequence(new ASN1Encodable[] { @@ -206,21 +227,15 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] } try { - DigestAlgorithm digestAlgorithm = DigestAlgorithm.getDefault(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - byte[] rsaPrefix = getHashPrefix(clientMechanism); - out.write(rsaPrefix); - + DigestAlgorithm digestAlgorithm = DigestAlgorithm.of(algorithm.substring(0, algorithm.toLowerCase().indexOf("with"))); data = digestAlgorithm.getMessageDigest().digest(data); - out.write(data); - byte[] arr_combined = out.toByteArray(); + + byte[] arr_combined = getASN1Prefix(digestAlgorithm, data); Map request = new HashMap<>(); Map clientInfo = new HashMap<>(); clientInfo.put("ClientLibraryName", "jsign"); - clientInfo.put("ClientLibraryVersion", "7.0.0"); Map processInfo = new HashMap<>(); clientInfo.put("Executable", "jsign"); diff --git a/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java b/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java index 4e3b9dad..a23c973c 100644 --- a/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java +++ b/jsign-crypto/src/test/java/net/jsign/KeyStoreBuilderTest.java @@ -307,34 +307,15 @@ public void testBuildGaraSign() throws Exception { @Test public void testBuildVenafi() throws Exception { - KeyStoreBuilder builder = new KeyStoreBuilder().storetype(VENAFI); + KeyStoreBuilder builder = new KeyStoreBuilder().storetype(VENAFI).keystore("https://tpp.example.local"); Exception e = assertThrows(IllegalArgumentException.class, builder::build); - assertEquals("message", "storepass parameter must specify the Venafi username/password and/or the path to the keystore containing the TLS client certificate: |, , or ||", e.getMessage()); - - builder.storepass("username|password|keystore.p12|storepass"); - - e = assertThrows(IllegalArgumentException.class, builder::build); - assertEquals("message", "storepass parameter must specify the Venafi username/password and/or the path to the keystore containing the TLS client certificate: |, , or ||", e.getMessage()); + assertEquals("message", "storepass parameter must specify the Venafi username/password", e.getMessage()); builder.storepass("username|password"); KeyStore keystore = builder.build(); assertNotNull("keystore", keystore); - - builder = new KeyStoreBuilder().storetype(VENAFI).keystore("https://api.garantir.io"); - builder.storepass("keystore.p12"); - - keystore = builder.build(); - assertNotNull("keystore", keystore); - - builder = new KeyStoreBuilder().storetype(VENAFI).keystore("https://api.garantir.io"); - builder.storepass("keystore.p12"); - builder.storepass("username|password|keystore.p12"); - builder.keypass("keypass"); - - keystore = builder.build(); - assertNotNull("keystore", keystore); } @Test diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java index fb5db523..8d7cf128 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java @@ -24,6 +24,7 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; +import java.util.Collections; import org.junit.After; import org.junit.Before; From 0d4df16ea7ee847bf19a96bc340a5182d7b6ca0e Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Tue, 18 Feb 2025 07:13:36 -0800 Subject: [PATCH 05/10] additional PR fixes --- .../net/jsign/jca/VenafiSigningService.java | 24 +++++------------ .../services/venafi-authenticate.json | 5 ---- .../resources/services/venafi-keystore.json | 26 +++---------------- .../resources/services/venafi-sign-error.json | 13 ++++++++++ .../test/resources/services/venafi-sign.json | 16 +++++++++--- 5 files changed, 35 insertions(+), 49 deletions(-) delete mode 100644 jsign-crypto/src/test/resources/services/venafi-authenticate.json create mode 100644 jsign-crypto/src/test/resources/services/venafi-sign-error.json diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index 96952b45..e4b3ebf9 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -86,21 +86,10 @@ public class VenafiSigningService implements SigningService { public static byte[] addASN1Prefix(DigestAlgorithm digestAlgorithm, byte[] hash) throws IOException { ASN1EncodableVector v = new ASN1EncodableVector(); - System.out.println(digestAlgorithm.name()); - switch(digestAlgorithm.name()) { - case "SHA256": - v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1")); - case "SHA384": - v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.2")); - case "SHA512": - v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.3")); - default: - v.add(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1")); - } - + v.add(digestAlgorithm.oid); v.add(org.bouncycastle.asn1.DERNull.INSTANCE); + DERSequence algorithmIdentifier = new DERSequence(v); - ASN1EncodableVector digestInfoVector = new ASN1EncodableVector(); digestInfoVector.add(algorithmIdentifier); digestInfoVector.add(new DEROctetString(hash)); @@ -189,7 +178,6 @@ public SigningServicePrivateKey getPrivateKey(String alias, char[] password) thr try { Certificate[] chain = getCertificateChain(alias); String algorithm = chain[0].getPublicKey().getAlgorithm(); - System.out.println("algorithm: " + algorithm); return new SigningServicePrivateKey(alias, algorithm, this); } catch (KeyStoreException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException().initCause(e); @@ -197,7 +185,8 @@ public SigningServicePrivateKey getPrivateKey(String alias, char[] password) thr } - public byte[] encodeASN1(byte[] sigBytes) throws IOException { + /* This function encodes the ECDSA signature response from Venafi CodeSign Protect /vedhsm/api/sign REST API */ + public byte[] encodeASN1Signature(byte[] sigBytes) throws IOException { // Split the sigbytes into r and s components BigInteger r = new BigInteger(1, Arrays.copyOfRange(sigBytes, 0, sigBytes.length / 2)); @@ -220,17 +209,16 @@ public byte[] encodeASN1(byte[] sigBytes) throws IOException { @Override public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] data) throws GeneralSecurityException { - //System.out.println(algorithm); Integer clientMechanism = algorithmMapping.get(algorithm); if (clientMechanism == null) { - throw new InvalidAlgorithmParameterException("Unsupported signing algorithm: " + clientMechanism); + throw new InvalidAlgorithmParameterException("Unsupported signing algorithm: " + algorithm); } try { DigestAlgorithm digestAlgorithm = DigestAlgorithm.of(algorithm.substring(0, algorithm.toLowerCase().indexOf("with"))); data = digestAlgorithm.getMessageDigest().digest(data); - byte[] arr_combined = getASN1Prefix(digestAlgorithm, data); + byte[] arr_combined = addASN1Prefix(digestAlgorithm, data); Map request = new HashMap<>(); diff --git a/jsign-crypto/src/test/resources/services/venafi-authenticate.json b/jsign-crypto/src/test/resources/services/venafi-authenticate.json deleted file mode 100644 index 0adbfc4a..00000000 --- a/jsign-crypto/src/test/resources/services/venafi-authenticate.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sessionToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJrdG11c2VyIiwibmJmIjoxNTIyMjgzNzU1LCJleHAiOjE1MjIzNzAxNTUsImVuY3J5cHRlZF9jbGFpbXMiOiJyV1Q1TlljWi83TFV1eTB3YlFnbDR5K08zbXJtS3RrOGFtdjFVSnpOYy8vM0JvaVkrai9RS0lYYTdJSGRicWIxUTVCaWNIQ2VMYWJRQjhzMWQ3ZjJBZDNKeVR6dlliS1gzVGloUThmY3RyZWRyQ21sTFZ2dDZMRFlrZ2IxbURibWVuQ1Z2VFNKbnlXWEplRzRPMGJUUXQwN1RqTHVRdGhPendQR0xXSGFhT0U1cWNSZUUzVjMzb0U0RzJ1R2duR25tSFJNZVFzUTgxQXU3bGp1c2FDR1J6enpwaTFhZmxBdHRCcjNsbThWYmdrV0VWQ3ZDNndjTlNHZXA3YzJnNG0yQzI2MzhzMml2K2hLOTFzPSJ9.kZ7ab16YLhDioc9BE0Xha9QgELXbU2GBze2x7XXALXw", - "requestId": "auth", - "status": "SUCCESS" -} diff --git a/jsign-crypto/src/test/resources/services/venafi-keystore.json b/jsign-crypto/src/test/resources/services/venafi-keystore.json index 285c2076..39efe5c1 100644 --- a/jsign-crypto/src/test/resources/services/venafi-keystore.json +++ b/jsign-crypto/src/test/resources/services/venafi-keystore.json @@ -1,24 +1,6 @@ { - "keys": [ - { - "name": "java_keystore_rsa_key", - "algorithm": "RSA", - "certChain": [ - [48,-126,3,122,48,-126,2,98,-96,3,2,1,2,2,4,90,116,-44,123,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,48,110,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,28,48,26,6,3,85,4,3,12,19,105,110,116,101,114,109,101,100,105,97,114,121,95,114,115,97,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,49,52,52,48,90,23,13,50,56,48,50,48,50,50,49,49,52,52,48,90,48,106,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,24,48,22,6,3,85,4,3,12,15,114,115,97,95,99,111,100,101,95,115,105,103,110,101,114,48,-126,1,34,48,13,6,9,42,-122,72,-122,-9,13,1,1,1,5,0,3,-126,1,15,0,48,-126,1,10,2,-126,1,1,0,-19,-120,54,109,121,90,-92,6,46,-83,10,-67,-15,57,-17,18,-17,-29,-48,53,39,31,-47,-29,-26,30,-64,33,21,127,-25,77,-25,-18,72,-79,-103,-105,-73,67,57,-98,-94,-108,94,108,66,87,-17,-60,-24,42,114,-91,55,-8,-28,14,57,53,100,97,120,7,104,86,-50,-107,-51,-75,77,-16,-36,-123,-88,122,-71,70,4,110,63,-121,105,-70,29,-8,13,-123,-77,54,36,-9,-2,-44,10,-83,-48,92,-118,39,24,32,-8,10,80,90,73,107,-11,23,-63,81,-23,84,-102,23,-126,28,75,117,-39,64,83,37,97,-73,94,-40,-123,-94,122,-81,-81,-100,104,-69,22,6,13,-30,34,22,61,96,-3,16,-82,-17,79,-92,-39,-104,-107,56,-93,-19,-94,-87,49,32,113,100,30,119,91,-116,107,-67,-104,79,-84,-121,-119,33,-17,-104,10,-61,-101,-54,79,-81,-20,28,-12,-116,83,41,-98,-66,-100,57,-32,118,-122,-25,47,108,-58,-82,82,99,-62,24,-33,58,95,-56,-5,-74,-72,-58,-72,-80,2,-110,-5,-38,-30,-95,72,35,-54,-98,-95,-43,125,61,-40,33,126,85,-29,-51,88,-60,-21,110,-40,3,-96,-125,-111,1,26,84,-76,-56,125,21,46,-72,-19,97,24,105,2,3,1,0,1,-93,36,48,34,48,11,6,3,85,29,15,4,4,3,2,6,64,48,19,6,3,85,29,37,4,12,48,10,6,8,43,6,1,5,5,7,3,3,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,3,-126,1,1,0,76,-105,-58,-39,-8,16,-116,61,-106,11,-102,-73,-64,-22,118,-80,-92,-82,-77,-96,93,30,-59,-50,-96,-69,-7,55,-46,45,-42,-86,9,120,-6,-76,43,84,-123,-17,-81,-123,-30,108,-107,0,41,37,-25,68,-33,50,86,-120,12,87,106,-8,-60,-51,-41,11,10,-25,-60,61,100,-6,-6,25,55,-37,112,57,34,-71,46,-63,-29,-76,58,-80,-43,68,59,35,116,100,-76,-71,-28,-31,-64,-78,-16,100,-99,-13,6,113,-60,-110,-93,-64,83,42,-12,-72,-127,74,-13,53,-9,117,-42,10,69,69,95,20,-48,12,61,126,114,-20,-117,108,43,-2,28,-124,52,33,-49,-79,-31,-118,-24,-70,-87,-82,65,-56,-84,44,-108,-54,41,90,-94,88,-78,-24,127,-11,113,-125,52,80,19,-104,103,-16,45,29,13,-29,-25,-121,-32,75,89,37,-105,20,-79,36,-55,60,83,-11,-83,-4,54,-13,118,-119,37,60,-83,-33,-4,18,-99,-90,-114,27,81,89,35,77,-54,17,122,-105,112,-27,-62,113,39,97,-26,-127,94,-125,-97,-12,6,-128,109,-80,-98,-80,21,36,-58,23,-5,-79,93,109,103,-117,126,71,-42,61,-84,-126,-111,-127,65,12,-41,-124,-44,-12,10,67,29,83,94,64,24,-43], - [48,-126,4,114,48,-126,2,90,-96,3,2,1,2,2,4,90,116,-44,14,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,48,102,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,20,48,18,6,3,85,4,3,12,11,114,111,111,116,95,114,115,97,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,49,50,51,57,90,23,13,51,48,48,50,48,50,50,49,49,50,51,57,90,48,110,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,28,48,26,6,3,85,4,3,12,19,105,110,116,101,114,109,101,100,105,97,114,121,95,114,115,97,95,99,97,48,-126,1,34,48,13,6,9,42,-122,72,-122,-9,13,1,1,1,5,0,3,-126,1,15,0,48,-126,1,10,2,-126,1,1,0,-75,-97,-11,-55,15,67,-66,80,4,-77,27,90,66,-6,-42,52,4,-128,-62,88,75,-90,90,-92,11,-82,104,-74,-10,88,115,110,-127,59,-8,-116,12,62,-52,119,56,-10,-77,-112,-40,96,-92,19,122,62,60,-87,-19,82,40,13,108,-59,127,-12,55,-57,11,88,-88,82,66,58,-22,63,25,105,55,11,-90,-76,107,21,87,-81,-87,-20,-119,45,-8,-27,72,-23,-74,101,-58,126,20,-124,53,-108,-58,-112,53,34,-28,52,-71,-5,18,40,-101,113,-89,-63,-50,44,-61,70,-44,-5,-73,-70,-34,-122,25,32,93,-52,-120,63,108,102,61,-16,-19,-82,111,110,94,-57,53,-103,100,108,116,35,-125,-116,-124,-105,-78,-91,-49,41,29,39,-102,-76,-107,-110,14,-3,97,-74,-98,39,105,97,5,-120,-108,57,78,60,-102,10,-79,110,11,-124,-126,-12,-13,80,-125,27,36,-36,-121,99,31,-64,122,71,-87,-124,-41,119,-27,-40,89,-50,68,-41,67,-63,-5,73,-113,122,-9,-75,-78,-57,119,62,-109,87,-22,106,-81,-31,120,-120,-86,-38,-128,85,120,-28,8,-90,26,88,-19,118,92,-104,45,-27,-84,116,-26,-75,9,-23,33,24,-62,36,-11,67,-43,-86,-1,-4,58,3,-98,-101,2,3,1,0,1,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,0,48,11,6,3,85,29,15,4,4,3,2,1,70,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,3,-126,2,1,0,-127,44,-123,17,-65,29,91,-6,-37,107,72,109,103,40,16,3,-42,-31,51,-6,103,-11,-102,-81,33,32,30,-117,59,18,116,57,-59,-13,-123,50,80,125,64,98,-18,114,-28,-78,-98,-41,109,-106,14,-117,-92,94,17,-97,120,-115,5,66,98,75,-126,-59,-88,61,104,103,-119,-28,125,45,85,8,-26,42,-107,-25,-23,41,110,-18,1,-85,-7,-89,-96,19,-105,98,103,-58,-21,-116,-120,-8,-43,-4,29,92,112,75,32,-97,-94,107,-20,-67,46,-127,10,17,125,36,-96,-88,-27,19,53,112,-51,-9,90,-62,31,-66,47,77,-102,54,-64,-99,85,114,-39,4,120,-54,-92,3,-17,89,-19,109,-49,-40,117,-54,43,33,11,22,124,-21,-77,-51,-19,-98,58,2,-36,68,31,-123,-83,49,122,73,-35,-97,-108,-80,28,-88,-67,-47,32,-75,9,100,-108,-100,71,36,-80,-32,16,72,-20,96,-58,23,-68,127,-55,-126,107,-55,-126,-77,62,127,45,67,54,75,-103,-46,-34,14,49,-67,-30,-1,-75,81,71,-31,57,-87,-19,-98,-81,-127,119,98,118,57,-121,45,-1,56,-12,-20,-43,-26,75,-19,119,-75,-45,4,-41,-28,115,-47,-58,2,13,41,-103,-48,-59,-65,42,-47,-26,14,-46,-111,-72,-27,-108,-26,-57,-128,-54,109,127,39,86,105,93,46,-6,-9,72,-69,-44,6,70,13,-49,-112,47,127,125,-110,-110,-41,99,-59,63,-121,-85,-25,-4,44,-124,63,-123,-64,-15,-6,116,-96,-126,-102,-8,-73,-59,-105,89,94,-54,9,-71,-114,-38,-97,38,6,-72,67,42,119,66,-103,91,76,-55,84,-98,-6,124,113,-34,-6,-119,68,9,75,80,48,117,-74,-117,77,18,92,-46,-91,-19,99,48,-43,70,34,-72,100,-73,52,80,32,84,-59,-76,-32,-11,-41,103,54,8,-119,-122,117,82,-90,107,35,70,49,37,32,68,-34,-49,51,109,31,-24,-93,31,88,36,86,38,34,34,51,-100,12,3,87,22,47,76,-67,-29,108,-116,68,64,-37,-10,-84,-90,88,22,-77,-99,-111,6,123,16,-11,78,-64,-87,-124,60,44,-26,102,97,-121,127,-72,70,-98,-99,-114,-111,25,-65,-91,87,-116,-49,-57,-120,9,-61,7,-11,32,-55,-52,84,54,42,0,-108,83,97,-50,11,28,-81,-23,16,-127,98,63,74,-37,122,-69,38,95,-66,-28,9,-13,-42,78,-109,-67,-36,-2,-89,-21,105,35,-1,91,72,1,-68,70,61,77,-24,-127,65,125,-10,-23,48,-110,46,-4,-17,-67], - [48,-126,5,106,48,-126,3,82,-96,3,2,1,2,2,4,90,116,-45,-124,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,48,102,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,20,48,18,6,3,85,4,3,12,11,114,111,111,116,95,114,115,97,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,49,48,53,56,90,23,13,51,51,48,50,48,50,50,49,49,48,53,56,90,48,102,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,20,48,18,6,3,85,4,3,12,11,114,111,111,116,95,114,115,97,95,99,97,48,-126,2,34,48,13,6,9,42,-122,72,-122,-9,13,1,1,1,5,0,3,-126,2,15,0,48,-126,2,10,2,-126,2,1,0,-32,-47,55,118,87,70,113,108,-96,-81,-41,-125,-67,-123,-110,84,-11,-3,16,116,31,-16,-106,85,-124,115,-106,87,-53,-101,-11,15,82,-95,-99,100,77,-94,-83,-38,-55,-72,-50,27,50,-14,-49,-42,-128,-45,79,-25,-44,86,-43,-120,-34,-95,4,88,-31,-82,90,37,66,-73,-43,22,-61,-121,42,81,41,30,-47,37,-86,43,-93,-88,-117,46,29,-90,74,19,-28,-91,4,-31,94,-76,12,-1,-111,71,125,21,1,-106,-126,71,-84,25,-112,-70,-4,21,34,-25,24,119,-23,-98,73,-122,51,65,106,-110,48,49,-125,-101,-111,76,-119,-40,47,96,-78,27,-88,-17,-90,-95,47,-106,70,-41,-117,-55,-91,-35,124,-68,-113,-23,-83,5,95,-92,-4,29,-108,-103,-67,-104,-7,63,9,16,28,-101,120,61,60,91,113,117,83,-27,-64,-70,116,94,94,73,112,61,127,76,-56,-70,100,49,18,126,2,-4,66,-124,72,-127,64,74,-32,1,21,118,79,54,64,48,-1,-23,-76,-100,-3,74,91,97,14,-14,85,73,89,-72,101,51,-1,9,29,5,-26,120,-107,113,87,3,106,123,-121,60,-13,86,-95,84,-89,41,2,-40,90,122,-56,17,31,118,-78,-75,126,24,98,88,-122,-128,-50,50,-49,54,-64,-27,15,6,-104,-111,88,8,-66,-3,-33,-105,-69,-17,69,-33,119,26,-42,25,100,-6,32,18,-83,63,115,13,-68,124,91,-77,-13,98,32,-34,24,104,123,-64,-13,0,44,83,-127,15,53,88,-64,53,-124,20,10,84,-6,-28,-126,76,43,-112,117,-57,-77,-94,75,-68,-109,-54,-56,93,29,15,-102,-17,-50,-46,-74,113,-88,-60,-49,-67,-99,-28,-78,117,78,37,-51,26,-13,123,73,112,-82,-126,66,-19,-14,-89,-22,32,18,127,-20,5,112,43,94,112,75,-84,72,0,30,11,-6,-3,23,88,-51,-76,-24,101,101,-124,-16,-13,116,-46,93,21,-40,89,-53,-88,-45,58,85,-88,-31,-40,-49,119,52,-3,10,-126,-51,37,72,76,50,48,-55,-61,91,-111,-8,-63,62,-96,126,-77,89,-8,-72,-119,56,42,44,16,-11,99,-113,-64,-3,-2,81,-109,13,99,-31,67,-23,71,31,62,-112,81,102,72,51,-15,47,17,-80,-31,-57,-95,-20,95,29,-63,108,-127,-74,5,51,78,-5,-112,82,6,-87,-98,-127,65,-34,-14,-21,51,20,107,116,-127,-5,29,15,124,100,-61,-116,-81,-72,-28,-35,88,64,112,87,82,-113,-8,36,31,-43,91,-125,-62,-88,103,2,3,1,0,1,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,1,48,11,6,3,85,29,15,4,4,3,2,1,70,48,13,6,9,42,-122,72,-122,-9,13,1,1,11,5,0,3,-126,2,1,0,77,81,109,-109,93,65,-125,49,-78,115,123,64,-37,10,47,28,55,120,115,94,47,76,5,-54,9,-17,127,115,32,-21,78,-23,58,-83,123,124,99,-35,-110,67,107,-12,-104,-73,-102,86,10,-60,-79,74,-39,21,-127,-100,-58,-118,-62,-7,-108,6,53,-55,-34,53,-117,114,18,70,25,-80,66,-30,-5,0,96,5,-39,-6,21,-25,105,-51,-101,-30,-105,70,56,-13,-43,-69,57,93,7,-62,71,-108,-89,11,37,-84,9,92,37,-76,20,38,15,-61,83,23,65,25,81,98,110,8,78,-16,27,-75,53,47,96,70,-112,-90,90,-60,-27,17,97,73,120,50,74,63,21,-20,-83,-127,85,-11,-26,47,-59,-96,-47,8,107,-38,8,70,-122,-23,-55,-86,-61,-88,-71,-51,21,-59,103,-91,-83,103,48,100,74,69,-9,-107,15,23,34,-40,-97,-98,-116,110,81,-65,97,-59,-12,-60,-124,-100,-116,34,-18,-117,-127,-105,-27,94,122,24,4,92,-126,-49,-107,58,-99,-47,-29,108,-26,124,-110,-86,-123,-101,24,-81,47,6,-114,-56,19,49,8,-54,-118,-87,-17,-71,83,-10,-2,-71,48,-95,-25,43,28,-27,45,119,-28,-36,39,-45,68,-91,73,122,-95,-46,-6,-111,-127,41,79,-23,-38,-78,-10,86,-56,23,-4,-67,96,-74,-37,-89,120,49,-66,94,63,-58,66,-84,-45,66,39,105,92,-3,-27,107,-62,83,-94,-74,-4,-126,103,-41,55,-56,-112,122,98,-118,-40,-1,-3,40,88,-75,-123,-106,91,25,67,-10,-28,16,-82,-101,30,82,49,73,24,-78,-49,-79,-11,-125,120,-80,-43,44,-31,-51,83,-63,-33,93,-79,-117,46,26,-38,45,-75,34,-92,-90,48,88,-92,-64,-68,60,27,-9,-99,76,-7,-53,-29,-117,64,65,-46,-94,-38,-31,78,-85,121,-84,106,89,81,13,-49,-40,36,-17,27,2,78,115,-41,45,71,114,99,12,23,-55,60,52,32,-79,-65,19,80,48,-41,52,-35,64,-20,109,-72,118,123,4,-66,-80,-84,-90,22,-119,107,107,31,46,-1,108,105,-73,18,55,20,104,90,-128,66,-61,112,47,45,-34,74,40,6,-37,93,85,100,56,-125,-88,-85,-1,102,48,-75,-46,21,80,94,11,-67,-31,-15,40,-74,-30,116,-127,-100,27,-12,-64,95,-121,-68,51,98,0,73,-115,-110,56,-64,-5,117,41,50,91,59,-100,6,124,63,-33,-23,-64,7,25,-40,36,41,-32,20,-72,-48,-82,-107,118,1,-102,71,105,-98,13,107,38,-103,95,-46,82] - ] - }, - { - "name": "java_keystore_ecdsa_key", - "algorithm": "EC", - "certChain": [ - [48,-126,1,-20,48,-126,1,-110,-96,3,2,1,2,2,4,90,116,-35,-49,48,10,6,8,42,-122,72,-50,61,4,3,2,48,109,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,27,48,25,6,3,85,4,3,12,18,105,110,116,101,114,109,101,100,105,97,114,121,95,101,99,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,53,52,48,56,90,23,13,50,56,48,50,48,50,50,49,53,52,48,56,90,48,105,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,23,48,21,6,3,85,4,3,12,14,101,99,95,99,111,100,101,95,115,105,103,110,101,114,48,89,48,19,6,7,42,-122,72,-50,61,2,1,6,8,42,-122,72,-50,61,3,1,7,3,66,0,4,57,-43,11,-123,49,-102,-107,-69,29,-24,29,45,-82,29,100,72,-96,1,-11,-30,31,115,-116,32,-98,-103,65,41,55,43,105,54,-70,60,-1,75,-61,60,115,77,-92,-67,-120,34,1,-66,62,-61,-32,-33,-77,67,127,71,113,113,-54,6,71,-6,9,-111,52,-69,-93,36,48,34,48,19,6,3,85,29,37,4,12,48,10,6,8,43,6,1,5,5,7,3,3,48,11,6,3,85,29,15,4,4,3,2,6,64,48,10,6,8,42,-122,72,-50,61,4,3,2,3,72,0,48,69,2,32,32,-32,54,-120,46,-49,-60,-29,109,83,89,-43,89,58,-43,-93,-112,-123,19,51,38,31,3,-110,-91,-73,-73,4,-29,77,-26,7,2,33,0,-58,-72,11,4,57,25,9,-60,117,-42,1,-17,-17,33,-3,-126,20,41,43,47,117,55,-60,-109,22,-54,18,97,112,-72,70,-101], - [48,-126,1,-28,48,-126,1,-118,-96,3,2,1,2,2,4,90,116,-35,113,48,10,6,8,42,-122,72,-50,61,4,3,2,48,101,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,19,48,17,6,3,85,4,3,12,10,114,111,111,116,95,101,99,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,53,50,51,56,90,23,13,51,48,48,50,48,50,50,49,53,50,51,56,90,48,109,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,27,48,25,6,3,85,4,3,12,18,105,110,116,101,114,109,101,100,105,97,114,121,95,101,99,95,99,97,48,89,48,19,6,7,42,-122,72,-50,61,2,1,6,8,42,-122,72,-50,61,3,1,7,3,66,0,4,-110,-4,127,36,-39,-31,13,-126,-41,121,-72,-68,61,12,53,-55,65,-53,-9,-15,55,22,-99,43,43,55,121,-65,-121,115,-91,-111,-30,-74,-46,76,110,54,-41,110,-113,-47,78,-105,48,77,-74,96,-19,-94,2,-49,-121,117,-69,-6,-15,66,-39,10,-30,-127,78,98,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,0,48,11,6,3,85,29,15,4,4,3,2,1,70,48,10,6,8,42,-122,72,-50,61,4,3,2,3,72,0,48,69,2,32,65,-49,-110,-57,-75,-17,-85,114,-74,7,-12,-25,-7,47,-91,-55,-71,21,-89,76,14,108,59,-40,-108,21,8,127,36,35,-92,-115,2,33,0,-40,37,-38,-61,-125,27,-14,-124,67,121,-100,80,-58,-114,66,108,101,-121,-24,-61,-99,-75,14,93,6,-84,58,-86,-74,-97,-16,59], - [48,-126,1,-36,48,-126,1,-126,-96,3,2,1,2,2,4,90,116,-35,27,48,10,6,8,42,-122,72,-50,61,4,3,2,48,101,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,19,48,17,6,3,85,4,3,12,10,114,111,111,116,95,101,99,95,99,97,48,30,23,13,49,56,48,50,48,50,50,49,53,49,49,49,90,23,13,51,51,48,50,48,50,50,49,53,49,49,49,90,48,101,49,11,48,9,6,3,85,4,6,19,2,85,83,49,11,48,9,6,3,85,4,8,12,2,67,65,49,18,48,16,6,3,85,4,7,12,9,83,97,110,32,68,105,101,103,111,49,17,48,15,6,3,85,4,10,12,8,71,97,114,97,110,116,105,114,49,13,48,11,6,3,85,4,11,12,4,116,101,115,116,49,19,48,17,6,3,85,4,3,12,10,114,111,111,116,95,101,99,95,99,97,48,89,48,19,6,7,42,-122,72,-50,61,2,1,6,8,42,-122,72,-50,61,3,1,7,3,66,0,4,-41,-63,7,35,10,-56,104,-41,94,3,57,-110,-17,-26,-12,124,-93,15,40,110,-94,103,-29,-16,83,15,-68,97,-28,22,-31,97,99,4,44,87,-60,-4,107,83,65,-66,33,-35,-29,44,73,32,-107,81,63,97,118,40,-82,68,25,-22,-34,112,44,-101,11,44,-93,32,48,30,48,15,6,3,85,29,19,4,8,48,6,1,1,-1,2,1,1,48,11,6,3,85,29,15,4,4,3,2,1,70,48,10,6,8,42,-122,72,-50,61,4,3,2,3,72,0,48,69,2,32,68,31,-79,94,-54,-46,-42,-12,-90,47,-81,3,65,67,109,82,-61,-98,98,107,63,118,44,-101,35,15,-32,72,42,69,-65,88,2,33,0,-11,-85,-104,-66,55,-120,-16,-112,-14,-119,-100,4,61,95,90,3,-117,-32,87,28,13,-64,-39,10,65,-117,59,-118,-59,79,-59,5] - ] - } - ], - "requestId": "keystore_request", - "status": "SUCCESS" + "LabelFilter": ["my-test-cert"], + "EnvironmentFilter": [0], + "ObjectTypeFilter": [1], + "IncludeChains": true } diff --git a/jsign-crypto/src/test/resources/services/venafi-sign-error.json b/jsign-crypto/src/test/resources/services/venafi-sign-error.json new file mode 100644 index 00000000..6ce9eae1 --- /dev/null +++ b/jsign-crypto/src/test/resources/services/venafi-sign-error.json @@ -0,0 +1,13 @@ +{ + "ProcessInfo": { + "Executable":"My Test" +}, + "ClientInfo": { + "ClientLibraryName": "MyHSMClienttest" + }, + + "KeyId":"{59744996-dac7-42d7-adea-8de76e34f306}", + "Mechanism": 1, + "ClientMechanism": 65, + "Data":"MDEwDQYJYIZIAWUDBAIBBQAEIEhtAwXZwEFVsL0LriCw7b61jyoy4fPgmEV75vlFw4/o" +} diff --git a/jsign-crypto/src/test/resources/services/venafi-sign.json b/jsign-crypto/src/test/resources/services/venafi-sign.json index 5feea206..8247e75d 100644 --- a/jsign-crypto/src/test/resources/services/venafi-sign.json +++ b/jsign-crypto/src/test/resources/services/venafi-sign.json @@ -1,5 +1,13 @@ { - "signature": [-79,-39,14,0,18,-6,27,-19,23,-33,41,113,20,35,124,36,-42,-97,-80,30,-63,123,15,-73,-88,97,-98,35,42,-60,20,-14,-104,33,-25,107,-4,60,-84,-17,-45,-110,-4,-112,46,-21,119,69,93,-37,10,5,-91,125,3,42,-102,122,103,114,66,18,16,-104,-65,108,40,-44,52,58,69,122,4,-65,111,-31,10,51,118,-31,92,-26,13,-86,-53,-108,63,121,86,-13,-59,-32,114,60,3,-122,-25,29,-22,104,-4,74,-106,-37,92,-78,-113,-44,60,-63,1,15,-37,-84,-9,58,-100,46,-119,-61,54,28,-53,25,82,107,100,19,35,66,-118,-121,-55,22,61,102,32,-102,-93,15,-18,-27,12,-36,72,-21,66,-76,-92,-89,-18,74,-64,43,43,19,0,78,9,46,84,-25,-65,126,-100,98,73,49,-4,-29,-7,65,97,-90,-57,60,27,-71,7,-40,-34,-55,20,7,-7,-124,-119,-81,-47,-61,-9,110,-115,-72,88,-59,-106,-79,67,-36,-101,-110,53,12,-114,72,0,107,84,116,-112,-19,84,38,35,-93,-15,67,3,-64,119,-24,17,-3,-19,-26,-101,-52,5,88,-107,-30,-65,14,-97,-10,121,4,-113,11,10,34,92,-16,33,-102,-110,2,-54,-6,-73,-4,-53,-45,68,119], - "requestId": "61", - "status": "SUCCESS" -} + "ProcessInfo": { + "Executable":"My Test" +}, + "ClientInfo": { + "ClientLibraryName": "MyHSMClienttest" + }, + + "KeyId":"{59744996-dac7-42d7-adea-8de76e34f306}", + "Mechanism": 1, + "ClientMechanism": 64, + "Data":"MDEwDQYJYIZIAWUDBAIBBQAEIEhtAwXZwEFVsL0LriCw7b61jyoy4fPgmEV75vlFw4/o" +} \ No newline at end of file From 58aa4efefa5e9ac8acd52fc883300cabe014d1c1 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Tue, 18 Feb 2025 10:02:27 -0800 Subject: [PATCH 06/10] update json files --- .../net/jsign/jca/VenafiSigningService.java | 2 +- .../resources/services/venafi-keystore.json | 30 ++++++++++++++++--- .../resources/services/venafi-sign-error.json | 13 ++------ .../test/resources/services/venafi-sign.json | 13 ++------ 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index e4b3ebf9..8873eeb7 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -252,7 +252,7 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] String signature = (String) response.get("ResultData"); if (algorithm.equals("SHA256withECDSA") || algorithm.equals("SHA384withECDSA") || algorithm.equals("SHA512withECDSA")) { - return encodeASN1(Base64.getDecoder().decode(signature)); + return encodeASN1Signature(Base64.getDecoder().decode(signature)); } else { return Base64.getDecoder().decode(signature); } diff --git a/jsign-crypto/src/test/resources/services/venafi-keystore.json b/jsign-crypto/src/test/resources/services/venafi-keystore.json index 39efe5c1..d6df2d68 100644 --- a/jsign-crypto/src/test/resources/services/venafi-keystore.json +++ b/jsign-crypto/src/test/resources/services/venafi-keystore.json @@ -1,6 +1,28 @@ { - "LabelFilter": ["my-test-cert"], - "EnvironmentFilter": [0], - "ObjectTypeFilter": [1], - "IncludeChains": true + "Certificates": [ + { + "Authentication": false, + "CreatedOn": "2025-02-13T16:30:28.6214597Z", + "Encipherment": false, + "EnvironmentType": 0, + "Handle": 28460, + "Id": "dnNpZ24tc2VsZnNpZ25lZC1wMjU2", + "KeyContext": null, + "KeyId": "{9bad128b-c5df-4ff4-b412-c32ab54a9e86}", + "Label": "test-selfsigned-p256", + "ObjectType": 1, + "Signing": true, + "Token": true, + "CheckValue": "2Af2", + "EndDate": "20260213", + "Issuer": "MIGJMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExETAPBgNVBAcTCFNhbiBKb3NlMRowGAYDVQQLExFHbG9iYWwgQXJjaGl0ZWN0czEVMBMGA1UEChMMVmVuYWZpLCBJbmMuMScwJQYDVQQDEx5zZWxmc2lnbmVkLXAyNTYudmVuYWZpZGVtby5jb20=", + "StartDate": "20250213", + "Subject": "MIGJMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExETAPBgNVBAcTCFNhbiBKb3NlMRowGAYDVQQLExFHbG9iYWwgQXJjaGl0ZWN0czEVMBMGA1UEChMMVmVuYWZpLCBJbmMuMScwJQYDVQQDEx5zZWxmc2lnbmVkLXAyNTYudmVuYWZpZGVtby5jb20=", + "Trusted": true, + "Value": "MIICYzCCAgqgAwIBAgIRANrShCO1C61GuyDwmzVpEaUwCgYIKoZIzj0EAwIwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTERMA8GA1UEBxMIU2FuIEpvc2UxGjAYBgNVBAsTEUdsb2JhbCBBcmNoaXRlY3RzMRUwEwYDVQQKEwxWZW5hZmksIEluYy4xJzAlBgNVBAMTHnNlbGZzaWduZWQtcDI1Ni52ZW5hZmlkZW1vLmNvbTAeFw0yNTAyMTMxNjMwMjlaFw0yNjAyMTMxNjMwMjlaMIGJMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExETAPBgNVBAcTCFNhbiBKb3NlMRowGAYDVQQLExFHbG9iYWwgQXJjaGl0ZWN0czEVMBMGA1UEChMMVmVuYWZpLCBJbmMuMScwJQYDVQQDEx5zZWxmc2lnbmVkLXAyNTYudmVuYWZpZGVtby5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATRYtLccF+Yo19eypFHjo3\/zVinlHYDYBQ29dlnjFHe1Z7QCm98SjcJlSpisFv3K3zPCbgjepsuWmo\/niYnjY2No1EwTzAdBgNVHQ4EFgQU+UTc1jX5gB96yQpAf7xHmWTewCQwCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCBoAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwCgYIKoZIzj0EAwIDRwAwRAIgL+v9pndvdbaDI09C6VOQfniysQfiyaP3iTNJgcufSNUCIFx8Pt3qZZwjpc4XWYjllXzjpElARw4HM+pLmuESP9DJ" + } + ], + "PrivateKeys": [], + "PublicKeys": [], + "Success": true } diff --git a/jsign-crypto/src/test/resources/services/venafi-sign-error.json b/jsign-crypto/src/test/resources/services/venafi-sign-error.json index 6ce9eae1..aa822747 100644 --- a/jsign-crypto/src/test/resources/services/venafi-sign-error.json +++ b/jsign-crypto/src/test/resources/services/venafi-sign-error.json @@ -1,13 +1,4 @@ { - "ProcessInfo": { - "Executable":"My Test" -}, - "ClientInfo": { - "ClientLibraryName": "MyHSMClienttest" - }, - - "KeyId":"{59744996-dac7-42d7-adea-8de76e34f306}", - "Mechanism": 1, - "ClientMechanism": 65, - "Data":"MDEwDQYJYIZIAWUDBAIBBQAEIEhtAwXZwEFVsL0LriCw7b61jyoy4fPgmEV75vlFw4/o" + "Error": "Private Key Access: 'sign' operation failed. More info: Error signing data (Failed to sign data using engine: 'Software', error: Call to C_Sign failed [DataInvalid])", + "RequestThumbprint": "C8B78011FF6C2E6C936544B1D0D5455C29890BEE745ADEE5A9E03A6D72E6A1C6" } diff --git a/jsign-crypto/src/test/resources/services/venafi-sign.json b/jsign-crypto/src/test/resources/services/venafi-sign.json index 8247e75d..b90d96a8 100644 --- a/jsign-crypto/src/test/resources/services/venafi-sign.json +++ b/jsign-crypto/src/test/resources/services/venafi-sign.json @@ -1,13 +1,4 @@ { - "ProcessInfo": { - "Executable":"My Test" -}, - "ClientInfo": { - "ClientLibraryName": "MyHSMClienttest" - }, - - "KeyId":"{59744996-dac7-42d7-adea-8de76e34f306}", - "Mechanism": 1, - "ClientMechanism": 64, - "Data":"MDEwDQYJYIZIAWUDBAIBBQAEIEhtAwXZwEFVsL0LriCw7b61jyoy4fPgmEV75vlFw4/o" + "ResultData": "HLNy8jjS+p6bwlg0UEHjL1MQ1dBuuNi82KwWaPOPie0KfE+MyZ5QcgQZIzOS40\/fovWHuSdDLXTFHLyyfOZuXzD4bb9Rjveo2h4bt7ge6UAovvJjU1JOXylkwon0DeDQhuvM0En1O9cfsPvY9zzUn+MkWlyfmWic8COF3RyzSOVDeE\/kIFVWeIHFvIOwHKo5b\/fwURvDguFw6aa1Gh6A7Xz8bfvz+SU5G8ixd63kdUPQyzQih0+sp3aNtF7bjqg4wFRxga3JOMIM+tJjdT2huVWU4hCtJU\/CrbiFxD6X\/+egu4tyfKaTH8an7woVOW4BINd5N7lkeUJi7dDLa1nNPg==", + "Success": true } \ No newline at end of file From e753b0c10074840f044c53232c8e6a9655cc3c2e Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Tue, 18 Feb 2025 12:33:45 -0800 Subject: [PATCH 07/10] PR updates --- .../net/jsign/jca/VenafiSigningService.java | 34 +++++-------- .../jsign/jca/VenafiSigningServiceTest.java | 49 ++++++++++++++++--- .../services/venafi-sign-ecdsa-error.json | 4 ++ .../resources/services/venafi-sign-ecdsa.json | 4 ++ ...-error.json => venafi-sign-rsa-error.json} | 0 ...{venafi-sign.json => venafi-sign-rsa.json} | 0 6 files changed, 64 insertions(+), 27 deletions(-) create mode 100644 jsign-crypto/src/test/resources/services/venafi-sign-ecdsa-error.json create mode 100644 jsign-crypto/src/test/resources/services/venafi-sign-ecdsa.json rename jsign-crypto/src/test/resources/services/{venafi-sign-error.json => venafi-sign-rsa-error.json} (100%) rename jsign-crypto/src/test/resources/services/{venafi-sign.json => venafi-sign-rsa.json} (100%) diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index 8873eeb7..b8db14bd 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -46,6 +46,12 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + + + import net.jsign.DigestAlgorithm; @@ -74,9 +80,11 @@ public class VenafiSigningService implements SigningService { /** Mapping between Java and Venafi CodeSign Protect signing algorithms */ private final Map algorithmMapping = new HashMap<>(); { + algorithmMapping.put("SHA1withRSA", 6); algorithmMapping.put("SHA256withRSA", 64); algorithmMapping.put("SHA384withRSA", 65); algorithmMapping.put("SHA512withRSA", 66); + algorithmMapping.put("SHA1withECDSA", 4162); algorithmMapping.put("SHA256withECDSA", 4164); algorithmMapping.put("SHA384withECDSA", 4165); algorithmMapping.put("SHA512withECDSA", 4166); @@ -85,20 +93,9 @@ public class VenafiSigningService implements SigningService { /* Add ASN.1 DER prefix to MessageDigest */ public static byte[] addASN1Prefix(DigestAlgorithm digestAlgorithm, byte[] hash) throws IOException { - ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(digestAlgorithm.oid); - v.add(org.bouncycastle.asn1.DERNull.INSTANCE); - - DERSequence algorithmIdentifier = new DERSequence(v); - ASN1EncodableVector digestInfoVector = new ASN1EncodableVector(); - digestInfoVector.add(algorithmIdentifier); - digestInfoVector.add(new DEROctetString(hash)); - DERSequence digestInfo = new DERSequence(digestInfoVector); - - return digestInfo.getEncoded("DER"); + return new DigestInfo(new AlgorithmIdentifier(digestAlgorithm.oid, DERNull.INSTANCE), hash).getEncoded("DER"); } - /** * Creates a new Venafi CodeSign Protect service. * @@ -209,11 +206,6 @@ public byte[] encodeASN1Signature(byte[] sigBytes) throws IOException { @Override public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] data) throws GeneralSecurityException { - Integer clientMechanism = algorithmMapping.get(algorithm); - if (clientMechanism == null) { - throw new InvalidAlgorithmParameterException("Unsupported signing algorithm: " + algorithm); - } - try { DigestAlgorithm digestAlgorithm = DigestAlgorithm.of(algorithm.substring(0, algorithm.toLowerCase().indexOf("with"))); data = digestAlgorithm.getMessageDigest().digest(data); @@ -232,12 +224,12 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] request.put("ProcessInfo", processInfo); request.put("KeyId", KeyId); request.put("Data", Base64.getEncoder().encodeToString(arr_combined)); - request.put("ClientMechanism", clientMechanism); - switch (algorithm) { - case "SHA256withRSA": case "SHA384withRSA": case "SHA512withRSA": + //switch (algorithm) { + switch (algorithm.substring(algorithm.toLowerCase().indexOf("with") + 4)) { + case "RSA": request.put("Mechanism", 1); // RSA break; - case "SHA256withECDSA": case "SHA384withECDSA": case "SHA512withECDSA": + case "ECDSA": request.put("Mechanism", 4161); // ECDSA break; default: diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java index 8d7cf128..94b3a49c 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java @@ -88,7 +88,7 @@ public void testGetCertificateChainWithInvalidAlias() throws Exception { } @Test - public void testSign() throws Exception { + public void testSignRSA() throws Exception { onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/sign") @@ -98,7 +98,7 @@ public void testSign() throws Exception { .withBody(new FileReader("target/test-classes/services/venafi-sign.json")); SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-cert", null); + SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-rsa-cert", null); byte[] signature = service.sign(privateKey, "SHA256withRSA", "Hello".getBytes()); @@ -107,19 +107,56 @@ public void testSign() throws Exception { } @Test - public void testSignWithFailure() throws Exception { + public void testSignECDSA() throws Exception { onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/sign") .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") .respond() .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-sign-error.json")); + .withBody(new FileReader("target/test-classes/services/venafi-sign.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-ecdsa-cert", null); + + byte[] signature = service.sign(privateKey, "SHA256withECDSA", "Hello".getBytes()); + + assertNotNull("null signature", signature); + assertEquals("length", 256, signature.length); + } + + + @Test + public void testSignRSAWithFailure() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedhsm/api/sign") + .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-sign-rsa-error.json")); + + SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); + SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-rsa-cert", null); + + Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); + assertEquals("message", "java.io.IOException: Private Key Access: 'sign' operation failed. More info: Error signing data (Failed to sign data using engine: 'Software', error: Call to C_Sign failed [DataInvalid])", e.getMessage()); + } + + @Test + public void testSignECDSAWithFailure() throws Exception { + onRequest() + .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedhsm/api/sign") + .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-sign-ecdsa-error.json")); SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); - SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-cert", null); + SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-ecdsa-cert", null); Exception e = assertThrows(GeneralSecurityException.class, () -> service.sign(privateKey, "SHA256withRSA", "Hello".getBytes())); - assertEquals("message", "java.io.IOException: Signing operation failed: Bad Request", e.getMessage()); + assertEquals("message", "java.io.IOException: Signing operation failed: Private Key Access: 'sign' operation failed. More info: Error signing data (Failed to sign data using engine: 'Software', error: Mechanism RSA_PKCS not supported by key 'CryptokiECPrivateKey [4294967295])", e.getMessage()); } } diff --git a/jsign-crypto/src/test/resources/services/venafi-sign-ecdsa-error.json b/jsign-crypto/src/test/resources/services/venafi-sign-ecdsa-error.json new file mode 100644 index 00000000..7fc04294 --- /dev/null +++ b/jsign-crypto/src/test/resources/services/venafi-sign-ecdsa-error.json @@ -0,0 +1,4 @@ +{ + "Error": "Private Key Access: 'sign' operation failed. More info: Error signing data (Failed to sign data using engine: 'Software', error: Mechanism RSA_PKCS not supported by key 'CryptokiECPrivateKey [4294967295])", + "RequestThumbprint": "3F8B611F3B2FD02264368E3E52E1473B7B6EF2EDAADD58A8821476136C3319E7" +} diff --git a/jsign-crypto/src/test/resources/services/venafi-sign-ecdsa.json b/jsign-crypto/src/test/resources/services/venafi-sign-ecdsa.json new file mode 100644 index 00000000..ab2dce7d --- /dev/null +++ b/jsign-crypto/src/test/resources/services/venafi-sign-ecdsa.json @@ -0,0 +1,4 @@ +{ + "ResultData": "v54401Dj+fKDo6ISPxcn0o0HDDYgxQXjP\/2I1TX9VXB\/LDr6MC67ikgVSVZz31MEGqqaLx4gyJDRSz\/cbLGlmw==", + "Success": true +} \ No newline at end of file diff --git a/jsign-crypto/src/test/resources/services/venafi-sign-error.json b/jsign-crypto/src/test/resources/services/venafi-sign-rsa-error.json similarity index 100% rename from jsign-crypto/src/test/resources/services/venafi-sign-error.json rename to jsign-crypto/src/test/resources/services/venafi-sign-rsa-error.json diff --git a/jsign-crypto/src/test/resources/services/venafi-sign.json b/jsign-crypto/src/test/resources/services/venafi-sign-rsa.json similarity index 100% rename from jsign-crypto/src/test/resources/services/venafi-sign.json rename to jsign-crypto/src/test/resources/services/venafi-sign-rsa.json From 9b583377f81f7c215573bf830af7ffbb569351d8 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Wed, 19 Feb 2025 06:38:12 -0800 Subject: [PATCH 08/10] update tests --- .../net/jsign/jca/VenafiSigningService.java | 8 ++--- .../jsign/jca/VenafiSigningServiceTest.java | 30 +++++++++++++++++++ .../resources/services/venafi-authorize.json | 10 +++++++ 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 jsign-crypto/src/test/resources/services/venafi-authorize.json diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index b8db14bd..5984fa58 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -224,12 +224,12 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] request.put("ProcessInfo", processInfo); request.put("KeyId", KeyId); request.put("Data", Base64.getEncoder().encodeToString(arr_combined)); - //switch (algorithm) { - switch (algorithm.substring(algorithm.toLowerCase().indexOf("with") + 4)) { + + switch (privateKey.getAlgorithm()) { case "RSA": request.put("Mechanism", 1); // RSA break; - case "ECDSA": + case "EC": request.put("Mechanism", 4161); // ECDSA break; default: @@ -243,7 +243,7 @@ public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] } String signature = (String) response.get("ResultData"); - if (algorithm.equals("SHA256withECDSA") || algorithm.equals("SHA384withECDSA") || algorithm.equals("SHA512withECDSA")) { + if ("EC".equals(privateKey.getAlgorithm())) { return encodeASN1Signature(Base64.getDecoder().decode(signature)); } else { return Base64.getDecoder().decode(signature); diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java index 94b3a49c..4f12d6bd 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java @@ -56,6 +56,11 @@ public void testGetAliases() throws Exception { @Test public void testGetCertificateChain() throws Exception { + onRequest("/vedauth/authorize/oauth") + .havingMethodEqualTo("POST") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/getobjects") @@ -73,6 +78,11 @@ public void testGetCertificateChain() throws Exception { @Test public void testGetCertificateChainWithInvalidAlias() throws Exception { + onRequest("/vedauth/authorize/oauth") + .havingMethodEqualTo("POST") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/getobjects") @@ -89,6 +99,11 @@ public void testGetCertificateChainWithInvalidAlias() throws Exception { @Test public void testSignRSA() throws Exception { + onRequest("/vedauth/authorize/oauth") + .havingMethodEqualTo("POST") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/sign") @@ -108,6 +123,11 @@ public void testSignRSA() throws Exception { @Test public void testSignECDSA() throws Exception { + onRequest("/vedauth/authorize/oauth") + .havingMethodEqualTo("POST") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/sign") @@ -128,6 +148,11 @@ public void testSignECDSA() throws Exception { @Test public void testSignRSAWithFailure() throws Exception { + onRequest("/vedauth/authorize/oauth") + .havingMethodEqualTo("POST") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/sign") @@ -145,6 +170,11 @@ public void testSignRSAWithFailure() throws Exception { @Test public void testSignECDSAWithFailure() throws Exception { + onRequest("/vedauth/authorize/oauth") + .havingMethodEqualTo("POST") + .respond() + .withStatus(200) + .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); onRequest() .havingMethodEqualTo("POST") .havingPathEqualTo("/vedhsm/api/sign") diff --git a/jsign-crypto/src/test/resources/services/venafi-authorize.json b/jsign-crypto/src/test/resources/services/venafi-authorize.json new file mode 100644 index 00000000..dd87e3d4 --- /dev/null +++ b/jsign-crypto/src/test/resources/services/venafi-authorize.json @@ -0,0 +1,10 @@ +{ + "access_token": "FpBFnGsryqrIiuzewOc3aw==", + "refresh_token": "enLssS1xDzxZ\/M0EJMlRIQ==", + "expires_in": 7775999, + "expires": 1747751472, + "token_type": "Bearer", + "scope": "codesignclient", + "identity": "local:{412fb225-b109-48c9-85d6-3abf45f725dc}", + "refresh_until": 1771511472 +} \ No newline at end of file From c072b421d06c16669b43771a162bde01cab04539 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Wed, 19 Feb 2025 12:24:02 -0800 Subject: [PATCH 09/10] additional fixes --- .../net/jsign/jca/VenafiSigningService.java | 13 ------------- .../jsign/jca/VenafiSigningServiceTest.java | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java index 5984fa58..c36258fc 100644 --- a/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java +++ b/jsign-crypto/src/main/java/net/jsign/jca/VenafiSigningService.java @@ -77,19 +77,6 @@ public class VenafiSigningService implements SigningService { /** The name of the Venafi CodeSign Protect certificate KeyId */ private String KeyId; - /** Mapping between Java and Venafi CodeSign Protect signing algorithms */ - private final Map algorithmMapping = new HashMap<>(); - { - algorithmMapping.put("SHA1withRSA", 6); - algorithmMapping.put("SHA256withRSA", 64); - algorithmMapping.put("SHA384withRSA", 65); - algorithmMapping.put("SHA512withRSA", 66); - algorithmMapping.put("SHA1withECDSA", 4162); - algorithmMapping.put("SHA256withECDSA", 4164); - algorithmMapping.put("SHA384withECDSA", 4165); - algorithmMapping.put("SHA512withECDSA", 4166); - } - /* Add ASN.1 DER prefix to MessageDigest */ public static byte[] addASN1Prefix(DigestAlgorithm digestAlgorithm, byte[] hash) throws IOException { diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java index 4f12d6bd..90d64dec 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java @@ -56,8 +56,9 @@ public void testGetAliases() throws Exception { @Test public void testGetCertificateChain() throws Exception { - onRequest("/vedauth/authorize/oauth") + onRequest() .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedauth/authorize/oauth") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); @@ -78,8 +79,9 @@ public void testGetCertificateChain() throws Exception { @Test public void testGetCertificateChainWithInvalidAlias() throws Exception { - onRequest("/vedauth/authorize/oauth") + onRequest() .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedauth/authorize/oauth") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); @@ -99,8 +101,9 @@ public void testGetCertificateChainWithInvalidAlias() throws Exception { @Test public void testSignRSA() throws Exception { - onRequest("/vedauth/authorize/oauth") + onRequest() .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedauth/authorize/oauth") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); @@ -123,8 +126,9 @@ public void testSignRSA() throws Exception { @Test public void testSignECDSA() throws Exception { - onRequest("/vedauth/authorize/oauth") + onRequest() .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedauth/authorize/oauth") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); @@ -148,8 +152,9 @@ public void testSignECDSA() throws Exception { @Test public void testSignRSAWithFailure() throws Exception { - onRequest("/vedauth/authorize/oauth") + onRequest() .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedauth/authorize/oauth") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); @@ -170,8 +175,9 @@ public void testSignRSAWithFailure() throws Exception { @Test public void testSignECDSAWithFailure() throws Exception { - onRequest("/vedauth/authorize/oauth") + onRequest() .havingMethodEqualTo("POST") + .havingPathEqualTo("/vedauth/authorize/oauth") .respond() .withStatus(200) .withBody(new FileReader("target/test-classes/services/venafi-authorize.json")); From 0ec9bbc534b062b86bd7adf71dd215b0d821bc44 Mon Sep 17 00:00:00 2001 From: Ivan Wallis Date: Wed, 19 Feb 2025 13:06:40 -0800 Subject: [PATCH 10/10] update tests --- .../src/test/java/net/jsign/jca/VenafiSigningServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java index 90d64dec..6fdafccd 100644 --- a/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java +++ b/jsign-crypto/src/test/java/net/jsign/jca/VenafiSigningServiceTest.java @@ -113,7 +113,7 @@ public void testSignRSA() throws Exception { .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") .respond() .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-sign.json")); + .withBody(new FileReader("target/test-classes/services/venafi-sign-rsa.json")); SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-rsa-cert", null); @@ -138,7 +138,7 @@ public void testSignECDSA() throws Exception { .havingHeaderEqualTo("Authorization", "Bearer da49LbfHokLO+fKwFIneJg==") .respond() .withStatus(200) - .withBody(new FileReader("target/test-classes/services/venafi-sign.json")); + .withBody(new FileReader("target/test-classes/services/venafi-sign-ecdsa.json")); SigningService service = new VenafiSigningService("http://localhost:" + port(), new VenafiCredentials("username", "password", null)); SigningServicePrivateKey privateKey = service.getPrivateKey("project-test-ecdsa-cert", null);