Improve crypto
- Re-organize packages to be consistent - Add Key store tests
This commit is contained in:
@@ -27,6 +27,9 @@ import io.kamax.mxisd.backend.IdentityStoreSupplier;
|
|||||||
import io.kamax.mxisd.backend.sql.synapse.Synapse;
|
import io.kamax.mxisd.backend.sql.synapse.Synapse;
|
||||||
import io.kamax.mxisd.config.MxisdConfig;
|
import io.kamax.mxisd.config.MxisdConfig;
|
||||||
import io.kamax.mxisd.crypto.CryptoFactory;
|
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.DirectoryManager;
|
||||||
import io.kamax.mxisd.directory.DirectoryProviders;
|
import io.kamax.mxisd.directory.DirectoryProviders;
|
||||||
import io.kamax.mxisd.dns.ClientDnsOverwrite;
|
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.registration.RegistrationManager;
|
||||||
import io.kamax.mxisd.session.SessionManager;
|
import io.kamax.mxisd.session.SessionManager;
|
||||||
import io.kamax.mxisd.storage.IStorage;
|
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 io.kamax.mxisd.storage.ormlite.OrmLiteSqlStorage;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
@@ -21,7 +21,11 @@
|
|||||||
package io.kamax.mxisd.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
import io.kamax.mxisd.config.KeyConfig;
|
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.io.FileUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
public class GenericKey implements Key {
|
public class GenericKey implements Key {
|
||||||
|
|
@@ -18,7 +18,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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 {
|
public class GenericKeyIdentifier implements KeyIdentifier {
|
||||||
|
|
||||||
@@ -31,7 +35,11 @@ public class GenericKeyIdentifier implements KeyIdentifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GenericKeyIdentifier(KeyType type, String algo, String serial) {
|
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.algo = algo;
|
||||||
this.serial = serial;
|
this.serial = serial;
|
||||||
}
|
}
|
||||||
@@ -51,4 +59,18 @@ public class GenericKeyIdentifier implements KeyIdentifier {
|
|||||||
return serial;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A signing key
|
* A signing key
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
public interface KeyAlgorithm {
|
public interface KeyAlgorithm {
|
||||||
|
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifying data for a given Key.
|
* Identifying data for a given Key.
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types of keys used by an Identity server.
|
* Types of keys used by an Identity server.
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
public class RegularKeyIdentifier extends GenericKeyIdentifier {
|
public class RegularKeyIdentifier extends GenericKeyIdentifier {
|
||||||
|
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
public interface Signature {
|
public interface Signature {
|
||||||
|
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
@@ -26,10 +26,17 @@ import java.nio.charset.StandardCharsets;
|
|||||||
|
|
||||||
public interface SignatureManager {
|
public interface SignatureManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign the message and produce a <code>signatures</code> 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 <code>signatures</code> object
|
||||||
|
*/
|
||||||
JsonObject signMessageGson(String domain, String message);
|
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
|
* @param obj The JSON object to canonicalize and sign
|
||||||
* @return The signature
|
* @return The signature
|
||||||
@@ -37,17 +44,17 @@ public interface SignatureManager {
|
|||||||
Signature sign(JsonObject obj);
|
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
|
* @param message The UTF-8 encoded message
|
||||||
* @return
|
* @return The signature
|
||||||
*/
|
*/
|
||||||
default Signature sign(String message) {
|
default Signature sign(String message) {
|
||||||
return sign(message.getBytes(StandardCharsets.UTF_8));
|
return sign(message.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign the data
|
* Sign the data.
|
||||||
*
|
*
|
||||||
* @param data The data to sign
|
* @param data The data to sign
|
||||||
* @return The signature
|
* @return The signature
|
@@ -18,7 +18,12 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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 {
|
public class Ed25519Key implements Key {
|
||||||
|
|
@@ -18,9 +18,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto.ed25519;
|
||||||
|
|
||||||
import io.kamax.matrix.codec.MxBase64;
|
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.EdDSAPrivateKey;
|
||||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||||
import net.i2p.crypto.eddsa.KeyPairGenerator;
|
import net.i2p.crypto.eddsa.KeyPairGenerator;
|
||||||
@@ -38,6 +40,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Ed25519KeyManager implements KeyManager {
|
public class Ed25519KeyManager implements KeyManager {
|
||||||
|
|
||||||
@@ -51,7 +54,12 @@ public class Ed25519KeyManager implements KeyManager {
|
|||||||
this.store = store;
|
this.store = store;
|
||||||
|
|
||||||
if (!store.getCurrentKey().isPresent()) {
|
if (!store.getCurrentKey().isPresent()) {
|
||||||
List<KeyIdentifier> keys = store.list(KeyType.Regular);
|
List<KeyIdentifier> keys = store.list(KeyType.Regular).stream()
|
||||||
|
.map(this::getKey)
|
||||||
|
.filter(Key::isValid)
|
||||||
|
.map(Key::getId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
if (keys.isEmpty()) {
|
if (keys.isEmpty()) {
|
||||||
keys.add(generateKey(KeyType.Regular));
|
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);
|
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
|
||||||
buffer.putLong(Instant.now().toEpochMilli() - 1546297200000L); // TS since 2019-01-01T00:00:00Z to keep IDs short
|
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);
|
return Base64.encodeBase64URLSafeString(buffer.array()) + RandomStringUtils.randomAlphanumeric(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getPrivateKeyBase64(EdDSAPrivateKey key) {
|
private String getPrivateKeyBase64(EdDSAPrivateKey key) {
|
||||||
return MxBase64.encode(key.getSeed());
|
return MxBase64.encode(key.getSeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
public EdDSAParameterSpec getKeySpecs() {
|
EdDSAParameterSpec getKeySpecs() {
|
||||||
return keySpecs;
|
return keySpecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,15 +113,15 @@ public class Ed25519KeyManager implements KeyManager {
|
|||||||
return store.get(id);
|
return store.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EdDSAPrivateKeySpec getPrivateKeySpecs(KeyIdentifier id) {
|
private EdDSAPrivateKeySpec getPrivateKeySpecs(KeyIdentifier id) {
|
||||||
return new EdDSAPrivateKeySpec(Base64.decodeBase64(getKey(id).getPrivateKeyBase64()), keySpecs);
|
return new EdDSAPrivateKeySpec(Base64.decodeBase64(getKey(id).getPrivateKeyBase64()), keySpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EdDSAPrivateKey getPrivateKey(KeyIdentifier id) {
|
EdDSAPrivateKey getPrivateKey(KeyIdentifier id) {
|
||||||
return new EdDSAPrivateKey(getPrivateKeySpecs(id));
|
return new EdDSAPrivateKey(getPrivateKeySpecs(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public EdDSAPublicKey getPublicKey(KeyIdentifier id) {
|
private EdDSAPublicKey getPublicKey(KeyIdentifier id) {
|
||||||
EdDSAPrivateKeySpec privKeySpec = getPrivateKeySpecs(id);
|
EdDSAPrivateKeySpec privKeySpec = getPrivateKeySpecs(id);
|
||||||
EdDSAPublicKeySpec pubKeySpec = new EdDSAPublicKeySpec(privKeySpec.getA(), keySpecs);
|
EdDSAPublicKeySpec pubKeySpec = new EdDSAPublicKeySpec(privKeySpec.getA(), keySpecs);
|
||||||
return new EdDSAPublicKey(pubKeySpec);
|
return new EdDSAPublicKey(pubKeySpec);
|
@@ -18,11 +18,14 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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);
|
super(KeyAlgorithm.Ed25519, serial);
|
||||||
}
|
}
|
||||||
|
|
@@ -18,11 +18,14 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.crypto.ed25519;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import io.kamax.matrix.codec.MxBase64;
|
import io.kamax.matrix.codec.MxBase64;
|
||||||
import io.kamax.matrix.json.MatrixJson;
|
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 net.i2p.crypto.eddsa.EdDSAEngine;
|
||||||
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
@@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.http.undertow.handler.identity.v1;
|
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.http.IsAPIv1;
|
||||||
import io.kamax.mxisd.storage.crypto.KeyManager;
|
|
||||||
import io.kamax.mxisd.storage.crypto.KeyType;
|
|
||||||
import io.undertow.server.HttpServerExchange;
|
import io.undertow.server.HttpServerExchange;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@@ -21,11 +21,11 @@
|
|||||||
package io.kamax.mxisd.http.undertow.handler.identity.v1;
|
package io.kamax.mxisd.http.undertow.handler.identity.v1;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
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.IsAPIv1;
|
||||||
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
|
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 io.undertow.server.HttpServerExchange;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.http.undertow.handler.identity.v1;
|
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.http.IsAPIv1;
|
||||||
import io.kamax.mxisd.storage.crypto.KeyManager;
|
|
||||||
import io.kamax.mxisd.storage.crypto.KeyType;
|
|
||||||
import io.undertow.server.HttpServerExchange;
|
import io.undertow.server.HttpServerExchange;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@@ -26,11 +26,11 @@ import io.kamax.matrix._MatrixID;
|
|||||||
import io.kamax.matrix.json.GsonUtil;
|
import io.kamax.matrix.json.GsonUtil;
|
||||||
import io.kamax.matrix.json.MatrixJson;
|
import io.kamax.matrix.json.MatrixJson;
|
||||||
import io.kamax.mxisd.config.MxisdConfig;
|
import io.kamax.mxisd.config.MxisdConfig;
|
||||||
|
import io.kamax.mxisd.crypto.SignatureManager;
|
||||||
import io.kamax.mxisd.http.IsAPIv1;
|
import io.kamax.mxisd.http.IsAPIv1;
|
||||||
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
|
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
|
||||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||||
import io.kamax.mxisd.invitation.InvitationManager;
|
import io.kamax.mxisd.invitation.InvitationManager;
|
||||||
import io.kamax.mxisd.storage.crypto.SignatureManager;
|
|
||||||
import io.undertow.server.HttpServerExchange;
|
import io.undertow.server.HttpServerExchange;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@@ -26,12 +26,12 @@ import io.kamax.matrix.json.GsonUtil;
|
|||||||
import io.kamax.matrix.json.MatrixJson;
|
import io.kamax.matrix.json.MatrixJson;
|
||||||
import io.kamax.mxisd.config.MxisdConfig;
|
import io.kamax.mxisd.config.MxisdConfig;
|
||||||
import io.kamax.mxisd.config.ServerConfig;
|
import io.kamax.mxisd.config.ServerConfig;
|
||||||
|
import io.kamax.mxisd.crypto.SignatureManager;
|
||||||
import io.kamax.mxisd.http.IsAPIv1;
|
import io.kamax.mxisd.http.IsAPIv1;
|
||||||
import io.kamax.mxisd.http.io.identity.SingeLookupReplyJson;
|
import io.kamax.mxisd.http.io.identity.SingeLookupReplyJson;
|
||||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||||
import io.kamax.mxisd.lookup.SingleLookupRequest;
|
import io.kamax.mxisd.lookup.SingleLookupRequest;
|
||||||
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
||||||
import io.kamax.mxisd.storage.crypto.SignatureManager;
|
|
||||||
import io.undertow.server.HttpServerExchange;
|
import io.undertow.server.HttpServerExchange;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@@ -26,6 +26,7 @@ import io.kamax.matrix.MatrixID;
|
|||||||
import io.kamax.matrix._MatrixID;
|
import io.kamax.matrix._MatrixID;
|
||||||
import io.kamax.matrix.json.GsonUtil;
|
import io.kamax.matrix.json.GsonUtil;
|
||||||
import io.kamax.mxisd.config.ServerConfig;
|
import io.kamax.mxisd.config.ServerConfig;
|
||||||
|
import io.kamax.mxisd.crypto.KeyManager;
|
||||||
import io.kamax.mxisd.exception.BadRequestException;
|
import io.kamax.mxisd.exception.BadRequestException;
|
||||||
import io.kamax.mxisd.http.IsAPIv1;
|
import io.kamax.mxisd.http.IsAPIv1;
|
||||||
import io.kamax.mxisd.http.io.identity.StoreInviteRequest;
|
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.IThreePidInviteReply;
|
||||||
import io.kamax.mxisd.invitation.InvitationManager;
|
import io.kamax.mxisd.invitation.InvitationManager;
|
||||||
import io.kamax.mxisd.invitation.ThreePidInvite;
|
import io.kamax.mxisd.invitation.ThreePidInvite;
|
||||||
import io.kamax.mxisd.storage.crypto.KeyManager;
|
|
||||||
import io.undertow.server.HttpServerExchange;
|
import io.undertow.server.HttpServerExchange;
|
||||||
import io.undertow.util.QueryParameterUtils;
|
import io.undertow.util.QueryParameterUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@@ -29,6 +29,7 @@ import io.kamax.matrix.json.GsonUtil;
|
|||||||
import io.kamax.mxisd.config.InvitationConfig;
|
import io.kamax.mxisd.config.InvitationConfig;
|
||||||
import io.kamax.mxisd.config.MxisdConfig;
|
import io.kamax.mxisd.config.MxisdConfig;
|
||||||
import io.kamax.mxisd.config.ServerConfig;
|
import io.kamax.mxisd.config.ServerConfig;
|
||||||
|
import io.kamax.mxisd.crypto.*;
|
||||||
import io.kamax.mxisd.dns.FederationDnsOverwrite;
|
import io.kamax.mxisd.dns.FederationDnsOverwrite;
|
||||||
import io.kamax.mxisd.exception.BadRequestException;
|
import io.kamax.mxisd.exception.BadRequestException;
|
||||||
import io.kamax.mxisd.exception.ConfigurationException;
|
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.notification.NotificationManager;
|
||||||
import io.kamax.mxisd.profile.ProfileManager;
|
import io.kamax.mxisd.profile.ProfileManager;
|
||||||
import io.kamax.mxisd.storage.IStorage;
|
import io.kamax.mxisd.storage.IStorage;
|
||||||
import io.kamax.mxisd.storage.crypto.*;
|
|
||||||
import io.kamax.mxisd.storage.ormlite.dao.ThreePidInviteIO;
|
import io.kamax.mxisd.storage.ormlite.dao.ThreePidInviteIO;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.storage.crypto;
|
||||||
|
|
||||||
|
import io.kamax.mxisd.crypto.Key;
|
||||||
|
|
||||||
public class FileKeyJson {
|
public class FileKeyJson {
|
||||||
|
|
||||||
public static FileKeyJson get(Key key) {
|
public static FileKeyJson get(Key key) {
|
||||||
|
@@ -23,6 +23,7 @@ package io.kamax.mxisd.storage.crypto;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import io.kamax.matrix.crypto.KeyFileStore;
|
import io.kamax.matrix.crypto.KeyFileStore;
|
||||||
import io.kamax.matrix.json.GsonUtil;
|
import io.kamax.matrix.json.GsonUtil;
|
||||||
|
import io.kamax.mxisd.crypto.*;
|
||||||
import io.kamax.mxisd.exception.ObjectNotFoundException;
|
import io.kamax.mxisd.exception.ObjectNotFoundException;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
@@ -54,31 +55,39 @@ public class FileKeyStore implements KeyStore {
|
|||||||
base = new File(path).getAbsoluteFile().toString();
|
base = new File(path).getAbsoluteFile().toString();
|
||||||
File f = new File(base);
|
File f = new File(base);
|
||||||
|
|
||||||
if (f.exists() && f.isFile()) {
|
if (!f.exists()) {
|
||||||
try {
|
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);
|
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) {
|
} 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 {
|
} 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()) {
|
if (!f.isDirectory()) {
|
||||||
@@ -207,6 +216,10 @@ public class FileKeyStore implements KeyStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCurrentKey(KeyIdentifier id) throws IllegalArgumentException {
|
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();
|
JsonObject json = new JsonObject();
|
||||||
json.addProperty("type", id.getType().name());
|
json.addProperty("type", id.getType().name());
|
||||||
json.addProperty("algo", id.getAlgorithm());
|
json.addProperty("algo", id.getAlgorithm());
|
||||||
|
@@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
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 io.kamax.mxisd.exception.ObjectNotFoundException;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -84,9 +87,9 @@ public interface KeyStore {
|
|||||||
* Store the information of which key is the current signing key
|
* Store the information of which key is the current signing key
|
||||||
*
|
*
|
||||||
* @param id The key identifier
|
* @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
|
* Retrieve the previously stored information of which key is the current signing key, if any
|
||||||
|
@@ -20,18 +20,18 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.storage.crypto;
|
package io.kamax.mxisd.storage.crypto;
|
||||||
|
|
||||||
|
import io.kamax.mxisd.crypto.*;
|
||||||
import io.kamax.mxisd.exception.ObjectNotFoundException;
|
import io.kamax.mxisd.exception.ObjectNotFoundException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class MemoryKeyStore implements KeyStore {
|
public class MemoryKeyStore implements KeyStore {
|
||||||
|
|
||||||
private Map<KeyType, Map<String, Map<String, String>>> keys = new ConcurrentHashMap<>();
|
private Map<KeyType, Map<String, Map<String, FileKeyJson>>> keys = new ConcurrentHashMap<>();
|
||||||
private KeyIdentifier current;
|
private KeyIdentifier current;
|
||||||
|
|
||||||
private Map<String, String> getMap(KeyType type, String algo) {
|
private Map<String, FileKeyJson> getMap(KeyType type, String algo) {
|
||||||
return keys.computeIfAbsent(type, k -> new ConcurrentHashMap<>()).computeIfAbsent(algo, k -> new ConcurrentHashMap<>());
|
return keys.computeIfAbsent(type, k -> new ConcurrentHashMap<>()).computeIfAbsent(algo, k -> new ConcurrentHashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,23 +56,23 @@ public class MemoryKeyStore implements KeyStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key get(KeyIdentifier id) throws ObjectNotFoundException {
|
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)) {
|
if (Objects.isNull(data)) {
|
||||||
throw new ObjectNotFoundException("Key", id.getType() + ":" + id.getAlgorithm() + ":" + id.getSerial());
|
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) {
|
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);
|
getMap(key.getId().getType(), key.getId().getAlgorithm()).put(key.getId().getSerial(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(Key key) throws IllegalStateException {
|
public void add(Key key) throws IllegalStateException {
|
||||||
if (has(key.getId())) {
|
if (has(key.getId())) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException("Key " + key.getId().getId() + " already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
set(key);
|
set(key);
|
||||||
@@ -89,13 +89,17 @@ public class MemoryKeyStore implements KeyStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(KeyIdentifier id) throws ObjectNotFoundException {
|
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());
|
keys.computeIfAbsent(id.getType(), k -> new ConcurrentHashMap<>()).computeIfAbsent(id.getAlgorithm(), k -> new ConcurrentHashMap<>()).remove(id.getSerial());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCurrentKey(KeyIdentifier id) throws ObjectNotFoundException {
|
public void setCurrentKey(KeyIdentifier id) throws IllegalArgumentException {
|
||||||
if (!has(id)) {
|
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;
|
current = id;
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.test.storage.crypto;
|
package io.kamax.mxisd.test.crypto;
|
||||||
|
|
||||||
public class KeyTest {
|
public class KeyTest {
|
||||||
|
|
@@ -18,12 +18,19 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.test.storage.crypto;
|
package io.kamax.mxisd.test.crypto;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import io.kamax.matrix.json.GsonUtil;
|
import io.kamax.matrix.json.GsonUtil;
|
||||||
import io.kamax.matrix.json.MatrixJson;
|
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.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -36,7 +43,7 @@ public class SignatureManagerTest {
|
|||||||
private static SignatureManager signMgr;
|
private static SignatureManager signMgr;
|
||||||
|
|
||||||
private static SignatureManager build(String keySeed) {
|
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();
|
KeyStore store = new MemoryKeyStore();
|
||||||
store.add(key);
|
store.add(key);
|
||||||
|
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<KeyIdentifier> currentKey = store.getCurrentKey();
|
||||||
|
assertTrue(currentKey.isPresent());
|
||||||
|
assertEquals(currentKey.get(), key.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void setCurrentKeyNonExisting() {
|
||||||
|
store.setCurrentKey(generateRandomKey().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user