-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
2609 lines (2144 loc) · 145 KB
/
Copy pathindex.html
File metadata and controls
2609 lines (2144 loc) · 145 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
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 lang="en">
<head>
<meta charset="utf-8">
<title>Lease-CAP: Liveness-Bound Capabilities for Decentralized Authorization</title>
<script src="https://www.w3.org/Tools/respec/respec-w3c" class="remove" defer></script>
<script class="remove">
var respecConfig = {
specStatus: "CG-DRAFT",
latestVersion: "https://w3id.org/lease-cap/",
edDraftURI: "https://github.com/sirrayalabs/lease-cap/spec/",
github: "https://github.com/sirrayalabs/lease-cap",
shortName: "lease-cap",
copyrightStart: "2024",
group: "credentials-community-group",
editors: [
{
name: "Amir Hameed Mir",
company: "Sirraya Labs",
companyURL: "https://sirraya.com",
w3cid: ""
}
],
authors: [
{
name: "Amir Hameed Mir",
company: "Sirraya Labs"
}
],
formerEditors: [],
subjectPrefix: "[lease-cap]",
doJsonLd: true,
lint: {
"no-unused-dfns": false,
"check-punctuation": true
},
localBiblio: {
"UCAN": {
title: "User Controlled Authorization Networks (UCAN)",
href: "https://github.com/ucan-wg/spec/",
authors: ["Brooklyn Zelenka", "Alan Shaw", "Irakli Gozalishvili"],
status: "Draft",
publisher: "UCAN Working Group"
},
"ZCAP-LD": {
title: "ZCAP-LD: Authorization Capabilities for Linked Data",
href: "https://w3c-ccg.github.io/zcap-ld/",
authors: ["Christopher Lemmer Webber", "Dmitri Zagidulin"],
status: "CG-DRAFT",
publisher: "W3C Credentials Community Group"
},
"DIDComm": {
title: "DIDComm Messaging Specification",
href: "https://identity.foundation/didcomm-messaging/spec/",
authors: ["Sam Curren", "Daniel Hardman", "Oliver Terbu"],
status: "Specification",
publisher: "DIF"
},
"RFC8785": {
title: "JSON Canonicalization Scheme (JCS)",
href: "https://www.rfc-editor.org/rfc/rfc8785.html",
publisher: "IETF"
}
},
otherLinks: [
{
key: "Repository",
data: [
{
value: "GitHub Repository",
href: "https://github.com/sirrayalabs/lease-cap"
},
{
value: "Issue Tracker",
href: "https://github.com/sirrayalabs/lease-cap/issues"
}
]
},
{
key: "Implementation",
data: [
{
value: "TypeScript Reference Implementation",
href: "https://github.com/sirrayalabs/lease-cap-ts"
},
{
value: "Python Reference Implementation",
href: "https://github.com/sirrayalabs/lease-cap-py"
}
]
}
],
maxTocLevel: 3,
postProcess: [addCustomStyles]
};
function addCustomStyles() {
const style = document.createElement("style");
style.textContent = `
.state-diagram {
font-family: monospace;
background: #f5f5f5;
padding: 1.5em;
border-radius: 8px;
overflow-x: auto;
line-height: 1.5;
}
.comparison-table td, .comparison-table th {
padding: 0.75em;
border: 1px solid #ddd;
}
.warning {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 1em;
margin: 1.5em 0;
border-radius: 4px;
}
.note {
background: #d1ecf1;
border-left: 4px solid #17a2b8;
padding: 1em;
margin: 1.5em 0;
border-radius: 4px;
}
.test-vector {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 1em;
margin: 1.5em 0;
font-family: monospace;
font-size: 0.9em;
overflow-x: auto;
}
.algorithm {
background: #e9ecef;
padding: 1.25em;
border-radius: 4px;
margin: 1.5em 0;
font-family: monospace;
}
.parameter-table {
width: 100%;
border-collapse: collapse;
margin: 1em 0;
}
.parameter-table th, .parameter-table td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
vertical-align: top;
}
.parameter-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.protocol-flow {
font-family: monospace;
background: #f5f5f5;
padding: 1em;
border-radius: 4px;
margin: 1em 0;
}
dfn {
font-weight: bold;
}
.security-box {
background: #fef9e6;
border: 1px solid #f0dbaa;
padding: 1em;
margin: 1em 0;
border-radius: 4px;
}
`;
document.head.appendChild(style);
}
</script>
</head>
<body>
<section id="abstract">
<p>Decentralized authorization systems face a fundamental challenge: once a capability is issued, it remains valid indefinitely unless explicitly revoked. In networks where revocation information cannot be reliably propagated — due to partitions, offline operation, or lack of centralized infrastructure — this creates the "zombie capability" problem. Existing solutions either centralize revocation (defeating decentralization) or lack temporal freshness guarantees altogether.</p>
<p><strong>Lease-CAP</strong> introduces <strong>Liveness-Bound Capabilities (LBC)</strong> — a novel temporal authorization layer where capabilities decay unless actively maintained through periodic synchronization. Unlike traditional capabilities that remain valid until explicit revocation, LBC requires controllers to regularly prove continued authorization to issuers. This creates a provable <strong>liveness guarantee</strong> for decentralized authorization, solving the zombie capability problem without central revocation services.</p>
<p>The specification introduces a <strong>STALE state</strong> — a bounded grace period for renewal that acknowledges network reality while maintaining security boundaries. During this window, verifiers require controllers to synchronize with the issuer before granting access, but do not immediately deny service. This elegant compromise enables seamless operation during temporary network partitions without compromising security.</p>
<p>A key architectural insight is the <strong>strict separation</strong> between the static capability credential (which describes <em>what</em> authority is granted) and the dynamic lease state (which captures <em>when</em> the capability was last synchronized). The immutable Verifiable Credential never contains timestamps; instead, an issuer-signed <code>LeaseSyncResponse</code> carries the current <code>lastSync</code> timestamp. Verifiers derive effective lease state exclusively from the latest valid response, never from fields embedded in the credential itself. This separation prevents forgery, supports multi-device scenarios, and enables efficient state management.</p>
<p>Lease-CAP is designed as a <strong>temporal control layer</strong> applicable to any capability-based authorization system, including UCAN, ZCAP-LD, and DIDComm-based agent-to-agent communication. The specification provides complete protocol definitions, cryptographic proof formats, verification algorithms, security analysis, and production-ready reference implementations in TypeScript and Python.</p>
</section>
<section id="sotd">
<p>This document is an Editor's Draft being prepared for consideration by the <strong>W3C Credentials Community Group (CCG)</strong>. It is not a W3C Standard nor is it on the W3C Standards Track.</p>
<p><strong>Implementation Status:</strong> The specification has reached production readiness with complete reference implementations:</p>
<ul>
<li><strong>TypeScript/JavaScript:</strong> Production-ready implementation with full test suite, used in production deployments.</li>
<li><strong>Python:</strong> Production-ready implementation with comprehensive test coverage.</li>
<li><strong>Test Vectors:</strong> Complete set of edge-case test vectors covering all state transitions, error conditions, and security scenarios.</li>
</ul>
<p><strong>Draft Note:</strong> This draft incorporates feedback from implementers and security reviewers. Key areas under active discussion include offline mode parameters, delegation chain depth limits, and multi-device synchronization semantics. Implementers are encouraged to provide feedback through the GitHub issue tracker.</p>
<p>This document is governed by the <a href="https://www.w3.org/2023/Process-20231103/#patent-policy">W3C Patent Policy</a>.</p>
</section>
<section id="toc"></section>
<section id="introduction">
<h2>Introduction</h2>
<p>Authorization in decentralized systems presents unique challenges absent in traditional client-server architectures. When there is no central authority to consult for every access decision, systems must rely on cryptographic proofs of authorization — capabilities that can be presented to any verifier without real-time issuer involvement. This delegation of authority is powerful but introduces fundamental security questions: How does a capability ever become invalid? How does an issuer revoke access? How does a verifier know that the controller still deserves access?</p>
<section id="problem-statement">
<h3>Problem Statement</h3>
<p>Traditional capability systems suffer from what we term the <strong>"zombie capability" problem</strong>: once issued, capabilities remain valid indefinitely unless explicitly revoked. In centralized systems, revocation can be enforced through token introspection or revocation lists. However, in decentralized systems where revocation information cannot be reliably propagated — due to network partitions, offline operation, or the absence of a centralized revocation authority — this creates significant security risks.</p>
<p>Consider a typical scenario: An employee leaves an organization but possesses a capability issued months ago for accessing cloud resources. Without a central revocation service that the employee cannot bypass, that capability may remain usable indefinitely. Existing decentralized capability systems offer limited solutions:</p>
<ul>
<li><strong>UCAN (User Controlled Authorization Networks)</strong> provides delegation chains but has no built-in revocation mechanism. Capabilities remain valid until their optional expiry, which many deployments omit.</li>
<li><strong>ZCAP-LD</strong> offers similar delegation without temporal freshness guarantees. Revocation requires global revocation lists that are difficult to maintain in decentralized environments.</li>
<li><strong>Time-bound tokens (OAuth-style)</strong> provide expiry but no renewal mechanism, requiring complete re-issuance — impractical for long-lived delegations.</li>
</ul>
<p>The core insight of Lease-CAP is that <strong>authorization without liveness is incomplete in decentralized systems</strong>. A capability should not be a static, unchanging assertion of authority; rather, it should represent a continuing relationship that requires active maintenance. This shift from passive to active authorization fundamentally changes the security properties of decentralized systems.</p>
</section>
<section id="solution-overview">
<h3>Solution Overview</h3>
<p>Lease-CAP introduces <strong>Liveness-Bound Capabilities (LBC)</strong> where validity is a function of continuous participation, not just issuance. Each capability carries a lease specification that defines two key parameters:</p>
<ul>
<li><strong>TTL (Time-To-Live):</strong> The duration during which a capability remains ACTIVE after the last successful synchronization.</li>
<li><strong>GracePeriod:</strong> A bounded window after TTL expiration during which synchronization can still succeed, albeit with a "sync required" response from verifiers.</li>
</ul>
<p>Capabilities transition through four deterministic states as time advances:</p>
<table class="parameter-table">
<thead>
<tr>
<th>State</th>
<th>Condition</th>
<th>Verifier Action</th>
<th>Controller Action</th>
<th>Security Property</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ACTIVE</strong></td>
<td><code>N ≤ L + T + ε</code></td>
<td>Grant access normally</td>
<td>Proactive sync recommended before TTL expiration</td>
<td>Full authorization; no issuer contact required</td>
</tr>
<tr>
<td><strong>STALE</strong></td>
<td><code>L + T + ε < N ≤ L + T + G + ε</code></td>
<td>Return 403 with sync endpoint; require sync</td>
<td>Immediate sync required before retry</td>
<td>Bounded grace period; liveness preserved during partitions</td>
</tr>
<tr>
<td><strong>EXPIRED</strong></td>
<td><code>N > L + T + G + ε</code></td>
<td>Deny access; require re-issuance</td>
<td>Request new capability from issuer</td>
<td>Absolute expiry; zombie capability prevention</td>
</tr>
<tr>
<td><strong>FUTURE</strong></td>
<td><code>N < L − Δ</code></td>
<td>Deny access; report clock inconsistency</td>
<td>Check system clock synchronization</td>
<td>Prevents timestamp manipulation attacks</td>
</tr>
</tbody>
</table>
<p>The <strong>STALE state is the core innovation</strong> of Lease-CAP. It provides a bounded grace period for renewal that acknowledges the reality of distributed systems: network partitions happen, issuers may be temporarily unreachable, and controllers cannot always synchronize instantaneously. During this window, verifiers do not immediately deny access; instead, they return a 403 response that includes the sync endpoint and the verifier's current timestamp, enabling the controller to synchronize and retry. This design preserves liveness during temporary network issues without sacrificing security — a capability cannot remain in STALE indefinitely, as the GracePeriod bounds the window.</p>
</section>
<section id="what-makes-this-novel">
<h3>What Makes This Novel</h3>
<p>Lease-CAP introduces the concept of <strong>synchronization-bound authority</strong> — the principle that authority decays unless actively maintained through cryptographic proof of continued authorization. This is fundamentally different from existing approaches:</p>
<table class="comparison-table">
<thead>
<tr>
<th>Approach</th>
<th>Mechanism</th>
<th>Liveness Guarantee</th>
<th>Revocation Capability</th>
<th>Offline Operation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Time-bound tokens (OAuth)</td>
<td>Passive decay with absolute expiry</td>
<td>None (just expiry)</td>
<td>Requires introspection endpoint</td>
<td>Limited (no renewal)</td>
</tr>
<tr>
<td>Revocation lists</td>
<td>Reactive control via lists</td>
<td>None (propagation delay)</td>
<td>Yes, but propagation is unbounded</td>
<td>Unreliable (lists may be stale)</td>
</tr>
<tr>
<td>Static capabilities (UCAN, ZCAP-LD)</td>
<td>None (immutable assertions)</td>
<td>None</td>
<td>No</td>
<td>Full (unbounded, which is a risk)</td>
</tr>
<tr>
<td><strong>Lease-CAP</strong></td>
<td><strong>Active synchronization</strong></td>
<td><strong>Bounded liveness (T+G window)</strong></td>
<td><strong>Yes, bounded by T+G</strong></td>
<td><strong>Bounded, explicit opt-in</strong></td>
</tr>
</tbody>
</table>
<p>Beyond the liveness guarantee, Lease-CAP introduces several novel technical contributions:</p>
<ul>
<li><strong>State Separation:</strong> The static credential and dynamic lease state are strictly separated. This architectural decision prevents forgery, eliminates the need to re-issue credentials on every sync, and enables efficient multi-device scenarios where each device maintains its own lease state.</li>
<li><strong>Cryptographic Binding:</strong> Every sync response includes a hash of the original capability credential. This prevents substitution attacks where an attacker presents a valid lease state for a different capability, a vulnerability present in naive implementations of temporal capabilities.</li>
<li><strong>Lease Attenuation:</strong> Delegated capabilities must satisfy <code>T_child + G_child ≤ T_parent + G_parent</code>, ensuring that no child capability can outlive its parent's absolute expiration boundary. This preserves the principle of attenuation of authority throughout delegation chains.</li>
<li><strong>Multi-Device Sync Independence:</strong> The specification explicitly handles scenarios where multiple devices hold the same capability, allowing each to sync independently without invalidating others. This is essential for real-world deployments where users expect to use the same identity across phones, laptops, and other devices.</li>
</ul>
</section>
<section id="relationship-to-existing-standards">
<h3>Relationship to Existing Standards</h3>
<p>Lease-CAP is designed as a <strong>temporal control layer</strong> that can be applied to any capability-based authorization system. Rather than replacing existing standards, it extends them with liveness guarantees:</p>
<dl>
<dt><strong>UCAN (User Controlled Authorization Networks)</strong></dt>
<dd>Lease-CAP wraps UCAN delegation chains with lease state, adding temporal freshness to UCAN's delegation model. The UCAN's optional expiry field can be set to <code>issuanceDate + maxLifetime</code> as an absolute upper bound, while lease state provides fine-grained liveness control.</dd>
<dt><strong>ZCAP-LD</strong></dt>
<dd>Lease-CAP extends ZCAP-LD root capabilities with a lease specification. The ZCAP's invocation mechanism remains unchanged; lease state is carried separately, verified alongside the capability proof.</dd>
<dt><strong>DIDComm</strong></dt>
<dd>Lease-CAP sync messages can be wrapped in DIDComm envelopes for agent-to-agent communication. The specification provides guidance on asynchronous sync handling, mediator support, and end-to-end encryption.</dd>
<dt><strong>OAuth 2.0</strong></dt>
<dd>Lease-CAP offers a decentralized alternative to token introspection. Instead of a centralized introspection endpoint, issuers provide sync endpoints that controllers contact directly. Revocation is bounded and does not require real-time communication for every access.</dd>
</dl>
<div class="note">
<p><strong>Integration Note:</strong> When integrating Lease-CAP with existing systems, the lease specification is added as a new property in the capability object. Verifiers that understand Lease-CAP check liveness; those that don't can ignore the lease specification and treat the capability as a traditional static capability (though this is not recommended for production deployments).</p>
</div>
</section>
</section>
<section id="conformance">
<h2>Conformance</h2>
<p>This specification defines conformance criteria for three distinct roles: Controllers (entities that hold and exercise capabilities), Verifiers (entities that check capability validity), and Issuers (entities that create capabilities and manage sync state). Each role has mandatory and recommended requirements.</p>
<section id="rfc-2119-language">
<h3>RFC 2119 Language</h3>
<p>The key words <em class="rfc2119">MUST</em>, <em class="rfc2119">MUST NOT</em>, <em class="rfc2119">REQUIRED</em>, <em class="rfc2119">SHALL</em>, <em class="rfc2119">SHALL NOT</em>, <em class="rfc2119">SHOULD</em>, <em class="rfc2119">SHOULD NOT</em>, <em class="rfc2119">RECOMMENDED</em>, <em class="rfc2119">MAY</em>, and <em class="rfc2119">OPTIONAL</em> in this document are to be interpreted as described in <cite><a href="https://www.rfc-editor.org/rfc/rfc2119">RFC 2119</a></cite> and <cite><a href="https://www.rfc-editor.org/rfc/rfc8174">RFC 8174</a></cite>.</p>
</section>
<section id="conforming-controller">
<h3>Conforming Controller</h3>
<p>A <dfn>Controller</dfn> is the entity that holds a capability and exercises it to access resources. In the Lease-CAP model, controllers are responsible for maintaining the liveness of their capabilities through periodic synchronization with issuers.</p>
<p>A conforming Controller <em class="rfc2119">MUST</em>:</p>
<ol>
<li><strong>Implement the sync protocol</strong> defined in <a href="#protocol-flows"></a>, including the ability to send signed <code>LeaseSyncRequest</code> messages and process <code>LeaseSyncResponse</code> responses.</li>
<li><strong>Respect TTL and GracePeriod values</strong> from the issuer as specified in the capability's <code>leaseSpec</code>. Controllers <em class="rfc2119">MUST NOT</em> attempt to sync more frequently than the issuer's rate limits, nor less frequently than would cause the capability to expire.</li>
<li><strong>Apply jitter to sync scheduling</strong> as defined in <a href="#thundering-herd"></a> to prevent thundering herd problems when large fleets of devices sync simultaneously.</li>
<li><strong>Store and manage capabilities securely</strong>, protecting private keys and capability storage from unauthorized access. At minimum, capabilities <em class="rfc2119">SHOULD</em> be stored in encrypted form.</li>
<li><strong>Generate valid capability invocation proofs</strong> using the <code>capabilityInvocation</code> proof purpose, demonstrating control over the controller's private key.</li>
<li><strong>Never embed <code>lastSync</code> in the Verifiable Credential</strong>. The lease state is derived from <code>LeaseSyncResponse</code> objects stored separately. Any controller that embeds timestamps in the credential body is non-conforming.</li>
<li><strong>Maintain a lease state cache</strong> keyed by <code>capabilityId</code>, storing the latest valid <code>LeaseSyncResponse</code> for each capability.</li>
</ol>
<p>A conforming Controller <em class="rfc2119">SHOULD</em>:</p>
<ol>
<li><strong>Perform proactive sync before TTL expiration</strong> rather than waiting for STALE responses from verifiers. Proactive sync eliminates the first-request latency penalty and provides a better user experience.</li>
<li><strong>Implement Randomized Truncated Exponential Backoff</strong> for sync failures as defined in <a href="#implementation-guidance"></a>, preventing network storms during issuer outages.</li>
<li><strong>Log audit events</strong> for compliance, including successful syncs, failed sync attempts, and access requests. Audit logs <em class="rfc2119">SHOULD</em> include timestamps, capability IDs, and results.</li>
<li><strong>Detect clock drift</strong> by comparing local time with verifier timestamps received in 403 responses, and adjust sync timing accordingly.</li>
</ol>
<div class="note">
<p><strong>Multi-device Considerations:</strong> When the same capability is held across multiple devices (e.g., a user's phone and laptop), each device maintains its own independent lease state cache and sync schedule. The issuer <em class="rfc2119">MUST</em> accept sync requests where <code>previousLastSync</code> does not match the issuer's most recent sync value, as long as it matches a previously issued value (including the initial <code>issuanceDate</code>). This allows each device to sync independently without coordination.</p>
</div>
</section>
<section id="conforming-verifier">
<h3>Conforming Verifier</h3>
<p>A <dfn>Verifier</dfn> is the entity that checks capability validity before granting access to a protected resource. Verifiers are responsible for evaluating lease state, checking revocation status, and enforcing temporal bounds.</p>
<p>A conforming Verifier <em class="rfc2119">MUST</em>:</p>
<ol>
<li><strong>Implement the full state evaluation algorithm</strong> defined in <a href="#verification-algorithms"></a>, including all state transitions and priority ordering (FUTURE → REVOKED → INVALID → ACTIVE → STALE → EXPIRED).</li>
<li><strong>Enforce the future skew bound Δ</strong> configurable per <code>leaseSpec</code>. If <code>now < lastSync − Δ</code>, the capability <em class="rfc2119">MUST</em> be treated as FUTURE and rejected, regardless of other conditions.</li>
<li><strong>Validate all cryptographic proofs</strong> using the appropriate verification method. Verifiers <em class="rfc2119">MUST</em> resolve the issuer's DID to obtain the current verification key and verify the proof according to the Data Integrity specification.</li>
<li><strong>Maintain a revocation cache</strong> with <code>expiresAt</code> set to <code>max(revokedAt + TTL + GracePeriod, lastSeenTimestamp + TTL + GracePeriod)</code>. This formula ensures the cache entry outlives any capability instance that was valid at the time of revocation, even for verifiers that haven't recently seen the capability.</li>
<li><strong>Reject capabilities where <code>now < lastSync − Δ</code></strong> as FUTURE state, preventing timestamp manipulation attacks where an issuer or attacker sets <code>newLastSync</code> far in the future.</li>
<li><strong>Derive effective lease state exclusively from the latest valid <code>LeaseSyncResponse</code></strong> in the lease state cache. If no valid response exists, use the initial state with <code>lastSync = issuanceDate</code>. Verifiers <em class="rfc2119">MUST NOT</em> read timestamp fields from the credential body.</li>
<li><strong>Include the current timestamp in all 403 Sync Required responses</strong> using the <code>verifierTimestamp</code> field. This enables controllers to detect clock drift before attempting sync.</li>
<li><strong>Reject any <code>LeaseSyncResponse</code> whose <code>capabilityHash</code> does not match <code>H(canonicalize(capability))</code></strong>. This check prevents substitution attacks where a valid lease state is presented for a different capability.</li>
</ol>
<p>A conforming Verifier <em class="rfc2119">SHOULD</em>:</p>
<ol>
<li><strong>Use NTP-synchronized wall-clock time</strong> with monotonic clocks for drift detection. While absolute time is needed for state evaluation, monotonic clocks provide a tamper-resistant source for measuring intervals.</li>
<li><strong>Implement rate limiting per controller</strong> to prevent denial-of-service attacks. The RECOMMENDED rate limit is 10 sync requests per minute with a burst allowance of 30 requests.</li>
<li><strong>Log verification decisions for audit</strong>, including the capability ID, controller DID, evaluated state, timestamp, and outcome. Audit logs <em class="rfc2119">SHOULD</em> be stored in a tamper-evident manner.</li>
<li><strong>Support offline mode only when explicitly enabled by the issuer</strong> in the <code>leaseSpec.offlineMode</code> object. When offline mode is disabled, verifiers <em class="rfc2119">MUST</em> deny access if they cannot reach the issuer to verify STALE capabilities.</li>
</ol>
</section>
<section id="conforming-issuer">
<h3>Conforming Issuer</h3>
<p>An <dfn>Issuer</dfn> is the entity that creates capabilities and manages their lease state. Issuers are trusted to enforce lease attenuation, maintain revocation state, and provide sync endpoints.</p>
<p>A conforming Issuer <em class="rfc2119">MUST</em>:</p>
<ol>
<li><strong>Provide a sync endpoint</strong> as defined in <a href="#protocol-flows"></a> that accepts <code>LeaseSyncRequest</code> messages and returns signed <code>LeaseSyncResponse</code> messages.</li>
<li><strong>Sign all sync responses with <code>capabilityAssertion</code> proofs</strong> using the issuer's private key. The signature <em class="rfc2119">MUST</em> be verifiable using the verification method referenced in the capability credential.</li>
<li><strong>Enforce lease attenuation</strong>: for any delegated capability, <code>T_child + G_child ≤ T_parent + G_parent</code> <em class="rfc2119">MUST</em> hold. Issuers <em class="rfc2119">MUST NOT</em> issue child capabilities that could outlive their parent's absolute expiration boundary.</li>
<li><strong>Maintain capability state</strong> including revocation status, delegation chains, and historical <code>newLastSync</code> values (for at least <code>TTL + GracePeriod</code> to support multi-device scenarios).</li>
<li><strong>Verify controller identity before issuing sync responses</strong> by checking the <code>capabilityInvocation</code> proof in the sync request. Issuers <em class="rfc2119">MUST</em> ensure the request signer matches the controller DID in the capability.</li>
<li><strong>Not issue a successful <code>LeaseSyncResponse</code> for a revoked capability</strong>. If a capability is revoked, the issuer <em class="rfc2119">MUST</em> return a response with <code>status: "revoked"</code>.</li>
<li><strong>Include <code>status = "revoked"</code> in sync responses for revoked capabilities</strong>, along with <code>revokedAt</code> timestamp and revocation reason. The response <em class="rfc2119">MUST</em> be signed normally.</li>
<li><strong>Support configurable Δ per leaseSpec</strong> to accommodate different network environments (e.g., 5 seconds for web applications, 30 seconds for satellite links). When not specified, Δ defaults to 5000 ms.</li>
<li><strong>Verify that a parent capability is in ACTIVE state before renewing a child capability</strong>. If the parent is STALE or EXPIRED, the issuer <em class="rfc2119">MUST NOT</em> issue a successful sync response for the child.</li>
<li><strong>Remember previously issued <code>newLastSync</code> values</strong> for at least <code>TTL + GracePeriod</code> to support multi-device scenarios where one device's <code>previousLastSync</code> may be older than the most recent sync issued to another device.</li>
</ol>
<p>A conforming Issuer <em class="rfc2119">SHOULD</em>:</p>
<ol>
<li><strong>Implement rate limiting per controller</strong> to prevent abuse. The RECOMMENDED limit is 10 sync requests per minute with a burst of 30.</li>
<li><strong>Support batch sync</strong> where a single request can update multiple capabilities simultaneously, improving privacy and efficiency.</li>
<li><strong>Provide revocation endpoints</strong> allowing controllers or administrators to request revocation of compromised capabilities.</li>
<li><strong>Monitor for thundering herd patterns</strong> where many devices sync simultaneously, and adjust sync response timing or rate limits accordingly.</li>
</ol>
<div class="security-box">
<p><strong>Security Note on Parent State Verification:</strong> The requirement to verify parent ACTIVE state before renewing a child capability introduces a potential race condition: a parent could expire between the check and the child's next use. To mitigate this, issuers <em class="rfc2119">SHOULD</em> include the parent's <code>lastSync</code> value in the child's sync response, or verifiers <em class="rfc2119">SHOULD</em> re-check parent state during delegation chain verification (as specified in Algorithm 11.5).</p>
</div>
</section>
</section>
<section id="terminology">
<h2>Terminology</h2>
<p>This section defines terms used throughout the specification. Readers familiar with Verifiable Credentials, DID Core, and capability-based authorization systems will recognize many concepts; Lease-CAP introduces new terminology around temporal state and synchronization.</p>
<section id="core-terms">
<h3>Core Terms</h3>
<dl>
<dt><dfn>Liveness-Bound Capability (LBC)</dfn></dt>
<dd>A capability whose validity requires periodic synchronization with the issuer. Unlike static capabilities that remain valid until revocation or expiry, LBCs decay over time unless actively maintained.</dd>
<dt><dfn>Lease</dfn></dt>
<dd>The temporal validity period of a capability, defined by the combination of TTL and GracePeriod. The lease determines how long a capability remains ACTIVE after synchronization and how long it can be renewed.</dd>
<dt><dfn>TTL (Time-To-Live)</dfn></dt>
<dd>The duration in seconds that a capability remains in the ACTIVE state after the <code>lastSync</code> timestamp. During this period, verifiers grant access without requiring issuer contact.</dd>
<dt><dfn>GracePeriod</dfn></dt>
<dd>The duration in seconds after TTL expiration during which synchronization can still succeed. Capabilities in the STALE state are not granted access until sync completes, but they have not yet expired.</dd>
<dt><dfn>lastSync</dfn></dt>
<dd>The <code>newLastSync</code> timestamp from the latest valid <code>LeaseSyncResponse</code> for a capability. This value determines the starting point for TTL and GracePeriod calculations.</dd>
<dt><dfn>Effective Lease State</dfn></dt>
<dd>The current validity state (ACTIVE, STALE, EXPIRED, FUTURE, REVOKED, or INVALID) derived from the latest valid <code>LeaseSyncResponse</code> and the current time.</dd>
<dt>Controller</dt>
<dd>The entity that holds a capability and exercises it to access resources. Controllers are responsible for maintaining liveness through synchronization.</dd>
<dt>Issuer</dt>
<dd>The entity that creates and signs the capability credential and sync responses. Issuers manage lease state and enforce revocation.</dd>
<dt>Verifier</dt>
<dd>The entity that checks capability validity before granting resource access. Verifiers evaluate lease state, check revocation, and enforce temporal bounds.</dd>
<dt><dfn>Liveness Guarantee</dfn></dt>
<dd>The property that a capability remains valid only while the controller successfully synchronizes within bounded intervals. Formally, a capability is live at time t if there exists a valid sync response with <code>newLastSync > t - (T + G)</code>.</dd>
<dt><dfn>Lease State Cache</dfn></dt>
<dd>The verifier- or controller-side store of received <code>LeaseSyncResponse</code> objects, keyed by <code>capabilityId</code>. The cache holds the most recent lease state for each capability.</dd>
</dl>
</section>
<section id="state-definitions">
<h3>State Definitions</h3>
<p>The following parameters define the temporal state of a capability. All time values are expressed in milliseconds since the Unix epoch (1970-01-01T00:00:00Z), unless otherwise specified.</p>
<p>Let:</p>
<ul>
<li><code>L</code> = <code>lastSync</code> timestamp (milliseconds since epoch), from the latest valid <code>LeaseSyncResponse</code></li>
<li><code>T</code> = TTL in milliseconds (<code>leaseSpec.ttl × 1000</code>)</li>
<li><code>G</code> = GracePeriod in milliseconds (<code>leaseSpec.gracePeriod × 1000</code>)</li>
<li><code>N</code> = current time on the verifier's NTP-synchronized wall-clock (milliseconds since epoch)</li>
<li><code>ε</code> = clockTolerance in milliseconds (RECOMMENDED: 5000 ms)</li>
<li><code>Δ</code> = futureSkewBound in milliseconds (configurable per leaseSpec; RECOMMENDED default: 5000 ms)</li>
</ul>
<p>The four temporal states are <strong>mutually exclusive</strong> and evaluated in the following priority order:</p>
<ol>
<li><strong>FUTURE:</strong> <code>N < L − Δ</code> — The <code>lastSync</code> timestamp is too far in the future relative to the verifier's clock, indicating possible clock manipulation or an issuer error.</li>
<li><strong>REVOKED:</strong> The issuer has explicitly revoked the capability (checked separately via revocation cache).</li>
<li><strong>INVALID:</strong> The capability proof is invalid or the controller does not match.</li>
<li><strong>ACTIVE:</strong> <code>L − Δ ≤ N ≤ L + T + ε</code> — The capability is within its TTL window and can be used normally.</li>
<li><strong>STALE:</strong> <code>L + T + ε < N ≤ L + T + G + ε</code> — The TTL has elapsed but the capability is within the grace period; sync is required before access.</li>
<li><strong>EXPIRED:</strong> <code>N > L + T + G + ε</code> — The capability has exceeded both TTL and GracePeriod; it cannot be renewed and requires re-issuance.</li>
</ol>
<div class="note">
<p><strong>On Clock Tolerance ε:</strong> The clock tolerance <code>ε</code> is applied symmetrically to both the ACTIVE/STALE boundary and the STALE/EXPIRED boundary. A capability with <code>N = L + T + ε</code> is ACTIVE; at <code>N = L + T + ε + 1ms</code> it becomes STALE. This provides symmetric handling of clock skew without creating overlapping state regions or gaps.</p>
</div>
<div class="note">
<p><strong>On Future Skew Bound Δ:</strong> The <code>Δ</code> parameter prevents attacks where an issuer or replay attack sets <code>newLastSync</code> far in the future, effectively bypassing expiration. If the verifier's clock is properly synchronized, <code>Δ</code> should be set to a small value (e.g., 5 seconds). For high-latency environments (e.g., satellite communications), <code>Δ</code> may be increased to accommodate legitimate clock differences.</p>
</div>
</section>
<section id="notation">
<h3>Notation</h3>
<p>The following notation is used throughout this specification:</p>
<table class="parameter-table">
<thead>
<tr><th>Symbol</th><th>Meaning</th><th>Example</th></tr>
</thead>
<tbody>
<tr><td><code>||</code></td><td>Concatenation of byte strings</td><td><code>"abc" || "def" = "abcdef"</code></td></tr>
<tr><td><code>H(x)</code></td><td>SHA-256 hash of x, returned as hex-encoded string</td><td><code>H("hello") = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"</code></td></tr>
<tr><td><code>Sign(k, m)</code></td><td>Digital signature of message m with key k using Ed25519</td><td><code>Sign(privateKey, canonicalDoc)</code></td></tr>
<tr><td><code>[x]</code></td><td>Optional element; may be present or absent</td><td><code>"proof": { ... }</code> is optional in some contexts</td></tr>
<tr><td><code>canonicalize(x)</code></td><td>JSON Canonicalization Scheme (RFC 8785) applied to x</td><td><code>canonicalize({"a":1,"b":2})</code> produces deterministic output</td></tr>
<tr><td><code>base58btc(s)</code></td><td>Base58 Bitcoin encoding of byte string s</td><td>Used for proof values in Data Integrity proofs</td></tr>
</tbody>
</table>
</section>
</section>
<section id="liveness-property">
<h2>Liveness Property</h2>
<p>The liveness property is the fundamental contribution of Lease-CAP. In distributed systems, liveness guarantees that something good eventually happens — in this case, that an authorized controller can eventually gain access to a resource. Safety guarantees that something bad never happens — that unauthorized access never occurs. Lease-CAP provides both.</p>
<section id="definition-of-liveness">
<h3>Definition</h3>
<p>A capability is considered <dfn>live</dfn> if and only if the controller can successfully synchronize with the issuer within intervals bounded by TTL and GracePeriod. Formally:</p>
<pre>Live(capability, t) ⇔ ∃ valid LeaseSyncResponse R such that R.newLastSync > t − (T + G)</pre>
<p>This definition captures the intuition that a live capability is one where the controller has successfully maintained the authorization relationship within a bounded time window of length <code>T + G</code> before time <code>t</code>. The issuer's memory of successful syncs anchors the liveness property.</p>
<p>Note that liveness is distinct from safety: a capability could be safe (not usable by unauthorized parties) but not live (the authorized controller cannot use it due to sync failures). The STALE state is specifically designed to trade off liveness against safety during network partitions.</p>
</section>
<section id="liveness-guarantee-2">
<h3>Liveness Guarantee</h3>
<p><strong>Theorem (Liveness Guarantee):</strong> For any capability that has not been revoked, there exists a bounded time window <code>[lastSync, lastSync + T + G]</code> during which a controller who can successfully synchronize will be granted access. Outside this window, the capability is EXPIRED regardless of controller intent.</p>
<p>This guarantee has several important consequences:</p>
<ul>
<li><strong>Bounded Revocation:</strong> Even if the issuer does not actively revoke a capability, it will naturally expire within <code>lastSync + T + G</code> of the last successful sync. This bounds the "zombie capability" window.</li>
<li><strong>Failure Detection:</strong> If a controller fails to sync within <code>T + G</code>, the system can safely assume the controller is no longer authorized (or the network is partitioned).</li>
<li><strong>Partition Tolerance:</strong> During network partitions, capabilities remain usable for at most <code>T + G</code> without sync. The STALE state provides a <code>G</code>-length window where access is blocked until sync completes, rather than immediately expiring.</li>
</ul>
<p>The guarantee is bounded because the issuer cannot guarantee liveness indefinitely — if the controller cannot reach the issuer, eventually the capability will expire. This is an intentional design choice: unbounded offline operation is a security risk, as it allows capabilities to be used long after they should be invalid.</p>
</section>
<section id="relationship-to-safety">
<h3>Relationship to Safety</h3>
<p>Safety and liveness are complementary properties. In Lease-CAP:</p>
<table class="parameter-table">
<thead>
<tr><th>Property</th><th>Definition</th><th>Lease-CAP Mechanism</th><th>Bound</th></tr>
</thead>
<tbody>
<tr>
<td><strong>Safety</strong> (no unauthorized access)</td>
<td>Unauthorized parties cannot access protected resources</td>
<td>Revocation + cryptographic expiry + proof verification</td>
<td>Absolute: access requires valid proofs and non-expired state</td>
</tr>
<tr>
<td><strong>Liveness</strong> (authorized access eventually possible)</td>
<td>Authorized controllers can eventually gain access</td>
<td>Sync protocol + STALE grace period</td>
<td>Temporary: depends on network connectivity and issuer availability</td>
</tr>
</tbody>
</table>
<p>The STALE state represents the trade-off between these properties. During network partitions, liveness may be temporarily sacrificed (access is blocked until sync completes) to preserve safety (a capability that cannot sync will eventually expire rather than remaining usable indefinitely). This trade-off is controlled by the <code>gracePeriod</code> parameter, which can be tuned based on expected network reliability.</p>
<div class="note">
<p><strong>Formal Property:</strong> Lease-CAP provides eventual liveness under the assumption of eventual issuer reachability. Formally: if a capability is not revoked and the issuer becomes reachable within some finite time <code>δ</code>, then there exists a time <code>t ≤ lastSync + T + G + δ</code> such that the controller can sync and regain access. The worst-case liveness delay is <code>δ + (network round-trip time)</code>.</p>
</div>
</section>
</section>
<section id="security-model">
<h2>Security Model</h2>
<p>The security model defines the capabilities of attackers, the security goals of the system, and the trust assumptions required for correct operation. This model informs the design decisions throughout the specification.</p>
<section id="attacker-capabilities">
<h3>Attacker Capabilities</h3>
<p>The security model assumes an attacker who can:</p>
<ol>
<li><strong>Compromise controllers:</strong> steal private keys or capability storage, either through software vulnerabilities or physical access.</li>
<li><strong>Observe network traffic:</strong> eavesdrop on sync requests and responses, gaining knowledge of which capabilities are being exercised and when.</li>
<li><strong>Replay messages:</strong> capture and retransmit old sync responses, potentially attempting to extend capability lifetime.</li>
<li><strong>Manipulate clocks:</strong> adjust system time within bounds, either on the controller, verifier, or issuer, to attempt to extend or shrink temporal windows.</li>
<li><strong>Control network partitions:</strong> block access to issuers temporarily, either through network-level attacks or by compromising network infrastructure.</li>
<li><strong>Launch denial-of-service attacks:</strong> flood sync endpoints with requests, potentially overwhelming issuers.</li>
</ol>
<p>The attacker <em class="rfc2119">CANNOT</em>:</p>
<ol>
<li><strong>Compromise the issuer's private key</strong> — this would allow the attacker to issue arbitrary sync responses and break all security properties.</li>
<li><strong>Break cryptographic primitives</strong> (Ed25519 for signatures, SHA-256 for hashing) — these are assumed to be secure under standard cryptographic assumptions.</li>
<li><strong>Undetectably modify signed messages</strong> — any modification to a signed message will cause signature verification to fail.</li>
<li><strong>Control NTP-synchronized clocks on honest verifiers</strong> — verifiers are assumed to maintain accurate time through trusted NTP sources or hardware clocks.</li>
</ol>
<p>These attacker capabilities represent a realistic threat model for decentralized systems. The security mitigations are designed to remain effective even when multiple attacker capabilities are combined.</p>
</section>
<section id="security-goals">
<h3>Security Goals</h3>
<p>Lease-CAP is designed to achieve the following security goals, each of which is formally defined and verified in the security analysis:</p>
<ol>
<li><strong>Freshness:</strong> Capabilities cannot be used beyond their intended temporal window. More formally: for any capability usage at time <code>t</code>, there must exist a valid sync response with <code>newLastSync > t - (T + G)</code>. This bounds the "zombie capability" window.</li>
<li><strong>Revocability:</strong> Issuers can revoke capabilities with bounded propagation delay. When an issuer marks a capability as revoked, all verifiers will reject that capability within at most <code>T + G</code> time units. This bound is tight — after <code>T + G</code>, the capability would have expired anyway.</li>
<li><strong>Delegation safety:</strong> Delegated capabilities cannot exceed parent authority or lifetime. For any valid delegation chain, the lease parameters must satisfy <code>T_child + G_child ≤ T_parent + G_parent</code>. This ensures the child capability cannot outlive its parent.</li>
<li><strong>Replay resistance:</strong> Captured sync responses cannot extend capability lifetime beyond intended bounds. The combination of strictly increasing timestamps, nonce binding, and <code>previousLastSync</code> chaining prevents replay attacks.</li>
<li><strong>Offline safety:</strong> Offline mode provides bounded grace without compromising security. When offline mode is enabled, capabilities can be used for at most <code>maxDurationSeconds</code> without issuer contact, and the <code>graceMultiplier</code> is bounded by 2.0.</li>
<li><strong>Binding integrity:</strong> Lease state cannot be substituted across different capability credentials. The <code>capabilityHash</code> field in every sync response cryptographically binds the lease state to a specific capability credential.</li>
</ol>
</section>
<section id="trust-assumptions">
<h3>Trust Assumptions</h3>
<p>Lease-CAP operates under the following trust assumptions. These assumptions must be satisfied for the security guarantees to hold:</p>
<ol>
<li><strong>Issuers are trusted to enforce lease attenuation, revocation, and parent-state checks.</strong> A malicious issuer could violate these properties, but such behavior would be detectable through audit logs and would violate the issuer's reputation. In decentralized systems, trust in issuers is typically established through DID-based identities and verifiable credentials.</li>
<li><strong>NTP-synchronized clocks are available on verifiers</strong> (hardware-backed where required by policy). Clock manipulation is a primary attack vector; verifiers must maintain accurate time. High-security deployments <em class="rfc2119">SHOULD</em> use hardware security modules (HSMs) or trusted platform modules (TPMs) for timekeeping.</li>
<li><strong>Cryptographic keys are stored securely</strong> (HSM or equivalent for high-security deployments). Key compromise is catastrophic; controllers and issuers must protect private keys accordingly.</li>
<li><strong>TLS provides channel security</strong> (defense in depth alongside cryptographic proofs). While cryptographic proofs provide message integrity and authenticity, TLS protects against traffic analysis and provides forward secrecy.</li>
<li><strong>Verifiers correctly implement the state evaluation algorithm</strong> and enforce all bounds. A faulty verifier could grant inappropriate access or deny legitimate access.</li>
</ol>
<div class="warning">
<p><strong>Trust Minimization:</strong> Lease-CAP minimizes trust requirements compared to centralized systems. Verifiers do not need to trust issuers beyond verifying cryptographic proofs. Controllers do not need to trust verifiers beyond accepting signed responses. The only entity that requires significant trust is the issuer, which is identified by a DID and can be held accountable through verifiable evidence.</p>
</div>
</section>
<section id="threat-model-summary">
<h3>Threat Model Summary</h3>
<p>The following table summarizes key threats, their mitigations, and the sections where mitigations are specified:</p>
<table class="parameter-table">
<thead>
<tr><th>Threat</th><th>Mitigation</th><th>Section</th></tr>
</thead>
<tbody>
<tr><td>Zombie capabilities</td><td>Natural expiration <code>(T + G)</code> bounds worst-case lifetime</td><td><a href="#state-machine"></a></td></tr>
<tr><td>Clock manipulation</td><td><code>ε</code> + <code>Δ</code> bounds, NTP synchronization, monotonic clocks</td><td><a href="#clock-skew"></a></td></tr>
<tr><td>Replay attacks</td><td>Strictly increasing timestamps + nonce binding + <code>previousLastSync</code> chain + issuer historical state</td><td><a href="#replay-attacks"></a></td></tr>
<tr><td>Capability substitution</td><td><code>capabilityHash</code> binding in every sync response</td><td><a href="#cryptographic-binding"></a></td></tr>
<tr><td>Revocation race</td><td>Issuer refuses sync for revoked caps; verifier caches revocation proofs with extended expiry</td><td><a href="#revocation-race"></a></td></tr>
<tr><td>Denial of service</td><td>Rate limiting + randomized truncated exponential backoff</td><td><a href="#denial-of-service"></a></td></tr>
<tr><td>Key compromise</td><td>Revocation endpoint + cache; key rotation via re-issuance</td><td><a href="#key-compromise"></a></td></tr>
<tr><td>Thundering herd</td><td>Jitter + truncated exponential backoff + load-aware sync window assignment</td><td><a href="#thundering-herd"></a></td></tr>
<tr><td>Offline abuse</td><td>Bounded grace + audit + multiplier limit + explicit issuer opt-in</td><td><a href="#offline-mode-security"></a></td></tr>
<tr><td>Lease attenuation bypass</td><td><code>T_child + G_child ≤ T_parent + G_parent</code> enforced by issuer</td><td><a href="#lease-attenuation"></a></td></tr>
<tr><td>Parent expiry bypass</td><td>Issuer checks parent ACTIVE state before renewing child</td><td><a href="#lease-attenuation"></a></td></tr>
</tbody>
</table>
</section>
</section>
<section id="core-concepts">
<h2>Core Concepts</h2>
<p>The following concepts form the foundation of Lease-CAP. Understanding these concepts is essential for implementing conforming systems.</p>
<section id="state-separation">
<h3>State Separation: Static Credential and Dynamic Lease State</h3>
<p>A Liveness-Bound Capability consists of two <strong>strictly separated</strong> components. This separation is a fundamental architectural decision that enables efficient state management, prevents forgery, and supports multi-device scenarios.</p>
<p><strong>Static Capability Credential (immutable):</strong> A W3C Verifiable Credential containing fixed properties that never change throughout the capability's lifetime:</p>
<ul>
<li>Issuer DID and verification method</li>
<li>Controller DID (the entity authorized to exercise the capability)</li>
<li>Invocation target (the resource or service being accessed)</li>
<li>Allowed actions (e.g., read, write, delete)</li>
<li>Lease specification (TTL, GracePeriod, sync endpoint, offline mode configuration)</li>
<li>Caveats (additional constraints like rate limits or geographic restrictions)</li>
</ul>
<p>Once issued, this document <em class="rfc2119">MUST NOT</em> change. Any modification would invalidate the issuer's signature and break the cryptographic binding to lease state.</p>
<p><strong>Dynamic Lease State (mutable, issuer-signed):</strong> A <code>LeaseSyncResponse</code> object that captures the current synchronization state of the capability:</p>
<ul>
<li><code>newLastSync</code>: The timestamp of the most recent successful sync (or issuance date for initial state)</li>
<li><code>previousLastSync</code>: The previous sync timestamp, enabling chain validation</li>
<li><code>nextSyncRecommended</code>: Optional hint from the issuer about optimal next sync time</li>
<li><code>capabilityHash</code>: Cryptographic binding to the static credential</li>
<li><code>status</code>: "active" or "revoked"</li>
</ul>
<p>This object is NOT embedded in the credential. It is stored separately by controllers and verifiers, updated each time a successful sync occurs.</p>
<div class="warning">
<p><strong>Critical Implementation Requirement:</strong> The <code>lastSync</code> value <em class="rfc2119">MUST NOT</em> appear in the Verifiable Credential body. Any implementation that embeds <code>lastSync</code> inside <code>credentialSubject</code> is non-conforming. Embedding timestamps in the credential would require re-issuing the credential on every sync, defeating the purpose of state separation, and would allow controllers to forge lease state by presenting a self-constructed credential. Verifiers <em class="rfc2119">MUST</em> derive the effective lease state from the latest valid <code>LeaseSyncResponse</code> stored in their lease state cache.</p>
</div>
</section>
<section id="effective-lease-state-2">
<h3>Effective Lease State</h3>
<p>The <dfn>Effective Lease State</dfn> of a capability is determined by the latest valid <code>LeaseSyncResponse</code> in the lease state cache:</p>
<pre>EffectiveLeaseState(capabilityId) = entry in LeaseStateCache with largest newLastSync
that passes proof verification and capabilityHash check</pre>
<p>If no valid <code>LeaseSyncResponse</code> exists in the cache, the initial lease state is:</p>
<ul>
<li><code>lastSync</code> = <code>issuanceDate</code> of the capability credential</li>
<li><code>previousLastSync</code> = null</li>
<li><code>status</code> = "active"</li>
</ul>
<p>This means a freshly issued capability is immediately usable without a prior sync, for up to TTL seconds from issuance. This design choice enables smooth onboarding and reduces latency for first use.</p>
<p>Verifiers and controllers maintain their own caches, which may diverge temporarily. This is acceptable because:</p>
<ul>
<li>Verifiers can only grant access based on their cache state; if a controller has a newer lease state not yet seen by the verifier, the controller will receive a 403 response and can present the newer sync response.</li>
<li>Controllers can proactively sync to update their cache; verifiers learn of new lease states when controllers present them.</li>
<li>The <code>capabilityHash</code> ensures that even if caches diverge, the binding to the correct credential is maintained.</li>
</ul>
</section>
<section id="cryptographic-binding-2">
<h3>Cryptographic Binding Between Credential and Lease State</h3>
<p>To prevent substitution attacks — where an attacker presents a valid lease state for a different capability with the same ID — each <code>LeaseSyncResponse</code> <em class="rfc2119">MUST</em> include a hash of the original capability credential:</p>
<pre class="test-vector">
{
"capabilityId": "urn:cap:9f8e7d6c...",
"capabilityHash": "H(canonicalize(capability))",
"newLastSync": "...",
"proof": { ... }
}</pre>
<p>Verifiers <em class="rfc2119">MUST</em> check:</p>
<pre>H(canonicalize(capability)) == response.capabilityHash</pre>
<p>If the check fails, the sync response <em class="rfc2119">MUST</em> be rejected and the effective lease state <em class="rfc2119">MUST NOT</em> be updated.</p>
<p><strong>Attack Scenario Prevented:</strong> Without this binding, an attacker could:</p>
<ol>
<li>Obtain a valid <code>LeaseSyncResponse</code> for capability A (which they legitimately control).</li>
<li>Create a new capability B with the same <code>capabilityId</code> but a different controller DID.</li>
<li>Present the sync response for A as if it applied to B, potentially gaining access with B using A's lease state.</li>
</ol>
<p>The <code>capabilityHash</code> prevents this by ensuring each sync response is cryptographically bound to a specific credential. Since the hash includes the controller DID and all other fields, any change to the credential results in a different hash, causing verification to fail.</p>
</section>
<section id="lease-attenuation-2">
<h3>Lease Attenuation and Delegation</h3>
<p>Capability delegation is a powerful feature of capability-based systems. Lease-CAP supports delegation with the important constraint of <strong>lease attenuation</strong>: a delegated capability cannot have a longer effective lifetime than its parent.</p>
<p>When delegating capabilities, the following <em class="rfc2119">MUST</em> hold:</p>
<pre>T_child + G_child ≤ T_parent + G_parent</pre>
<p>A child capability <em class="rfc2119">MUST NOT</em> outlive the absolute expiration boundary of its parent. This preserves the principle of attenuation of authority: a delegate cannot receive more authority than the delegator possesses.</p>
<p><strong>Child Sync Independence:</strong> A child capability's <code>lastSync</code> can be updated independently of its parent. The child maintains its own lease state cache and sync schedule. However, the issuer <em class="rfc2119">MUST</em> verify that the parent capability is in ACTIVE state at the time of the child's renewal request. If the parent is STALE or EXPIRED, the issuer <em class="rfc2119">MUST NOT</em> issue a successful sync response for the child.</p>
<p><strong>Delegation Chain Depth:</strong> Implementations <em class="rfc2119">MUST</em> enforce a configurable maximum delegation depth. The RECOMMENDED maximum depth is 5 levels. Chains exceeding this depth <em class="rfc2119">MUST</em> be rejected. This prevents unbounded recursion and potential denial-of-service attacks through deep delegation chains.</p>
<p><strong>Example:</strong></p>
<ul>
<li>Parent capability: TTL = 86400 seconds (24 hours), GracePeriod = 300 seconds (5 minutes). Total lifetime = 24h 5m.</li>
<li>Child capability: TTL = 43200 seconds (12 hours), GracePeriod = 300 seconds (5 minutes). Total lifetime = 12h 5m (valid, ≤ parent).</li>
<li>Invalid child: TTL = 86400 seconds, GracePeriod = 600 seconds (10 minutes). Total lifetime = 24h 10m (invalid, > parent).</li>
</ul>
</section>
<section id="synchronization-bound-authority-2">
<h3>Synchronization-Bound Authority</h3>
<p>Lease-CAP's fundamental contribution is that <strong>authority decays unless actively maintained</strong>. This represents a paradigm shift from static to dynamic authorization. To understand why this matters, consider the differences:</p>
<ul>
<li><strong>Static capabilities (ZCAP-LD, UCAN without expiry):</strong> Valid until explicitly revoked. In decentralized systems where revocation is difficult, this creates unbounded risk.</li>
<li><strong>Time-bound tokens (OAuth):</strong> Valid until absolute expiry, but no renewal possible. This requires frequent re-issuance, which is impractical for long-lived delegations.</li>
<li><strong>Refresh tokens (OAuth):</strong> Renewal possible but centralized and not delegatable. The refresh token is a backchannel secret that cannot be further delegated.</li>
<li><strong>Lease-CAP:</strong> Authority is maintained through periodic synchronization. The controller <em class="rfc2119">MUST</em> regularly prove continued authorization to the issuer. The STALE state provides a bounded window for this proof without service interruption.</li>
</ul>
<p>This synchronization-bound authority has several benefits:</p>
<ol>
<li><strong>Automatic expiration:</strong> Even without explicit revocation, capabilities expire naturally if not maintained.</li>
<li><strong>Freshness verification:</strong> Verifiers can be confident that recently-synced capabilities represent current authorization.</li>
<li><strong>Compromise recovery:</strong> If a controller is compromised, the attacker's access is limited to at most <code>T + G</code> from the last sync.</li>
<li><strong>Audit visibility:</strong> Sync events provide a verifiable audit trail of continued authorization.</li>
</ol>
</section>
<section id="future-state-protection-2">
<h3>Future State Protection</h3>
<p>To prevent attacks where an issuer or replay sets <code>newLastSync</code> far in the future — effectively bypassing expiration — verifiers <em class="rfc2119">MUST</em> enforce a maximum future skew bound <code>Δ</code>. If <code>N < L − Δ</code>, the capability <em class="rfc2119">MUST</em> be treated as FUTURE and rejected.</p>
<p><strong>Attack Scenario:</strong> Without FUTURE protection, an attacker could:</p>
<ol>
<li>Compromise an issuer or intercept a sync response.</li>
<li>Modify the <code>newLastSync</code> timestamp to a value far in the future (e.g., year 2030).</li>
<li>Present this modified response to verifiers, who would see a valid signature and treat the capability as ACTIVE for years.</li>
</ol>
<p><strong>Mitigation:</strong> The FUTURE state rejects any capability where the verifier's current time is more than <code>Δ</code> behind <code>lastSync</code>. Since <code>Δ</code> is typically small (5 seconds for most applications), any timestamp significantly in the future is rejected.</p>
<p>The value of <code>Δ</code> <em class="rfc2119">SHOULD</em> be configurable per <code>leaseSpec</code> to accommodate different environments:</p>
<ul>
<li><strong>5 seconds:</strong> High-speed networks, local deployments, financial transactions</li>
<li><strong>30 seconds:</strong> Satellite links, cross-continental communication</li>
<li><strong>60 seconds:</strong> Highly asynchronous environments, batch processing</li>
</ul>
<p>When not specified, <code>Δ</code> defaults to 5000 ms (5 seconds).</p>
</section>
<section id="temporal-coupling-2">
<h3>Temporal Coupling Across Delegation Chains</h3>
<p>During verification of a delegation chain, each capability in the chain <em class="rfc2119">MUST</em> be evaluated at the same reference time <code>N</code>. If any capability in the chain resolves to STALE or EXPIRED, the entire chain <em class="rfc2119">MUST</em> be treated as invalid for the purpose of granting access, unless the controller performs sync and retries.</p>
<p>This temporal coupling ensures that a controller cannot bypass the liveness requirement by using a stale parent capability to authorize a child. The entire delegation chain must be fresh at the time of access.</p>
<p><strong>Example:</strong></p>
<ul>
<li>Root capability: lastSync = 2024-01-15T10:00:00Z, TTL = 24h, GracePeriod = 5m</li>
<li>Child capability: lastSync = 2024-01-15T12:00:00Z, TTL = 12h, GracePeriod = 5m</li>
<li>Current time: 2024-01-16T11:00:00Z</li>
</ul>
<p>The root capability's TTL expired at 2024-01-16T10:00:00Z. Even though the child's TTL (from its 12:00 sync) expires at 2024-01-16T00:00:00Z, both are evaluated at the same time. The root is STALE/EXPIRED (depending on whether within grace), so the entire chain is invalid.</p>
</section>
</section>
<section id="data-model">
<h2>Data Model</h2>
<p>The Lease-CAP data model defines the structure of capability credentials, sync messages, and cache entries. All messages are JSON objects that can be signed using W3C Data Integrity proofs.</p>
<section id="capability-credential-detailed">
<h3>Capability Credential (Static, Immutable)</h3>
<p>The Capability Credential is a W3C Verifiable Credential with additional context for lease specifications. The <code>leaseSpec</code> field carries all lease parameters needed by both controllers and verifiers. <strong>Note that <code>lastSync</code> does NOT appear here</strong> — it is part of the dynamic lease state.</p>
<pre class="test-vector">
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/lease-cap/v1"
],
"id": "urn:cap:9f8e7d6c-4b3a-2c1d-8e7f-6a5b4c3d2e1f",
"type": ["VerifiableCredential", "LeaseCapability"],
"issuer": "did:key:z6MkhaXgBcjvVgJKKKZo9vQqYhF8JxqB3d5hL5xK5X5x5X",
"issuanceDate": "2024-01-15T10:00:00Z",
"credentialSubject": {
"id": "did:key:z6MkhaXgBcjvVgJKKKZo9vQqYhF8JxqB3d5hL5xK5X5x5Y",