diff --git a/src/main/java/io/kamax/mxisd/Mxisd.java b/src/main/java/io/kamax/mxisd/Mxisd.java
index 2410f70..6eb47ed 100644
--- a/src/main/java/io/kamax/mxisd/Mxisd.java
+++ b/src/main/java/io/kamax/mxisd/Mxisd.java
@@ -27,6 +27,9 @@ import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.backend.sql.synapse.Synapse;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.crypto.CryptoFactory;
+import io.kamax.mxisd.crypto.KeyManager;
+import io.kamax.mxisd.crypto.SignatureManager;
+import io.kamax.mxisd.crypto.ed25519.Ed25519KeyManager;
import io.kamax.mxisd.directory.DirectoryManager;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.dns.ClientDnsOverwrite;
@@ -47,9 +50,6 @@ import io.kamax.mxisd.profile.ProfileProviders;
import io.kamax.mxisd.registration.RegistrationManager;
import io.kamax.mxisd.session.SessionManager;
import io.kamax.mxisd.storage.IStorage;
-import io.kamax.mxisd.storage.crypto.Ed25519KeyManager;
-import io.kamax.mxisd.storage.crypto.KeyManager;
-import io.kamax.mxisd.storage.crypto.SignatureManager;
import io.kamax.mxisd.storage.ormlite.OrmLiteSqlStorage;
import org.apache.commons.lang.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
diff --git a/src/main/java/io/kamax/mxisd/crypto/CryptoFactory.java b/src/main/java/io/kamax/mxisd/crypto/CryptoFactory.java
index 38f1263..253e978 100644
--- a/src/main/java/io/kamax/mxisd/crypto/CryptoFactory.java
+++ b/src/main/java/io/kamax/mxisd/crypto/CryptoFactory.java
@@ -21,7 +21,11 @@
package io.kamax.mxisd.crypto;
import io.kamax.mxisd.config.KeyConfig;
-import io.kamax.mxisd.storage.crypto.*;
+import io.kamax.mxisd.crypto.ed25519.Ed25519KeyManager;
+import io.kamax.mxisd.crypto.ed25519.Ed25519SignatureManager;
+import io.kamax.mxisd.storage.crypto.FileKeyStore;
+import io.kamax.mxisd.storage.crypto.KeyStore;
+import io.kamax.mxisd.storage.crypto.MemoryKeyStore;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/GenericKey.java b/src/main/java/io/kamax/mxisd/crypto/GenericKey.java
similarity index 97%
rename from src/main/java/io/kamax/mxisd/storage/crypto/GenericKey.java
rename to src/main/java/io/kamax/mxisd/crypto/GenericKey.java
index 7d59079..685ac2d 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/GenericKey.java
+++ b/src/main/java/io/kamax/mxisd/crypto/GenericKey.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
public class GenericKey implements Key {
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/GenericKeyIdentifier.java b/src/main/java/io/kamax/mxisd/crypto/GenericKeyIdentifier.java
similarity index 65%
rename from src/main/java/io/kamax/mxisd/storage/crypto/GenericKeyIdentifier.java
rename to src/main/java/io/kamax/mxisd/crypto/GenericKeyIdentifier.java
index 0390eda..9dda144 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/GenericKeyIdentifier.java
+++ b/src/main/java/io/kamax/mxisd/crypto/GenericKeyIdentifier.java
@@ -18,7 +18,11 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Objects;
public class GenericKeyIdentifier implements KeyIdentifier {
@@ -31,7 +35,11 @@ public class GenericKeyIdentifier implements KeyIdentifier {
}
public GenericKeyIdentifier(KeyType type, String algo, String serial) {
- this.type = type;
+ if (StringUtils.isAnyBlank(algo, serial)) {
+ throw new IllegalArgumentException("Aglorith and/or Serial cannot be blank");
+ }
+
+ this.type = Objects.requireNonNull(type);
this.algo = algo;
this.serial = serial;
}
@@ -51,4 +59,18 @@ public class GenericKeyIdentifier implements KeyIdentifier {
return serial;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof GenericKeyIdentifier)) return false;
+ GenericKeyIdentifier that = (GenericKeyIdentifier) o;
+ return type == that.type &&
+ algo.equals(that.algo) &&
+ serial.equals(that.serial);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, algo, serial);
+ }
}
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/Key.java b/src/main/java/io/kamax/mxisd/crypto/Key.java
similarity index 96%
rename from src/main/java/io/kamax/mxisd/storage/crypto/Key.java
rename to src/main/java/io/kamax/mxisd/crypto/Key.java
index 9a98917..628e237 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/Key.java
+++ b/src/main/java/io/kamax/mxisd/crypto/Key.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
/**
* A signing key
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/KeyAlgorithm.java b/src/main/java/io/kamax/mxisd/crypto/KeyAlgorithm.java
similarity index 95%
rename from src/main/java/io/kamax/mxisd/storage/crypto/KeyAlgorithm.java
rename to src/main/java/io/kamax/mxisd/crypto/KeyAlgorithm.java
index bb453ee..4e63d35 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/KeyAlgorithm.java
+++ b/src/main/java/io/kamax/mxisd/crypto/KeyAlgorithm.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
public interface KeyAlgorithm {
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/KeyIdentifier.java b/src/main/java/io/kamax/mxisd/crypto/KeyIdentifier.java
similarity index 97%
rename from src/main/java/io/kamax/mxisd/storage/crypto/KeyIdentifier.java
rename to src/main/java/io/kamax/mxisd/crypto/KeyIdentifier.java
index db28f25..1954d06 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/KeyIdentifier.java
+++ b/src/main/java/io/kamax/mxisd/crypto/KeyIdentifier.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
/**
* Identifying data for a given Key.
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/KeyManager.java b/src/main/java/io/kamax/mxisd/crypto/KeyManager.java
similarity index 96%
rename from src/main/java/io/kamax/mxisd/storage/crypto/KeyManager.java
rename to src/main/java/io/kamax/mxisd/crypto/KeyManager.java
index 68a2cbc..a36f70b 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/KeyManager.java
+++ b/src/main/java/io/kamax/mxisd/crypto/KeyManager.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
import java.util.List;
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/KeyType.java b/src/main/java/io/kamax/mxisd/crypto/KeyType.java
similarity index 96%
rename from src/main/java/io/kamax/mxisd/storage/crypto/KeyType.java
rename to src/main/java/io/kamax/mxisd/crypto/KeyType.java
index 84565f6..2b63ba2 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/KeyType.java
+++ b/src/main/java/io/kamax/mxisd/crypto/KeyType.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
/**
* Types of keys used by an Identity server.
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/RegularKeyIdentifier.java b/src/main/java/io/kamax/mxisd/crypto/RegularKeyIdentifier.java
similarity index 96%
rename from src/main/java/io/kamax/mxisd/storage/crypto/RegularKeyIdentifier.java
rename to src/main/java/io/kamax/mxisd/crypto/RegularKeyIdentifier.java
index b1b8721..3990587 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/RegularKeyIdentifier.java
+++ b/src/main/java/io/kamax/mxisd/crypto/RegularKeyIdentifier.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
public class RegularKeyIdentifier extends GenericKeyIdentifier {
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/Signature.java b/src/main/java/io/kamax/mxisd/crypto/Signature.java
similarity index 95%
rename from src/main/java/io/kamax/mxisd/storage/crypto/Signature.java
rename to src/main/java/io/kamax/mxisd/crypto/Signature.java
index 9174449..08d5887 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/Signature.java
+++ b/src/main/java/io/kamax/mxisd/crypto/Signature.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
public interface Signature {
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/SignatureManager.java b/src/main/java/io/kamax/mxisd/crypto/SignatureManager.java
similarity index 73%
rename from src/main/java/io/kamax/mxisd/storage/crypto/SignatureManager.java
rename to src/main/java/io/kamax/mxisd/crypto/SignatureManager.java
index 316cb2c..bcfdcfa 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/SignatureManager.java
+++ b/src/main/java/io/kamax/mxisd/crypto/SignatureManager.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto;
import com.google.gson.JsonObject;
@@ -26,10 +26,17 @@ import java.nio.charset.StandardCharsets;
public interface SignatureManager {
+ /**
+ * Sign the message and produce a signatures object that can directly be added to the object being signed.
+ *
+ * @param domain The domain under which the signature should be added
+ * @param message The message to sign
+ * @return The signatures object
+ */
JsonObject signMessageGson(String domain, String message);
/**
- * Sign the canonical form of a JSON object
+ * Sign the canonical form of a JSON object.
*
* @param obj The JSON object to canonicalize and sign
* @return The signature
@@ -37,17 +44,17 @@ public interface SignatureManager {
Signature sign(JsonObject obj);
/**
- * Sign the message, using UTF-8 as decoding character set
+ * Sign the message, using UTF-8 as decoding character set.
*
* @param message The UTF-8 encoded message
- * @return
+ * @return The signature
*/
default Signature sign(String message) {
return sign(message.getBytes(StandardCharsets.UTF_8));
}
/**
- * Sign the data
+ * Sign the data.
*
* @param data The data to sign
* @return The signature
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/Ed25519Key.java b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519Key.java
similarity index 86%
rename from src/main/java/io/kamax/mxisd/storage/crypto/Ed25519Key.java
rename to src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519Key.java
index af31552..1416101 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/Ed25519Key.java
+++ b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519Key.java
@@ -18,7 +18,12 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto.ed25519;
+
+import io.kamax.mxisd.crypto.GenericKeyIdentifier;
+import io.kamax.mxisd.crypto.Key;
+import io.kamax.mxisd.crypto.KeyAlgorithm;
+import io.kamax.mxisd.crypto.KeyIdentifier;
public class Ed25519Key implements Key {
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/Ed25519KeyManager.java b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519KeyManager.java
similarity index 86%
rename from src/main/java/io/kamax/mxisd/storage/crypto/Ed25519KeyManager.java
rename to src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519KeyManager.java
index 2b4dae5..ac64475 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/Ed25519KeyManager.java
+++ b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519KeyManager.java
@@ -18,9 +18,11 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto.ed25519;
import io.kamax.matrix.codec.MxBase64;
+import io.kamax.mxisd.crypto.*;
+import io.kamax.mxisd.storage.crypto.KeyStore;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.KeyPairGenerator;
@@ -38,6 +40,7 @@ import java.nio.ByteBuffer;
import java.security.KeyPair;
import java.time.Instant;
import java.util.List;
+import java.util.stream.Collectors;
public class Ed25519KeyManager implements KeyManager {
@@ -51,7 +54,12 @@ public class Ed25519KeyManager implements KeyManager {
this.store = store;
if (!store.getCurrentKey().isPresent()) {
- List keys = store.list(KeyType.Regular);
+ List keys = store.list(KeyType.Regular).stream()
+ .map(this::getKey)
+ .filter(Key::isValid)
+ .map(Key::getId)
+ .collect(Collectors.toList());
+
if (keys.isEmpty()) {
keys.add(generateKey(KeyType.Regular));
}
@@ -60,17 +68,17 @@ public class Ed25519KeyManager implements KeyManager {
}
}
- protected String generateId() {
+ private String generateId() {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(Instant.now().toEpochMilli() - 1546297200000L); // TS since 2019-01-01T00:00:00Z to keep IDs short
return Base64.encodeBase64URLSafeString(buffer.array()) + RandomStringUtils.randomAlphanumeric(1);
}
- protected String getPrivateKeyBase64(EdDSAPrivateKey key) {
+ private String getPrivateKeyBase64(EdDSAPrivateKey key) {
return MxBase64.encode(key.getSeed());
}
- public EdDSAParameterSpec getKeySpecs() {
+ EdDSAParameterSpec getKeySpecs() {
return keySpecs;
}
@@ -105,15 +113,15 @@ public class Ed25519KeyManager implements KeyManager {
return store.get(id);
}
- public EdDSAPrivateKeySpec getPrivateKeySpecs(KeyIdentifier id) {
+ private EdDSAPrivateKeySpec getPrivateKeySpecs(KeyIdentifier id) {
return new EdDSAPrivateKeySpec(Base64.decodeBase64(getKey(id).getPrivateKeyBase64()), keySpecs);
}
- public EdDSAPrivateKey getPrivateKey(KeyIdentifier id) {
+ EdDSAPrivateKey getPrivateKey(KeyIdentifier id) {
return new EdDSAPrivateKey(getPrivateKeySpecs(id));
}
- public EdDSAPublicKey getPublicKey(KeyIdentifier id) {
+ private EdDSAPublicKey getPublicKey(KeyIdentifier id) {
EdDSAPrivateKeySpec privKeySpec = getPrivateKeySpecs(id);
EdDSAPublicKeySpec pubKeySpec = new EdDSAPublicKeySpec(privKeySpec.getA(), keySpecs);
return new EdDSAPublicKey(pubKeySpec);
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/Ed2219RegularKeyIdentifier.java b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519RegularKeyIdentifier.java
similarity index 76%
rename from src/main/java/io/kamax/mxisd/storage/crypto/Ed2219RegularKeyIdentifier.java
rename to src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519RegularKeyIdentifier.java
index 091728a..e0d5856 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/Ed2219RegularKeyIdentifier.java
+++ b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519RegularKeyIdentifier.java
@@ -18,11 +18,14 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto.ed25519;
-public class Ed2219RegularKeyIdentifier extends RegularKeyIdentifier {
+import io.kamax.mxisd.crypto.KeyAlgorithm;
+import io.kamax.mxisd.crypto.RegularKeyIdentifier;
- public Ed2219RegularKeyIdentifier(String serial) {
+public class Ed25519RegularKeyIdentifier extends RegularKeyIdentifier {
+
+ public Ed25519RegularKeyIdentifier(String serial) {
super(KeyAlgorithm.Ed25519, serial);
}
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/Ed25519SignatureManager.java b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519SignatureManager.java
similarity index 94%
rename from src/main/java/io/kamax/mxisd/storage/crypto/Ed25519SignatureManager.java
rename to src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519SignatureManager.java
index cbb1f1f..dab5a99 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/Ed25519SignatureManager.java
+++ b/src/main/java/io/kamax/mxisd/crypto/ed25519/Ed25519SignatureManager.java
@@ -18,11 +18,14 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.storage.crypto;
+package io.kamax.mxisd.crypto.ed25519;
import com.google.gson.JsonObject;
import io.kamax.matrix.codec.MxBase64;
import io.kamax.matrix.json.MatrixJson;
+import io.kamax.mxisd.crypto.KeyIdentifier;
+import io.kamax.mxisd.crypto.Signature;
+import io.kamax.mxisd.crypto.SignatureManager;
import net.i2p.crypto.eddsa.EdDSAEngine;
import java.security.InvalidKeyException;
diff --git a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/EphemeralKeyIsValidHandler.java b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/EphemeralKeyIsValidHandler.java
index d39ccc1..0f70013 100644
--- a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/EphemeralKeyIsValidHandler.java
+++ b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/EphemeralKeyIsValidHandler.java
@@ -20,9 +20,9 @@
package io.kamax.mxisd.http.undertow.handler.identity.v1;
+import io.kamax.mxisd.crypto.KeyManager;
+import io.kamax.mxisd.crypto.KeyType;
import io.kamax.mxisd.http.IsAPIv1;
-import io.kamax.mxisd.storage.crypto.KeyManager;
-import io.kamax.mxisd.storage.crypto.KeyType;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/KeyGetHandler.java b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/KeyGetHandler.java
index 4a1ac69..8b1de81 100644
--- a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/KeyGetHandler.java
+++ b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/KeyGetHandler.java
@@ -21,11 +21,11 @@
package io.kamax.mxisd.http.undertow.handler.identity.v1;
import com.google.gson.JsonObject;
+import io.kamax.mxisd.crypto.GenericKeyIdentifier;
+import io.kamax.mxisd.crypto.KeyManager;
+import io.kamax.mxisd.crypto.KeyType;
import io.kamax.mxisd.http.IsAPIv1;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
-import io.kamax.mxisd.storage.crypto.GenericKeyIdentifier;
-import io.kamax.mxisd.storage.crypto.KeyManager;
-import io.kamax.mxisd.storage.crypto.KeyType;
import io.undertow.server.HttpServerExchange;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
diff --git a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/RegularKeyIsValidHandler.java b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/RegularKeyIsValidHandler.java
index f181ed9..6b5167c 100644
--- a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/RegularKeyIsValidHandler.java
+++ b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/RegularKeyIsValidHandler.java
@@ -20,9 +20,9 @@
package io.kamax.mxisd.http.undertow.handler.identity.v1;
+import io.kamax.mxisd.crypto.KeyManager;
+import io.kamax.mxisd.crypto.KeyType;
import io.kamax.mxisd.http.IsAPIv1;
-import io.kamax.mxisd.storage.crypto.KeyManager;
-import io.kamax.mxisd.storage.crypto.KeyType;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SignEd25519Handler.java b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SignEd25519Handler.java
index f76e7f5..8d6dc7e 100644
--- a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SignEd25519Handler.java
+++ b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SignEd25519Handler.java
@@ -26,11 +26,11 @@ import io.kamax.matrix._MatrixID;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.MatrixJson;
import io.kamax.mxisd.config.MxisdConfig;
+import io.kamax.mxisd.crypto.SignatureManager;
import io.kamax.mxisd.http.IsAPIv1;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.kamax.mxisd.invitation.IThreePidInviteReply;
import io.kamax.mxisd.invitation.InvitationManager;
-import io.kamax.mxisd.storage.crypto.SignatureManager;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java
index 8702b5d..d81d38c 100644
--- a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java
+++ b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java
@@ -26,12 +26,12 @@ import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.MatrixJson;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.config.ServerConfig;
+import io.kamax.mxisd.crypto.SignatureManager;
import io.kamax.mxisd.http.IsAPIv1;
import io.kamax.mxisd.http.io.identity.SingeLookupReplyJson;
import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
-import io.kamax.mxisd.storage.crypto.SignatureManager;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/StoreInviteHandler.java b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/StoreInviteHandler.java
index 1d22ab4..11996a0 100644
--- a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/StoreInviteHandler.java
+++ b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/StoreInviteHandler.java
@@ -26,6 +26,7 @@ import io.kamax.matrix.MatrixID;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.config.ServerConfig;
+import io.kamax.mxisd.crypto.KeyManager;
import io.kamax.mxisd.exception.BadRequestException;
import io.kamax.mxisd.http.IsAPIv1;
import io.kamax.mxisd.http.io.identity.StoreInviteRequest;
@@ -35,7 +36,6 @@ import io.kamax.mxisd.invitation.IThreePidInvite;
import io.kamax.mxisd.invitation.IThreePidInviteReply;
import io.kamax.mxisd.invitation.InvitationManager;
import io.kamax.mxisd.invitation.ThreePidInvite;
-import io.kamax.mxisd.storage.crypto.KeyManager;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.QueryParameterUtils;
import org.apache.commons.lang3.StringUtils;
diff --git a/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java b/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java
index f8004a7..362f867 100644
--- a/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java
+++ b/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java
@@ -29,6 +29,7 @@ import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.config.InvitationConfig;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.config.ServerConfig;
+import io.kamax.mxisd.crypto.*;
import io.kamax.mxisd.dns.FederationDnsOverwrite;
import io.kamax.mxisd.exception.BadRequestException;
import io.kamax.mxisd.exception.ConfigurationException;
@@ -40,7 +41,6 @@ import io.kamax.mxisd.lookup.strategy.LookupStrategy;
import io.kamax.mxisd.notification.NotificationManager;
import io.kamax.mxisd.profile.ProfileManager;
import io.kamax.mxisd.storage.IStorage;
-import io.kamax.mxisd.storage.crypto.*;
import io.kamax.mxisd.storage.ormlite.dao.ThreePidInviteIO;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyJson.java b/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyJson.java
index 15164e9..5938a9d 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyJson.java
+++ b/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyJson.java
@@ -20,6 +20,8 @@
package io.kamax.mxisd.storage.crypto;
+import io.kamax.mxisd.crypto.Key;
+
public class FileKeyJson {
public static FileKeyJson get(Key key) {
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyStore.java b/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyStore.java
index 025353d..7ced08b 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyStore.java
+++ b/src/main/java/io/kamax/mxisd/storage/crypto/FileKeyStore.java
@@ -23,6 +23,7 @@ package io.kamax.mxisd.storage.crypto;
import com.google.gson.JsonObject;
import io.kamax.matrix.crypto.KeyFileStore;
import io.kamax.matrix.json.GsonUtil;
+import io.kamax.mxisd.crypto.*;
import io.kamax.mxisd.exception.ObjectNotFoundException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
@@ -54,31 +55,39 @@ public class FileKeyStore implements KeyStore {
base = new File(path).getAbsoluteFile().toString();
File f = new File(base);
- if (f.exists() && f.isFile()) {
+ if (!f.exists()) {
try {
- log.info("Found old key store format at {}, migrating...", base);
- File oldStorePath = new File(f.toString() + ".backup-before-migration");
- FileUtils.moveFile(f, oldStorePath);
FileUtils.forceMkdir(f);
-
-
- String privKey = new KeyFileStore(oldStorePath.toString()).load().orElse("");
- if (StringUtils.isBlank(privKey)) {
- log.info("Empty file, nothing to migrate");
- } else {
- // We ensure this is valid Base64 data before migrating
- Base64.decodeBase64(privKey);
-
- // We store the new key
- add(new GenericKey(new GenericKeyIdentifier(KeyType.Regular, KeyAlgorithm.Ed25519, "0"), true, privKey));
-
- log.info("Store migrated to new directory format");
- }
} catch (IOException e) {
- throw new RuntimeException("Unable to migrate store from old single file format to new directory format", e);
+ throw new RuntimeException("Unable to create key store");
}
} else {
- log.info("Key store is already in directory format");
+ if (f.isFile()) {
+ try {
+ log.info("Found old key store format at {}, migrating...", base);
+ File oldStorePath = new File(f.toString() + ".backup-before-migration");
+ FileUtils.moveFile(f, oldStorePath);
+ FileUtils.forceMkdir(f);
+
+
+ String privKey = new KeyFileStore(oldStorePath.toString()).load().orElse("");
+ if (StringUtils.isBlank(privKey)) {
+ log.info("Empty file, nothing to migrate");
+ } else {
+ // We ensure this is valid Base64 data before migrating
+ Base64.decodeBase64(privKey);
+
+ // We store the new key
+ add(new GenericKey(new GenericKeyIdentifier(KeyType.Regular, KeyAlgorithm.Ed25519, "0"), true, privKey));
+
+ log.info("Store migrated to new directory format");
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to migrate store from old single file format to new directory format", e);
+ }
+ } else {
+ log.info("Key store is already in directory format");
+ }
}
if (!f.isDirectory()) {
@@ -207,6 +216,10 @@ public class FileKeyStore implements KeyStore {
@Override
public void setCurrentKey(KeyIdentifier id) throws IllegalArgumentException {
+ if (!has(id)) {
+ throw new IllegalArgumentException("Key " + id.getType() + ":" + id.getAlgorithm() + ":" + id.getSerial() + " is not known to the store");
+ }
+
JsonObject json = new JsonObject();
json.addProperty("type", id.getType().name());
json.addProperty("algo", id.getAlgorithm());
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/KeyStore.java b/src/main/java/io/kamax/mxisd/storage/crypto/KeyStore.java
index 72c24b3..23c7277 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/KeyStore.java
+++ b/src/main/java/io/kamax/mxisd/storage/crypto/KeyStore.java
@@ -20,6 +20,9 @@
package io.kamax.mxisd.storage.crypto;
+import io.kamax.mxisd.crypto.Key;
+import io.kamax.mxisd.crypto.KeyIdentifier;
+import io.kamax.mxisd.crypto.KeyType;
import io.kamax.mxisd.exception.ObjectNotFoundException;
import java.util.List;
@@ -84,9 +87,9 @@ public interface KeyStore {
* Store the information of which key is the current signing key
*
* @param id The key identifier
- * @throws ObjectNotFoundException If the key is not known to the store
+ * @throws IllegalArgumentException If the key is not known to the store
*/
- void setCurrentKey(KeyIdentifier id) throws ObjectNotFoundException;
+ void setCurrentKey(KeyIdentifier id) throws IllegalArgumentException;
/**
* Retrieve the previously stored information of which key is the current signing key, if any
diff --git a/src/main/java/io/kamax/mxisd/storage/crypto/MemoryKeyStore.java b/src/main/java/io/kamax/mxisd/storage/crypto/MemoryKeyStore.java
index d2d8419..f67df68 100644
--- a/src/main/java/io/kamax/mxisd/storage/crypto/MemoryKeyStore.java
+++ b/src/main/java/io/kamax/mxisd/storage/crypto/MemoryKeyStore.java
@@ -20,18 +20,18 @@
package io.kamax.mxisd.storage.crypto;
+import io.kamax.mxisd.crypto.*;
import io.kamax.mxisd.exception.ObjectNotFoundException;
-import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class MemoryKeyStore implements KeyStore {
- private Map>> keys = new ConcurrentHashMap<>();
+ private Map>> keys = new ConcurrentHashMap<>();
private KeyIdentifier current;
- private Map getMap(KeyType type, String algo) {
+ private Map getMap(KeyType type, String algo) {
return keys.computeIfAbsent(type, k -> new ConcurrentHashMap<>()).computeIfAbsent(algo, k -> new ConcurrentHashMap<>());
}
@@ -56,23 +56,23 @@ public class MemoryKeyStore implements KeyStore {
@Override
public Key get(KeyIdentifier id) throws ObjectNotFoundException {
- String data = getMap(id.getType(), id.getAlgorithm()).get(id.getSerial());
+ FileKeyJson data = getMap(id.getType(), id.getAlgorithm()).get(id.getSerial());
if (Objects.isNull(data)) {
throw new ObjectNotFoundException("Key", id.getType() + ":" + id.getAlgorithm() + ":" + id.getSerial());
}
- return new GenericKey(new GenericKeyIdentifier(id), StringUtils.isEmpty(data), data);
+ return new GenericKey(new GenericKeyIdentifier(id), data.isValid(), data.getKey());
}
private void set(Key key) {
- String data = key.isValid() ? key.getPrivateKeyBase64() : "";
+ FileKeyJson data = FileKeyJson.get(key);
getMap(key.getId().getType(), key.getId().getAlgorithm()).put(key.getId().getSerial(), data);
}
@Override
public void add(Key key) throws IllegalStateException {
if (has(key.getId())) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Key " + key.getId().getId() + " already exists");
}
set(key);
@@ -89,13 +89,17 @@ public class MemoryKeyStore implements KeyStore {
@Override
public void delete(KeyIdentifier id) throws ObjectNotFoundException {
+ if (!has(id)) {
+ throw new ObjectNotFoundException("Key", id.getType() + ":" + id.getAlgorithm() + ":" + id.getSerial());
+ }
+
keys.computeIfAbsent(id.getType(), k -> new ConcurrentHashMap<>()).computeIfAbsent(id.getAlgorithm(), k -> new ConcurrentHashMap<>()).remove(id.getSerial());
}
@Override
- public void setCurrentKey(KeyIdentifier id) throws ObjectNotFoundException {
+ public void setCurrentKey(KeyIdentifier id) throws IllegalArgumentException {
if (!has(id)) {
- throw new ObjectNotFoundException("Key", id.getType() + ":" + id.getAlgorithm() + ":" + id.getSerial());
+ throw new IllegalArgumentException("Key " + id.getType() + ":" + id.getAlgorithm() + ":" + id.getSerial() + " is not known to the store");
}
current = id;
diff --git a/src/test/java/io/kamax/mxisd/test/storage/crypto/KeyTest.java b/src/test/java/io/kamax/mxisd/test/crypto/KeyTest.java
similarity index 96%
rename from src/test/java/io/kamax/mxisd/test/storage/crypto/KeyTest.java
rename to src/test/java/io/kamax/mxisd/test/crypto/KeyTest.java
index 4c5a365..aa0fd34 100644
--- a/src/test/java/io/kamax/mxisd/test/storage/crypto/KeyTest.java
+++ b/src/test/java/io/kamax/mxisd/test/crypto/KeyTest.java
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.test.storage.crypto;
+package io.kamax.mxisd.test.crypto;
public class KeyTest {
diff --git a/src/test/java/io/kamax/mxisd/test/storage/crypto/SignatureManagerTest.java b/src/test/java/io/kamax/mxisd/test/crypto/SignatureManagerTest.java
similarity index 86%
rename from src/test/java/io/kamax/mxisd/test/storage/crypto/SignatureManagerTest.java
rename to src/test/java/io/kamax/mxisd/test/crypto/SignatureManagerTest.java
index 9c4a3ac..06d2fed 100644
--- a/src/test/java/io/kamax/mxisd/test/storage/crypto/SignatureManagerTest.java
+++ b/src/test/java/io/kamax/mxisd/test/crypto/SignatureManagerTest.java
@@ -18,12 +18,19 @@
* along with this program. If not, see .
*/
-package io.kamax.mxisd.test.storage.crypto;
+package io.kamax.mxisd.test.crypto;
import com.google.gson.JsonObject;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.MatrixJson;
-import io.kamax.mxisd.storage.crypto.*;
+import io.kamax.mxisd.crypto.Signature;
+import io.kamax.mxisd.crypto.SignatureManager;
+import io.kamax.mxisd.crypto.ed25519.Ed25519Key;
+import io.kamax.mxisd.crypto.ed25519.Ed25519KeyManager;
+import io.kamax.mxisd.crypto.ed25519.Ed25519RegularKeyIdentifier;
+import io.kamax.mxisd.crypto.ed25519.Ed25519SignatureManager;
+import io.kamax.mxisd.storage.crypto.KeyStore;
+import io.kamax.mxisd.storage.crypto.MemoryKeyStore;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -36,7 +43,7 @@ public class SignatureManagerTest {
private static SignatureManager signMgr;
private static SignatureManager build(String keySeed) {
- Ed25519Key key = new Ed25519Key(new Ed2219RegularKeyIdentifier("0"), keySeed);
+ Ed25519Key key = new Ed25519Key(new Ed25519RegularKeyIdentifier("0"), keySeed);
KeyStore store = new MemoryKeyStore();
store.add(key);
diff --git a/src/test/java/io/kamax/mxisd/test/storage/crypto/FileKeyStoreTest.java b/src/test/java/io/kamax/mxisd/test/storage/crypto/FileKeyStoreTest.java
new file mode 100644
index 0000000..fdfed23
--- /dev/null
+++ b/src/test/java/io/kamax/mxisd/test/storage/crypto/FileKeyStoreTest.java
@@ -0,0 +1,42 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2019 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.test.storage.crypto;
+
+import io.kamax.mxisd.storage.crypto.FileKeyStore;
+import io.kamax.mxisd.storage.crypto.KeyStore;
+import org.apache.commons.io.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.UUID;
+
+public class FileKeyStoreTest extends KeyStoreTest {
+
+ @Override
+ public KeyStore create() throws IOException {
+ String path = FileUtils.getTempDirectoryPath() +
+ "/mxisd-test-key-store-" +
+ UUID.randomUUID().toString().replace("-", "");
+ FileUtils.forceDeleteOnExit(new File(path));
+ return new FileKeyStore(path);
+ }
+
+}
diff --git a/src/test/java/io/kamax/mxisd/test/storage/crypto/KeyStoreTest.java b/src/test/java/io/kamax/mxisd/test/storage/crypto/KeyStoreTest.java
new file mode 100644
index 0000000..dd64dcf
--- /dev/null
+++ b/src/test/java/io/kamax/mxisd/test/storage/crypto/KeyStoreTest.java
@@ -0,0 +1,128 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2019 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.test.storage.crypto;
+
+import io.kamax.mxisd.crypto.*;
+import io.kamax.mxisd.exception.ObjectNotFoundException;
+import io.kamax.mxisd.storage.crypto.KeyStore;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Optional;
+
+import static org.junit.Assert.*;
+
+public abstract class KeyStoreTest {
+
+ private KeyStore store;
+
+ public abstract KeyStore create() throws Exception;
+
+ private Key generateRandomKey() {
+ KeyIdentifier keyId = new GenericKeyIdentifier(KeyType.Regular, "algo", RandomStringUtils.randomAlphanumeric(6));
+ return new GenericKey(keyId, true, RandomStringUtils.randomAlphanumeric(48));
+ }
+
+ @Before
+ public void before() throws Exception {
+ store = create();
+ }
+
+ @Test
+ public void isEmptyAfterCreate() {
+ assertTrue(store.list().isEmpty());
+ assertFalse(store.getCurrentKey().isPresent());
+ }
+
+ @Test
+ public void add() {
+ Key key = generateRandomKey();
+ KeyIdentifier keyId = key.getId();
+
+ store.add(key);
+
+ Key keyFromStore = store.get(keyId);
+ assertEquals(key.getId(), keyFromStore.getId());
+ assertEquals(key.getPrivateKeyBase64(), keyFromStore.getPrivateKeyBase64());
+ assertEquals(key.isValid(), keyFromStore.isValid());
+
+ assertTrue(store.list().contains(keyId));
+ assertTrue(store.list(keyId.getType()).contains(keyId));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void addDuplicate() {
+ Key key = generateRandomKey();
+ store.add(key);
+ store.add(key);
+ }
+
+ @Test
+ public void update() {
+ Key key = generateRandomKey();
+ store.add(key);
+
+ Key keyUpdated = new GenericKey(key.getId(), !key.isValid(), key.getPrivateKeyBase64());
+ store.update(keyUpdated);
+
+ Key keyFromStore = store.get(key.getId());
+ assertEquals(key.getId(), keyFromStore.getId());
+ assertEquals(key.getPrivateKeyBase64(), keyFromStore.getPrivateKeyBase64());
+ assertEquals(key.isValid(), !keyFromStore.isValid());
+ }
+
+ @Test(expected = ObjectNotFoundException.class)
+ public void updateNonExisting() {
+ store.update(generateRandomKey());
+ }
+
+ @Test
+ public void delete() {
+ Key key = generateRandomKey();
+ store.add(key);
+
+ store.delete(key.getId());
+ assertFalse(store.list().contains(key.getId()));
+ assertFalse(store.list(key.getId().getType()).contains(key.getId()));
+ }
+
+ @Test(expected = ObjectNotFoundException.class)
+ public void deleteNonExisting() {
+ store.delete(generateRandomKey().getId());
+ }
+
+ @Test
+ public void setCurrentKey() {
+ Key key = generateRandomKey();
+ store.add(key);
+ store.setCurrentKey(key.getId());
+ Optional currentKey = store.getCurrentKey();
+ assertTrue(currentKey.isPresent());
+ assertEquals(currentKey.get(), key.getId());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void setCurrentKeyNonExisting() {
+ store.setCurrentKey(generateRandomKey().getId());
+ }
+
+}
diff --git a/src/test/java/io/kamax/mxisd/test/storage/crypto/MemoryKeyStoreTest.java b/src/test/java/io/kamax/mxisd/test/storage/crypto/MemoryKeyStoreTest.java
new file mode 100644
index 0000000..af918da
--- /dev/null
+++ b/src/test/java/io/kamax/mxisd/test/storage/crypto/MemoryKeyStoreTest.java
@@ -0,0 +1,33 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2019 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.test.storage.crypto;
+
+import io.kamax.mxisd.storage.crypto.KeyStore;
+import io.kamax.mxisd.storage.crypto.MemoryKeyStore;
+
+public class MemoryKeyStoreTest extends KeyStoreTest {
+
+ @Override
+ public KeyStore create() {
+ return new MemoryKeyStore();
+ }
+
+}