From c2d42a8a7fae930552f2867914c0ab2c293e6a2a Mon Sep 17 00:00:00 2001 From: Hellblazer Date: Sat, 6 Jan 2024 16:44:10 -0800 Subject: [PATCH] add encryption caps, expand keystore to alias storage :( moar cleanup --- .../apollo/cryptography/EdDSAOperations.java | 4 +- .../cryptography/EncryptionAlgorithm.java | 116 ++++++++++++++++++ .../cryptography/SignatureAlgorithm.java | 42 +------ .../salesforce/apollo/cryptography/XTest.java | 56 +++++++++ .../com/salesforce/apollo/model/Domain.java | 3 - .../apollo/model/ProcessContainerDomain.java | 34 +++-- pom.xml | 10 ++ stereotomy/pom.xml | 2 +- .../apollo/stereotomy/StereotomyKeyStore.java | 13 +- .../apollo/stereotomy/jks/FileKeyStore.java | 34 ++++- .../apollo/stereotomy/jks/JksKeyStore.java | 103 ++++++++-------- .../apollo/stereotomy/mem/MemKeyStore.java | 27 +++- .../apollo/stereotomy/FileKeyStoreTest.java | 7 +- .../apollo/stereotomy/JksKeyStoreTest.java | 7 +- 14 files changed, 321 insertions(+), 137 deletions(-) create mode 100644 cryptography/src/main/java/com/salesforce/apollo/cryptography/EncryptionAlgorithm.java create mode 100644 cryptography/src/test/java/com/salesforce/apollo/cryptography/XTest.java diff --git a/cryptography/src/main/java/com/salesforce/apollo/cryptography/EdDSAOperations.java b/cryptography/src/main/java/com/salesforce/apollo/cryptography/EdDSAOperations.java index 9131e34710..50b9be23b4 100644 --- a/cryptography/src/main/java/com/salesforce/apollo/cryptography/EdDSAOperations.java +++ b/cryptography/src/main/java/com/salesforce/apollo/cryptography/EdDSAOperations.java @@ -72,7 +72,7 @@ public EdDSAOperations(SignatureAlgorithm signatureAlgorithm) { } } - private static void reverse(byte[] arr) { + public static void reverse(byte[] arr) { var i = 0; var j = arr.length - 1; @@ -83,7 +83,7 @@ private static void reverse(byte[] arr) { } } - private static void swap(byte[] arr, int i, int j) { + public static void swap(byte[] arr, int i, int j) { var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; diff --git a/cryptography/src/main/java/com/salesforce/apollo/cryptography/EncryptionAlgorithm.java b/cryptography/src/main/java/com/salesforce/apollo/cryptography/EncryptionAlgorithm.java new file mode 100644 index 0000000000..04a68ffd32 --- /dev/null +++ b/cryptography/src/main/java/com/salesforce/apollo/cryptography/EncryptionAlgorithm.java @@ -0,0 +1,116 @@ +package com.salesforce.apollo.cryptography; + +import java.math.BigInteger; +import java.security.*; +import java.security.interfaces.EdECPrivateKey; +import java.security.interfaces.EdECPublicKey; +import java.security.interfaces.XECPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.NamedParameterSpec; +import java.security.spec.XECPublicKeySpec; + +public enum EncryptionAlgorithm { + X_25519 { + @Override + public String algorithmName() { + return "X25519"; + } + + @Override + public String curveName() { + return "Curve25519"; + } + + @Override + public int publicKeyLength() { + return 32; + } + }, X_448 { + @Override + public String algorithmName() { + return "X448"; + } + + @Override + public String curveName() { + return "Curve448"; + } + + @Override + public int publicKeyLength() { + return 57; + } + }; + + public static EncryptionAlgorithm lookup(PrivateKey privateKey) { + return switch (privateKey.getAlgorithm()) { + case "XDH" -> lookupX(((EdECPrivateKey) privateKey).getParams()); + case "x25519" -> X_25519; + case "x448" -> X_448; + default -> throw new IllegalArgumentException("Unknown algorithm: " + privateKey.getAlgorithm()); + }; + } + + public static EncryptionAlgorithm lookup(PublicKey publicKey) { + return switch (publicKey.getAlgorithm()) { + case "XDH" -> lookupX(((EdECPublicKey) publicKey).getParams()); + case "X25519" -> X_25519; + case "X448" -> X_448; + default -> throw new IllegalArgumentException("Unknown algorithm: " + publicKey.getAlgorithm()); + }; + } + + private static EncryptionAlgorithm lookupX(NamedParameterSpec params) { + var curveName = params.getName(); + return switch (curveName.toLowerCase()) { + case "x25519" -> X_25519; + case "x448" -> X_448; + default -> throw new IllegalArgumentException("Unknown edwards curve: " + curveName); + }; + } + + abstract public String algorithmName(); + + abstract public String curveName(); + + final public byte[] encode(PublicKey publicKey) { + return ((XECPublicKey) publicKey).getU().toByteArray(); + } + + final public KeyPair generateKeyPair() { + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH"); + kpg.initialize(getParamSpec()); + return kpg.generateKeyPair(); + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { + throw new IllegalArgumentException("Cannot generate key pair", e); + } + } + + final public KeyPair generateKeyPair(SecureRandom secureRandom) { + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH"); + kpg.initialize(getParamSpec(), secureRandom); + return kpg.generateKeyPair(); + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { + throw new IllegalArgumentException("Cannot generate key pair", e); + } + } + + final public PublicKey publicKey(byte[] bytes) { + try { + KeyFactory kf = KeyFactory.getInstance("XDH"); + BigInteger u = new BigInteger(bytes); + XECPublicKeySpec pubSpec = new XECPublicKeySpec(getParamSpec(), u); + return kf.generatePublic(pubSpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new IllegalArgumentException("Cannot create public key", e); + } + } + + abstract public int publicKeyLength(); + + private NamedParameterSpec getParamSpec() { + return new NamedParameterSpec(algorithmName()); + } +} diff --git a/cryptography/src/main/java/com/salesforce/apollo/cryptography/SignatureAlgorithm.java b/cryptography/src/main/java/com/salesforce/apollo/cryptography/SignatureAlgorithm.java index 2e535d71b9..5965ff6e02 100644 --- a/cryptography/src/main/java/com/salesforce/apollo/cryptography/SignatureAlgorithm.java +++ b/cryptography/src/main/java/com/salesforce/apollo/cryptography/SignatureAlgorithm.java @@ -56,16 +56,6 @@ public KeyPair generateKeyPair(SecureRandom secureRandom) { return ops.generateKeyPair(secureRandom); } - @Override - public PrivateKey privateKey(byte[] bytes) { - return ops.privateKey(bytes); - } - - @Override - public int privateKeyLength() { - return 32; - } - @Override public PublicKey publicKey(byte[] bytes) { return ops.publicKey(bytes); @@ -141,16 +131,6 @@ public KeyPair generateKeyPair(SecureRandom secureRandom) { return ops.generateKeyPair(secureRandom); } - @Override - public PrivateKey privateKey(byte[] bytes) { - return ops.privateKey(bytes); - } - - @Override - public int privateKeyLength() { - return 56; - } - @Override public PublicKey publicKey(byte[] bytes) { return ops.publicKey(bytes); @@ -222,16 +202,6 @@ public KeyPair generateKeyPair(SecureRandom secureRandom) { return null; } - @Override - public PrivateKey privateKey(byte[] bytes) { - return null; - } - - @Override - public int privateKeyLength() { - return 0; - } - @Override public PublicKey publicKey(byte[] bytes) { return null; @@ -330,14 +300,6 @@ private static SignatureAlgorithm lookupEd(NamedParameterSpec params) { abstract public KeyPair generateKeyPair(SecureRandom secureRandom); - public KeyPair keyPair(byte[] bytes, byte[] publicKey) { - return new KeyPair(publicKey(publicKey), privateKey(bytes)); - } - - abstract public PrivateKey privateKey(byte[] bytes); - - abstract public int privateKeyLength(); - abstract public PublicKey publicKey(byte[] bytes); abstract public int publicKeyLength(); @@ -374,12 +336,12 @@ final public boolean verify(PublicKey publicKey, JohnHancock signature, ByteStri return verify(publicKey, signature, BbBackedInputStream.aggregate(message)); } - abstract protected boolean verify(PublicKey publicKey, byte[] signature, InputStream message); - abstract JohnHancock sign(ULong sequenceNumber, PrivateKey[] privateKeys, InputStream message); final boolean verify(PublicKey publicKey, JohnHancock signature, InputStream message) { return new DefaultVerifier(new PublicKey[] { publicKey }).verify(SigningThreshold.unweighted(1), signature, message); } + + abstract protected boolean verify(PublicKey publicKey, byte[] signature, InputStream message); } diff --git a/cryptography/src/test/java/com/salesforce/apollo/cryptography/XTest.java b/cryptography/src/test/java/com/salesforce/apollo/cryptography/XTest.java new file mode 100644 index 0000000000..0d99a08eb9 --- /dev/null +++ b/cryptography/src/test/java/com/salesforce/apollo/cryptography/XTest.java @@ -0,0 +1,56 @@ +package com.salesforce.apollo.cryptography; + +import org.junit.jupiter.api.Test; + +import javax.crypto.KeyAgreement; +import java.security.SecureRandom; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author hal.hildebrand + **/ +public class XTest { + @Test + public void testEncoding() throws Exception { + var entropy = SecureRandom.getInstance("SHA1PRNG"); + entropy.setSeed(new byte[] { 6, 6, 6 }); + + var algorithm = EncryptionAlgorithm.X_25519; + var pair = algorithm.generateKeyPair(entropy); + assertNotNull(pair); + var encodedPublic = algorithm.encode(pair.getPublic()); + assertNotNull(encodedPublic); + var decodedPublic = algorithm.publicKey(encodedPublic); + assertNotNull(decodedPublic); + assertEquals(pair.getPublic(), decodedPublic); + } + + @Test + public void testRoundTrip() throws Exception { + var entropy = SecureRandom.getInstance("SHA1PRNG"); + entropy.setSeed(new byte[] { 6, 6, 6 }); + + var algorithm = EncryptionAlgorithm.X_25519; + var pair1 = algorithm.generateKeyPair(entropy); + assertNotNull(pair1); + var pair2 = algorithm.generateKeyPair(entropy); + assertNotNull(pair2); + + KeyAgreement ka = KeyAgreement.getInstance("XDH"); + KeyAgreement ka2 = KeyAgreement.getInstance("XDH"); + + ka.init(pair1.getPrivate()); + ka2.init(pair2.getPrivate()); + + ka.doPhase(pair2.getPublic(), true); + ka2.doPhase(pair1.getPublic(), true); + + byte[] secret1 = ka.generateSecret(); + assertNotNull(secret1); + byte[] secret2 = ka2.generateSecret(); + assertNotNull(secret2); + + assertArrayEquals(secret1, secret2); + } +} diff --git a/model/src/main/java/com/salesforce/apollo/model/Domain.java b/model/src/main/java/com/salesforce/apollo/model/Domain.java index 87112adb73..7d876b7908 100644 --- a/model/src/main/java/com/salesforce/apollo/model/Domain.java +++ b/model/src/main/java/com/salesforce/apollo/model/Domain.java @@ -47,8 +47,6 @@ import java.sql.Connection; import java.sql.JDBCType; import java.util.*; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import static com.salesforce.apollo.cryptography.QualifiedBase64.qb64; import static java.nio.file.Path.of; @@ -62,7 +60,6 @@ abstract public class Domain { private static final Logger log = LoggerFactory.getLogger(Domain.class); - protected final Executor executor = Executors.newVirtualThreadPerTaskExecutor(); protected final CHOAM choam; protected final ControlledIdentifierMember member; protected final Mutator mutator; diff --git a/model/src/main/java/com/salesforce/apollo/model/ProcessContainerDomain.java b/model/src/main/java/com/salesforce/apollo/model/ProcessContainerDomain.java index 8c7882dad2..6f04e70618 100644 --- a/model/src/main/java/com/salesforce/apollo/model/ProcessContainerDomain.java +++ b/model/src/main/java/com/salesforce/apollo/model/ProcessContainerDomain.java @@ -42,9 +42,7 @@ import java.nio.file.Path; import java.time.Duration; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import static com.salesforce.apollo.comm.grpc.DomainSocketServerInterceptor.IMPL; @@ -55,22 +53,22 @@ **/ public class ProcessContainerDomain extends ProcessDomain { - private final static Logger log = LoggerFactory.getLogger( + private final static Logger log = LoggerFactory.getLogger( ProcessContainerDomain.class); - private final static Class channelType = IMPL.getChannelType(); - - private final DomainSocketAddress bridge; - private final EventLoopGroup clientEventLoopGroup = IMPL.getEventLoopGroup(); - private final Path communicationsDirectory; - private final EventLoopGroup contextEventLoopGroup = IMPL.getEventLoopGroup(); - private final Map hostedDomains = new ConcurrentHashMap<>(); - private final DomainSocketAddress outerContextEndpoint; - private final Server outerContextService; - private final Portal portal; - private final DomainSocketAddress portalEndpoint; - private final EventLoopGroup portalEventLoopGroup = IMPL.getEventLoopGroup(); - private final Map routes = new HashMap<>(); - private final IdentifierSpecification.Builder subDomainSpecification; + private final static Class channelType = IMPL.getChannelType(); + protected final Executor executor = Executors.newVirtualThreadPerTaskExecutor(); + private final DomainSocketAddress bridge; + private final EventLoopGroup clientEventLoopGroup = IMPL.getEventLoopGroup(); + private final Path communicationsDirectory; + private final EventLoopGroup contextEventLoopGroup = IMPL.getEventLoopGroup(); + private final Map hostedDomains = new ConcurrentHashMap<>(); + private final DomainSocketAddress outerContextEndpoint; + private final Server outerContextService; + private final Portal portal; + private final DomainSocketAddress portalEndpoint; + private final EventLoopGroup portalEventLoopGroup = IMPL.getEventLoopGroup(); + private final Map routes = new HashMap<>(); + private final IdentifierSpecification.Builder subDomainSpecification; public ProcessContainerDomain(Digest group, ControlledIdentifierMember member, ProcessDomainParameters parameters, Parameters.Builder builder, Parameters.RuntimeParameters.Builder runtime, diff --git a/pom.xml b/pom.xml index 93364fc578..0fe5dc06df 100644 --- a/pom.xml +++ b/pom.xml @@ -552,6 +552,11 @@ ${graal.vm.version} provided + + org.netbeans.api + org-netbeans-modules-keyring + RELEASE200 + @@ -772,6 +777,11 @@ maven-surefire-plugin 3.1.2 + + org.apache.maven.plugins + maven-clean-plugin + 3.3.2 + org.apache.maven.plugins maven-compiler-plugin diff --git a/stereotomy/pom.xml b/stereotomy/pom.xml index ff874279b1..7f99a70405 100644 --- a/stereotomy/pom.xml +++ b/stereotomy/pom.xml @@ -83,8 +83,8 @@ build-helper-maven-plugin + org.apache.maven.plugins maven-clean-plugin - 2.5 clean-db diff --git a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/StereotomyKeyStore.java b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/StereotomyKeyStore.java index 372bfaf002..1e3f3bfe3f 100644 --- a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/StereotomyKeyStore.java +++ b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/StereotomyKeyStore.java @@ -10,22 +10,27 @@ import java.util.Optional; /** - * The interface for a keystore that tracks KeyPairs by keyCoordinates, and - * knows about current and next keypairs associated with those coordinates - * - * @author hal.hildebrand + * The interface for a keystore that tracks KeyPairs by keyCoordinates, and knows about current and next keypairs + * associated with those coordinates * + * @author hal.hildebrand */ public interface StereotomyKeyStore { + Optional getKey(String alias); + Optional getKey(KeyCoordinates keyCoordinates); Optional getNextKey(KeyCoordinates keyCoordinates); void removeKey(KeyCoordinates keyCoordinates); + void removeKey(String alias); + void removeNextKey(KeyCoordinates keyCoordinates); + void storeKey(String alias, KeyPair keyPair); + void storeKey(KeyCoordinates keyCoordinates, KeyPair keyPair); void storeNextKey(KeyCoordinates keyCoordinates, KeyPair keyPair); diff --git a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/FileKeyStore.java b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/FileKeyStore.java index 84a19a9e8f..d54284f9f8 100644 --- a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/FileKeyStore.java +++ b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/FileKeyStore.java @@ -6,6 +6,10 @@ */ package com.salesforce.apollo.stereotomy.jks; +import com.salesforce.apollo.stereotomy.KeyCoordinates; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -16,12 +20,8 @@ import java.security.cert.CertificateException; import java.util.function.Supplier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * @author hal.hildebrand - * */ public class FileKeyStore extends JksKeyStore { private static final Logger log = LoggerFactory.getLogger(FileKeyStore.class); @@ -37,8 +37,30 @@ public FileKeyStore(KeyStore keyStore, Supplier passwordProvider, File f } @Override - protected void store(String alias, KeyPair keyPair) { - super.store(alias, keyPair); + public void removeKey(String alias) { + super.removeKey(alias); + save(); + } + + @Override + public void removeKey(KeyCoordinates keyCoordinates) { + super.removeKey(keyCoordinates); + save(); + } + + @Override + public void removeNextKey(KeyCoordinates keyCoordinates) { + super.removeNextKey(keyCoordinates); + save(); + } + + @Override + public void storeKey(String alias, KeyPair keyPair) { + super.storeKey(alias, keyPair); + save(); + } + + private void save() { try (var fos = new FileOutputStream(file)) { keyStore.store(fos, passwordProvider.get()); } catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException e) { diff --git a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/JksKeyStore.java b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/JksKeyStore.java index de662e958f..2b23f92381 100644 --- a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/JksKeyStore.java +++ b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/jks/JksKeyStore.java @@ -6,16 +6,16 @@ */ package com.salesforce.apollo.stereotomy.jks; -import static com.salesforce.apollo.cryptography.QualifiedBase64.qb64; -import static com.salesforce.apollo.stereotomy.identifier.QualifiedBase64Identifier.qb64; +import com.salesforce.apollo.cryptography.cert.BcX500NameDnImpl; +import com.salesforce.apollo.cryptography.cert.CertExtension; +import com.salesforce.apollo.cryptography.cert.Certificates; +import com.salesforce.apollo.stereotomy.KeyCoordinates; +import com.salesforce.apollo.stereotomy.StereotomyKeyStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.math.BigInteger; -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.UnrecoverableKeyException; +import java.security.*; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.time.Instant; @@ -26,26 +26,27 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.salesforce.apollo.cryptography.cert.BcX500NameDnImpl; -import com.salesforce.apollo.cryptography.cert.CertExtension; -import com.salesforce.apollo.cryptography.cert.Certificates; -import com.salesforce.apollo.stereotomy.KeyCoordinates; -import com.salesforce.apollo.stereotomy.StereotomyKeyStore; +import static com.salesforce.apollo.cryptography.QualifiedBase64.qb64; +import static com.salesforce.apollo.stereotomy.identifier.QualifiedBase64Identifier.qb64; /** * @author hal.hildebrand - * */ public class JksKeyStore implements StereotomyKeyStore { - private static Logger log = LoggerFactory.getLogger(JksKeyStore.class); + private static final Logger log = LoggerFactory.getLogger(JksKeyStore.class); + protected final KeyStore keyStore; + protected final Supplier passwordProvider; + private final Lock lock = new ReentrantLock(); + + public JksKeyStore(KeyStore keyStore, Supplier passwordProvider) { + this.keyStore = keyStore; + this.passwordProvider = passwordProvider; + } public static String coordinateOrdering(KeyCoordinates coords) { var eventCoords = coords.getEstablishmentEvent(); - return qb64(eventCoords.getIdentifier()) + ':' + eventCoords.getSequenceNumber() + ':' - + qb64(eventCoords.getDigest()) + ":" + Integer.toString(coords.getKeyIndex()); + return qb64(eventCoords.getIdentifier()) + ':' + eventCoords.getSequenceNumber() + ':' + qb64( + eventCoords.getDigest()) + ":" + coords.getKeyIndex(); } private static String current(KeyCoordinates keyCoordinates) { @@ -56,14 +57,9 @@ private static String next(KeyCoordinates keyCoordinates) { return String.format("%s:%s", coordinateOrdering(keyCoordinates), "1"); } - protected final KeyStore keyStore; - protected final Supplier passwordProvider; - - private final Lock lock = new ReentrantLock(); - - public JksKeyStore(KeyStore keyStore, Supplier passwordProvider) { - this.keyStore = keyStore; - this.passwordProvider = passwordProvider; + @Override + public Optional getKey(String alias) { + return get(alias, null); } @Override @@ -79,12 +75,21 @@ public Optional getNextKey(KeyCoordinates keyCoordinates) { @Override public void removeKey(KeyCoordinates keyCoordinates) { try { - keyStore.deleteEntry(next(keyCoordinates)); + keyStore.deleteEntry(current(keyCoordinates)); } catch (KeyStoreException e) { throw new IllegalStateException("Error deleting current: " + keyCoordinates, e); } } + @Override + public void removeKey(String alias) { + try { + keyStore.deleteEntry(alias); + } catch (KeyStoreException e) { + throw new IllegalStateException("Error deleting: " + alias, e); + } + } + @Override public void removeNextKey(KeyCoordinates keyCoordinates) { try { @@ -94,11 +99,26 @@ public void removeNextKey(KeyCoordinates keyCoordinates) { } } + public void storeKey(final String alias, KeyPair keyPair) { + BcX500NameDnImpl dn = new BcX500NameDnImpl("CN=noop"); + BigInteger sn = BigInteger.valueOf(Long.MAX_VALUE); + var notBefore = Instant.now(); + var notAfter = Instant.now().plusSeconds(2_000_000_000); + List extensions = Collections.emptyList(); + X509Certificate selfSignedCert = Certificates.selfSign(true, dn, sn, keyPair, notBefore, notAfter, extensions); + try { + keyStore.setKeyEntry(alias, keyPair.getPrivate(), passwordProvider.get(), + new Certificate[] { selfSignedCert }); + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + } + @Override public void storeKey(KeyCoordinates keyCoordinates, KeyPair keyPair) { lock.lock(); try { - store(current(keyCoordinates), keyPair); + storeKey(current(keyCoordinates), keyPair); } finally { lock.unlock(); } @@ -108,41 +128,26 @@ public void storeKey(KeyCoordinates keyCoordinates, KeyPair keyPair) { public void storeNextKey(KeyCoordinates keyCoordinates, KeyPair keyPair) { lock.lock(); try { - store(next(keyCoordinates), keyPair); + storeKey(next(keyCoordinates), keyPair); } finally { lock.unlock(); } } - protected void store(final String alias, KeyPair keyPair) { - BcX500NameDnImpl dn = new BcX500NameDnImpl("CN=noop"); - BigInteger sn = BigInteger.valueOf(Long.MAX_VALUE); - var notBefore = Instant.now(); - var notAfter = Instant.now().plusSeconds(2_000_000_000); - List extensions = Collections.emptyList(); - X509Certificate selfSignedCert = Certificates.selfSign(true, dn, sn, keyPair, notBefore, notAfter, extensions); - try { - keyStore.setKeyEntry(alias, keyPair.getPrivate(), passwordProvider.get(), - new Certificate[] { selfSignedCert }); - } catch (KeyStoreException e) { - throw new IllegalStateException(e); - } - } - private Optional get(String alias, KeyCoordinates keyCoordinates) { try { if (!keyStore.containsAlias(alias)) { return Optional.empty(); } } catch (KeyStoreException e) { - log.error("Unable to query keystore for: {}", keyCoordinates, e); + log.error("Unable to query keystore for: {}", keyCoordinates != null ? keyCoordinates : alias, e); return Optional.empty(); } Certificate cert; try { cert = keyStore.getCertificate(alias); } catch (KeyStoreException e) { - log.error("Unable to retrieve certificate for: {}", keyCoordinates, e); + log.error("Unable to retrieve certificate for: {}", keyCoordinates != null ? keyCoordinates : alias, e); return Optional.empty(); } var publicKey = cert.getPublicKey(); @@ -150,7 +155,7 @@ private Optional get(String alias, KeyCoordinates keyCoordinates) { try { privateKey = (PrivateKey) keyStore.getKey(alias, passwordProvider.get()); } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) { - log.error("Unable to retrieve certificate for: {}", keyCoordinates, e); + log.error("Unable to retrieve certificate for: {}", keyCoordinates != null ? keyCoordinates : alias, e); return Optional.empty(); } return Optional.of(new KeyPair(publicKey, privateKey)); diff --git a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/mem/MemKeyStore.java b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/mem/MemKeyStore.java index 7480c578f3..b6a703e054 100644 --- a/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/mem/MemKeyStore.java +++ b/stereotomy/src/main/java/com/salesforce/apollo/stereotomy/mem/MemKeyStore.java @@ -6,22 +6,27 @@ */ package com.salesforce.apollo.stereotomy.mem; +import com.salesforce.apollo.stereotomy.KeyCoordinates; +import com.salesforce.apollo.stereotomy.StereotomyKeyStore; + import java.security.KeyPair; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; -import com.salesforce.apollo.stereotomy.KeyCoordinates; -import com.salesforce.apollo.stereotomy.StereotomyKeyStore; - /** * @author hal.hildebrand - * */ public class MemKeyStore implements StereotomyKeyStore { - private final Map keys = new ConcurrentHashMap<>(); - private final Map nextKeys = new ConcurrentHashMap<>(); + private final Map keys = new ConcurrentHashMap<>(); + private final Map nextKeys = new ConcurrentHashMap<>(); + private final Map aliasedKeys = new ConcurrentHashMap<>(); + + @Override + public Optional getKey(String alias) { + return Optional.ofNullable(aliasedKeys.get(alias)); + } @Override public Optional getKey(KeyCoordinates keyCoordinates) { @@ -38,11 +43,21 @@ public void removeKey(KeyCoordinates keyCoordinates) { this.keys.remove(keyCoordinates); } + @Override + public void removeKey(String alias) { + aliasedKeys.remove(alias); + } + @Override public void removeNextKey(KeyCoordinates keyCoordinates) { this.nextKeys.remove(keyCoordinates); } + @Override + public void storeKey(String alias, KeyPair keyPair) { + aliasedKeys.put(alias, keyPair); + } + @Override public void storeKey(KeyCoordinates coordinates, KeyPair keyPair) { this.keys.put(coordinates, keyPair); diff --git a/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/FileKeyStoreTest.java b/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/FileKeyStoreTest.java index a8c5f0bcaa..05d6ae7bd2 100644 --- a/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/FileKeyStoreTest.java +++ b/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/FileKeyStoreTest.java @@ -6,6 +6,8 @@ */ package com.salesforce.apollo.stereotomy; +import com.salesforce.apollo.stereotomy.jks.FileKeyStore; + import java.io.File; import java.io.IOException; import java.security.KeyStore; @@ -14,11 +16,8 @@ import java.security.cert.CertificateException; import java.util.function.Supplier; -import com.salesforce.apollo.stereotomy.jks.FileKeyStore; - /** * @author hal.hildebrand - * */ public class FileKeyStoreTest extends StereotomyTests { @@ -28,7 +27,7 @@ protected FileKeyStore initializeKeyStore() { file.delete(); final Supplier passwordProvider = () -> new char[] { 'f', 'o', 'o' }; try { - final var ks = KeyStore.getInstance("JKS"); + final var ks = KeyStore.getInstance("jceks"); ks.load(null, passwordProvider.get()); return new FileKeyStore(ks, passwordProvider, file); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { diff --git a/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/JksKeyStoreTest.java b/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/JksKeyStoreTest.java index 454e23f295..1f59a95218 100644 --- a/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/JksKeyStoreTest.java +++ b/stereotomy/src/test/java/com/salesforce/apollo/stereotomy/JksKeyStoreTest.java @@ -6,6 +6,8 @@ */ package com.salesforce.apollo.stereotomy; +import com.salesforce.apollo.stereotomy.jks.JksKeyStore; + import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -13,11 +15,8 @@ import java.security.cert.CertificateException; import java.util.function.Supplier; -import com.salesforce.apollo.stereotomy.jks.JksKeyStore; - /** * @author hal.hildebrand - * */ public class JksKeyStoreTest extends StereotomyTests { @@ -25,7 +24,7 @@ public class JksKeyStoreTest extends StereotomyTests { protected JksKeyStore initializeKeyStore() { final Supplier passwordProvider = () -> new char[] { 'f', 'o', 'o' }; try { - final var ks = KeyStore.getInstance("JKS"); + final var ks = KeyStore.getInstance("jceks"); ks.load(null, passwordProvider.get()); return new JksKeyStore(ks, passwordProvider); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {