-
Notifications
You must be signed in to change notification settings - Fork 10
/
index.html
1353 lines (1220 loc) · 60.1 KB
/
index.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
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
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Authorization Capabilities for Linked Data v0.3</title>
<script src='//www.w3.org/Tools/respec/respec-w3c' class='remove'></script> <script class='remove'>
var respecConfig = {
specStatus: "CG-DRAFT",
subtitle: "An object capability framework for linked data systems",
editors: [
{name: "Christine Lemmer-Webber",
url: "https://dustycloud.org/",
company: "Spec-Ops",
companyURL: "https://www.spec-ops.io/"},
{name: "Manu Sporny",
url: "http://manu.sporny.org/",
company: "Digital Bazaar",
companyURL: "http://digitalbazaar.com/"}],
authors: [
{name: "Christine Lemmer-Webber",
url: "https://dustycloud.org/",
company: "Spec-Ops",
companyURL: "https://www.spec-ops.io/"},
{name: "Manu Sporny",
url: "http://manu.sporny.org/",
company: "Digital Bazaar",
companyURL: "http://digitalbazaar.com/"},
{name: "Mark S. Miller",
url: "http://www.erights.org/talks/thesis/",
company: "Agoric",
companyURL: "https://agoric.com"}],
license: "w3c-software-doc",
processVersion: 2017,
edDraftURI: "https://w3c-ccg.github.io/zcap-spec/",
shortName: "zcap-spec",
group: "credentials",
otherLinks: [
{
"key": "Repository",
"data": [
{
"value": "Git repository",
"href": "https://github.com/w3c-ccg/zcap-spec",
},
{
"value": "Issues",
"href": "https://github.com/w3c-ccg/zcap-spec/issues",
},
{
"value": "Commits",
"href": "https://github.com/w3c-ccg/zcap-spec/commits/gh-pages",
}
]
}
],
// name of the WG
wg: "Credentials Community Group",
// URI of the public WG page
wgURI: "https://www.w3.org/community/credentials/",
// name (with the @w3c.org) of the public mailing to which comments are due
wgPublicList: "public-credentials",
// URI of the patent status for this WG, for Rec-track documents
// !!!! IMPORTANT !!!!
// This is important for Rec-track documents, do not copy a patent URI from a random
// document unless you know what you're doing. If in doubt ask your friendly neighbourhood
// Team Contact.
// NOTE: Though not a Working Group, and this spec is not yet rec-track,
// the CCG follows the W3C Community Contributor License Agreement.
wgPatentURI: "https://www.w3.org/community/about/agreements/cla/",
};
</script>
</head>
<!-- Style guide for this document:
- Indent tags appropriately according to nesting depth
- Newline after every sentence (this helps making reading git diffs
easier, as well as merging in complicated changes, because a change
will only affect a sentence at a time rather than a complete
paragraph)
- Wrap text at column 79 (the least critical of the three conventions
since this merely helps the text look nicer in many text editors)
-->
<body>
<section id='abstract'>
<p>
Authorization Capabilities for Linked Data (<code>ZCAP-LD</code> for
short) provides a
secure way for linked data systems to grant and express authority
utilizing the
<a href="https://en.wikipedia.org/wiki/Object-capability_model">
object capability model</a>.
Capabilities are represented as linked data objects which are signed
with <a href="https://w3c-ccg.github.io/ld-proofs/">
Linked Data Proofs</a>.
ZCAP-LD supports delegating authority to other entities
on the network by chaining together capability documents.
"Caveats" may be attached to capability documents which may be used to
restrict the scope of their use, for example to restrict the actions
which may be used or providing a mechanism by which the capability may
be later revoked.
</p>
</section>
<section id='sotd'>
<p>
This specification is currently being drafted to be considered as a
work item for the
<a href="https://w3c-ccg.github.io/">Community Credentials Group</a>.
</p>
</section>
<section id="introduction">
<h2>Introduction</h2>
<p><i>
This document is being based off of a
<a href="https://github.com/WebOfTrustInfo/rebooting-the-web-of-trust-fall2017/blob/master/draft-documents/lds-ocap/lds-ocap.md">paper from Rebooting Web of Trust</a>.
In the early stages of this document some ideas may be better
described in that paper than yet in this specification.
</i></p>
<p>
This document does not cover a specific method for delivering ZCAP-LD
invocations to an object, though something like the inbox property and
associated delivery mechanisms from Linked Data Notifications and
ActivityPub is one possible system.
However there is nothing about ZCAP-LD that is specific to HTTP; for
example, both capabilities and invocations could be stored on a
blockchain or a distributed hash table.
</p>
<section>
<h2>Capabilities vs. Access Control Lists</h2>
<p>
One of the first questions that is usually asked about using
Object Capabilities for authorization is: "How are Capabilities
different from Access Control Lists?". Fundamentally, Access Control
Lists are about <em>authority by identity</em> whereas
Object Capabilities are about <em>authority by possession</em>.
</p>
<p>
Authority by identity is the process of giving access to a resource
to a specific entity based on their identity. These processes
typically ask the question: "Who are you?"
</p>
<p>
Authority by possession is the process of giving access to a resource
to any entity that possesses something, like a key. These processes
typically ask the question: "Do you have a key that fits this lock?"
</p>
<p>
This document doesn't explain why Access Control Lists lead to
a variety of security issues or why Object Capabilities provide
stronger security guarantees. For those that would like to
learn more about these topics,
<a href="http://srl.cs.jhu.edu/pubs/SRL2003-02.pdf">Capability Myths Demolished</a>
and
<a href="http://waterken.sourceforge.net/aclsdont/current.pdf">ACLs Don't</a>
provide a deeper exploration into the benefits of Object Capabilities.
</p>
</section>
<section id="zcap-by-example">
<h2>ZCAP-LD by Example</h2>
<p>
Much of modern computing security infrastructure relies on "who is
doing something" using access control lists.
For example, our friend Alyssa P. Hacker has a car, and she would
like to drive it
In the access control list world, the car itself may scan Alyssa's
face, determine that Alyssa is the driver, and say "Welcome Alyssa,
you are now free to drive."
Talking cars are appealing and fun, but Alyssa may run into
challenges when she would like to allow others to drive her car.
</p>
<p>
Fortunately, there is another paradigm that is even more familiar to
the car scenario, but less familiar in the context of computing,
despite providing some superior properties and a greater degree
of safety: object capabilities.
Object capabilities focus not on "who" is performing an action, but
upon "what" source of authority permits an action to occur.
As it turns out, Alyssa does not have a talking and face-scanning
car, she has a car that accepts a car key.
The car may have no memory of Alyssa whatsoever, but as long as
Alyssa holds the kind of key that enables her to drive the car, she
can drive the car.
Capabilities are very similar to this car metaphor, and we can encode
this same idea in ZCAP-LD.
The following document delegates authority from the car (who always
has authority over itself) to Alyssa so that she may drive:
</p>
<!-- TODO: Should we include the full embedded key? That's better
practice in general (outside of DIDs) but will make the example
noisier -->
<pre class="example highlight javascript">
{
"@context": ["https://w3id.org/security/v2",
"https://autopower.example/"],
"id": "https://whatacar.example/a-fancy-car/proc/7a397d7b",
// Since this is the first delegated capability, the parentCapability
// points to the target this capability will operate against
// (in this case, Alyssa's Car)
"parentCapability": "https://whatacar.example/a-fancy-car",
// We are granting authority specifically to one of Alyssa's
// cryptographic keys (not to be confused with the car
// key metaphor!)
"invoker": "https://social.example/alyssa#key-for-car",
// Finally we sign this object with cryptographic material from
// Alyssa's Car's capabilityDelegation field, and using the
// capabilityDelegation proofPurpose.
"proof": {
"type": "Ed25519Signature2018",
"created": "2018-02-13T21:26:08Z",
"capabilityChain": [
"https://whatacar.example/a-fancy-car"
],
"jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..lfAFjrWE-4RxhL0gtzSMRX72NR9SRDgaMmkjPA4if0ERbw4R2bnts5sAs8OyhAlbFzBAKOqrFk57AYqwSR2vCw",
"proofPurpose": "capabilityDelegation",
"verificationMethod": "https://example.com/i/alice/keys/1"
}
}
</pre>
<p>
Turning on this car and driving into the sunset is as easy as
invoking the capability to do so:
</p>
<pre class="example highlight javascript">
{"@context": ["https://example.org/zcap/v1",
"https://autopower.example/"],
"id": "urn:uuid:ad86cb2c-e9db-434a-beae-71b82120a8a4",
"action": "Drive",
"proof": {
"type": "RsaSignature2016",
// A linked data document can be an invocation if it has a
// proofPurpose of capabilityInvocation and links to the capability
// chain it is invoking
"proofPurpose": "capabilityInvocation",
"capability": "https://whatacar.example/a-fancy-car/proc/7a397d7b",
"created": "2016-02-08T17:13:48Z",
"creator": "https://social.example/alyssa/#key-for-car",
"signatureValue": "..."}}
</pre>
<p>
Alyssa lives with her roommate and long-time friend Ben Bitdiddle.
While they're living together, she'd like that he be able to drive
her car too.
Capabilities support delegation, so she could delegate a new
capability to Ben giving him full authority, not unlike going to the
hardware store and having them copy the car key.
But Alyssa knows that she and Ben will probably not be roommates
forever, and she feels no need for him to be able to drive her car
once they are not, so she would like to have the option to revoke
his authority.
In the world of object capabilities, this is entirely possible by
adding a "caveat" that permits future revocation.
We can imagine this to be like a new car key that has a remote
destruction mechanism: Alyssa can press a button that she has,
a wire burns out inside the car key, and the car key will not be usable
anymore.
Alyssa generates a new capability document that points at the
capability she has, adding the caveat:
</p>
<pre class="example highlight javascript">
{"@context": ["https://example.org/zcap/v1",
"https://autopower.example/"],
"id": "https://social.example/alyssa/caps#79795d78",
// Pointing up the chain at the capability from which Alyssa was
// initially gained authority
"parentCapability": "https://whatacar.example/a-fancy-car/proc/7a397d7b",
// Alyssa grants authority specifically to one of Ben's
// cryptographic keys
"invoker": "https://chatty.example/ben/#key-33",
// Alyssa adds a caveat: Ben can drive her car, unless she flips
// the bit at this url
"caveat": [
{"type": "ValidWhileTrue",
"uri": "https://social.example/alyssa/ben-can-still-drive"}],
// Finally Alyssa signs this object with the key she was granted
// authority with
"proof": {
"type": "RsaSignature2016",
"proofPurpose": "capabilityDelegation",
"created": "2017-03-28T06:01:25Z",
"creator": "https://social.example/alyssa/#key-for-car",
"signatureValue": "..."}}
</pre>
<p>
Alyssa hands the car key to Ben, and Ben marks the car key in such
a way that reminds him that it's specifically to drive Alyssa's car.
Several months pass and Ben receives a message from Alyssa asking if
he might enjoy joining her at an award ceremony her university is
holding.
Alyssa is already at the university and is getting a ride to the
venue, so she suggests Ben drive her car and meet her there.
Ben invokes his capability, the car performs all relevant checks on
the capability (including that the proof/signature is valid and applicable,
and that the caveat is still valid), and off Ben drives.
</p>
<p>
Ben arrives at the fancy award venue, where there is valet parking.
The Valet approaches wearing the nametag "Lem E. Driveit" and asks
for a key to park the car.
Ben remembers he has heard some stories about valets going on
joyrides and isn't sure if they're true, but decides there's no need
to take the risk: he can use his capability to create a new, further
restricted capability which he can delegate to Lem.
This new car key has the caveat that it can be used to drive up
to 5 kilometers, but no more:
</p>
<pre class="example highlight javascript">
{"@context": ["https://example.org/zcap/v1",
"https://autopower.example/"],
"id": "https://chatty.example/ben/caps#2cdea8c1",
"parentCapability": "https://social.example/alyssa/caps#79795d78",
"invoker": "https://lem.example/#key-bf36",
// Ben adds this caveat: this capability can be used to drive the
// car, but not for more than 5 kilometers
"caveat": [
{"type": "DriveNoMoreThan",
// Alyssa's gauge currently says 123854 kilometers driven,
// so this is only 5 km more than the current value
"kilometers": 123859}],
// Finally Ben signs this object with the key he was granted
// authority with
"proof": {
"type": "RsaSignature2016",
"proofPurpose": "capabilityDelegation",
"created": "2017-06-13T19:15:03Z",
"creator": "https://chatty.example/ben/#key-33",
"signatureValue": "..."}}
</pre>
<p>
(It probably doesn't matter to this scenario, but since it is derived
from the car key that Ben holds, it also has the same caveat that it
will also be remote destructed by Alyssa along with Ben's car key
should she press the relevant button.)
</p>
</section>
<section id="capabilities-are-safer">
<h2>Capabilities Are Safer</h2>
<p>
We can see from the above example that using an object capability
system such as ZCAP-LD can give us some additional
power around delegating and restricting the scope of capabilities.
But object capabilities provide improved safety characteristics
over Access Control Lists which may make them frequently better
choices (for more details, see the paper
<a href="http://waterken.sourceforge.net/aclsdont/current.pdf">
ACLs Don't</a>).
Object capability systems are in general more robust against:
</p>
<ul>
<li>
<b>Ambient authority problems:</b>
For example, in an access control list environment,
if an attacker gets you to open a message in your email client
which contains an image which triggers an arbitrary code execution
vulnerability in the image library it is using, an attacker can
use this to do everything that you can: they can read or destroy your
documents, they can run programs as you, and they can in general
do anything that you can... all from a pin-prick sized vulnerability.
Properly using an object capability environment, the worst an
attacker could do is mess with your email (or if the program is
itself capability aware, they may not be able to do even
that... they could just display some nasty imagery on your screen,
which they could do already anyway).
</li>
<li>
<b>Confused deputy attacks:</b>
For example, browsers and both backend and frontend software for
the web have frequently struggled with Cross-Site Request Forgery
attack issues.
Your browser may both allow websites to access resources on
other websites and also allow you to log into various websites,
say a social networking site or a bank.
A malicious website could use this to its advantage to trick
your browser into performing actions as you on those other sites...
say to read from or spam to your social timeline, or to withdraw
money from your bank account.
While various techniques to can be used to restrict the scope
of these attacks, they are notoriously hard to prevent.
</li>
</ul>
<p>
Object capabilities are less vulnerable to these kinds of attacks
because capabilities are an encoding of "the principle of least
authority" in software development practice.
ZCAP-LD helps bring the power of capabilities to the web, providing
specific and directed grants of authority.
</p>
</section>
<section id="root-capability">
<h2>Root Capability</h2>
<p>
A root zcap looks like this:
</p>
<pre class="example highlight javascript">
{
"@context": [
"https://w3id.org/zcap/v1"
],
"id": "urn:zcap:root:https%3A%2F%2Fexample.com%2Ffoo",
"controller": "did:key:example",
"invocationTarget": "https://example.com/foo"
}
</pre>
<p>
A root zcap MUST have an `@context` field that is a string with the
value `https://w3id.org/zcap/v1`. This field makes zcaps JSON-LD
compatible, but does not mean that any other JSON-LDisms are
permitted. In other words, zcaps are JSON-based, and the JSON has
been chosen carefully such that it can be interpreted properly as
JSON-LD as well. Other JSON-LD representations that deviate from the
JSON expression of a zcap are not permitted.
</p>
<p>
By enabling JSON-LD compatibility, DI proofs (Data Integrity Proofs,
formerly known as Linked Data proofs) are used instead of JOSE-based
signatures. This helps keep zcap sizes small by eliminating the need to
encapsulate zcaps via base64 encoding. This is particularly important
for expressing capability chains [TODO: link to capability chains],
where ancestor zcaps would be base64-encoded N+1 times where N is the
length or position in the chain. If neither of these approaches were
used, a novel signature encapsulation mechanism would have to be
invented to get the same benefits; instead, reuse of existing work is
preferred.
</p>
<p>
Additionally, JSON-LD compatibility enables CBOR-LD to be used
to express zcaps — further reducing size via semantic compression.
[Note: [See invoking a root zcap section]. When invoking a root zcap,
a capability invocation proof is added, not to the root zcap itself,
but rather to another document that is acceptable to an API. This
means that no additional contexts (especially cryptosuite contexts) ever
need to be added to a root zcap. Further work on the Data Integrity
1.0 spec could alleviate the need for additional cryptosuite
contexts entirely.]
</p>
<p>
A root zcap MUST have an `id` that is a string that expresses a URN.
This ID can always be dereferenced by the verifier system if it is a
valid root zcap for a particular endpoint. The ID of a root zcap
SHOULD [Note: this should become a MUST if it covers all use cases,
to keep things simple] have the following format:
</p>
<pre>
urn:zcap:root:${encodeURIComponent(invocationTarget)}
</pre>
<p>
This format makes it clear that the identifier is for the
root zcap for the root invocation target, `invocationTarget`.
</p>
<p>
A root zcap MUST have an `invocationTarget` that is a string that
expresses a URI. The invocation target identifies where the zcap may
be invoked, and identifies the target object for which the root zcap
expresses authority.
</p>
<p>
A root zcap MUST have a `controller` that is a string or an array of
strings that each express a URI that identifies a controller for the
root zcap. The controller (or controllers) may take any actions with
the invocation target (that are supported by the verifier) by
invoking the root zcap. The controller (or controllers) may create
delegated zcaps from the root zcap [TODO: link to delegated zcap
section].
</p>
<p>
Note: A root zcap MUST NOT have any other fields.
</p>
<p>
A root zcap can be invoked by referencing only its ID because the
verifier can (and MUST) always dereference the zcap locally using a
trusted dereferencing mechanism. This is because a root zcap does not
have a capability delegation proof; it is the root of trust for a
capability chain [TODO: link to capability chains].
</p>
<section id="invoking-root-capability">
<h2>Invoking a Root ZCAP</h2>
<p>
There can be multiple ways to invoke a root zcap; these include 1) by
using an HTTP signature in an HTTP request, and 2) by attaching an LD
capability invocation proof to a document. The verifier will decide
which of these methods is acceptable and what other information must
be signed (in the case of an HTTP signature) or what documents may
be submitted with attached capability invocation proof(s).
</p>
<p>
When invoking a root zcap using an HTTP signature, a
capability-invocation header must be included that identifies the
root zcap by ID (via an `id` parameter) and the capability action
that is being invoked (via an `action` parameter). The request URL
identifies the intended invocation target, which must either match
the invocation target in the root zcap, or, if the verifier allows
it, have the root zcap's invocation target as a prefix. The
capability action must be an action that is expected (supported) by
the verifier at the request URL. The capability action SHOULD be
read or write. The key used to create the HTTP signature must be either
1) the private key paired with a verification method that matches
the controller of the root zcap or 2) a verification method that is
controlled by the controller of the root zcap — and authorized for the
purpose of `capabilityInvocation`.
</p>
<p>
When invoking using a DI proof, a capability invocation proof must
be attached to a document that is acceptable by the API, as
defined by the specific API being accessed. The capability
invocation proof MUST include the intended `invocationTarget`, the
root zcap ID in the `capability` property, and the action to be taken
in the `capabilityAction` property. The same controller rules apply
as in the HTTP signature case.
</p>
</section>
<section id="dereferencing-root-capability">
<h2>Dereferencing a Root Capability on a Verifier System</h2>
<p>
It is expected that only verification systems will dereference root
zcaps from their IDs. One model for new HTTP APIs is to store a
controller value with every resource at the base of a hierarchy,
for instance, store controller `X` for the collection
`https://foo.example/collections/123`. When the root zcap for this
collection is invoked or referenced via a delegated zcap invocation,
the verifier can look up the `controller` property (or receive it from
another system in some kind of decentralized setup) for that
resource and include it in a "dynamically dereferenced" root zcap.
In other words, the verifier sees the root zcap ID
`urn:zcap:root:<encodeURIComponent(https://foo.example/collections/123)>`,
and dynamically converts that (after looking up its controller) into:
</p>
<pre class="example highlight javascript">
{
"@context": [
"https://w3id.org/zcap/v1"
],
"id": "urn:zcap:root:https%3A%2F%2Ffoo.example%2Fcollections%2F123",
// populated via a database or external system call
"controller": "did:key:example",
"invocationTarget": "https://foo.example/collections/123"
}
</pre>
</section>
</section>
<section id="delegated-capability">
<h2>Delegated Capability</h2>
<p>
A delegated zcap looks like this:
</p>
<pre class="example highlight javascript">
{
"@context": [
"https://w3id.org/zcap/v1",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "urn:uuid:cdc77118-6bfa-11ec-aceb-10bf48838a41",
"parentCapability": "urn:zcap:root:https%3A%2F%2Fexample.com%2Ffoo",
"controller": "did:key:example",
"invocationTarget": "https://example.com/foo",
"expires": "2021-11-03T18:33:51Z",
"allowedAction": [
"write",
"read"
],
"proof": {
"type": "Ed25519Signature2020",
"created": "2021-10-27T18:33:51Z",
"verificationMethod": "did:key:z6MkfWKcvBiKCfNgz5UUGseNt37t4dguEvFgJ9XvX2UV6zB9#z6MkfWKcvBiKCfNgz5UUGseNt37t4dguEvFgJ9XvX2UV6zB9",
"proofPurpose": "capabilityDelegation",
"capabilityChain": [
"urn:zcap:root:https%3A%2F%2Fexample.com%2Ffoo"
],
"proofValue": "z3t9BCQyF21MDVYmLKc9zbLreqx4wBtQnUsd5aqyoWS5FfhapRz7QjPNLcgKAornUVmJR4ZjbGpuxRFnffxX1ZjtF"
}
}
</pre>
<p>
A delegated zcap is different from a root zcap primarily in that it
has a `parentCapability`, an expiration date-time, and a capability
delegation proof (found in proof). It is also different from a root
zcap in that all delegated zcaps in a chain [link to capability
chains] must be fully provided to the verifier when invoking a
delegated zcap, so that the verifier is not required to dereference
them other than via the provided chain. <i><b>Note:</b> A verifier may still
need to query a database for delegated zcaps to perform
revocation checks by ID. However, a verifier MUST NOT be required to perform
network requests or database queries to dereference delegated zcaps
by ID when verifying the capability chain [link to capability
chains], prior to inspecting it for potential revocations.</i>
</p>
<p>
A delegated zcap MUST have an `@context` field with an array where the
first value is the zcapld context and any subsequent values identify
context(s) used to define vocabulary terms used in the capability
delegation proof. [Note: Maximum array size should be defined in the
spec along with rationale].
</p>
<p>
A delegated zcap MUST have an `id` that is a string that expresses a
URI. The id SHOULD have the format:
</p>
<pre>
urn:uuid:<uuid>
</pre>
<p>
Using this format enables CBOR-LD to perform compression on the ID
value, and reduces correlation risk by making the ID semantically
opaque.
</p>
<p>
A delegated zcap MUST have a `parentCapability` that is a string that
expresses the ID of the parent zcap. The parent zcap may be another
delegated zcap or the root zcap. A verifier MUST ensure that a
delegated zcap was created by a controller of its parent capability
by checking its capability delegation proof.
</p>
<p>
A delegated zcap can only be invoked by submitting the entire zcap. A
delegated zcap MUST have a capability delegation proof which
MUST contain the delegation chain.
</p>
<p>
[target for link to capability chains]
</p>
<p>
A capability delegation chain MUST be an array that includes the root
zcap using its ID (i.e., by reference only, not embedded) and every
other delegated zcap in its ancestry must be referenced by ID except
for the parent delegated zcap, which MUST be fully embedded. This
ensures that delegated zcaps are of minimal size (other delegated
zcaps in the chain are never repeated) and that every delegated zcap
can be dereferenced directly from the chain without ever having to hit
a network resource or similar. The capability delegation chain is
ordered; the first entry MUST be the root zcap's ID and any other
entries must be in the order of delegation from least recent to most
recent.
</p>
<p>
A verifier MUST limit the length of the capability chain to prevent
long chain attacks. A verifier SHOULD limit the length of the
capability chain to 10. [exposition on why 10 / link to security
section].
</p>
<p>
A root zcap MUST have an `invocationTarget` that is a string that
expresses a URI. The invocation target identifies where the zcap may
be invoked. A verifier MUST ensure that the `invocationTarget` either
matches the `invocationTarget` in the parent capability or, if
invocation target attenuation [link] is permitted, that it has the
`invocationTarget` from the parent capability as a prefix. A prefix is
defined as a base URI and parent path (and optional query) (i.e.,
`/`-delimited and `?`/`&`-delimited) [more rigorous definition].
</p>
<p>
A delegated zcap MUST have a `controller` that is a string or an array
of strings that each express a URI that identifies a controller for
the delegated zcap. The controller (or controllers) may take any
allowed actions [link] with the invocation target (that are supported
by the verifier) by invoking the delegated zcap. The controller (or
controllers) may create delegated zcaps from the delegated zcap.
<i><b>Note:</b> As with other data model sections in W3C specs, every property
of a zcap should be called out in its own subsection along with the
rules for the property.</i>
</p>
<p>
A delegated zcap MUST have an `expires` field that expresses an XSD
date-time <i><b>Note:</b> The JavaScript `new Date().toISOString()` code can
produce such a date representation, though it is preferred to remove
millisecond precision via `new Date().toISOString().slice(0, -5) +
'Z'`.</i>
</p>
<p>
A verifier MUST ensure that an invoked delegated zcap has not expired.
A verifier MUST ensure that a delegated zcap's expiration date-time is
not less restrictive than its parent capability's expiration
date-time, if present. <i><b>Note:</b> a root zcap does not have an expiration
date-time.</i>
</p>
<p>
A verifier SHOULD ensure that an invoked delegated zcap does not have
an expiration date-time that is more than three months in the
future. [TODO: exposition on why 3 months?] This is because a verifier
MUST store revoked zcaps [link to revocation] until they expire, to
prevent their use. A delegated zcap with an expiration date that is
unreasonably far into the future will have to be stored for an
unreasonable period of time to prevent its invocation. There are
other mitigation strategies here, such as considering all zcaps
delegated from a particular controller as revoked, or full key
revocation.
</p>
<p>
Delegated zcaps MUST have expiration date-times to support good
security hygiene practices and because zcaps support decentralized
delegation. In order to revoke a zcap, it must be submitted to the
verifier's revocation endpoint for the associated invocation target.
If a delegated zcap has been lost or misplaced, it MUST eventually
expire to avoid undesirable access.
</p>
<p>
A delegated zcap MAY have an `allowedAction` field that is a string or
an array of strings that each express an action that the controller of
the zcap may take when invoking the capability. A verifier MUST ensure
that the `allowedAction` field in a delegated zcap is not less
restrictive than the parent's capability, if present.
</p>
<p>
A delegated zcap MUST have a `proof` field that is an object or an
array of objects that each express a DI proof. At least one of these
proofs MUST be a zcap capability delegation proof.
[TODO: more details on this proof]
</p>
<p>
A capability delegator (one who creates a delegated zcap) may
attenuate authority by setting a more restrictive expiration
date-time, a more restrictive invocation target (via URL path- or
query-based attenuation), or a greater limit on the allowed actions. Taken
together, the API that a verifier manages access is expected to have
the flexibility required to model all desired authorization models.
</p>
<section id="delegated-capability-attenuation">
<h2>URL Path- or Query-based Attenuation</h2>
<p>
Note: The `@context` / vocab-based caveats have been removed and replaced with:
</p>
<p>
A verifier will accept delegations (and invocations) where a suffix
has been added to the parent zcap's invocation target (invoked zcap's
invocation target). The suffix MUST start with `/` or `?` if the
invocation target prefix has no `?`, and with `&` otherwise. This allows for
fully customizable attenuations via HTTP API path and query
parameters. For example, a ZCAP that can be invoked at
`https://foo.example/bars/123` can be delegated with an attenuation
such that the delegated ZCAP has an invocation target of
`https://foo.example/bars/123/bazzes/456`. This could be further
delegated and attenuated with a ZCAP with an invocation target of
`https://foo.example/bars/123/bazzes/456?day=tuesday` and then again
with `https://foo.example/bars/123/bazzes/456?day=tuesday&hour=12`.
</p>
</section>
<section id="invoke-delegate-capability">
<h2>
Invoking a Delegated ZCAP
</h2>
<p>
Just like with root zcaps, there can be multiple ways to invoke a
delegated zcap; two are the same as with root zcaps and are
defined with the differences described below:
</p>
<p>
When invoking a delegated zcap using an HTTP signature, a
capability-invocation header must be included that includes the full
delegated zcap in a `capability` parameter by serializing it to JSON,
gzipping the result, and then base64url-encoding the gzipped JSON.
</p>
<p>
When invoking using a DI proof, the `capability` property must express
the full delegated zcap.
</p>
<p>
TODO: Add section on revocation, detailing what verifiers MUST/SHOULD
do to provide revocation endpoints for zcaps. A root invocation
target SHOULD have a `/zcaps/revocations` subpath, where a root zcap of
`urn:zcap:root:<the revocations path/the zcap ID to revoke>` can be
invoked. The verifier SHOULD set the controllers for that root
zcap to all controllers in the (to be revoked) zcap's chain so
that any controller in the chain can revoke the zcap. Link to
example server-side revocation implementation:
https://github.com/digitalbazaar/ezcap-express/blob/main/lib/revoke.js
</p>
<p>
TODO: Detail algorithm for validation process:
https://github.com/digitalbazaar/zcapld/blob/4386185f784f552d6eaeb2c3c82959cb2e09762e/lib/CapabilityProofPurpose.js#L85
</p>
<p>
TODO: Detail how revocation works: Any controller in the chain of a
delegated zcap may post that zcap to:
`<rootInvocationTarget>/zcaps/revocations/<zcapToRevokeId>` using the
root zcap: `urn:zcap:root:encodeURIComponent(<rootInvocationTarget>/zcaps/revocations/<zcapToRevokeId>)`
to revoke.
Example: https://github.com/digitalbazaar/ezcap-express/blob/main/lib/revoke.js
</p>
</section>
</section>
</section>
<section id="terminology">
<h2>Terminology</h2>
<!-- TODO: Add introductory paragraph to this section -->
<dl>
<dt>capability</dt>
<dd>
Authority which may be invoked to perform some operation upon a
(linked data) object.
</dd>
<dt>target</dt>
<dd>
The entity that will be acted upon when the capability is invoked.
</dd>
<dt>capability chain</dt>
<dd>
A chain of capability documents which may be used to delegate
authority to other entities in the system.
Each capability document in the chain inherits the caveats of
previous capabilities in the chain and may only be granted by
entities which have existing authority within the chain.
</dd>
<dt>caveat</dt>
<dd>
Also known as "attenuation" within object capability literature,
a "caveat" may be attached to a capability as a restriction on
how that capability may be used.
Delegated capabilities will preserve caveats and themselves
may be further restricted by adding more caveats.
</dd>
<dt>invocation</dt>
<dd>
The "activation" of a capability, represented as a linked data
document which is signed in such a way that matches authority
granted through a prior capability.
<!-- TODO: fix up awkward wording here -->
An invocation may have arguments, similar to how a procedure call
may have arguments.
</dd>
<dt>action</dt>
<dd>
An argument of an invocation which directs what particular
functionality of the object is being used.
For example, an invocation against a file storage service
may specify either a write action or a read action.
(Actions are the same as what are frequently called "methods" in
computer programming.)
</dd>
<dt>parentCapability</dt>
<dd>
The previous capability document on the chain, which is granting
authority to this invocation document.
In the case of the first delegated capability document, this points
at the target.
</dd>
<dt>capabilityDelegation</dt>
<dd>
This term serves two purposes:
<ul>
<li>
As a property from which the target supplies the "initial source
of authority" on the chain.
This holds cryptographic material which it may use to initially
delegate on the chain (and in some cases which it may use to
invoke itself as a capability).
</li>
<li>
As the value of a proof's <code>proofPurpose</code> to indicate
that this proof is intended to grant authority to the <code>invoker</code>
entities on the capability.
</li>
</ul>
</dd>
</dl>
</section>
<section id="capabilities">
<h2>Capabilities</h2>
<p>
ZCAP-LD capabilities are encoded through a chain of linked data
documents, granting authority to a target, possibly restricted through
"caveats".
Authority starts with the target (which always has authority to invoke
itself) and extends to further <code>invoker</code> entities along
the chain.
Each capability document granting authority must be signed off with a
proof by an entity which has previously been granted authority on the
chain.
Any caveat applied by a parent in the chain applies to its descendants.
</p>
<div class="note">
<p>
The target's json-ld document is a kind of "special" capability document
implicitly granting authority to itself.
But why?
Surely in most protocols, such as when objects are sending
invocations over HTTP POST requests, any target that wants to
self-modify could do so internally without an explicit invocation
process.
But in some systems such as blockchains, there is no "internal" state,
so explicitly doing an invocation to change behavior is still useful.
</p>
<p>
Another reason is that it simplifies the invocation algorithm: as we
delegate authority to the first non-target entity, we do so using the
target's cryptographic authority.
If this authority can be used to grant capabilities, it may as well
be able to be used to invoke them as well.
</p>
</div>
<p>
Every capability document, except for the target, MUST have:
</p>
<ul>
<!-- TODO: What's the right way to say this?
This sounds very json-ld centric -->
<li>an associated <code>id</code></li>
<li>
<code>parentCapability</code>, which links to the target if this is
the first delegated capability on the chain, or otherwise links to
another capability document
</li>
<li>
<!-- TODO: open this up a bit more for more than just "keys" -->
a <code>proof</code> field, which MUST sign the document with