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

proposed HIPE: Credential Exchange Message Family #89

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
398 changes: 398 additions & 0 deletions text/credential-exchange-message-family/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,398 @@
- Name: credential-exchange-message-family
- Author: Nikita Khateev
- Start Date: 2019-01-30
- PR: (leave this empty)
- Jira Issue: (leave this empty)

# Summary
[summary]: #summary

Formalization and generalization of existing message formats used for credential
exchange according to existing HIPEs about message formats.

# Motivation
[motivation]: #motivation

We need to define standard protocols for credential issuance and presentation.

# Tutorial
[tutorial]: #tutorial

Credential exchange consists of two processes connected by data. Therefore, we need 2 message families -- one for credential issuance and another one for credential presentation.

## Credential Issuance

The Credential Issuance Message Family consists of these messages:

* Credential Offer
* Credential Request
* Credential
* Credential Ack
* Credential Reject

#### Choreography Diagram:

![issuance](credential-issuance.png)

#### Credential Offer
This message is sent by Issuer to Prover to initiate credential issuance. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-issuance/1.0/credential-offer",
"@id": "<uuid-offer>",
"cred_def_id": "KTwaKJkvyjKKf55uc6U8ZB:3:CL:59:tag1",
"comment": "some comment",
"credential_preview": <json-ld object>,
"~attach": [
{
"nickname": "libindy-offer",
Copy link
Contributor

@kdenhartog kdenhartog Mar 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding @type: "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/anoncreds/1.0" into the ~attach JSON-LD object of the attachment would allow us to support multiple credential types in here. We would likely need to do this for the Credential Offer, Credential Proposal, so that we can agree on the data that needs to be passed back in the Credential Request.

"mime-type": "application/json",
"content": {
"base64": "<bytes for base64>"
}
}
]
}
```

Description of fields:
* `comment` -- a field that provide some human readable information about this Credential Offer;
* `cred_def_id` -- id cof credential definition for offered credential
* `credential_preview` -- a JSON-LD object that represents the credential data that Issuer is willing to issue. It should follow the schema of [Credential Preview](#credential-preview);
* attachment `libindy-offer` -- data for libindy about credential offer. It is base64 encoded. Here is an example of what lies inside, more information is in [Libindy API](https://github.com/hyperledger/indy-sdk/blob/57dcdae74164d1c7aa06f2cccecaae121cefac25/libindy/src/api/anoncreds.rs#L280) :
```json
{
"schema_id": string,
"cred_def_id": string,
"nonce": string,
"key_correctness_proof" : <key_correctness_proof>
}
```


#### Credential Request
This message is sent in response to Credential Offer by Prover to give needed details for credential issuance. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-issuance/1.0/credential-request",
"@id": "<uuid-request>",
"cred_def_id": "2hoqvcwupRTUNkXn6ArYzs:3:CL:1766",
"comment": "some comment",
"credential_preview": <json-ld object>,
"payment": {

},
"~attach": [
{
"nickname": "libindy_cred_req",
"mime-type": "application/json",
"content": {
"base64": "<bytes for base64>"
}
},
]
}
```

Description of Fields:
* `cred_def_id` -- Credential Definition ID for requested credential
* `comment` -- a field that provide some human readable information about this Credential Offer.
* `credential_preview` -- an object that represents the credential data that Prover wants to be issued. It is an optional field and not needed if Credential from Credential Offer message satisfies the Prover. It should follow the schema of [Credential Preview](#credential-preview).
* `payment`
* attachment `libindy_cred_req` -- an attachment with data that is needed to Issuer to generate a credential. It is base64 encoded. Here is an example of what lies inside, more information is in [Libindy API](https://github.com/hyperledger/indy-sdk/blob/57dcdae74164d1c7aa06f2cccecaae121cefac25/libindy/src/api/anoncreds.rs#L658):
```json
{
"prover_did" : string,
"cred_def_id" : string,
"blinded_ms" : <blinded_master_secret>,
"blinded_ms_correctness_proof" : <blinded_ms_correctness_proof>,
"nonce": string
}
```


#### Credential
This message contains the credential and sent in responce to Credential Request. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-issuance/1.0/credential",
"@id": "<uuid-credential>",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the @id should be the uuid_credential, should it? It's the @id of the message.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uuid_credential is just a name that was meant to refer to some particular @id for threading. No particular credential connection here.

"rev_reg_def_id": "<rev_reg_def_id>",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this embedded in the attachment? Does it need to be called out, or does that just make it easier for the prover to handle the incoming credential?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is also a field inside of an attachment, but it is needed to save the credential (id is needed to get the json in case of libindy). If we send it in this message, messaging library won't need to parse the libindy-specific attachment.

"cred_def_id": "2hoqvcwupRTUNkXn6ArYzs:3:CL:1766",
"~attach": [
{
"nickname": "libindy-cred",
"mime-type": "application/json",
"content": {
"base64": "<bytes for base64>"
}
}
]
}
```

Description of fields:

* `rev_reg_def_id` -- an ID of Revocation Registry Definition for this credential
* `cred_def_id` -- ID of Credential Definition this credential were issued to
* attachment `libindy-cred` -- an actual credential to store, it is a json encoded in base64. Here is the schema of what lies in it and you can find more information in [Libindy API](https://github.com/hyperledger/indy-sdk/blob/57dcdae74164d1c7aa06f2cccecaae121cefac25/libindy/src/api/anoncreds.rs#L338):
```json
{
"schema_id": string,
"cred_def_id": string,
"rev_reg_def_id": Optional<string>,
"values": <see cred_values_json above>,
"signature": <signature>,
"signature_correctness_proof": <signature_correctness_proof>
}
```

#### Credential Preview

This is not a message but an inner object for other messages in this message family. It is used to make a preview of credential that is going to be issued. Schema:

```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-issuance/1.0/credential-preview",
"attributes": [
{
"name": "attribute name",
"mime-type": "type",
"value": "value"
},
...
]
}
```

The main field here is `attributes`. It is an array of objects with three fields in it:
* `name` -- string with atribute name;
* `mime-type` -- type of attribute
* `value` -- value of credential

#### Credential Reject
This message can be sent by any side of the conversation to finish credential issuance without any credential created. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-issuance/1.0/reject",
"@id": "id"
}
```

