supportedJWSAlgorithms() {
+ return Set.of(this.getAlgorithm());
+ }
+
+ /**
+ * Returns the KID intended to be stored in the header of the signed JWT as `kid`.
+ * @return
+ */
+ String getKid();
+
+ /**
+ * Returns the preferred algorithm to be used for signing.
+ * @return
+ */
+ JWSAlgorithm getAlgorithm();
+
+ /**
+ * Returns a {@link ProofOfPossessionJWSSigner} using the key material of the pem for signing.
+ * Only P-256 and Ed25519 are supported.
+ *
+ * @param path to the PEM file containing a private key
+ * @param kid to be included in the JWT header
+ * @return
+ * @throws IOException if the file cannot be read
+ * @throws JOSEException if the pem cannot be parsed to P-256
+ * @throws VcDataIntegrityCryptographicSuiteException if the file cannot be parsed to Ed25519
+ */
+ static ProofOfPossessionJWSSigner of(Path path, String kid) throws IOException, VcDataIntegrityCryptographicSuiteException, JOSEException {
+ try {
+ var keyPair = PemUtils.parsePemKeyPair(Files.newBufferedReader(path));
+ if (keyPair.getPublic() instanceof ECPublicKey) {
+ return new EcP256ProofOfPossessionJWSSigner(keyPair, kid);
+ }
+ } catch (IllegalArgumentException ignore) { } // NOPMD: try EdDsa as fallback
+
+ var signer = new EdDsaJcs2022JWSSigner(path);
+ return of(signer, kid, JWSAlgorithm.EdDSA);
}
- public String getKid();
+ /**
+ * Relies on Securosys Primus HSM cluster as source for signing.
+ *
+ * @param primus the HSM cluster
+ * @param password to load the key
+ * @param alias of the key inside the HSM cluster
+ * @param kid of the key inside the JWT
+ */
+ static ProofOfPossessionJWSSigner of(PrimusKeyStoreLoader primus, String alias, String password, String kid) throws UnrecoverableEntryException, KeyStoreException, NoSuchAlgorithmException, KeyException, JOSEException {
+ var pk = (ECPrivateKey) primus.loadKeyPair(alias, password).getPrivate();
+ if (pk instanceof ECPrivateKey) {
+ var signer = new ECDSASigner(pk);
+ signer.getJCAContext().setProvider(primus.getKeyStore().getProvider());
+ return of(signer, kid, JWSAlgorithm.ES256);
+ } else {
+ var signer = new PrimusEd25519ProofOfPossessionJWSSignerImpl(primus, alias, password, kid);
+ return of(signer, kid, JWSAlgorithm.EdDSA);
+ }
+ }
+
+ /**
+ * Creates a ProofOfPosessionsJWSSigner using the provided signer, kid, and alg.
+ *
+ * @param signer
+ * @param kid
+ * @param alg
+ * @return
+ */
+ static ProofOfPossessionJWSSigner of(JWSSigner signer, String kid, JWSAlgorithm alg) {
+ return new ProofOfPossessionJWSSigner(){
+ @Override
+ public Base64URL sign(JWSHeader header, byte[] signingInput) throws JOSEException {
+ return signer.sign(header, signingInput);
+ }
+
+ @Override
+ public String getKid() {
+ return kid;
+ }
+
+ @Override
+ public JWSAlgorithm getAlgorithm() {
+ return alg;
+ }
+
+ @Override
+ public JCAContext getJCAContext() {
+ return signer.getJCAContext();
+ }
+ };
+ }
- public JWSAlgorithm getAlgorithm();
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifier.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifier.java
index 14c2abff..c47fdd80 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifier.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifier.java
@@ -11,6 +11,7 @@
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.ECDSAVerifier;
+import com.nimbusds.jose.crypto.Ed25519Verifier;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
@@ -108,36 +109,26 @@ public void verify(SignedJWT signedJWT, String nonce) throws ProofOfPossessionVe
// - use secure string comparison method
// - add check for nbf if present
var algorithm = signedJWT.getHeader().getAlgorithm();
- if (!Set.of(JWSAlgorithm.ES256).contains(algorithm)) {
+ if (!Set.of(JWSAlgorithm.ES256, JWSAlgorithm.EdDSA).contains(algorithm)) {
throw ProofOfPossessionVerifierException.unsupportedAlgorithm(algorithm.toString());
}
- // check nonce
- String nonceClaim;
- try {
- nonceClaim = signedJWT.getJWTClaimsSet().getStringClaim("nonce");
- } catch (ParseException e) {
- throw ProofOfPossessionVerifierException.unparsable(e);
- }
- if (!nonce.equals(nonceClaim)) {
- throw ProofOfPossessionVerifierException.invalidNonce(nonceClaim, nonce);
- }
-
- // check timestamp
// ParseException is thrown here, if something's wrong with the provided JWT
- JWTClaimsSet claimset;
+ JWTClaimsSet claimSet;
try {
- claimset = signedJWT.getJWTClaimsSet();
- } catch (ParseException e) {
+ claimSet = signedJWT.getJWTClaimsSet();
+ // check nonce
+ String nonceClaim = claimSet.getStringClaim("nonce");
+ if (!nonce.equals(nonceClaim)) {
+ throw ProofOfPossessionVerifierException.invalidNonce(nonceClaim, nonce);
+ }
+ } catch (ParseException e) { // NOPMD ExceptionAsFlowControl: false positive
throw ProofOfPossessionVerifierException.unparsable(e);
}
- var expirationTime = claimset.getExpirationTime();
- if (expirationTime == null) {
- throw ProofOfPossessionVerifierException.expired();
- }
- var now = Instant.now();
- if (now.isAfter(expirationTime.toInstant())) {
+ // check timestamp
+ var expirationTime = claimSet.getExpirationTime();
+ if (expirationTime == null || Instant.now().isAfter(expirationTime.toInstant())) {
throw ProofOfPossessionVerifierException.expired();
}
@@ -159,8 +150,18 @@ public void verify(SignedJWT signedJWT, String nonce) throws ProofOfPossessionVe
throw ProofOfPossessionVerifierException.unparsable(e);
}
+
try {
- JWSVerifier jwsVerifier = new ECDSAVerifier(jwk.toECKey());
+ JWSVerifier jwsVerifier;
+ // if else pattern because final class instances cannot be used as cases for a switch statement
+ if (JWSAlgorithm.EdDSA.equals(algorithm)) {
+ jwsVerifier = new Ed25519Verifier(jwk.toOctetKeyPair());
+ } else if (JWSAlgorithm.ES256.equals(algorithm)) {
+ jwsVerifier = new ECDSAVerifier(jwk.toECKey());
+ } else {
+ throw new RuntimeException("Tried to construct a JWS verifier of an algorithm that's not supported and should have been caught earlier."); // NOPMD: code is unreachable
+ };
+
if (!signedJWT.verify(jwsVerifier)) {
throw ProofOfPossessionVerifierException.invalidSignature();
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwCreator.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwCreator.java
index 81ae3d5f..26c430ca 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwCreator.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwCreator.java
@@ -41,14 +41,14 @@
*
* - {@link TdwCreator#cryptographicSuite} for the purpose of adding data integrity proof
* - {@link TdwCreator#authentications} for setting authentication
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256 JsonWebKey2020) keys
* - {@link TdwCreator#assertionMethods} for setting/assertion
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256 JsonWebKey2020) keys
*
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256 JsonWebKey2020 keys from
* PEM files, you may rely on {@link JwkUtils}.
*
* CAUTION Any explicit use of this class in your code is HIGHLY INADVISABLE.
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwDeactivator.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwDeactivator.java
index 705293bc..ffd0f2ab 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwDeactivator.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwDeactivator.java
@@ -38,7 +38,7 @@
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VcDataIntegrityCryptographicSuite} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256 JsonWebKey2020 keys from
* PEM files, you may rely on {@link JwkUtils}.
*
* CAUTION Any explicit use of this class in your code is HIGHLY INADVISABLE.
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwUpdater.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwUpdater.java
index 181c5d01..a171d09e 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwUpdater.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/TdwUpdater.java
@@ -41,14 +41,14 @@
*
* - {@link TdwUpdater#cryptographicSuite} for the purpose of adding data integrity proof
* - {@link TdwUpdater#authenticationKeys} for setting authentication
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed2519 JsonWebKey2020) keys
* - {@link TdwUpdater#assertionMethodKeys} for setting/assertion
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed2519 JsonWebKey2020) keys
*
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256/Ed25519 JsonWebKey2020 keys from
* PEM files, you may rely on {@link JwkUtils}.
*
* CAUTION Any explicit use of this class in your code is HIGHLY INADVISABLE.
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogCreatorContext.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogCreatorContext.java
index 74d12086..1f3c7ab5 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogCreatorContext.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogCreatorContext.java
@@ -30,14 +30,14 @@
*
* - {@link DidLogCreatorContext#cryptographicSuite} for the purpose of adding data integrity proof
* - {@link DidLogCreatorContext#authenticationKeys} for setting authentication
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed25519 JsonWebKey2020) keys
* - {@link DidLogCreatorContext#assertionMethods} for setting/assertion
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed25519 JsonWebKey2020) keys
*
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256/Ed25519 JsonWebKey2020 keys from
* PEM files, you may rely on {@link JwkUtils}.
*
* For instance:
@@ -94,7 +94,8 @@ public static DidLogCreatorContextBuilder builder() {
}
/**
- * Constructs a builder for creating did logs with the provided crypto Suite
+ * Constructs a builder for creating did logs with the provided crypto suite
+ * @param method version of the did log (WEBVH or TDW)
* @param cryptoSuite used to create the log entry signature
* @return the builder, it's recommended to also call 'assertionMethods' or 'authentications' on it.
*/
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogDeactivatorContext.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogDeactivatorContext.java
index 8c703657..2b64e7c5 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogDeactivatorContext.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogDeactivatorContext.java
@@ -30,7 +30,7 @@
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256 JsonWebKey2020 keys from
* PEM files, you may rely on {@link JwkUtils}.
*
* For instance:
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogUpdaterContext.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogUpdaterContext.java
index 5daca497..13839928 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogUpdaterContext.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/context/DidLogUpdaterContext.java
@@ -33,14 +33,14 @@
*
* - {@link DidLogUpdaterContext#cryptographicSuite} for the purpose of adding data integrity proof
* - {@link DidLogUpdaterContext#authentications} for setting authentication
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed25519 JsonWebKey2020) keys
* - {@link DidLogUpdaterContext#assertionMethods} for setting/assertion
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed25519 JsonWebKey2020) keys
*
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+
* PEM files, you may rely on {@link JwkUtils}.
*
* For instance:
@@ -106,7 +106,12 @@ public static DidLogUpdaterContextBuilder builder() {
return new DidLogUpdaterContextBuilder();
}
- // TODO@MP provide proper java docs
+ /**
+ * Constructs a builder for updating did logs with the provided crypto suite
+ * @param method version of the did log (WEBVH or TDW)
+ * @param cryptoSuite used to create the log entry signature
+ * @return the builder, it's recommended to call 'assertionMethods' or 'authentications' on it.
+ */
public static DidLogUpdaterContextBuilder builder(DidMethodEnum method, VcDataIntegrityCryptographicSuite cryptoSuite) {
return new DidLogUpdaterContextBuilder().didMethod(method).cryptographicSuite(cryptoSuite);
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/AbstractKeyMaterialDidLogCommand.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/AbstractKeyMaterialDidLogCommand.java
index bd8ddb46..4d442b0d 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/AbstractKeyMaterialDidLogCommand.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/AbstractKeyMaterialDidLogCommand.java
@@ -1,11 +1,17 @@
package ch.admin.bj.swiyu.didtoolbox.jcommander;
+import ch.admin.bj.swiyu.didtoolbox.FilesPrivacy;
+import ch.admin.bj.swiyu.didtoolbox.JwkUtils;
import ch.admin.bj.swiyu.didtoolbox.jcommander.validator.PemFileParameterValidator;
import ch.admin.bj.swiyu.didtoolbox.jcommander.validator.VerificationMethodKeyParametersValidator;
+import ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm;
+import ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod;
+import ch.admin.bj.swiyu.didtoolbox.model.VerificationMethodException;
import com.beust.jcommander.Parameter;
-import org.bouncycastle.jcajce.provider.asymmetric.mldsa.MLDSAKeyFactorySpi;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
@@ -25,38 +31,99 @@ String getCommandName() {
}
@Parameter(names = {PARAM_NAME_LONG_VERIFYING_KEY_FILES, PARAM_NAME_SHORT_VERIFYING_KEY_FILES},
- description = "One or more ed25519 public key file(s) for the DID Document’s verification method. In PEM format.",
+ description = "One or more Ed25519 public key file(s) for the DID Document’s verification method. In PEM format.",
listConverter = PemFileParameterListConverter.class,
validateWith = PemFileParameterValidator.class,
variableArity = true)
public Set verifyingKeyPemFiles = new HashSet<>();
@Parameter(names = {PARAM_NAME_LONG_NEXT_VERIFYING_KEY_FILES, PARAM_NAME_SHORT_NEXT_VERIFYING_KEY_FILES},
- description = "One or more ed25519 public key file(s) to be used as 'pre-rotation' keys. In PEM format. Using the CLI option activates 'key pre-rotation'. Analogously, deactivating 'key pre-rotation' goes simply by omitting this option altogether",
+ description = "One or more Ed25519 public key file(s) to be used as 'pre-rotation' keys. In PEM format. Using the CLI option activates 'key pre-rotation'. Analogously, deactivating 'key pre-rotation' goes simply by omitting this option altogether",
listConverter = PemFileParameterListConverter.class,
validateWith = PemFileParameterValidator.class,
variableArity = true)
public Set nextVerifyingKeyPemFiles = new HashSet<>();
@Parameter(names = {PARAM_NAME_LONG_GENERATE_NEXT_VERIFYING_KEY, PARAM_NAME_SHORT_GENERATE_NEXT_VERIFYING_KEY},
- description = "Generates a new ed25519 key pair to be used as the next signing key. The generated key pair is stored in the `.didtoolbox` directory. CAUTION: using `-f` can override existing keys in the directory, make sure to back them up. Cannot be used together with the generate verifying key next flag ('-gv')")
+ description = "Generates a new Ed25519 key pair to be used as the next signing key. The generated key pair is stored in the `.didtoolbox` directory. CAUTION: using `-f` can override existing keys in the directory, make sure to back them up. Cannot be used together with the generate verifying key next flag ('-gv')")
public boolean shouldGenerateNextVerifyingKeyPem;
@Parameter(names = {PARAM_NAME_LONG_ASSERTION_METHOD_KEYS, PARAM_NAME_SHORT_ASSERTION_METHOD_KEYS},
- description = "One or more assertion method parameter(s) - each parameter consists of a (comma-separated) key name and a PEM file containing EC P-256 public/verifying key",
+ description = "One or more assertion method parameter(s) - each parameter consists of a (comma-separated) key name and a PEM file containing an P-256 or Ed25519 public/verifying key",
listConverter = VerificationMethodParametersConverter.class,
validateWith = VerificationMethodKeyParametersValidator.class,
variableArity = true)
public Set assertionMethodKeys;
@Parameter(names = {PARAM_NAME_LONG_AUTHENTICATION_METHOD_KEYS, PARAM_NAME_SHORT_AUTHENTICATION_METHOD_KEYS},
- description = "One or more authentication method parameter(s) - each parameter consists of a (comma-separated) key name and a PEM file containing EC P-256 public/verifying key",
+ description = "One or more authentication method parameter(s) - each parameter consists of a (comma-separated) key name and a PEM file containing P-256 or Ed25519 public/verifying key",
listConverter = VerificationMethodParametersConverter.class,
validateWith = VerificationMethodKeyParametersValidator.class,
variableArity = true)
public Set authenticationKeys;
- @Parameter(names = {"--force-overwrite", "-f"},
+ @Parameter(names = {PARAM_NAME_LONG_CRYPTOGRAPHIC_ALGORITHM, PARAM_NAME_SHORT_CRYPTOGRAPHIC_ALGORITHM},
+ description = "Specify which type of keys to generate as assertion and authorization keys when none are provided through other means. Available are P-256 and Ed25519")
+ public CryptographicAlgorithm cryptoAlgorithm = CryptographicAlgorithm.P256;
+
+ @Parameter(names = {PARAM_NAME_LONG_FORCE, PARAM_NAME_SHORT_FORCE},
description = "Overwrite existing PEM key files, if any")
public boolean forceOverwrite;
+
+ /**
+ * Parses the provided verification methods from {@link #assertionMethodKeys} into verification methods.
+ * If none are set, this functions generates new keys and stores them in the provided directory as `assert-key-01` and
+ * `assert-key-01.pub`. This function throws an exception if the files already exist and {@link #forceOverwrite} is set to false.
+ *
+ * @param directoryToStoreGeneratedKeys directory in which the function would store the public and private key files
+ * @return all assertion methods
+ * @throws IOException when the generated keys cannot be stored
+ * @throws VerificationMethodException when it fails to parse the provided keys
+ */
+ public Set getAssertionMethods(Path directoryToStoreGeneratedKeys) throws IOException, VerificationMethodException {
+ var assertionMethods = new HashSet();
+ if (this.assertionMethodKeys != null && !this.assertionMethodKeys.isEmpty()) {
+ for (VerificationMethodParameters param : this.assertionMethodKeys) {
+ assertionMethods.add(VerificationMethod.of(param.key, param.jwk));
+ }
+ } else {
+ assertionMethods.add(generateVerificationMethod(directoryToStoreGeneratedKeys, "assert-key-01"));
+ }
+
+ return assertionMethods;
+ }
+
+ /**
+ * Parses the provided verification methods from {@link #authenticationKeys} into verification methods.
+ * If none are set, this functions generates new keys and stores them in the provided directory as `auth-key-01` and
+ * `auth-key-01.pub`. This function throws an exception if the files already exist and {@link #forceOverwrite} is set to false.
+ *
+ * @param directoryToStoreGeneratedKeys directory in which the function would store the public and private key files
+ * @return all assertion methods
+ * @throws IOException when the generated keys cannot be stored
+ * @throws VerificationMethodException when it fails to parse the provided keys
+ */
+ public Set getAuthentications(Path directoryToStoreGeneratedKeys) throws IOException, VerificationMethodException {
+ var authentications = new HashSet();
+ if (this.authenticationKeys != null && !this.authenticationKeys.isEmpty()) {
+ for (VerificationMethodParameters param : this.authenticationKeys) {
+ authentications.add(VerificationMethod.of(param.key, param.jwk));
+ }
+ } else {
+ authentications.add(generateVerificationMethod(directoryToStoreGeneratedKeys, "auth-key-01"));
+ }
+
+ return authentications;
+ }
+
+ private VerificationMethod generateVerificationMethod(Path directory, String name) throws IOException {
+ FilesPrivacy.createPrivateKeyDirectoryIfDoesNotExist(directory);
+ var file = new File(directory.toString(), name);
+
+ return switch (this.cryptoAlgorithm) { // NOPMD TooFewBranchesForSwitch
+ case P256 ->
+ JwkUtils.generatePublicP256VerificationMethod(name, file, this.forceOverwrite);
+ case ED25519 -> JwkUtils.generatePublicEd25519VerificationMethod(name, file, this.forceOverwrite);
+ };
+ }
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CommandParameterNames.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CommandParameterNames.java
index 382d128b..5264464b 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CommandParameterNames.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CommandParameterNames.java
@@ -56,4 +56,10 @@ public interface CommandParameterNames {
public String PARAM_NAME_LONG_JWT = "--jwt";
public String PARAM_NAME_SHORT_JWT = "-j";
+
+ public String PARAM_NAME_LONG_FORCE = "--force";
+ public String PARAM_NAME_SHORT_FORCE = "-f";
+
+ public String PARAM_NAME_LONG_CRYPTOGRAPHIC_ALGORITHM = "--cryptographic-algorithm";
+ public String PARAM_NAME_SHORT_CRYPTOGRAPHIC_ALGORITHM = "-c";
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CreateProofOfPossessionCommand.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CreateProofOfPossessionCommand.java
index d1594e29..7f2d8d90 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CreateProofOfPossessionCommand.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/CreateProofOfPossessionCommand.java
@@ -38,7 +38,7 @@ String getCommandName() {
public String kid;
@Parameter(names = {CommandParameterNames.PARAM_NAME_LONG_SIGNING_KEY_FILE, CommandParameterNames.PARAM_NAME_SHORT_SIGNING_KEY_FILE},
- description = "An EC P-256 private key file matching the specified key within the DID log",
+ description = "A P-256 private key file matching the specified key within the DID log",
converter = PemFileParameterConverter.class,
validateWith = PemFileParameterValidator.class,
required = false)
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodParametersConverter.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodParametersConverter.java
index bff6e98a..6699c9b6 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodParametersConverter.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodParametersConverter.java
@@ -21,7 +21,7 @@ public List convert(String value) {
String jwk;
try {
jwk = JwkUtils.loadECPublicJWKasJSON(Path.of(split[1]), kid);
- } catch (IOException | InvalidKeySpecException e) {
+ } catch (IOException e) {
throw new IllegalArgumentException(e);
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/validator/VerificationMethodKeyParametersValidator.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/validator/VerificationMethodKeyParametersValidator.java
index ee8c22d5..a1e32517 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/validator/VerificationMethodKeyParametersValidator.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/jcommander/validator/VerificationMethodKeyParametersValidator.java
@@ -14,7 +14,7 @@ public class VerificationMethodKeyParametersValidator implements IParameterValid
public void validate(String name, String value) {
String[] split = value.split(",");
if (split.length != 2) { // NOPMD AvoidLiteralsInIfCondition
- throw new ParameterException("Option " + name + " should supply a comma-separated list (in format key-name,public-key-file (EC P-256 public/verifying key in PEM format)) (found " + value + ")");
+ throw new ParameterException("Option " + name + " should supply a comma-separated list (in format key-name,public-key-file (P-256 or Ed25519 public/verifying key in PEM format)) (found " + value + ")");
}
String kid = split[0];
@@ -32,13 +32,13 @@ public void validate(String name, String value) {
String jwkFile = split[1];
var f = Path.of(jwkFile);
if (!Files.isReadable(f)) {
- throw new ParameterException("A public key file (" + jwkFile + ") supplied by " + name + " option must be a regular file containing EC P-256 public/verifying key in PEM format (found " + jwkFile + ")");
+ throw new ParameterException("A public key file (" + jwkFile + ") supplied by " + name + " option must be a regular file containing an P-256 or Ed25519 public/verifying key in PEM format (found " + jwkFile + ")");
}
try {
JwkUtils.loadECPublicJWKasJSON(f, kid);
- } catch (IOException | InvalidKeySpecException exc) {
- throw new ParameterException("A public key file (" + jwkFile + ") supplied by " + name + " option must contain an EC P-256 public/verifying key in PEM format: " + exc.getLocalizedMessage(), exc);
+ } catch (IOException exc) {
+ throw new ParameterException("A public key file (" + jwkFile + ") supplied by " + name + " option must contain an P-256 or Ed25519 public/verifying key in PEM format: " + exc.getLocalizedMessage(), exc);
}
}
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/CryptographicAlgorithm.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/CryptographicAlgorithm.java
new file mode 100644
index 00000000..2c284cc3
--- /dev/null
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/CryptographicAlgorithm.java
@@ -0,0 +1,17 @@
+package ch.admin.bj.swiyu.didtoolbox.model;
+
+public enum CryptographicAlgorithm {
+ ED25519("Ed25519"),
+ P256("P-256");
+
+ private final String name;
+
+ CryptographicAlgorithm(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return this.name;
+ }
+}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/DidMethodEnum.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/DidMethodEnum.java
index 1ec423fe..f13e6a05 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/DidMethodEnum.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/DidMethodEnum.java
@@ -74,10 +74,12 @@ public static DidMethodEnum parse(String str) throws ParseException {
throw new ParseException("Unknown or unsupported DID method: " + str, 0);
}
+ @Deprecated(since = "2.3.0")
public boolean isTdw03() {
return false;
}
+ @Deprecated(since = "2.3.0")
public boolean isWebVh10() {
return false;
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMaterial.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMaterial.java
index f7fee4ef..0723d07c 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMaterial.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMaterial.java
@@ -1,13 +1,19 @@
package ch.admin.bj.swiyu.didtoolbox.model;
import ch.admin.bj.swiyu.didtoolbox.PemUtils;
+import ch.admin.eid.did_sidekicks.DidSidekicksException;
+import ch.admin.eid.did_sidekicks.Ed25519VerifyingKey;
+import com.google.gson.JsonParser;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
+import lombok.NonNull;
import java.io.IOException;
+import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.EdECPublicKey;
/**
* Verification material is any information that is used by a process that applies a
@@ -39,27 +45,70 @@ public interface VerificationMaterial {
* @return a valid {@link VerificationMaterial} implementation object representing Elliptic Curve JWK with any
* private values removed, never {@code null}
*/
- static VerificationMaterial of(String kid, ECPublicKey ecPublicKey) {
+ static VerificationMaterial of(String kid, @NonNull ECPublicKey ecPublicKey) {
return () -> new ECKey.Builder(Curve.P_256, ecPublicKey).keyID(kid).build().toPublicJWK().toJSONString();
}
/**
* Yet another static factory method of the interface.
*
- * For the supplied public Elliptic Curve key {@code ecPublicKey},
+ * For the supplied pem file {@code publicKeyPemFile},
* a valid {@link VerificationMaterial} implementation object is returned featuring {@link #getPublicKeyJwk()} method
- * that always returns JSON representation of the Elliptic Curve JWK with any private values removed.
- * The cryptographic curve is always P-256 (secp256r1, also called prime256v1, OID = 1.2.840.10045.3.1.7).
+ * that always returns JSON representation of the JWK with any private values removed.
+ * The cryptographic curve is either P-256 (secp256r1, also called prime256v1, OID = 1.2.840.10045.3.1.7) or Ed25519.
*
- * @param kid non-empty string representing a "kid" (Key ID) Parameter
- * @param ecPublicKeyPemPath file featuring a proper public EC key in PEM format
+ * @param kid non-empty string representing a "kid" (Key ID) Parameter
+ * @param publicKeyPemPath file featuring a proper public P-256 or Ed25519 key in PEM format
* @return a valid {@link VerificationMaterial} implementation object representing Elliptic Curve JWK with any
* @throws IOException if the supplied {@code ecPublicKeyPemPath} does not feature a proper public EC key in PEM format
* private values removed, never {@code null}
*/
- static VerificationMaterial of(String kid, Path ecPublicKeyPemPath) throws IOException {
- var ecPublicKey = (ECPublicKey) PemUtils.parsePemPublicKey(Files.newBufferedReader(ecPublicKeyPemPath));
- return () -> new ECKey.Builder(Curve.P_256, ecPublicKey).keyID(kid).build().toPublicJWK().toJSONString();
+ static VerificationMaterial of(String kid, @NonNull Path publicKeyPemPath) throws IOException, DidSidekicksException {
+ var publicKey = PemUtils.parsePemPublicKey(Files.newBufferedReader(publicKeyPemPath));
+ if (publicKey instanceof ECPublicKey ecPublicKey) {
+ return () -> new ECKey.Builder(Curve.P_256, ecPublicKey).keyID(kid).build().toPublicJWK().toJSONString();
+ }
+
+ if (publicKey instanceof EdECPublicKey) {
+ try (var dsaPublicKey = Ed25519VerifyingKey.Companion.readPublicKeyPemFile(publicKeyPemPath.toString())) {
+ var jwk = JsonParser.parseString(dsaPublicKey.toJwk());
+ jwk.getAsJsonObject().addProperty("kid", kid);
+ return jwk::toString;
+ }
+ }
+
+ throw new IllegalArgumentException("provided pem is not supported.");
+ }
+
+ /**
+ * Yet another static factory method of the interface.
+ *
+ * For the supplied pem file as string {@code pem},
+ * a valid {@link VerificationMaterial} implementation object is returned featuring {@link #getPublicKeyJwk()} method
+ * that always returns JSON representation of the JWK with any private values removed.
+ * The cryptographic curve is either P-256 (secp256r1, also called prime256v1, OID = 1.2.840.10045.3.1.7) or Ed25519.
+ *
+ * @param kid non-empty string representing a "kid" (Key ID) Parameter
+ * @param pem a proper public ES256 or Ed25519 key in PEM format
+ * @return a valid {@link VerificationMaterial} implementation object representing Elliptic Curve JWK with any
+ * @throws IOException if the supplied {@code ecPublicKeyPemPath} does not feature a proper public EC key in PEM format
+ * private values removed, never {@code null}
+ */
+ static VerificationMaterial of(String kid, @NonNull String pem) throws IOException, DidSidekicksException {
+ var publicKey = PemUtils.parsePemPublicKey(new StringReader(pem));
+ if (publicKey instanceof ECPublicKey ecPublicKey) {
+ return () -> new ECKey.Builder(Curve.P_256, ecPublicKey).keyID(kid).build().toPublicJWK().toJSONString();
+ }
+
+ if (publicKey instanceof EdECPublicKey) {
+ try (var dsaPublicKey = Ed25519VerifyingKey.Companion.fromPublicKeyPem(pem)) {
+ var jwk = JsonParser.parseString(dsaPublicKey.toJwk());
+ jwk.getAsJsonObject().addProperty("kid", kid);
+ return jwk::toString;
+ }
+ }
+
+ throw new IllegalArgumentException("provided pem is not supported.");
}
/**
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMethod.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMethod.java
index 0a055760..40fb7bf7 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMethod.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMethod.java
@@ -1,5 +1,6 @@
package ch.admin.bj.swiyu.didtoolbox.model;
+import ch.admin.eid.did_sidekicks.DidSidekicksException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
@@ -28,8 +29,49 @@ public interface VerificationMethod {
* JsonWebKey2020, which is
* the type of the verification method for the signature suite {@code JsonWebSignature2020}.
*/
+ @Deprecated(since = "2.3.0") // NOPMD AvoidDuplicateLiterals
String VM_TYPE_JSON_WEB_KEY_2020 = "JsonWebKey2020";
+ /**
+ * As specified
+ * and w.r.t. RFC3986
+ *
+ * @return a string that conforms to the DID URL Syntax
+ */
+ String getIdFragment();
+
+ /**
+ * As specified
+ * and w.r.t. RFC3986
+ *
+ * @return a string that references exactly one verification method type
+ */
+ @Deprecated(since = "2.3.0")
+ String getType();
+
+ /**
+ * As specified:
+ *
+ * Verification material is any information that is used by a process that applies a
+ * verification method.
+ *
+ * @return a valid {@link VerificationMaterial} implementation object, never {@code null}
+ */
+ VerificationMaterial getVerificationMaterial();
+
+ /**
+ * Effectively, this is the default {@link Object#equals(Object)} implementation introduced for the sake of preventing:
+ *
Default method 'equals' overrides a member of 'java.lang.Object'
+ *
+ * @param obj the reference object with which to compare.
+ * @return {@code true} if this object is the same as the obj
+ * argument; {@code false} otherwise.
+ */
+ default boolean defaultEquals(Object obj) {
+ return (obj instanceof VerificationMethod other) &&
+ this.getIdFragment().equals(other.getIdFragment());
+ }
+
/**
* Yet another static factory method of the interface.
*
@@ -48,8 +90,9 @@ public interface VerificationMethod {
* @throws VerificationMethodException if the supplied {@code publicKeyJwk} does not represent a proper
* JSON Web Key (JWK) as described above
*/
+ // Upon removal, move logic to constructor without type parameter
+ @Deprecated(since = "2.3.0")
static VerificationMethod of(String kid, String type, String publicKeyJwk) throws VerificationMethodException {
-
JsonObject jsonObj;
try {
jsonObj = JsonParser.parseString(publicKeyJwk).getAsJsonObject();
@@ -57,16 +100,9 @@ static VerificationMethod of(String kid, String type, String publicKeyJwk) throw
throw new VerificationMethodException("The supplied string does not represent a public key JWK", exc);
}
- var kty = jsonObj.get("kty");
- var crv = jsonObj.get("crv");
- var x = jsonObj.get("x");
- var y = jsonObj.get("y");
- if (kty == null || crv == null || x == null || y == null) {
- throw new VerificationMethodException("The supplied string representing a public key JWK does not feature all the required parameters ('kty', 'crv', 'x' or 'y'");
- }
+ validateJwk(jsonObj);
return new VerificationMethod() {
-
@Override
public String getIdFragment() {
return kid;
@@ -79,12 +115,9 @@ public String getType() {
@Override
public VerificationMaterial getVerificationMaterial() {
- return new VerificationMaterial() {
- @Override
- public String getPublicKeyJwk() {
- jsonObj.addProperty("kid", kid);
- return jsonObj.toString();
- }
+ return () -> {
+ jsonObj.addProperty("kid", kid);
+ return jsonObj.toString();
};
}
@@ -122,49 +155,28 @@ static VerificationMethod of(String kid, String publicKeyJwk) throws Verificatio
* {@link VerificationMaterial} implementation object of type {@code type}
* (e.g. {@link #VM_TYPE_JSON_WEB_KEY_2020}).
*
- * @param kid non-empty string representing a "kid" (Key ID) Parameter
- * @param type string representation of a verification method type
- * (e.g. {@link #VM_TYPE_JSON_WEB_KEY_2020})
- * @param ecPublicKeyPemPath file featuring a proper public EC key in PEM format
+ * @param kid non-empty string representing a "kid" (Key ID) Parameter
+ * @param type string representation of a verification method type
+ * (e.g. {@link #VM_TYPE_JSON_WEB_KEY_2020})
+ * @param publicKeyPemPath file featuring a proper P-256 or Ed25519 public key in PEM format
* @return a valid {@link VerificationMethod} implementation object, never {@code null}
* @throws VerificationMethodException if the supplied {@code ecPublicKeyPemPath} does not feature a proper public EC key in PEM format
* @see #of(String, String, String)
*/
- static VerificationMethod of(String kid, String type, Path ecPublicKeyPemPath) throws VerificationMethodException {
+ // Upon removal, move logic to constructor without type parameter
+ @Deprecated(since = "2.3.0")
+ static VerificationMethod of(String kid, String type, Path publicKeyPemPath) throws VerificationMethodException {
VerificationMaterial vm;
try {
- vm = VerificationMaterial.of(kid, ecPublicKeyPemPath);
- } catch (IOException exc) {
+ vm = VerificationMaterial.of(kid, publicKeyPemPath);
+ } catch (IOException | DidSidekicksException exc) {
throw new VerificationMethodException(exc);
}
- return new VerificationMethod() {
- @Override
- public String getIdFragment() {
- return kid;
- }
-
- @Override
- public String getType() {
- return type;
- }
-
- @Override
- public VerificationMaterial getVerificationMaterial() {
- return vm;
- }
-
- @Override
- public boolean equals(Object obj) {
- return this.defaultEquals(obj);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(this.getIdFragment());
- }
- };
+ // Assigning vm to new variable, as the vm cannot be final, as it has "2" assignments
+ // even though only 1 of them can work.
+ return of(vm);
}
/**
@@ -196,6 +208,8 @@ static VerificationMethod of(String kid, Path pemPath) throws VerificationMethod
* @return a valid {@link VerificationMethod} implementation object, never {@code null}
* @see VerificationMaterial#of(String, ECPublicKey)
*/
+ // Upon removal, move logic to constructor without type parameter
+ @Deprecated(since = "2.3.0")
static VerificationMethod of(String kid, String type, ECPublicKey ecPublicKey) {
return new VerificationMethod() {
@Override
@@ -239,42 +253,89 @@ static VerificationMethod of(String kid, ECPublicKey ecPublicKey) {
}
/**
- * As specified
- * and w.r.t. RFC3986
+ * Returns a verification method of the provided material. The fragment is the kid extracted from the material as JWK.
*
- * @return a string that conforms to the DID URL Syntax
+ * @param verificationMaterial to be wrapped
+ * @return
+ * @throws VerificationMethodException if the provided verificationMaterial returns an invalid JWK or is missing the property 'kid'
*/
- String getIdFragment();
+ static VerificationMethod of(VerificationMaterial verificationMaterial) throws VerificationMethodException {
+ JsonObject jsonObj;
+ try {
+ jsonObj = JsonParser.parseString(verificationMaterial.getPublicKeyJwk()).getAsJsonObject();
+ } catch (JsonSyntaxException exc) {
+ throw new VerificationMethodException("The supplied string does not represent a public key JWK", exc);
+ }
+ var rawKid = jsonObj.get("kid");
+ if (rawKid == null || !rawKid.isJsonPrimitive()) {
+ throw new VerificationMethodException("Expected JWK to bo present in the JWK as string");
+ }
+ var kid = rawKid.getAsString();
- /**
- * As specified
- * and w.r.t. RFC3986
- *
- * @return a string that references exactly one verification method type
- */
- String getType();
+ return new VerificationMethod() {
+ @Override
+ public String getIdFragment() {
+ return kid;
+ }
- /**
- * As specified:
- *
- * Verification material is any information that is used by a process that applies a
- * verification method.
- *
- * @return a valid {@link VerificationMaterial} implementation object, never {@code null}
- */
- VerificationMaterial getVerificationMaterial();
+ @Override
+ public String getType() {
+ return VM_TYPE_JSON_WEB_KEY_2020;
+ }
+
+ @Override
+ public VerificationMaterial getVerificationMaterial() {
+ return verificationMaterial;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this.defaultEquals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.getIdFragment());
+ }
+ };
+ }
/**
- * Effectively, this is the default {@link Object#equals(Object)} implementation introduced for the sake of preventing:
- *
Default method 'equals' overrides a member of 'java.lang.Object'
- *
- * @param obj the reference object with which to compare.
- * @return {@code true} if this object is the same as the obj
- * argument; {@code false} otherwise.
+ * Validates that the JWK has the required fields and that the alg is supported by the ecosystem.
+ * @param jwk to validate
+ * @throws VerificationMethodException if the JWK is invalid or not supported
*/
- default boolean defaultEquals(Object obj) {
+ private static void validateJwk(JsonObject jwk) throws VerificationMethodException {
+ var crv = jwk.get("crv");
+ if (crv == null || !crv.isJsonPrimitive()) {
+ throw new VerificationMethodException("Property 'crv' is required");
+ }
- return (obj instanceof VerificationMethod other) &&
- this.getIdFragment().equals(other.getIdFragment());
+ var kty = jwk.get("kty");
+ if (kty == null) {
+ throw new VerificationMethodException("Property 'kty' is required.");
+ }
+ switch (kty.getAsString()) {
+ case "OKP" -> {
+ if (!CryptographicAlgorithm.ED25519.toString().equals(crv.getAsString())) {
+ throw new VerificationMethodException("Only curve 'Ed25519' is supported for key type OKP.");
+ }
+ }
+ case "EC" -> {
+ if (!CryptographicAlgorithm.P256.toString().equals(crv.getAsString())) {
+ throw new VerificationMethodException("Only curve 'P-256' is supported for key type EC.");
+ }
+ var y = jwk.get("y");
+ if (y == null || y.getAsString().isEmpty()) {
+ throw new VerificationMethodException("Property 'y' must be set to a string.");
+ }
+ }
+ default -> throw new VerificationMethodException("Key type %s not supported.".formatted(kty.getAsString()));
+ }
+ // Both JWK cases require x
+ var x = jwk.get("x");
+ if (x == null || x.getAsString().isEmpty()) {
+ throw new VerificationMethodException("Property 'x' must be set to a string.");
+ }
}
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/HsmProofOfPossessionJWSSigner.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/HsmProofOfPossessionJWSSigner.java
index fd467481..75278fce 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/HsmProofOfPossessionJWSSigner.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/HsmProofOfPossessionJWSSigner.java
@@ -6,6 +6,7 @@
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.ECDSASigner;
+import com.nimbusds.jose.jca.JCAContext;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.util.Base64URL;
@@ -13,7 +14,7 @@
import java.security.*;
import java.security.cert.CertificateException;
import java.security.interfaces.ECPrivateKey;
-import java.util.Set;
+import java.security.interfaces.EdECPrivateKey;
/**
* {@link HsmProofOfPossessionJWSSigner} provides multiple constructors for different HSM providers intended to be used with {@link ch.admin.bj.swiyu.didtoolbox.ProofOfPossessionCreator}.
@@ -30,34 +31,45 @@ private HsmProofOfPossessionJWSSigner(JWSSigner signer, String kid) {
/**
* Relies on Securosys Primus HSM cluster as source for signing.
*
- * @param primus the HSM cluster
+ * @param primus the HSM cluster
* @param password to load the key
- * @param alias of the key inside the HSM cluster
- * @param kid of the key inside the JWT
+ * @param alias of the key inside the HSM cluster
+ * @param kid of the key inside the JWT
*/
public static HsmProofOfPossessionJWSSigner newPrimusSigner(PrimusKeyStoreLoader primus, String alias, String password, String kid) throws UnrecoverableEntryException, KeyStoreException, NoSuchAlgorithmException, KeyException, JOSEException {
- var pk = (ECPrivateKey) primus.loadKeyPair(alias, password).getPrivate();
- var signer = new ECDSASigner(pk);
- signer.getJCAContext().setProvider(primus.getKeyStore().getProvider());
- return new HsmProofOfPossessionJWSSigner(signer, kid);
+ KeyPair kp = primus.loadKeyPair(alias, password);
+ switch (kp.getPrivate()) {
+ case ECPrivateKey ecPrivateKey -> {
+ var signer = new ECDSASigner(ecPrivateKey);
+ signer.getJCAContext().setProvider(primus.getKeyStore().getProvider());
+ return new HsmProofOfPossessionJWSSigner(signer, kid);
+ }
+ case EdECPrivateKey ignored -> {
+ var signer = new PrimusEd25519ProofOfPossessionJWSSignerImpl(kp, kid, primus);
+ return new HsmProofOfPossessionJWSSigner(signer, kid);
+ }
+ default -> {
+ throw new IllegalArgumentException();
+ }
+ }
}
/**
* Relies on PKCS11 for signing.
*
- * @param cfgPath Path to the configuration file
+ * @param cfgPath Path to the configuration file
* @param keystoreSecret
* @param keyId
- * @param kid of the key inside the JWT
+ * @param kid of the key inside the JWT
* @return
*/
- public static HsmProofOfPossessionJWSSigner newPkcs11Signer(String cfgPath, String keystoreSecret, String keyId, String kid) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, JOSEException { // NOPMD UseObjectForClearerAPI
+ public static HsmProofOfPossessionJWSSigner newPkcs11Signer(String cfgPath, String keystoreSecret, String keyId, String kid) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, JOSEException {
Provider provider = Security.getProvider("SunPKCS11");
provider = provider.configure(cfgPath);
Security.addProvider(provider);
var hsmKeyStore = KeyStore.getInstance("PKCS11", provider);
hsmKeyStore.load(null, keystoreSecret.toCharArray());
- var privateKey = ECKey.load(hsmKeyStore, keyId, keystoreSecret.toCharArray());
+ var privateKey = ECKey.load(hsmKeyStore, keyId, keystoreSecret.toCharArray());
var signer = new ECDSASigner(privateKey);
return new HsmProofOfPossessionJWSSigner(signer, kid);
}
@@ -78,7 +90,7 @@ public Base64URL sign(JWSHeader jwsHeader, byte[] bytes) throws JOSEException {
}
@Override
- public Set supportedJWSAlgorithms() {
- return Set.of(this.getAlgorithm());
+ public JCAContext getJCAContext() {
+ return this.signer.getJCAContext();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519ProofOfPossessionJWSSignerImpl.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519ProofOfPossessionJWSSignerImpl.java
index 4f5b688d..4968533c 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519ProofOfPossessionJWSSignerImpl.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519ProofOfPossessionJWSSignerImpl.java
@@ -5,12 +5,11 @@
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.jca.JCAContext;
import com.nimbusds.jose.util.Base64URL;
-import java.security.KeyException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableEntryException;
+import java.security.*;
+import java.security.interfaces.EdECPrivateKey;
import java.util.Set;
/**
@@ -19,9 +18,9 @@
*
* To be used in conjunction with {@link ProofOfPossessionCreator#ProofOfPossessionCreator(ProofOfPossessionJWSSigner)}.
*/
-@Deprecated(since = "1.9.0")
public class PrimusEd25519ProofOfPossessionJWSSignerImpl extends PrimusEd25519VerificationMethodKeyProviderImpl implements ProofOfPossessionJWSSigner {
- final private String kid;
+ private final String kid;
+ private final JCAContext jcaContext = new JCAContext();
/**
* @see PrimusEd25519VerificationMethodKeyProviderImpl#PrimusEd25519VerificationMethodKeyProviderImpl(PrimusKeyStoreLoader, String, String)
@@ -32,6 +31,11 @@ public PrimusEd25519ProofOfPossessionJWSSignerImpl(PrimusKeyStoreLoader primus,
this.kid = kid;
}
+ public PrimusEd25519ProofOfPossessionJWSSignerImpl(KeyPair keyPair, String kid, PrimusKeyStoreLoader primus) {
+ super(keyPair, primus);
+ this.kid = kid;
+ }
+
@Override
public String getKid() {
return this.kid;
@@ -39,7 +43,7 @@ public String getKid() {
@Override
public JWSAlgorithm getAlgorithm() {
- return JWSAlgorithm.Ed25519;
+ return JWSAlgorithm.EdDSA;
}
@Override
@@ -51,4 +55,9 @@ public Set supportedJWSAlgorithms() {
public Base64URL sign(JWSHeader jwsHeader, byte[] bytes) throws JOSEException {
return Base64URL.encode(super.generateSignature(bytes));
}
+
+ @Override
+ public JCAContext getJCAContext() {
+ return jcaContext;
+ }
}
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519VerificationMethodKeyProviderImpl.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519VerificationMethodKeyProviderImpl.java
index d72e983c..f916ade8 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519VerificationMethodKeyProviderImpl.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusEd25519VerificationMethodKeyProviderImpl.java
@@ -5,10 +5,7 @@
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
-import java.security.KeyException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableEntryException;
+import java.security.*;
/**
* The {@link PrimusEd25519VerificationMethodKeyProviderImpl} class is a {@link VerificationMethodKeyProvider} implementation
@@ -44,6 +41,10 @@ public PrimusEd25519VerificationMethodKeyProviderImpl(PrimusKeyStoreLoader primu
super(primus.loadKeyPair(alias, password), primus.getKeyStore().getProvider());
}
+ public PrimusEd25519VerificationMethodKeyProviderImpl(KeyPair keyPair, PrimusKeyStoreLoader primus) {
+ super(keyPair, primus.getKeyStore().getProvider());
+ }
+
/**
* A simple wrapper for PrimusEncoding#optionallyUnderifyRS helper.
*/
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusKeyStoreLoader.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusKeyStoreLoader.java
index c8c684f7..c068c322 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusKeyStoreLoader.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/securosys/primus/PrimusKeyStoreLoader.java
@@ -4,10 +4,10 @@
import lombok.Getter;
import java.io.*;
- import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.security.*;
- import java.security.cert.CertificateException;
+import java.security.cert.CertificateException;
import java.util.Locale;
import java.util.Properties;
@@ -25,7 +25,7 @@ public class PrimusKeyStoreLoader {
public static final String PROVIDER_CLASS = "com.securosys.primus.jce.PrimusProvider";
private static final String KEY_STORE_TYPE_GETTER = "getKeyStoreTypeName";
private static final String PROVIDER_NAME_GETTER = "getProviderName";
- @Getter(AccessLevel.PACKAGE)
+ @Getter(AccessLevel.PUBLIC)
private final KeyStore keyStore;
/**
@@ -221,7 +221,7 @@ private String toCredentialFileLine(String value) {
* @throws KeyException
*/
@SuppressWarnings("PMD.UnusedAssignment")
- KeyPair loadKeyPair(String alias, String password)
+ public KeyPair loadKeyPair(String alias, String password)
throws UnrecoverableEntryException, KeyStoreException, NoSuchAlgorithmException, KeyException {
var keyStore = this.getKeyStore();
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryCreator.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryCreator.java
index a661166b..9b09811a 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryCreator.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryCreator.java
@@ -48,14 +48,14 @@
*
* - {@link WebVerifiableHistoryCreator#verificationMethodKeyProvider} for the purpose of adding data integrity proof
* - {@link WebVerifiableHistoryCreator#authentications} for setting authentication
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed25519 JsonWebKey2020) keys
* - {@link WebVerifiableHistoryCreator#assertionMethods} for setting/assertion
- * (EC/P-256 JsonWebKey2020) keys
+ * (P-256/Ed25519 JsonWebKey2020) keys
*
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256/Ed25519 JsonWebKey2020 keys from
* PEM files, you may rely on {@link JwkUtils}.
*
* CAUTION Any explicit use of this class in your code is HIGHLY INADVISABLE.
@@ -499,7 +499,6 @@ public String createDidLog(URL identifierRegistryUrl, ZonedDateTime zdt) throws
return createDidLog(createDidDoc(identifierRegistryUrl, this.allAuthentications(), this.allAssertionMethods()), zdt);
}
- //@SuppressWarnings({"PMD.CyclomaticComplexity"})
private String createDidLog(JsonObject didDoc, ZonedDateTime zdt) throws DidLogCreatorStrategyException {
if (getCryptoSuite() == null) {
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryDeactivator.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryDeactivator.java
index c6ff3873..3aa9915e 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryDeactivator.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryDeactivator.java
@@ -42,7 +42,7 @@
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256 JsonWebKey2020 keys from
* PEM files, you may rely on {@link JwkUtils}.
*
* CAUTION Any explicit use of this class in your code is HIGHLY INADVISABLE.
diff --git a/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryUpdater.java b/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryUpdater.java
index 826c7a56..5f599274 100644
--- a/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryUpdater.java
+++ b/src/main/java/ch/admin/bj/swiyu/didtoolbox/webvh/WebVerifiableHistoryUpdater.java
@@ -50,7 +50,7 @@
* To load required (Ed25519) keys (e.g. from the file system in PEM format),
* feel free to explore all available {@link ch.admin.bj.swiyu.didtoolbox.VerificationMethodKeyProvider} implementations.
*
- * To load authentication/assertion public EC P-256 JsonWebKey2020 keys from
+ * To load authentication/assertion public P-256 JsonWebKey2020 keys from
* PEM files, you may rely on {@link ch.admin.bj.swiyu.didtoolbox.JwkUtils}.
*
* CAUTION Any explicit use of this class in your code is HIGHLY INADVISABLE.
diff --git a/src/main/plantuml/DidLogCreatorContext-create.puml b/src/main/plantuml/DidLogCreatorContext-create.puml
index 9630e791..f2616b82 100644
--- a/src/main/plantuml/DidLogCreatorContext-create.puml
+++ b/src/main/plantuml/DidLogCreatorContext-create.puml
@@ -5,6 +5,7 @@ participant ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
participant ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory
participant ch.admin.bj.swiyu.didtoolbox.TdwCreator
participant ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+participant ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
participant ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator
participant ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorStrategy
@@ -25,20 +26,32 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
- ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.TdwCreator : builder
- activate ch.admin.bj.swiyu.didtoolbox.TdwCreator
- ch.admin.bj.swiyu.didtoolbox.TdwCreator --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.TdwCreator$TdwCreatorBuilder
- deactivate ch.admin.bj.swiyu.didtoolbox.TdwCreator
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : getCryptoSuite
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
+ ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.TdwCreator : builder
+ activate ch.admin.bj.swiyu.didtoolbox.TdwCreator
+ ch.admin.bj.swiyu.didtoolbox.TdwCreator --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.TdwCreator$TdwCreatorBuilder
+ deactivate ch.admin.bj.swiyu.didtoolbox.TdwCreator
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : allAssertionMethods
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
@@ -51,6 +64,18 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
@@ -61,20 +86,32 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : java.util.Set
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
- ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator : builder
- activate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator
- ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator$WebVerifiableHistoryCreatorBuilder
- deactivate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : getCryptoSuite
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
+ ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator : builder
+ activate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator
+ ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator$WebVerifiableHistoryCreatorBuilder
+ deactivate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryCreator
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : allAssertionMethods
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
@@ -87,6 +124,18 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
diff --git a/src/main/plantuml/DidLogDeactivatorContext-deactivate.puml b/src/main/plantuml/DidLogDeactivatorContext-deactivate.puml
index c297de22..650bd518 100644
--- a/src/main/plantuml/DidLogDeactivatorContext-deactivate.puml
+++ b/src/main/plantuml/DidLogDeactivatorContext-deactivate.puml
@@ -16,6 +16,10 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
+ ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext : getCryptoSuite
+ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
+ ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite
+ deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.TdwDeactivator : builder
activate ch.admin.bj.swiyu.didtoolbox.TdwDeactivator
ch.admin.bj.swiyu.didtoolbox.TdwDeactivator --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.TdwDeactivator$TdwDeactivatorBuilder
@@ -28,10 +32,6 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
activate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryDeactivator
ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryDeactivator --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryDeactivator$WebVerifiableHistoryDeactivatorBuilder
deactivate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryDeactivator
- ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext : getCryptoSuite
- activate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
- ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite
- deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory --> ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext : ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorStrategy
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory
ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext -> ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorStrategy : deactivateDidLog
diff --git a/src/main/plantuml/DidLogUpdaterContext-update.puml b/src/main/plantuml/DidLogUpdaterContext-update.puml
index cb443c37..fc2ed1c4 100644
--- a/src/main/plantuml/DidLogUpdaterContext-update.puml
+++ b/src/main/plantuml/DidLogUpdaterContext-update.puml
@@ -5,6 +5,7 @@ participant ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
participant ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory
participant ch.admin.bj.swiyu.didtoolbox.TdwUpdater
participant ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+participant ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
participant ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater
participant ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterStrategy
@@ -25,20 +26,32 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
- ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.TdwUpdater : builder
- activate ch.admin.bj.swiyu.didtoolbox.TdwUpdater
- ch.admin.bj.swiyu.didtoolbox.TdwUpdater --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.TdwUpdater$TdwUpdaterBuilder
- deactivate ch.admin.bj.swiyu.didtoolbox.TdwUpdater
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : getCryptoSuite
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
+ ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.TdwUpdater : builder
+ activate ch.admin.bj.swiyu.didtoolbox.TdwUpdater
+ ch.admin.bj.swiyu.didtoolbox.TdwUpdater --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.TdwUpdater$TdwUpdaterBuilder
+ deactivate ch.admin.bj.swiyu.didtoolbox.TdwUpdater
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : allAssertionMethods
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
@@ -51,6 +64,18 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
@@ -61,20 +86,32 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : java.util.Set
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
- ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater : builder
- activate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater
- ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater$WebVerifiableHistoryUpdaterBuilder
- deactivate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : getCryptoSuite
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite
deactivate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
+ ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater : builder
+ activate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater
+ ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater --> ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory : ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater$WebVerifiableHistoryUpdaterBuilder
+ deactivate ch.admin.bj.swiyu.didtoolbox.webvh.WebVerifiableHistoryUpdater
ch.admin.bj.swiyu.didtoolbox.context.DidLogStrategyFactory -> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : allAssertionMethods
activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
@@ -87,6 +124,18 @@ activate ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : of
activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : validateJwk
+ activate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod -> ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm : toString
+ activate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : java.lang.String
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm
+ ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : void
+ deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
deactivate ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod --> ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
diff --git a/src/main/plantuml/didtoolbox-api-classes-only.puml b/src/main/plantuml/didtoolbox-api-classes-only.puml
index 98aeae9b..62810fe8 100644
--- a/src/main/plantuml/didtoolbox-api-classes-only.puml
+++ b/src/main/plantuml/didtoolbox-api-classes-only.puml
@@ -24,7 +24,8 @@ interface ch.admin.bj.swiyu.didtoolbox.VerificationMethodKeyProvider {
class ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext {
- {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext$DidLogCreatorContextBuilder
+ {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext$DidLogCreatorContextBuilder <>
+ {method} {static} +builder ( paramDidMethodEnum1 : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum , paramVcDataIntegrityCryptographicSuite2 : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite ) : ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext$DidLogCreatorContextBuilder
{method} +create ( paramURL1 : java.net.URL ) : String
}
@@ -58,7 +59,8 @@ class ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorStrategyException {
class ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext {
- {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext$DidLogDeactivatorContextBuilder
+ {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext$DidLogDeactivatorContextBuilder <>
+ {method} {static} +builder ( paramDidMethodEnum1 : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum , paramVcDataIntegrityCryptographicSuite2 : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite ) : ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext$DidLogDeactivatorContextBuilder
{method} +deactivate ( paramString1 : String ) : String
{method} +deactivate ( paramFile1 : java.io.File ) : String
}
@@ -85,7 +87,8 @@ class ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorStrategyException {
class ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext {
- {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext$DidLogUpdaterContextBuilder
+ {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext$DidLogUpdaterContextBuilder <>
+ {method} {static} +builder ( paramDidMethodEnum1 : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum , paramVcDataIntegrityCryptographicSuite2 : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite ) : ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext$DidLogUpdaterContextBuilder
{method} +update ( paramString1 : String ) : String
{method} +update ( paramFile1 : java.io.File ) : String
}
@@ -172,6 +175,7 @@ class ch.admin.bj.swiyu.didtoolbox.model.UpdateKeysDidMethodParameterException {
interface ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial {
{method} {abstract} +getPublicKeyJwk () : String
+ {method} {static} +of ( paramString1 : String , paramString2 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
{method} {static} +of ( paramString1 : String , paramPath2 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
{method} {static} +of ( paramString1 : String , paramECPublicKey2 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
}
@@ -180,14 +184,15 @@ interface ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial {
interface ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod {
{method} +defaultEquals ( paramObject1 : Object ) : boolean
{method} {abstract} +getIdFragment () : String
- {method} {abstract} +getType () : String
+ {method} {abstract} +getType () : String <>
{method} {abstract} +getVerificationMaterial () : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
+ {method} {static} +of ( paramVerificationMaterial1 : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
{method} {static} +of ( paramString1 : String , paramString2 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
{method} {static} +of ( paramString1 : String , paramPath2 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
{method} {static} +of ( paramString1 : String , paramECPublicKey2 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
- {method} {static} +of ( paramString1 : String , paramString2 : String , paramString3 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
- {method} {static} +of ( paramString1 : String , paramString2 : String , paramPath3 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
- {method} {static} +of ( paramString1 : String , paramString2 : String , paramECPublicKey3 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ {method} {static} +of ( paramString1 : String , paramString2 : String , paramString3 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod <>
+ {method} {static} +of ( paramString1 : String , paramString2 : String , paramPath3 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod <>
+ {method} {static} +of ( paramString1 : String , paramString2 : String , paramECPublicKey3 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod <>
}
diff --git a/src/main/plantuml/didtoolbox-api.puml b/src/main/plantuml/didtoolbox-api.puml
index 4170eacb..540963e8 100644
--- a/src/main/plantuml/didtoolbox-api.puml
+++ b/src/main/plantuml/didtoolbox-api.puml
@@ -24,7 +24,8 @@ interface ch.admin.bj.swiyu.didtoolbox.VerificationMethodKeyProvider {
class ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext {
- {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext$DidLogCreatorContextBuilder
+ {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext$DidLogCreatorContextBuilder <>
+ {method} {static} +builder ( paramDidMethodEnum1 : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum , paramVcDataIntegrityCryptographicSuite2 : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite ) : ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorContext$DidLogCreatorContextBuilder
{method} +create ( paramURL1 : java.net.URL ) : String
}
@@ -58,7 +59,8 @@ class ch.admin.bj.swiyu.didtoolbox.context.DidLogCreatorStrategyException {
class ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext {
- {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext$DidLogDeactivatorContextBuilder
+ {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext$DidLogDeactivatorContextBuilder <>
+ {method} {static} +builder ( paramDidMethodEnum1 : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum , paramVcDataIntegrityCryptographicSuite2 : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite ) : ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorContext$DidLogDeactivatorContextBuilder
{method} +deactivate ( paramString1 : String ) : String
{method} +deactivate ( paramFile1 : java.io.File ) : String
}
@@ -85,7 +87,8 @@ class ch.admin.bj.swiyu.didtoolbox.context.DidLogDeactivatorStrategyException {
class ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext {
- {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext$DidLogUpdaterContextBuilder
+ {method} {static} +builder () : ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext$DidLogUpdaterContextBuilder <>
+ {method} {static} +builder ( paramDidMethodEnum1 : ch.admin.bj.swiyu.didtoolbox.model.DidMethodEnum , paramVcDataIntegrityCryptographicSuite2 : ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuite ) : ch.admin.bj.swiyu.didtoolbox.context.DidLogUpdaterContext$DidLogUpdaterContextBuilder
{method} +update ( paramString1 : String ) : String
{method} +update ( paramFile1 : java.io.File ) : String
}
@@ -172,6 +175,7 @@ class ch.admin.bj.swiyu.didtoolbox.model.UpdateKeysDidMethodParameterException {
interface ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial {
{method} {abstract} +getPublicKeyJwk () : String
+ {method} {static} +of ( paramString1 : String , paramString2 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
{method} {static} +of ( paramString1 : String , paramPath2 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
{method} {static} +of ( paramString1 : String , paramECPublicKey2 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
}
@@ -180,14 +184,15 @@ interface ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial {
interface ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod {
{method} +defaultEquals ( paramObject1 : Object ) : boolean
{method} {abstract} +getIdFragment () : String
- {method} {abstract} +getType () : String
+ {method} {abstract} +getType () : String <>
{method} {abstract} +getVerificationMaterial () : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial
+ {method} {static} +of ( paramVerificationMaterial1 : ch.admin.bj.swiyu.didtoolbox.model.VerificationMaterial ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
{method} {static} +of ( paramString1 : String , paramString2 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
{method} {static} +of ( paramString1 : String , paramPath2 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
{method} {static} +of ( paramString1 : String , paramECPublicKey2 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
- {method} {static} +of ( paramString1 : String , paramString2 : String , paramString3 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
- {method} {static} +of ( paramString1 : String , paramString2 : String , paramPath3 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
- {method} {static} +of ( paramString1 : String , paramString2 : String , paramECPublicKey3 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod
+ {method} {static} +of ( paramString1 : String , paramString2 : String , paramString3 : String ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod <>
+ {method} {static} +of ( paramString1 : String , paramString2 : String , paramPath3 : java.nio.file.Path ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod <>
+ {method} {static} +of ( paramString1 : String , paramString2 : String , paramECPublicKey3 : java.security.interfaces.ECPublicKey ) : ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod <>
}
diff --git a/src/test/data/rsa b/src/test/data/rsa
new file mode 100644
index 00000000..5f4d9fba
--- /dev/null
+++ b/src/test/data/rsa
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDfWPH8rkc3YXyw
+E069paRbH/PPmxNQB10dEJAVAloSlnMVtVMnVy9uakDdipyim7idin0GI21LcdEx
+AECTe31tOtvYMv4l2ZFAiZOeJ9bguTRVI9YM5ZpoxzN8y5T9Z8v2wwPnFmOq4uf8
+Tjg8+9/K3tFs1DOftHVlp23SRseiZbkJDofAXOlDueHd6xxObzu+N5tuQhiN4+Jh
+swHQghruhaot4kswHT8qk8UKofp4YNFY8S6ONmMNmukwu4mZsvO1bbsrPeVvyIx5
+7F402wLJgB9+mrGfqhWMFC8SFes5vkJaDgo6TBMqLrlodAn349ddhcYnwOebP+HU
+hKiVW0zZAgMBAAECggEANaeoeotjkGpbCfGZePXSBhInADjA6vjZ5aGU+3cVLGH4
+Q77Luye2vU/JRW+HMYk3UKF0Z4UbPISbPKpS2RtRhmwdZFLbuzwJKPfj/pqThGj5
+qXpycaa28XTpaZF+uWG2HhG7XkiCqQrZsEMaP4xCtvnQVdSkkjlH+qO+PkXCr8BN
+Lh0PAXG+N9lVLrUXL/ytlCevjnqALolM5nEuLIjKGMnj4aM5G99w50AMjbIbBsHn
+YlaRZL6ovYlr2gqOPUxcpo0L5bEylkpumtEevtm0UnC3jzQVJK2Ag6hYmGXGrQdw
+Xp1VIIFQ/hVbKBOUkTN5uOkYlQwAFX5mR9qOpMfYAQKBgQD63vhw4orxD5cc7cMn
+H8vteo0XkJ5a/8uZR1JfHsQfO4+dX2Mf/50TtDADUX1OQwRwIeSNKDIVf9fyWIKP
+3oaz1aAEvXEjF1u7XTYO71D563DnHGib1jDXPODGPis/gQTBUXItZh9wAk95x8mR
+c5JuB3nwYRVATNvHQjXcGbGQdQKBgQDj6et4MQ9fl6fCueAOmHYTttUfFSafv+RT
+xh2y3I5D/6Tu9e0K8amWimgeHhuvcknwPEkwCzgdvuWsYb6Qf2xZEAlAAqj7dZyb
+bu2RnROb7Aa7gb8Fxk8DO84BypPKoqQ2h1hrbt3IoQEt+nFKIVNQre9z/DCDYSW7
+xUk6zYI+VQKBgCID1X/I17nzuTOM8Wb+orHiafsF+tKv2DVCPGL1UvZBJynZYyFV
+kUC4r8HjbLAN2i4yCkExcAkGOot7gMhtDaqYjofV/98YLbHr44aG4F3ilH5hlbV7
+h0fH01pN16NWpQRpPKf3LtALICeM9UGpf/M3REtZfn4nba1IxvC+8xp5AoGAKzzI
+aB/ei8MIl3+NyxcPZ4QLAH+RuUK9PUtbfQAsmSfZkV/kXWwlQSL2x6fslqc28bVu
+KQgn2DTL+5z7ewxBcNADATq/9hyE3lP4C+ThwHXRfScLJzxM5w8kcOCOkyWxw4p/
+srnwp0wsHh3h+i9CUA7/W2Cfj30RnIK79sTgDZUCgYEAs5H2pD/aXACmzeGycMPW
+vdFAatkCG3Oa3R/m7hsdVHtvZuLv9jIQHU0FytwAlbrUlRZOu8JxuOXVXZ+hLREB
+yxLenU07WpDdUWWsZpItnU7SCOLYy9y7gXVOc7VUvIlAW0cC91GUmCc1Bd21ieWq
+5URz/JAeYPhUCD91HbZjFVY=
+-----END PRIVATE KEY-----
\ No newline at end of file
diff --git a/src/test/data/rsa.pub b/src/test/data/rsa.pub
new file mode 100644
index 00000000..acf2ea16
--- /dev/null
+++ b/src/test/data/rsa.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA31jx/K5HN2F8sBNOvaWk
+Wx/zz5sTUAddHRCQFQJaEpZzFbVTJ1cvbmpA3Yqcopu4nYp9BiNtS3HRMQBAk3t9
+bTrb2DL+JdmRQImTnifW4Lk0VSPWDOWaaMczfMuU/WfL9sMD5xZjquLn/E44PPvf
+yt7RbNQzn7R1Zadt0kbHomW5CQ6HwFzpQ7nh3escTm87vjebbkIYjePiYbMB0IIa
+7oWqLeJLMB0/KpPFCqH6eGDRWPEujjZjDZrpMLuJmbLztW27Kz3lb8iMeexeNNsC
+yYAffpqxn6oVjBQvEhXrOb5CWg4KOkwTKi65aHQJ9+PXXYXGJ8Dnmz/h1ISolVtM
+2QIDAQAB
+-----END PUBLIC KEY-----
\ No newline at end of file
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/AbstractUtilTestBase.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/AbstractUtilTestBase.java
index d2f319c8..6c883c19 100644
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/AbstractUtilTestBase.java
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/AbstractUtilTestBase.java
@@ -45,7 +45,7 @@ public abstract class AbstractUtilTestBase {
final protected static VcDataIntegrityCryptographicSuite TEST_CRYPTO_SUITE_JKS;
/**
- * Sharing the very same keys ({@link #TEST_PRIVATE_KEY_MULTIBASE}, {@link #TEST_PUBLIC_KEY_MULTIBASE}) with {@link #TEST_POP_JWS_SIGNER}
+ * Sharing the very same keys ({@link #TEST_PRIVATE_KEY_MULTIBASE}, {@link #TEST_PUBLIC_KEY_MULTIBASE})
*/
final protected static VcDataIntegrityCryptographicSuite TEST_CRYPTO_SUITE;
@@ -74,11 +74,8 @@ public abstract class AbstractUtilTestBase {
/**
* Sharing the very same keys ({@link #TEST_PRIVATE_KEY_MULTIBASE}, {@link #TEST_PUBLIC_KEY_MULTIBASE}) with {@link #TEST_CRYPTO_SUITE}
*/
- final protected static ProofOfPossessionJWSSigner TEST_POP_JWS_SIGNER;
final static String TEST_POP_JWS_KID = "did:webvh:SCID:example.com#key-1";
- final static String TEST_POP_JWS_KID_ANOTHER = "did:webvh:SCID:example.com#key-2";
-
/**
* Collection of signing/verifying Ed25519 keys in various (appropriate) format intended for testing purposes only
*
@@ -160,9 +157,8 @@ public abstract class AbstractUtilTestBase {
try {
// Using (example) keys from https://www.w3.org/TR/vc-di-eddsa/#example-private-and-public-keys-for-signature-0
- var suite = new EdDsaJcs2022ProofOfPossessionJWSSignerImpl(TEST_PRIVATE_KEY_MULTIBASE, TEST_POP_JWS_KID);
- TEST_POP_JWS_SIGNER = suite;
- TEST_CRYPTO_SUITE = suite;
+ var suite =
+ TEST_CRYPTO_SUITE = new EdDsaJcs2022VcDataIntegrityCryptographicSuite(TEST_PRIVATE_KEY_MULTIBASE);;
// Total 3 (PrivateKeyEntry) entries available in the JKS: myalias/myalias2/myalias3
var suiteJks = new EdDsaJcs2022JWSSigner(
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/BlackboxIT.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/BlackboxIT.java
index fcb41479..10b67adb 100644
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/BlackboxIT.java
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/BlackboxIT.java
@@ -1,5 +1,6 @@
package ch.admin.bj.swiyu.didtoolbox;
+import ch.admin.bj.swiyu.didtoolbox.model.DidLogMetaPeekerException;
import ch.admin.bj.swiyu.didtoolbox.model.WebVerifiableHistoryDidLogMetaPeeker;
import com.beust.jcommander.internal.DefaultConsole;
import org.junit.jupiter.api.Test;
@@ -106,17 +107,7 @@ void createUpdateAndDeactivateDidLog_thenFailUpdate(@TempDir Path tempDir) throw
didLog = cliOutput.toString();
cliOutput.reset();
- // FIXME: the current didresolver does not yet throw an exception when trying to resolve a deactivated did.
- // The below line should work once the didresolver exhibits the desired behavior.
- // assertThrows(() -> WebVerifiableHistoryDidLogMetaPeeker.peek(didLog), DidLogMetaPeekerException.class);
- // Current workaround is to try and update a deactivated did log, which fails.
- var didLogFilePathV3 = tempDir + "/didlogV3.jsonl";
- try (var writer = new PrintWriter(didLogFilePathV3, StandardCharsets.UTF_8)) {
- writer.write(didLog);
- }
- var updateDeactivatedDidLog = new String[]{"update", "-d", didLogFilePathV3, "-s", "./src/test/data/private.pem", "-v", "./src/test/data/public.pem", "-a", "assert-key-03,./src/test/data/assert-key-01.pub", "-t", "auth-key-03,./src/test/data/auth-key-01.pub"};
- assertEquals(1, main.run(updateDeactivatedDidLog));
- var out = cliOutput.toString();
- assertTrue(out.contains("can no longer be updated"));
+ final var finalDidLog = didLog;
+ assertThrows(DidLogMetaPeekerException.class, () -> WebVerifiableHistoryDidLogMetaPeeker.peek(finalDidLog));
}
}
\ No newline at end of file
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/EdDsaJcs2022ProofOfPossessionJWSSignerImpl.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/EdDsaJcs2022ProofOfPossessionJWSSignerImpl.java
deleted file mode 100644
index 355c4290..00000000
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/EdDsaJcs2022ProofOfPossessionJWSSignerImpl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package ch.admin.bj.swiyu.didtoolbox;
-
-import ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.EdDsaJcs2022VcDataIntegrityCryptographicSuite;
-import ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuiteException;
-import com.nimbusds.jose.JOSEException;
-import com.nimbusds.jose.JWSAlgorithm;
-import com.nimbusds.jose.JWSHeader;
-import com.nimbusds.jose.util.Base64URL;
-
-import java.util.Set;
-
-/**
- * Intended for unit testing purposes only.
- */
-//@SuppressWarnings("PMD")
-class EdDsaJcs2022ProofOfPossessionJWSSignerImpl extends EdDsaJcs2022VcDataIntegrityCryptographicSuite implements ProofOfPossessionJWSSigner {
- private final String kid;
-
- EdDsaJcs2022ProofOfPossessionJWSSignerImpl(String privateKeyMultibase, String kid) throws VcDataIntegrityCryptographicSuiteException {
- super(privateKeyMultibase);
- this.kid = kid;
- }
-
- @Override
- public String getKid() {
- return this.kid;
- }
-
- @Override
- public JWSAlgorithm getAlgorithm() {
- return JWSAlgorithm.Ed25519;
- }
-
- @Override
- public Set supportedJWSAlgorithms() {
- return Set.of(this.getAlgorithm());
- }
-
- @Override
- public Base64URL sign(JWSHeader jwsHeader, byte[] bytes) throws JOSEException {
- return Base64URL.encode(this.generateSignature(bytes));
- }
-}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/FilesPrivacyTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/FilesPrivacyTest.java
index f71a1162..7fe8a08d 100644
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/FilesPrivacyTest.java
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/FilesPrivacyTest.java
@@ -1,6 +1,7 @@
package ch.admin.bj.swiyu.didtoolbox;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.nio.file.*;
@@ -175,4 +176,22 @@ void testRestrictAccessToCurrentUserOnly() {
assertTrue(Files.isWritable(tempPath));
});
}
+
+ @Test
+ void createPrivateKeyDirectoryIfDoesNotExist_directoryDoesntExist_createsDirectory(@TempDir Path tmpDir) {
+ var directory = new File(tmpDir.toString(), "dir");
+ assertFalse(directory.exists());
+
+ assertDoesNotThrow(() -> FilesPrivacy.createPrivateKeyDirectoryIfDoesNotExist(directory.toPath()));
+ assertTrue(directory.exists());
+ }
+
+ @Test
+ void createPrivateKeyDirectoryIfDoesNotExist_directoryAlreadyExist_doesNothing(@TempDir Path tmpDir) {
+ var directory = new File(tmpDir.toString());
+ assertTrue(directory.exists());
+
+ assertDoesNotThrow(() -> FilesPrivacy.createPrivateKeyDirectoryIfDoesNotExist(directory.toPath()));
+ assertTrue(directory.exists());
+ }
}
\ No newline at end of file
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/JwkUtilsTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/JwkUtilsTest.java
index 75312e68..2f312ea2 100644
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/JwkUtilsTest.java
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/JwkUtilsTest.java
@@ -1,10 +1,12 @@
package ch.admin.bj.swiyu.didtoolbox;
+import ch.admin.bj.swiyu.didtoolbox.model.VerificationMethod;
import com.google.gson.JsonParser;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jose.crypto.ECDSAVerifier;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.io.IOException;
@@ -21,8 +23,10 @@
@SuppressWarnings({"PMD"})
class JwkUtilsTest {
- private static void assertGeneratePublicEC256(String json, String kid) {
- assertNotNull(json);
+ private static void assertGeneratePublicEC256(VerificationMethod verificationMethod, String kid) {
+ assertEquals(kid, verificationMethod.getIdFragment());
+
+ var json = verificationMethod.getVerificationMaterial().getPublicKeyJwk();
var publicJwkJsonObject = JsonParser.parseString(json).getAsJsonObject();
assertTrue(publicJwkJsonObject.has("kty"));
assertEquals("EC", publicJwkJsonObject.get("kty").getAsString());
@@ -63,22 +67,38 @@ private static void ecPemSanityCheck(File privatePemFile, File publicPemFile)
}
@Test
- void testGeneratePublicEC256() {
+ void testGeneratePublicEC256_withNoPreexistingFiles_createsFiles(@TempDir Path tmpDir) {
+ var file = new File(tmpDir.toString(), "pem");
+ String kid = "auth-key-01";
+ assertDoesNotThrow(() -> {
+ var verificationMethod = JwkUtils.generatePublicP256VerificationMethod(kid, file, false);
+ assertGeneratePublicEC256(verificationMethod, kid);
+ });
+ assertTrue(file.exists());
+ assertTrue(new File(tmpDir.toString(), "pem.pub").exists());
+ }
+
+ @Test
+ void generatePublicEd25519_withNoPreexistingFiles_createsFiles(@TempDir Path tmpDir) {
+ var file = new File(tmpDir.toString(), "pem");
+ String kid = "auth-key-01";
assertDoesNotThrow(() -> {
- // No PEM files are exported here
- assertGeneratePublicEC256(JwkUtils.generatePublicEC256("auth-key-01", null, false), null); // MUT
+ var verificationMethod = JwkUtils.generatePublicP256VerificationMethod(kid, file, false);
+ assertGeneratePublicEC256(verificationMethod, kid);
});
+ assertTrue(file.exists());
+ assertTrue(new File(tmpDir.toString(), "pem.pub").exists());
}
@Test
- void testGeneratePublicEC256WithOutputOverwriteExisting() {
+ void generatePublicEC256VerificationMethod_withPreexistingFileAndForce_overwritesFiles() {
assertDoesNotThrow(() -> {
var tempFile = File.createTempFile("mypublic", "");
// Exists at the moment of key generation, and should therefore be overwritten if forceOverwritten == true
tempFile.deleteOnExit();
var kid = "auth-key-01";
- assertGeneratePublicEC256(JwkUtils.generatePublicEC256(kid, tempFile, true), kid); // MUT
+ assertGeneratePublicEC256(JwkUtils.generatePublicP256VerificationMethod(kid, tempFile, true), kid); // MUT
// Verification of the exported PEM files
assertNotEquals(0, Files.size(tempFile.toPath()));
@@ -92,20 +112,16 @@ void testGeneratePublicEC256WithOutputOverwriteExisting() {
}
@Test
- void testGeneratePublicEC256WithOutputNoOverwriteExistingThrowsException() {
+ void generatePublicEC256VerificationMethod_withOutputNoOverwriteExisting_throwsException() throws IOException {
File tempFile = null;
- try {
- tempFile = File.createTempFile("mypublic", "");
- // Exists at the moment of key generation, and should NOT be overwritten if forceOverwritten == false
- tempFile.deleteOnExit();
- } catch (Exception e) {
- fail(e);
- }
+ tempFile = File.createTempFile("mypublic", "");
+ // Exists at the moment of key generation, and should NOT be overwritten if forceOverwritten == false
+ tempFile.deleteOnExit();
File finalTempFile = tempFile;
var exc = assertThrowsExactly(IOException.class, () -> {
// kid is irrelevant here
- JwkUtils.generatePublicEC256(null, finalTempFile, false); // MUT
+ JwkUtils.generatePublicP256VerificationMethod("kid", finalTempFile, false); // MUT
});
assertTrue(exc.getMessage().contains("The PEM file(s) exist(s) already and will remain intact until overwrite mode is engaged"));
@@ -129,7 +145,7 @@ void testGeneratePublicEC256WithOutputOverwriteNonExisting() {
tempFile.deleteOnExit();
var kid = "auth-key-01";
- assertGeneratePublicEC256(JwkUtils.generatePublicEC256(kid, tempFile, true), kid); // MUT
+ assertGeneratePublicEC256(JwkUtils.generatePublicP256VerificationMethod(kid, tempFile, true), kid); // MUT
// Verification of the exported PEM files
assertNotEquals(0, Files.size(tempFile.toPath()));
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionCreatorTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionCreatorTest.java
index d8893956..ab050488 100644
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionCreatorTest.java
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionCreatorTest.java
@@ -1,29 +1,34 @@
package ch.admin.bj.swiyu.didtoolbox;
import ch.admin.bj.swiyu.didtoolbox.model.WebVerifiableHistoryDidLogMetaPeeker;
+import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import org.junit.jupiter.api.Test;
import java.nio.file.Path;
import java.time.Duration;
+import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@SuppressWarnings("PMD")
class ProofOfPossessionCreatorTest extends AbstractUtilTestBase {
private static final Duration ONE_DAY_LONG = Duration.ofDays(1);
@Test
- void testCreateJWT_valid() throws Exception {
+ void create_withValidParameters_returnsValidJWT() throws Exception {
var nonce = "test_nonce";
var didLog = buildInitialWebVerifiableHistoryDidLogEntry(TEST_CRYPTO_SUITE);
var didLogMeta = WebVerifiableHistoryDidLogMetaPeeker.peek(didLog);
- var crypto = new EcP256ProofOfPossessionJWSSigner(Path.of("src/test/data/assert-key-01"), didLogMeta.getDidDoc().getId() + "#my-assert-key-01");
+ var crypto = ProofOfPossessionJWSSigner.of(Path.of("src/test/data/assert-key-01"), didLogMeta.getDidDoc().getId() + "#my-assert-key-01");
var proofCreator = new ProofOfPossessionCreator(crypto);
- var pop = proofCreator.create(nonce, Duration.ofDays(90));
+ var pop = proofCreator.create(nonce, ONE_DAY_LONG);
var header = pop.getHeader();
assertEquals(JWSAlgorithm.ES256, pop.getHeader().getAlgorithm());
@@ -42,56 +47,49 @@ void testCreateJWT_valid() throws Exception {
}
@Test
- void testCreateInvalid() throws Exception {
+ void create_withInvalidSigner_throwsProofOfPossessionCreatorException() throws Exception {
+ var exceptionMessage = "mock exception";
var nonce = "my_nonce";
-
- // NOTE The very same keys are shared only between:
- // - EXAMPLE_VERIFICATION_METHOD_KEY_PROVIDER and EXAMPLE_POP_JWS_SIGNER
- // - EXAMPLE_VERIFICATION_METHOD_KEY_PROVIDER_ANOTHER and EXAMPLE_POP_JWS_SIGNER_ANOTHER
-
- // for the purpose, you may also use EXAMPLE_POP_JWS_SIGNER_ANOTHER here, instead
- var didLog = buildInitialTdwDidLogEntry(TEST_CRYPTO_SUITE_ANOTHER);
+ var signer = mock(ProofOfPossessionJWSSigner.class);
+ when(signer.getAlgorithm()).thenReturn(JWSAlgorithm.EdDSA);
+ when(signer.getKid()).thenReturn(TEST_POP_JWS_KID);
+ when(signer.supportedJWSAlgorithms()).thenReturn(Set.of(JWSAlgorithm.EdDSA));
+ when(signer.sign(any(), any())).thenThrow(new JOSEException(exceptionMessage));
// create proof
- var proof = new ProofOfPossessionCreator(TEST_POP_JWS_SIGNER)
- .create(nonce, ONE_DAY_LONG);
+ var creator = new ProofOfPossessionCreator(signer);
+ var ex = assertThrowsExactly(ProofOfPossessionCreatorException.class, () -> creator.create(nonce, ONE_DAY_LONG));
+ assertTrue(ex.getMessage().contains(exceptionMessage));
+ }
- // verify JWT (head/payload) claims
- var header = proof.getHeader();
- assertEquals(JWSAlgorithm.Ed25519, header.getAlgorithm());
+ @Test
+ void create_withoutDuration_throwsProofOfPossessionCreatorException() throws Exception {
+ var nonce = "test_nonce";
- // CAUTION: MUST differ!
- assertFalse(didLog.contains(header.getKeyID()));
+ var didLog = buildInitialWebVerifiableHistoryDidLogEntry(TEST_CRYPTO_SUITE);
+ var didLogMeta = WebVerifiableHistoryDidLogMetaPeeker.peek(didLog);
- var payload = proof.getPayload().toJSONObject();
- assertNotNull(payload.get("exp"));
- assertNotNull(payload.get("nonce"));
- assertEquals(nonce, payload.get("nonce").toString());
+ var crypto = new EcP256ProofOfPossessionJWSSigner(Path.of("src/test/data/assert-key-01"), didLogMeta.getDidDoc().getId() + "#my-assert-key-01");
+ var proofCreator = new ProofOfPossessionCreator(crypto);
- // CAUTION: MUST be invalid
- assertFalse(new ProofOfPossessionVerifier(didLog).isValid(proof, nonce));
+ assertThrowsExactly(NullPointerException.class, () -> proofCreator.create(nonce, null));
}
@Test
- void testCreateValidJWT_fail() throws Exception {
- var nonce = "my_nonce";
+ void create_withNonce_returnsJWTWithNullNonce() throws Exception {
+ var didLog = buildInitialWebVerifiableHistoryDidLogEntry(TEST_CRYPTO_SUITE);
+ var didLogMeta = WebVerifiableHistoryDidLogMetaPeeker.peek(didLog);
- var didLog = buildInitialTdwDidLogEntry(TEST_CRYPTO_SUITE);
+ var crypto = new EcP256ProofOfPossessionJWSSigner(Path.of("src/test/data/assert-key-01"), didLogMeta.getDidDoc().getId() + "#my-assert-key-01");
+ var proofCreator = new ProofOfPossessionCreator(crypto);
- // create proof
- var proof = new ProofOfPossessionCreator(TEST_POP_JWS_SIGNER)
- .create(nonce, ONE_DAY_LONG);
-
- // verify JWT (head/payload) claims
- var header = proof.getHeader();
- assertEquals(JWSAlgorithm.Ed25519, header.getAlgorithm());
- assertFalse(didLog.contains(header.getKeyID()));
- var payload = proof.getPayload().toJSONObject();
- assertNotNull(payload.get("exp"));
- assertNotNull(payload.get("nonce"));
- assertEquals(nonce, payload.get("nonce").toString());
+ var pop = proofCreator.create(null, ONE_DAY_LONG);
- // verify proof
- assertFalse(new ProofOfPossessionVerifier(didLog).isValid(proof, nonce));
+ var header = pop.getHeader();
+ assertEquals(JWSAlgorithm.ES256, pop.getHeader().getAlgorithm());
+ assertTrue(didLog.contains(header.getKeyID()));
+
+ var payload = pop.getPayload().toJSONObject();
+ assertNull(payload.get("nonce"));
}
}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionJWSSignerTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionJWSSignerTest.java
new file mode 100644
index 00000000..e4846042
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionJWSSignerTest.java
@@ -0,0 +1,49 @@
+package ch.admin.bj.swiyu.didtoolbox;
+
+import ch.admin.bj.swiyu.didtoolbox.vc_data_integrity.VcDataIntegrityCryptographicSuiteException;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ProofOfPossessionJWSSignerTest {
+
+ private static final String KID = "did:webvh:scid:example.com#kid";
+
+ @Test
+ void of_validP256Pem_returnsJWSSigner() {
+ var path = Path.of("src/test/data/assert-key-01");
+ var signer = assertDoesNotThrow(() -> ProofOfPossessionJWSSigner.of(path, KID));
+
+ assertEquals(JWSAlgorithm.ES256, signer.getAlgorithm());
+ assertEquals(KID, signer.getKid());
+ assertNotNull(signer.getJCAContext());
+
+ var data = "Hello, world!".getBytes();
+ var header = new JWSHeader(JWSAlgorithm.ES256);
+ assertDoesNotThrow(() -> signer.sign(header, data));
+ }
+
+ @Test
+ void of_validEd25519Pem_returnsJWSSigner() {
+ var path = Path.of("src/test/data/private.pem");
+ var signer = assertDoesNotThrow(() -> ProofOfPossessionJWSSigner.of(path, KID));
+
+ assertEquals(JWSAlgorithm.EdDSA, signer.getAlgorithm());
+ assertEquals(KID, signer.getKid());
+ assertNotNull(signer.getJCAContext());
+
+ var data = "Hello, world!".getBytes();
+ var header = new JWSHeader(JWSAlgorithm.EdDSA);
+ assertDoesNotThrow(() -> signer.sign(header, data));
+ }
+
+ @Test
+ void of_invalidPemFile_returnsJWSSigner() {
+ var path = Path.of("src/test/data/README.md");
+ assertThrowsExactly(VcDataIntegrityCryptographicSuiteException.class, () -> ProofOfPossessionJWSSigner.of(path, KID));
+ }
+}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifierTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifierTest.java
index 6c46523c..928e98c6 100644
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifierTest.java
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/ProofOfPossessionVerifierTest.java
@@ -2,17 +2,24 @@
import ch.admin.bj.swiyu.didtoolbox.model.WebVerifiableHistoryDidLogMetaPeeker;
import ch.admin.eid.did_sidekicks.DidDoc;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.nio.file.Path;
+import java.text.ParseException;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@SuppressWarnings("PMD")
class ProofOfPossessionVerifierTest extends AbstractUtilTestBase {
+ private static final String NONCE = "example_nonce";
private static final Duration ONE_DAY_LONG = Duration.ofDays(1);
String didLog;
@@ -35,28 +42,44 @@ void testProofOfPossessionConstructor() {
}
@Test
- void testVerify() {
- var nonce = "my_nonce";
+ void isValid_withCreatorCreatedPoP_returnsTrue() {
+ // create proof
+ var proof = assertDoesNotThrow(() -> new ProofOfPossessionCreator(signer).create(NONCE, ONE_DAY_LONG));
+
+ var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
+ assertTrue(verifier.isValid(proof, NONCE));
+ }
+ @Test
+ void verify_withP256Key_doesNotThrow() {
// create proof
- var proof = assertDoesNotThrow(() -> new ProofOfPossessionCreator(signer).create(nonce, ONE_DAY_LONG));
+ var proof = assertDoesNotThrow(() -> new ProofOfPossessionCreator(signer).create(NONCE, ONE_DAY_LONG));
var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
- assertTrue(verifier.isValid(proof, nonce));
+ assertDoesNotThrow(() -> verifier.verify(proof, NONCE));
+ }
- assertDoesNotThrow(() -> verifier.verify(proof, nonce));
+ @Test
+ void verify_withEd25519Key_doesNotThrow() {
+ var didLog = """
+ {"versionId":"1-QmPuz69mEWiTum1PCzmu5zUgdG4vCKWi4FkBZTnMvGYHSa","versionTime":"2026-07-22T07:18:47Z","parameters":{"method":"did:webvh:1.0","scid":"QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP","updateKeys":["z6Mks5QkVWEK4w1GirvtzWpCkXUMoeiCEgTLdmuPTwpzxmLi"],"portable":false},"state":{"id":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com","profile_version":"swiss-profile-anchor:1.0.0","authentication":["did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#auth-key-01","did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#auth-key-02"],"assertionMethod":["did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#assert-key-01","did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#assert-key-02"],"verificationMethod":[{"id":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#auth-key-01","controller":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"OKP","crv":"Ed25519","x":"OfyYdxv2AjSTMddJHONMFHnXLcZnPiQ1KGFa-AX75x0","kid":"auth-key-01"}},{"id":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#auth-key-02","controller":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"EC","crv":"P-256","kid":"auth-key-02","x":"CCw9szn4CYfHmTKluoERTU40QOX68ghbxQWz7HUsjuI","y":"6Bf9ySbmakgFx-aApAN2okcvZ-nqW-HvARS_mQd9010"}},{"id":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#assert-key-01","controller":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"OKP","crv":"Ed25519","x":"-BfbOxS0VRGntlDa8TmcoXfEZP_EvpgKox67sARrlsE","kid":"assert-key-01"}},{"id":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com#assert-key-02","controller":"did:webvh:QmSDKjwjKxjf9Bie8F6V9Up9j6LUtv8TRawKVP64dVQXdP:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"EC","crv":"P-256","kid":"assert-key-02","x":"arXHklzxgekECtQ9QwTfEuCVMrJSdCte7KUWFrKQ8kI","y":"0NS2Z8ydCXU7IJoM86shegENExHgLGPfPx3Yi9YK9kM"}}]},"proof":[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","created":"2026-07-22T07:18:47Z","verificationMethod":"did:key:z6Mks5QkVWEK4w1GirvtzWpCkXUMoeiCEgTLdmuPTwpzxmLi#z6Mks5QkVWEK4w1GirvtzWpCkXUMoeiCEgTLdmuPTwpzxmLi","proofPurpose":"assertionMethod","proofValue":"z53mYjrN7WBdPoxp8LBCMbm7koYAqGCkEJQiu6TqjUTKk8x8oGGcM9PWSUX3mDzXAEuzjjhEFpEcCb4TwjCt6eqRf"}]}
+ """;
+ var jwt = "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDp3ZWJ2aDpRbVNES2p3akt4amY5QmllOEY2VjlVcDlqNkxVdHY4VFJhd0tWUDY0ZFZRWGRQOmV4YW1wbGUuY29tI2F1dGgta2V5LTAxIiwidHlwIjoiSldUIn0.eyJpc3MiOiJkaWQ6d2Vidmg6UW1TREtqd2pLeGpmOUJpZThGNlY5VXA5ajZMVXR2OFRSYXdLVlA2NGRWUVhkUDpleGFtcGxlLmNvbSIsImV4cCI6MTAwMDAwMDAwMDAsIm5vbmNlIjoibXlfbm9uY2UiLCJpYXQiOjE3ODQ3MDQ2Mjh9.eOF7PmbJwQ4qDtwpjH3yOVzUL9FC7V2VGEki0xgITOwrSD_uHfXCjZNJhELrno-TwsBaWh0t5Pf__beoT2-0Cw";
+ var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
+ var signedJWT = assertDoesNotThrow(() -> SignedJWT.parse(jwt));
+ assertDoesNotThrow(() -> verifier.verify(signedJWT, "my_nonce"));
}
@Test
void verify_KeyNotInDidLog() {
var nonce = "my_nonce";
signer = assertDoesNotThrow(() -> new EcP256ProofOfPossessionJWSSigner(Path.of("src/test/data/assert-key-01"), didDoc.getId() + "#my-assert-key-01-not-in-doc"));
- var proof = assertDoesNotThrow(() -> new ProofOfPossessionCreator(signer).create(nonce, ONE_DAY_LONG));
+ var proof = assertDoesNotThrow(() -> new ProofOfPossessionCreator(signer).create(NONCE, ONE_DAY_LONG));
// for the purpose, you may also use EXAMPLE_POP_JWS_SIGNER_ANOTHER here, instead
var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog)); // CAUTION: Using a whole other key
- var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(proof, nonce));
+ var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(proof, NONCE));
assertEquals(ProofOfPossessionVerifierException.ErrorCause.KEY_MISMATCH, exc.getErrorCause());
}
@@ -76,7 +99,7 @@ void verify_nonceMismatch_thenFailure() {
var proof = assertDoesNotThrow(() -> new ProofOfPossessionCreator(signer).create(nonce, ONE_DAY_LONG));
var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
- var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(proof, "foo"));
+ var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(proof, NONCE));
assertEquals(ProofOfPossessionVerifierException.ErrorCause.INVALID_NONCE, exc.getErrorCause());
}
@@ -87,7 +110,51 @@ void verify_unsupportedAlgorithm_thenFailure() {
var signedJWT = assertDoesNotThrow(() -> SignedJWT.parse(jwt));
var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
- var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(signedJWT, "foo"));
+ var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(signedJWT, NONCE));
assertEquals(ProofOfPossessionVerifierException.ErrorCause.UNSUPPORTED_ALGORITHM, exc.getErrorCause());
}
+
+ @Test
+ void verify_unparsableJWT_throwsProofOfPossessionVerifierException() throws ParseException {
+ var jwt = mock(SignedJWT.class);
+ var header = mock(JWSHeader.class);
+
+ when(jwt.getHeader()).thenReturn(header);
+ when(header.getAlgorithm()).thenReturn(JWSAlgorithm.EdDSA);
+ when(jwt.getJWTClaimsSet()).thenThrow(new ParseException("mock exception", 1));
+
+ var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
+ var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(jwt, NONCE));
+ assertEquals(ProofOfPossessionVerifierException.ErrorCause.UNPARSABLE, exc.getErrorCause());
+ }
+
+ @Test
+ void verify_getNonceThrowsException_throwsProofOfPossessionVerifierException() throws ParseException {
+ var jwt = mock(SignedJWT.class);
+ var header = mock(JWSHeader.class);
+ var claims = mock(JWTClaimsSet.class);
+
+ when(jwt.getHeader()).thenReturn(header);
+ when(header.getAlgorithm()).thenReturn(JWSAlgorithm.EdDSA);
+ when(jwt.getJWTClaimsSet()).thenReturn(claims);
+ when(claims.getStringClaim("nonce")).thenThrow(new ParseException("mock exception", 1));
+
+ var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
+ var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(jwt, NONCE));
+ assertEquals(ProofOfPossessionVerifierException.ErrorCause.UNPARSABLE, exc.getErrorCause());
+ }
+
+ @Test
+ void verify_noClaimset_throwsProofOfPosessionVerifierException() throws ParseException {
+ var jwt = mock(SignedJWT.class);
+ var header = mock(JWSHeader.class);
+
+ when(jwt.getHeader()).thenReturn(header);
+ when(header.getAlgorithm()).thenReturn(JWSAlgorithm.EdDSA);
+ when(jwt.getJWTClaimsSet()).thenThrow(new ParseException("mock exception", 1));
+
+ var verifier = assertDoesNotThrow(() -> new ProofOfPossessionVerifier(didLog));
+ var exc = assertThrowsExactly(ProofOfPossessionVerifierException.class, () -> verifier.verify(jwt, NONCE));
+ assertEquals(ProofOfPossessionVerifierException.ErrorCause.UNPARSABLE, exc.getErrorCause());
+ }
}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/jcommander/AbstractKeyMaterialDidLogCommandTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/jcommander/AbstractKeyMaterialDidLogCommandTest.java
new file mode 100644
index 00000000..64759a12
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/jcommander/AbstractKeyMaterialDidLogCommandTest.java
@@ -0,0 +1,170 @@
+package ch.admin.bj.swiyu.didtoolbox.jcommander;
+
+import ch.admin.bj.swiyu.didtoolbox.JwkUtils;
+import ch.admin.bj.swiyu.didtoolbox.model.CryptographicAlgorithm;
+import com.google.gson.JsonParser;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class AbstractKeyMaterialDidLogCommandTest {
+ private final String jwk = """
+ {
+ "kty": "EC",
+ "crv": "P-256",
+ "x": "ZcDtTSv1dP94JR9zTqFSO4hRPPByCQ0ctYGZdHyeHws",
+ "y": "lOlpaJZbQDyJFRCBOEMQLzPeoG02pa3G5Ux5tIYMXHo"
+ }
+ """;
+
+ // Extends AbstractKeyMaterialDidLogCommand to test that class
+ private static class Command extends AbstractKeyMaterialDidLogCommand {}
+
+ @Test
+ void getAssertionMethods_noMethodsProvided_generateKeys(@TempDir Path tmpDir) {
+ var command = new Command();
+ assertDoesNotThrow(() -> {
+ var keys = command.getAssertionMethods(tmpDir);
+ assertEquals(1, keys.size());
+ var method = keys.stream().findFirst();
+ assertTrue(method.isPresent());
+ assertEquals("assert-key-01", method.get().getIdFragment());
+ });
+ assertEquals(2, tmpDir.toFile().listFiles().length);
+ }
+
+ @Test
+ void getAssertionMethods_typeP256_generateKeys(@TempDir Path tmpDir) {
+ var command = new Command();
+ command.cryptoAlgorithm = CryptographicAlgorithm.P256;
+
+ assertDoesNotThrow(() -> {
+ var keys = command.getAssertionMethods(tmpDir);
+ assertEquals(1, keys.size());
+ var method = keys.stream().findFirst();
+ assertTrue(method.isPresent());
+ assertEquals("assert-key-01", method.get().getIdFragment());
+ });
+ assertEquals(2, tmpDir.toFile().listFiles().length);
+
+ assertDoesNotThrow(() -> {
+ var jwk = JwkUtils.loadECPublicJWKasJSON(new File(tmpDir.toString(), "assert-key-01.pub"), "foo");
+ var jsonJwk = JsonParser.parseString(jwk).getAsJsonObject();
+ var crv = jsonJwk.get("crv");
+ assertEquals("P-256", crv.getAsString());
+ });
+ }
+
+ @Test
+ void getAssertionMethods_typeEd25519_generateKeys(@TempDir Path tmpDir) {
+ var command = new Command();
+ command.cryptoAlgorithm = CryptographicAlgorithm.ED25519;
+
+ assertDoesNotThrow(() -> {
+ var keys = command.getAssertionMethods(tmpDir);
+ assertEquals(1, keys.size());
+ var method = keys.stream().findFirst();
+ assertTrue(method.isPresent());
+ assertEquals("assert-key-01", method.get().getIdFragment());
+ });
+ assertEquals(2, tmpDir.toFile().listFiles().length);
+
+ assertDoesNotThrow(() -> {
+ var jwk = JwkUtils.loadECPublicJWKasJSON(new File(tmpDir.toString(), "assert-key-01.pub"), "foo");
+ var jsonJwk = JsonParser.parseString(jwk).getAsJsonObject();
+ var crv = jsonJwk.get("crv");
+ assertEquals("Ed25519", crv.getAsString());
+ });
+ }
+
+ @Test
+ void getAssertionMethods_withMethods_doesNotGenerateKeys(@TempDir Path tmpDir) {
+ var command = new Command();
+ command.assertionMethodKeys = Set.of(new VerificationMethodParameters("foo", jwk));
+ assertDoesNotThrow(() -> {
+ var keys = command.getAssertionMethods(tmpDir);
+ assertEquals(1, keys.size());
+ var method = keys.stream().findFirst();
+ assertTrue(method.isPresent());
+ assertEquals("foo", method.get().getIdFragment());
+ });
+ // directory should stay empty
+ assertEquals(0, tmpDir.toFile().listFiles().length);
+ }
+
+ @Test
+ void getAssertionMethods_withoutMethodsAndExistingPublicKeyFileNoOverwrite_throwsException(@TempDir Path tmpDir) throws IOException {
+ var publicFile = new File(tmpDir.toString(), "assert-key-01.pub");
+ publicFile.createNewFile();
+
+ var command = new Command();
+ assertThrowsExactly(IOException.class, () -> command.getAssertionMethods(tmpDir));
+ }
+
+ @Test
+ void getAssertionMethods_withoutMethodsAndExistingPrivateKeyFileNoOverwrite_throwsException(@TempDir Path tmpDir) throws IOException {
+ var privateFile = new File(tmpDir.toString(), "assert-key-01");
+ privateFile.createNewFile();
+
+ var command = new Command();
+ assertThrowsExactly(IOException.class, () -> command.getAssertionMethods(tmpDir));
+ }
+
+ @Test
+ void getAuthentications_noMethodsProvided_generateKeys(@TempDir Path tmpDir) {
+ var command = new Command();
+ assertDoesNotThrow(() -> {
+ var keys = command.getAuthentications(tmpDir);
+ assertEquals(1, keys.size());
+ var method = keys.stream().findFirst();
+ assertTrue(method.isPresent());
+ assertEquals("auth-key-01", method.get().getIdFragment());
+ });
+ assertEquals(2, tmpDir.toFile().listFiles().length);
+ }
+
+ @Test
+ void getAuthentications_withMethods_doesNotGenerateKeys(@TempDir Path tmpDir) {
+ var command = new Command();
+ command.authenticationKeys = Set.of(new VerificationMethodParameters("foo", jwk));
+ assertDoesNotThrow(() -> {
+ var keys = command.getAuthentications(tmpDir);
+ assertEquals(1, keys.size());
+ var method = keys.stream().findFirst();
+ assertTrue(method.isPresent());
+ assertEquals("foo", method.get().getIdFragment());
+ });
+ // directory should stay empty
+ assertEquals(0, tmpDir.toFile().listFiles().length);
+ }
+
+ @Test
+ void getAuthentications_withoutMethodsAndExistingPublicKeyFileNoOverwrite_throwsException(@TempDir Path tmpDir) throws IOException {
+ var publicFile = new File(tmpDir.toString(), "auth-key-01.pub");
+ publicFile.createNewFile();
+
+ var command = new Command();
+ assertThrowsExactly(IOException.class, () -> command.getAuthentications(tmpDir));
+ }
+
+ @Test
+ void getAuthentications_withoutMethodsAndExistingPrivateKeyFileNoOverwrite_throwsException(@TempDir Path tmpDir) throws IOException {
+ var privateFile = new File(tmpDir.toString(), "auth-key-01");
+ privateFile.createNewFile();
+
+ var command = new Command();
+ assertThrowsExactly(IOException.class, () -> command.getAuthentications(tmpDir));
+ }
+
+ @Test
+ void cryptoAlgorithm_perDefault_isP256() {
+ var command = new Command();
+ assertEquals(CryptographicAlgorithm.P256, command.cryptoAlgorithm);
+ }
+}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodKeyParametersValidatorTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodKeyParametersValidatorTest.java
index cf50197c..296993a7 100644
--- a/src/test/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodKeyParametersValidatorTest.java
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/jcommander/VerificationMethodKeyParametersValidatorTest.java
@@ -78,11 +78,11 @@ void testValidate() {
},
{
"no-comma-separator",
- "should supply a comma-separated list (in format key-name,public-key-file (EC P-256 public/verifying key in PEM format))",
+ "should supply a comma-separated list (in format key-name,public-key-file (P-256 or Ed25519 public/verifying key in PEM format))",
},
{
"my-assert-key-02,non-existing-file",
- "option must be a regular file containing EC P-256 public/verifying key in PEM format"
+ "option must be a regular file containing an P-256 or Ed25519 public/verifying key in PEM format"
},
};
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/CryptographicAlgorithmTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/CryptographicAlgorithmTest.java
new file mode 100644
index 00000000..e90c2d69
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/CryptographicAlgorithmTest.java
@@ -0,0 +1,14 @@
+package ch.admin.bj.swiyu.didtoolbox.model;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CryptographicAlgorithmTest {
+
+ @Test
+ void toString_returnsAlgorithmName() {
+ assertEquals("P-256", CryptographicAlgorithm.P256.toString());
+ assertEquals("Ed25519", CryptographicAlgorithm.ED25519.toString());
+ }
+}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/DidMethodEnumTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/DidMethodEnumTest.java
new file mode 100644
index 00000000..1dd2ba86
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/DidMethodEnumTest.java
@@ -0,0 +1,86 @@
+package ch.admin.bj.swiyu.didtoolbox.model;
+
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class DidMethodEnumTest {
+
+ @Test
+ void parse_null_returnsNull() {
+ var version = assertDoesNotThrow(() -> DidMethodEnum.parse(null));
+ assertEquals(null, version);
+ }
+
+ @Test
+ void parse_tdwMixedCase_returnsTdw() {
+ var tdwStrig = "dId:TDw:0.3";
+ var version = assertDoesNotThrow(() -> DidMethodEnum.parse(tdwStrig));
+ assertEquals(DidMethodEnum.TDW_0_3, version);
+ }
+
+ @Test
+ void parse_webvhMixedCase_returnsTdw() {
+ var webvhString = "DiD:wEBvH:1.0";
+ var version = assertDoesNotThrow(() -> DidMethodEnum.parse(webvhString));
+ assertEquals(DidMethodEnum.WEBVH_1_0, version);
+ }
+
+ @Test
+ void parse_tdwWithWrongVersion_returnsTdw() {
+ var tdwString = "DiD:tDw:1.0";
+ assertThrowsExactly(ParseException.class, () -> DidMethodEnum.parse(tdwString));
+ }
+
+ @Test
+ void parse_webvhWithWrongVersion_returnsTdw() {
+ var webvhString = "DiD:wEBvH:0.3";
+ assertThrowsExactly(ParseException.class, () -> DidMethodEnum.parse(webvhString));
+ }
+
+ @Test
+ void isTdw03() {
+ assertTrue(DidMethodEnum.TDW_0_3.isTdw03());
+ assertFalse(DidMethodEnum.WEBVH_1_0.isTdw03());
+ }
+
+ @Test
+ void isWebv10() {
+ assertFalse(DidMethodEnum.TDW_0_3.isWebVh10());
+ assertTrue(DidMethodEnum.WEBVH_1_0.isWebVh10());
+ }
+
+ @Test
+ void detectDidMethod_withValidTdwLog_returnsTdw() {
+ var tdw = """
+ ["1-QmRVQ8EFiYfGqLXTpHSYMYXMcpFZwsy58gBeFYBEG3RPgj","2026-07-27T05:13:16Z",{"method":"did:tdw:0.3","scid":"QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC","updateKeys":["z6MkffRFEaq5wypbXTNK7AvmhvTWf4XiKVLomouvkpjuRPmP"],"portable":false},{"value":{"id":"did:tdw:QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC:example.com","authentication":["did:tdw:QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC:example.com#auth-key-01"],"assertionMethod":["did:tdw:QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC:example.com#assert-key-01"],"verificationMethod":[{"id":"did:tdw:QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC:example.com#auth-key-01","controller":"did:tdw:QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"EC","crv":"P-256","kid":"auth-key-01","x":"5mEj0G8RrCIK6Y-LFN0XAwEpRwhvyqwuqZ-4yQp6p4U","y":"q5-z3xdICaa7hTAfc-0HTiyR-5XklJTsjfcKWG9tGaw"}},{"id":"did:tdw:QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC:example.com#assert-key-01","controller":"did:tdw:QmY8Qa5YJynh7syyaUuBYSBJX18DjuYZ2BKsYBXoAv2VeC:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"EC","crv":"P-256","kid":"assert-key-01","x":"bwUStKHLIRy3RN1lyqgOdgTXO8h80KfcbGIZdn0wzEY","y":"JJG7jrkfY8PpW_yjHMJoB8GbuXpZWdPGX06vGAJlfOY"}}]}},[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","created":"2026-07-27T05:13:16Z","verificationMethod":"did:key:z6MkffRFEaq5wypbXTNK7AvmhvTWf4XiKVLomouvkpjuRPmP#z6MkffRFEaq5wypbXTNK7AvmhvTWf4XiKVLomouvkpjuRPmP","proofPurpose":"authentication","challenge":"1-QmRVQ8EFiYfGqLXTpHSYMYXMcpFZwsy58gBeFYBEG3RPgj","proofValue":"z5SjoNbsuT8z7WTvhVFWtLA8HNiteaQVsViYktcQ9EBtBaXEzqpbSCUSnqBw8io7MmLJMYy2Y3L9CAw7FySzWGoLs"}]]
+ """;
+ var version = assertDoesNotThrow(() -> DidMethodEnum.detectDidMethod(tdw));
+ assertEquals(DidMethodEnum.TDW_0_3, version);
+ }
+
+ @Test
+ void detectDidMethod_withValidWebvhLog_returnsWebvh() {
+ var webvh = """
+ {"versionId":"1-QmRYUsgbt7VLoNNWoG2KNAjTHgiRVXGMTJZ2arPAp54HZv","versionTime":"2026-07-27T05:11:17Z","parameters":{"method":"did:webvh:1.0","scid":"QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW","updateKeys":["z6MkhcZ1SvznbP5SdGqDXFJeZWtMebj9sFvk7VdLVBwBs57Z"],"portable":false},"state":{"id":"did:webvh:QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW:example.com","profile_version":"swiss-profile-anchor:1.0.0","authentication":["did:webvh:QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW:example.com#auth-key-01"],"assertionMethod":["did:webvh:QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW:example.com#assert-key-01"],"verificationMethod":[{"id":"did:webvh:QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW:example.com#auth-key-01","controller":"did:webvh:QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"OKP","crv":"Ed25519","x":"pKBaly1Q4Ef6ZQDLmMHYYM40JvdvsBSEmUrqD6AxUeE","kid":"auth-key-01"}},{"id":"did:webvh:QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW:example.com#assert-key-01","controller":"did:webvh:QmNZxwVtNp68iTXdZUwjMMqyPS7Xj5JTZpr424whqkLXyW:example.com","type":"JsonWebKey2020","publicKeyJwk":{"kty":"OKP","crv":"Ed25519","x":"AAuX9zdzGa2lm8NgLGpDm0iwDEfhjf3t7yMGhrJYkEQ","kid":"assert-key-01"}}]},"proof":[{"type":"DataIntegrityProof","cryptosuite":"eddsa-jcs-2022","created":"2026-07-27T05:11:17Z","verificationMethod":"did:key:z6MkhcZ1SvznbP5SdGqDXFJeZWtMebj9sFvk7VdLVBwBs57Z#z6MkhcZ1SvznbP5SdGqDXFJeZWtMebj9sFvk7VdLVBwBs57Z","proofPurpose":"assertionMethod","proofValue":"z26ATsdLQXp2kBSCEPwSyasGChdqUJJ6gaHmQbzrrXSSjxoauL5SxqgKwNpa51WLQ1GwbgG2k3nccbbDtpgi5AsxA"}]}
+ """;
+ var version = assertDoesNotThrow(() -> DidMethodEnum.detectDidMethod(webvh));
+ assertEquals(DidMethodEnum.WEBVH_1_0, version);
+ }
+
+ @Test
+ void detectDidMethod_nonDidLogJson_throws() {
+ var json = """
+ {"foo": "bar", "numbers: [1,2,3,4,5]}
+ """;
+ assertThrowsExactly(DidLogMetaPeekerException.class, () -> DidMethodEnum.detectDidMethod(json));
+ }
+
+ @Test
+ void detectDidMethod_ofNull_throwsNullPointerException() {
+ String didLog = null;
+ assertThrowsExactly(NullPointerException.class,() -> DidMethodEnum.detectDidMethod(didLog));
+ }
+}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/ProfileVersionTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/ProfileVersionTest.java
new file mode 100644
index 00000000..49f6b6b7
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/ProfileVersionTest.java
@@ -0,0 +1,19 @@
+package ch.admin.bj.swiyu.didtoolbox.model;
+
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ProfileVersionTest {
+
+ @Test
+ void toString_returnsFormattedProfileVersion() {
+ assertEquals("swiss-profile-anchor:1.0.0", ProfileVersion.SWISS_PROFILE_ANCHOR_1_0_0.toString());
+ }
+
+ @Test
+ void getLatest_returnsProfileAnchor1_0_0() {
+ assertEquals(ProfileVersion.SWISS_PROFILE_ANCHOR_1_0_0, ProfileVersion.getLatest());
+ }
+}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMaterialTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMaterialTest.java
new file mode 100644
index 00000000..47ae6061
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMaterialTest.java
@@ -0,0 +1,109 @@
+package ch.admin.bj.swiyu.didtoolbox.model;
+
+import com.google.gson.JsonParser;
+import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPublicKey;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class VerificationMaterialTest {
+
+ private void assertKid(String expectedKid, VerificationMaterial material) {
+ var jwk = material.getPublicKeyJwk();
+ var json = JsonParser.parseString(jwk).getAsJsonObject();
+ var kid = json.get("kid");
+ assertNotNull(kid);
+ assertTrue(kid.isJsonPrimitive());
+ assertEquals(expectedKid, kid.getAsString());
+ }
+
+ @Test
+ void of_validEcPublicKey_returnsVerificationMaterial() throws NoSuchAlgorithmException {
+ KeyPairGenerator keyPairGenerator;
+ keyPairGenerator = KeyPairGenerator.getInstance("EC", BouncyCastleProviderSingleton.getInstance());
+ keyPairGenerator.initialize(256);
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+ var verificationMaterial = VerificationMaterial.of("example_kid",(ECPublicKey) keyPair.getPublic());
+ assertKid("example_kid", verificationMaterial);
+
+ }
+
+ @Test
+ void of_pathToP256PemFile_returnsVerificationMaterial() {
+ var path = Path.of("src/test/data/assert-key-01.pub");
+ assertDoesNotThrow(() -> {
+ var verificationMaterial = VerificationMaterial.of("example_kid", path);
+ assertKid("example_kid", verificationMaterial);
+ });
+ }
+
+ @Test
+ void of_pathToEd25519PemFile_returnsVerificationMaterial() {
+ var path = Path.of("src/test/data/public.pem");
+ assertDoesNotThrow(() -> {
+ var verificationMaterial = VerificationMaterial.of("example_kid", path);
+ assertKid("example_kid", verificationMaterial);
+ });
+ }
+
+ @Test
+ void of_pathToUnsupportedPemFile_throwsIllegalArgumentException() {
+ var path = Path.of("src/test/data/rsa");
+ assertThrowsExactly(IllegalArgumentException.class, () -> VerificationMaterial.of("example_kid", path));
+ }
+
+ @Test
+ void of_pathToMissingFile_throwsError() {
+ var path = Path.of("thisFileDoesNotExist.pem");
+ assertThrowsExactly(NoSuchFileException.class, () -> VerificationMaterial.of("example_kid", path));
+ }
+
+ @Test
+ void of_pathToWrongFile_throwsError() {
+ var path = Path.of("README.md");
+ assertThrowsExactly(IllegalArgumentException.class, () -> VerificationMaterial.of("example_kid", path));
+ }
+
+ @Test
+ void of_ecP256PemString_returnsVerificationMaterial() {
+ String ecP256Pem = """
+ -----BEGIN PUBLIC KEY-----
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwdET0dp6vq59s1yyVh/XXyIPPU9C
+ o7PlcTPMRRXx85Z5OEL3416036hcDlZTQOfR553t+Ae2xezYTeZTzakD2Q==
+ -----END PUBLIC KEY-----
+ """;
+ assertDoesNotThrow(() -> {
+ var verificationMaterial = VerificationMaterial.of("example_kid", ecP256Pem);
+ assertKid("example_kid", verificationMaterial);
+ });
+ }
+
+ @Test
+ void of_ed25519PemString_returnsVerificationMaterial() {
+ String ed25519 = """
+ -----BEGIN PUBLIC KEY-----
+ MCowBQYDK2VwAyEA8ETLwQBKgk9fM2V0tQV5AdjrMvetLrgj5C+FOmYGTJg=
+ -----END PUBLIC KEY-----
+ """;
+ assertDoesNotThrow(() -> {
+ var verificationMaterial = VerificationMaterial.of("example_kid", ed25519);
+ assertKid("example_kid", verificationMaterial);
+ });
+ }
+
+ @Test
+ void of_invalidPemString_throwsError() {
+ String invalidPem = """
+ Not a Pem
+ """;
+ assertThrowsExactly(IllegalArgumentException.class, () -> VerificationMaterial.of("example_kid", invalidPem));
+ }
+}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMethodTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMethodTest.java
new file mode 100644
index 00000000..b4f07ae1
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/model/VerificationMethodTest.java
@@ -0,0 +1,105 @@
+package ch.admin.bj.swiyu.didtoolbox.model;
+
+import ch.admin.eid.did_sidekicks.Ed25519SigningKey;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+
+import java.io.*;
+import java.nio.file.Path;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPublicKey;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class VerificationMethodTest {
+
+ @Test
+ void verificationMethodOfJWK_withValidEcP256_returnVerificationMethod() throws VerificationMethodException {
+ var jwk = """
+ {
+ "kty": "EC",
+ "crv": "P-256",
+ "x": "WqLccrJ0NOQwVgFLP4cHCtEfR2M_SNguTsx9US5Ui7o",
+ "y": "nhBUhaovZ6aw2tFeT25b1NFE96wYpY4z6WO5etAHfTw",
+ "kid": "assert-key-01"
+ }
+ """;
+ var method = VerificationMethod.of("fragment", "JsonWebKey2020", jwk);
+ assertEquals("JsonWebKey2020", method.getType());
+ assertEquals("fragment", method.getIdFragment());
+ method.getVerificationMaterial().getPublicKeyJwk();
+ }
+
+ @Test
+ void verificationMethodOfJWK_withValidEdDSA25519_returnsVerificationMethod() throws VerificationMethodException, JOSEException {
+ var jwk = Ed25519SigningKey.Companion.generate().getVerifyingKey().toJwk();
+ var method = VerificationMethod.of("fragment", "JsonWebKey2020", jwk);
+ assertEquals("fragment", method.getIdFragment());
+ method.getVerificationMaterial().getPublicKeyJwk();
+ }
+
+ @Test
+ void verificationMethodOfJWK_withInvalidJWK_throwsError() {
+ // empty json
+ var emptyJwk = "{}";
+ assertThrowsExactly(VerificationMethodException.class, () -> VerificationMethod.of("fragment", emptyJwk));
+
+ // jwk with missing fields
+ var incompleteJwk = "{\"kty\":\"EC\"}";
+ assertThrowsExactly(VerificationMethodException.class, () -> VerificationMethod.of("fragment", incompleteJwk));
+ }
+
+ @Test
+ void verificationMethodOfEcPublicKey_withValidKey_returnsVerificationMethod() throws NoSuchAlgorithmException {
+ var keyPairGenerator = KeyPairGenerator.getInstance("EC", BouncyCastleProviderSingleton.getInstance());
+ keyPairGenerator.initialize(256);
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ var key = (ECPublicKey)keyPair.getPublic();
+ assertDoesNotThrow(() -> VerificationMethod.of("fragment", key));
+ }
+
+ @Test
+ void verificationMethodOfPath_withEcP256Pem_returnsVerificationMethod() {
+ var path = Path.of("src/test/data/assert-key-01.pub");
+ assertDoesNotThrow(() -> VerificationMethod.of("fragment", path));
+ }
+
+ @Test
+ void verificationMethodOfPath_withEdDSAPem_returnsVerificationMethod() {
+ var path = Path.of("src/test/data/public.pem");
+ assertDoesNotThrow(() -> VerificationMethod.of("fragment", path));
+ }
+
+ @Test
+ void verificationMethodOfPath_withNonPemfile_throwsError(@TempDir Path tempdir) throws FileNotFoundException {
+ var file = new File(tempdir.toString(), "test.txt");
+ try (var out = new PrintWriter(file)) {
+ out.write("Foo");
+ }
+
+ var ex = assertThrowsExactly(IllegalArgumentException.class, () -> VerificationMethod.of("fragment", file.toPath()));
+ assertTrue(ex.getMessage().contains("no PEM-encoded public key"));
+ }
+
+ @Test
+ void verificationMethodOfVerificationMaterial_withValidMaterial_returnsVerificationMethod() throws VerificationMethodException {
+ VerificationMaterial verificationMaterial = () -> "{ \"kty\": \"EC\", \"crv\": \"P-256\", \"x\": \"ZcDtTSv1dP94JR9zTqFSO4hRPPByCQ0ctYGZdHyeHws\", \"y\": \"lOlpaJZbQDyJFRCBOEMQLzPeoG02pa3G5Ux5tIYMXHo\", \"kid\": \"auth-key-01\" }";
+ var verificationMethod = VerificationMethod.of(verificationMaterial);
+ assertEquals("auth-key-01", verificationMethod.getIdFragment());
+ }
+
+ @Test
+ void verificationMethodOfVerificationMaterial_withInvalidMaterial_throwsError() {
+ VerificationMaterial emptyJWK = () -> "{}";
+ assertThrowsExactly(VerificationMethodException.class, () -> VerificationMethod.of(emptyJWK));
+
+ VerificationMaterial jwKWithInvalidKid = () -> "{ \"kid\": [\"foo\"] }";
+ assertThrowsExactly(VerificationMethodException.class, () -> VerificationMethod.of(jwKWithInvalidKid));
+ }
+
+}
diff --git a/src/test/java/ch/admin/bj/swiyu/didtoolbox/vc_data_integrity/VcDataIntegrityCryptographicSuiteTest.java b/src/test/java/ch/admin/bj/swiyu/didtoolbox/vc_data_integrity/VcDataIntegrityCryptographicSuiteTest.java
new file mode 100644
index 00000000..a8a3b105
--- /dev/null
+++ b/src/test/java/ch/admin/bj/swiyu/didtoolbox/vc_data_integrity/VcDataIntegrityCryptographicSuiteTest.java
@@ -0,0 +1,40 @@
+package ch.admin.bj.swiyu.didtoolbox.vc_data_integrity;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.ZonedDateTime;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
+
+public class VcDataIntegrityCryptographicSuiteTest {
+
+ @Test
+ void verifyProof_defaultImplementation_throwsIllegalArgumentException() {
+ var cryptoSuite = new CryptographicSuite();
+ assertThrowsExactly(IllegalArgumentException.class, () -> cryptoSuite.verifyProof("", ""));
+ }
+
+ // Class that just implements the VcDataIntegrityCryptographicSuite interface to test the default implementations.
+ private class CryptographicSuite implements VcDataIntegrityCryptographicSuite {
+ @Override
+ public String addProof(String unsecuredDocument, String challenge, String proofPurpose, ZonedDateTime dateTime) throws VcDataIntegrityCryptographicSuiteException {
+ return "";
+ }
+
+ @Override
+ public String getVerificationKeyMultibase() {
+ return "";
+ }
+
+ @Override
+ public byte[] generateSignature(byte[] message) {
+ return new byte[0];
+ }
+
+ @Override
+ public boolean isKeyMultibaseInSet(Set multibaseEncodedKeys) {
+ return false;
+ }
+ }
+}