Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add vcdm 2.0 model and context #3436

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7ba9b99
add vcdm 2.0 model and context
PatStLouis Jan 10, 2025
9879a4a
add backwards compatibility checks: limit proof type and add issuance…
PatStLouis Jan 10, 2025
262ae0a
seperate test fixtures, lint
PatStLouis Jan 10, 2025
5951683
replace issuanceDate tests
PatStLouis Jan 10, 2025
3383cd5
Merge branch 'openwallet-foundation:main' into vcdm-2.0-data-model-su…
PatStLouis Jan 14, 2025
909e187
Merge branch 'openwallet-foundation:main' into vcdm-2.0-data-model-su…
PatStLouis Jan 21, 2025
db5d959
remove askar issuanceDate sorting
PatStLouis Jan 21, 2025
b9a8049
Merge branch 'vcdm-2.0-data-model-support' of github.com:OpSecId/arie…
PatStLouis Jan 21, 2025
0025828
rename credential context constant
PatStLouis Jan 21, 2025
ede1d4b
linting
PatStLouis Jan 21, 2025
19df824
updated linting
PatStLouis Jan 21, 2025
41c7b14
remove askar sorting step
PatStLouis Jan 21, 2025
a7c4243
add vcdm 2.0 tests, fix presentation route default cryptosuite
PatStLouis Jan 21, 2025
286a18c
Fix broken tests, add v2 context to test document loader
PatStLouis Jan 21, 2025
12b8298
Lint
PatStLouis Jan 21, 2025
830201c
Debugging unit tests
PatStLouis Jan 21, 2025
c46c816
Merge branch 'openwallet-foundation:main' into vcdm-2.0-data-model-su…
PatStLouis Jan 27, 2025
efdd239
Merge branch 'vcdm-2.0-data-model-support' of github.com:OpSecId/arie…
PatStLouis Jan 27, 2025
c16c4a0
rename test function to v2
PatStLouis Jan 27, 2025
2c09df6
add list of support cryptosuites for vcdm 2.0
PatStLouis Jan 27, 2025
2f17be3
add list of supported cryptosuites for vcdm 2.0
PatStLouis Jan 27, 2025
a08d72c
fix presentation fixture
PatStLouis Jan 27, 2025
286d345
fix created format check
PatStLouis Jan 27, 2025
09d3d74
fix tset fixtures
PatStLouis Jan 27, 2025
1cfe448
lint
PatStLouis Jan 27, 2025
1765caa
add authentication proof purpose
PatStLouis Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions acapy_agent/messaging/valid.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,8 +875,11 @@ def __call__(self, value):
class CredentialContext(Validator):
"""Credential Context."""

FIRST_CONTEXT = "https://www.w3.org/2018/credentials/v1"
EXAMPLE = [FIRST_CONTEXT, "https://www.w3.org/2018/credentials/examples/v1"]
FIRST_CONTEXT = [
PatStLouis marked this conversation as resolved.
Show resolved Hide resolved
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/ns/credentials/v2",
]
EXAMPLE = [FIRST_CONTEXT[0], "https://www.w3.org/2018/credentials/examples/v1"]

def __init__(self) -> None:
"""Initialize the instance."""
Expand All @@ -886,9 +889,9 @@ def __call__(self, value):
"""Validate input value."""
length = len(value)

if length < 1 or value[0] != CredentialContext.FIRST_CONTEXT:
if length < 1 or value[0] not in CredentialContext.FIRST_CONTEXT:
raise ValidationError(
f"First context must be {CredentialContext.FIRST_CONTEXT}"
f"First context must be one of {CredentialContext.FIRST_CONTEXT}"
)

return value
PatStLouis marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
1 change: 1 addition & 0 deletions acapy_agent/vc/ld_proofs/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
SECURITY_CONTEXT_URL = SECURITY_CONTEXT_V2_URL
DID_V1_CONTEXT_URL = "https://www.w3.org/ns/did/v1"
CREDENTIALS_CONTEXT_V1_URL = "https://www.w3.org/2018/credentials/v1"
CREDENTIALS_CONTEXT_V2_URL = "https://www.w3.org/ns/credentials/v2"
SECURITY_CONTEXT_BBS_URL = "https://w3id.org/security/bbs/v1"
SECURITY_CONTEXT_ED25519_2020_URL = "https://w3id.org/security/suites/ed25519-2020/v1"