#### Credential Ack
This message is sent by Prover as he confirms that he had received the credential and everything is correct. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-issuance/1.0/ack",
"@id": "id"
}
```

## Credential Presentation

The Credential Presentation Message Family consists of 4 messages:

* Presentation Request
* Presentation
* Presentation Ack
* Presentation Reject

#### Choreography Diagram:

![presentation](credential-presentation.png)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although revocation is an operation between the Issuer and the Ledger, should we add a message that notifies the holder that a credential issued to them has been revoked?

Related; A common pattern with credentials will be that a change of information will trigger the revocation of a credential and the issuance of a new credential. Perhaps that common credential lifecycle pattern is worthy of enhancing the "credential_offer" message to have an optional, associated credential revocation indicator.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this is an awesome idea!
I will add that to open questions.

#### Presentation Request
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since credential issuance and presentation (and revocation, if/depending on how we include it) are different protocols. Should they be in separate message families? At minimum, if properly defined state-transition models for the message family are added (which I think need to be added) - it should be clear that the issuance and presentation are separate.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't formally prove that they should be in one message family. However, I can't go through the same process about two message families as well. The problem here is that we don't have a clear formal definition of "Message Family" in previous HIPEs.

The only definition (not formal, though) that I found is in HIPE #21. It says:

Message families provide a logical grouping for message types

All of these message types are used for operations with credentials. We can as well state that we can unite them into two groups -- one about credential issuance, and the second one about proof verification. It might be even more convenient to use them as two message families as we can make their versioning separately.

Formally, two message families are at the value level same as one here. In terms of common sense two seems to be better, but I have to think more about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a proposed HIPE that defines how to document Message Families (aka protocols) with an example (tic-tac-toe) - #69. I took a look at it as I was reading this and I think that would lead us to separating out these into several protocols. That might help as you think about this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, there are two families instead of one. I had split them.

Presentation Request is a message from Verifier to Prover that describes values that need to be revealed and predicates that need to be fulfilled. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-presentation/1.0/presentation-request",
"@id": "<uuid-request>",
"comment": "some comment",
"~attach": [
{
"nickname": "libindy-presentation-request",
"mime-type": "application/json",
"content": {
"base64": "<bytes for base64>"
}
}
]
}
```

Description of fields:

