From fea59bab21bd73796abff1db5ecd10c14f211456 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Mon, 5 Aug 2024 17:02:25 -0700 Subject: [PATCH] updated keystore providers to handle root certs --- .../tools/security/EnvKeyProvider.java | 19 +++++++++ .../tools/security/FileKeyProvider.java | 19 +++++++++ .../tools/security/KeyStoreKeyProvider.java | 20 +++++----- .../security/MacKeyStoreKeyProvider.java | 28 ++++++++----- .../security/WindowsKeyStoreKeyProvider.java | 39 ++++++++++++------- 5 files changed, 90 insertions(+), 35 deletions(-) diff --git a/shared/src/main/java/ca/weblite/tools/security/EnvKeyProvider.java b/shared/src/main/java/ca/weblite/tools/security/EnvKeyProvider.java index 5a03bb7d..50bebcbd 100644 --- a/shared/src/main/java/ca/weblite/tools/security/EnvKeyProvider.java +++ b/shared/src/main/java/ca/weblite/tools/security/EnvKeyProvider.java @@ -12,6 +12,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.ArrayList; import java.util.Base64; import java.util.Collections; import java.util.List; @@ -21,6 +22,7 @@ public class EnvKeyProvider implements KeyProvider { private static final String ENV_VAR_SIGNING_KEY = "JDEPLOY_PRIVATE_KEY"; private static final String ENV_VAR_SIGNING_CERTIFICATE = "JDEPLOY_CERTIFICATE"; + private static final String ENV_VAR_ROOT_CERTIFICATE = "JDEPLOY_ROOT_CERTIFICATE"; private static final Pattern PEM_PATTERN = Pattern.compile("-----BEGIN (.+?)-----"); private final EnvVarProvider envVarProvider; @@ -64,9 +66,26 @@ public List getSigningCertificateChain() throws Exception { @Override public List getTrustedCertificates() throws Exception { + List trustedCerts = new ArrayList<>(); + trustedCerts.add(getSigningCertificate()); + Certificate rootCertificate = getRootCertificate(); + if (rootCertificate != null) { + trustedCerts.add(rootCertificate); + } return Collections.singletonList(getSigningCertificate()); } + private Certificate getRootCertificate() throws Exception { + String rootCertificateEnvVar = envVarProvider.getEnv(ENV_VAR_ROOT_CERTIFICATE); + if (rootCertificateEnvVar == null) { + return null; + } + + byte[] certBytes = loadKey(rootCertificateEnvVar); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + return factory.generateCertificate(new java.io.ByteArrayInputStream(certBytes)); + } + private byte[] loadKey(String key) throws Exception { if (PEM_PATTERN.matcher(key).find()) { return decodePEM(key); diff --git a/shared/src/main/java/ca/weblite/tools/security/FileKeyProvider.java b/shared/src/main/java/ca/weblite/tools/security/FileKeyProvider.java index c4081ff1..b245d9d0 100644 --- a/shared/src/main/java/ca/weblite/tools/security/FileKeyProvider.java +++ b/shared/src/main/java/ca/weblite/tools/security/FileKeyProvider.java @@ -10,6 +10,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.ArrayList; import java.util.Base64; import java.util.Collections; import java.util.List; @@ -19,10 +20,16 @@ public class FileKeyProvider implements KeyProvider { private final String privateKeyPath; private final String certificatePath; + private final String rootCertificatePath; public FileKeyProvider(String privateKeyPath, String certificatePath) { + this(privateKeyPath, certificatePath, null); + } + + public FileKeyProvider(String privateKeyPath, String certificatePath, String rootCertificatePath) { this.privateKeyPath = privateKeyPath; this.certificatePath = certificatePath; + this.rootCertificatePath = rootCertificatePath; } @Override @@ -48,9 +55,21 @@ public List getSigningCertificateChain() throws Exception { @Override public List getTrustedCertificates() throws Exception { + List trustedCerts = new ArrayList<>(); + trustedCerts.add(getSigningCertificate()); + if (rootCertificatePath != null) { + trustedCerts.add(getRootCertificate()); + } return Collections.singletonList(getSigningCertificate()); } + private Certificate getRootCertificate() throws Exception { + String pem = readPemFile(rootCertificatePath); + byte[] der = decodePem(pem); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + return factory.generateCertificate(new java.io.ByteArrayInputStream(der)); + } + private String readPemFile(String filePath) throws IOException { try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { return reader.lines() diff --git a/shared/src/main/java/ca/weblite/tools/security/KeyStoreKeyProvider.java b/shared/src/main/java/ca/weblite/tools/security/KeyStoreKeyProvider.java index cd5a7259..eb2f7550 100644 --- a/shared/src/main/java/ca/weblite/tools/security/KeyStoreKeyProvider.java +++ b/shared/src/main/java/ca/weblite/tools/security/KeyStoreKeyProvider.java @@ -83,19 +83,17 @@ public List getTrustedCertificates() throws Exception { keyStore.load(fis, keyStorePassword); } - if (rootCertificateAlias == null) { - // If the root alias is null, return the signing certificate as the root - Certificate signingCert = keyStore.getCertificate(certificateAlias); - if (signingCert == null) { - throw new Exception("No certificate found for alias: " + certificateAlias); + List trustedCerts = new ArrayList<>(); + trustedCerts.add(getSigningCertificate()); + + if (rootCertificateAlias != null) { + Certificate rootCert = keyStore.getCertificate(rootCertificateAlias); + if (rootCert == null) { + throw new Exception("No root certificate found for alias: " + rootCertificateAlias); } - return Collections.singletonList(signingCert); + trustedCerts.add(rootCert); } - Certificate rootCert = keyStore.getCertificate(rootCertificateAlias); - if (rootCert == null) { - throw new Exception("No root certificate found for alias: " + rootCertificateAlias); - } - return Collections.singletonList(rootCert); + return trustedCerts; } } diff --git a/shared/src/main/java/ca/weblite/tools/security/MacKeyStoreKeyProvider.java b/shared/src/main/java/ca/weblite/tools/security/MacKeyStoreKeyProvider.java index 882a2a41..8bb4a38d 100644 --- a/shared/src/main/java/ca/weblite/tools/security/MacKeyStoreKeyProvider.java +++ b/shared/src/main/java/ca/weblite/tools/security/MacKeyStoreKeyProvider.java @@ -58,20 +58,28 @@ public List getSigningCertificateChain() throws Exception { public List getTrustedCertificates() throws Exception { KeyStore keyStore = KeyStore.getInstance("KeychainStore"); keyStore.load(null, null); + List trustedCerts = new ArrayList<>(); + trustedCerts.add(getSigningCertificate()); - if (rootCertificateAlias == null) { - // If the root alias is null, return the signing certificate as the root - Certificate signingCert = keyStore.getCertificate(alias); - if (signingCert == null) { - throw new Exception("No certificate found for alias: " + alias); + if (rootCertificateAlias != null) { + Certificate rootCert = keyStore.getCertificate(rootCertificateAlias); + if (rootCert == null) { + throw new Exception("No root certificate found for alias: " + rootCertificateAlias); } - return Collections.singletonList(signingCert); + trustedCerts.add(getRootCertificate()); } - Certificate rootCert = keyStore.getCertificate(rootCertificateAlias); - if (rootCert == null) { - throw new Exception("No root certificate found for alias: " + rootCertificateAlias); + return trustedCerts; + + } + + private Certificate getRootCertificate() throws Exception { + KeyStore keyStore = KeyStore.getInstance("KeychainStore"); + keyStore.load(null, null); + Certificate cert = keyStore.getCertificate(rootCertificateAlias); + if (cert == null) { + throw new Exception("No certificate found for alias: " + rootCertificateAlias); } - return Collections.singletonList(rootCert); + return cert; } } diff --git a/shared/src/main/java/ca/weblite/tools/security/WindowsKeyStoreKeyProvider.java b/shared/src/main/java/ca/weblite/tools/security/WindowsKeyStoreKeyProvider.java index 5fef2887..20a0e4f7 100644 --- a/shared/src/main/java/ca/weblite/tools/security/WindowsKeyStoreKeyProvider.java +++ b/shared/src/main/java/ca/weblite/tools/security/WindowsKeyStoreKeyProvider.java @@ -76,28 +76,33 @@ public List getSigningCertificateChain() throws Exception { @Override public List getTrustedCertificates() throws Exception { - if (rootCertificateAlias == null) { - // If the root alias is null, return the signing certificate as the root - Certificate signingCert = getSigningCertificate(); - if (signingCert == null) { - throw new Exception("No certificate found for alias: " + alias); - } - return Collections.singletonList(signingCert); + KeyStore keyStore = KeyStore.getInstance("KeychainStore"); + keyStore.load(null, null); + + List trustedCerts = new ArrayList<>(); + trustedCerts.add(getSigningCertificate()); + + if (rootCertificateAlias != null) { + trustedCerts.add(getRootCertificate()); } + return trustedCerts; + } + + private Certificate getRootCertificate() throws Exception { // First try Windows-MY keystore - Certificate rootCert = getCertificateFromKeystore("Windows-MY", rootCertificateAlias); - if (rootCert != null) { - return Collections.singletonList(rootCert); + Certificate cert = getRootCertificateFromKeystore("Windows-MY"); + if (cert != null) { + return cert; } // If not found, try Windows-ROOT keystore - rootCert = getCertificateFromKeystore("Windows-ROOT", rootCertificateAlias); - if (rootCert != null) { - return Collections.singletonList(rootCert); + cert = getRootCertificateFromKeystore("Windows-ROOT"); + if (cert != null) { + return cert; } - throw new Exception("No root certificate found for alias: " + rootCertificateAlias); + throw new Exception("No certificate found for alias: " + rootCertificateAlias); } private PrivateKey getPrivateKeyFromKeystore(String keystoreType) throws Exception { @@ -112,6 +117,12 @@ private Certificate getCertificateFromKeystore(String keystoreType) throws Excep return keyStore.getCertificate(alias); } + private Certificate getRootCertificateFromKeystore(String keystoreType) throws Exception { + KeyStore keyStore = KeyStore.getInstance(keystoreType); + keyStore.load(null, null); + return keyStore.getCertificate(rootCertificateAlias); + } + private Certificate getCertificateFromKeystore(String keystoreType, String alias) throws Exception { KeyStore keyStore = KeyStore.getInstance(keystoreType); keyStore.load(null, null);