Expand Down
1 change: 1 addition & 0 deletions acapy_agent/vc/ld_proofs/document_downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class StaticCacheJsonLdDownloader:

CONTEXT_FILE_MAPPING = {
"https://www.w3.org/2018/credentials/v1": "credentials_context.jsonld",
"https://www.w3.org/ns/credentials/v2": "credentials_v2_context.jsonld",
"https://w3id.org/vc/status-list/2021/v1": "status_list_context.jsonld",
"https://www.w3.org/ns/did/v1": "did_documents_context.jsonld",
"https://w3id.org/security/v1": "security-v1-context.jsonld",
Expand Down
301 changes: 301 additions & 0 deletions acapy_agent/vc/ld_proofs/resources/credentials_v2_context.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
{
"@context": {
"@protected": true,
"id": "@id",
"type": "@type",
"description": "https://schema.org/description",
"digestMultibase": {
"@id": "https://w3id.org/security#digestMultibase",
"@type": "https://w3id.org/security#multibase"
},
"digestSRI": {
"@id": "https://www.w3.org/2018/credentials#digestSRI",
"@type": "https://www.w3.org/2018/credentials#sriString"
},
"mediaType": {
"@id": "https://schema.org/encodingFormat"
},
"name": "https://schema.org/name",
"VerifiableCredential": {
"@id": "https://www.w3.org/2018/credentials#VerifiableCredential",
"@context": {
"@protected": true,
"id": "@id",
"type": "@type",
"confidenceMethod": {
"@id": "https://www.w3.org/2018/credentials#confidenceMethod",
"@type": "@id"
},
"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"
},
"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"
},
"relatedResource": {
"@id": "https://www.w3.org/2018/credentials#relatedResource",
"@type": "@id"
},
"renderMethod": {
"@id": "https://www.w3.org/2018/credentials#renderMethod",
"@type": "@id"
},
"termsOfUse": {
"@id": "https://www.w3.org/2018/credentials#termsOfUse",
"@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"
}
}
},
"EnvelopedVerifiableCredential": "https://www.w3.org/2018/credentials#EnvelopedVerifiableCredential",
"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"
},
"termsOfUse": {
"@id": "https://www.w3.org/2018/credentials#termsOfUse",
"@type": "@id"
},
"verifiableCredential": {
"@id": "https://www.w3.org/2018/credentials#verifiableCredential",
"@type": "@id",
"@container": "@graph",
"@context": null
}
}
},
"EnvelopedVerifiablePresentation": "https://www.w3.org/2018/credentials#EnvelopedVerifiablePresentation",
"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://www.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",
"encodedList": {
"@id": "https://www.w3.org/ns/credentials/status#encodedList",
"@type": "https://w3id.org/security#multibase"
},
"statusMessage": {
"@id": "https://www.w3.org/ns/credentials/status#statusMessage",
"@context": {
"@protected": true,
"id": "@id",
"type": "@type",
"message": "https://www.w3.org/ns/credentials/status#message",
"status": "https://www.w3.org/ns/credentials/status#status"
}
},
"statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose",
"statusReference": {
"@id": "https://www.w3.org/ns/credentials/status#statusReference",
"@type": "@id"
},
"statusSize": {
"@id": "https://www.w3.org/ns/credentials/status#statusSize",
"@type": "https://www.w3.org/2001/XMLSchema#positiveInteger"
},
"ttl": "https://www.w3.org/ns/credentials/status#ttl"
}
},
"BitstringStatusListEntry": {
"@id": "https://www.w3.org/ns/credentials/status#BitstringStatusListEntry",
"@context": {
"@protected": true,
"id": "@id",
"type": "@type",
"statusListCredential": {
"@id": "https://www.w3.org/ns/credentials/status#statusListCredential",
"@type": "@id"
},
"statusListIndex": "https://www.w3.org/ns/credentials/status#statusListIndex",
"statusPurpose": "https://www.w3.org/ns/credentials/status#statusPurpose"
}
},
"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"
},
"cryptosuite": {
"@id": "https://w3id.org/security#cryptosuite",
"@type": "https://w3id.org/security#cryptosuiteString"
},
"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"
},
"capabilityDelegation": {
"@id": "https://w3id.org/security#capabilityDelegationMethod",
"@type": "@id",
"@container": "@set"
},
"capabilityInvocation": {
"@id": "https://w3id.org/security#capabilityInvocationMethod",
"@type": "@id",
"@container": "@set"
},
"keyAgreement": {
"@id": "https://w3id.org/security#keyAgreementMethod",
"@type": "@id",
"@container": "@set"
}
}
},
"proofValue": {
"@id": "https://w3id.org/security#proofValue",
"@type": "https://w3id.org/security#multibase"
},
"verificationMethod": {
"@id": "https://w3id.org/security#verificationMethod",
"@type": "@id"
}
}
},
"...": {
"@id": "https://www.iana.org/assignments/jwt#..."
},
"_sd": {
"@id": "https://www.iana.org/assignments/jwt#_sd",
"@type": "@json"
},
"_sd_alg": {
"@id": "https://www.iana.org/assignments/jwt#_sd_alg"
},
"aud": {
"@id": "https://www.iana.org/assignments/jwt#aud",
"@type": "@id"
},
"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"
}
}
},
"exp": {
"@id": "https://www.iana.org/assignments/jwt#exp",
"@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"
},
"iss": {
"@id": "https://www.iana.org/assignments/jose#iss",
"@type": "@id"
},
"jku": {
"@id": "https://www.iana.org/assignments/jose#jku",
"@type": "@id"
},
"kid": {
"@id": "https://www.iana.org/assignments/jose#kid",
"@type": "@id"
},
"nbf": {
"@id": "https://www.iana.org/assignments/jwt#nbf",
"@type": "https://www.w3.org/2001/XMLSchema#nonNegativeInteger"
},
"sub": {
"@id": "https://www.iana.org/assignments/jose#sub",
"@type": "@id"
},
"x5u": {
"@id": "https://www.iana.org/assignments/jose#x5u",
"@type": "@id"
}
}
}
19 changes: 18 additions & 1 deletion acapy_agent/vc/vc_ld/manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Manager for performing Linked Data Proof signatures over JSON-LD formatted W3C VCs."""

from datetime import datetime, timezone
from typing import Dict, List, Optional, Type, Union, cast

from pyld import jsonld
Expand All @@ -14,6 +15,8 @@
from ...wallet.error import WalletNotFoundError
from ...wallet.key_type import BLS12381G2, ED25519, KeyType
from ..ld_proofs.constants import (
CREDENTIALS_CONTEXT_V1_URL,
CREDENTIALS_CONTEXT_V2_URL,
SECURITY_CONTEXT_BBS_URL,
SECURITY_CONTEXT_ED25519_2020_URL,
)
Expand Down Expand Up @@ -271,6 +274,12 @@ async def prepare_credential(
and SECURITY_CONTEXT_ED25519_2020_URL not in credential.context_urls
):
credential.add_context(SECURITY_CONTEXT_ED25519_2020_URL)
# Limit VCDM 2.0 with Ed25519Signature2020
elif (
options.proof_type == Ed25519Signature2018.signature_type
PatStLouis marked this conversation as resolved.
Show resolved Hide resolved
and credential.context_urls[0] == CREDENTIALS_CONTEXT_V2_URL
):
raise VcLdpManagerError("Invalid proof type, use Ed25519Signature2020.")

# Permit late binding of credential subject:
# IFF credential subject doesn't already have an id, add holder_did as
Expand All @@ -281,7 +290,15 @@ async def prepare_credential(
# How should this be handled?
if isinstance(subject, list):
subject = subject[0]


if (
not credential.issuance_date
and credential.context_urls[0] == CREDENTIALS_CONTEXT_V1_URL
):
credential.issuance_date = str(
datetime.now(timezone.utc).isoformat('T', 'seconds')
)

if not subject:
raise VcLdpManagerError("Credential subject is required")

Expand Down
Loading
Loading