From 3097b6bd28605ba0ed6474f5f08e79d3ca8dd125 Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Tue, 19 Mar 2024 18:56:20 +0100 Subject: [PATCH 01/15] Added vcdm 2.0 context --- .../vc/util/CachingDocumentLoader.java | 1 + .../resources/contexts/credentials-v2.jsonld | 322 ++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100644 inspector-vc/src/main/resources/contexts/credentials-v2.jsonld diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java index 6b5454a..eb37955 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/util/CachingDocumentLoader.java @@ -120,6 +120,7 @@ public class CachingDocumentLoader extends ConfigurableDocumentLoader { .put("https://w3id.org/security/suites/ed25519-2020/v1",Resources.getResource("contexts/security-suites-ed25519-2020-v1.jsonld")) .put("https://w3id.org/security/data-integrity/v1",Resources.getResource("contexts/data-integrity-v1.jsonld")) .put("https://www.w3.org/2018/credentials/v1", Resources.getResource("contexts/2018-credentials-v1.jsonld")) + .put("https://www.w3.org/ns/credentials/v2", Resources.getResource("contexts/credentials-v2.jsonld")) .put("https://w3id.org/security/v1", Resources.getResource("contexts/security-v1.jsonld")) .put("https://w3id.org/security/v2", Resources.getResource("contexts/security-v2.jsonld")) .put("https://w3id.org/security/v3", Resources.getResource("contexts/security-v3-unstable.jsonld")) diff --git a/inspector-vc/src/main/resources/contexts/credentials-v2.jsonld b/inspector-vc/src/main/resources/contexts/credentials-v2.jsonld new file mode 100644 index 0000000..94cd09f --- /dev/null +++ b/inspector-vc/src/main/resources/contexts/credentials-v2.jsonld @@ -0,0 +1,322 @@ +{ + "@context": { + "@protected": true, + "@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#", + + "id": "@id", + "type": "@type", + + "kid": { + "@id": "https://www.iana.org/assignments/jose#kid", + "@type": "@id" + }, + "iss": { + "@id": "https://www.iana.org/assignments/jose#iss", + "@type": "@id" + }, + "sub": { + "@id": "https://www.iana.org/assignments/jose#sub", + "@type": "@id" + }, + "jku": { + "@id": "https://www.iana.org/assignments/jose#jku", + "@type": "@id" + }, + "x5u": { + "@id": "https://www.iana.org/assignments/jose#x5u", + "@type": "@id" + }, + "aud": { + "@id": "https://www.iana.org/assignments/jwt#aud", + "@type": "@id" + }, + "exp": { + "@id": "https://www.iana.org/assignments/jwt#exp", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "nbf": { + "@id": "https://www.iana.org/assignments/jwt#nbf", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "iat": { + "@id": "https://www.iana.org/assignments/jwt#iat", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "cnf": { + "@id": "https://www.iana.org/assignments/jwt#cnf", + "@context": { + "@protected": true, + "kid": { + "@id": "https://www.iana.org/assignments/jwt#kid", + "@type": "@id" + }, + "jwk": { + "@id": "https://www.iana.org/assignments/jwt#jwk", + "@type": "@json" + } + } + }, + "_sd_alg": { + "@id": "https://www.iana.org/assignments/jwt#_sd_alg" + }, + "_sd": { + "@id": "https://www.iana.org/assignments/jwt#_sd" + }, + "...": { + "@id": "https://www.iana.org/assignments/jwt#..." + }, + + "digestSRI": { + "@id": "https://www.w3.org/2018/credentials#digestSRI", + "@type": "https://www.w3.org/2018/credentials#sriString" + }, + "digestMultibase": { + "@id": "https://w3id.org/security#digestMultibase", + "@type": "https://w3id.org/security#multibase" + }, + + "mediaType": { + "@id": "https://schema.org/encodingFormat" + }, + + "description": "https://schema.org/description", + "name": "https://schema.org/name", + + "EnvelopedVerifiableCredential": + "https://www.w3.org/2018/credentials#EnvelopedVerifiableCredential", + + "VerifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "credentialSchema": { + "@id": "https://www.w3.org/2018/credentials#credentialSchema", + "@type": "@id" + }, + "credentialStatus": { + "@id": "https://www.w3.org/2018/credentials#credentialStatus", + "@type": "@id" + }, + "credentialSubject": { + "@id": "https://www.w3.org/2018/credentials#credentialSubject", + "@type": "@id" + }, + "description": "https://schema.org/description", + "evidence": { + "@id": "https://www.w3.org/2018/credentials#evidence", + "@type": "@id" + }, + "validFrom": { + "@id": "https://www.w3.org/2018/credentials#validFrom", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "validUntil": { + "@id": "https://www.w3.org/2018/credentials#validUntil", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "issuer": { + "@id": "https://www.w3.org/2018/credentials#issuer", + "@type": "@id" + }, + "name": "https://schema.org/name", + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph" + }, + "refreshService": { + "@id": "https://www.w3.org/2018/credentials#refreshService", + "@type": "@id" + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id" + }, + "confidenceMethod": { + "@id": "https://www.w3.org/2018/credentials#confidenceMethod", + "@type": "@id" + }, + "relatedResource": { + "@id": "https://www.w3.org/2018/credentials#relatedResource", + "@type": "@id" + } + } + }, + + "VerifiablePresentation": { + "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "holder": { + "@id": "https://www.w3.org/2018/credentials#holder", + "@type": "@id" + }, + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph" + }, + "verifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#verifiableCredential", + "@type": "@id", + "@container": "@graph", + "@context": null + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id" + } + } + }, + + "JsonSchemaCredential": "https://www.w3.org/2018/credentials#JsonSchemaCredential", + + "JsonSchema": { + "@id": "https://www.w3.org/2018/credentials#JsonSchema", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "jsonSchema": { + "@id": "https://w3.org/2018/credentials#jsonSchema", + "@type": "@json" + } + } + }, + + "BitstringStatusListCredential": "https://www.w3.org/ns/credentials/status#BitstringStatusListCredential", + + "BitstringStatusList": { + "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusList", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "statusPurpose": + "https://www.w3.org/ns/credentials/status#statusPurpose", + "encodedList": { + "@id": "https://www.w3.org/ns/credentials/status#encodedList", + "@type": "https://w3id.org/security#multibase" + }, + "ttl": "https://www.w3.org/ns/credentials/status#ttl", + "statusReference": "https://www.w3.org/ns/credentials/status#statusReference", + "statusSize": "https://www.w3.org/ns/credentials/status#statusSize", + "statusMessage": { + "@id": "https://www.w3.org/ns/credentials/status#statusMessage", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "status": "https://www.w3.org/ns/credentials/status#status", + "message": "https://www.w3.org/ns/credentials/status#message" + } + } + } + }, + + "BitstringStatusListEntry": { + "@id": + "https://www.w3.org/ns/credentials/status#BitstringStatusListEntry", + "@context": { + "@protected": true, + + "id": "@id", + "type": "@type", + + "statusPurpose": + "https://www.w3.org/ns/credentials/status#statusPurpose", + "statusListIndex": + "https://www.w3.org/ns/credentials/status#statusListIndex", + "statusListCredential": { + "@id": + "https://www.w3.org/ns/credentials/status#statusListCredential", + "@type": "@id" + } + } + }, + + "DataIntegrityProof": { + "@id": "https://w3id.org/security#DataIntegrityProof", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "challenge": "https://w3id.org/security#challenge", + "created": { + "@id": "http://purl.org/dc/terms/created", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "domain": "https://w3id.org/security#domain", + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "nonce": "https://w3id.org/security#nonce", + "previousProof": { + "@id": "https://w3id.org/security#previousProof", + "@type": "@id" + }, + "proofPurpose": { + "@id": "https://w3id.org/security#proofPurpose", + "@type": "@vocab", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "assertionMethod": { + "@id": "https://w3id.org/security#assertionMethod", + "@type": "@id", + "@container": "@set" + }, + "authentication": { + "@id": "https://w3id.org/security#authenticationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityInvocation": { + "@id": "https://w3id.org/security#capabilityInvocationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityDelegation": { + "@id": "https://w3id.org/security#capabilityDelegationMethod", + "@type": "@id", + "@container": "@set" + }, + "keyAgreement": { + "@id": "https://w3id.org/security#keyAgreementMethod", + "@type": "@id", + "@container": "@set" + } + } + }, + "cryptosuite": { + "@id": "https://w3id.org/security#cryptosuite", + "@type": "https://w3id.org/security#cryptosuiteString" + }, + "proofValue": { + "@id": "https://w3id.org/security#proofValue", + "@type": "https://w3id.org/security#multibase" + }, + "verificationMethod": { + "@id": "https://w3id.org/security#verificationMethod", + "@type": "@id" + } + } + } + } + } \ No newline at end of file From 169f5a608d72838c114e1c24827f180abc9e088f Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Wed, 20 Mar 2024 14:28:05 +0100 Subject: [PATCH 02/15] Updated public core version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a8de9f4..44208b7 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 11 2.17.2 false - 1.0.4 + 1.0.6 From f600e5abeb44d6c40b32c19ab984e1aa928c54ef Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 17:23:44 +0100 Subject: [PATCH 03/15] Defined dates fields depending on vcdm version --- .../inspect/vc/VerifiableCredential.java | 321 ++++++++++-------- 1 file changed, 183 insertions(+), 138 deletions(-) diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java index af1833b..3886f84 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java @@ -5,162 +5,207 @@ import static org.oneedtech.inspect.vc.VerifiableCredential.Type.ClrCredential; import static org.oneedtech.inspect.vc.VerifiableCredential.Type.EndorsementCredential; import static org.oneedtech.inspect.vc.VerifiableCredential.Type.VerifiablePresentation; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; - import org.oneedtech.inspect.schema.Catalog; import org.oneedtech.inspect.schema.SchemaKey; import org.oneedtech.inspect.util.resource.MimeType; import org.oneedtech.inspect.util.resource.Resource; import org.oneedtech.inspect.vc.util.JsonNodeUtil; -import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.base.MoreObjects; -import com.google.common.collect.ImmutableMap; - /** - * A wrapper object for a verifiable credential. This contains e.g. the origin resource - * and the extracted JSON data plus any other stuff Probes need. + * A wrapper object for a verifiable credential. This contains e.g. the origin resource and the + * extracted JSON data plus any other stuff Probes need. + * * @author mgylling */ -public class VerifiableCredential extends Credential { - final VerifiableCredential.Type credentialType; +public class VerifiableCredential extends Credential { + final VerifiableCredential.Type credentialType; - protected VerifiableCredential(Resource resource, JsonNode data, String jwt, Map schemas, String issuedOnPropertyName, String expiresAtPropertyName) { - super(ID, resource, data, jwt, schemas, issuedOnPropertyName, expiresAtPropertyName); + protected VerifiableCredential( + Resource resource, + JsonNode data, + String jwt, + Map schemas, + String issuedOnPropertyName, + String expiresAtPropertyName) { + super(ID, resource, data, jwt, schemas, issuedOnPropertyName, expiresAtPropertyName); - JsonNode typeNode = jsonData.get("type"); - this.credentialType = VerifiableCredential.Type.valueOf(typeNode); + JsonNode typeNode = jsonData.get("type"); + this.credentialType = VerifiableCredential.Type.valueOf(typeNode); + } + + public CredentialEnum getCredentialType() { + return credentialType; + } + + public ProofType getProofType() { + return jwt == null ? ProofType.EMBEDDED : ProofType.EXTERNAL; + } + + private static final Map schemas = + new ImmutableMap.Builder() + .put(AchievementCredential, Catalog.OB_30_ANY_ACHIEVEMENTCREDENTIAL_JSON) + .put(ClrCredential, Catalog.CLR_20_ANY_CLRCREDENTIAL_JSON) + .put(VerifiablePresentation, Catalog.CLR_20_ANY_CLRCREDENTIAL_JSON) + .put(EndorsementCredential, Catalog.OB_30_ANY_ENDORSEMENTCREDENTIAL_JSON) + .build(); + + private static final Map, List> contextMap = + new ImmutableMap.Builder, List>() + .put( + Set.of(Type.OpenBadgeCredential, AchievementCredential, EndorsementCredential), + List.of( + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json")) + .put( + Set.of(ClrCredential), + List.of( + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1.json", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json")) + .build(); + + private static final Map> contextAliasesMap = + new ImmutableMap.Builder>() + .put( + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + List.of( + "https://purl.imsglobal.org/spec/ob/v3p0/context/ob_v3p0.jsonld", + "https://purl.imsglobal.org/spec/ob/v3p0/context.json")) + .put( + "https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1.json", + List.of("https://purl.imsglobal.org/spec/clr/v2p0/context.json")) + .put( + "https://www.w3.org/ns/credentials/v2", + List.of("https://www.w3.org/2018/credentials/v1")) + .build(); + + private static final Map> contextVersioningPatternMap = + new ImmutableMap.Builder>() + .put( + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + List.of( + "https:\\/\\/purl\\.imsglobal\\.org\\/spec\\/ob\\/v3p0\\/context(-\\d+\\.\\d+\\.\\d+)*\\.json")) + .put( + "https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1.json", + List.of( + "https:\\/\\/purl\\.imsglobal\\.org\\/spec\\/clr\\/v2p0\\/context(-\\d+\\.\\d+\\.\\d+)*\\.json")) + .build(); + + public enum Type implements CredentialEnum { + AchievementCredential(Collections.emptyList()), + OpenBadgeCredential( + List.of( + "OpenBadgeCredential", + "AchievementCredential")), // treated as an alias of AchievementCredential + ClrCredential(List.of("ClrCredential")), + EndorsementCredential(List.of("EndorsementCredential")), + VerifiablePresentation(Collections.emptyList()), + VerifiableCredential( + List.of("VerifiableCredential")), // this is an underspecifier in our context + Unknown(Collections.emptyList()); + + private final List allowedTypeValues; + + Type(List allowedTypeValues) { + this.allowedTypeValues = allowedTypeValues; } - public CredentialEnum getCredentialType() { - return credentialType; - } - - public ProofType getProofType() { - return jwt == null ? ProofType.EMBEDDED : ProofType.EXTERNAL; - } - - private static final Map schemas = new ImmutableMap.Builder() - .put(AchievementCredential, Catalog.OB_30_ACHIEVEMENTCREDENTIAL_JSON) - .put(ClrCredential, Catalog.CLR_20_CLRCREDENTIAL_JSON) - .put(VerifiablePresentation, Catalog.CLR_20_CLRCREDENTIAL_JSON) - .put(EndorsementCredential, Catalog.OB_30_ENDORSEMENTCREDENTIAL_JSON) - .build(); - - private static final Map, List> contextMap = new ImmutableMap.Builder, List>() - .put(Set.of(Type.OpenBadgeCredential, AchievementCredential, EndorsementCredential), - List.of("https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json")) - .put(Set.of(ClrCredential), - List.of("https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/clr/v2p0/context.json", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json")) - - .build(); - - private static final Map> contextAliasesMap = new ImmutableMap.Builder>() - .put("https://purl.imsglobal.org/spec/ob/v3p0/context.json", - List.of("https://purl.imsglobal.org/spec/ob/v3p0/context/ob_v3p0.jsonld")) - .build(); - - private static final Map> contextVersioningPatternMap = new ImmutableMap.Builder>() - .put("https://purl.imsglobal.org/spec/ob/v3p0/context.json", - List.of("https:\\/\\/purl\\.imsglobal\\.org\\/spec\\/ob\\/v3p0\\/context(-\\d+\\.\\d+\\.\\d+)*\\.json")) - .put("https://purl.imsglobal.org/spec/clr/v2p0/context.json", - List.of("https:\\/\\/purl\\.imsglobal\\.org\\/spec\\/clr\\/v2p0\\/context(-\\d+\\.\\d+\\.\\d+)*\\.json")) - .build(); - - public enum Type implements CredentialEnum { - AchievementCredential(Collections.emptyList()), - OpenBadgeCredential(List.of("OpenBadgeCredential", "AchievementCredential")), //treated as an alias of AchievementCredential - ClrCredential(List.of("ClrCredential")), - EndorsementCredential(List.of("EndorsementCredential")), - VerifiablePresentation(Collections.emptyList()), - VerifiableCredential(List.of("VerifiableCredential")), //this is an underspecifier in our context - Unknown(Collections.emptyList()); - - private final List allowedTypeValues; - - Type(List allowedTypeValues) { - this.allowedTypeValues = allowedTypeValues; - } - - public static VerifiableCredential.Type valueOf (JsonNode typeNode) { - if(typeNode != null) { - List values = JsonNodeUtil.asStringList(typeNode); - for (String value : values) { - if(value.equals("AchievementCredential") || value.equals("OpenBadgeCredential")) { - return AchievementCredential; - } else if(value.equals("ClrCredential")) { - return ClrCredential; - } else if(value.equals("VerifiablePresentation")) { - return VerifiablePresentation; - } else if(value.equals("EndorsementCredential")) { - return EndorsementCredential; - } - } - } - return Unknown; - } - - @Override - public List getRequiredTypeValues() { - return List.of("VerifiableCredential"); - } - - @Override - public List getAllowedTypeValues() { - return allowedTypeValues; - } - - @Override - public boolean isAllowedTypeValuesRequired() { - return true; - } - @Override - public List getContextUris() { - return contextMap.get(contextMap.keySet() - .stream() - .filter(s->s.contains(this)) - .findFirst() - .orElseThrow(()-> new IllegalArgumentException(this.name() + " not recognized"))); - } - @Override - public Map> getContextAliases() { - return contextAliasesMap; - } - @Override - public Map> getContextVersionPatterns() { - return contextVersioningPatternMap; - } - } - - public enum ProofType { - EXTERNAL, - EMBEDDED - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("super", super.toString()) - .add("credentialType", credentialType) - .toString(); - } - - public static class Builder extends Credential.Builder { - @Override - public VerifiableCredential build() { - return new VerifiableCredential(getResource(), getJsonData(), getJwt(), schemas, ISSUED_ON_PROPERTY_NAME, EXPIRES_AT_PROPERTY_NAME); + public static VerifiableCredential.Type valueOf(JsonNode typeNode) { + if (typeNode != null) { + List values = JsonNodeUtil.asStringList(typeNode); + for (String value : values) { + if (value.equals("AchievementCredential") || value.equals("OpenBadgeCredential")) { + return AchievementCredential; + } else if (value.equals("ClrCredential")) { + return ClrCredential; + } else if (value.equals("VerifiablePresentation")) { + return VerifiablePresentation; + } else if (value.equals("EndorsementCredential")) { + return EndorsementCredential; + } } + } + return Unknown; } - public static final String ID = VerifiableCredential.class.getCanonicalName(); - private static final String ISSUED_ON_PROPERTY_NAME = "issuanceDate"; - private static final String EXPIRES_AT_PROPERTY_NAME = "expirationDate"; - public static final String JWT_NODE_NAME = "vc"; - public static final List REFRESH_SERVICE_MIME_TYPES = List.of(MimeType.JSON, MimeType.JSON_LD, MimeType.TEXT_PLAIN); + @Override + public List getRequiredTypeValues() { + return List.of("VerifiableCredential"); + } + + @Override + public List getAllowedTypeValues() { + return allowedTypeValues; + } + + @Override + public boolean isAllowedTypeValuesRequired() { + return true; + } + + @Override + public List getContextUris() { + return contextMap.get( + contextMap.keySet().stream() + .filter(s -> s.contains(this)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(this.name() + " not recognized"))); + } + + @Override + public Map> getContextAliases() { + return contextAliasesMap; + } + + @Override + public Map> getContextVersionPatterns() { + return contextVersioningPatternMap; + } + } + + public enum ProofType { + EXTERNAL, + EMBEDDED + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("super", super.toString()) + .add("credentialType", credentialType) + .toString(); + } + + public static class Builder extends Credential.Builder { + @Override + public VerifiableCredential build() { + boolean is2p0VC = JsonNodeUtil.asNodeList(getJsonData().get("@context")) + .stream() + .anyMatch(node -> node.isTextual() && node.asText().equals("https://www.w3.org/ns/credentials/v2")); + + return new VerifiableCredential( + getResource(), + getJsonData(), + getJwt(), + schemas, + is2p0VC ? ISSUED_ON_PROPERTY_NAME_V20 : ISSUED_ON_PROPERTY_NAME_V11, + is2p0VC ? EXPIRES_AT_PROPERTY_NAME_V20 : EXPIRES_AT_PROPERTY_NAME_V11); + } + } + + public static final String ID = VerifiableCredential.class.getCanonicalName(); + private static final String ISSUED_ON_PROPERTY_NAME_V11 = "issuanceDate"; + private static final String ISSUED_ON_PROPERTY_NAME_V20 = "validFrom"; + private static final String EXPIRES_AT_PROPERTY_NAME_V11 = "expirationDate"; + private static final String EXPIRES_AT_PROPERTY_NAME_V20 = "validUntil"; + public static final String JWT_NODE_NAME = "vc"; + public static final List REFRESH_SERVICE_MIME_TYPES = + List.of(MimeType.JSON, MimeType.JSON_LD, MimeType.TEXT_PLAIN); } From 12e7221e8c8b6fc0cce74c85ff30212ee1ce445c Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 17:23:59 +0100 Subject: [PATCH 04/15] Raise a warning when the context is not the latest one --- .../oneedtech/inspect/vc/probe/ContextPropertyProbe.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ContextPropertyProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ContextPropertyProbe.java index 865daca..b41e31d 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ContextPropertyProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ContextPropertyProbe.java @@ -2,6 +2,7 @@ package org.oneedtech.inspect.vc.probe; import static org.oneedtech.inspect.util.code.Defensives.checkNotNull; +import java.util.ArrayList; import java.util.List; import org.oneedtech.inspect.core.probe.RunContext; @@ -35,12 +36,20 @@ public class ContextPropertyProbe extends StringValuePropertyProbe { checkNotNull(contextUris); int pos = 0; + List warnings = new ArrayList<>(); for (String uri : contextUris) { if ((nodeValues.size() < pos + 1) || !contains(uri, nodeValues.get(pos))) { return error("missing required @context uri " + uri + " at position " + (pos + 1), ctx); } + if (!nodeValues.get(pos).equals(uri)) { + warnings.add(warning("expected @context uri " + uri + " at position " + (pos + 1) + ", gotten " + nodeValues.get(pos).toString() + " instead", ctx)); + } + pos++; } + if (!warnings.isEmpty()) { + return new ReportItems(warnings); + } } return success(ctx); From c97c455d09aad52133707a57316cca71a4494bbc Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 17:24:50 +0100 Subject: [PATCH 05/15] better comments --- .../org/oneedtech/inspect/vc/probe/ExpirationProbe.java | 6 +++--- .../java/org/oneedtech/inspect/vc/probe/IssuanceProbe.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java index c616015..ac2825f 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/ExpirationProbe.java @@ -22,7 +22,7 @@ public class ExpirationProbe extends Probe { @Override public ReportItems run(Credential crd, RunContext ctx) throws Exception { /* - * If the AchievementCredential or EndorsementCredential has an “expirationDate” property + * If the AchievementCredential or EndorsementCredential has an “expirationDate” or "validUntil" property * and the expiration date is prior to the current date, the credential has expired. */ JsonNode node = crd.getJson().get(crd.getExpiresAtPropertyName()); @@ -30,10 +30,10 @@ public class ExpirationProbe extends Probe { try { ZonedDateTime expirationDate = ZonedDateTime.parse(node.textValue()); if (ZonedDateTime.now().isAfter(expirationDate)) { - return fatal("The credential has expired (expiration date was " + node.asText() + ").", ctx); + return fatal("The credential has expired (expiration date or validUntil was " + node.asText() + ").", ctx); } } catch (Exception e) { - return exception("Error while checking expirationDate: " + e.getMessage(), ctx.getResource()); + return exception("Error while checking expirationDate or validUntil: " + e.getMessage(), ctx.getResource()); } } return success(ctx); diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/IssuanceProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/IssuanceProbe.java index 2328199..b1c213f 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/IssuanceProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/IssuanceProbe.java @@ -22,7 +22,7 @@ public class IssuanceProbe extends Probe { @Override public ReportItems run(Credential crd, RunContext ctx) throws Exception { /* - * If the AchievementCredential or EndorsementCredential “issuanceDate” + * If the AchievementCredential or EndorsementCredential “issuanceDate” or "validFrom" * property after the current date, the credential is not yet valid. */ JsonNode node = crd.getJson().get(crd.getIssuedOnPropertyName()); @@ -30,10 +30,10 @@ public class IssuanceProbe extends Probe { try { ZonedDateTime issuanceDate = ZonedDateTime.parse(node.textValue()); if (issuanceDate.isAfter(ZonedDateTime.now())) { - return fatal("The credential is not yet issued (issuance date is " + node.asText() + ").", ctx); + return fatal("The credential is not yet issued or valid (issuance date or validFrom is " + node.asText() + ").", ctx); } } catch (Exception e) { - return exception("Error while checking issuanceDate: " + e.getMessage(), ctx.getResource()); + return exception("Error while checking issuanceDate or ValidFrom: " + e.getMessage(), ctx.getResource()); } } return success(ctx); From be7e496d47c3f743d57d4d806c88f919234f90d1 Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 17:25:15 +0100 Subject: [PATCH 06/15] Added support for VCDM 2.0 --- .../Ed25519Signature2022LdVerifier.java | 2 +- .../Ed25519Signature2022VCDM20LdVerifier.java | 53 ++ .../vc/verification/Eddsa2022v2LdProof.java | 49 ++ .../vc/verification/LDSecurityContexts.java | 3 + .../verification/URDNA2015Canonicalizer.java | 15 +- .../resources/contexts/credentials-v2.jsonld | 594 +++++++++--------- 6 files changed, 395 insertions(+), 321 deletions(-) create mode 100644 inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Ed25519Signature2022VCDM20LdVerifier.java create mode 100644 inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Eddsa2022v2LdProof.java diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Ed25519Signature2022LdVerifier.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Ed25519Signature2022LdVerifier.java index 2f2fce0..cc567c0 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Ed25519Signature2022LdVerifier.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Ed25519Signature2022LdVerifier.java @@ -13,7 +13,7 @@ public class Ed25519Signature2022LdVerifier extends LdVerifier { + + public Ed25519Signature2022VCDM20LdVerifier(ByteVerifier verifier) { + + super(SignatureSuites.SIGNATURE_SUITE_ED25519SIGNATURE2022, verifier, new URDNA2015Canonicalizer(Eddsa2022v2LdProof.builder())); + } + + public Ed25519Signature2022VCDM20LdVerifier(byte[] publicKey) { + + this(new Ed25519_EdDSA_PublicKeyVerifier(publicKey)); + } + + public Ed25519Signature2022VCDM20LdVerifier() { + + this((ByteVerifier) null); + } + + public static boolean verify(byte[] signingInput, LdProof ldProof, ByteVerifier verifier) throws GeneralSecurityException { + + // verify + + String proofValue = ldProof.getProofValue(); + if (proofValue == null) throw new GeneralSecurityException("No 'proofValue' in proof."); + + boolean verify; + + byte[] bytes = Multibase.decode(proofValue); + verify = verifier.verify(signingInput, bytes, JWSAlgorithm.EdDSA); + + // done + + return verify; + } + + @Override + public boolean verify(byte[] signingInput, LdProof ldProof) throws GeneralSecurityException { + + return verify(signingInput, ldProof, this.getVerifier()); + } + +} + diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Eddsa2022v2LdProof.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Eddsa2022v2LdProof.java new file mode 100644 index 0000000..c56fa06 --- /dev/null +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/Eddsa2022v2LdProof.java @@ -0,0 +1,49 @@ +package org.oneedtech.inspect.vc.verification; + +import java.net.URI; + +import com.apicatalog.jsonld.loader.DocumentLoader; + +import foundation.identity.jsonld.JsonLDObject; +import foundation.identity.jsonld.JsonLDUtils; +import info.weboftrust.ldsignatures.LdProof; + +public class Eddsa2022v2LdProof extends LdProof { + public static final URI[] DEFAULT_JSONLD_CONTEXTS = { LDSecurityContexts.JSONLD_CONTEXT_W3ID_VC_V2 }; + public static final DocumentLoader DEFAULT_DOCUMENT_LOADER = LDSecurityContexts.DOCUMENT_LOADER; + + public static Builder> builder() { + return new Builder(new Eddsa2022v2LdProof()); + } + + /* + * Factory methods + */ + + public static class Builder> extends LdProof.Builder { + + private boolean addCryptosuite = true; + + public Builder(LdProof jsonLdObject) { + super(jsonLdObject); + } + + @Override + public B base(JsonLDObject base) { + addCryptosuite = false; + return super.base(base); + } + + @Override + public LdProof build() { + super.build(); + + if (addCryptosuite) { + JsonLDUtils.jsonLdAdd(this.jsonLdObject, "cryptosuite", "eddsa-rdfc-2022"); + } + + return (LdProof) this.jsonLdObject; + + } + } +} diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/LDSecurityContexts.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/LDSecurityContexts.java index f8652e1..0e9f313 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/LDSecurityContexts.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/LDSecurityContexts.java @@ -15,6 +15,7 @@ import foundation.identity.jsonld.ConfigurableDocumentLoader; public class LDSecurityContexts { public static final URI JSONLD_CONTEXT_W3ID_SUITES_ED25519_2022_V1 = URI.create("https://w3id.org/security/data-integrity/v1"); + public static final URI JSONLD_CONTEXT_W3ID_VC_V2 = URI.create("https://www.w3.org/ns/credentials/v2"); public static final Map CONTEXTS; public static final DocumentLoader DOCUMENT_LOADER; @@ -29,6 +30,8 @@ public class LDSecurityContexts { CONTEXTS.put(JSONLD_CONTEXT_W3ID_SUITES_ED25519_2022_V1, JsonDocument.of(MediaType.JSON_LD, Resources.getResource("contexts/data-integrity-v1.jsonld").openStream())); + CONTEXTS.put(JSONLD_CONTEXT_W3ID_VC_V2, + JsonDocument.of(MediaType.JSON_LD, Resources.getResource("contexts/credentials-v2.jsonld").openStream())); for (Map.Entry context : CONTEXTS.entrySet()) { context.getValue().setDocumentUrl(context.getKey()); diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/URDNA2015Canonicalizer.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/URDNA2015Canonicalizer.java index 0ed3a9f..9eedcae 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/URDNA2015Canonicalizer.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/verification/URDNA2015Canonicalizer.java @@ -1,28 +1,29 @@ package org.oneedtech.inspect.vc.verification; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.List; + import foundation.identity.jsonld.JsonLDException; import foundation.identity.jsonld.JsonLDObject; import info.weboftrust.ldsignatures.LdProof; import info.weboftrust.ldsignatures.canonicalizer.Canonicalizer; import info.weboftrust.ldsignatures.util.SHAUtil; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.List; - public class URDNA2015Canonicalizer extends Canonicalizer { - public URDNA2015Canonicalizer() { + private LdProof.Builder proofBuilder; + public URDNA2015Canonicalizer(LdProof.Builder proofBuilder) { super(List.of("urdna2015")); + this.proofBuilder = proofBuilder; } @Override public byte[] canonicalize(LdProof ldProof, JsonLDObject jsonLdObject) throws IOException, GeneralSecurityException, JsonLDException { // construct the LD proof without proof values - - LdProof ldProofWithoutProofValues = Eddsa2022LdProof.builder() + LdProof ldProofWithoutProofValues = proofBuilder .base(ldProof) .defaultContexts(true) .build(); diff --git a/inspector-vc/src/main/resources/contexts/credentials-v2.jsonld b/inspector-vc/src/main/resources/contexts/credentials-v2.jsonld index 94cd09f..4e5a69b 100644 --- a/inspector-vc/src/main/resources/contexts/credentials-v2.jsonld +++ b/inspector-vc/src/main/resources/contexts/credentials-v2.jsonld @@ -1,322 +1,290 @@ { - "@context": { - "@protected": true, - "@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#", - - "id": "@id", - "type": "@type", - - "kid": { - "@id": "https://www.iana.org/assignments/jose#kid", - "@type": "@id" - }, - "iss": { - "@id": "https://www.iana.org/assignments/jose#iss", - "@type": "@id" - }, - "sub": { - "@id": "https://www.iana.org/assignments/jose#sub", - "@type": "@id" - }, - "jku": { - "@id": "https://www.iana.org/assignments/jose#jku", - "@type": "@id" - }, - "x5u": { - "@id": "https://www.iana.org/assignments/jose#x5u", - "@type": "@id" - }, - "aud": { - "@id": "https://www.iana.org/assignments/jwt#aud", - "@type": "@id" - }, - "exp": { - "@id": "https://www.iana.org/assignments/jwt#exp", - "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" - }, - "nbf": { - "@id": "https://www.iana.org/assignments/jwt#nbf", - "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" - }, - "iat": { - "@id": "https://www.iana.org/assignments/jwt#iat", - "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" - }, - "cnf": { - "@id": "https://www.iana.org/assignments/jwt#cnf", - "@context": { - "@protected": true, - "kid": { - "@id": "https://www.iana.org/assignments/jwt#kid", - "@type": "@id" - }, - "jwk": { - "@id": "https://www.iana.org/assignments/jwt#jwk", - "@type": "@json" - } + "@context": { + "@protected": true, + "@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#", + "id": "@id", + "type": "@type", + "kid": { + "@id": "https://www.iana.org/assignments/jose#kid", + "@type": "@id" + }, + "iss": { + "@id": "https://www.iana.org/assignments/jose#iss", + "@type": "@id" + }, + "sub": { + "@id": "https://www.iana.org/assignments/jose#sub", + "@type": "@id" + }, + "jku": { + "@id": "https://www.iana.org/assignments/jose#jku", + "@type": "@id" + }, + "x5u": { + "@id": "https://www.iana.org/assignments/jose#x5u", + "@type": "@id" + }, + "aud": { + "@id": "https://www.iana.org/assignments/jwt#aud", + "@type": "@id" + }, + "exp": { + "@id": "https://www.iana.org/assignments/jwt#exp", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "nbf": { + "@id": "https://www.iana.org/assignments/jwt#nbf", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "iat": { + "@id": "https://www.iana.org/assignments/jwt#iat", + "@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger" + }, + "cnf": { + "@id": "https://www.iana.org/assignments/jwt#cnf", + "@context": { + "@protected": true, + "kid": { + "@id": "https://www.iana.org/assignments/jwt#kid", + "@type": "@id" + }, + "jwk": { + "@id": "https://www.iana.org/assignments/jwt#jwk", + "@type": "@json" } - }, - "_sd_alg": { - "@id": "https://www.iana.org/assignments/jwt#_sd_alg" - }, - "_sd": { - "@id": "https://www.iana.org/assignments/jwt#_sd" - }, - "...": { - "@id": "https://www.iana.org/assignments/jwt#..." - }, - - "digestSRI": { - "@id": "https://www.w3.org/2018/credentials#digestSRI", - "@type": "https://www.w3.org/2018/credentials#sriString" - }, - "digestMultibase": { - "@id": "https://w3id.org/security#digestMultibase", - "@type": "https://w3id.org/security#multibase" - }, - - "mediaType": { - "@id": "https://schema.org/encodingFormat" - }, - - "description": "https://schema.org/description", - "name": "https://schema.org/name", - - "EnvelopedVerifiableCredential": - "https://www.w3.org/2018/credentials#EnvelopedVerifiableCredential", - - "VerifiableCredential": { - "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", - "@context": { - "@protected": true, - - "id": "@id", - "type": "@type", - - "credentialSchema": { - "@id": "https://www.w3.org/2018/credentials#credentialSchema", - "@type": "@id" - }, - "credentialStatus": { - "@id": "https://www.w3.org/2018/credentials#credentialStatus", - "@type": "@id" - }, - "credentialSubject": { - "@id": "https://www.w3.org/2018/credentials#credentialSubject", - "@type": "@id" - }, - "description": "https://schema.org/description", - "evidence": { - "@id": "https://www.w3.org/2018/credentials#evidence", - "@type": "@id" - }, - "validFrom": { - "@id": "https://www.w3.org/2018/credentials#validFrom", - "@type": "http://www.w3.org/2001/XMLSchema#dateTime" - }, - "validUntil": { - "@id": "https://www.w3.org/2018/credentials#validUntil", - "@type": "http://www.w3.org/2001/XMLSchema#dateTime" - }, - "issuer": { - "@id": "https://www.w3.org/2018/credentials#issuer", - "@type": "@id" - }, - "name": "https://schema.org/name", - "proof": { - "@id": "https://w3id.org/security#proof", - "@type": "@id", - "@container": "@graph" - }, - "refreshService": { - "@id": "https://www.w3.org/2018/credentials#refreshService", - "@type": "@id" - }, - "termsOfUse": { - "@id": "https://www.w3.org/2018/credentials#termsOfUse", - "@type": "@id" - }, - "confidenceMethod": { - "@id": "https://www.w3.org/2018/credentials#confidenceMethod", - "@type": "@id" - }, - "relatedResource": { - "@id": "https://www.w3.org/2018/credentials#relatedResource", - "@type": "@id" - } + } + }, + "_sd_alg": { + "@id": "https://www.iana.org/assignments/jwt#_sd_alg" + }, + "_sd": { + "@id": "https://www.iana.org/assignments/jwt#_sd" + }, + "...": { + "@id": "https://www.iana.org/assignments/jwt#..." + }, + "digestSRI": { + "@id": "https://www.w3.org/2018/credentials#digestSRI", + "@type": "https://www.w3.org/2018/credentials#sriString" + }, + "digestMultibase": { + "@id": "https://w3id.org/security#digestMultibase", + "@type": "https://w3id.org/security#multibase" + }, + "mediaType": { + "@id": "https://schema.org/encodingFormat" + }, + "description": "https://schema.org/description", + "name": "https://schema.org/name", + "EnvelopedVerifiableCredential": "https://www.w3.org/2018/credentials#EnvelopedVerifiableCredential", + "VerifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "credentialSchema": { + "@id": "https://www.w3.org/2018/credentials#credentialSchema", + "@type": "@id" + }, + "credentialStatus": { + "@id": "https://www.w3.org/2018/credentials#credentialStatus", + "@type": "@id" + }, + "credentialSubject": { + "@id": "https://www.w3.org/2018/credentials#credentialSubject", + "@type": "@id" + }, + "description": "https://schema.org/description", + "evidence": { + "@id": "https://www.w3.org/2018/credentials#evidence", + "@type": "@id" + }, + "validFrom": { + "@id": "https://www.w3.org/2018/credentials#validFrom", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "validUntil": { + "@id": "https://www.w3.org/2018/credentials#validUntil", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "issuer": { + "@id": "https://www.w3.org/2018/credentials#issuer", + "@type": "@id" + }, + "name": "https://schema.org/name", + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph" + }, + "refreshService": { + "@id": "https://www.w3.org/2018/credentials#refreshService", + "@type": "@id" + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id" + }, + "confidenceMethod": { + "@id": "https://www.w3.org/2018/credentials#confidenceMethod", + "@type": "@id" + }, + "relatedResource": { + "@id": "https://www.w3.org/2018/credentials#relatedResource", + "@type": "@id" } - }, - - "VerifiablePresentation": { - "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", - "@context": { - "@protected": true, - - "id": "@id", - "type": "@type", - - "holder": { - "@id": "https://www.w3.org/2018/credentials#holder", - "@type": "@id" - }, - "proof": { - "@id": "https://w3id.org/security#proof", - "@type": "@id", - "@container": "@graph" - }, - "verifiableCredential": { - "@id": "https://www.w3.org/2018/credentials#verifiableCredential", - "@type": "@id", - "@container": "@graph", - "@context": null - }, - "termsOfUse": { - "@id": "https://www.w3.org/2018/credentials#termsOfUse", - "@type": "@id" - } + } + }, + "VerifiablePresentation": { + "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "holder": { + "@id": "https://www.w3.org/2018/credentials#holder", + "@type": "@id" + }, + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph" + }, + "verifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#verifiableCredential", + "@type": "@id", + "@container": "@graph", + "@context": null + }, + "termsOfUse": { + "@id": "https://www.w3.org/2018/credentials#termsOfUse", + "@type": "@id" } - }, - - "JsonSchemaCredential": "https://www.w3.org/2018/credentials#JsonSchemaCredential", - - "JsonSchema": { - "@id": "https://www.w3.org/2018/credentials#JsonSchema", - "@context": { - "@protected": true, - - "id": "@id", - "type": "@type", - - "jsonSchema": { - "@id": "https://w3.org/2018/credentials#jsonSchema", - "@type": "@json" - } + } + }, + "JsonSchemaCredential": "https://www.w3.org/2018/credentials#JsonSchemaCredential", + "JsonSchema": { + "@id": "https://www.w3.org/2018/credentials#JsonSchema", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "jsonSchema": { + "@id": "https://w3.org/2018/credentials#jsonSchema", + "@type": "@json" } - }, - - "BitstringStatusListCredential": "https://www.w3.org/ns/credentials/status#BitstringStatusListCredential", - - "BitstringStatusList": { - "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusList", - "@context": { - "@protected": true, - - "id": "@id", - "type": "@type", - - "statusPurpose": - "https://www.w3.org/ns/credentials/status#statusPurpose", - "encodedList": { - "@id": "https://www.w3.org/ns/credentials/status#encodedList", - "@type": "https://w3id.org/security#multibase" - }, - "ttl": "https://www.w3.org/ns/credentials/status#ttl", - "statusReference": "https://www.w3.org/ns/credentials/status#statusReference", - "statusSize": "https://www.w3.org/ns/credentials/status#statusSize", - "statusMessage": { - "@id": "https://www.w3.org/ns/credentials/status#statusMessage", - "@context": { - "@protected": true, - - "id": "@id", - "type": "@type", - - "status": "https://www.w3.org/ns/credentials/status#status", - "message": "https://www.w3.org/ns/credentials/status#message" - } - } - } - }, - - "BitstringStatusListEntry": { - "@id": - "https://www.w3.org/ns/credentials/status#BitstringStatusListEntry", - "@context": { - "@protected": true, - - "id": "@id", - "type": "@type", - - "statusPurpose": - "https://www.w3.org/ns/credentials/status#statusPurpose", - "statusListIndex": - "https://www.w3.org/ns/credentials/status#statusListIndex", - "statusListCredential": { - "@id": - "https://www.w3.org/ns/credentials/status#statusListCredential", - "@type": "@id" - } - } - }, - - "DataIntegrityProof": { - "@id": "https://w3id.org/security#DataIntegrityProof", - "@context": { - "@protected": true, - "id": "@id", - "type": "@type", - "challenge": "https://w3id.org/security#challenge", - "created": { - "@id": "http://purl.org/dc/terms/created", - "@type": "http://www.w3.org/2001/XMLSchema#dateTime" - }, - "domain": "https://w3id.org/security#domain", - "expires": { - "@id": "https://w3id.org/security#expiration", - "@type": "http://www.w3.org/2001/XMLSchema#dateTime" - }, - "nonce": "https://w3id.org/security#nonce", - "previousProof": { - "@id": "https://w3id.org/security#previousProof", - "@type": "@id" - }, - "proofPurpose": { - "@id": "https://w3id.org/security#proofPurpose", - "@type": "@vocab", - "@context": { - "@protected": true, - "id": "@id", - "type": "@type", - "assertionMethod": { - "@id": "https://w3id.org/security#assertionMethod", - "@type": "@id", - "@container": "@set" - }, - "authentication": { - "@id": "https://w3id.org/security#authenticationMethod", - "@type": "@id", - "@container": "@set" - }, - "capabilityInvocation": { - "@id": "https://w3id.org/security#capabilityInvocationMethod", - "@type": "@id", - "@container": "@set" - }, - "capabilityDelegation": { - "@id": "https://w3id.org/security#capabilityDelegationMethod", - "@type": "@id", - "@container": "@set" - }, - "keyAgreement": { - "@id": "https://w3id.org/security#keyAgreementMethod", - "@type": "@id", - "@container": "@set" - } - } - }, - "cryptosuite": { - "@id": "https://w3id.org/security#cryptosuite", - "@type": "https://w3id.org/security#cryptosuiteString" - }, - "proofValue": { - "@id": "https://w3id.org/security#proofValue", - "@type": "https://w3id.org/security#multibase" - }, - "verificationMethod": { - "@id": "https://w3id.org/security#verificationMethod", - "@type": "@id" + } + }, + "BitstringStatusListCredential": "https://www.w3.org/ns/credentials/status#BitstringStatusListCredential", + "BitstringStatusList": { + "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusList", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose", + "encodedList": { + "@id": "https://www.w3.org/ns/credentials/status#encodedList", + "@type": "https://w3id.org/security#multibase" + }, + "ttl": "https://www.w3.org/ns/credentials/status#ttl", + "statusReference": "https://www.w3.org/ns/credentials/status#statusReference", + "statusSize": "https://www.w3.org/ns/credentials/status#statusSize", + "statusMessage": { + "@id": "https://www.w3.org/ns/credentials/status#statusMessage", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "status": "https://www.w3.org/ns/credentials/status#status", + "message": "https://www.w3.org/ns/credentials/status#message" } } } + }, + "BitstringStatusListEntry": { + "@id": "https://www.w3.org/ns/credentials/status#BitstringStatusListEntry", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose", + "statusListIndex": "https://www.w3.org/ns/credentials/status#statusListIndex", + "statusListCredential": { + "@id": "https://www.w3.org/ns/credentials/status#statusListCredential", + "@type": "@id" + } + } + }, + "DataIntegrityProof": { + "@id": "https://w3id.org/security#DataIntegrityProof", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "challenge": "https://w3id.org/security#challenge", + "created": { + "@id": "http://purl.org/dc/terms/created", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "domain": "https://w3id.org/security#domain", + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "nonce": "https://w3id.org/security#nonce", + "previousProof": { + "@id": "https://w3id.org/security#previousProof", + "@type": "@id" + }, + "proofPurpose": { + "@id": "https://w3id.org/security#proofPurpose", + "@type": "@vocab", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "assertionMethod": { + "@id": "https://w3id.org/security#assertionMethod", + "@type": "@id", + "@container": "@set" + }, + "authentication": { + "@id": "https://w3id.org/security#authenticationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityInvocation": { + "@id": "https://w3id.org/security#capabilityInvocationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityDelegation": { + "@id": "https://w3id.org/security#capabilityDelegationMethod", + "@type": "@id", + "@container": "@set" + }, + "keyAgreement": { + "@id": "https://w3id.org/security#keyAgreementMethod", + "@type": "@id", + "@container": "@set" + } + } + }, + "cryptosuite": { + "@id": "https://w3id.org/security#cryptosuite", + "@type": "https://w3id.org/security#cryptosuiteString" + }, + "proofValue": { + "@id": "https://w3id.org/security#proofValue", + "@type": "https://w3id.org/security#multibase" + }, + "verificationMethod": { + "@id": "https://w3id.org/security#verificationMethod", + "@type": "@id" + } + } } - } \ No newline at end of file + } +} From 36878c620ccc057231b3d889d67d9ab56c17ada2 Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 17:26:04 +0100 Subject: [PATCH 07/15] Fixed tests --- .../java/org/oneedtech/inspect/vc/OB30Tests.java | 12 ++++++++++-- .../test/java/org/oneedtech/inspect/vc/Samples.java | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java index e213038..046c876 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java @@ -44,6 +44,15 @@ public class OB30Tests { }); } + @Test + void testSimpleV1JsonValid() { + assertDoesNotThrow(()->{ + Report report = validator.run(Samples.OB30.JSON.SIMPLE_V1_JSON.asFileResource()); + if(verbose) PrintHelper.print(report, true); + assertWarning(report); + }); + } + @Test void testSimpleDidKeyMethodJsonValid() { assertDoesNotThrow(()->{ @@ -219,7 +228,7 @@ public class OB30Tests { assertDoesNotThrow(()->{ Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_VERSION_CONTEXT.asFileResource()); if(verbose) PrintHelper.print(report, true); - assertHasValidProbeID(report, ContextPropertyProbe.ID); + assertHasProbeID(report, ContextPropertyProbe.ID, true); }); } @@ -342,7 +351,6 @@ public class OB30Tests { }); } - @Disabled //TODO IssuanceVerifierProbe is not run because FATAL: InvalidSignature terminates @Test void testSimpleJsonNotIssued() { //"issuanceDate": "2040-01-01T00:00:00Z", diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java index b0ab19e..b64faae 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java @@ -10,7 +10,9 @@ public class Samples { } public static final class JSON { public final static Sample COMPLETE_JSON = new Sample("ob30/complete.json", false); + public final static Sample BUG_JSON = new Sample("ob30/bug.json", false); public final static Sample SIMPLE_JSON = new Sample("ob30/simple.json", true); + public final static Sample SIMPLE_V1_JSON = new Sample("ob30/simple_v1.json", true); public final static Sample SIMPLE_EDDSA_20222_JSON = new Sample("ob30/simple-eddsa-2022.json", true); public final static Sample SIMPLE_DID_KEY_METHOD_JSON = new Sample("ob30/simple-did-key-method.json", true); public final static Sample SIMPLE_DID_WEB_METHOD_JSON = new Sample("ob30/simple-did-web-method.json", true); From ef8d4b08c4d4162063c5804db9862c2a535e4d3c Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 17:27:09 +0100 Subject: [PATCH 08/15] Updated fixtures --- .../resources/ob30/simple-context-alias.json | 25 +- .../ob30/simple-context-version.json | 26 +- .../resources/ob30/simple-did-key-method.json | 70 ++-- .../resources/ob30/simple-did-web-method.json | 41 ++- .../resources/ob30/simple-err-context.json | 12 +- ...t-achievement-result-description-type.json | 334 +++++++++--------- ...rr-credential-subject-identifier-type.json | 86 ++--- ...e-err-credential-subject-profile-type.json | 74 ++-- ...le-err-credential-subject-result-type.json | 152 ++++---- .../simple-err-credential-subject-type.json | 82 +++-- .../ob30/simple-err-evidence-type.json | 100 +++--- .../resources/ob30/simple-err-expired.json | 26 +- .../resources/ob30/simple-err-issued.json | 26 +- ...imple-err-issuer-otheridentifier-type.json | 90 +++-- .../simple-err-issuer-parentorg-type.json | 74 ++-- .../ob30/simple-err-issuer-type.json | 66 ++-- .../resources/ob30/simple-err-issuer.json | 24 +- .../simple-err-proof-method-no-scheme.json | 33 +- ...e-err-proof-method-unknown-did-method.json | 33 +- ...imple-err-proof-method-unknown-scheme.json | 33 +- .../ob30/simple-err-proof-method.json | 26 +- .../ob30/simple-err-proof-value.json | 48 +-- .../test/resources/ob30/simple-err-type.json | 62 ++-- .../src/test/resources/ob30/simple-json.png | Bin 84163 -> 84056 bytes .../src/test/resources/ob30/simple-json.svg | 33 +- .../ob30/simple-multiple-proofs.json | 19 +- .../src/test/resources/ob30/simple.json | 35 +- .../src/test/resources/ob30/simple_v1.json | 38 ++ 28 files changed, 821 insertions(+), 847 deletions(-) create mode 100644 inspector-vc/src/test/resources/ob30/simple_v1.json diff --git a/inspector-vc/src/test/resources/ob30/simple-context-alias.json b/inspector-vc/src/test/resources/ob30/simple-context-alias.json index 40ce9fe..14c90a4 100644 --- a/inspector-vc/src/test/resources/ob30/simple-context-alias.json +++ b/inspector-vc/src/test/resources/ob30/simple-context-alias.json @@ -1,8 +1,7 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context/ob_v3p0.jsonld", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ @@ -35,13 +34,13 @@ "name": "Teamwork" } }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] -} + "validFrom": "2024-03-21T14:56:35Z", + "proof": [{ + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z56yYTVAJxcTduuDvdCfnmEcYsRwHS7aBxHTgqYQUWYuXQxTyEswJTs4ynNeB8yjdoLcspTYL4z6mscwC47fJ8bBN" + }] +} \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-context-version.json b/inspector-vc/src/test/resources/ob30/simple-context-version.json index 29ad406..80744b9 100644 --- a/inspector-vc/src/test/resources/ob30/simple-context-version.json +++ b/inspector-vc/src/test/resources/ob30/simple-context-version.json @@ -1,8 +1,7 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.1.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.2.json" ], "id": "http://example.com/credentials/3527", "type": [ @@ -16,7 +15,7 @@ ], "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", @@ -35,13 +34,12 @@ "name": "Teamwork" } }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] -} + "proof": [{ + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "zD8RrkKVSVEPYspwCe9T1a68NAVt2GyV566uR6QLdxCMdkg2b4rdUf9w1BC8ZEyhGdEz13kzkBwkjTTvoYAYsy15" + }] +} \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-did-key-method.json b/inspector-vc/src/test/resources/ob30/simple-did-key-method.json index 764298f..52fea29 100644 --- a/inspector-vc/src/test/resources/ob30/simple-did-key-method.json +++ b/inspector-vc/src/test/resources/ob30/simple-did-key-method.json @@ -1,33 +1,47 @@ { - "@context" : [ "https://www.w3.org/2018/credentials/v1", "https://purl.imsglobal.org/spec/ob/v3p0/context.json", "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json", "https://w3id.org/security/suites/ed25519-2020/v1" ], - "id" : "urn:uuid:280c19b6-9680-4a37-ba84-e38b1a4e4584", - "type" : [ "VerifiableCredential", "AchievementCredential" ], - "issuer" : { - "type" : [ "Profile" ], - "name" : "Andy F. Miller", - "id" : "urn:uuid:6f2e33e5-7a29-4155-840a-59483ba10164" + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json" + ], + "id": "urn:uuid:280c19b6-9680-4a37-ba84-e38b1a4e4584", + "type": [ + "VerifiableCredential", + "AchievementCredential" + ], + "issuer": { + "type": [ + "Profile" + ], + "name": "Andy F. Miller", + "id": "urn:uuid:6f2e33e5-7a29-4155-840a-59483ba10164" }, - "issuanceDate" : "2022-11-10T07:38:00-08:00", - "name" : "test 1", - "credentialSubject" : { - "id" : "urn:uuid:6f2e33e5-7a29-4155-840a-59483ba10164", - "type" : [ "AchievementSubject" ], - "achievement" : { - "id" : "urn:uuid:35258e6f-4c05-4215-8ada-38a5a5b80510", - "type" : [ "Achievement" ], - "achievementType" : "Achievement", - "name" : "test 1", - "description" : "This is a test achievement", - "criteria" : { - "narrative" : "There is no criteria" + "validFrom": "2022-11-10T07:38:00-08:00", + "name": "test 1", + "credentialSubject": { + "id": "urn:uuid:6f2e33e5-7a29-4155-840a-59483ba10164", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "urn:uuid:35258e6f-4c05-4215-8ada-38a5a5b80510", + "type": [ + "Achievement" + ], + "achievementType": "Achievement", + "name": "test 1", + "description": "This is a test achievement", + "criteria": { + "narrative": "There is no criteria" } } }, - "proof" : [ { - "type" : "Ed25519Signature2020", - "created" : "2022-11-16T20:39:53Z", - "proofPurpose" : "assertionMethod", - "verificationMethod" : "did:key:z6MkwAQmEfso8UjHJZTQajRtqR5hDxAD95iJD4z53XnKCFms", - "proofValue" : "z361ueyGzREPvsWdnWUfkzTKXEd6u2DPPu2kDw3pDERJmzDFCqsuaPneqcRgz2hk9ycaNDYmC4Fy9c6S6BDDt5fVB" - } ] -} + "proof": [{ + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "did:key:z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5v2mkEWTLxzJ4VCxvUx5dRoy54Hp81GpyABUk7NswQECwDH6Ecwv5F3Mqso7t18UY6WScm5Qszo6nqiiqmevRWHc" + }] +} \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-did-web-method.json b/inspector-vc/src/test/resources/ob30/simple-did-web-method.json index 36c2de0..24d0ac1 100644 --- a/inspector-vc/src/test/resources/ob30/simple-did-web-method.json +++ b/inspector-vc/src/test/resources/ob30/simple-did-web-method.json @@ -1,9 +1,7 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.1.json", - "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "https://dc.1edtech.org/wellspring2022/wellspring-portal/credential/d002b4e9-6fd9-4af0-b1f7-faa9237b46ca", "type": [ @@ -12,22 +10,30 @@ ], "issuer": { "id": "did:web:dc.1edtech.org:wellspring2022:wellspring-portal:org:da1e96e9-afcc-4eed-b9a2-2ddf7353214c", - "type": ["Profile"], + "type": [ + "Profile" + ], "address": { - "type": ["Address"], + "type": [ + "Address" + ], "addressCountry": "Japan" }, "name": "1EdTech Testing" }, "awardedDate": "2023-05-22T14:09:00Z", - "issuanceDate": "2023-05-23T01:07:22Z", + "validFrom": "2023-05-23T01:07:22Z", "name": "ob3-simple-did-web-method.json", "credentialSubject": { "id": "did:web:dc.1edtech.org:wellspring2022:wellspring-portal:learner:6896f98f-6b42-4c75-98ec-8befd0dc0b29", - "type": ["AchievementSubject"], + "type": [ + "AchievementSubject" + ], "achievement": { "id": "https://dc.1edtech.org/wellspring2022/wellspring-portal/achievement/66457db3-fb3d-4ae3-8f32-bc8c79c9f0db", - "type": ["Achievement"], + "type": [ + "Achievement" + ], "achievementType": "Achievement", "criteria": { "narrative": "Passes tests" @@ -37,9 +43,13 @@ }, "source": { "id": "did:web:dc.1edtech.org:wellspring2022:wellspring-portal:org:da1e96e9-afcc-4eed-b9a2-2ddf7353214c", - "type": ["Profile"], + "type": [ + "Profile" + ], "address": { - "type": ["Address"], + "type": [ + "Address" + ], "addressCountry": "Japan" }, "name": "1EdTech Testing" @@ -54,10 +64,11 @@ "type": "1EdTechCredentialRefresh" }, "proof": [{ - "type": "Ed25519Signature2020", - "created": "2023-05-23T01:07:22Z", - "proofPurpose": "assertionMethod", + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", "verificationMethod": "did:web:dc.1edtech.org:wellspring2022:wellspring-portal:org:da1e96e9-afcc-4eed-b9a2-2ddf7353214c#key-0", - "proofValue": "z5tVhex5rV9aTxTrGh26uyVdC6BWXG8dQCkzNjgkPWtwAjGzMyYXzrQYJ2XrKUsNpYE3fTXsgUSBwDCY11vbyGBw7" + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z54xk5KNnchymcgxxaTECoREb3n9t8AeUU7AV5mNXhF56D82KPBtoXrPrR9DuEDL5oJtDxL3Cdv42Bt5QCJYcG4gc" }] } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-context.json b/inspector-vc/src/test/resources/ob30/simple-err-context.json index be960df..415ac9c 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-context.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-context.json @@ -1,7 +1,6 @@ { "@context": [ - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.edu/credentials/3732", "type": [ @@ -25,11 +24,12 @@ }, "proof": [ { - "type": "Ed25519Signature2020", - "created": "2022-06-28T16:28:36Z", - "verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj", + "type": "DataIntegrityProof", + "created": "2024-03-20T14:53:19Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkrvfzkMnvCroEUP2DVc9SHPE48CRsvHiVSusHioxTYu1x", + "cryptosuite": "eddsa-rdfc-2022", "proofPurpose": "assertionMethod", - "proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM" + "proofValue": "z76jrNcyxHg5fV17h96yCRwqUaTQZD2QQivyNqHyLSvqu3aWGC3nLShzZEGbH3LnVFodwov9rPQxi3QRP7adCrzV" } ] } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-achievement-result-description-type.json b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-achievement-result-description-type.json index dd6b7ae..05872fe 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-achievement-result-description-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-achievement-result-description-type.json @@ -1,188 +1,186 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "VerifiableCredential", + "OpenBadgeCredential" ], "issuer": { - "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], - "name": "Example Corp" + "id": "https://example.com/issuers/876543", + "type": [ + "Profile" + ], + "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork", - "resultDescription": [ - { - "id": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", - "type": "ResultDescription", - "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFItem", - "targetUrl": "https://1edtech.edu/catalog/degree/project" - } - ], - "allowedValue": [ - "D", - "C", - "B", - "A" - ], - "name": "Final Project Grade", - "requiredValue": "C", - "resultType": "LetterGrade" - }, - { - "id": "urn:uuid:a70ddc6a-4c4a-4bd8-8277-cb97c79f40c5", - "type": "ResultDescription", - "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFItem", - "targetUrl": "https://1edtech.edu/catalog/degree/project" - } - ], - "allowedValue": [ - "D", - "C", - "B", - "A" - ], - "name": "Final Project Grade", - "requiredLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", - "resultType": "RubricCriterionLevel", - "rubricCriterionLevel": [ - { - "id": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", - "type": "RubricCriterionLevel", - "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFRubricCriterionLevel", - "targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/mastered" - } - ], - "description": "The author demonstrated...", - "level": "Mastered", - "name": "Mastery", - "points": "4" - }, - { - "id": "urn:uuid:6b84b429-31ee-4dac-9d20-e5c55881f80e", - "type": "RubricCriterionLevel", - "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFRubricCriterionLevel", - "targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/basic" - } - ], - "description": "The author demonstrated...", - "level": "Basic", - "name": "Basic", - "points": "4" - } - ] - }, - { - "id": "urn:uuid:b07c0387-f2d6-4b65-a3f4-f4e4302ea8f7", - "type": "InvalidResultDescription", - "name": "Project Status", - "resultType": "Status" - } - ] + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, - "result": [ - { - "type": [ - "Result" - ], + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork", + "resultDescription": [ + { + "id": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "type": "ResultDescription", + "alignment": [ + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project" + } + ], + "allowedValue": [ + "D", + "C", + "B", + "A" + ], + "name": "Final Project Grade", + "requiredValue": "C", + "resultType": "LetterGrade" + }, + { + "id": "urn:uuid:a70ddc6a-4c4a-4bd8-8277-cb97c79f40c5", + "type": "ResultDescription", + "alignment": [ + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project" + } + ], + "allowedValue": [ + "D", + "C", + "B", + "A" + ], + "name": "Final Project Grade", + "requiredLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "resultType": "RubricCriterionLevel", + "rubricCriterionLevel": [ + { + "id": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "type": "RubricCriterionLevel", "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFItem", - "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" - } + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFRubricCriterionLevel", + "targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/mastered" + } ], - "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", - "value": "A" - }, - { - "type": [ - "Result" - ], - "achievedLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "description": "The author demonstrated...", + "level": "Mastered", + "name": "Mastery", + "points": "4" + }, + { + "id": "urn:uuid:6b84b429-31ee-4dac-9d20-e5c55881f80e", + "type": "RubricCriterionLevel", "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFItem", - "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" - } + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFRubricCriterionLevel", + "targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/basic" + } ], - "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c" - }, - { - "type": [ - "Result" - ], - "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", - "status": "Completed" - } + "description": "The author demonstrated...", + "level": "Basic", + "name": "Basic", + "points": "4" + } + ] + }, + { + "id": "urn:uuid:b07c0387-f2d6-4b65-a3f4-f4e4302ea8f7", + "type": "InvalidResultDescription", + "name": "Project Status", + "resultType": "Status" + } ] - }, - "proof": [ + }, + "result": [ { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" + "type": [ + "Result" + ], + "alignment": [ + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "value": "A" + }, + { + "type": [ + "Result" + ], + "achievedLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "alignment": [ + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c" + }, + { + "type": [ + "Result" + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "status": "Completed" } - ] -} \ No newline at end of file + ] + }, + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "zW2X3KbSiPJ4zmN1GD641owCgz87NjsFpcRpjAdDoPhW7pWvyJUEap3iDKUWovRM43r15Wru6cv8qBVvVgnJxhuH" + } + } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-identifier-type.json b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-identifier-type.json index 64960bd..f8a572d 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-identifier-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-identifier-type.json @@ -1,52 +1,52 @@ { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" - ], - "id": "http://example.com/credentials/3527", + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://example.com/credentials/3527", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/876543", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "Profile" ], - "issuer": { - "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], - "name": "Example Corp" - }, - "issuanceDate": "2010-01-01T00:00:00Z", - "name": "Teamwork Badge", - "credentialSubject": { - "identifier": [{ + "name": "Example Corp" + }, + "validFrom": "2010-01-01T00:00:00Z", + "name": "Teamwork Badge", + "credentialSubject": { + "identifier": [ + { "type": "InvalidIdentityObject", "hashed": true, "identityHash": "asdjhsadas", "identityType": "lisSourcedId" - }], + } + ], + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" - } - }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] - } \ No newline at end of file + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + } + }, + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5M8kUcxhKZ8niHpZt1LUBLrJGeLMnYaCmwrdR7MrcGzyiGz65zkk59212f7xpd7odxGVDp4e6MvNABsQ8YGn7U98" + } +} \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-profile-type.json b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-profile-type.json index 57646c7..68fd961 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-profile-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-profile-type.json @@ -1,52 +1,50 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "VerifiableCredential", + "OpenBadgeCredential" ], "issuer": { - "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], - "name": "Example Corp" + "id": "https://example.com/issuers/876543", + "type": [ + "Profile" + ], + "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, - "source": { - "id": "https://school.edu/issuers/201234", - "type": "InvalidProfile", - "name": "1EdTech College of Arts" - } + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + }, + "source": { + "id": "https://school.edu/issuers/201234", + "type": "InvalidProfile", + "name": "1EdTech College of Arts" + } }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] -} \ No newline at end of file + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5kJkNSdserQduikVPAfEZ3qMPQRkyvcB7tTaNuxjqNZioQmijmWouvBqSGnAeKKoXAavTk4cxY94iuiEW9boXVyV" + } + } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-result-type.json b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-result-type.json index 5275a9a..5663d3f 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-result-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-result-type.json @@ -1,92 +1,90 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "VerifiableCredential", + "OpenBadgeCredential" ], "issuer": { - "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], - "name": "Example Corp" + "id": "https://example.com/issuers/876543", + "type": [ + "Profile" + ], + "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, - "result": [ - { - "type": [ - "Result" - ], - "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFItem", - "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" - } - ], - "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", - "value": "A" - }, - { - "type": [ - "InvalidResult" - ], - "achievedLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", - "alignment": [ - { - "type": "Alignment", - "targetCode": "project", - "targetDescription": "Project description", - "targetName": "Final Project", - "targetFramework": "1EdTech University Program and Course Catalog", - "targetType": "CFItem", - "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" - } - ], - "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c" - }, - { - "type": [ - "Result" - ], - "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", - "status": "Completed" - } - ] - }, - "proof": [ + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + }, + "result": [ { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" + "type": [ + "Result" + ], + "alignment": [ + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "value": "A" + }, + { + "type": [ + "InvalidResult" + ], + "achievedLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "alignment": [ + { + "type": "Alignment", + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c" + }, + { + "type": [ + "Result" + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "status": "Completed" } - ] -} \ No newline at end of file + ] + }, + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5YBoPB9tjivuKpRyj9GknLKkReBcpjHxmeR4fGbAppoUpGC2GhbEC8eFdtrnk97ToRPYoQKdtFYDdixGqWXtRpsm" + } + } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-type.json b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-type.json index 37712c5..85851e0 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-credential-subject-type.json @@ -1,47 +1,45 @@ { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" - ], - "id": "http://example.com/credentials/3527", + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://example.com/credentials/3527", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/876543", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "Profile" ], - "issuer": { - "id": "https://example.com/issuers/876543", + "name": "Example Corp" + }, + "validFrom": "2010-01-01T00:00:00Z", + "name": "Teamwork Badge", + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "InvalidAchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "Profile" + "Achievement" ], - "name": "Example Corp" - }, - "issuanceDate": "2010-01-01T00:00:00Z", - "name": "Teamwork Badge", - "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", - "type": [ - "InvalidAchievementSubject" - ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" - } - }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] - } \ No newline at end of file + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + } + }, + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z57amKtkLGz6Gs4s1R7hcgkWzrxayXt7HZ4L5Gt8VBGcM2Z4881fEDARqa8pM2N2dniqXz3U4cC6zW3UBfkQZCfN" + } +} \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-evidence-type.json b/inspector-vc/src/test/resources/ob30/simple-err-evidence-type.json index 245cbd6..0bb8acb 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-evidence-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-evidence-type.json @@ -1,66 +1,64 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "VerifiableCredential", + "OpenBadgeCredential" ], "issuer": { - "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], - "name": "Example Corp" + "id": "https://example.com/issuers/876543", + "type": [ + "Profile" + ], + "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" - } + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + } }, "evidence": [ - { - "id": "https://1edtech.edu/credentials/3732/evidence/1", - "type": "Evidence", - "narrative": "# Final Project Report \n This project was ...", - "name": "Final Project Report", - "description": "This is the final project report.", - "genre": "Research", - "audience": "Department" - }, - { - "id": "https://github.com/somebody/project", - "type": "InvalidEvidence", - "name": "Final Project Code", - "description": "This is the source code for the final project app.", - "genre": "Research", - "audience": "Department" - } + { + "id": "https://1edtech.edu/credentials/3732/evidence/1", + "type": "Evidence", + "narrative": "# Final Project Report \n This project was ...", + "name": "Final Project Report", + "description": "This is the final project report.", + "genre": "Research", + "audience": "Department" + }, + { + "id": "https://github.com/somebody/project", + "type": "InvalidEvidence", + "name": "Final Project Code", + "description": "This is the source code for the final project app.", + "genre": "Research", + "audience": "Department" + } ], - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] -} \ No newline at end of file + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "zbXsNxLTdGdCTdyfkefLRenndjs6QoXnwCYtNbXj4ZtwxrGa2xctb78XrBjuTNK8FKskysBYvMuSzvWYSzfzTXWX" + } + } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-expired.json b/inspector-vc/src/test/resources/ob30/simple-err-expired.json index 3127b92..1949ac7 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-expired.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-expired.json @@ -1,8 +1,7 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ @@ -16,8 +15,8 @@ ], "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", - "expirationDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", @@ -36,13 +35,12 @@ "name": "Teamwork" } }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z2mAP6ezimojRWSHDhS1VfJgDdMCqa4oPbmJT1tCs43t5bRiwsrrhHxrmTEeAF2EBjErrzxoJj3HCKsdkyVkno11f" + } } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-issued.json b/inspector-vc/src/test/resources/ob30/simple-err-issued.json index 471a3df..9f6ff6f 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-issued.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-issued.json @@ -1,8 +1,7 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.edu/credentials/3732", "type": [ @@ -16,8 +15,8 @@ ], "name": "Example University" }, - "issuanceDate": "2040-01-01T00:00:00Z", - "expirationDate": "2050-01-20T00:00:00Z", + "validFrom": "2040-01-01T00:00:00Z", + "validUntil": "2050-01-20T00:00:00Z", "name": "Example University Degree", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", @@ -25,13 +24,12 @@ "AchievementSubject" ] }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-06-28T16:28:36Z", - "verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj", - "proofPurpose": "assertionMethod", - "proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM" - } - ] + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.edu/issuers/565049#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5EUB8AAu98Tdagjaf6QP7zY7MovnYTEB6vnNBgWjaCtaiNQfqNLQmEPpxvQuQPmVfQ49wcadz3DNUDk4CAt79HaF" + } } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-issuer-otheridentifier-type.json b/inspector-vc/src/test/resources/ob30/simple-err-issuer-otheridentifier-type.json index 94a134a..c0014cd 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-issuer-otheridentifier-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-issuer-otheridentifier-type.json @@ -1,59 +1,57 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "VerifiableCredential", + "OpenBadgeCredential" ], "issuer": { - "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], - "name": "Example Corp", - "otherIdentifier": [ - { - "type": "IdentifierEntry", - "identifier": "12345", - "identifierType": "sourcedId" - }, - { - "type": "InvalidIdentifierEntry", - "identifier": "67890", - "identifierType": "nationalIdentityNumber" - } - ] + "id": "https://example.com/issuers/876543", + "type": [ + "Profile" + ], + "name": "Example Corp", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "12345", + "identifierType": "sourcedId" + }, + { + "type": "InvalidIdentifierEntry", + "identifier": "67890", + "identifierType": "nationalIdentityNumber" + } + ] }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" - } + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + } }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] -} \ No newline at end of file + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z3y8SeYGgaCjgeqe5vbKv9egn5zxHPoFNDYRXa9pHPxMua2P9PEinYmmjq12FqXYr272DhKj6tvBTCzvx3KRc8ys8" + } + } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-issuer-parentorg-type.json b/inspector-vc/src/test/resources/ob30/simple-err-issuer-parentorg-type.json index c2f1dad..eb098fb 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-issuer-parentorg-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-issuer-parentorg-type.json @@ -1,54 +1,52 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "VerifiableCredential", + "OpenBadgeCredential" ], "issuer": { + "id": "https://example.com/issuers/876543", + "type": [ + "Profile" + ], + "name": "Example Corp", + "parentOrg": { "id": "https://example.com/issuers/876543", "type": [ - "Profile" + "InvalidProfile" ], - "name": "Example Corp", - "parentOrg": { - "id": "https://example.com/issuers/876543", - "type": [ - "InvalidProfile" - ], - "name": "Example Parent Corp" - } + "name": "Example Parent Corp" + } }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" - } + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + } }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] -} \ No newline at end of file + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z3f57gU5zssuyZTW2HxK2tV6qXCHyE3xdCHCczsUoRMSDBooCGboVBWUZygqpqskN5Mmpww8Qu3JARf1YvGcCzE34" + } + } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-issuer-type.json b/inspector-vc/src/test/resources/ob30/simple-err-issuer-type.json index a42b0d1..f9e317d 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-issuer-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-issuer-type.json @@ -1,47 +1,45 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "VerifiableCredential", + "OpenBadgeCredential" ], "issuer": { - "id": "https://example.com/issuers/876543", - "type": [ - "InvalidProfile" - ], - "name": "Example Corp" + "id": "https://example.com/issuers/876543", + "type": [ + "InvalidProfile" + ], + "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", "type": [ - "AchievementSubject" + "Achievement" ], - "achievement": { - "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], - "criteria": { - "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." - }, - "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", - "name": "Teamwork" - } + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "name": "Teamwork" + } }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "https://example.com/issuers/876543#z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", - "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" - } - ] -} \ No newline at end of file + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z2t8HUUbHs1G3o5t1uCTA7kbdprP21W9xmf8qJaDBWBoHSBFvJB26Bdq7Fi1ko2cnaHAvXETdMX6dPGFSA2rTP4KW" + } + } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-issuer.json b/inspector-vc/src/test/resources/ob30/simple-err-issuer.json index 5735768..a63cb00 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-issuer.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-issuer.json @@ -1,15 +1,14 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.edu/credentials/3732", "type": [ "VerifiableCredential", "OpenBadgeCredential" ], - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Example University Degree", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", @@ -17,13 +16,12 @@ "AchievementSubject" ] }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-06-28T16:28:36Z", - "verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj", - "proofPurpose": "assertionMethod", - "proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM" - } - ] + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5ZjnJNPeQznivpmedtQZDAy9vXVz2BbhZp13fGpTfMnsgzccs2Z3Se2BRWeECSMo92cUsQP63LhMb6veWuD223j2" + } } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-proof-method-no-scheme.json b/inspector-vc/src/test/resources/ob30/simple-err-proof-method-no-scheme.json index 1fc7e2f..5ea950a 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-proof-method-no-scheme.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-proof-method-no-scheme.json @@ -1,33 +1,23 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", - "type": [ - "VerifiableCredential", - "OpenBadgeCredential" - ], + "type": ["VerifiableCredential", "OpenBadgeCredential"], "issuer": { "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], + "type": ["Profile"], "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", - "type": [ - "AchievementSubject" - ], + "type": ["AchievementSubject"], "achievement": { "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], + "type": ["Achievement"], "criteria": { "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, @@ -37,11 +27,12 @@ }, "proof": [ { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", + "type": "DataIntegrityProof", + "created": "2024-03-20T14:53:19Z", + "verificationMethod": "z6MkrvfzkMnvCroEUP2DVc9SHPE48CRsvHiVSusHioxTYu1x", + "cryptosuite": "eddsa-rdfc-2022", "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" + "proofValue": "z76jrNcyxHg5fV17h96yCRwqUaTQZD2QQivyNqHyLSvqu3aWGC3nLShzZEGbH3LnVFodwov9rPQxi3QRP7adCrzV" } ] } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-did-method.json b/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-did-method.json index 60601f2..fe56cee 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-did-method.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-did-method.json @@ -1,33 +1,23 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", - "type": [ - "VerifiableCredential", - "OpenBadgeCredential" - ], + "type": ["VerifiableCredential", "OpenBadgeCredential"], "issuer": { "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], + "type": ["Profile"], "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", - "type": [ - "AchievementSubject" - ], + "type": ["AchievementSubject"], "achievement": { "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], + "type": ["Achievement"], "criteria": { "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, @@ -37,11 +27,12 @@ }, "proof": [ { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "did:example:z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", + "type": "DataIntegrityProof", + "created": "2024-03-20T14:53:19Z", + "verificationMethod": "did:example:z6MkrvfzkMnvCroEUP2DVc9SHPE48CRsvHiVSusHioxTYu1x", + "cryptosuite": "eddsa-rdfc-2022", "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" + "proofValue": "z76jrNcyxHg5fV17h96yCRwqUaTQZD2QQivyNqHyLSvqu3aWGC3nLShzZEGbH3LnVFodwov9rPQxi3QRP7adCrzV" } ] } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-scheme.json b/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-scheme.json index bb11ff3..fa737fb 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-scheme.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-proof-method-unknown-scheme.json @@ -1,33 +1,23 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", - "type": [ - "VerifiableCredential", - "OpenBadgeCredential" - ], + "type": ["VerifiableCredential", "OpenBadgeCredential"], "issuer": { "id": "https://example.com/issuers/876543", - "type": [ - "Profile" - ], + "type": ["Profile"], "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", - "type": [ - "AchievementSubject" - ], + "type": ["AchievementSubject"], "achievement": { "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], + "type": ["Achievement"], "criteria": { "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, @@ -37,11 +27,12 @@ }, "proof": [ { - "type": "Ed25519Signature2020", - "created": "2022-11-16T18:54:22Z", - "verificationMethod": "xxx:z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv", + "type": "DataIntegrityProof", + "created": "2024-03-20T14:53:19Z", + "verificationMethod": "xxx:z6MkrvfzkMnvCroEUP2DVc9SHPE48CRsvHiVSusHioxTYu1x", + "cryptosuite": "eddsa-rdfc-2022", "proofPurpose": "assertionMethod", - "proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK" + "proofValue": "z76jrNcyxHg5fV17h96yCRwqUaTQZD2QQivyNqHyLSvqu3aWGC3nLShzZEGbH3LnVFodwov9rPQxi3QRP7adCrzV" } ] } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-proof-method.json b/inspector-vc/src/test/resources/ob30/simple-err-proof-method.json index 037a10c..49ff8ab 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-proof-method.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-proof-method.json @@ -1,9 +1,8 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json", - "https://w3id.org/security/suites/ed25519-2020/v1" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json" ], "id": "http://example.edu/credentials/3732", "type": [ @@ -17,7 +16,7 @@ ], "name": "Example University" }, - "issuanceDate": "2010-01-01T00:00:00Z", + "validFrom": "2010-01-01T00:00:00Z", "name": "Example University Degree", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", @@ -42,13 +41,12 @@ "type": "1EdTechJsonSchemaValidator2019" } ], - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-09-15T15:48:32Z", - "verificationMethod": "https://example.edu/issuers/565049#xxMkmY1R6tG2NEdRHzphdRT6JqxeYpHwLAHwbrDfQULpkMAj", - "proofPurpose": "assertionMethod", - "proofValue": "z3yUuWbFsLUp2CUrSZRaRbTk1UnkhpoJgJYu1SdMqd3AEMotpY41sKky7VzavnSfjApggtWJg1tcREvs5H4ZNnBRH" - } - ] + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.edu/issuers/565049#z6MkjZRsdasZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z4HwAsa7GvwL7so7CoQ8v3ShzykRPCq8pfkAFKuAPrJx28S69pXphpqL8ApjoxEcMaqbgkaCUyKuEohhGXBR4Fh3L" + } } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-proof-value.json b/inspector-vc/src/test/resources/ob30/simple-err-proof-value.json index d26f49d..f2803f6 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-proof-value.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-proof-value.json @@ -1,34 +1,23 @@ { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json", - "https://w3id.org/security/suites/ed25519-2020/v1" - ], - "id": "http://example.edu/credentials/3732", - "type": [ - "VerifiableCredential", - "OpenBadgeCredential" + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], + "id": "http://example.com/credentials/3527", + "type": ["VerifiableCredential", "OpenBadgeCredential"], "issuer": { - "id": "https://example.edu/issuers/565049", - "type": [ - "Profile" - ], - "name": "Example University" + "id": "https://example.com/issuers/876543", + "type": ["Profile"], + "name": "Example Corp" }, - "issuanceDate": "2010-01-01T00:00:00Z", - "name": "Example University Degree", + "validFrom": "2010-01-01T00:00:00Z", + "name": "Teamwork Badge", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", - "type": [ - "AchievementSubject" - ], + "type": ["AchievementSubject"], "achievement": { "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": [ - "Achievement" - ], + "type": ["Achievement"], "criteria": { "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, @@ -36,19 +25,14 @@ "name": "Teamwork" } }, - "credentialSchema": [ - { - "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", - "type": "1EdTechJsonSchemaValidator2019" - } - ], "proof": [ { - "type": "Ed25519Signature2020", - "created": "2022-09-15T15:48:32Z", - "verificationMethod": "https://example.edu/issuers/565049#z6MkmY1R6tG2NEdRHzphdRT6JqxeYpHwLAHwbrDfQULpkMAj", + "type": "DataIntegrityProof", + "created": "2024-03-20T14:53:19Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkrvfzkMnvCroEUP2DVc9SHPE48CRsvHiVSusHioxTYu1x", + "cryptosuite": "eddsa-rdfc-2022", "proofPurpose": "assertionMethod", - "proofValue": "z3fQCWGpz7b1HSH6DTwYiH5vutqtpJb5SHiP1VFK22xeBEW2D61tC9j3SktwPLNxPnTNZnPt4GeAZJPdVYserRqs4" + "proofValue": "z76jrNcyxHg5fV17h96yCRwqUaTQZD2QQivyNqHyLSvqu3aWGC3nLShzZEGbH3LvNFodwov9rPQxi3QRP7adCrzV" } ] } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-err-type.json b/inspector-vc/src/test/resources/ob30/simple-err-type.json index cf146d2..23cc91f 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-type.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-type.json @@ -1,36 +1,34 @@ { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://w3id.org/security/suites/ed25519-2020/v1" - ], - "id": "http://example.edu/credentials/3732", + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://example.edu/credentials/3732", + "type": [ + "VerifiableCredential", + "OtherCredential" + ], + "issuer": { + "id": "https://example.edu/issuers/565049", "type": [ - "VerifiableCredential", - "OtherCredential" + "Profile" ], - "issuer": { - "id": "https://example.edu/issuers/565049", - "type": [ - "Profile" - ], - "name": "Example University" - }, - "issuanceDate": "2010-01-01T00:00:00Z", - "name": "Example University Degree", - "credentialSubject": { - "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", - "type": [ - "AchievementSubject" - ] - }, - "proof": [ - { - "type": "Ed25519Signature2020", - "created": "2022-06-09T22:56:28Z", - "verificationMethod": "https://example.edu/issuers/565049#key-1", - "proofPurpose": "assertionMethod", - "proofValue": "z58ieJCh4kN6eE2Vq4TyYURKSC4hWWEK7b75NNUL2taZMhKqwTteuByG1wRoGDdCqqNLW5Gq1diUi4qyZ63tQRtyN" - } + "name": "Example University" + }, + "validFrom": "2010-01-01T00:00:00Z", + "name": "Example University Degree", + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" ] - } \ No newline at end of file + }, + "proof": { + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.edu/issuers/565049#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z662W1sSqKoA8ryTKK7PPVGKRrBkx5id3aDvdFNtguJcVFHJggDnkwJFntbo2cWfSwumCh9mgcYUe2RgpK1GZFyxa" + } +} \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple-json.png b/inspector-vc/src/test/resources/ob30/simple-json.png index 4ae4fb318f199334c592ff32524c7068cb779bf1..88616c9f784cd57af196df3a7dc1a3bd561d5f37 100644 GIT binary patch delta 800 zcmY*XOOMh(9CuHh#vqp3ihjxHrp;M-B2+?@(tf!vV zFJR)yZ{Xdddi9$)Esw>?T&Dd!{=eVMkIyH6KApV(4t`a^BKchfk18C;KQ)Q%p~&Ma z+-r_4e(HISTM>jX3=5%BAao+wu3%DRA=|@n?h1j-=MqH)#rt`sAQqIu%q2F@ahJK| zs|pGYCgQ~oN)>qnQ9QNgoIwPoGj@stV0PIGlA?1*E`0}majn%Ua(7^ zQ0&F5L59rg+XjaovKW(9Bp36dl9$E4RIHpS6{*ZB;<)5X15^hz7_Y9L+kr}nHfYN= z!z}mowpM(icHKb7M$dP3OrriPUy6>@W5*+|&+?@X$g*6Rr`FhHCUW|S?&;w1K3^8W zfO9{?u1e=K+A`xvpPY>isWdI0$7(lR4q(4CtjV1Y4&v5QkDI+<=_~MMLsjf%Z@L<4 vjghW2ZKF=CkOXDg?nGGWblW9psdQ!RTf5xcz2^SjV(aumYt_D0-+uT9bO-Nw delta 872 zcmZvaJ#W)c6o$D&CFH3SLLj8b17aZlO5!$Ip#Dfg6M|7f+89;Bac-O&5<9uRc0Q^I zgalh9nEVSESeW<+>_{xooq@l>wVgC=g>{#6&pFS1&wG6Sap(J|owwh>F9n=OzZG!r z5tGTVk8RH-a8B4#<|U2k&47@JU*h@MY{t!UoQEA=62yJp#;^xnf~=9xha&rsi8vMH zHE!s8E{(4C=1?!`^r0PKL>9asAOd|J_M}2VEM_G^5@HH%JE0`305b0K<6W>)jpS^cQyDJN z*p|w8AQy9;?o$-TO6b>&Y@Ye2hBshV^rW&?)p Date: Thu, 21 Mar 2024 18:00:16 +0100 Subject: [PATCH 09/15] Fixed tests --- .../resources/ob30/simple-err-expired.json | 4 +- .../src/test/resources/ob30/simple.json | 37 +++++++++++-------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/inspector-vc/src/test/resources/ob30/simple-err-expired.json b/inspector-vc/src/test/resources/ob30/simple-err-expired.json index 1949ac7..ea9b3a8 100644 --- a/inspector-vc/src/test/resources/ob30/simple-err-expired.json +++ b/inspector-vc/src/test/resources/ob30/simple-err-expired.json @@ -35,12 +35,12 @@ "name": "Teamwork" } }, - "proof": { + "proof": [{ "type": "DataIntegrityProof", "created": "2010-01-01T19:23:24Z", "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", "cryptosuite": "eddsa-rdfc-2022", "proofPurpose": "assertionMethod", "proofValue": "z2mAP6ezimojRWSHDhS1VfJgDdMCqa4oPbmJT1tCs43t5bRiwsrrhHxrmTEeAF2EBjErrzxoJj3HCKsdkyVkno11f" - } + }] } \ No newline at end of file diff --git a/inspector-vc/src/test/resources/ob30/simple.json b/inspector-vc/src/test/resources/ob30/simple.json index 0543c90..c0776c4 100644 --- a/inspector-vc/src/test/resources/ob30/simple.json +++ b/inspector-vc/src/test/resources/ob30/simple.json @@ -4,20 +4,29 @@ "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" ], "id": "http://example.com/credentials/3527", - "type": ["VerifiableCredential", "OpenBadgeCredential"], + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], "issuer": { "id": "https://example.com/issuers/876543", - "type": ["Profile"], + "type": [ + "Profile" + ], "name": "Example Corp" }, "validFrom": "2010-01-01T00:00:00Z", "name": "Teamwork Badge", "credentialSubject": { "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", - "type": ["AchievementSubject"], + "type": [ + "AchievementSubject" + ], "achievement": { "id": "https://example.com/achievements/21st-century-skills/teamwork", - "type": ["Achievement"], + "type": [ + "Achievement" + ], "criteria": { "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." }, @@ -25,14 +34,12 @@ "name": "Teamwork" } }, - "proof": [ - { - "type": "DataIntegrityProof", - "created": "2024-03-20T14:53:19Z", - "verificationMethod": "https://example.com/issuers/876543#z6MkrvfzkMnvCroEUP2DVc9SHPE48CRsvHiVSusHioxTYu1x", - "cryptosuite": "eddsa-rdfc-2022", - "proofPurpose": "assertionMethod", - "proofValue": "z76jrNcyxHg5fV17h96yCRwqUaTQZD2QQivyNqHyLSvqu3aWGC3nLShzZEGbH3LnVFodwov9rPQxi3QRP7adCrzV" - } - ] -} + "proof": [{ + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://example.com/issuers/876543#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z41ZsNkz78FHSGkAD5J4b8EN49DkywMMJSL3UdUNffbsCAWmTLPvtnJpd3JGGooYX7TNrzgsTLkXUWiGsRRZ788ML" + }] +} \ No newline at end of file From 50b29ee1675528a8b66d271da31142a6fe5d828d Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 18:00:35 +0100 Subject: [PATCH 10/15] Added v2 version of W3C Verifiable Credential --- .../inspect/vc/VerifiableCredential.java | 52 +- .../org/oneedtech/inspect/vc/W3CVCHolder.java | 22 +- .../vc/W3CVerifiableCredentialDM2.java | 22 + .../inspect/vc/probe/EmbeddedProofProbe.java | 473 +++++++++--------- 4 files changed, 328 insertions(+), 241 deletions(-) create mode 100644 inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVerifiableCredentialDM2.java diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java index 3886f84..dc1b3e3 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/VerifiableCredential.java @@ -8,6 +8,8 @@ import static org.oneedtech.inspect.vc.VerifiableCredential.Type.VerifiablePrese import com.fasterxml.jackson.databind.JsonNode; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableMap; + +import java.net.URI; import java.util.Collections; import java.util.List; import java.util.Map; @@ -26,18 +28,19 @@ import org.oneedtech.inspect.vc.util.JsonNodeUtil; */ public class VerifiableCredential extends Credential { final VerifiableCredential.Type credentialType; + final VCVersion version; protected VerifiableCredential( Resource resource, JsonNode data, String jwt, Map schemas, - String issuedOnPropertyName, - String expiresAtPropertyName) { - super(ID, resource, data, jwt, schemas, issuedOnPropertyName, expiresAtPropertyName); + VCVersion version) { + super(ID, resource, data, jwt, schemas, version.issuanceDateField, version.expirationDateField); JsonNode typeNode = jsonData.get("type"); this.credentialType = VerifiableCredential.Type.valueOf(typeNode); + this.version = version; } public CredentialEnum getCredentialType() { @@ -48,6 +51,10 @@ public class VerifiableCredential extends Credential { return jwt == null ? ProofType.EMBEDDED : ProofType.EXTERNAL; } + public VCVersion getVersion() { + return version; + } + private static final Map schemas = new ImmutableMap.Builder() .put(AchievementCredential, Catalog.OB_30_ANY_ACHIEVEMENTCREDENTIAL_JSON) @@ -56,17 +63,19 @@ public class VerifiableCredential extends Credential { .put(EndorsementCredential, Catalog.OB_30_ANY_ENDORSEMENTCREDENTIAL_JSON) .build(); - private static final Map, List> contextMap = + public static final String JSONLD_CONTEXT_W3C_CREDENTIALS_V2 = "https://www.w3.org/ns/credentials/v2"; + + private static final Map, List> contextMap = new ImmutableMap.Builder, List>() .put( Set.of(Type.OpenBadgeCredential, AchievementCredential, EndorsementCredential), List.of( - "https://www.w3.org/ns/credentials/v2", + JSONLD_CONTEXT_W3C_CREDENTIALS_V2, "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json")) .put( Set.of(ClrCredential), List.of( - "https://www.w3.org/ns/credentials/v2", + JSONLD_CONTEXT_W3C_CREDENTIALS_V2, "https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1.json", "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json")) .build(); @@ -82,7 +91,7 @@ public class VerifiableCredential extends Credential { "https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1.json", List.of("https://purl.imsglobal.org/spec/clr/v2p0/context.json")) .put( - "https://www.w3.org/ns/credentials/v2", + JSONLD_CONTEXT_W3C_CREDENTIALS_V2, List.of("https://www.w3.org/2018/credentials/v1")) .build(); @@ -183,20 +192,39 @@ public class VerifiableCredential extends Credential { .toString(); } + public static enum VCVersion { + VCDMv2p0(ISSUED_ON_PROPERTY_NAME_V20, EXPIRES_AT_PROPERTY_NAME_V20), + VCDMv1p1(ISSUED_ON_PROPERTY_NAME_V11, EXPIRES_AT_PROPERTY_NAME_V11); + + final String issuanceDateField; + final String expirationDateField; + + VCVersion(String issuanceDateField, String expirationDateField) { + this.issuanceDateField = issuanceDateField; + this.expirationDateField = expirationDateField; + } + + static VCVersion of(JsonNode context) { + if (JsonNodeUtil.asNodeList(context) + .stream() + .anyMatch(node -> node.isTextual() && node.asText().equals(JSONLD_CONTEXT_W3C_CREDENTIALS_V2)) ) + return VCDMv2p0; + + return VCDMv1p1; + } + } + public static class Builder extends Credential.Builder { @Override public VerifiableCredential build() { - boolean is2p0VC = JsonNodeUtil.asNodeList(getJsonData().get("@context")) - .stream() - .anyMatch(node -> node.isTextual() && node.asText().equals("https://www.w3.org/ns/credentials/v2")); + VCVersion version = VCVersion.of(getJsonData().get("@context")); return new VerifiableCredential( getResource(), getJsonData(), getJwt(), schemas, - is2p0VC ? ISSUED_ON_PROPERTY_NAME_V20 : ISSUED_ON_PROPERTY_NAME_V11, - is2p0VC ? EXPIRES_AT_PROPERTY_NAME_V20 : EXPIRES_AT_PROPERTY_NAME_V11); + version); } } diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVCHolder.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVCHolder.java index e6e2b34..cc27088 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVCHolder.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVCHolder.java @@ -1,23 +1,33 @@ package org.oneedtech.inspect.vc; +import java.io.StringReader; import java.util.List; import org.oneedtech.inspect.vc.jsonld.JsonLDObjectUtils; import org.oneedtech.inspect.vc.util.CachingDocumentLoader; -import com.danubetech.verifiablecredentials.VerifiableCredential; - import info.weboftrust.ldsignatures.LdProof; /** * Holder for W3C's Verifiable Credential */ public class W3CVCHolder { - private VerifiableCredential credential; + private com.danubetech.verifiablecredentials.VerifiableCredential credential; public W3CVCHolder(VerifiableCredential credential) { - this.credential = credential; - credential.setDocumentLoader(new CachingDocumentLoader()); + switch (credential.version) { + case VCDMv1p1: + this.credential = com.danubetech.verifiablecredentials.VerifiableCredential + .fromJson(new StringReader(credential.getJson().toString())); + break; + case VCDMv2p0: + this.credential = W3CVerifiableCredentialDM2 + .fromJson(new StringReader(credential.getJson().toString())); + break; + default: + throw new IllegalArgumentException("Unsupported version: " + credential.version); + } + this.credential.setDocumentLoader(new CachingDocumentLoader()); } /** @@ -30,7 +40,7 @@ public class W3CVCHolder { return JsonLDObjectUtils.getListFromJsonLDObject(LdProof.class, credential); } - public VerifiableCredential getCredential() { + public com.danubetech.verifiablecredentials.VerifiableCredential getCredential() { return credential; } } diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVerifiableCredentialDM2.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVerifiableCredentialDM2.java new file mode 100644 index 0000000..cea520c --- /dev/null +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/W3CVerifiableCredentialDM2.java @@ -0,0 +1,22 @@ +package org.oneedtech.inspect.vc; + +import java.net.URI; +import java.util.Date; + +import foundation.identity.jsonld.JsonLDUtils; + +public class W3CVerifiableCredentialDM2 extends com.danubetech.verifiablecredentials.VerifiableCredential { + public static final URI[] DEFAULT_JSONLD_CONTEXTS = { URI.create(VerifiableCredential.JSONLD_CONTEXT_W3C_CREDENTIALS_V2) }; + + public Date getValidFrom() { + return JsonLDUtils.stringToDate(JsonLDUtils.jsonLdGetString(this.getJsonObject(), JSONLD_TERM_VALIDFROM)); + } + + public Date getValidUntil() { + return JsonLDUtils.stringToDate(JsonLDUtils.jsonLdGetString(this.getJsonObject(), JSONLD_TERM_VALIDUNTIL)); + } + + private static final String JSONLD_TERM_VALIDFROM = "validFrom"; + private static final String JSONLD_TERM_VALIDUNTIL = "validUntil"; + +} diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java index 2b57b1e..692efce 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java @@ -1,34 +1,30 @@ package org.oneedtech.inspect.vc.probe; -import java.io.StringReader; -import java.net.URI; -import java.net.URLEncoder; -import java.nio.charset.Charset; -import java.util.List; -import java.util.Optional; - -import org.oneedtech.inspect.core.probe.Probe; -import org.oneedtech.inspect.core.probe.RunContext; -import org.oneedtech.inspect.core.report.ReportItems; -import org.oneedtech.inspect.vc.VerifiableCredential; -import org.oneedtech.inspect.vc.W3CVCHolder; -import org.oneedtech.inspect.vc.verification.Ed25519Signature2022LdVerifier; - import com.apicatalog.jsonld.StringUtils; import com.apicatalog.jsonld.document.Document; import com.apicatalog.jsonld.loader.DocumentLoaderOptions; import com.apicatalog.multibase.Multibase; import com.apicatalog.multicodec.Multicodec; import com.apicatalog.multicodec.Multicodec.Codec; - import info.weboftrust.ldsignatures.LdProof; import info.weboftrust.ldsignatures.verifier.Ed25519Signature2020LdVerifier; import info.weboftrust.ldsignatures.verifier.LdVerifier; import jakarta.json.JsonArray; import jakarta.json.JsonObject; -import jakarta.json.JsonString; import jakarta.json.JsonStructure; import jakarta.json.JsonValue; +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Optional; +import org.oneedtech.inspect.core.probe.Probe; +import org.oneedtech.inspect.core.probe.RunContext; +import org.oneedtech.inspect.core.report.ReportItems; +import org.oneedtech.inspect.vc.VerifiableCredential; +import org.oneedtech.inspect.vc.W3CVCHolder; +import org.oneedtech.inspect.vc.verification.Ed25519Signature2022LdVerifier; +import org.oneedtech.inspect.vc.verification.Ed25519Signature2022VCDM20LdVerifier; /** * A Probe that verifies a credential's embedded proof. @@ -37,244 +33,275 @@ import jakarta.json.JsonValue; */ public class EmbeddedProofProbe extends Probe { - private final static List ALLOWED_CRYPTOSUITES = List.of("eddsa-2022", "eddsa-rdfc-2022"); + private static final List ALLOWED_CRYPTOSUITES = List.of("eddsa-2022", "eddsa-rdfc-2022"); - public EmbeddedProofProbe() { - super(ID); - } + public EmbeddedProofProbe() { + super(ID); + } - /* - * Using verifiable-credentials-java from Danubetech - * (https://github.com/danubetech/verifiable-credentials-java) - */ - @Override - public ReportItems run(VerifiableCredential crd, RunContext ctx) throws Exception { + /* + * Using verifiable-credentials-java from Danubetech + * (https://github.com/danubetech/verifiable-credentials-java) + */ + @Override + public ReportItems run(VerifiableCredential crd, RunContext ctx) throws Exception { - W3CVCHolder credentialHolder = new W3CVCHolder(com.danubetech.verifiablecredentials.VerifiableCredential - .fromJson(new StringReader(crd.getJson().toString()))); + W3CVCHolder credentialHolder = new W3CVCHolder(crd); - List proofs = credentialHolder.getProofs(); - if (proofs == null || proofs.size() == 0) { - return error("The verifiable credential is missing a proof.", ctx); - } + List proofs = credentialHolder.getProofs(); + if (proofs == null || proofs.size() == 0) { + return error("The verifiable credential is missing a proof.", ctx); + } - // get proof of standard type and purpose - Optional selectedProof = proofs.stream() - .filter(proof -> proof.getProofPurpose().equals("assertionMethod")) - .filter(proof -> proof.isType("Ed25519Signature2020") || - (proof.isType("DataIntegrityProof") && proof.getJsonObject().containsKey("cryptosuite") && ALLOWED_CRYPTOSUITES.contains(proof.getJsonObject().get("cryptosuite")))) - .findFirst(); + // get proof of standard type and purpose + Optional selectedProof = + proofs.stream() + .filter(proof -> proof.getProofPurpose().equals("assertionMethod")) + .filter( + proof -> + proof.isType("Ed25519Signature2020") + || (proof.isType("DataIntegrityProof") + && proof.getJsonObject().containsKey("cryptosuite") + && ALLOWED_CRYPTOSUITES.contains( + proof.getJsonObject().get("cryptosuite")))) + .findFirst(); - if (!selectedProof.isPresent()) { - return error("No proof with type any of (\"Ed25519Signature2020\", \"DataIntegrityProof\" with cryptosuite attr of \"eddsa-rdfc-2022\" or \"eddsa-2022\") or proof purpose \"assertionMethod\" found", ctx); - } + if (!selectedProof.isPresent()) { + return error( + "No proof with type any of (\"Ed25519Signature2020\", \"DataIntegrityProof\" with" + + " cryptosuite attr of \"eddsa-rdfc-2022\" or \"eddsa-2022\") or proof purpose" + + " \"assertionMethod\" found", + ctx); + } - LdProof proof = selectedProof.get(); + LdProof proof = selectedProof.get(); - URI method = proof.getVerificationMethod(); + URI method = proof.getVerificationMethod(); - // The verification method must dereference to an Ed25519VerificationKey2020. - // Danubetech's Ed25519Signature2020LdVerifier expects the decoded public key - // from the Ed25519VerificationKey2020 (32 bytes). - // - // Formats accepted: - // - // [controller]#[publicKeyMultibase] - // did:key:[publicKeyMultibase] - // did:web:[url-encoded domain-name][:path]* - // http/s://[location of a Ed25519VerificationKey2020 document] - // http/s://[location of a controller document with a 'verificationMethod' with - // a Ed25519VerificationKey2020] + // The verification method must dereference to an Ed25519VerificationKey2020. + // Danubetech's Ed25519Signature2020LdVerifier expects the decoded public key + // from the Ed25519VerificationKey2020 (32 bytes). + // + // Formats accepted: + // + // [controller]#[publicKeyMultibase] + // did:key:[publicKeyMultibase] + // did:web:[url-encoded domain-name][:path]* + // http/s://[location of a Ed25519VerificationKey2020 document] + // http/s://[location of a controller document with a 'verificationMethod' with + // a Ed25519VerificationKey2020] - String publicKeyMultibase; - String controller = null; + String publicKeyMultibase; + String controller = null; - publicKeyMultibase = method.toString(); + publicKeyMultibase = method.toString(); - if (method.getFragment() != null && IsValidPublicKeyMultibase(method.getFragment())) { - publicKeyMultibase = method.getFragment(); - controller = method.toString().substring(0, method.toString().indexOf("#")); - } else { - if (StringUtils.isBlank(method.getScheme())) { - return error("The verification method must be a valid URI (missing scheme)", ctx); - } else if (method.getScheme().equals("did")) { - if (method.getSchemeSpecificPart().startsWith("key:")) { - publicKeyMultibase = method.getSchemeSpecificPart().substring("key:".length()); - } else if (method.getSchemeSpecificPart().startsWith("web:")) { - String methodSpecificId = method.getRawSchemeSpecificPart().substring("web:".length()); + if (method.getFragment() != null && IsValidPublicKeyMultibase(method.getFragment())) { + publicKeyMultibase = method.getFragment(); + controller = method.toString().substring(0, method.toString().indexOf("#")); + } else { + if (StringUtils.isBlank(method.getScheme())) { + return error("The verification method must be a valid URI (missing scheme)", ctx); + } else if (method.getScheme().equals("did")) { + if (method.getSchemeSpecificPart().startsWith("key:")) { + publicKeyMultibase = method.getSchemeSpecificPart().substring("key:".length()); + } else if (method.getSchemeSpecificPart().startsWith("web:")) { + String methodSpecificId = method.getRawSchemeSpecificPart().substring("web:".length()); - // read algorithm at https://w3c-ccg.github.io/did-method-web/#read-resolve. - // Steps in comments + // read algorithm at https://w3c-ccg.github.io/did-method-web/#read-resolve. + // Steps in comments - // 1. Replace ":" with "/" in the method specific identifier to obtain the fully - // qualified domain name and optional path. - methodSpecificId = methodSpecificId.replaceAll(":", "/"); + // 1. Replace ":" with "/" in the method specific identifier to obtain the fully + // qualified domain name and optional path. + methodSpecificId = methodSpecificId.replaceAll(":", "/"); - // 2. If the domain contains a port percent decode the colon. - String portPercentEncoded = URLEncoder.encode(":", Charset.forName("UTF-8")); - int index = methodSpecificId.indexOf(portPercentEncoded); - if (index >= 0 && index < methodSpecificId.indexOf("/")) { - methodSpecificId = methodSpecificId.replace(portPercentEncoded, ":"); - } + // 2. If the domain contains a port percent decode the colon. + String portPercentEncoded = URLEncoder.encode(":", Charset.forName("UTF-8")); + int index = methodSpecificId.indexOf(portPercentEncoded); + if (index >= 0 && index < methodSpecificId.indexOf("/")) { + methodSpecificId = methodSpecificId.replace(portPercentEncoded, ":"); + } - // 3. Generate an HTTPS URL to the expected location of the DID document by - // prepending https://. - URI uri = new URI("https://" + methodSpecificId); + // 3. Generate an HTTPS URL to the expected location of the DID document by + // prepending https://. + URI uri = new URI("https://" + methodSpecificId); - // 4. If no path has been specified in the URL, append /.well-known. - if (uri.getPath() == null) { - uri = uri.resolve("/well-known"); - } + // 4. If no path has been specified in the URL, append /.well-known. + if (uri.getPath() == null) { + uri = uri.resolve("/well-known"); + } - // 5. Append /did.json to complete the URL. - uri = uri.resolve(uri.getPath() + "/did.json"); + // 5. Append /did.json to complete the URL. + uri = uri.resolve(uri.getPath() + "/did.json"); - // 6. Perform an HTTP GET request to the URL using an agent that can - // successfully negotiate a secure HTTPS connection, which enforces the security - // requirements as described in 2.6 Security and privacy considerations. - // 7. When performing the DNS resolution during the HTTP GET request, the client - // SHOULD utilize [RFC8484] in order to prevent tracking of the identity being - // resolved. - Optional keyStructure; - try { - Document keyDocument = credentialHolder.getCredential().getDocumentLoader().loadDocument(uri, - new DocumentLoaderOptions()); - keyStructure = keyDocument.getJsonContent(); - } catch (Exception e) { - return error("Key document not found at " + method + ". URI: " + uri - + " doesn't return a valid document. Reason: " + e.getMessage() + " ", ctx); - } - if (keyStructure.isEmpty()) { - return error("Key document not found at " + method + ". URI: " + uri - + " doesn't return a valid document. Reason: The document is empty.", ctx); - } + // 6. Perform an HTTP GET request to the URL using an agent that can + // successfully negotiate a secure HTTPS connection, which enforces the security + // requirements as described in 2.6 Security and privacy considerations. + // 7. When performing the DNS resolution during the HTTP GET request, the client + // SHOULD utilize [RFC8484] in order to prevent tracking of the identity being + // resolved. + Optional keyStructure; + try { + Document keyDocument = + credentialHolder + .getCredential() + .getDocumentLoader() + .loadDocument(uri, new DocumentLoaderOptions()); + keyStructure = keyDocument.getJsonContent(); + } catch (Exception e) { + return error( + "Key document not found at " + + method + + ". URI: " + + uri + + " doesn't return a valid document. Reason: " + + e.getMessage() + + " ", + ctx); + } + if (keyStructure.isEmpty()) { + return error( + "Key document not found at " + + method + + ". URI: " + + uri + + " doesn't return a valid document. Reason: The document is empty.", + ctx); + } - // check did in "assertionMethod" - JsonArray assertionMethod = keyStructure.get().asJsonObject() - .getJsonArray("assertionMethod"); - if (assertionMethod == null) { - return error("Document doesn't have a list of assertion methods at URI: " + uri, ctx); - } else { - Boolean anyMatch = false; - for(int i = 0; i < assertionMethod.size(); i++) { - String assertionMethodValue = assertionMethod.getString(i); - if (assertionMethodValue.equals(method.toString())) { - anyMatch = true; - break; - } - } - if (!anyMatch) { - return error("Assertion method " + method + " not found in DID document.", ctx); - } - } + // check did in "assertionMethod" + JsonArray assertionMethod = + keyStructure.get().asJsonObject().getJsonArray("assertionMethod"); + if (assertionMethod == null) { + return error("Document doesn't have a list of assertion methods at URI: " + uri, ctx); + } else { + Boolean anyMatch = false; + for (int i = 0; i < assertionMethod.size(); i++) { + String assertionMethodValue = assertionMethod.getString(i); + if (assertionMethodValue.equals(method.toString())) { + anyMatch = true; + break; + } + } + if (!anyMatch) { + return error("Assertion method " + method + " not found in DID document.", ctx); + } + } - // get keys from "verificationMethod" - JsonArray keyVerificationMethod = keyStructure.get().asJsonObject() - .getJsonArray("verificationMethod"); - if (keyVerificationMethod == null) { - return error("Document doesn't have a list of verification methods at URI: " + uri, ctx); - } - Optional verificationMethodMaybe = keyVerificationMethod.stream() - .filter(n -> n.asJsonObject().getString("id").equals(method.toString())) - .findFirst(); - if (verificationMethodMaybe.isEmpty()) { - return error("Verification method " + method + " not found in DID document.", ctx); - } - JsonObject verificationMethod = verificationMethodMaybe.get().asJsonObject(); - // assuming a Ed25519VerificationKey2020 document - controller = verificationMethod.getString("controller"); - publicKeyMultibase = verificationMethod.getString("publicKeyMultibase"); + // get keys from "verificationMethod" + JsonArray keyVerificationMethod = + keyStructure.get().asJsonObject().getJsonArray("verificationMethod"); + if (keyVerificationMethod == null) { + return error( + "Document doesn't have a list of verification methods at URI: " + uri, ctx); + } + Optional verificationMethodMaybe = + keyVerificationMethod.stream() + .filter(n -> n.asJsonObject().getString("id").equals(method.toString())) + .findFirst(); + if (verificationMethodMaybe.isEmpty()) { + return error("Verification method " + method + " not found in DID document.", ctx); + } + JsonObject verificationMethod = verificationMethodMaybe.get().asJsonObject(); + // assuming a Ed25519VerificationKey2020 document + controller = verificationMethod.getString("controller"); + publicKeyMultibase = verificationMethod.getString("publicKeyMultibase"); - } else { - return error("Unknown verification method: " + method, ctx); - } - } else if (method.getScheme().equals("http") || method.getScheme().equals("https")) { - try { - Document keyDocument = credentialHolder.getCredential().getDocumentLoader().loadDocument(method, - new DocumentLoaderOptions()); - Optional keyStructure = keyDocument.getJsonContent(); - if (keyStructure.isEmpty()) { - return error("Key document not found at " + method, ctx); - } + } else { + return error("Unknown verification method: " + method, ctx); + } + } else if (method.getScheme().equals("http") || method.getScheme().equals("https")) { + try { + Document keyDocument = + credentialHolder + .getCredential() + .getDocumentLoader() + .loadDocument(method, new DocumentLoaderOptions()); + Optional keyStructure = keyDocument.getJsonContent(); + if (keyStructure.isEmpty()) { + return error("Key document not found at " + method, ctx); + } - // First look for a Ed25519VerificationKey2020 document - controller = keyStructure.get().asJsonObject().getString("controller"); - if (StringUtils.isBlank(controller)) { - // Then look for a controller document (e.g. DID Document) with a - // 'verificationMethod' - // that is a Ed25519VerificationKey2020 document - JsonObject keyVerificationMethod = keyStructure.get().asJsonObject() - .getJsonObject("verificationMethod"); - if (keyVerificationMethod.isEmpty()) { - return error("Cannot parse key document from " + method, ctx); - } - controller = keyVerificationMethod.getString("controller"); - publicKeyMultibase = keyVerificationMethod.getString("publicKeyMultibase"); - } else { - publicKeyMultibase = keyStructure.get().asJsonObject().getString("publicKeyMultibase"); - } + // First look for a Ed25519VerificationKey2020 document + controller = keyStructure.get().asJsonObject().getString("controller"); + if (StringUtils.isBlank(controller)) { + // Then look for a controller document (e.g. DID Document) with a + // 'verificationMethod' + // that is a Ed25519VerificationKey2020 document + JsonObject keyVerificationMethod = + keyStructure.get().asJsonObject().getJsonObject("verificationMethod"); + if (keyVerificationMethod.isEmpty()) { + return error("Cannot parse key document from " + method, ctx); + } + controller = keyVerificationMethod.getString("controller"); + publicKeyMultibase = keyVerificationMethod.getString("publicKeyMultibase"); + } else { + publicKeyMultibase = keyStructure.get().asJsonObject().getString("publicKeyMultibase"); + } - } catch (Exception e) { - return error("Invalid verification key URL: " + e.getMessage(), ctx); - } - } else { - return error("Unknown verification method scheme: " + method.getScheme(), ctx); - } - } + } catch (Exception e) { + return error("Invalid verification key URL: " + e.getMessage(), ctx); + } + } else { + return error("Unknown verification method scheme: " + method.getScheme(), ctx); + } + } - // Decode the Multibase to Multicodec and check that it is an Ed25519 public key - // https://w3c-ccg.github.io/di-eddsa-2020/#ed25519verificationkey2020 - byte[] publicKeyMulticodec; - try { - publicKeyMulticodec = Multibase.decode(publicKeyMultibase); - if (publicKeyMulticodec[0] != (byte) 0xed || publicKeyMulticodec[1] != (byte) 0x01) { - return error("Verification method does not contain an Ed25519 public key", ctx); - } - } catch (Exception e) { - return error("Invalid public key: " + e.getMessage(), ctx); - } + // Decode the Multibase to Multicodec and check that it is an Ed25519 public key + // https://w3c-ccg.github.io/di-eddsa-2020/#ed25519verificationkey2020 + byte[] publicKeyMulticodec; + try { + publicKeyMulticodec = Multibase.decode(publicKeyMultibase); + if (publicKeyMulticodec[0] != (byte) 0xed || publicKeyMulticodec[1] != (byte) 0x01) { + return error("Verification method does not contain an Ed25519 public key", ctx); + } + } catch (Exception e) { + return error("Invalid public key: " + e.getMessage(), ctx); + } - if (controller != null) { - if (!controller.equals(credentialHolder.getCredential().getIssuer().toString())) { - return error("Key controller does not match issuer: " + credentialHolder.getCredential().getIssuer(), - ctx); - } - } + if (controller != null) { + if (!controller.equals(credentialHolder.getCredential().getIssuer().toString())) { + return error( + "Key controller does not match issuer: " + credentialHolder.getCredential().getIssuer(), + ctx); + } + } - // Extract the publicKey bytes from the Multicodec - byte[] publicKey = Multicodec.decode(Codec.Ed25519PublicKey, publicKeyMulticodec); + // Extract the publicKey bytes from the Multicodec + byte[] publicKey = Multicodec.decode(Codec.Ed25519PublicKey, publicKeyMulticodec); - // choose verifier - LdVerifier verifier = getVerifier(proof, publicKey); + // choose verifier + LdVerifier verifier = getVerifier(proof, publicKey, crd); - try { - boolean verify = verifier.verify(credentialHolder.getCredential(), proof); - if (!verify) { - return error("Embedded proof verification failed.", ctx); - } - } catch (Exception e) { - return fatal("Embedded proof verification failed: " + e.getMessage(), ctx); - } + try { + boolean verify = verifier.verify(credentialHolder.getCredential(), proof); + if (!verify) { + return error("Embedded proof verification failed.", ctx); + } + } catch (Exception e) { + return fatal("Embedded proof verification failed: " + e.getMessage(), ctx); + } - return success(ctx); - } + return success(ctx); + } - private LdVerifier getVerifier(LdProof proof, byte[] publicKey) { - return proof.isType("Ed25519Signature2020") - ? new Ed25519Signature2020LdVerifier(publicKey) - : new Ed25519Signature2022LdVerifier(publicKey); - } + private LdVerifier getVerifier(LdProof proof, byte[] publicKey, VerifiableCredential crd) { + return proof.isType("Ed25519Signature2020") + ? new Ed25519Signature2020LdVerifier(publicKey) + : crd.getVersion() == VerifiableCredential.VCVersion.VCDMv1p1 + ? new Ed25519Signature2022LdVerifier(publicKey) + : new Ed25519Signature2022VCDM20LdVerifier(publicKey); + } - private Boolean IsValidPublicKeyMultibase(String publicKeyMultibase) { - try { - byte[] publicKeyMulticodec = Multibase.decode(publicKeyMultibase); - byte[] publicKey = Multicodec.decode(Codec.Ed25519PublicKey, publicKeyMulticodec); - return publicKey.length == 32; - } catch (Exception e) { - return false; - } + private Boolean IsValidPublicKeyMultibase(String publicKeyMultibase) { + try { + byte[] publicKeyMulticodec = Multibase.decode(publicKeyMultibase); + byte[] publicKey = Multicodec.decode(Codec.Ed25519PublicKey, publicKeyMulticodec); + return publicKey.length == 32; + } catch (Exception e) { + return false; + } + } - } - - public static final String ID = EmbeddedProofProbe.class.getSimpleName(); + public static final String ID = EmbeddedProofProbe.class.getSimpleName(); } From bb38df634456c862ac086fa6eeb5099babaad813 Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 18:13:10 +0100 Subject: [PATCH 11/15] Update testEddsa2022Valid to testEddsa2022Warning --- .../src/test/java/org/oneedtech/inspect/vc/OB30Tests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java index 046c876..a92a52d 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/OB30Tests.java @@ -390,11 +390,11 @@ public class OB30Tests { } @Test - void testEddsa2022Valid() { + void testEddsa2022Warning() { assertDoesNotThrow(()->{ Report report = validator.run(Samples.OB30.JSON.SIMPLE_EDDSA_20222_JSON.asFileResource()); if(verbose) PrintHelper.print(report, true); - assertValid(report); + assertWarning(report); }); } From c0495dc41a8ede624621e9ebe04454a803ad8ce9 Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 18:14:35 +0100 Subject: [PATCH 12/15] Updated version --- inspector-vc-web/pom.xml | 2 +- inspector-vc/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/inspector-vc-web/pom.xml b/inspector-vc-web/pom.xml index 13891cd..4dd572c 100644 --- a/inspector-vc-web/pom.xml +++ b/inspector-vc-web/pom.xml @@ -6,7 +6,7 @@ org.1edtech vc-public-validator - 1.0.4 + 1.0.5 inspector-vc-web diff --git a/inspector-vc/pom.xml b/inspector-vc/pom.xml index 238d5a0..4870bbe 100644 --- a/inspector-vc/pom.xml +++ b/inspector-vc/pom.xml @@ -5,7 +5,7 @@ org.1edtech vc-public-validator - 1.0.4 + 1.0.5 inspector-vc diff --git a/pom.xml b/pom.xml index 44208b7..f498fc0 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.1edtech vc-public-validator - 1.0.4 + 1.0.5 vc-public-validator pom From e0ff4598db96d6add84fc5635ece78abef719e74 Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 18:26:02 +0100 Subject: [PATCH 13/15] Remove unused sample --- inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java | 1 - 1 file changed, 1 deletion(-) diff --git a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java index b64faae..3a2176f 100644 --- a/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java +++ b/inspector-vc/src/test/java/org/oneedtech/inspect/vc/Samples.java @@ -10,7 +10,6 @@ public class Samples { } public static final class JSON { public final static Sample COMPLETE_JSON = new Sample("ob30/complete.json", false); - public final static Sample BUG_JSON = new Sample("ob30/bug.json", false); public final static Sample SIMPLE_JSON = new Sample("ob30/simple.json", true); public final static Sample SIMPLE_V1_JSON = new Sample("ob30/simple_v1.json", true); public final static Sample SIMPLE_EDDSA_20222_JSON = new Sample("ob30/simple-eddsa-2022.json", true); From e1b831d251bd2871199f1549d1fa1b188f82314c Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 18:33:57 +0100 Subject: [PATCH 14/15] check issuer only if provided --- .../java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java index 692efce..8d5cbd9 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/probe/EmbeddedProofProbe.java @@ -259,7 +259,7 @@ public class EmbeddedProofProbe extends Probe { return error("Invalid public key: " + e.getMessage(), ctx); } - if (controller != null) { + if (controller != null && credentialHolder.getCredential().getIssuer() != null) { if (!controller.equals(credentialHolder.getCredential().getIssuer().toString())) { return error( "Key controller does not match issuer: " + credentialHolder.getCredential().getIssuer(), From ae0f590e98de780e87f076555809e5c1c0154bdf Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Thu, 21 Mar 2024 18:34:01 +0100 Subject: [PATCH 15/15] Updated test --- .../resources/ob30/endorsement-valid.json | 74 ++++++++++--------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/inspector-vc/src/test/resources/ob30/endorsement-valid.json b/inspector-vc/src/test/resources/ob30/endorsement-valid.json index e04a1c0..39ab18e 100644 --- a/inspector-vc/src/test/resources/ob30/endorsement-valid.json +++ b/inspector-vc/src/test/resources/ob30/endorsement-valid.json @@ -1,39 +1,43 @@ { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://purl.imsglobal.org/spec/ob/v3p0/context.json", - "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json", - "https://w3id.org/security/suites/ed25519-2020/v1" - ], - "id": "http://1edtech.edu/endorsementcredential/3732", + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3732", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "issuer": { + "id": "https://state.gov/issuers/565049", "type": [ - "VerifiableCredential", - "EndorsementCredential" + "Profile" ], - "issuer": { - "id": "https://state.gov/issuers/565049", - "type": ["Profile"], - "name": "State Department of Education" - }, - "issuanceDate": "2010-01-01T00:00:00Z", - "expirationDate": "2030-01-01T00:00:00Z", - "name": "Example endorsement", - "credentialSubject": { - "id": "https://1edtech.edu/issuers/565049", - "type": ["EndorsementSubject"], - "endorsementComment": "1EdTech University is in good standing" - }, - "credentialSchema": [ - { - "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", - "type": "1EdTechJsonSchemaValidator2019" - } + "name": "State Department of Education" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2030-01-01T00:00:00Z", + "name": "Example endorsement", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" ], - "proof": [{ - "type": "Ed25519Signature2020", - "created": "2010-01-01T19:23:24Z", - "verificationMethod": "https://state.gov/issuers/565049#z6MkjZRZv3aez3r18pB1RBFJR1kwUVJ5jHt92JmQwXbd5hwi", - "proofPurpose": "assertionMethod", - "proofValue": "z347N8ntbL3usCGshtUZiyrBeGBhYVAqyi4HUhz4fBmU1zVwk5eRfPZJvKoendfyGaeSbJcAfQEVNpvcHLzVhDtQC" - }] - } \ No newline at end of file + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "proof": [{ + "type": "DataIntegrityProof", + "created": "2010-01-01T19:23:24Z", + "verificationMethod": "https://state.gov/issuers/565049#z6MkoMGF38Ck9xkdqrbZt4h9eHb1qc3GhAAkoSWa4Vy3SHRN", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z4DKZeDFKKvz5dDVPEky9NU8Zk3J8tH62Vtnm7drwwvPhDKwd6wL6td8skZkbyqw17y5zNJxfjT42dKpQc3Mgx1x6" + }] +} \ No newline at end of file