# ACA-PY JSON-LD Signatures The following commit introduced a plugin to sign and verify JSON-LD VCs using LD Signatures ``` https://github.com/hyperledger/aries-cloudagent-python/commit/3d4c63b66b03a5e533f1ee88628cabb32aade5c8 ``` ## Register Plugin The plugin is not registered per default. There are two ways to register a plugin. 1. Load the plugin when starting ACA-PY `--plugin aries_cloudagent.messaging.jsonld` 3. Register plugin in the default_context To register the plugin in the default_context you have to add it in `./config/default_context` ``` async def load_plugins(self, context: InjectionContext): """Set up plugin registry and load plugins.""" plugin_registry = PluginRegistry() context.injector.bind_instance(PluginRegistry, plugin_registry) # Register standard protocol plugins ... plugin_registry.register_plugin("aries_cloudagent.messaging.jsonld") ... ``` ## Start Agent For example with the following command ``` PORTS="8000:8000 1000:1000" ./scripts/run_docker start 0.0.0.0 8000 --inbound-transport http 0.0.0.0 10000 --outbound-transport http --log-level DEBUG --admin --admin-insecure-mode --plugin aries_cloudagent.messaging.jsonld ``` Now, we have the following two new admin routes available: ![](https://i.imgur.com/htj9sVj.png) ### Signing a JSON-LD VC The signing API is pretty low level and does not provide a lot of validation. It only supports LD-Signatures of type `Ed25519Signature2018`. It takes a JSON body of the following form ``` { "verkey": "8yvKE7H77rx7vGF3VUEU1cjjMgTT1qJzSkDsrURcmp8T", "doc": { "credential": { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "http://example.gov/credentials/3732", "type": [ "VerifiableCredential", "UniversityDegreeCredential" ], "issuer": "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", "issuanceDate": "2020-03-10T04:24:12.164Z", "credentialSubject": { "id": "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", "degree": { "type": "BachelorDegree", "name": "Bachelor of Science and Arts" } } }, "options": { "type": "Ed25519Signature2018", "created": "2020-04-10T21:35:35Z", "verificationMethod": "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd#z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", "proofPurpose": "assertionMethod" } } } ``` `verkey` has to be in the wallet. `doc` is the actual JSON-LD document. I'm not sure if really only valid JSON-LD or even a valid JSON-LD VC is accepted `options` does at least require the specification of `verificationMethod`, but there is no validation if the verificationMethod can be used to verify the signature. In the example above the verificationMethod is no relation to the key that is actually used to sign the VC. The response `signed_doc` contains the LD Signature. There is JSON-LD processing in the background: * Adding a property that is not defined in the context will lead to an error: ``` { "error": "Extra Attribute Detected" } ``` * Removing the context leads to: ``` { "error": "not enough values to unpack (expected 1, got 0)" } ``` #### Signing a JSON-LD VP ``` { "verkey": "Adqw7ULX1oKKRodGymdA3u23igdngimhE9MoE5sUaTEm", "doc": { "credential": { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "http://example.gov/credentials/3732", "type": ["VerifiablePresentation"], "verifiableCredential": [ { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "http://example.gov/credentials/3732", "type": ["VerifiableCredential"], "credentialSubject": {} } ] }, "options": { "type": "Ed25519Signature2018", "created": "2020-04-10T21:35:35Z", "verificationMethod": "did:key:Adqw7ULX1oKKRodGymdA3u23igdngimhE9MoE5sUaTEm#Adqw7ULX1oKKRodGymdA3u23igdngimhE9MoE5sUaTEm", "proofPurpose": "assertionMethod" } } } ``` returns ``` { "signed_doc": { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "http://example.gov/credentials/3732", "type": [ "VerifiablePresentation" ], "verifiableCredential": [ { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "http://example.gov/credentials/3732", "type": [ "VerifiableCredential" ], "credentialSubject": {} } ], "proof": { "type": "Ed25519Signature2018", "created": "2020-04-10T21:35:35Z", "verificationMethod": "did:key:Adqw7ULX1oKKRodGymdA3u23igdngimhE9MoE5sUaTEm#Adqw7ULX1oKKRodGymdA3u23igdngimhE9MoE5sUaTEm", "proofPurpose": "assertionMethod", "jws": "eyJhbGciOiAiRWREU0EiLCAiYjY0IjogZmFsc2UsICJjcml0IjogWyJiNjQiXX0..aP6VxoypNwjjZ2i0FNIQPoyehGzEyK-GowS1fBxXH6_xRXb3Ktk9eEujGQoIHHGFqVvENOLrcjVS08w6hgknCA" } } } ``` ### Verifying a JSON-LD VC The verifying API accepts a JSON document containing ``` { "verkey": "doc": } ``` An example using the LD signature from above ``` { "verkey": "8yvKE7H77rx7vGF3VUEU1cjjMgTT1qJzSkDsrURcmp8T", "doc": { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1" ], "id": "http://example.gov/credentials/3732", "type": [ "VerifiableCredential", "UniversityDegreeCredential" ], "issuer":"did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", "issuanceDate": "2020-03-10T04:24:12.164Z", "credentialSubject": { "id": "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", "degree": { "type": "BachelorDegree", "name": "Bachelor of Science and Arts" } }, "proof": { "verificationMethod": "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd#z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", "created": "2020-06-10T19:34:42Z", "type": "Ed25519Signature2018", "jws": "eyJhbGciOiAiRWREU0EiLCAiYjY0IjogZmFsc2UsICJjcml0IjogWyJiNjQiXX0..yP9KnkUKZ0aDwA-ErR_MznErIB6mArewLaoP3jBr4O6NVs2W-8a7M0kFeIR7mxCBRJBPbnaM0CrI5PQDttDHDA" } } } ``` Again the LD Signature is verifed using the explicitly provided `verkey`. The `verificationMethod` is neglected and there is also no validation that the `issuer` property is in any relation to the `verificationMethod` ## Significance for IIL-core We could now use the ACA-PY REST API to sign and verify JSON-LD VCs. For signing, We still have to provide the logic to properly construct the VC in IIl-core. For verification, we have to do quite some validation and DID resolution in IIL-core. This leaves the question if we should not just try see how we can add these features to ACA-PY itself. ### Signing using the public DID *We sign only the presentation* Assuming the agent is registered on the ledger, we can get the verkey of the public DID by ``` GET: /wallet/did/public ``` which returns something like ``` { "result": { "verkey": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", "public": true, "did": "WgWxqztrNooG92RXvxSTWv" } } ``` Given this `verkey` and `did` we can construct the body for ``` POST: /jsonld/sign ``` Presentations specify a *holder*, not an *issuer*. ``` { "verkey": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" "doc" : { "credential" { ... "holder": "did:sov:iil:WgWxqztrNooG92RXvxSTWv" ... }, "options": { "verificationMethod": "did:sov:iil:WgWxqztrNooG92RXvxSTWv#key-1" } } } ``` ### Verifying **Scope** In the first step, we assume a presentation consisting of only one verifiable credential which would be self-signed. However, since we wrap it in a signed presentation we don't need to sign the credential itself. We do not include additional third party signed VCs. We will add this later on. In IIL-core, we would have to do the following 1. Parse `verificationMethod` If `verificationMethod` is a DID including fragment then check if `holder === verificationMethod` before # 2. Resolve `holder` using the universal resolver 3. If `verificationMethod` referenced a key by id, then try to find the respective key. If ' 4. `verificationMethod` was `assertionMethod`, then try to find all (referenced) keys in the `assertionMethod` array in the DID doc. 5. For all keys that are found do `POST: /jsonld/verify` with the key in `verkey` and the signed credential in `doc`. 6. Verify that `holder === credentialSubject.id`. The UI needs a warning if this is not the case. In addition there could be an `expirationDate` or a revocation mechanism defined. But we'll neglect this for now.