diff --git a/convex-cli/src/main/java/convex/cli/client/AClientCommand.java b/convex-cli/src/main/java/convex/cli/client/AClientCommand.java index 6932d6e55..39213c175 100644 --- a/convex-cli/src/main/java/convex/cli/client/AClientCommand.java +++ b/convex-cli/src/main/java/convex/cli/client/AClientCommand.java @@ -109,7 +109,7 @@ protected void ensureKeyPair(Convex convex) throws InterruptedException { throw new CLIError(ExitCodes.CONFIG,"Multiple key pairs found"); } - keyPair=storeMixin.loadKeyFromStore(pk,keyMixin.getKeyPassword()); + keyPair=storeMixin.loadKeyFromStore(pk,()->keyMixin.getKeyPassword()); if (keyPair==null) { // We didn't find required keypair throw new CLIError(ExitCodes.CONFIG,"Can't find keypair with public key: "+pk); diff --git a/convex-cli/src/main/java/convex/cli/key/KeyExport.java b/convex-cli/src/main/java/convex/cli/key/KeyExport.java index 3b68dc9d1..49c6eba21 100644 --- a/convex-cli/src/main/java/convex/cli/key/KeyExport.java +++ b/convex-cli/src/main/java/convex/cli/key/KeyExport.java @@ -86,7 +86,7 @@ public void execute() { } String publicKey = keystorePublicKey; - AKeyPair keyPair = storeMixin.loadKeyFromStore(publicKey,keyMixin.getKeyPassword()); + AKeyPair keyPair = storeMixin.loadKeyFromStore(publicKey,()->keyMixin.getKeyPassword()); if (keyPair==null) { // TODO: maybe prompt? throw new CLIError("Key pair not found for key: "+keystorePublicKey); diff --git a/convex-cli/src/main/java/convex/cli/key/KeySign.java b/convex-cli/src/main/java/convex/cli/key/KeySign.java index d35e2c1c9..a6114f097 100644 --- a/convex-cli/src/main/java/convex/cli/key/KeySign.java +++ b/convex-cli/src/main/java/convex/cli/key/KeySign.java @@ -66,7 +66,7 @@ public void execute() { } String publicKey = keystorePublicKey; - AKeyPair keyPair = storeMixin.loadKeyFromStore(publicKey,keyMixin.getKeyPassword()); + AKeyPair keyPair = storeMixin.loadKeyFromStore(publicKey,()->keyMixin.getKeyPassword()); if (keyPair==null) { throw new CLIError(ExitCodes.NOUSER,"Key pair not found for requested signing key: "+keystorePublicKey); } diff --git a/convex-cli/src/main/java/convex/cli/local/LocalStart.java b/convex-cli/src/main/java/convex/cli/local/LocalStart.java index ee65cba9a..d0f938a5a 100644 --- a/convex-cli/src/main/java/convex/cli/local/LocalStart.java +++ b/convex-cli/src/main/java/convex/cli/local/LocalStart.java @@ -79,7 +79,7 @@ private List getPeerKeyPairs(int count) { String keyPrefix = values.get(index); if (keyPrefix.isBlank()) continue; - AKeyPair keyPair = storeMixin.loadKeyFromStore(keyPrefix, keyMixin.getKeyPassword()); + AKeyPair keyPair = storeMixin.loadKeyFromStore(keyPrefix, ()->keyMixin.getKeyPassword()); if (keyPair == null) { log.warn("Unable to find public key in store: "+keyPrefix); } else { diff --git a/convex-cli/src/main/java/convex/cli/mixins/KeyStoreMixin.java b/convex-cli/src/main/java/convex/cli/mixins/KeyStoreMixin.java index bff417ac4..39b9cb2d0 100644 --- a/convex-cli/src/main/java/convex/cli/mixins/KeyStoreMixin.java +++ b/convex-cli/src/main/java/convex/cli/mixins/KeyStoreMixin.java @@ -8,6 +8,7 @@ import java.security.KeyStore; import java.security.UnrecoverableKeyException; import java.util.Enumeration; +import java.util.function.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -199,7 +200,7 @@ public static String trimKey(String publicKey) { * @param publicKey String identifying the public key. May be a prefix * @return Keypair instance, or null if not found */ - public AKeyPair loadKeyFromStore(String publicKey, char[] keyPassword) { + public AKeyPair loadKeyFromStore(String publicKey, Supplier passFunction) { if (publicKey == null) return null; @@ -214,6 +215,7 @@ public AKeyPair loadKeyFromStore(String publicKey, char[] keyPassword) { String alias = aliases.nextElement(); if (alias.indexOf(publicKey) == 0) { log.trace("found keypair " + alias); + char[] keyPassword=passFunction.get(); return PFXTools.getKeyPair(keyStore, alias, keyPassword); } } diff --git a/convex-cli/src/main/java/convex/cli/peer/APeerCommand.java b/convex-cli/src/main/java/convex/cli/peer/APeerCommand.java index 112e74d19..01f770285 100644 --- a/convex-cli/src/main/java/convex/cli/peer/APeerCommand.java +++ b/convex-cli/src/main/java/convex/cli/peer/APeerCommand.java @@ -47,8 +47,7 @@ protected AKeyPair specifiedPeerKey() { paranoia("You must specify a --peer-key for the peer"); return null; } else { - char[] keyPass=peerKeyMixin.getKeyPassword(); - AKeyPair result=storeMixin.loadKeyFromStore(peerPublicKey, keyPass); + AKeyPair result=storeMixin.loadKeyFromStore(peerPublicKey, ()->peerKeyMixin.getKeyPassword()); return result; } } @@ -63,9 +62,7 @@ protected AKeyPair ensureControllerKey() { return null; } - char[] keyPass=keyMixin.getKeyPassword(); - - AKeyPair result=storeMixin.loadKeyFromStore(controllerKey, keyPass); + AKeyPair result=storeMixin.loadKeyFromStore(controllerKey, ()->keyMixin.getKeyPassword()); return result; } } diff --git a/convex-cli/src/main/java/convex/cli/peer/PeerStart.java b/convex-cli/src/main/java/convex/cli/peer/PeerStart.java index 0def650f1..82bd43940 100644 --- a/convex-cli/src/main/java/convex/cli/peer/PeerStart.java +++ b/convex-cli/src/main/java/convex/cli/peer/PeerStart.java @@ -110,7 +110,7 @@ private AKeyPair findPeerKey(EtchStore store) { throw new CLIError(ExitCodes.CONFIG,"Multiple peers configured in Etch store "+store+". specify which one you want with --peer-key."); } AccountKey peerKey=peerList.get(0); - AKeyPair pkp=storeMixin.loadKeyFromStore(peerKey.toHexString(), peerKeyMixin.getKeyPassword()); + AKeyPair pkp=storeMixin.loadKeyFromStore(peerKey.toHexString(), ()->peerKeyMixin.getKeyPassword()); return pkp; } catch (IOException e) { log.debug("IO Exception trying to read etch peer list",e); @@ -127,8 +127,12 @@ public void execute() throws InterruptedException { AKeyPair peerKey; AKeyPair genesisKey=null; if (genesis!=null&&(!genesis.isEmpty())) { + // Using a genesis seed for testing paranoia("Should't use Genesis Seed in strict security mode! Consider key compromised!"); Blob seed=Blob.parse(genesis); + if (seed==null) { + throw new CLIError("Genesis seed must be 32 byte hex blob"); + } if (seed.count()!=32) { throw new CLIError("Genesis seed must be 32 byte hex blob"); } @@ -136,6 +140,7 @@ public void execute() throws InterruptedException { genesisKey=peerKey; informWarning("Using test genesis seed: "+seed); } else { + // peerKey=findPeerKey(store); if (peerKey==null) { informWarning("No --peer-key specified or inferred from Etch Store "+store); diff --git a/convex-core/src/main/java/convex/core/crypto/PFXTools.java b/convex-core/src/main/java/convex/core/crypto/PFXTools.java index b7f78a039..7aa37a590 100644 --- a/convex-core/src/main/java/convex/core/crypto/PFXTools.java +++ b/convex-core/src/main/java/convex/core/crypto/PFXTools.java @@ -94,9 +94,9 @@ public static KeyStore saveStore(KeyStore ks, File keyFile, char[] storePassword * @param alias Alias used for finding the key pair in the store * @param keyPassword Passphrase used for decrypting the key pair. Mandatory. * @return Found key pair - * @throws UnrecoverableKeyException If key cannot be recovered - * @throws KeyStoreException If a general key store exception occurs - * @throws NoSuchAlgorithmException If crypto algorithm is not available + * @throws UnrecoverableKeyException if the key cannot be recovered (e.g. the password is wrong) + * @throws KeyStoreException if a general key store exception occurs + * @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found */ public static AKeyPair getKeyPair(KeyStore ks, String alias, char[] keyPassword) throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException { diff --git a/convex-core/src/main/java/convex/core/store/AStore.java b/convex-core/src/main/java/convex/core/store/AStore.java index 50a0be74e..73f320522 100644 --- a/convex-core/src/main/java/convex/core/store/AStore.java +++ b/convex-core/src/main/java/convex/core/store/AStore.java @@ -106,8 +106,9 @@ public Ref getRootRef() throws IOException { Hash h=getRootHash(); Ref ref=refForHash(h); - // special case, we always recognise null even if not in store - if ((ref==null) &&(Hash.NULL_HASH.equals(h))) { + // special cases: + // we always recognise `nil` or the zero hash `0x0000000....` even if not in store + if ((ref==null) &&((Hash.EMPTY_HASH.equals(h))||(Hash.NULL_HASH.equals(h)))) { return (Ref) Ref.NULL_VALUE; } return ref;