forked from openssi/peer-did-method-spec
-
Notifications
You must be signed in to change notification settings - Fork 0
/
protocols.html
285 lines (270 loc) · 18.8 KB
/
protocols.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
<h1>Protocols</h1>
<section class="informative">
<h2>Roles and Agents</h2>
<p>As described in the introduction, we call this the "peer" DID method because it enables peers to exchange
DIDs without recourse to a central authority. Thus, we expect all participants in the protocol to play the
same <code>peer</code> role, and to operate by exactly the same rules. And this is the case, at a high
level.
</p>
<p>However, at another level of detail, each peer may interact through various pieces of software and hardware that
proxy them. They may need to reveal a modest amount of information about such <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0004-agents/README.md">agents</a> to
achieve cooperative security. For example, Alice may control three devices and may wish to protect
herself from hacking by saying that at least two of her existing devices must agree before a new device can be
added or an existing device can be revoked. This requires her to share her M-of-N <a href="#authorization">
authorization policy</a> with Bob, with enough information about agent keys that he can validate a multi-party
digital signature. Thus, our protocol must occasionally contemplate details about this more granular level
of each peer's <a>sovereign domain</a>.
</p>
</section>
<section class="informative">
<h2>Messages</h2>
<dl>
<dt>Peers interact via messages.</dt>
<dd>This is a more general claim than saying that peers expose an API because it doesn't assume that peers
are directly callable by each other. It must be possible to exchange DIDs in this method in a very
asynchronous fashion (e.g., one party sends a message while the other party is offline; a response is
returned when the original sender may not be actively listening).
</dd>
<dt>Message transmission is transport-agnostic.</dt>
<dd>That is, the messages can flow over any combination of HTTP, Bluetooth, NFC, email, AMPRNet (TCP/IP over
ham radio), snail mail, sneakernet, intermediaries, or future protocols we have not yet imagined.
</dd>
<dt>Messages are JSON ([[RFC8259]]).</dt>
<dd>They are compatible with <a target="jsonld" href="https://w3c.github.io/json-ld-syntax/#basic-concepts">
basic concepts of [[JSON-LD]]</a>, but <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0047-json-ld-compatibility/README.md">
no deep knowledge of JSON-LD is required to understand them, and no dependency
on JSON-LD libraries is necessary</a>. The specifics of the JSON format are discussed below.
</dd>
<dt>Messages are serialized and encrypted in a standard way for transport.</dt>
<dd>
<p>This method associates security guarantees with the message envelope rather than the transport, and is
aligned philosophically with the approach of <a href="https://datatracker.ietf.org/wg/mls/about/"
target="rfc">IETF's Message Level Security initiative</a>. However, the first version of this spec
predates MLS's maturity, so the wire format uses JWEs ([[RFC7516]]) with
<a href="https://github.com/openssi/peer-did-method-spec/issues/14#issuecomment-493626810"
target="_blank">some extensions</a>, instead. The extensions allow the same message to be
encrypted once for multiple recipients and sent to them all in an efficient manner:
</p>
<figure id="multiplexed encryption">
<img src="multiplex.png" alt="multiplexed encryption"/>
<figcaption>Multiplexed encryption lets multiple parties decrypt.</figcaption>
</figure>
<p>These extensions are under review by the maintainers of JWE/JWT and are likely to be mainstreamed
eventually. The particulars are detailed in <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0019-encryption-envelope/README.md">
a doc</a> that explains how agents in the Hyperledger Aries ecosystem have implemented the format -
but the format is easy to implement without any Aries dependencies, and its design has no connection
to any particular blockchain. See <a href="https://github.com/dbluhm/indy-pack-unpack-js/blob/db9d83e4/index.js"
target="_blank">this implementation in pure javascript</a>, and
<a href="https://github.com/bcgov/indy-catalyst/blob/bba2ef5c/agent/indy_catalyst_agent/wallet/crypto.py#L402"
target="_blank">this one in pure python</a>, in addition to
<a target="_blank" href="https://github.com/hyperledger/indy-sdk/blob/fbad7422/libindy/src/api/crypto.rs#L634">
Indy's C-callable implementation in Rust</a>.
</p>
</dd>
</dl>
</section>
<section>
<h2>CRUD Operations</h2>
<section>
<h3>Create (Register)</h3>
<p>Although the work of <em>creating</em> a peer DID and the <a>genesis version</a> of its DID doc can be
done at any time and does not require a message, <em>registering</em> a peer DID with the other party or
parties in a relationship involves a specific sequence of messages known as the <dfn>DID Exchange
protocol</dfn>. The protocol is <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0023-did-exchange/README.md">
formally documented in Aries RFC 0023</a>; only a summary is offered here. It has 3 steps:
</p>
<ol>
<li>One of the parties (the <dfn>inviter</dfn>) sends an <dfn>invitation</dfn> to connect. The
invitation is NOT encrypted, and it does NOT require the recipient (the <dfn>invitee</dfn>) to
have special software that understands this protocol. Instead, it is a specially formatted URI
that can be a <a target="wikipedia" href="https://en.wikipedia.org/wiki/Deferred_deep_linking">
deferred deep link</a>, helping the invitee to learn about SSI, get an SSI-capable app, and
otherwise onboard into the ecosystem. If the invitee already has SSI-aware software, the URI
can be recognized by a registered handler, short-circuiting the URI fetch and the onboarding/
learning process. This invitation URI may be transmitted by email, SMS, QR code, or any other
convenient method. If it is important to the inviter that it be secured, the inviter can share
the invitation on a secure channel. Important to note that if the messaging is to be done
anonymously without sharing of personal identifiable information (PII) between both parties the
invitation should not be transmitted to personal email, sms, etc. A one time identifier shall be
used to send initial invitation.
</li>
<li>The invitee sends an encrypted <dfn>connection request</dfn> back to the inviter, using the
endpoint that the inviter supplied in the invitation. This connection request includes a signed
version of the <a>resolved variant</a> [TODO: signed variant??] of the <a>genesis version</a> of
the invitee's DID doc. The inviter must verify that the received DID was generated according to
the <a href="#namestring-generation-method">namestring generation method</a> from the <a>stored variant</a>
of the received genesis DID Doc. This is to ensure a strong binding between the received DID and
the public key(s) contained in the DID Doc, see also: <a href="#proof-of-control">proof of control</a>.
</li>
<li>The inviter sends an encrypted <dfn>connection response</dfn> the other direction. This response
includes a signed version of the <a>resolved variant</a> of the <a>genesis version</a> of the
inviter's DID doc.
</li>
</ol>
<p>These three steps have been carefully defined to achieve a number of important goals:</p>
<ul>
<li>Because the invitation can be sent to someone who does not know about DIDs or SSI at all,
and because it can be sent over insecure channels, establishing DID relationships has an
extremely low bar. This is vital to the virality of SSI.
</li>
<li>The invitation identifies an endpoint over which the connection can occur, but it does not
communicate peer keys or a peer DID from the inviter, and the endpoint that the inviter uses (as
well as the inviter's DID and keys) are only transmitted once security and privacy are guaranteed.
</li>
<li>The protocol can be used by parties using any DID method. One of the parties can be using
a peer DID, both can, or neither can.
</li>
<li>The invitation can be sent by a third party, allow introductions (Alice introduces Carol to Bob).
However, an introducer is prevented from seeing the secure and private connection built by the
two parties.
</li>
</ul>
<p>Additional security against man-in-the-middle attacks may be achieved by signing an invitation, if it is
public. If the public invitation includes an <a>anywise</a> DID, then the invitee should verify that the
signature on the invitation matches with an active verification key for the associated anywise DID. If the
public invitation includes a verification key, then the invitee can verify that the signature on the
invitation matches with the verification key. Once the DIDs are exchanged, the invitee can
ask the inviter for proof-of-control of that initial verification key. In any case, further action is
advisable to build deeper trust about the identity of other side. This likely includes mutual exchange
of <a target="vcspec" href="https://w3c.github.io/vc-data-model/">verifiable credentials</a>.
</p>
</section>
<section>
<h4>Read (Resolve)</h4>
<p>This operation is documented in greater detail in
<a href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0124-did-resolution-protocol/README.md"
target="aries">Aries RFC 0124</a>. Here, we offer only a summary.
</p>
<p>A peer DID can be resolved to a DID document by sending a <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0124-did-resolution-protocol/README.md#resolve-message">
resolve</a> message from one peer to another:</p>
<pre class="example" title="A resolve message">
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/did_resolution/0.1/resolve",
"@id": "6a4986dd-f50e-4ed5-a389-718e61517207",
"did": "did:peer:11-479cbc07c3f991725836a3aa2a581ca2029198aa420b9d99bc0e131d9f3e2cbe",
"input_options": {
"version_time": "2019-07-23T18:05:06.123Z"
}
}
</pre>
<p>The <code>version_time</code> property is optional and often omitted; if so, the DID doc at
the current time is returned (see <a href="https://w3c-ccg.github.io/did-resolution/#resolving-input-version-time">version-time</a> in DID Resolution).</p>
<p>A <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0124-did-resolution-protocol/README.md#resolve_result-message">
resolve_result</a> message is returned. It includes a DID doc and some additional metadata, and looks like
this:
</p>
<pre class="example" title="A resolve_result message">
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/sync-connection/1.0/state_response",
"@id": "1517207d-f50e-4ed5-a389-6a4986d718e6",
"~thread": { "thid": "6a4986dd-f50e-4ed5-a389-718e61517207" },
"did_document": {
// full content of resolved variant of DID doc here
}
}
</pre>
<p class="note">Note the use of <code>~thread</code> in the response, with <code>thid</code> equal to the
<code>@id</code> property of the previous request, to connect the two messages. This is a <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/concepts/0008-message-id-and-threading#threaded-messages">
standard message threading feature of DID Communication</a>, and also shows up in other message interactions
described here.</p>
</section>
<section>
<h3 id="sync-protocol">Update</h3>
<p>The subject of a peer DID can update their associated DID document with anyone who knows the
DID—one or more agents of the peer(s), or agents of the owner—by sending a <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0030-sync-connection/README.md#sync_state">
sync_state</a> message to another peer. An example of this type of message is:
</p>
<pre class="example" title="A sync_state message">
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/sync-connection/1.0/sync_state",
"@id": "e61586dd-f50e-4ed5-a389-716a49817207",
"for": "did:peer:11-479cbc07c3f991725836a3aa2a581ca2029198aa420b9d99bc0e131d9f3e2cbe",
"base_hash": "d48f058771956a305e12a3b062a3ac81bd8653d7b1a88dd07db8f663f37bf8e0",
"base_hash_time": "2019-07-23 18:05:06.123Z",
"deltas": [
{
"id": "040aaa5e-1a27-40d8-8d53-13a00b82d235",
"change": "ewogICJwdWJsaWNLZXkiOiBbCiAgICB...ozd1htcVBWcGZrY0pDd0R3biIKICAgIH0KICBdCn0=",
"by": [ {"key": "H3C2AVvL", "sig": "if8ooA+32YZc4SQBvIDDY9tgTa...i4VvND87PUqq5/0vsNFEGIIEDA=="} ],
"when": "2019-07-18T15:49:22.03Z"
}
]
} </pre>
<p>This message does not follow a simple request~response pattern, and does not have "update" in its name,
because either party may know details that the other party lacks. This is especially likely when some
agents of either party have been offline. The sender picks a point in time, <code>delta_time</code>,
where it believes it and the receiver were probably in sync; it then describes the <a>deltas</a>
that it knows about, that have happened since.
</p>
<p>If the recipient already has the same state, it replies with an <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0015-acks/README.md">ACK</a>.
</p>
<p>If the recipient knew about a subset of the delta, but not all of it, it applies what is left of the
delta, and sends an ACK.
</p>
<p>If the recipient has a more evolved state, the recipient sends a reply that is a new <code>sync_state
</code> message informing the sender of hitherto unknown information. As with the ACKs, this new message is
known to be a reply to the original <code>sync_state</code> because its <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/concepts/0008-message-id-and-threading#threaded-messages">
<code>~thread</code> decorator identifies the previous message's <code>@id</code> as its
<code>thid</code></a>.
</p>
<p>If the recipient does not recognize the base_hash, it selects a hash from a point in time earlier than
<code>base_hash_time</code> and sends back a new <code>sync_state</code> message with that earlier base.
</p>
<p>Because of the nature of our <a href="#crdt-rules">CRDT rules</a>, truly
problematic merge conflicts cannot occur. All objects in the DID doc that
have an <code>id</code> property are immutable, and ordering of operations does not
need to be highly consistent. Furthermore, an object in both deleted and
undeleted state must be deemed to be deleted. However, if the recipient
detects a trivial conflict, the delta with the <code>id</code> that sorts smaller/lower
is selected.</a>.
</p>
</section>
<section>
<h3>Deactivate</h3>
<p>In a self-sovereign paradigm, abandoning a relationship can be done unilaterally, and does not
require formal announcement; one party can simply stop communicating with the other. Since there
is no public record of the relationship to delete, no further action is strictly required.
Indeed, sometimes a formal announcement is impossible, if one of the parties
is offline.</p>
<p>However, it is best practice to announce that the relationship is being abandoned. This
should cause the other party to clean up by removing the DID, DID doc, and associated metadata from its
local cache. It should also prevent the other party from trying to communicate in the future.
Formally terminating a connection happens by sending an <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/features/0030-sync-connection/abandon-connection-protocol#announce"><code>
announce</code> message</a> to a peer:</p>
<pre class="example" title="Sample announce message">
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/abandon_connection/1.0/announce",
"@id": "c17147d2-ada6-4d3c-a489-dc1e1bf778ab",
"~please_ack": {}
}
</pre>
<p>If Bob receives a message like this, he should assume that Alice no longer considers
herself connected, and take appropriate action. This could include destroying
data about Alice that he has accumulated over the course of their relationship,
removing her peer DID and its public key(s) and endpoints from his wallet, and so
forth. The nature of the relationship, the need for a historical audit trail, regulatory
requirements, and many other factors may influence what's appropriate; the protocol
simply requires that the message be understood to have permanent termination semantics.
</p>
<p>The <a target="aries" href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0015-acks/README.md#requesting-an-ack-please_ack">
<code>~please_ack</code> decorator</a> is optional. It asks the receiver to send an acknowledgement that
it has processed the message. If used, the receiver should send an ACK that looks like this:</p>
<pre class="example" title="An ACK">
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/abandon_connection/1.0/ack",
"@thread": { "thid": "c17147d2-ada6-4d3c-a489-dc1e1bf778ab" }
}
</pre>
</section>
</section>