Repository navigation
Expand file tree
/
Copy pathdid-docs.html
More file actions
572 lines (527 loc) · 33.5 KB
/
Copy pathdid-docs.html
File metadata and controls
572 lines (527 loc) · 33.5 KB
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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
<h1>DID docs</h1>
<p>A special, ultra-simple form of DID doc is supported.</p>
<section>
<h2>Backing Storage</h2>
<p>At first glance, it might seem that parties dealing in peer DID docs could just store raw DID docs.
However, this is only a viable answer for the lower 2 <a href="#layers-of-support">layers of support</a>
for peer DIDs. Any time a DID doc evolves, proof that the evolution is authorized must be found
in the DID doc's previous state. If an agent is offline for an extended period (e.g., a phone is lost in the
couch cushions for a week), multiple evolutions may have occurred by the time it reconnects--and it cannot
accept the latest state of the doc without validating the sequence of changes it underwent to get there. Agents
must be able to prove to one another that the state they hold is correct, and they must be able to answer
questions about <em>what</em> the state used to be, and <em>who</em> authorized <em>which</em> changes, <em>when
</em>.
</p>
<p>This means that updatable peer DID docs need to be associated with some type of <dfn>backing storage</dfn> that
adds metadata and history to the simple content of the docs themselves.
</p>
<p>The backing storage for updatable peer DID docs is therefore a sequence of <dfn>deltas</dfn>. Each delta is
a JSON object in this form:</p>
<pre class="example nohighlight" title="Delta structure">
{
"change": <base64url encoding of a change fragment>,
"by": [ {"key": <id of key>, "sig": <signature value>} ... ],
"when": <ISO8601/RFC3339 UTC timestamp with at least second precision>
}
</pre>
<p>Here, a <dfn>change fragment</dfn> is a sparse version of a DID doc that shows just the section being
updated. The <code>by</code> property contains one or more key+signature pairs over the raw (non-base64url-encoded)
JSON text of the change fragment, and <code>when</code> contains a value supplied by the system clock. This
value is like timestamps on an email header—not guaranteed to be highly accurate, but useful for rough
analysis.
</p>
<p>Deltas are uniquely identified by the SHA256 hash of the raw (non-base64url-encoded) bytes of their change fragment,
and so are the change fragments themselves. Two change fragments with the same semantic meaning but different
indents or different attribute orders are considered different changes. This is because peer DIDs entirely
ignore the thorny problem of JSON canonicalization. The raw bytes of change fragments are normative and MUST
NOT be altered.
</p>
<p>Comparisons of state between any two versions of a peer DID doc look at the raw bytes of all known
change fragments, beginning with the stored variant of the genesis doc. Instead of testing the semantic
equivalence of data structures built from DID docs, or comparing the resolved variants of DID Docs, they ask:
"Do both parties know about the same changes?" If yes, then peer DID docs are considered equivalent, regardless
of formatting differences.
</p>
<p>Deltas are like database transactions, in that they may embody multiple changes that must be performed together.
For example, key rotation involves both a key addition and a key deletion, performed as a unit.
All changes in a single delta MUST share a common authorization; it is invalid to combine into one delta changes
requiring two different authorizations, as this makes authorization of each individual change ambiguous.
</p>
<p>A resolved peer DID doc at any given point in time is a view or projection of the cumulative effect of all
known deltas up to that point, with resolution adding the DID value itself to the composite <a>stored
variant</a> of DID doc data.
</p>
<p class="note">Early explorations of this DID method used the term <dfn>microledger</dfn> for backing storage. This
term has some resonance, in that backing storage is an append-only record of immutable transactions. However,
ledger technology requires strong ordering, whereas our ordering requirements are somewhat relaxed. What we need
is closer to the approach of <a target="_blank" href="https://opentransactions.org/wiki/Triple-Signed_Receipts">
triple-signed receipts</a> or <a target="_blank" href="https://arxiv.org/abs/1907.02143">KERI</a>, not to a
ledger or blockchain maintained by pure consensus. Thus, we have chosen not to emphasize the term here, because
it may feel intimidating to some, and because the actual storage mechanism in an implementation of this method
could be a simple file, a database, or anything else that provides suitable features.
</p>
<p>In the discussion about generating a <a>numeric basis</a> for a peer DID, the <a>genesis version</a> of a peer
DID doc was defined. The genesis version is the one associated with the first delta committed to backing
storage. In the first delta, <code>change</code> contains the genesis state of the doc, <code>by</code> holds
a signature from any key defined internally in the genesis state, and <code>when</code> is populated by the
system clock.
</p>
<p class="note">The genesis state MUST only be accepted by a peer if it is properly authenticated. This cannot be
done by signing the DID doc, since such a signature doesn't bind the signer to the intention to share in any
given context. Instead, the holder of the <a>inception key</a> must either sign a nonce that's
bound to the sharing context, or must place authenticated encryption around the message that transmits the
document to the peer. This proves that the creator of the DID intended to register it with the peer, and has
not been shadowed by a malicious man-in-the-middle.
</p>
</section>
<section>
<h2>CRDTs</h2>
<p>Because peer DID docs can be updated by multiple parties at the same time (as when two agents of the same
identity owner rotate their keys without coordinating), they have the potential for merge conflicts. Resolving
these merge conflicts could introduce much complexity in our DID method. However, peer DID docs use a clever
technique that avoids much of the pain. The backing storage for peer DID docs is carefully defined to
be a <a target="wikipedia" href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">conflict-free
replicated data type</a> (<dfn>CRDT</dfn>).
</p>
<p>CRDTs are a deep subject unto themselves, with a body of academic research; additional study is recommended.
They are behind familiar experiences like simultaneous, distributed editing of Google Docs, which never raises
error messages about merge conflicts. Here, we will not explain their theory; we will simply note some key
requirements that they impose on DID docs and their <a>backing storage</a>. More details are given later in
this spec, where individual parts of the DID doc are described. The general rules are:
</p>
<ol id="crdt-rules">
<li>Core building blocks—keys, rules, and service endpoints—must be assigned
<code>id</code> properties that are unique within the DID doc, across all its versions.</li>
<li>All items with <code>id</code> properties must be immutable. They can be deleted, but they can never have
a different state than they were created with. The effect of modifying an item can be achieved by
deleting an old item and replacing it with a new item that has a different <code>id</code> and updated
properties.</li>
<li>Deleting an item is accomplished by adding its <code>id</code> to a <dfn>deletion list</dfn>. This list
is a root property of the <a>stored variant</a> of a DID doc and is named <code>deleted</code>. It is
suppressed when generating a <a>resolved variant</a> of the DID doc, so it is only visible in the deltas
of <a>backing storage</a>. See <a href="#deleting-a-publickey">this clarifying example</a>.</li>
<li>When any party encounters two versions of a peer DID doc that are mututally incompatible, an impartial,
ungameable resolution algorithm is used to restore harmony. See <a href="#conflict-resolution">Conflict
Resolution</a> in the appendix for details.
</li>
</ol>
</section>
<section>
<h2><code><dfn>publicKey</dfn></code></h2>
<p>The <code>publicKey</code> section of a peer DID document, in either stored or resolved form, is as you would
expect from a reading of the <a target="didspec" href="https://w3c-ccg.github.io/did-spec/#authentication">DID
spec</a>. Peer DID docs MUST define all of their internal and external keys in this section; although the DID
spec permits inline definitions in the <code>authentication</code> and <code>authorization</code> sections of a
DID doc, this DID method disallows that option to simplify the possible permutations of a <a>change fragment</a>.
</p>
<p>All <code>id</code> properties associated with a key defined internally in the DID doc MUST be in
relative, not absolute form (that is, "#xyz" instead of "did:peer:abc#xyz"). IDs for keys defined
interally may be generated in either of these two ways:
</p>
<ul>
<li>The first 8 characters of the key's unique representation may be used as the <code>id</code>, if this
provides enough uniqueness within the document. (Global uniqueness is irrelevant.) For example, if the
key is defined with a <code>publicKeyBase58</code> property value that begins with <code>H3C2AVvL</code>,
then its <code>id</code> would be <code>H3C2AVvL</code>; a key with a <code>publicKeyHex</code> property
that begins with <code>02b97c30</code> would have an <code>id</code> of <code>02b97c30</code>, and a key
with a <code>publicKeyPem</code> property that begins, after its <code>-----BEGIN PUBLIC KEY</code>
delimiter, with the value <code>izfrNTmQ</code>, would have an <code>id</code> of <code>izfrNTmQ</code>.
</li>
<li>A standard 128-bit UUID of type 1, 2, 3, 4, or 5 (see [[RFC4122]]), rendered with hyphens and in lower
case, may be used as the<code>id</code> instead.</li>
</ul>
<p class="note">All IDs in DID docs, including these, should be considered case-sensitive. Ignoring case will result
in invalid comparisons for key <code>id</code>s based on encodings that are not hex.
</p>
<p>Because peer DIDs usually operate independent of global registries, external references (where <code>controller</code>
is not <code>#id</code>) will probably be rare, with the possible exception of <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0046-mediators-and-relays/README.md">
mediator</a> keys that have the <a>route</a> privilege.
</p>
<pre class="example" title="A publicKey section">
{
...
"publicKey": [
{
"id": "H3C2AVvL",
"type": "Ed25519VerificationKey2018",
"controller": "#id",
"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}, {
"id": "02b97c30",
"type": "Secp256k1VerificationKey2018",
"controller": "#id",
"publicKeyHex": "02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71"
}, {
"id": "izfrNTmQ",
"type": "RsaVerificationKey2018",
"controller": "#id",
"publicKeyPem": "-----BEGIN PUBLIC KEY\r\nizfrNTmQ...END PUBLIC KEY-----\r\n"
}
]
...
}
</pre>
<p class="note">This DID method is relatively agnostic with respect to key types. However, elliptic curve
keys (Ed25519, Secp256, etc) are recommended because the keys are smaller, the number
of bits of security are greater, and the computations more efficient, than RSA key types.
</p>
<section>
<h3 id="adding-a-publickey">Adding a key</h3>
<p>To add a new key with <code>id</code> = <code>Mv6gmMNa</code> to a peer DID doc, you might create
a <a>change fragment</a> of the DID doc that looks like this:
</p>
<pre class="example" title="Change fragment that adds a new key">
{
"publicKey": [
{
"id": "Mv6gmMNa",
"type": "Ed25519VerificationKey2018",
"controller": "#id",
"publicKeyBase58": "Mv6gmMNam3uVAjH3C2AVvLZZn6z3wXmqPVpfkcJCwDwn"
}
],
"authorization": { "profiles": [ {"key": "#Mv6gmMNa", "roles", ["edge"]} ] }
}
</pre>
<p>Change fragments only show where something is <em>appended</em> to either normal lists or the <a>deletion
list</a>. Here, the single entries under <code>publicKey</code> and <code>authorization.profiles</code> are
additions, not replacements, to the lists that already contain values. (The <a>trust profile</a> embodied in
the <code>authorization.profiles</code> associates the new key with privileges. This must be done at creation
time. It is discussed under <a href="#authorization"><code>authorization</code></a>.) The <a>delta</a> that
encapsulates this update would take the above JSON text, base64url-encode it, and assign the result to the
delta's <code>change</code> property. It would need to be authorized by a key with the <a>key_admin</a>
privilege, evidenced in the delta's <code>by</code> field. The resulting delta might look like this:
</p>
<pre class="example" title="Delta that adds a new key">
{
"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>
</section>
<section>
<h3 id="deleting-a-publickey">Deleting a key</h3>
<p>Any key can be deleted by appending its <code>id</code> to the <code>deleted</code> list at the root of
the <a>stored variant</a> of a peer DID doc, and by removing its corresponding entry from the <code>publicKey</code>
section. Only the append-to-<code>deleted</code> operation needs to be represented in the <a>change
fragment</a>; the corresponding removal from the <code>publicKey</code> section is implied. For example, to
delete a key with <code>id</code> = <code>izfrNTmQ</code>, your <a>change fragment</a> would look like
this:
</p>
<pre class="example" title="Change fragment that deletes a key with id=izfrNTmQ">
{
"deleted": [ "izfrNTmQ" ]
}
</pre>
<p>This fragment would be base64url-encoded and signed in a corresponding delta, in much the same way that
the fragment was handled in the example about adding a key.</p>
</section>
</section>
<section>
<h2><code><dfn>authentication</dfn></code></h2>
<p>The <code>authentication</code> section of a peer DID document conforms to <a target="didspec"
href="https://w3c-ccg.github.io/did-spec/#authentication">standard practice described in the DID spec</a>,
with the constraint that only references, not inline key definitions, are allowed. Any keys referenced
here may be used to authenticate or login as the DID.
</p>
<p>However, the meaning of "authenticate" or "login" deserves comment, because there is a tendency in DID
circles to reference too many keys in this section, and because heavy use of this section is discouraged
with peer DIDs.
</p>
<p>A <dfn>sovereign domain</dfn> (the scope of things under the control of a single, sovereign identity owner) may
include keys that represent the identity owner with greater or lesser degrees of trust. For example, the
identity owner may hold one key on paper, locked in a safe; she may hold another key on a mobile device's
secure enclave, protected by a biometric; she may hold a third key on a server in a config file protected
only by an ACL. These keys may all be legitimate evidence that the DID subject is interacting, but
they are not equally strong evidence. Only the strongest forms of evidence should be accepted as a
basis for authentication when stakes are high.</p>
<p>This is not unlike what happens on the political landscape. A low-level diplomat and the president / premier
/ prime minister of a nation are both authentic representatives of their people—but the scope of their
privileges, and the concomitant trust, are different. Only the highest-level officials should be signing
binding international treaties.
</p>
<p>The <a href="#authorization"><code>authorization</code> section</a> of peer DID docs, described next, is
where fine-grained privileges are described. The <code>authentication</code> section is a blunt instrument,
incapable of distinguishing between these levels of trust, and incapable of associating trust with anything
more complex than a single key. It is supported for historical reasons, and because most so-called "DID
Authentication" use cases assume it will be populated. With peer DIDs, the strong recommendation is that
only keys held by the most trusted proxies should be referenced here—only list the equivalent of your
president / premier / prime minister keys in this section, not the equivalent of keys for your low-level
diplomats. This will prevent impersonation by less trusted keys when stakes are high.
</p>
<section>
<h3 id="adding-key-to-authn">Adding a key</h3>
<p>As mentioned earlier, all objects having an <code>id</code> property in peer DID docs are immutable. This
means that a key cannot change its status with respect to the <code>authentication</code> section of a peer
DID doc during its lifetime in that doc; it must be declared as an authentication key when it is first
defined. A <a>change fragment</a> for adding an internally defined key and giving it status in the
<code>authentication</code> section at the same time might look like this:
</p>
<pre class="example" title="Change fragment that adds a new key with authentication privileges">
{
"publicKey": [
{
"id": "Mv6gmMNa",
"type": "Ed25519VerificationKey2018",
"controller": "#id",
"publicKeyBase58": "Mv6gmMNam3uVAjH3C2AVvLZZn6z3wXmqPVpfkcJCwDwn"
}
],
"authentication": [ "#Mv6gmMNa" ],
"authorization": { "profiles": [ {"key": "#Mv6gmMNa", "roles", ["edge"]} ] }
}
</pre>
<p class="note">Adding or deleting a key with authentication privileges can only be authorized by a key that
has the <a>key_admin</a> privilege.</p>
<h3 id="deleting-key-from-authn">Deleting a key</h3>
<p>Because a key's authentication privileges are immutable, the only way to take away authentication
privileges from a key is to <a href="#deleting-a-key">remove it entirely from the DID doc</a>.
</p>
</section>
</section>
<section>
<h2><code><dfn>authorization</dfn></code></h2>
<p class="note">This section of a peer DID docs governs how DID docs are updated and DIDComm trust flows. It doesn't
contemplate custom authorization schemes such as peers might develop to give each other spending limits or
access to sensitive data. Those matters are better formalized with something like a verifiable credential, or a
simple digitally signed permission slip.
</p>
<p>Peer DID docs organize their <code>authorization</code> section into two lists. The first, <code>profiles
</code>, gives a <dfn>trust profile</dfn> for each key, as expressed by named roles the key holds. These
named roles are arbitrary strings chosen by the implementer; since they are only used to match against
rules in the second list, their meaning in normal language does not need to be understood by a party
wishing to support correct semantics.
</p>
<p class="note">Changes to the <code>profiles</code> list MUST be performed when a key is added or deleted;
the <a>trust profile</a> of a key cannot change after it is created.</p>
<p>The second list contains <a href="https://evernym.github.io/sgl" target="sgl">SGL</a> rules that grant
privileges according to named roles. Here is an example:
</p>
<pre class="example" title="An authorization section">
“authorization”: {
"profiles": [
{"key": "#Mv6gmMNa", "roles", ["edge"]}, // an "edge" key
{"key": "#izfrNTmQ", "roles", ["edge", "biometric"]}, // an "edge" and a "biometric" key
{"key": "#02b97c30", "roles", ["cloud"]}, // a "cloud" key
{"key": "#H3C2AVvL", "roles", ["offline"]}, // an "offline" key
],
"rules": [
{
"grant": ["register"],
"when": {"id": "#Mv6gmMNa"},
"id": "7ac4c6be"
},
{
"grant": ["route", "authcrypt"],
"when": {"roles": "cloud"},
"id": "98c2c9cc"
},
{
"grant": ["authcrypt", "plaintext", "sign"],
"when": {"roles": "edge"},
"id": "e1e7d7bc"
},
{
"grant": ["key_admin", "se_admin", "rule_admin"],
"when": {
"any": [{"roles": "offline"}, {"roles": "biometric"}],
"n": 2
}
"id": "8586d26c"
}
]
}
</pre>
<p>In plain english, these rules say:</p>
<ul>
<li>Let the key with id=#Mv6gmMNa have the <a>register</a> privilege.</li>
<li>Let a key have the <a>route</a> and <a>authcrypt</a> privileges when its set of roles contains "cloud".</li>
<li>Let a key have the <a>authcrypt</a>, <a>plaintext</a> and <a>sign</a> privileges when its set of roles
contains "edge".</li>
<li>Let any 2 keys, acting together, have the <a>key_admin</a>, <a>se_admin</a>, and <a>rule_admin</a>
privileges when their roles each contain either "offline" or "biometric".</li>
</ul>
<p>Far more elaborate rules can be constructed. See the <a target="sgl" href="https://evernym.github.io/sgl">
SGL documentation</a> for details.</p>
<section>
<h3>Privilege Inventory</h3>
<p>Unlike role names, the privileges named in these rules DO need to be understood by code that parses peer
DID docs; it is these privileges that others in a relationship should enforce. Possible values include:</p>
<dl>
<dt><dfn>register</dfn></dt>
<dd>The holder of this privilege is allowed to register the DID as an identifier with another party. Exactly
one key MUST hold this privilege in the genesis version of the DID doc. This <a>inception key</a> creates
the DID and takes custody of it at least until it can be exchanged with a peer. This key MUST authenticate
with the peer during DID exchange; any other authentication MUST be rejected as it may represent a
different, otherwise-authorized key trying to exchange the DID in ways that diverge from its creator's
intentions. After the DID has been registered once, no key SHOULD hold this privilege unless/until it is
registered again (e.g., in upgrading <a>pairwise</a> to <a>n-wise</a>).
</dd>
<dt><dfn>route</dfn></dt>
<dd>The holder of this privilege is allowed to receive and decrypt <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/concepts/0094-cross-domain-messaging#required-mediators-process-forward-messages">
DIDComm <code>forward</code> messages</a> encrypted for itself, and to forward the contained
<a href="https://github.com/hyperledger/aries-rfcs/blob/master/features/0019-encryption-envelope/README.md"
target="aries">DIDComm encryption envelope</a> to another key. Holders of these keys thus become aware
of the timing and size of some incoming messages for the recipient (though not of the messages' senders
or content). This privilege is required and appropriate for any cloud agent or <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0046-mediators-and-relays/README.md">
mediator</a> that exposes a service endpoint on behalf of mobile devices or other agents behind a
firewall.</dd>
<dt><dfn>authcrypt</dfn></dt>
<dd>The holder of this privilege is allowed to create messages and send them with <a target="wikipedia"
href="https://en.wikipedia.org/wiki/Authenticated_encryption">authenticated encryption</a>
that reveals the identity associated with this DID to the reciever. Most agents are likely to have this
privilege, but one designed for passive reception only (e.g., on an IoT sensor) might have it removed;
doing so would prevent a hacker from co-opting such a key into sending in a trusted way. Messages that
are authcrypted by a key that lacks this privilege SHOULD be rejected as unauthorized.</dd>
<dt><dfn>plaintext</dfn></dt>
<dd>The holder of this privilege can see <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/features/0044-didcomm-file-and-mime-types#didcomm-messages-dm">
plaintext DIDComm messages</a> intended for an identity owner engaged in a <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0003-protocols/README.md">protocol
</a>. External parties sending to the owner of a given DIDDoc should multiplex encrypt for all keys that
hold this privilege, except in special circumstances.</dd>
<dt><dfn>sign</dfn></dt>
<dd><p>The holder of this privilege can incur non-repudiable contractual obligations on behalf of the DID subject.
This may actually be a better test for login or authentication, in many cases, than whether a key appears
in the <a href="#authentication"><code>authentication</code> section</a> of the DID doc; it depends on
what trust is imputed after login.</p>
<p class="note">Any key holder can sign a DIDComm message; doing so gives non-repudiation to the
message. However, remember our <a href="#authentication">earlier discussion</a> about low-level
diplomats versus the president or prime minister of a country—both are authentic officials,
but only the president or prime minister's signature is binding on an international treaty. This
privilege makes explicit that sort of special binding-the-owner status; any other signatures
serve to prove origin with a specific agent but not the endorsement of the DID subject.
</p></dd>
<dt><dfn>key_admin</dfn></dt>
<dd>The holder of this privilege can add or remove other keys from a peer DID doc's <a href="#publickey">
<code>publicKey</code> section</a>, <a href="#authentication"><code>authentication</code> section</a>,
or <code>authorization.profiles</code> list. Typically this privilege is held only by very privileged
keys, or by combinations of keys, to prevent hackers who co-opt one device from adding new, malicious
keys to the inventory.
To guard against privilege escalation, it is important to enforce that entity
adding the new key can only add grant privileges (add <code>roles</code>) that it itself has.
Also note that a key can remove itself from <a href="#publickey"><code>publicKey</code> section</a>,
it does not need the <code>key_admin</code> privilege. A real example would be when an existing device with a
key in the DID doc gets damaged and the identity owner has no plans to replace it.
</dd>
<dt><dfn>se_admin</dfn></dt>
<dd><p>The holder of this privilege can add or remove items from a peer DID doc's <a href="#service">
<code>service</code> section</a>.</p>
</dd>
<dt><dfn>rule_admin</dfn></dt>
<dd><p>The holder of this privilege can add or remove rules from a peer DID doc's <code>authorization.rules
</code> list. Typically this privilege is held only by very privileged keys, or by combinations of keys.</p>
</dd>
<dt><dfn>rotate</dfn></dt>
<dd>The holder of this privilege can replace its associated key definition, and all references to that
key throughout a DID doc, with a new key definition and references, in a single delete-and-add
operation. If key #2 has this privilege and exercises it, the result is that key #2 is revoked from
the doc, but a new key (perhaps key #7) appears with exactly the same profile. This privilege is
assumed to be held by all keys unless rules specify otherwise. The construct <code>revoke-implicit</code>
is used to prevent keys from having implicit privileges. The example below shows that the key id
<code>#H3C2AVvL</code> is unable to replace its associated key definition.
</dd>
<pre class="example" title="Preventing keys from having implicit privileges">
“authorization”: {
"profiles": [
{"key": "#Mv6gmMNa", "roles", ["edge"]}, // an "edge" key
{"key": "#H3C2AVvL", "roles", ["offline"]}, // an "offline" key
],
"rules": [
{
"grant": ["authcrypt", "plaintext", "sign"],
"when": {"roles": "edge"},
"id": "e1e7d7bc"
},
{
"revoke-implicit": ["rotate"],
"when": {"key": "#H3C2AVvL"},
"id": "f908a18c"
},
{
"grant": ["key_admin", "se_admin", "rule_admin"],
......
......
......
}
]
}
</pre>
</dl>
</section>
<section>
<h3>Adding a rule</h3>
<p>Notice that rules have <code>id</code> properties. The IDs for these rules can be assigned by any convenient
method that provides collision resistance across concurrent updates.
</p>
<p>These <code>id</code>s give rules the same <a>CRDT</a> semantics as keys
and service endpoints—they can be added or removed with deltas, but never modified. A <a>change
fragment</a> that adds a new rule might be:
</p>
<pre class="example" title="Change fragment that adds a new rule">
{
"authorization": {
"rules": [
{
"grant": ["route", "authcrypt"],
"when": {"roles": "cloud"},
"id": "rule-7"
}
]
}
}
</pre>
<p class="note">Both adding and deleting a rule must be authorized by a key with the <a>rule_admin</a> privilege.
Care should be taken to bundle additions and deletions of rules in such a way that once a full <a>delta</a>
is applied, the new state provides adequate privileges for all existing keys.
</p>
</section>
<section>
<h3>Deleting a rule</h3>
<p>A <a>change fragment</a> that deletes a rule might look like this:
</p>
<pre class="example" title="Change fragment that deletes a rule with id=rule-7">
{
"deleted": [ "rule-7" ]
}
</pre>
<p>See the note above, in the <a href="#adding-a-rule">Adding a rule</a> section, about privileges and
transactional logic when deleting rules.</p>
</section>
</section>
<section>
<h2><code><dfn>service</dfn></code></h2>
<p>This section matches the <a target="didspec" href="https://w3c-ccg.github.io/did-spec/#service-endpoints">
general description of service endpoints in the DID Spec</a>. Any changes to this section of the DID doc
must be authorized by a key with the <a>se_admin</a> privilege.
</p>
<section>
<h4>Adding a service endpoint</h4>
<p>A <a>change fragment</a> that adds a service endpoint might look like this:</p>
<pre class="example" title="Change fragment that adds a service endpoint">
{
"service": [
{
"id": "#agent",
"type": "AgentService",
"serviceEndpoint": "https://agents-r-us.com"
}
]
}
</pre>
</section>
<section>
<h3>Deleting a service endpoint</h3>
<p>A <a>change fragment</a> that deletes a service endpoint might look like this:</p>
<pre class="example" title="Change fragment that deletes a service endpoint with id=agent">
{
"deleted": [ "#agent" ]
}
</pre>
</section>
</section>