Skip to content

Commit 00fe7d5

Browse files
Add AnonCred method specification
This commit adds a draft for the AnonCred method specification based on the PRISM DID method
1 parent 0bb23aa commit 00fe7d5

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed

AnonCred-method-spec.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# did:prism AnonCreds Method v1.0
2+
3+
## Objective of this specification
4+
5+
The primary goal of this document is to describe a way to identify and retrieve resources using the PRISM DID method as a building block.
6+
As a secondary set of goals we want our approach to be re-usable by other DID methods that share some basic functionalities. Finally, we will present a component we identify as useful in the interoperability of AnonCred Methods.
7+
8+
## Definitions
9+
10+
In this section we will present a way to classify the resources we want to treat, and then define the properties we want to satisfy with our AnonCred method.
11+
12+
Within the context of SSI, different resources are involved in the creation, sharing and verification of Verifiable Credentials (VCs). Some of these resources can be described as _static_ due to the fact that they do not change once associated to a VC. Examples of these resources are schema objects and credential definitions. Conversely, other resources could be described as _dynamic_ in nature, as VCs refer to them, but the resources per se are updated over time. Examples of these resources are status lists or revocation entries. This classification will help us later in this document to describe how to identify, retrieve and validate resources in accordance to this specification.
13+
14+
As a whole, this AnonCred method aims to provide:
15+
- Integrity assurance for static resources: When a user retrieves a resource based on its identifier, he can validate on his own that the resource hasn't been tampered with.
16+
- Storage layer extensibility: after resource creation, the user controlling the resource identifier can update the storage location and/or retrieval protocols without affecting the original resource identifier.
17+
18+
### Underlying DID method properties
19+
20+
As we mentioned in the objectives section, we will define the AnonCred method in terms of the PRISM DID method. However, the AnonCred method could be constructed on top of any DID method that simply supports for services.
21+
22+
In the remaining of this document we will take the following conventions:
23+
24+
- For each resource, the user has an intended URL where the resource should be retrieved. We will call this URL `baseURL`
25+
- Each resource has an associated DID, `userDID`, that is used to create the resource identifier.
26+
- The `userDID` has a service we will call `baseService`
27+
+ The `baseService` has `baseURL` as its only service endpoint.
28+
+ The `baseService` has type `LinkedResourceV1`
29+
- The resource has an optional associated path `resourcePath` relative to its `baseURL`
30+
- The resource has an optional associated query parameter `resourceQuery`
31+
32+
As an illustrative example we can show the following DID document where:
33+
- `userDID` is `did:prism:123...abc`
34+
- `baseService` is `did:prism:123...abc#service1`
35+
- `baseURL` is `https://example.com`
36+
37+
Based on those values, we can present the following DID document
38+
39+
```json
40+
{
41+
"id" : "did:prism:123...abc",
42+
...
43+
service : [
44+
{
45+
"id" : "did:prism:123...abc#service1",
46+
"type : "LinkedResourceV1",
47+
"serviceEndpoint" : "https://example.com"
48+
}
49+
]
50+
}
51+
```
52+
53+
## Identifiers
54+
55+
In this section we will define the identifiers structure for any given resource.
56+
We will start describing a basic identifier where each resource uses its own service, and later explain how to optionally share the same service between multiple resources.
57+
We will also distinguish the identifier construction for static and dynamic resources.
58+
59+
### Dynamic resources
60+
61+
For dynamic resources such as revocation lists, we define the identifiers in this AnonCred method as follows.
62+
Given a resource `r` with associated `userDID` and base service `baseService`, we can define `r`'s identifier as follows:
63+
64+
```
65+
userDID ? resourceService= baseService
66+
```
67+
68+
69+
### Static resources
70+
71+
For static resources, like a schema or a credential definition, we don't usually have an integrity check at application layer. For this reason, we add to identifiers a `resourceHash` section that will serve for integrity check.
72+
Hence, given a resource `r` with associated `userDID` and base service `baseService`, we can define `r` identifier as follows:
73+
74+
```
75+
userDID ? resourceService= baseService & resourceHash = encoded_hash(r)
76+
```
77+
78+
where `encoded_hash` is the hex encoded SHA256 hash of the base64URL encoded resource `r`.
79+
80+
#### A comment about resource authenticity
81+
82+
We want to remark that, in practice, dynamic resources in SSI are signed by a key associated to the issuer of an associated VC. For this reason, this AnonCred method does not add any integrity nor authenticity check for dynamic resources, and leave it to the application layer. In this way, we avoid an overhead for a second authenticity/integrity check at this stage.
83+
84+
On a related note, we want to point out that we are also not performing an authenticity checks for static resources inside the AnonCred method. The reason is that in the context of VCs, the identifiers we are generating are attached in signed objects (VCs). By attaching an integrity check to the identifier, we are inheriting the authenticity of the expected resource from the signature on the VC that contained the identifier in the first place. Future versions of this AnonCred method could add more flexibility by embedding a signature in the resource envelope. However, we argue that the relevant authenticity property is attached to the authenticity of the identifier, and not the authenticity of the indirect resource it represents (see Future Work section).
85+
86+
### Sharing a common `baseURL`
87+
88+
There are situations where a user controlling multiple resources would prefer to share the same service to support multiple resources. The advantage is to require less services in the `userDID` document, where the trade off is that updating the service for one resource will imply updating the location of all the resources. We consider that this trade off is use case dependent, and we added the following structure to support both scenarios.
89+
90+
If a user wants to share the same `resourceService` and consequently `baseURL` for multiple resources, they have the option to distinguish specific resources by relative path from the `baseURL`. The relative path is specified with the `resourcePath` query parameter. As an example, if we imagine resources `r1` and `r2` located at `https://example.com/resources/r1.txt` and `https://example.com/resources/r2.txt` respectively. We can use the `baseURL` `https://example.com` and relative paths `/resource/r1.txt` and `/resource/r2.txt` respectively to obtain the following identifiers.
91+
92+
```
93+
userDID ?resourceService=resourceService & resourcePath = /resource/r1.txt
94+
```
95+
and
96+
97+
```
98+
userDID ?resourceService=resourceService & resourcePath = /resource/r2.txt
99+
```
100+
101+
If the resources require a hash, the corresponding query parameter would also be included. Namely:
102+
103+
```
104+
userDID ?resourceService=resourceService & resourcePath = /resource/r2.txt & resourceHash= encoded_hash(r2.txt)
105+
```
106+
107+
where `encoded_hash`, once again, represents the hex encoded sha256 hash of the base64URL encodedresource.
108+
109+
## Resources retrieval
110+
111+
In this section, we will describe how to obtain a resource from a given identifier in this AnonCred method.
112+
We start by briefly displaying some example identifiers using the DIDs from the PRISM DID method.
113+
114+
```
115+
// Example 1
116+
did:prism:abc...123?resourceService="service1"&resourcePath="/schemas/123.json"&resourceHash="hffa...31aef3"
117+
118+
// Example 2
119+
did:prism:abc...123?resourceService="service1"&resourcePath="/schemas/123.json"
120+
121+
//Example 3: long form DID with all parameters
122+
did:prism:abc...123:abfha...1d4s8fr?resourceService="service1"&resourcePath="/schemas/123.json"&resourceHash="hffa...31aef3"
123+
```
124+
125+
An implementation of this specification will behave as follows:
126+
- First, extract the PRISM DID from the URI. In examples 1 and 2, this is `did:prism:abc...123`, while in example 4, this is `did:prism:abc...123:abfha...1d4s8fr`
127+
- Then, resolve the extracted DID from the previous step
128+
- The resolution will return a DID document. The implementation should validate that:
129+
- Given the value of `resourceService` parameter, lets call it `serviceId`. There must be a service with name `<prism-did>#serviceId` in the resolved DID document. In examples 1 and 2, this is a service with id equal to `did:prism:abc...123#service1`. See example DID document at the end of this section.
130+
- the identified service type must be `LinkedResourceV1`
131+
- The `serviceEndpoint` of the service previously identified will contain a URL, lets call it `baseURL` in the next steps.
132+
- If present, attach to `baseURL` the value in `resourcePath`. For the examples shown above, this would lead to a URL `baseURL/schemas/123.json`
133+
- Perform a GET call to that URL to obtain the resource, expecting a JSON response.
134+
The resource will be encoded as a base64url string inside a JSON object of the form
135+
136+
```
137+
{
138+
“resource“ : <base64url string>
139+
}
140+
```
141+
- if the initial identifier contains a `resourceHash` query parameter, validate that the hex encoded sha256 hash of the string located in the `“response“` field of the JSON, matches the string in the `resourceHash` value.
142+
- If all the validations in the previous steps were correct, then return the JSON that it received from the server that generated the JSON response
143+
144+
Example DID document to illustrate an expected service
145+
146+
```
147+
{
148+
"id": "did:prism:abc...123",
149+
...
150+
"service" : [
151+
{
152+
"id" : "did:prism:abc...123#service1",
153+
"type": "LinkedResourceV1",
154+
"serviceEndpoint" : baseUrl
155+
}
156+
]
157+
}
158+
```
159+
160+
## Universal AnonCred method resolver
161+
162+
We want to dedicate a section to discuss an additional component, which is not exactly part of this AnonCred Method, but sits on top of it.
163+
164+
Different methods in the AnonCreds method registry have described custom formats to represent resources when they are queried. Some methods return the resource as a string in a verbatim form. Other methods, including this one, create an envelope JSON object that contains the resources under some encoding (Base58, Base64URL, etc). From an application point of view, this format discrepancies hinders interoperability. We would like to describe here a simple layer that most application will have to implement in one form or another. We can call this component AnonCred method universal resolver. The sole purpose of this layer is to receive a URI that identifies a resources, and return the string resource without any envelope. The input URI can represent an identifier from any AnonCred method. The universal resolver would determine from the URI which specific AnonCred method it should call, and after receiving the response, it would do any needed validation (e.g. integrity checks), and remove the potential specific envelope that any method may be adding.
165+
166+
We want to remark that URIs would need to contain enough information to distinguish which AnonCred method needs to be called. We could suggest to have in the URIs a reserved query parameter to identify the method (see Future Work section).
167+
168+
## Future Work
169+
170+
This section is kept to list possible extensions for this AnonCred method
171+
172+
### Add a `resourceMethod` query parameter
173+
174+
As mentioned in the previous section, we have observed the lack of clear ways to identify how to resolve a resource based solely on an identifier. Several AnonCred methods use a DID URL as resource identifier. However, they all follow slightly different resource resolution steps. We consider useful, if not actually needed, to add a `resourceMethod` query parameter to identify the AnonCred method that the identifier is representing. This allows a clear mechanism to take an identifier and determine how to treat it. It is also a good tool to identify a version of the AnonCred method the identifier is associated with. In the future of this specification, we may add new features where version names like `DIDURLsV1`, `DIDURLsV2`, etc. may become handy.
175+
176+
### More flexible `serviceEndpoint` values
177+
178+
In this first conservative version, our method allows for a single URL for `serviceEndpoint` in the associated `resourceService`. However, one could see many alternatives to this:
179+
- Allow a list to represent a fallback semantic
180+
- Allow other URIs for resources. For example, IPFS identifiers for static resources
181+
- Allow a map to represent richer data. For example, a way to specify holder to verifier direct transmission of a resource.
182+
183+
### More flexible authenticity checks
184+
185+
In order to add another layer for authenticity checks, the resource identifier would need to add a reference to a key, while the resource envelope would need a signature field.
186+
For example, the resource identifier could have query parameters `signingKey` and `signingAlgorithm`. Where `signingKey` could be either an encoded key or a DID URL that refers to a verification method. Key encodings and signing algorithms should be standardize. The JSON response that serves as resource envelope would add an adequate `proof` field containing necessary signature information.
187+
188+
In that way, the user would be able to validate expected source for the resource. We want to note that the information related to the signing key is added in the identifier, in order to avoid the server side of the resolution process to tamper the key. However, we also need to remark that the resource identifier itself is susceptible to be modified, meaning that a user trying to dereference an identifier needs to trust the identifier's source in the first place. This implies that the authenticity of the resource is strongly tight to the authenticity of the identifier, and this is why we consider that supporting an integrity check between an static resource and its identifier is enough for this AnonCred method. Adding the authenticity at resource level does not solve the more relevant identifier authenticity, which is the likely intended property to preserve.
189+
190+
For the case of dynamic resources, we remind the reader that existing SSI protocols already enforce a signature checks at application layer, but we would find it adequate to have an optional authenticity check for the case of dynamic resources in the future version of this AnonCred method.

0 commit comments

Comments
 (0)