-
Notifications
You must be signed in to change notification settings - Fork 17
/
protocols.html
374 lines (358 loc) · 25.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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
<h1>Protocols</h1>
<section class="informative">
<h2>What is a protocol?</h2>
<p>Protocols are just formal recipes for stateful interactions. All peers will interact through protocols of one
type or another. Work on this spec grew out of work on <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0005-didcomm/README.md">DIDComm</a>,
which is the basis of <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/index.md">many JSON-message-based protocols</a>
that take advantage of DID-based encryption and privacy. However, using DIDComm is not the only way
to build a protocol. Therefore, this spec presents a general recipe for creating, reading, updating, and
deactivating DIDs, and then specifies how that recipe manifests specifically in a DIDComm
variant. It is possible to be compliant with the spec using a non-DIDComm protocol, too--as long as whatever
protocol is used is known to both parties and meets the requirements of the general recipe.
</p>
</section>
<section class="informative">
<h2>Roles and Agents in Protocols</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>
<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 communication, <em>registering</em> a peer DID with the other party or
parties in a relationship requires a specific protocol. This is the only protocol that must be supported
by an implementation that targets <a>Layer 2a</a> or <a>Layer 2b</a> support.
</p>
<section>
<h4>General Recipe</h4>
<p>Give the <a>stored variant</a> of a peer DID doc to a remote party in a way that guarantees:</p>
<ul>
<li>No other party knows the DID values or the content of DID docs (the "confidentiality" guarantee
of traditional security analysis).</li>
<li>Both parties can be sure that they know what the other party intends (the "integrity" guarantee).</li>
</ul>
<p>A trivial example of a compliant protocol might be for Alice and Bob to use AirDrop to trade DID docs
between Macbooks when they are standing next to each other -- IFF they are confident that the
communication channel between them is not hacked. This approach would not work well when the parties
are remote, because trust would be unachievable. Using HTTPS might be an improvement in that situation,
if it were done carefully. However, even with HTTPS, there are subtleties to consider and ways to go
wrong. A careful study of the DIDComm protocol and its guarantees is recommended when exploring
alternatives.
</p>
</section>
<section>
<h4>DIDComm Approach</h4>
<p>Agents that are capable of DIDComm use the <dfn>Out-of-Band Protocol</dfn> to invite/trigger connections, and a handshake protocol like <dfn>DID Exchange</dfn> to complete it. These protocols are
<a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0434-outofband/README.md">
formally documented in Aries RFC 0434</a> and <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0023-did-exchange/README.md">Aries RFC 0023</a>; only a summary of the process is offered here. It has 3 steps:
</p>
<ol>
<li>
<p>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.
</p>
<p class="note">If this relationship is intended to preserve anonymity, it should not be sent from
or to personal email, sms, etc. Instead, a one time identifier should be for whichever side(s)
wish be anonymous.
</p>
</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 an attachment
of the raw bytes of the <a>stored variant</a> of the <a>genesis version</a> of the invitee's DID
doc. The sender of the request message must be the <a>inception key</a> in the DID doc; this is
proved by using authenticated encryption with the encryption envelope. The inviter must verify that
the received DID and its doc were generated according to the <a href="#generation-method">namestring
generation method</a>, and that the inception key is the authenticated sender. This ensures a
strong binding between the received DID and the public key(s) contained in the DID Doc. See
<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>stored variant</a> of the <a>genesis version</a> of the
inviter's DID doc, and must be authenticated against the inviter's <a>inception key</a> in the same
way as the request.
</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>
<li>It is possible to conduct the protocol very asynchronously. Either party can be offline when the
other party sends a message; no server has to be listening in realtime to make it work. Invitations and
subsequent steps can be widely separated in time, and can use different transports.
</li>
</ul>
<p class="note">
For public invitations, additional security against man-in-the-middle attacks may be achieved by signing
the invitation message. If the public invitation includes an <a>anywise</a> DID, the invitee should verify
that the signature on the invitation matches with an active (not revoked!) verification key for the
DID. If the public invitation includes a verification key, then the invitee should verify that the
signature on the invitation matches that key, and once the DIDs are exchanged, the invitee should ask the
inviter to prove they still control that verification key. Regardless, having a trustworthy channel of
communication is not the same as knowing that the party you're connected with is trustworthy. Further
trustbuilding should usually follow the initial connection. This
likely includes mutual exchange of <a target="vcspec" href="https://w3c.github.io/vc-data-model/">verifiable credentials</a>.
</p>
</section>
</section>
<section>
<h3>Read (Resolve)</h3>
<p>With peer DIDs, resolution can be local or remote, and it can be resolution of <em>either</em> one's own peer
DID, or of a peer DID from a remote party. Local resolution of any DID--one's own or another's--is often
a simple matter of looking up a DID doc in a local cache. This lookup is internal and can be done any way
an implementation chooses. No protocol is required, and this spec has no opinion about how it should work.
However, when resolution involves a remote party (either one's own agent or the agent of a peer), a protocol
is involved.
</p>
<p class="note">Because peer DIDs are supposed to be resolvable ONLY by peers, resolution requests in this method
MUST NOT be honored if they do not come from peers. Furthermore, reasoning about the correctness of a response
is only possible if the genesis version of a peer DID doc is known to the requester. Implementations SHOULD
NOT return a resolved DID doc to a party that does not possess a copy of the genesis DID doc, or some
legitmate derivation thereof. To do otherwise would be to ask the <code>requester</code> to trust the
<code>responder</code> in a way that dilutes the goals of the method.
</p>
<section>
<h4>General Recipe</h4>
<p>A <code>requester</code> should formally ask a remote party for the DID doc--perhaps a specific version
or timestamp thereof--that corresponds to a particular DID. A <code>responder</code> should reply with
compatible data, in a way that guarantees confidentiality and integrity, plus:</p>
<ul>
<li>The <code>responder</code> can tell that the <code>requester</code> is an authorized peer.</li>
<li>It can be proved that the state in the response is derived from the genesis version of the DID doc.</li>
</ul>
<p>A trivial example of this recipe might be for Alice and Bob to perform mutual (NOT one-way) authentication
over HTTPS, and then to engage in a web service-based interaction that produces the resolved doc. This
approach is susceptible to MITM eavesdropping such as the ones used by SSL visibility appliances
<a target="_blank" href="https://www.symantec.com/products/ssl-visibility-appliance">offered by Symantec
</a> and <a target="_blank" href="https://www.f5.com/solutions/application-security/ssl-visibility">F5</a>.
It should therefore be used with careful consideration of the required <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0029-message-trust-contexts/README.md">
Message Trust Context</a>.
</p>
</section>
<section>
<h4>DIDComm Approach</h4>
<p>The DIDComm variant of this recipe 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:1zQmZMygzYqNwU6Uhmewx5Xepf2VLp5S4HLSwwgf2aiKZuwa",
"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/did_resolution/0.1/resolve_result",
"@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>
<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 subject. This operation is more important in the peer DID method than
in most other methods, because a loose collection of decentralized peers may include many different views
of current state, caused by inconsistent and incomplete connectivity within the peer group.
</p>
<section>
<h4>General Recipe</h4>
<p>As with other operations, update must cause data to flow in a way that provides confidentiality and
integrity. In addition, the protocol must guarantee that:</p>
<ul>
<li>Problems with order-of-update and data gaps are solved.</li>
<li>It is possible to prove the correctness of an update, even if it is reported by an untrusted party.</li>
<li>Eventual consistency is achievable.</li>
<li>The protocol can tolerate imperfectly or inconsistently connected participants. Some agents may
not be able to participate in synchronization at any given point in time--or ever.</li>
<li>Alice cannot assume that Bob's agents are centralized (communicate through a central clearinghouse;
all share a common view), and vice-versa. Alice can assume this about her <em>own</em> agents
if she likes, but requiring such a strategy of the other partner is not safe or reasonable.</li>
</ul>
<p>These requirements are very demanding. An approach that fails to satisfy the final requirement is
easy to imagine, though. Each side maintains a server that knows their own definitive state. Whenever
Alice changes her state, she makes sure that her state is known to her server. Bob does corresponding work
on his side. Whenever Alice gets a state update from Bob, she assumes that all of Bob's agents agree;
whenever she wants to notify Bob that her state has updated, she tells Bob's server, and depends on it to
pass the word along inside Bob's domain.
</p>
<p>Such an approach does not conform to this spec, because it requires that both identity owners, not just
the one running a particular implementation, centralize the management of their identity domains. It
also requires that servers be online and reachable during any DID doc updates by either party. This may
be a perfectly reasonable choice for any given identity owner, but it is not reasonable to impose on a
remote party.
</p>
</section>
<section>
<h4>DIDComm Approach</h4>
<p>The DIDComm approach implements these protocol requirements by trading <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0030-sync-connection/README.md#sync_state">
sync_state</a> messages with one or more peers. These messages can be sent in a very deliberate fashion,
but also in a more casual, gossip style. In addition, any other DIDComm messages exchanged between peers can
be decorated with `~state`, allowing checks to see whether a sync is needed. The details of `sync_state`
usage are documented in <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0030-sync-connection/README.md">Aries
RFC 0030</a>; here, we only summarize.</p>
<p>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 <code>base_hash</code>, 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>
<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.
</p>
<section>
<h4>General Recipe</h4>
<p>Send a message or make an API call announcing that the relationship is over. Possibly, receive an
acknowledgement in response.</p>
</section>
<section>
<h4>DIDComm Approach</h4>
<p>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>
</section>