1 unstable release
0.3.0 | May 6, 2022 |
---|
#776 in Authentication
Used in vade-evan
195KB
4K
SLoC
vade-didcomm
About
This crate is a DIDComm V2 vade plugin that currently offers:
- message encryption & decryption using DIDComm rs
- protocol support using DIDComm message
type
It implements the following VadePlugin
functions:
Currently supported protocols:
Usage
didcomm_send
prepares a message for being sent to the recipient and didcomm_receive
is used for decryption and analyzing an incoming message. Per default each sent message will be encrypted, either with the saved encryption key from an existing DID exchange with the communication partner, or with the provided one. Specific protocol types can override the encryption setting of a message to just send a plain message (like DID exchange).
NOTE: When you send any message that will be encrypted, you need to have a finished DID exchange or correct encryption keys, that are passed to vade_didcomm.
The two functions didcomm_send
and didcomm_receive
can be called with two parameters, options
and message
:
- Options: Contains specific information for passing special configuration to the vade_didcomm. Currently its just used to inject specific encryption configuration, to overwrite the default DIDComm DID exchange key encryption and signing.
{
"encryptionKeys": {
"encryptionMySecret": "...",
"encryptionOthersPublic": "..."
},
"signingKeys": {
"signingMySecret": "...",
"signingOthersPublic": "..."
}
}
- Message: The plain message object, containing at least the type, to DID and from DID.
The result of both functions will always return a stringified json with almost same structure, only difference is that didcomm_receive
doesn't return messageRaw
property, the return has following pattern:
didcomm_send
{
"message": {},
"messageRaw": {},
"metadata": {}
}
didcomm_receive
{
"message": {},
"metadata": {}
}
The data that is represented in message
and metadata
is protocol specific. The message is also attached unencrypted as messageRaw
.
trust_ping
This protocol implementation has only 2 steps and is used more like a testing protocol.
To send a trust_ping
message, pass the following message to the didcomm_send
:
{
"type": "https://didcomm.org/trust_ping/1.0/ping",
"from": "did::xyz:34r3cu403hnth03r49g01",
"to": [ "did::xyz:34r3cu403hnth03r49g03" ],
}
This will return an encrypted stringified message and will also add a body to the message, that contains:
{
"body": {
"response_requested": true
}
}
did_exchange
The DID exchange protocol
is a bit more complex and consist of 3 steps. The whole flow is implemented in the did-exchange test
. Like with the trust_ping, you can pass a simple message, that will be enhanced with the actual data that will be sent. Here an example for the first request (ensure, to set the service_endpoint to the url, where your DID agent is available):
{
"type": "https://didcomm.org/didexchange/1.0/request",
"service_endpoint": "https://evan.network",
"from": "did:uknow:d34db33d",
"to": ["did:uknow:d34db33f"]
}
This will return the following result:
{
"message": {
"body": {
"@context": "https://w3id.org/did/v1",
"authentication": [
"{0}#key-1"
],
"id": "did:uknow:d34db33d",
"publicKey": [
{
"id": "did:uknow:d34db33d#key-1",
"publicKeyBase58": "b1f88eebc9576fcb923837d9455ffd24a2c634d95e4e7c9fdf0ab362fd092a7c",
"type": [
"Ed25519VerificationKey2018"
]
}
],
"service": [
{
"id": "did:uknow:d34db33d#didcomm",
"priority": 0,
"recipientKeys": [
"b1f88eebc9576fcb923837d9455ffd24a2c634d95e4e7c9fdf0ab362fd092a7c"
],
"serviceEndpoint": "",
"type": "did-communication"
}
]
},
"from": "did:uknow:d34db33d",
"id": "de9358ae810341e6b02bc08f7fd061ec",
"pthid": "de9358ae810341e6b02bc08f7fd061ec#key-1",
"thid": "did:uknow:d34db33d#key-1",
"to": [
"did:uknow:d34db33f"
],
"type": "https://didcomm.org/didexchange/1.0/request"
},
"metadata": {
"pub_key": "b1f88eebc9576fcb923837d9455ffd24a2c634d95e4e7c9fdf0ab362fd092a7c",
"secret_key": "487db1e4be6f0ec0cb4fa07a64a5aea9bd5e77ba8f639e8595563535c5784166",
"target_pub_key": "",
"target_service_endpoint": ""
}
}
As you can see, the whole message was enriched with the data that is necessary for the DID exchange. The metadata contains the generated communication hex encoded public key and secret key. The receiver can just pass the whole json to the didcomm_receive
function, that will analyse the message, will save the communication keys and generate new ones for himself as well. The receiver can then use the logic for sending the response, by just replacing the type of the message https://didcomm.org/didexchange/1.0/response.
present_proof protocol
The Present Proof Protocol
consists of 4 steps. The whole flow is implemented in the present-proof test
. The general flow starts with a verifier sending a request-presentation
message to a prover. The prover has the option to answer with the requested presentation or propose a new presentation to the verifier. The format for request-presentation
is the following:
{
"@type": "https://didcomm.org/present-proof/1.0/request-presentation",
"@id": "<uuid-request>",
"comment": "some comment",
"request_presentations~attach": [
{
"@id": "libindy-request-presentation-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
The prover then responds with either a presentation
or propose-presentation
message. The following are the formats for the messages:
Presentation response format:
{
"@type": "https://didcomm.org/present-proof/1.0/presentation",
"@id": "<uuid-presentation>",
"comment": "some comment",
"presentations~attach": [
{
"@id": "libindy-presentation-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
Presentation proposal format:
{
"@type": "https://didcomm.org/present-proof/1.0/presentation-preview",
"attributes": [
{
"name": "<attribute_name>",
"cred_def_id": "<cred_def_id>",
"mime-type": "<type>",
"value": "<value>",
"referent": "<referent>"
},
// more attributes
],
"predicates": [
{
"name": "<attribute_name>",
"cred_def_id": "<cred_def_id>",
"predicate": "<predicate>",
"threshold": "<threshold>"
},
// more predicates
]
}
Once the presentation exchange is complete, the verifier sends an ack message to the prover to confirm the receival and validity of the received Presentation data.
issue_credential protocol
The Issue Credential Protocol
consists of 5 steps. The whole flow is implemented in the issue-credential test
. The general flow starts with a holder sending a propose-credential
message to a issuer. The issuer has the option to answer with the offer-credential
or terminate request with problem-report
message. Holder receives offer-credential
and decides to send request-credential
message , Once issuer receives request-credential
, he/she would respond with issue-credential
and Holder will receive and send ack
message to acknowledge the receipt of credential.
Propose Credential message:
{
"@type": "https://didcomm.org/issue-credential/1.1/propose-credential",
"@id": "<uuid-of-propose-message>",
"comment": "some comment",
"credential_proposal": "<json-ld object>",
"schema_issuer_did": "DID of the proposed schema issuer",
"schema_id": "Schema ID string",
"schema_name": "Schema name string",
"schema_version": "Schema version string",
"cred_def_id": "Credential Definition ID string",
"issuer_did": "DID of the proposed issuer"
}
Offer Credential message :
{
"@type": "https://didcomm.org/issue-credential/1.0/offer-credential",
"@id": "<uuid-of-offer-message>",
"comment": "some comment",
"credential_preview": "<json-ld object>",
"offers~attach": [
{
"@id": "libindy-cred-offer-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
Request Credential message:
{
"@type": "https://didcomm.org/issue-credential/1.0/request-credential",
"@id": "<uuid-of-request-message>",
"comment": "some comment",
"requests~attach": [
{
"@id": "attachment id",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
},
]
}
Issue Credential message:
{
"@type": "https://didcomm.org/issue-credential/1.0/issue-credential",
"@id": "<uuid-of-issue-message>",
"comment": "some comment",
"credentials~attach": [
{
"@id": "libindy-cred-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
presentation_exchange protocol
The Presentation Exchange Protocol
consists of 3 steps. The whole flow is implemented in the presentation-exchange test
. The general flow starts with a verifier sending a request-presentation
message to a holder. The holder has an option to answer with the propose-presentation
or send presentation
message. Once Verifier receives presentation
message, he/she will match the received credential claims against presentation-definition
request and validate the claims values with the contraints present in the input-descriptors
array in presentation-definition
In the current implementation of presentation exchange protocol, the json schema constraints have to be verified by the client application which is using vade because the constraints are quite diverse and specific to application requirements, for details regarding constraints, please visit Presentation Exchange Protocol
.
request-presentation message:
{
"options": {
"challenge": "...",
"domain": "...",
},
"presentation_definition": {
// presentation definition object
}
}
presentation-definition example:
{
"comment": "Note: VP, OIDC, DIDComm, or CHAPI outer wrapper would be here.",
"presentation_definition": {
"id": "32f54163-7166-48f1-93d8-ff217bdb0653",
"input_descriptors": [
{
"id": "wa_driver_license",
"name": "Washington State Business License",
"purpose": "We can only allow licensed Washington State business representatives into the WA Business Conference",
"schema": [{
"uri": "https://licenses.example.com/business-license.json"
}]
}
]
}
}
presentation message example:
{
"@type": "https://didcomm.org/present-proof/%VER/presentation",
"@id": "f1ca8245-ab2d-4d9c-8d7d-94bf310314ef",
"comment": "some comment",
"formats" : [{
"attach_id" : "2a3f1c4c-623c-44e6-b159-179048c51260",
"format" : "dif/presentation-exchange/submission@v1.0"
}],
"presentations~attach": [{
"@id": "2a3f1c4c-623c-44e6-b159-179048c51260",
"mime-type": "application/ld+json",
"data": {
"json": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://identity.foundation/presentation-exchange/submission/v1"
],
"type": [
"VerifiablePresentation",
"PresentationSubmission"
],
"presentation_submission": {
"descriptor_map": [{
"id": "citizenship_input",
"path": "$.verifiableCredential.[0]"
}]
},
"verifiableCredential": [{
"@context": "https://www.w3.org/2018/credentials/v1",
"id": "https://eu.com/claims/DriversLicense",
"type": ["EUDriversLicense"],
"issuer": "did:foo:123",
"issuanceDate": "2010-01-01T19:73:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"license": {
"number": "34DGE352",
"dob": "07/13/80"
}
},
"proof": {
"type": "RsaSignature2018",
"created": "2017-06-18T21:19:10Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "https://example.edu/issuers/keys/1",
"jws": "..."
}
}],
"proof": {
"type": "RsaSignature2018",
"created": "2018-09-14T21:19:10Z",
"proofPurpose": "authentication",
"verificationMethod": "did:example:ebfeb1f712ebc6f1c276e12ec21#keys-1",
"challenge": "1f44d55f-f161-4938-a659-f8026467f126",
"domain": "4jt78h47fh47",
"jws": "..."
}
}
}
}]
}
Registering a new protocol
Each protocol is represented by a set of steps. To register a new protocol, just follow the following steps:
1. Add new file into src/protocols
This file can look like following:
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CustomBody {
custom: Option<bool>,
}
pub fn generate_my_custom_protocol() -> Protocol {
let mut protocol = Protocol {
name: String::from("my_custom_protocol"),
steps: Vec::new(),
};
protocol.steps.push(send_step("step1", send_step1));
protocol.steps.push(receive_step("step1", receive_step1));
return protocol;
}
pub fn send_step1(_options: &str, message: &str) -> StepResult {
let mut parsed_message: MessageWithBody<CustomBody> = serde_json::from_str(message)?;
parsed_message.body = Some(CustomBody {
response_requested: Some(true),
});
return generate_step_output(&serde_json::to_string(&parsed_message)?, "{}");
}
pub fn receive_step1(_options: &str, message: &str) -> StepResult {
return generate_step_output(message, "{}");
}
2. Import it into the protocols mod.rs
file
pub(crate) mod my_custom_protocol;
3. Register it within the protocol_handler.rs
let protocols: [&Protocol; 3] = [
&generate_did_exchange_protocol(),
&generate_ping_pong_protocol(),
&my_custom_protocol(),
];
Afterwards, you can just test your protocol by passing the following message to the DIDComm functions:
{
"type": "my_custom_protocol/step1",
"from": "did::xyz:34r3cu403hnth03r49g01",
"to": [ "did::xyz:34r3cu403hnth03r49g03" ],
}
Dependencies
~15–34MB
~540K SLoC