Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Java policy examples #5

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
val kotlin_version: String by project
val waltid_version: String = "0.5.0"
val waltid_version: String = "1.0.2408070002-SNAPSHOT"


plugins {
Expand All @@ -16,7 +16,7 @@ tasks.withType<Test>().configureEach {
repositories {
mavenLocal()
mavenCentral()
maven { url = uri("https://maven.waltid.dev/releases") }
maven { url = uri("https://maven.waltid.dev/snapshots") }

}

Expand Down
40 changes: 40 additions & 0 deletions src/main/java/waltid/CustomCredentialDataValidatorPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package waltid;

import id.walt.credentials.verification.JavaCredentialDataValidatorPolicy;
import java.util.Map;
import java.util.Objects;
import kotlinx.serialization.json.JsonObject;
import kotlinx.serialization.json.JsonPrimitive;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class CustomCredentialDataValidatorPolicy extends JavaCredentialDataValidatorPolicy {

@NotNull
@Override
public Object javaVerify(@NotNull JsonObject data, @Nullable Object args, @NotNull Map<String, ?> context) {
if (!data.containsKey("my_verification")) {
throw new IllegalArgumentException("Required attribute not found!");
}

String myVerificationContent = ((JsonPrimitive) Objects.requireNonNull(data.get("my_verification"))).getContent();

if (!myVerificationContent.equalsIgnoreCase("hello world")) {
throw new IllegalArgumentException("Greet the world!");
}

return myVerificationContent;
}

@NotNull
@Override
public String getName() {
return "java-custom-data-validator";
}

@NotNull
@Override
public String getDescription() {
return "This is a custom data validator for Java";
}
}
77 changes: 77 additions & 0 deletions src/main/java/waltid/CustomCredentialWrapperValidatorPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package waltid;

import id.walt.credentials.schemes.JwsSignatureScheme;
import id.walt.credentials.verification.HolderBindingException;
import id.walt.credentials.verification.JavaCredentialWrapperValidatorPolicy;
import id.walt.crypto.utils.JwsUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import kotlinx.serialization.json.JsonArray;
import kotlinx.serialization.json.JsonElement;
import kotlinx.serialization.json.JsonObject;
import kotlinx.serialization.json.JsonPrimitive;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class CustomCredentialWrapperValidatorPolicy extends JavaCredentialWrapperValidatorPolicy {
@NotNull
@Override
public String getName() {
return "java-custom-credential-wrapper-validator";
}

@NotNull
@Override
public String getDescription() {
return "This is a custom credential wrapper validator for Java";
}

@NotNull
@Override
public Object javaVerify(@NotNull JsonObject data, @Nullable Object args, @NotNull Map<String, ?> context) {
// Getting the 'presenterDid' from data
JsonElement issuerElement = data.get(JwsSignatureScheme.JwsOption.ISSUER);
if (!(issuerElement instanceof JsonPrimitive)) {
throw new IllegalArgumentException("Missing or invalid issuer in data");
}
String presenterDid = ((JsonPrimitive) issuerElement).getContent();

// Getting the 'vp' from data
JsonElement vpElement = data.get("vp");
if (!(vpElement instanceof JsonObject vp)) {
throw new IllegalArgumentException("No \"vp\" field in VP!");
}

// Getting the 'verifiableCredential' from 'vp'
JsonElement credentialsElement = vp.get("verifiableCredential");
if (!(credentialsElement instanceof JsonArray credentials)) {
throw new IllegalArgumentException("No \"verifiableCredential\" field in \"vp\"!");
}

// Processing the credentials to get 'credentialSubjects'
List<String> credentialSubjects = credentials.stream()
.map(it -> {
if (!(it instanceof JsonPrimitive primitive)) {
throw new IllegalArgumentException("Invalid credential in \"verifiableCredential\"!");
}
String content = primitive.getContent();
JwsUtils.JwsParts decodedJws = JwsUtils.INSTANCE.decodeJws(content, false, false);
JsonObject payload = decodedJws.getPayload();
JsonElement subElement = payload.get("sub");
if (!(subElement instanceof JsonPrimitive)) {
throw new IllegalArgumentException("Invalid 'sub' in payload!");
}
return ((JsonPrimitive) subElement).getContent().split("#")[0];
})
.collect(Collectors.toList());

// Returning the result based on 'credentialSubjects'
boolean allMatch = credentialSubjects.stream().allMatch(sub -> sub.equals(presenterDid));
if (allMatch) {
return presenterDid;
} else {
throw new HolderBindingException(presenterDid, credentialSubjects);
}
}
}
30 changes: 8 additions & 22 deletions src/main/java/waltid/CustomKeyExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import id.walt.crypto.keys.KeyMeta;
import id.walt.crypto.keys.KeyType;
import id.walt.crypto.keys.jwk.JWKKey;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
import kotlin.random.Random;
import kotlinx.serialization.json.Json;
import kotlinx.serialization.json.JsonElement;
Expand All @@ -13,11 +17,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;

public class CustomKeyExample extends JavaKey {

private String _xyz;
Expand Down Expand Up @@ -71,7 +70,8 @@ public Key javaGetPublicKey() {
return JWKKey.Companion.generateBlocking(getKeyType(), null);
}

public byte[] javaVerifyRaw(@NotNull byte[] signed, @Nullable byte[] detachedPlaintext) {
@Override
public byte @NotNull [] javaVerifyRaw(byte @NotNull [] signed, byte @Nullable [] detachedPlaintext) {
System.out.println("Verifying signed with custom key (example): " + Arrays.toString(signed));

assert detachedPlaintext != null;
Expand All @@ -83,18 +83,7 @@ public byte[] javaVerifyRaw(@NotNull byte[] signed, @Nullable byte[] detachedPla

}

@NotNull
@Override
public JsonElement javaVerifyJws() {
return null;
}

@NotNull
@Override
public byte[] javaVerifyRaw() {
return new byte[0];
}

@NotNull
public JsonElement javaVerifyJws(@Language(value = "json") @NotNull String signedJws) {
if (Random.Default.nextBoolean()) {
Expand All @@ -106,7 +95,7 @@ public JsonElement javaVerifyJws(@Language(value = "json") @NotNull String signe

@NotNull
@Override
public String javaSignJws(@NotNull byte[] plaintext, @NotNull Map<String, String> headers) {
public String javaSignJws(byte @NotNull [] plaintext, @NotNull Map<String, ? extends JsonElement> map) {
var base64 = Base64.getUrlEncoder();

String myHeaders = base64.encodeToString("{\"my-headers\": \"xyz\"}".getBytes(StandardCharsets.UTF_8));
Expand All @@ -116,9 +105,8 @@ public String javaSignJws(@NotNull byte[] plaintext, @NotNull Map<String, String
return myHeaders + "." + myPayload + "." + mySignature;
}

@NotNull
@Override
public byte[] javaSignRaw(@NotNull byte[] plaintext) {
public byte @NotNull [] javaSignRaw(byte @NotNull [] plaintext) {
System.out.println("Signing plaintext with custom key (stub implementation): " + Arrays.toString(plaintext));
return reverseArray(plaintext);
}
Expand Down Expand Up @@ -171,6 +159,4 @@ public KeyType javaGetKeyType() {
default -> throw new IllegalArgumentException("Unknown key type!");
};
}


}
38 changes: 25 additions & 13 deletions src/main/java/waltid/KeysExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class KeysExamples {
// demonstrating the Java (async) CompletableFuture API.
// Replace KeyType.Ed25519 with a different KeyType if desired.

public static void signBlocking() {
public static void signBlocking() throws Exception {
System.out.println("Generating key synchronous...");
JWKKey k = (JWKKey) JWKKey.Companion.generateBlocking(KeyType.Ed25519, null);
System.out.println("Sync generated key: " + k);
Expand All @@ -45,23 +45,35 @@ public static void signAsync() {
System.out.println("Async generated key: " + key);
System.out.println("Signing with key asynchronous...");

key.signRawAsync(plaintext).thenAccept(signed -> {
System.out.println("Signed asynchronous: " + Arrays.toString((byte[]) signed));

verifyAsync(key, (byte[]) signed, plaintext, "Test async verification");
});
try {
key.signRawAsync(plaintext).thenAccept(signed -> {
System.out.println("Signed asynchronous: " + Arrays.toString((byte[]) signed));

try {
verifyAsync(key, (byte[]) signed, plaintext, "Test async verification");
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}

public static void verifyAsync(Key key, byte[] signed, byte[] plaintext, String message) {
public static void verifyAsync(Key key, byte[] signed, byte[] plaintext, String message) throws Exception {
key.getPublicKeyAsync().thenAccept(publicKey -> {
publicKey.verifyRawAsync(signed, plaintext).thenAccept(result -> {
System.out.println("Verification result (" + message + "): " + result);
}).join();
try {
publicKey.verifyRawAsync(signed, plaintext).thenAccept(result -> {
System.out.println("Verification result (" + message + "): " + result);
}).join();
} catch (Exception e) {
throw new RuntimeException(e);
}
}).join();
}

public static String exportKey() {
public static String exportKey() throws Exception {
// Other KeyTypes:
var key2 = JWKKey.Companion.generateBlocking(KeyType.secp256r1, null);
System.out.println("Export key...");
Expand All @@ -76,7 +88,7 @@ public static void importKey(String jwk) throws ExecutionException, InterruptedE
System.out.println("Import result: " + keyImport);
}

public static void runKeyExample() throws ExecutionException, InterruptedException {
public static void runKeyExample() throws Exception {
KeysExamples.signAsync();
KeysExamples.signBlocking();

Expand All @@ -85,7 +97,7 @@ public static void runKeyExample() throws ExecutionException, InterruptedExcepti
}


public static void main(String[] args) throws ExecutionException, InterruptedException {
public static void main(String[] args) throws Exception {
runKeyExample();
}
}
2 changes: 1 addition & 1 deletion src/main/java/waltid/RunAll.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import static waltid.VcExamples.runVcExample;

public class RunAll {
public static void main(String[] args) throws ExecutionException, InterruptedException {
public static void main(String[] args) throws Exception {
runKeyExample();
runDidExample();
runVcExample();
Expand Down