* `comment` -- a field that provide some human readable information about this Credential Offer.
* attachment `libindy-presentation-request` -- base64-encoded data needed for libindy to process presentation request. Here is the schema of what lies in it and you can find more information in [Libindy API](https://github.com/hyperledger/indy-sdk/blob/57dcdae74164d1c7aa06f2cccecaae121cefac25/libindy/src/api/anoncreds.rs#L1214):
```json
{
"name": string,
"version": string,
"nonce": string,
"requested_attributes": {
"<attr_referent>": <attr_info>,
},
"requested_predicates": {
"<predicate_referent>": <predicate_info>,
},
"non_revoked": Optional<<non_revoc_interval>>,
}
```

#### Presentation
This message is a response to a Presentation Request message and contains signed presentations. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-presentation/1.0/presentation",
"@id": "<uuid-presentation>",
"comment": "some comment",
"presentation_request_preview": <json-ld object>
"~attach": [
{
"nickname": "libindy-presentation",
"mime-type": "application/json",
"content": {
"base64": "<bytes for base64>"
}
},
]
}
```

Decription of fields:

* `comment` -- a field that provide some human readable information about this Credential Offer.
* `presentation_request_preview` -- an object that represents information that Prover is willing to disclose to Verifier. It is an optional field and can be dismissed if Prover is willing to satisfy the original proof request from Verifier.
* attachment `libindy-presentation` -- actual presentation for presentation request, represented by base64-encoded json. Here is the schema of what lies in it and you can find more information in [Libindy API](https://github.com/hyperledger/indy-sdk/blob/57dcdae74164d1c7aa06f2cccecaae121cefac25/libindy/src/api/anoncreds.rs#L1404):
```json
{
"requested_proof": {
"revealed_attrs": {
"requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string},
"requested_attr4_id": {sub_proof_index: number: string, encoded: string},
},
"unrevealed_attrs": {
"requested_attr3_id": {sub_proof_index: number}
},
"self_attested_attrs": {
"requested_attr2_id": self_attested_value,
},
"requested_predicates": {
"requested_predicate_1_referent": {sub_proof_index: int},
"requested_predicate_2_referent": {sub_proof_index: int},
}
}
"proof": {
"proofs": [ <credential_proof>, <credential_proof>, <credential_proof> ],
"aggregated_proof": <aggregated_proof>
}
"identifiers": [{schema_id, cred_def_id, Optional<rev_reg_id>, Optional<timestamp>}]
}
```

#### Presentation Request Preview

This is again not a message but an inner object. It is used to negotiate a presentation request sent by Verifier. Schema:

```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-presentation/1.0/presentation-request-preview",
"name": "request name",
"requested_attributes": {
"attr_name": {
"name": "attribute name",
"restrictions": <json object>,
"non_revoked": {
"from": <u64>,
"to": <u64>
}
},
},
"requested_predicates": {
"pred_name": {
"name": "attribute name",
"p_type": ">=",
"p_value": <u64>,
"restrictions": <json object>,
"non_revoked": {
"from": <u64>,
"to": <u64>
}
},
},
"non_revoc_interval": {
"from": <u64>,
"to": <u64>
}
}
```

Description of fields:
* `name` -- a name of presentation request;
* `requested_attributes` -- a json object, where keys contain identifier for a requested attribute, and value is an object that describes an attribute.
Fields of this object:
* `name` -- name of needed attribute
* `restrictions` -- restriction on a credential to get attribute from. The language for this restrictions is WQL -- wallet query language. It is described in [this document](https://github.com/hyperledger/indy-sdk/tree/5f47aaf3713abff4ace2d69822f3c0644c0efa5e/docs/design/011-wallet-query-language). Optional field.
* `non-revoked` -- JSON object with to fields `from` and `to`. It describes precise time interval in which credential with this attribute should not be revoked. Optional field.
* requested_predicates` -- a json object, where keys contain identifier for a requested predicate, and value is an object that describes an predicate.
Fields of this object:
* `name` -- name of needed predicate;
* `restrictions` -- same restrictions, as in `requested_attributes`;
* `non-revoked` -- same as in `requested_attributes`;
* `p_type` -- predicate type. Can be ">=", "<=", ">", "<", "="
* `p_value` -- value to compare to.
* `non_revoc_interval` -- default revocation interval for all predicates and attributes. It has `from` and `to` fields as well, both are optional.

#### Presentation Reject
This message can be sent by any side of the conversation to finish credential issuance without any proof provided. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-presentation/1.0/reject",
"@id": "id"
}
```

#### Presentation Ack
This message is sent by Verifier as he confirms that he had received the proof and validated it. Schema:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/credential-presentation/1.0/ack",
"@id": "id"
}
```

## Threading

All of the messages require threading to be connected into a chain of messages. Using it we can mark what message we are responding to. This is a short set of rules that must be followed to use threading correctly:
* If you send a message in response to a non-threaded message, you must add a decorator `~thread` with a field `thid` with value of `@id` field of that message.
* If you send a message in response to an already threaded message, you must add a decorator `~thread` with `pthid` field with value of original `thid` and `thid` with n `@id` of message you respond to.

More details about threading you can find in the [threading and message id HIPE](https://github.com/hyperledger/indy-hipe/blob/master/text/0027-message-id-and-threading/README.md)

## Previews and negotiation

All of the messages (except Credential and Ack/Reject) can be negotiated. For these purposes you should use these fields: `credential_preview` in Credential Offer and Credential Request, `libindy_presentation_request` for Presentation Request and `presentation_request_preview` for Presentation.

# Reference
[reference]: #reference

* [VCX](https://github.com/hyperledger/indy-sdk/tree/master/vcx/libvcx/src/api) -- this implementation might not be perfect and needs to be improved, you can gather some info on parameters purpose from it

# Drawbacks
[drawbacks]: #drawbacks

Why should we *not* do this?

# Prior art
[prior-art]: #prior-art

Similar (but simplified) credential exchanged was already implemented in [von-anchor](https://von-anchor.readthedocs.io/en/latest/).

# Unresolved questions
[unresolved]: #unresolved-questions

- We might need to propose a new MIME type for credential (the same way as .docx is not processed as generic xml). The issue in W3C/vc-data-model: https://github.com/w3c/vc-data-model/issues/421
- We might need to have an extra message to inform Prover about revocation of his credential.
- It is a common practise when the change of some attributes in credential we revoke the old credential and issue a new one. It might be useful to have in Credential Offer message to have at least some connection between revocation and new offer.
- We might need some explicit documentation for nested `@type` fields.
- We need to provide a way to ask for some payment with Credential Offer and send payment receipt with Credential Request. It may be described generically in separate HIPE and this HIPE will be updated.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.