provared 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1062 -0
- package/LICENSE +202 -0
- package/LICENSE-CC-BY-4.0.txt +396 -0
- package/README.md +689 -0
- package/bin/provared-check.mjs +565 -0
- package/bin/provared-headers.mjs +110 -0
- package/docs/threat-model.md +997 -0
- package/net/headers.js +403 -0
- package/package.json +57 -0
- package/page/check-page.js +162 -0
- package/page/index.html +47 -0
- package/page/render.js +530 -0
- package/page/style.css +150 -0
- package/samples/office-supplies.expected.json +82 -0
- package/samples/office-supplies.jsonl +10 -0
- package/samples/office-supplies.show.json +59 -0
- package/spec/provared-format.md +1672 -0
- package/src/actions.js +90 -0
- package/src/approval.js +73 -0
- package/src/blockstamp.js +198 -0
- package/src/book.js +2232 -0
- package/src/check.d.ts +21 -0
- package/src/check.js +15 -0
- package/src/compare.js +276 -0
- package/src/cover.js +198 -0
- package/src/der.js +192 -0
- package/src/encoding.js +286 -0
- package/src/fields.js +94 -0
- package/src/guard.js +171 -0
- package/src/headers.js +380 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +37 -0
- package/src/jws.js +235 -0
- package/src/keys.js +149 -0
- package/src/pass.js +67 -0
- package/src/passkey-browser.d.ts +20 -0
- package/src/passkey-browser.js +171 -0
- package/src/recorder.js +1115 -0
- package/src/seal.js +133 -0
- package/src/service.js +124 -0
- package/src/signatures.js +147 -0
- package/src/slip.js +401 -0
- package/src/standing.js +181 -0
- package/src/stub.js +140 -0
- package/src/timestamp.js +351 -0
- package/src/tools.js +192 -0
- package/src/tree.js +143 -0
- package/src/types.d.ts +628 -0
- package/src/webauthn.js +119 -0
|
@@ -0,0 +1,1672 @@
|
|
|
1
|
+
# The Provared format — draft version 0
|
|
2
|
+
|
|
3
|
+
A way to write down what an AI agent was allowed to do, and what it then
|
|
4
|
+
did, so that someone else can check it later with free tools.
|
|
5
|
+
|
|
6
|
+
*Evidence, not a verdict.* A record shows what was signed and by which
|
|
7
|
+
keys. People decide what it means.
|
|
8
|
+
|
|
9
|
+
## 1. Status
|
|
10
|
+
|
|
11
|
+
This is **draft version 0**. Nothing in it is frozen. Every label below
|
|
12
|
+
ends in `v0` so that a frozen version can never be confused with this
|
|
13
|
+
draft. Do not rely on a draft record staying checkable.
|
|
14
|
+
|
|
15
|
+
Built in this draft: the Slip, with its limits, conditions and stated
|
|
16
|
+
rules; the Stub; the countersignature; the person's approval of one
|
|
17
|
+
action; a service's refusal and its terms for agents; the chain; the
|
|
18
|
+
book; the tree of fingerprints; the Seal, with outside time-stamps; the
|
|
19
|
+
one-page proof; cancelling a slip, and the agent's acknowledgement of a
|
|
20
|
+
cancellation; the block time-stamp; vouching for a name; covered fields
|
|
21
|
+
in a slip; and passing a slip on to a helper agent.
|
|
22
|
+
|
|
23
|
+
What is not in this draft is listed in section 12.
|
|
24
|
+
|
|
25
|
+
The words MUST, MUST NOT and MAY are used as RFC 2119 defines them.
|
|
26
|
+
|
|
27
|
+
## 2. Words used
|
|
28
|
+
|
|
29
|
+
| Word | Meaning |
|
|
30
|
+
|---|---|
|
|
31
|
+
| Slip | A permission that a person signs with a passkey: which agent, which actions, what limits, with whom, from when until when, and why |
|
|
32
|
+
| Stub | A signed receipt for one action, pointing back to its slip |
|
|
33
|
+
| Countersignature | The other side's signed statement that the action happened with it |
|
|
34
|
+
| Approval | The person's own yes to one action, signed with the same passkey as the slip |
|
|
35
|
+
| Refusal | A service's signed statement that an agent asked for something and was refused |
|
|
36
|
+
| Terms | A service's signed statement of which actions it accepts from agents |
|
|
37
|
+
| Seal | The signed statement, by whoever keeps a book, of its top fingerprint and its number of entries at one moment |
|
|
38
|
+
| Recorder | Whoever keeps a book and seals it |
|
|
39
|
+
| Time-stamp | A signed statement by an outside service that a fingerprint existed by a time (RFC 3161); a block time-stamp is the like, from a block of a public blockchain (section 21.4) |
|
|
40
|
+
| Cancellation | The person's signed statement that a slip is ended early |
|
|
41
|
+
| Vouching record | An organisation's signed statement that a key belongs to a name |
|
|
42
|
+
| Withdrawal | The organisation's signed statement that a vouching record is ended |
|
|
43
|
+
| Pass | An agent's signed statement that it hands part of its permission to a helper agent |
|
|
44
|
+
| Chain | The stubs under one slip, each naming the one before |
|
|
45
|
+
| Book | A list of entries, one to a line: slips, stubs and the other records of this format |
|
|
46
|
+
| Top fingerprint | One fingerprint that stands for the whole book (the root of a Merkle tree) |
|
|
47
|
+
| Show | One or more entries of a book, each with proof that it is in the book |
|
|
48
|
+
| Issuer | The person who signs a slip |
|
|
49
|
+
| Agent | The software that acts, and signs stubs |
|
|
50
|
+
| Service | Whoever the agent deals with; it may countersign |
|
|
51
|
+
| Checker | Anyone who verifies a record, or the software they use |
|
|
52
|
+
| Fingerprint | The SHA-256 hash of some bytes, written in base64url (43 characters) |
|
|
53
|
+
| Passkey | A private key held in a phone, laptop or security key and unlocked by fingerprint, face or PIN (the W3C Web Authentication standard) |
|
|
54
|
+
| Hybrid | Two signatures on one record, one of today's kind and one quantum-safe; the record counts only if both check |
|
|
55
|
+
|
|
56
|
+
## 3. Rules common to every record
|
|
57
|
+
|
|
58
|
+
### 3.1 The signed envelope
|
|
59
|
+
|
|
60
|
+
Every record is a JSON Web Signature (RFC 7515) in the **general JSON
|
|
61
|
+
serialisation** (RFC 7515, section 7.2.1):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"payload": "<base64url of the content>",
|
|
66
|
+
"signatures": [
|
|
67
|
+
{ "protected": "<base64url of the protected header>", "signature": "<base64url>" }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- The top level MUST hold exactly `payload` and `signatures`.
|
|
73
|
+
- Each entry of `signatures` MUST hold exactly `protected` and
|
|
74
|
+
`signature`, and, for a record signed with a passkey (a slip, an
|
|
75
|
+
approval or a cancellation), `header` (section 4.3).
|
|
76
|
+
- The bytes each signature covers are the JSON Web Signature signing
|
|
77
|
+
input (RFC 7515, section 5.1): the ASCII text of `protected`, a full
|
|
78
|
+
stop, and the ASCII text of `payload`.
|
|
79
|
+
- A record MUST NOT be larger than 65,536 characters, measured as the
|
|
80
|
+
lengths of its `payload` and of every text value in its signature
|
|
81
|
+
entries, added up. A writer MUST NOT make a larger record.
|
|
82
|
+
|
|
83
|
+
### 3.2 Labels: the protected header
|
|
84
|
+
|
|
85
|
+
The protected header says what kind of record this is and which signing
|
|
86
|
+
method was used. Because it is part of the signed bytes, a signature made
|
|
87
|
+
for one kind of record can never pass as another kind.
|
|
88
|
+
|
|
89
|
+
In this draft the protected header, once decoded, MUST be **exactly** one
|
|
90
|
+
of these twenty-two texts, byte for byte. A checker compares the bytes and does
|
|
91
|
+
not interpret anything else.
|
|
92
|
+
|
|
93
|
+
| Record | Method | Protected header |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| Slip | Passkey | `{"typ":"vnd.provared.slip.v0+json","alg":"prova.red/webauthn/v0"}` |
|
|
96
|
+
| Stub | Ed25519 | `{"typ":"vnd.provared.stub.v0+json","alg":"Ed25519"}` |
|
|
97
|
+
| Stub | ML-DSA-87 | `{"typ":"vnd.provared.stub.v0+json","alg":"ML-DSA-87"}` |
|
|
98
|
+
| Countersignature | Ed25519 | `{"typ":"vnd.provared.countersignature.v0+json","alg":"Ed25519"}` |
|
|
99
|
+
| Countersignature | ML-DSA-87 | `{"typ":"vnd.provared.countersignature.v0+json","alg":"ML-DSA-87"}` |
|
|
100
|
+
| Approval | Passkey | `{"typ":"vnd.provared.approval.v0+json","alg":"prova.red/webauthn/v0"}` |
|
|
101
|
+
| Refusal | Ed25519 | `{"typ":"vnd.provared.refusal.v0+json","alg":"Ed25519"}` |
|
|
102
|
+
| Refusal | ML-DSA-87 | `{"typ":"vnd.provared.refusal.v0+json","alg":"ML-DSA-87"}` |
|
|
103
|
+
| Terms | Ed25519 | `{"typ":"vnd.provared.terms.v0+json","alg":"Ed25519"}` |
|
|
104
|
+
| Terms | ML-DSA-87 | `{"typ":"vnd.provared.terms.v0+json","alg":"ML-DSA-87"}` |
|
|
105
|
+
| Seal | Ed25519 | `{"typ":"vnd.provared.seal.v0+json","alg":"Ed25519"}` |
|
|
106
|
+
| Seal | ML-DSA-87 | `{"typ":"vnd.provared.seal.v0+json","alg":"ML-DSA-87"}` |
|
|
107
|
+
| Seal | SLH-DSA-SHA2-256s | `{"typ":"vnd.provared.seal.v0+json","alg":"SLH-DSA-SHA2-256s"}` |
|
|
108
|
+
| Cancellation | Passkey | `{"typ":"vnd.provared.cancellation.v0+json","alg":"prova.red/webauthn/v0"}` |
|
|
109
|
+
| Acknowledgement | Ed25519 | `{"typ":"vnd.provared.acknowledgement.v0+json","alg":"Ed25519"}` |
|
|
110
|
+
| Acknowledgement | ML-DSA-87 | `{"typ":"vnd.provared.acknowledgement.v0+json","alg":"ML-DSA-87"}` |
|
|
111
|
+
| Vouching record | Ed25519 | `{"typ":"vnd.provared.vouching.v0+json","alg":"Ed25519"}` |
|
|
112
|
+
| Vouching record | ML-DSA-87 | `{"typ":"vnd.provared.vouching.v0+json","alg":"ML-DSA-87"}` |
|
|
113
|
+
| Withdrawal | Ed25519 | `{"typ":"vnd.provared.withdrawal.v0+json","alg":"Ed25519"}` |
|
|
114
|
+
| Withdrawal | ML-DSA-87 | `{"typ":"vnd.provared.withdrawal.v0+json","alg":"ML-DSA-87"}` |
|
|
115
|
+
| Pass | Ed25519 | `{"typ":"vnd.provared.pass.v0+json","alg":"Ed25519"}` |
|
|
116
|
+
| Pass | ML-DSA-87 | `{"typ":"vnd.provared.pass.v0+json","alg":"ML-DSA-87"}` |
|
|
117
|
+
|
|
118
|
+
`typ` is the media type of the record (RFC 7515, section 4.1.9), used as
|
|
119
|
+
explicit typing (RFC 8725, section 3.11). `alg` names the signing method
|
|
120
|
+
(RFC 7515, section 4.1.1). `Ed25519` is the name RFC 9864 registers;
|
|
121
|
+
`ML-DSA-87` is the name RFC 9964 registers. `SLH-DSA-SHA2-256s` is the
|
|
122
|
+
name FIPS 205 gives that method; no registered name for it in this
|
|
123
|
+
envelope was found when this draft was written. `prova.red/webauthn/v0` is
|
|
124
|
+
not a registered name: it is a collision-resistant name under a domain
|
|
125
|
+
the format's author controls, which RFC 7515 section 4.1.1 allows.
|
|
126
|
+
|
|
127
|
+
### 3.3 Base64url
|
|
128
|
+
|
|
129
|
+
Base64url is as RFC 4648, section 5, with no padding (RFC 7515, section
|
|
130
|
+
2). A checker MUST refuse a value that holds any other character, has
|
|
131
|
+
padding, has an impossible length, or has stray bits set in its last
|
|
132
|
+
character.
|
|
133
|
+
|
|
134
|
+
### 3.4 The content, and its canonical form
|
|
135
|
+
|
|
136
|
+
The content of a record (the decoded `payload`) is a JSON object in
|
|
137
|
+
UTF-8. It MUST be written in the JSON Canonicalization Scheme (RFC 8785):
|
|
138
|
+
no spaces or line breaks, the members of every object sorted by name, and
|
|
139
|
+
strings and numbers written in the one form that standard gives.
|
|
140
|
+
|
|
141
|
+
This draft narrows what the content may hold: objects, lists, strings,
|
|
142
|
+
whole numbers from 0 to 9,007,199,254,740,991, and nothing else. There
|
|
143
|
+
are no fractions, no negative numbers, no `null`, no `true` or `false`.
|
|
144
|
+
Strings MUST be well-formed Unicode. Nesting MUST NOT go deeper than 8
|
|
145
|
+
levels.
|
|
146
|
+
|
|
147
|
+
A checker MUST read the content, write it again in the canonical form,
|
|
148
|
+
and refuse the record if the two differ by a single byte. This refuses a
|
|
149
|
+
repeated member name, stray spaces and unusual number forms, so that two
|
|
150
|
+
checkers cannot read one record in two ways.
|
|
151
|
+
|
|
152
|
+
The signed bytes are always kept and checked exactly as they were signed.
|
|
153
|
+
The canonical form is a test the bytes must pass; it is never used to
|
|
154
|
+
rewrite them.
|
|
155
|
+
|
|
156
|
+
Every content object has a `type` member: `provared.slip.v0`,
|
|
157
|
+
`provared.stub.v0`, `provared.countersignature.v0`,
|
|
158
|
+
`provared.approval.v0`, `provared.refusal.v0`, `provared.terms.v0`,
|
|
159
|
+
`provared.seal.v0`, `provared.cancellation.v0`,
|
|
160
|
+
`provared.acknowledgement.v0`, `provared.vouching.v0`,
|
|
161
|
+
`provared.withdrawal.v0` or `provared.pass.v0`. It MUST match the `typ`
|
|
162
|
+
label of every signature on the record.
|
|
163
|
+
|
|
164
|
+
An object MUST hold exactly the members this document lists for it. A
|
|
165
|
+
checker MUST refuse an unknown member.
|
|
166
|
+
|
|
167
|
+
Wherever this document limits the length of a text, the length is counted
|
|
168
|
+
in characters (Unicode code points).
|
|
169
|
+
|
|
170
|
+
### 3.5 Fingerprints
|
|
171
|
+
|
|
172
|
+
The **fingerprint of a record** is the SHA-256 hash (FIPS 180-4) of its
|
|
173
|
+
content bytes (the decoded `payload`), written in base64url. It is how a
|
|
174
|
+
stub names its slip, how a stub names the stub before it, and how a
|
|
175
|
+
countersignature names its stub.
|
|
176
|
+
|
|
177
|
+
### 3.6 Times
|
|
178
|
+
|
|
179
|
+
A time is written as `YYYY-MM-DDTHH:MM:SSZ` (RFC 3339, in UTC, to the
|
|
180
|
+
second, with the letter Z). No other form is accepted.
|
|
181
|
+
|
|
182
|
+
### 3.7 Unique numbers
|
|
183
|
+
|
|
184
|
+
An `id` is 16 random bytes written in base64url (22 characters).
|
|
185
|
+
|
|
186
|
+
### 3.8 Keys
|
|
187
|
+
|
|
188
|
+
Public keys are written as JSON Web Keys (RFC 7517). Each MUST be exactly
|
|
189
|
+
one of these shapes, with no other member:
|
|
190
|
+
|
|
191
|
+
| Used by | Shape |
|
|
192
|
+
|---|---|
|
|
193
|
+
| Agent, service | `{"alg":"Ed25519","crv":"Ed25519","kty":"OKP","x":"…"}` (RFC 8037; `x` is 32 bytes) |
|
|
194
|
+
| Agent, service | `{"alg":"ML-DSA-87","kty":"AKP","pub":"…"}` (RFC 9964; `pub` is 2,592 bytes) |
|
|
195
|
+
| Recorder, third key | `{"alg":"SLH-DSA-SHA2-256s","kty":"AKP","pub":"…"}` (FIPS 205; `pub` is 64 bytes) |
|
|
196
|
+
| Issuer's passkey | `{"alg":"ES256","crv":"P-256","kty":"EC","x":"…","y":"…"}` (RFC 7518, section 6.2; 32 bytes each) |
|
|
197
|
+
| Issuer's passkey | `{"alg":"RS256","e":"AQAB","kty":"RSA","n":"…"}` (RFC 7518, section 6.3; `n` is 2,048 to 8,192 bits) |
|
|
198
|
+
| Issuer's passkey | `{"alg":"Ed25519","crv":"Ed25519","kty":"OKP","x":"…"}` |
|
|
199
|
+
|
|
200
|
+
A key is named for people by its **thumbprint**: the JSON Web Key
|
|
201
|
+
Thumbprint with SHA-256 (RFC 7638; for ML-DSA keys, RFC 9964 section 6).
|
|
202
|
+
|
|
203
|
+
### 3.9 A key set: the hybrid
|
|
204
|
+
|
|
205
|
+
An agent or a service is known by a **key set**: a list of exactly two
|
|
206
|
+
keys, the Ed25519 key first and the ML-DSA-87 key second.
|
|
207
|
+
|
|
208
|
+
A stub, a countersignature, a refusal, a set of terms, a vouching record,
|
|
209
|
+
a withdrawal or a pass MUST carry exactly two signatures, in the same order: Ed25519 (RFC 8032), then ML-DSA-87 (FIPS 204, the plain
|
|
210
|
+
method with an empty context, as RFC 9964 section 5 requires). Both cover
|
|
211
|
+
the same content. The record counts as signed **only if both signatures
|
|
212
|
+
check**. The two signatures stand side by side as two entries of the
|
|
213
|
+
`signatures` list, as RFC 7515 already allows. Nothing is combined by a
|
|
214
|
+
method of this format's own.
|
|
215
|
+
|
|
216
|
+
Because the slip names both keys, taking the quantum-safe signature off a
|
|
217
|
+
stub does not leave a valid stub.
|
|
218
|
+
|
|
219
|
+
A checker on a device with no built-in ML-DSA MUST report that the
|
|
220
|
+
quantum-safe signature could not be checked, and MUST NOT report the
|
|
221
|
+
record as intact. An entry none of whose signatures the device could
|
|
222
|
+
check MUST NOT be treated as evidence: what it says is not shown as fact,
|
|
223
|
+
and it is not compared with its slip.
|
|
224
|
+
|
|
225
|
+
A recorder is known by a key set of exactly three keys: Ed25519,
|
|
226
|
+
ML-DSA-87, then SLH-DSA-SHA2-256s (FIPS 205, the plain method with an
|
|
227
|
+
empty context). A seal MUST carry exactly three signatures, in that
|
|
228
|
+
order, and counts as signed only if all three check. The third rests only
|
|
229
|
+
on fingerprint functions, so it would stand even if the mathematics
|
|
230
|
+
behind ML-DSA were broken. When this draft was written, no browser
|
|
231
|
+
offered it to a page, and Node.js offered it outside the standard
|
|
232
|
+
interface: a checker in a browser reports it as not checked, which is
|
|
233
|
+
never a pass.
|
|
234
|
+
|
|
235
|
+
The issuer's passkey signature on a slip is of today's kind only. No
|
|
236
|
+
device offers a quantum-safe passkey.
|
|
237
|
+
|
|
238
|
+
## 4. The Slip
|
|
239
|
+
|
|
240
|
+
### 4.1 Content
|
|
241
|
+
|
|
242
|
+
| Member | Meaning | Form |
|
|
243
|
+
|---|---|---|
|
|
244
|
+
| `type` | The kind of record | `provared.slip.v0` |
|
|
245
|
+
| `id` | Unique number | Section 3.7 |
|
|
246
|
+
| `issuer` | Who gives permission | An object, below |
|
|
247
|
+
| `agent` | Which agent may act | `{"name": text, "keys": key set}`, and optionally `"software"`, below |
|
|
248
|
+
| `actions` | What it may do | A list of 1 to 64 action names, none repeated |
|
|
249
|
+
| `limits` | How much | A list of 0 to 64 limits, below |
|
|
250
|
+
| `requires` | What must go with an action | A list of 0 to 64 conditions, below |
|
|
251
|
+
| `never` | Stated rules | A list of 0 to 16 names, below, none repeated |
|
|
252
|
+
| `with` | With whom it may deal | A list of 0 to 64 services, below |
|
|
253
|
+
| `passes` | How many times the permission may be passed on. Optional | A whole number from 1 to 10. Absent: it may not be passed on (section 25) |
|
|
254
|
+
| `validFrom` | From when | A time |
|
|
255
|
+
| `validUntil` | Until when | A time, later than `validFrom` |
|
|
256
|
+
| `purpose` | Why | Text, 1 to 1,000 characters |
|
|
257
|
+
|
|
258
|
+
`issuer` is `{"name": text, "key": passkey public key, "rpId": text,
|
|
259
|
+
"origin": text}`. `rpId` is the website the passkey belongs to (the
|
|
260
|
+
"relying party identifier" of the Web Authentication standard). `origin`
|
|
261
|
+
is the address of the page the slip was signed on, for example
|
|
262
|
+
`https://sign.example.org`. The host in `origin` MUST be `rpId` or end
|
|
263
|
+
with a full stop and `rpId`. `origin` MUST use `https`, or be
|
|
264
|
+
`http://localhost` with or without a port number. It holds nothing after
|
|
265
|
+
the host and the port.
|
|
266
|
+
|
|
267
|
+
A **name** is text of 1 to 200 characters. It is a label chosen by
|
|
268
|
+
whoever wrote the slip. It is not checked against anything, unless a
|
|
269
|
+
vouching record stands behind it (section 23).
|
|
270
|
+
|
|
271
|
+
`agent.software`, where present, is a list of 1 to 16 of `{"name": text,
|
|
272
|
+
"sha256": fingerprint}`: the agent's program and settings as the person
|
|
273
|
+
approved them. It is a statement. Nothing in a record proves which
|
|
274
|
+
program signed with the agent's keys, and a checker MUST show it as a
|
|
275
|
+
statement.
|
|
276
|
+
|
|
277
|
+
An **action name** is 1 to 64 characters: the lower-case letters a to z,
|
|
278
|
+
digits, full stops, hyphens and underscores, beginning with a letter or digit,
|
|
279
|
+
for example `supplies.order`. The issuer chooses the names. A checker
|
|
280
|
+
compares them exactly. Names that begin `provared.` are reserved for the
|
|
281
|
+
shared list of section 16: such a name MUST be on that list.
|
|
282
|
+
|
|
283
|
+
A **limit** names an `action`, which MUST be one of `actions`, and holds
|
|
284
|
+
exactly one of `max`, `each` and `count`, each a whole number:
|
|
285
|
+
|
|
286
|
+
| Limit | Meaning |
|
|
287
|
+
|---|---|
|
|
288
|
+
| `{"action", "max", "unit"}` | The amounts of all stubs under this slip for this action, added up, must not pass `max` |
|
|
289
|
+
| `{"action", "each", "unit"}` | No single stub for this action may have an amount above `each` |
|
|
290
|
+
| `{"action", "count"}` | There must not be more than `count` stubs for this action. `count` is 1 or more |
|
|
291
|
+
| `{"action", "max", "per", "unit"}` | As `max`, within any period of `per` seconds |
|
|
292
|
+
| `{"action", "count", "per"}` | As `count`, within any period of `per` seconds |
|
|
293
|
+
|
|
294
|
+
`unit` is 1 to 16 characters: the letters a to z and A to Z, digits,
|
|
295
|
+
full stops, hyphens and underscores, with no spaces, beginning with a
|
|
296
|
+
letter or a digit, for example `items` or `hours`. (A unit is shown
|
|
297
|
+
beside the checker's own words, so it is kept too short and too plain to
|
|
298
|
+
be mistaken for them.) A `count` has no
|
|
299
|
+
unit, and `each` has no period. `per` is from 1 to 31,622,400 (366 days).
|
|
300
|
+
A period is counted backwards from each stub, by the times the stubs
|
|
301
|
+
state. It holds every stub under the slip for the action, in whichever
|
|
302
|
+
chain (section 25) and at whichever place in the book, whose `when` is
|
|
303
|
+
later than this stub's `when` less `per` seconds and earlier than this
|
|
304
|
+
stub's `when`; every such stub with the same `when` that stands earlier
|
|
305
|
+
in the book; and this stub. There are no calendar days and no time
|
|
306
|
+
zones. A stub further on in the book, in another chain, may state an
|
|
307
|
+
earlier time, so a checker works these limits out once it has read every
|
|
308
|
+
stub under the slip. The finding is given for the stub whose period
|
|
309
|
+
holds too much, which may be a stub of another chain than the one that
|
|
310
|
+
was written last. A slip MUST NOT hold two limits with the same action, the same one
|
|
311
|
+
of `max`, `each` and `count`, and the same `per`.
|
|
312
|
+
|
|
313
|
+
A **condition** is `{"need": "countersignature"}` or `{"need":
|
|
314
|
+
"approval"}`, with these optional members: `action` (one of `actions`;
|
|
315
|
+
without it the condition applies to every action), and `above` with
|
|
316
|
+
`unit` (the condition applies only to a stub whose amount is more than
|
|
317
|
+
`above`; these two come together and need an `action`).
|
|
318
|
+
`countersignature` means the stub must carry the countersignature of the
|
|
319
|
+
service it names (section 6). `approval` means the stub must carry the
|
|
320
|
+
person's approval (section 17). A slip MUST NOT hold two conditions with
|
|
321
|
+
the same `need` and the same `action`.
|
|
322
|
+
|
|
323
|
+
Every `unit` named for one action, in its limits and its conditions, MUST
|
|
324
|
+
be the same, because a stub gives one amount.
|
|
325
|
+
|
|
326
|
+
A name in **`never`** is a kind of action or a rule of conduct from
|
|
327
|
+
section 16, for example `destroys` or `impersonate`. A slip MUST NOT
|
|
328
|
+
allow, in `actions`, a shared action of a kind that its `never` forbids.
|
|
329
|
+
A rule of conduct is the person's signed instruction to the agent. No
|
|
330
|
+
check of a record can show that the agent kept it (section 13).
|
|
331
|
+
|
|
332
|
+
A **service** is `{"id": text, "name": text}` or `{"id": text, "keys":
|
|
333
|
+
key set, "name": text}`. `id` has the form of an action name and MUST NOT
|
|
334
|
+
repeat within the slip. A service with no `keys` cannot countersign.
|
|
335
|
+
|
|
336
|
+
### 4.2 How a passkey signs a slip
|
|
337
|
+
|
|
338
|
+
A passkey does not sign a document. It signs a short value the web page
|
|
339
|
+
hands to it (the challenge), together with the address of the website.
|
|
340
|
+
|
|
341
|
+
1. Write the content in the canonical form. Build the signing input
|
|
342
|
+
(section 3.1) with the slip's protected header (section 3.2).
|
|
343
|
+
2. The challenge is the SHA-256 hash of the signing input.
|
|
344
|
+
3. Ask the passkey to sign with that challenge, with the person confirmed
|
|
345
|
+
by the device ("user verification: required").
|
|
346
|
+
4. The passkey returns three values: the authenticator data, the client
|
|
347
|
+
data, and the signature. Store all three exactly as returned.
|
|
348
|
+
|
|
349
|
+
### 4.3 The signed slip
|
|
350
|
+
|
|
351
|
+
A slip has exactly one signature entry:
|
|
352
|
+
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"protected": "<the slip's protected header>",
|
|
356
|
+
"header": { "authenticatorData": "<base64url>", "clientDataJSON": "<base64url>" },
|
|
357
|
+
"signature": "<base64url of the signature as the passkey returned it>"
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
`header` MUST hold exactly those two members.
|
|
362
|
+
|
|
363
|
+
### 4.4 Checking a slip
|
|
364
|
+
|
|
365
|
+
A checker follows the checking steps of the Web Authentication standard
|
|
366
|
+
(W3C Web Authentication Level 3, section 7.2), as far as they apply to a
|
|
367
|
+
check made later and offline. It MUST confirm all of these:
|
|
368
|
+
|
|
369
|
+
1. The envelope, the label, the canonical form and every member are as
|
|
370
|
+
sections 3 and 4.1 require.
|
|
371
|
+
2. The client data is JSON whose `type` is `webauthn.get`.
|
|
372
|
+
3. The client data's `challenge` is the base64url of the SHA-256 hash of
|
|
373
|
+
the signing input.
|
|
374
|
+
4. The client data's `origin` equals `issuer.origin`, and `crossOrigin`
|
|
375
|
+
is not true.
|
|
376
|
+
5. The authenticator data is at least 37 bytes. Its first 32 bytes equal
|
|
377
|
+
the SHA-256 hash of `issuer.rpId`.
|
|
378
|
+
6. In the flags byte, "user present" (bit 0) and "user verified" (bit 2)
|
|
379
|
+
are both set. "Attested credential data" (bit 6) is not set. If
|
|
380
|
+
"extension data" (bit 7) is not set, the authenticator data is exactly
|
|
381
|
+
37 bytes.
|
|
382
|
+
7. The signature fits `issuer.key`, over the authenticator data followed
|
|
383
|
+
by the SHA-256 hash of the client data. For an `ES256` key the stored
|
|
384
|
+
signature is in ASN.1 DER form and MUST be strictly encoded.
|
|
385
|
+
|
|
386
|
+
If the checker was given the thumbprints of the issuer keys it expects,
|
|
387
|
+
it MUST also confirm that `issuer.key` is one of them. If it was given
|
|
388
|
+
none, it MUST say that the issuer's key was not compared with a known
|
|
389
|
+
key.
|
|
390
|
+
|
|
391
|
+
The signature counter in the authenticator data is not used: an offline
|
|
392
|
+
checker keeps no state.
|
|
393
|
+
|
|
394
|
+
## 5. The Stub
|
|
395
|
+
|
|
396
|
+
### 5.1 Content
|
|
397
|
+
|
|
398
|
+
| Member | Meaning | Form |
|
|
399
|
+
|---|---|---|
|
|
400
|
+
| `type` | The kind of record | `provared.stub.v0` |
|
|
401
|
+
| `id` | Unique number | Section 3.7 |
|
|
402
|
+
| `slip` | The slip relied on | The slip's fingerprint |
|
|
403
|
+
| `seq` | Place in the chain | A whole number: 0 for the first stub under the slip, then 1, 2, … |
|
|
404
|
+
| `previous` | The stub before | The fingerprint of the stub with the number before. Present unless `seq` is 0 |
|
|
405
|
+
| `action` | What was done | An action name |
|
|
406
|
+
| `amount` | How much. Optional | `{"unit": text, "value": whole number}` |
|
|
407
|
+
| `with` | With whom. Optional | The `id` of a service in the slip |
|
|
408
|
+
| `details` | The documents involved. Optional | A list of 1 to 32 of `{"name": text, "sha256": fingerprint of the document}` |
|
|
409
|
+
| `approval` | The person's approval of this action. Optional | The fingerprint of the approval (section 17) |
|
|
410
|
+
| `terms` | The service's terms the agent relied on. Optional; needs `with` | The fingerprint of the terms (section 19) |
|
|
411
|
+
| `pass` | For a helper agent: the pass it acts under. Optional | The fingerprint of the pass (section 25) |
|
|
412
|
+
| `when` | When it was done | A time |
|
|
413
|
+
|
|
414
|
+
A stub holds fingerprints of documents, never the documents.
|
|
415
|
+
|
|
416
|
+
### 5.2 Signing and checking
|
|
417
|
+
|
|
418
|
+
A stub is signed by the agent's key set (section 3.9), with the stub
|
|
419
|
+
labels of section 3.2.
|
|
420
|
+
|
|
421
|
+
A checker MUST confirm that both signatures check against the two keys
|
|
422
|
+
the slip gives for the agent.
|
|
423
|
+
|
|
424
|
+
## 6. The countersignature
|
|
425
|
+
|
|
426
|
+
Content: `{"stub": fingerprint of the stub, "type":
|
|
427
|
+
"provared.countersignature.v0", "when": a time}`. It means: "this action
|
|
428
|
+
happened with me".
|
|
429
|
+
|
|
430
|
+
It is signed by the service's key set, with the countersignature labels
|
|
431
|
+
of section 3.2. A checker MUST confirm that `stub` is the fingerprint of
|
|
432
|
+
the stub it accompanies, and that both signatures check against the keys
|
|
433
|
+
the slip gives for the service named in the stub's `with`.
|
|
434
|
+
|
|
435
|
+
A stub with no countersignature is **one-sided**. It is a named state,
|
|
436
|
+
not a failure. It proves what the agent's side said. A checker MUST show
|
|
437
|
+
it as one-sided.
|
|
438
|
+
|
|
439
|
+
## 7. The chain
|
|
440
|
+
|
|
441
|
+
There is one chain for the stubs of the slip's own agent, and one for the
|
|
442
|
+
stubs under each pass (section 25). For the stubs of one chain, taken in
|
|
443
|
+
the order they appear in a book, a checker MUST confirm:
|
|
444
|
+
|
|
445
|
+
- the first has `seq` 0 and no `previous`;
|
|
446
|
+
- each later one has the next number, and `previous` equal to the
|
|
447
|
+
fingerprint of the one before;
|
|
448
|
+
- `when` never goes backwards;
|
|
449
|
+
- no `id` appears twice in the book, among records of every kind
|
|
450
|
+
(`duplicate-id`).
|
|
451
|
+
|
|
452
|
+
## 8. What a stub shows about the agent
|
|
453
|
+
|
|
454
|
+
These are not faults in the record. A sound record can show that the
|
|
455
|
+
agent went outside its slip. A checker reports each of them, and at which
|
|
456
|
+
stub:
|
|
457
|
+
|
|
458
|
+
| Code | Shown when |
|
|
459
|
+
|---|---|
|
|
460
|
+
| `action-not-allowed` | `action` is not in the slip's `actions` |
|
|
461
|
+
| `party-not-allowed` | `with` is not the `id` of a service in the slip |
|
|
462
|
+
| `outside-valid-time` | `when` is before `validFrom`, or not before `validUntil` |
|
|
463
|
+
| `amount-missing` | The slip has a limit or a condition with a `unit` for this action, and the stub has no amount in that unit. Reported once for a stub |
|
|
464
|
+
| `over-limit` | The running total for this action, with this stub added, is more than a limit's `max` |
|
|
465
|
+
| `over-each-limit` | The stub's amount is more than a limit's `each` |
|
|
466
|
+
| `over-count-limit` | With this stub there are more stubs for this action than a limit's `count` |
|
|
467
|
+
| `over-period-limit` | Within the period that ends at this stub, the total is more than `max`, or the number of stubs is more than `count` |
|
|
468
|
+
| `countersignature-missing` | A condition asks for a countersignature, and the stub has none |
|
|
469
|
+
| `approval-missing` | A condition asks for the person's approval, and the stub has none |
|
|
470
|
+
| `prohibited` | `action` is a shared action of a kind the slip's `never` forbids |
|
|
471
|
+
| `after-cancellation` | The person cancelled the slip before this stub (section 22) |
|
|
472
|
+
| `pass-not-allowed` | The stub was written under a pass that the slip does not allow (section 25) |
|
|
473
|
+
| `outside-terms` | The stub relies on a service's terms (section 19), and the terms do not accept `action`, or `when` is before their `validFrom` or not before their `validUntil` |
|
|
474
|
+
|
|
475
|
+
A stub is compared with its slip only if the stub passed its own check.
|
|
476
|
+
Totals, counts and periods take in only the stubs that were compared. A
|
|
477
|
+
pass that hands on more than its writer holds is reported on the pass
|
|
478
|
+
(`pass-wider`, section 25).
|
|
479
|
+
|
|
480
|
+
The order in which a checker reports several findings for one entry is
|
|
481
|
+
not part of this format: two checkers agree if they report the same set.
|
|
482
|
+
Where an entry fails its own check in several ways, a checker MUST report
|
|
483
|
+
at least one of them, and MAY stop at the first.
|
|
484
|
+
|
|
485
|
+
A checker answers three questions and keeps them apart: was a problem
|
|
486
|
+
found in the record; was every signature checked on this device; and what
|
|
487
|
+
do the stubs show about the agent. It MUST call a record intact only if no
|
|
488
|
+
problem was found and every signature was checked. It MUST say that the
|
|
489
|
+
agent stayed within its slip only if every stub was compared with its slip
|
|
490
|
+
and none was outside it. If the checker itself meets something it did not
|
|
491
|
+
expect, it MUST report a problem, never a pass.
|
|
492
|
+
|
|
493
|
+
## 9. The book
|
|
494
|
+
|
|
495
|
+
A book is UTF-8 text. Each line is one entry, ended by a line feed (the
|
|
496
|
+
line feed after the last line may be missing). An
|
|
497
|
+
entry is a JSON object in the canonical form (section 3.4, with records
|
|
498
|
+
in place of the narrowed content), and is one of:
|
|
499
|
+
|
|
500
|
+
- `{"slip": slip record}`
|
|
501
|
+
- `{"stub": stub record}`, which MAY also hold `"countersignature":
|
|
502
|
+
countersignature record` and `"approval": approval record`
|
|
503
|
+
- `{"refusal": refusal record}`
|
|
504
|
+
- `{"terms": terms record}`
|
|
505
|
+
- `{"seal": seal record}`, which MAY also hold `"stamps": list of 1 to 4
|
|
506
|
+
time-stamps` (section 21)
|
|
507
|
+
- `{"cancellation": cancellation record}`, which MAY also hold `"stamps"`
|
|
508
|
+
(section 22)
|
|
509
|
+
- `{"acknowledgement": acknowledgement record}` (section 26)
|
|
510
|
+
- `{"vouching": vouching record}` and `{"withdrawal": withdrawal record}`
|
|
511
|
+
(section 23)
|
|
512
|
+
- `{"pass": pass record}` (section 25)
|
|
513
|
+
|
|
514
|
+
A slip MUST come before the entries that rely on it, and a set of terms
|
|
515
|
+
before the stubs that rely on it. A book MUST NOT hold
|
|
516
|
+
the same slip twice, nor more than 100,000 entries. A line MUST NOT be
|
|
517
|
+
longer than 131,072 bytes.
|
|
518
|
+
|
|
519
|
+
## 10. The tree and the top fingerprint
|
|
520
|
+
|
|
521
|
+
The entries of a book are the leaves of a Merkle tree built exactly as
|
|
522
|
+
RFC 6962 (Certificate Transparency), section 2.1, sets out, with SHA-256.
|
|
523
|
+
The data of a leaf is the bytes of its line, without the line feed. The
|
|
524
|
+
root of the tree is the book's **top fingerprint**.
|
|
525
|
+
|
|
526
|
+
A top fingerprint is signed, with the number of entries, by a seal
|
|
527
|
+
(section 21), and an outside time-stamp on the seal states when. Without
|
|
528
|
+
a seal that the checker has reason to trust, a top fingerprint is worth
|
|
529
|
+
as much as the checker's other reason to trust it, for example a copy
|
|
530
|
+
they took earlier.
|
|
531
|
+
|
|
532
|
+
The top fingerprint does not by itself fix how many entries the book
|
|
533
|
+
holds: that is a property of this kind of tree. Whoever keeps a copy of a
|
|
534
|
+
top fingerprint MUST keep the number of entries with it, and a later
|
|
535
|
+
signature or time-stamp MUST cover both, as RFC 6962 section 3.5 does. A
|
|
536
|
+
checker that is given a top fingerprint or a number of entries to expect
|
|
537
|
+
MUST compare it.
|
|
538
|
+
|
|
539
|
+
## 11. The Show: one page, with proof
|
|
540
|
+
|
|
541
|
+
A Show hands a checker some entries of a book and, for each, the few
|
|
542
|
+
fingerprints needed to work out the top fingerprint again (the audit path
|
|
543
|
+
of RFC 6962, section 2.1.1).
|
|
544
|
+
|
|
545
|
+
```json
|
|
546
|
+
{
|
|
547
|
+
"type": "provared.show.v0",
|
|
548
|
+
"size": 12,
|
|
549
|
+
"root": "<the top fingerprint>",
|
|
550
|
+
"pages": [
|
|
551
|
+
{ "index": 3, "entry": "<the line, exactly>", "path": ["<fingerprint>", "…"] }
|
|
552
|
+
]
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
A Show MAY also hold `"seal"`: an entry of the form `{"seal": seal
|
|
557
|
+
record}`, with or without `"stamps"`. The Show is then of the book as it
|
|
558
|
+
stood when that seal was made: the seal's `size` and `root` MUST equal the
|
|
559
|
+
Show's (`seal-mismatch`), and a checker checks the seal and its
|
|
560
|
+
time-stamps as section 21 sets out. Its `id` MUST NOT be that of a
|
|
561
|
+
record on any page (`duplicate-id`), as in a whole book (section 7).
|
|
562
|
+
Such a Show proves that its pages existed by the time the time-stamp
|
|
563
|
+
states, with no other copy of the top fingerprint.
|
|
564
|
+
|
|
565
|
+
A Show holds 1 to 64 pages, none repeated. It is not itself signed. A checker
|
|
566
|
+
MUST confirm each page with the checking steps of RFC 9162, section
|
|
567
|
+
2.1.3.2, then check each entry as above. A stub can be checked only if
|
|
568
|
+
its slip is among the pages, and a stub that relies on a service's terms
|
|
569
|
+
only if those terms are among the pages. A Show can show a stub outside
|
|
570
|
+
its slip, including a single stub that passes a limit by itself, and a
|
|
571
|
+
stub that lacks a countersignature or an approval the slip asks for. It
|
|
572
|
+
cannot show a count, that a limit was kept, or that an approval was used
|
|
573
|
+
only once: those need every stub under the slip. Nor can it show that a
|
|
574
|
+
slip was not cancelled (section 22), or that a vouching record was not
|
|
575
|
+
withdrawn (section 23), on a page that is not among its pages. A checker
|
|
576
|
+
MUST say both with every Show.
|
|
577
|
+
|
|
578
|
+
Whoever hands over a Show chooses its pages and its seal. So a Show does
|
|
579
|
+
not show what a seal that was left out of it would show. Where a page is
|
|
580
|
+
dated after the time-stamp of a seal that comes after it in the book,
|
|
581
|
+
that is reported only if the seal is among the pages, and the seal is
|
|
582
|
+
the page reported (section 21.3). Only the whole book shows it in every
|
|
583
|
+
case.
|
|
584
|
+
|
|
585
|
+
The same holds for the rules that rest on a seal earlier in the book
|
|
586
|
+
(section 21.1, rule 4, and section 21.3, the second case): a Show
|
|
587
|
+
applies them only for seals that are among its pages. With such a seal
|
|
588
|
+
left out, a Show may pass where the whole book reports a seal as dated
|
|
589
|
+
before a time-stamp it covers; it may count a block time-stamp that the
|
|
590
|
+
whole book sets aside, and so show its pages as having existed earlier
|
|
591
|
+
than the whole book shows; and it may report a seal as dated after its
|
|
592
|
+
block time-stamp where the whole book sets that time-stamp aside and
|
|
593
|
+
passes. The last two need a block that states a time far behind the
|
|
594
|
+
true time.
|
|
595
|
+
|
|
596
|
+
Nothing fixes the time-stamps beside the seal that comes with a Show.
|
|
597
|
+
They stand outside the tree and outside the seal's signatures, so
|
|
598
|
+
whoever hands the Show over can put a later time-stamp in the place of
|
|
599
|
+
an earlier one. The same holds for the last seal of a book. A later
|
|
600
|
+
time-stamp shows less, never more, and the pages are still held against
|
|
601
|
+
the seal's own date (section 21.1, rule 4).
|
|
602
|
+
|
|
603
|
+
## 12. Not in draft version 0
|
|
604
|
+
|
|
605
|
+
| Missing | What follows |
|
|
606
|
+
|---|---|
|
|
607
|
+
| A public place where seals are kept | The last seal of a book, with everything after it, can be removed unnoticed, unless someone else holds a copy of that seal or of its top fingerprint and number of entries |
|
|
608
|
+
| A quantum-safe time-stamp | Time-stamp services sign with methods of today's kind |
|
|
609
|
+
| Covered fields outside a slip's names and purpose | Every other field of an entry is visible to whoever holds it |
|
|
610
|
+
| A compact binary form | Records are JSON text only |
|
|
611
|
+
|
|
612
|
+
## 13. What a record does not prove
|
|
613
|
+
|
|
614
|
+
- It proves what was recorded, not what was left out. An agent that acts
|
|
615
|
+
and writes no stub leaves no trace.
|
|
616
|
+
- A one-sided stub proves what the agent's side said, not what the other
|
|
617
|
+
side did.
|
|
618
|
+
- A refusal proves what the service's side said, not what the agent did.
|
|
619
|
+
- A rule of conduct in a slip, such as "never claim to be a human being",
|
|
620
|
+
is the person's signed instruction. No check can show that the agent
|
|
621
|
+
kept it.
|
|
622
|
+
- An approval proves that the passkey approved that one action. It does
|
|
623
|
+
not prove that the person read what they approved.
|
|
624
|
+
- It does not show that an action was wise, lawful or wanted.
|
|
625
|
+
- A badly written slip is faithfully recorded as a badly written slip.
|
|
626
|
+
- It does not prove who was holding the device when the passkey signed.
|
|
627
|
+
- A name in a record is a label. Only keys are checked. A vouching
|
|
628
|
+
record shows which organisation stood behind a name; it does not prove
|
|
629
|
+
that the organisation checked well.
|
|
630
|
+
- The fingerprints of an agent's software in a slip are a statement of
|
|
631
|
+
what the person approved, not proof of what ran.
|
|
632
|
+
|
|
633
|
+
## 14. Standards used
|
|
634
|
+
|
|
635
|
+
| Standard | Used for |
|
|
636
|
+
|---|---|
|
|
637
|
+
| RFC 8259 (JSON); RFC 8785 (JSON Canonicalization Scheme) | Writing the content |
|
|
638
|
+
| RFC 7515 (JSON Web Signature), sections 5.1 and 7.2.1 | The signed envelope |
|
|
639
|
+
| RFC 7517 (JSON Web Key); RFC 7638 (thumbprints) | Keys and their names |
|
|
640
|
+
| RFC 8725, section 3.11 | Labels (explicit typing) |
|
|
641
|
+
| RFC 8032; RFC 8037; RFC 9864 | Ed25519 and its names |
|
|
642
|
+
| FIPS 204; RFC 9964 | ML-DSA-87 and its names |
|
|
643
|
+
| FIPS 180-4 | SHA-256 |
|
|
644
|
+
| W3C Web Authentication Level 3, section 7.2 | Passkey signatures |
|
|
645
|
+
| FIPS 186-5; RFC 7518; RFC 8017 | The signing methods passkeys use (ES256, RS256) |
|
|
646
|
+
| RFC 4648, section 5 | Base64url |
|
|
647
|
+
| RFC 3339 | Times |
|
|
648
|
+
| RFC 6962, section 2.1; RFC 9162, section 2.1.3.2 | The tree and its proofs |
|
|
649
|
+
| FIPS 205 | SLH-DSA-SHA2-256s, the third signature on a seal |
|
|
650
|
+
| RFC 3161; RFC 5652; RFC 5280; ITU-T X.690 | Time-stamps: the statement, its signed wrapper, the certificate, and the byte layout (DER) |
|
|
651
|
+
| The OpenTimestamps proof file, version 1 (an open format; not the work of a standards body) | Block time-stamps: the steps from a fingerprint to the Merkle root of a block |
|
|
652
|
+
| RFC 9901 (Selective Disclosure for JSON Web Tokens) | Covered fields |
|
|
653
|
+
|
|
654
|
+
## 15. Choices that go beyond the standards
|
|
655
|
+
|
|
656
|
+
Each of these is a choice of this draft, to be reviewed before the format
|
|
657
|
+
is frozen.
|
|
658
|
+
|
|
659
|
+
1. The method name `prova.red/webauthn/v0`: a passkey signature wrapped
|
|
660
|
+
as a JSON Web Signature. No registered name exists for it.
|
|
661
|
+
2. The media types of section 3.2 (`vnd.provared.slip.v0+json` and
|
|
662
|
+
the others, each ending in `.v0+json`) are not registered.
|
|
663
|
+
3. Protected headers are fixed texts, compared byte for byte.
|
|
664
|
+
4. The hybrid is two signatures side by side with the rule "both must
|
|
665
|
+
check", not a combined signature.
|
|
666
|
+
5. The content is narrowed to whole numbers, strings, lists and objects.
|
|
667
|
+
6. A fingerprint covers the content only, not the signatures.
|
|
668
|
+
7. The kinds of limit, the conditions and the `never` list of section 4.1.
|
|
669
|
+
8. A period is counted backwards from each stub, in seconds, with no
|
|
670
|
+
calendar days and no time zones.
|
|
671
|
+
9. The shared list of actions, the kinds of action and the rules of
|
|
672
|
+
conduct of section 16. They are a first draft, written before real
|
|
673
|
+
agents have used them.
|
|
674
|
+
10. The approval, the refusal and the terms for agents of sections 17 to
|
|
675
|
+
19, and the labels `vnd.provared.approval.v0+json`,
|
|
676
|
+
`vnd.provared.refusal.v0+json` and `vnd.provared.terms.v0+json`.
|
|
677
|
+
|
|
678
|
+
11. The seal of section 21, its label `vnd.provared.seal.v0+json`, and
|
|
679
|
+
its three signatures side by side. The name `SLH-DSA-SHA2-256s` is
|
|
680
|
+
used as FIPS 205 gives it.
|
|
681
|
+
12. A checker trusts a time-stamp service by the fingerprint of the
|
|
682
|
+
service's certificate, given by the person checking. It follows no
|
|
683
|
+
chain of certificates.
|
|
684
|
+
13. A time-stamp is made over the seal's fingerprint. The allowance
|
|
685
|
+
between clocks is 300 seconds. A time-stamp that states its own time
|
|
686
|
+
more loosely than that is refused.
|
|
687
|
+
13a. The block time-stamp of section 21.4: the proof read strictly, with
|
|
688
|
+
three kinds of step only; the block's header kept beside the proof; a
|
|
689
|
+
block trusted by its fingerprint, given by the person checking, or
|
|
690
|
+
found in a chain of block headers the checker checks itself, with
|
|
691
|
+
known blocks and six blocks after it; a block's time taken as right
|
|
692
|
+
to within 7,200 seconds.
|
|
693
|
+
|
|
694
|
+
14. The cancellation, the vouching record and the withdrawal of sections
|
|
695
|
+
22 and 23, and their labels.
|
|
696
|
+
15. A stub counts as made before a time-stamped cancellation only if an
|
|
697
|
+
outside time-stamp shows that it existed by then.
|
|
698
|
+
|
|
699
|
+
16. Covered fields follow RFC 9901, narrowed as section 24 sets out: only
|
|
700
|
+
a slip's names and purpose; never an item of a list; exactly one
|
|
701
|
+
fingerprint where a field is covered, with no decoys; disclosures in
|
|
702
|
+
the canonical form; SHA-256 only; disclosures kept beside the record,
|
|
703
|
+
not inside a line of the book.
|
|
704
|
+
|
|
705
|
+
17. The pass of section 25, its label, and one chain of stubs for each
|
|
706
|
+
pass.
|
|
707
|
+
18. The acknowledgement of section 26 and its label
|
|
708
|
+
`vnd.provared.acknowledgement.v0+json`.
|
|
709
|
+
|
|
710
|
+
## 16. The shared list: actions, kinds of action, rules of conduct
|
|
711
|
+
|
|
712
|
+
Anyone may use action names of their own. So that one organisation's slip
|
|
713
|
+
can be read by another, this format also keeps a shared list. Every name
|
|
714
|
+
on it begins `provared.`, and belongs to exactly one kind of action.
|
|
715
|
+
|
|
716
|
+
The kinds of action:
|
|
717
|
+
|
|
718
|
+
| Kind | Meaning |
|
|
719
|
+
|---|---|
|
|
720
|
+
| `reads` | Looks at data without changing it. |
|
|
721
|
+
| `changes` | Creates or changes data in a way that can be put back. |
|
|
722
|
+
| `destroys` | Removes data or a resource in a way that may not be put back. |
|
|
723
|
+
| `sends` | Sends a message or data to a person, to the public or to another system. |
|
|
724
|
+
| `commits` | Binds the person to something: an order, a booking, an agreement, an account. |
|
|
725
|
+
| `grants` | Gives someone or something access or permission. |
|
|
726
|
+
| `runs` | Runs a program or a command. |
|
|
727
|
+
| `enters` | Signs in to a system or an account. |
|
|
728
|
+
|
|
729
|
+
The shared actions:
|
|
730
|
+
|
|
731
|
+
| Action | Kind | Meaning |
|
|
732
|
+
|---|---|---|
|
|
733
|
+
| `provared.data.read` | `reads` | Read stored data or a file. |
|
|
734
|
+
| `provared.data.search` | `reads` | Search stored data. |
|
|
735
|
+
| `provared.data.create` | `changes` | Create a new item of data or a new file. |
|
|
736
|
+
| `provared.data.change` | `changes` | Change an item of data or a file that exists. |
|
|
737
|
+
| `provared.data.delete` | `destroys` | Delete data or a file. |
|
|
738
|
+
| `provared.data.export` | `sends` | Copy data out of the system that keeps it. |
|
|
739
|
+
| `provared.message.read` | `reads` | Read messages. |
|
|
740
|
+
| `provared.message.draft` | `changes` | Write a message without sending it. |
|
|
741
|
+
| `provared.message.send` | `sends` | Send a message to a person. |
|
|
742
|
+
| `provared.post.publish` | `sends` | Publish something where the public can see it. |
|
|
743
|
+
| `provared.calendar.read` | `reads` | Read a calendar. |
|
|
744
|
+
| `provared.calendar.change` | `changes` | Add, move or remove an entry in a calendar. |
|
|
745
|
+
| `provared.booking.make` | `commits` | Book a place, a time or a service. |
|
|
746
|
+
| `provared.booking.cancel` | `commits` | Cancel a booking. |
|
|
747
|
+
| `provared.order.place` | `commits` | Place an order for goods or services. |
|
|
748
|
+
| `provared.order.cancel` | `commits` | Cancel an order. |
|
|
749
|
+
| `provared.terms.accept` | `commits` | Accept terms, or sign an agreement. |
|
|
750
|
+
| `provared.form.submit` | `commits` | Submit a form or an application. |
|
|
751
|
+
| `provared.account.create` | `commits` | Open an account. |
|
|
752
|
+
| `provared.account.sign-in` | `enters` | Sign in to an account or a system. |
|
|
753
|
+
| `provared.access.grant` | `grants` | Give a person or a program access. |
|
|
754
|
+
| `provared.access.remove` | `changes` | Take access away from a person or a program. |
|
|
755
|
+
| `provared.key.create` | `grants` | Make a key or a password that gives access. |
|
|
756
|
+
| `provared.code.read` | `reads` | Read the source of a program. |
|
|
757
|
+
| `provared.code.change` | `changes` | Change the source of a program. |
|
|
758
|
+
| `provared.code.run` | `runs` | Run a program or a command. |
|
|
759
|
+
| `provared.code.release` | `runs` | Put a program into live use. |
|
|
760
|
+
| `provared.system.configure` | `changes` | Change the settings of a system. |
|
|
761
|
+
| `provared.web.read` | `reads` | Read a public web page. |
|
|
762
|
+
| `provared.agent.instruct` | `sends` | Hand a task to another agent. |
|
|
763
|
+
|
|
764
|
+
The rules of conduct that a slip's `never`, or a service's terms, may
|
|
765
|
+
state:
|
|
766
|
+
|
|
767
|
+
| Rule | Meaning |
|
|
768
|
+
|---|---|
|
|
769
|
+
| `impersonate` | Never claim to be a human being, or to be anyone other than the agent of the person who signed the slip. |
|
|
770
|
+
| `bypass` | Never go around an access control, a block or a refusal. |
|
|
771
|
+
| `escalate` | Never obtain or use access that it was not given. |
|
|
772
|
+
| `conceal` | Never hide, alter or leave out its own records. |
|
|
773
|
+
| `deceive` | Never state what it has reason to believe is false, and never make up a record or a result. |
|
|
774
|
+
| `harass` | Never threaten, pressure or attack a person. |
|
|
775
|
+
| `disclose` | Never pass information that is not public to anyone the slip does not name. |
|
|
776
|
+
| `continue-after-stop` | Never carry on after being told to stop. |
|
|
777
|
+
|
|
778
|
+
A `never` list MAY hold the name of any kind of action and of any rule of
|
|
779
|
+
conduct above.
|
|
780
|
+
|
|
781
|
+
## 17. The approval
|
|
782
|
+
|
|
783
|
+
A slip may ask for the person's own approval of an action (section 4.1).
|
|
784
|
+
The person gives it with the same passkey that signed the slip.
|
|
785
|
+
|
|
786
|
+
Content:
|
|
787
|
+
|
|
788
|
+
| Member | Meaning | Form |
|
|
789
|
+
|---|---|---|
|
|
790
|
+
| `type` | The kind of record | `provared.approval.v0` |
|
|
791
|
+
| `id` | Unique number | Section 3.7 |
|
|
792
|
+
| `slip` | The slip | The slip's fingerprint |
|
|
793
|
+
| `action` | What is approved | An action name |
|
|
794
|
+
| `amount`, `with`, `details` | Optional | As in a stub (section 5.1) |
|
|
795
|
+
| `when` | When it was given | A time |
|
|
796
|
+
|
|
797
|
+
It is signed as a slip is (sections 4.2 and 4.3), with the approval label
|
|
798
|
+
of section 3.2. An approval is for exactly one action. The stub names it
|
|
799
|
+
by its fingerprint, in `approval`, and the approval is kept on the same
|
|
800
|
+
line of the book as the stub.
|
|
801
|
+
|
|
802
|
+
A checker MUST confirm all of these, and otherwise report a problem:
|
|
803
|
+
|
|
804
|
+
1. The approval's fingerprint is the one the stub names
|
|
805
|
+
(`approval-mismatch`; a stub that names an approval which is not with
|
|
806
|
+
it: `approval-not-found`).
|
|
807
|
+
2. Its `slip` is the stub's `slip`, and its `action`, `amount`, `with` and
|
|
808
|
+
`details` are each the same as the stub's, or absent from both
|
|
809
|
+
(`approval-mismatch`).
|
|
810
|
+
3. Its `id` is not the `id` of an approval on an earlier line
|
|
811
|
+
(`approval-reused`), nor of any other record (`duplicate-id`). Single
|
|
812
|
+
pages cannot show this.
|
|
813
|
+
4. The passkey signature checks, by the steps of section 4.4, against the
|
|
814
|
+
`issuer` of the slip (`approval-invalid`).
|
|
815
|
+
5. Its `when` is not more than 300 seconds after the stub's `when`
|
|
816
|
+
(`approval-dated-after-stub`). The stub names the approval, so the
|
|
817
|
+
stub was signed after the approval was written.
|
|
818
|
+
|
|
819
|
+
## 18. The refusal
|
|
820
|
+
|
|
821
|
+
A service that refuses what an agent asked for may say so in a record of
|
|
822
|
+
its own. It leaves evidence of the attempt even if the agent's own record
|
|
823
|
+
is silent.
|
|
824
|
+
|
|
825
|
+
Content:
|
|
826
|
+
|
|
827
|
+
| Member | Meaning | Form |
|
|
828
|
+
|---|---|---|
|
|
829
|
+
| `type` | The kind of record | `provared.refusal.v0` |
|
|
830
|
+
| `id` | Unique number | Section 3.7 |
|
|
831
|
+
| `slip` | The slip the agent showed | The slip's fingerprint |
|
|
832
|
+
| `by` | Who refused | `{"keys": key set, "name": text}` |
|
|
833
|
+
| `action` | What the agent asked for | An action name. A name that begins `provared.` need not be on the shared list here: what was asked for is written down as it was asked |
|
|
834
|
+
| `amount` | Optional | `{"unit": text, "value": whole number}` |
|
|
835
|
+
| `reason` | Why | One of the names below |
|
|
836
|
+
| `when` | When | A time |
|
|
837
|
+
|
|
838
|
+
| Reason | Meaning |
|
|
839
|
+
|---|---|
|
|
840
|
+
| `not-in-slip` | The slip does not cover the action, or does not name this service. |
|
|
841
|
+
| `over-limit` | The action would pass a limit of the slip. |
|
|
842
|
+
| `outside-valid-time` | The slip was not in force at that time. |
|
|
843
|
+
| `slip-not-sound` | The slip did not pass its check. |
|
|
844
|
+
| `needs-approval` | The slip asks for the person's approval, and none was shown. |
|
|
845
|
+
| `against-terms` | The service's terms for agents do not accept the action. |
|
|
846
|
+
| `other` | Another reason. |
|
|
847
|
+
|
|
848
|
+
It is signed with the key set in `by`, with the refusal labels of section
|
|
849
|
+
3.2. A checker MUST confirm both signatures against `by.keys`, and MUST
|
|
850
|
+
say whether those keys are the keys the slip gives for one of its
|
|
851
|
+
services, or the keys of a party the slip does not name.
|
|
852
|
+
|
|
853
|
+
A refusal is one-sided: it is the service's statement. A checker MUST show
|
|
854
|
+
it as such, and MUST NOT count it as the agent going outside its slip.
|
|
855
|
+
|
|
856
|
+
## 19. A service's terms for agents
|
|
857
|
+
|
|
858
|
+
A service may state which actions it accepts from agents.
|
|
859
|
+
|
|
860
|
+
Content:
|
|
861
|
+
|
|
862
|
+
| Member | Meaning | Form |
|
|
863
|
+
|---|---|---|
|
|
864
|
+
| `type` | The kind of record | `provared.terms.v0` |
|
|
865
|
+
| `id` | Unique number | Section 3.7 |
|
|
866
|
+
| `by` | Whose terms | `{"keys": key set, "name": text}` |
|
|
867
|
+
| `accepts` | The actions it accepts | A list of 1 to 64 action names, none repeated |
|
|
868
|
+
| `never` | What it asks of agents | A list of 0 to 16 names from section 16, none repeated |
|
|
869
|
+
| `validFrom`, `validUntil` | When the terms are in force | Times; the second later than the first |
|
|
870
|
+
|
|
871
|
+
Terms MUST NOT accept a shared action of a kind that their own `never`
|
|
872
|
+
forbids. A rule of conduct in `never` is what the service asks of agents;
|
|
873
|
+
no check can show that an agent kept it.
|
|
874
|
+
|
|
875
|
+
It is signed with the key set in `by`, with the terms labels of section
|
|
876
|
+
3.2. A stub that relied on the terms names their fingerprint in `terms`.
|
|
877
|
+
A checker MUST show the fingerprint of the key set that signed a set of
|
|
878
|
+
terms or a refusal: the name in `by` is a label.
|
|
879
|
+
|
|
880
|
+
For such a stub a checker MUST confirm that the terms are earlier in the
|
|
881
|
+
book (`terms-not-found`), that they passed their own check
|
|
882
|
+
(`terms-unusable`), and that `by.keys` are exactly the keys the slip gives
|
|
883
|
+
for the service the stub names (`terms-mismatch`). It then reports
|
|
884
|
+
`outside-terms` as section 8 sets out.
|
|
885
|
+
|
|
886
|
+
How a service publishes its terms, for example at an address on its
|
|
887
|
+
website, is not part of this draft.
|
|
888
|
+
|
|
889
|
+
## 20. The check before acting
|
|
890
|
+
|
|
891
|
+
The software around an agent may ask, before each action, whether the
|
|
892
|
+
action would be outside the slip, and stop the action if so. The answer
|
|
893
|
+
MUST come from the same comparison as section 8, made over the book so
|
|
894
|
+
far. An action MUST be refused beforehand if, with its stub written, a
|
|
895
|
+
checker would report a finding for that stub, or because of it for a
|
|
896
|
+
stub dated after it. One case goes further. An action that would fall in
|
|
897
|
+
a period (a limit "within a period", section 4.1) which ends at a stub
|
|
898
|
+
dated after it, and which already holds more than the limit allows, MUST
|
|
899
|
+
be refused as well (`over-period-limit`): it would add to a period that
|
|
900
|
+
holds too much. A checker reports nothing new for it, because the
|
|
901
|
+
finding stands with the later stub. The answer MUST be that nothing is allowed
|
|
902
|
+
(`record-not-sound`) if the book so far has a problem, if any signature
|
|
903
|
+
in it could not be checked on that device, or if the check was not told
|
|
904
|
+
which issuer keys it trusts. An action dated before the last stub of
|
|
905
|
+
its own chain (the agent's, or the helper's under its pass; section 7)
|
|
906
|
+
is refused (`time-went-backwards`).
|
|
907
|
+
|
|
908
|
+
Where the slip asks for the person's approval, the action is allowed
|
|
909
|
+
only if the signed approval is handed to the check and passes the checks
|
|
910
|
+
of section 17. Where the slip asks for a countersignature, the check
|
|
911
|
+
says so: the action is inside the slip only if the other side then
|
|
912
|
+
countersigns it. Where the action names no service, or a service for
|
|
913
|
+
which the slip gives no keys, no countersignature could be given, and
|
|
914
|
+
the action is not allowed (`countersignature-missing`). An action whose
|
|
915
|
+
record, with its approval and a countersignature, could be longer than a
|
|
916
|
+
line of a book may be (section 9) is not allowed either (`too-large`).
|
|
917
|
+
|
|
918
|
+
This is a help to whoever runs the agent. It is not evidence: nothing in a
|
|
919
|
+
record shows that the check was made.
|
|
920
|
+
|
|
921
|
+
## 21. The Seal and the outside time-stamp
|
|
922
|
+
|
|
923
|
+
Whoever keeps a book (the recorder) seals it from time to time. A seal
|
|
924
|
+
fixes everything before it. An outside time-stamp on the seal states
|
|
925
|
+
when, in words the recorder cannot change afterwards.
|
|
926
|
+
|
|
927
|
+
### 21.1 The seal
|
|
928
|
+
|
|
929
|
+
Content:
|
|
930
|
+
|
|
931
|
+
| Member | Meaning | Form |
|
|
932
|
+
|---|---|---|
|
|
933
|
+
| `type` | The kind of record | `provared.seal.v0` |
|
|
934
|
+
| `id` | Unique number | Section 3.7 |
|
|
935
|
+
| `by` | The recorder | `{"keys": the recorder's three keys, "name": text}` |
|
|
936
|
+
| `size` | How many entries the book held | A whole number, 1 or more |
|
|
937
|
+
| `root` | The top fingerprint of those entries | A fingerprint (section 10) |
|
|
938
|
+
| `previous` | The seal before this one in the book. Absent for the first | That seal's fingerprint |
|
|
939
|
+
| `when` | When it was made, as the recorder states | A time |
|
|
940
|
+
|
|
941
|
+
It is signed with the three keys in `by`, with the seal labels of section
|
|
942
|
+
3.2. A seal is added to the book as its next entry, so the seal at entry
|
|
943
|
+
number n covers the n entries before it, and the next seal covers this
|
|
944
|
+
one too.
|
|
945
|
+
|
|
946
|
+
A checker that holds the whole book MUST confirm all of these, and
|
|
947
|
+
otherwise report a problem:
|
|
948
|
+
|
|
949
|
+
1. All three signatures check against `by.keys` (`signature-invalid`).
|
|
950
|
+
2. `size` is the number of entries before the seal, and `root` is their
|
|
951
|
+
top fingerprint (`seal-mismatch`).
|
|
952
|
+
3. `previous` is the fingerprint of the seal before it in the book, and
|
|
953
|
+
is absent if there is none (`seal-chain-broken`).
|
|
954
|
+
4. `when` is not earlier than the `when` of the seal before it
|
|
955
|
+
(`time-went-backwards`). `when` is also not more than 300 seconds
|
|
956
|
+
earlier than the latest time stated by an entry it covers that passed
|
|
957
|
+
its own check (`time-went-backwards`): one of the two dates is then
|
|
958
|
+
not as it says. There is one exception. Where the seal has a counted
|
|
959
|
+
time-stamp and that entry states a time more than 300 seconds after
|
|
960
|
+
the time the time-stamp counts as stating, the time-stamp settles
|
|
961
|
+
which date is wrong for that entry: the entry is reported instead
|
|
962
|
+
(section 21.3), and it does not count against the seal. Every other
|
|
963
|
+
entry the seal covers is still compared with the seal's `when`. The
|
|
964
|
+
same rule holds for a seal that comes with a Show, against the Show's
|
|
965
|
+
pages (section 11). The times
|
|
966
|
+
an entry states are its own `when` and the `when` of a
|
|
967
|
+
countersignature or an approval on the same line.
|
|
968
|
+
`when` is also not more than 300 seconds earlier than the latest time
|
|
969
|
+
that a counted time-stamp from a service gave any seal before it
|
|
970
|
+
(`time-went-backwards`). A seal covers the lines of the seals before
|
|
971
|
+
it, time-stamps included, so it cannot have been made before a
|
|
972
|
+
time-stamp that one of those lines holds. Among the pages of a Show,
|
|
973
|
+
and for the seal that comes with a Show, the seals before it are
|
|
974
|
+
those among the pages.
|
|
975
|
+
5. If the checker was given the fingerprints of the key sets of the
|
|
976
|
+
recorders it expects, the fingerprint of `by.keys` is one of them
|
|
977
|
+
(`sealer-not-expected`). If it was given none, it MUST say that the
|
|
978
|
+
seal's keys were not compared with keys it trusts.
|
|
979
|
+
|
|
980
|
+
The **fingerprint of a key set** is the SHA-256 hash of the list of keys
|
|
981
|
+
written in the canonical form (section 3.4), in base64url.
|
|
982
|
+
|
|
983
|
+
### 21.2 The time-stamps
|
|
984
|
+
|
|
985
|
+
An entry that holds a seal MAY hold, in `stamps`, 1 to 4 time-stamps,
|
|
986
|
+
none repeated. There are two kinds. A time-stamp from a service, set out
|
|
987
|
+
here, is text. A block time-stamp, set out in section 21.4, is an object.
|
|
988
|
+
|
|
989
|
+
A time-stamp from a service
|
|
990
|
+
is a "TimeStampToken" as RFC 3161, section 2.4.2, sets out, in DER,
|
|
991
|
+
written in base64url, of at most 12,288 bytes. What it stamps (its
|
|
992
|
+
"message imprint") MUST be the seal's fingerprint: the fingerprint method
|
|
993
|
+
SHA-256, and the 32 bytes of the fingerprint. It MUST carry the
|
|
994
|
+
certificate of the service that signed it.
|
|
995
|
+
|
|
996
|
+
A checker reads the time-stamps of a seal only if none of the seal's own
|
|
997
|
+
signatures failed. For each time-stamp it MUST confirm all of these, and
|
|
998
|
+
otherwise report a problem:
|
|
999
|
+
|
|
1000
|
+
1. It is laid out as RFC 3161 and RFC 5652 set out, in strict DER
|
|
1001
|
+
(`stamp-bad-data`). Every part is read, including parts the checker
|
|
1002
|
+
does not otherwise use: a whole number or an object identifier that is
|
|
1003
|
+
not in its shortest form, a part that does not fill what holds it, or a
|
|
1004
|
+
part the standards do not allow in that place, is refused. The signed
|
|
1005
|
+
data is of version 3, with exactly one signer.
|
|
1006
|
+
2. What it stamps is this seal's fingerprint (`stamp-wrong-data`).
|
|
1007
|
+
3. Its signed attributes name a time-stamp statement, hold the
|
|
1008
|
+
fingerprint of the statement, and name the certificate that signed, by
|
|
1009
|
+
the "signing certificate" attribute that RFC 3161, section 2.4.2,
|
|
1010
|
+
requires (in the form of RFC 5035, or the older form of RFC 2634). The
|
|
1011
|
+
time-stamp carries that certificate, and the signature over the
|
|
1012
|
+
attributes fits its public key (`stamp-invalid`). A certificate with
|
|
1013
|
+
the same key and other contents is another certificate.
|
|
1014
|
+
4. The fingerprint method used to check the signature is the one the
|
|
1015
|
+
signer names (RFC 5652, section 5.4): SHA-256, SHA-384 or SHA-512. A
|
|
1016
|
+
signing method that names another one is refused (`stamp-invalid`).
|
|
1017
|
+
The signing methods are RSA (PKCS #1 version 1.5; keys of 2,048 to
|
|
1018
|
+
8,192 bits, with a public number of at most 32 bits), ECDSA on the
|
|
1019
|
+
curves P-256 and P-384, and Ed25519.
|
|
1020
|
+
5. The time it states lies within the time that certificate is in force
|
|
1021
|
+
(`stamp-invalid`).
|
|
1022
|
+
6. It does not say that its time is exact to no better than more than 300
|
|
1023
|
+
seconds, and it carries no extension marked as one that must be
|
|
1024
|
+
understood (`stamp-invalid`).
|
|
1025
|
+
7. If it is counted (below): the seal's `when` is not more than 300
|
|
1026
|
+
seconds after the time it states (`dated-after-stamp`). A block
|
|
1027
|
+
time-stamp that section 21.3 sets aside is the one exception.
|
|
1028
|
+
|
|
1029
|
+
The time a time-stamp states is taken to the second, rounded down.
|
|
1030
|
+
|
|
1031
|
+
**Whom to trust is the checker's choice.** The person checking gives the
|
|
1032
|
+
fingerprint (SHA-256, in base64url) of the certificate of each time-stamp
|
|
1033
|
+
service they trust. A time-stamp counts only if the certificate it names
|
|
1034
|
+
is one of those, and only if all three signatures of the seal were
|
|
1035
|
+
checked on that device. A sound time-stamp from any other service MUST
|
|
1036
|
+
be shown as not counted, with the fingerprint of its certificate, and
|
|
1037
|
+
MUST NOT be treated as a time: it is compared with nothing. This format
|
|
1038
|
+
names no service.
|
|
1039
|
+
|
|
1040
|
+
A checker follows no chain of certificates and asks no outside party. It
|
|
1041
|
+
does not read what a certificate says its key may be used for: the person
|
|
1042
|
+
checking decides that by naming the certificate.
|
|
1043
|
+
|
|
1044
|
+
### 21.3 What a time-stamp fixes
|
|
1045
|
+
|
|
1046
|
+
Every counted time-stamp of a seal is taken, of either kind, and the
|
|
1047
|
+
earliest time that any of them states is the time by which every entry
|
|
1048
|
+
before that seal existed. (A block time-stamp states its block's time and
|
|
1049
|
+
7,200 seconds: section 21.4.) Two cases are set apart. In both, a block
|
|
1050
|
+
states a time far behind the true time, and a service settles it.
|
|
1051
|
+
|
|
1052
|
+
1. Where a seal has a counted time-stamp from a service, a counted block
|
|
1053
|
+
time-stamp that states a time more than 300 seconds before the seal's
|
|
1054
|
+
own `when`, even with its 7,200 seconds, is set aside: it gives no
|
|
1055
|
+
time, and rule 7 of section 21.2 is not applied to it. A checker MUST
|
|
1056
|
+
then say that the two do not agree.
|
|
1057
|
+
2. A counted block time-stamp that states a time, even with its 7,200
|
|
1058
|
+
seconds, more than 300 seconds before the latest time that a counted
|
|
1059
|
+
time-stamp from a service gave any seal before this one is set aside
|
|
1060
|
+
in the same way, whether or not a service's time-stamp stands beside
|
|
1061
|
+
it. This seal covers that seal's line, time-stamp included, so it
|
|
1062
|
+
cannot have existed by then. A checker MUST say that the block
|
|
1063
|
+
time-stamp was set aside. Among the pages of a Show, and for the seal
|
|
1064
|
+
that comes with a Show, the seals before it are those among the
|
|
1065
|
+
pages.
|
|
1066
|
+
|
|
1067
|
+
A time-stamp is counted only if all
|
|
1068
|
+
three signatures of its seal were checked on that device; where they
|
|
1069
|
+
were not, a checker MUST say that the time-stamp was not counted, and
|
|
1070
|
+
MUST NOT report any date against it. More exactly, it shows
|
|
1071
|
+
that the content of the seal existed then: the time-stamp is made over
|
|
1072
|
+
the seal's fingerprint, which covers its content and not its signatures.
|
|
1073
|
+
|
|
1074
|
+
The time that counts for an entry is the earliest that the counted
|
|
1075
|
+
time-stamps of any seal after it state: every seal after an entry covers
|
|
1076
|
+
it. (In section 22, only the seals before the cancellation are taken.) A
|
|
1077
|
+
checker
|
|
1078
|
+
MUST report an entry that states a time (its own `when`, or the `when` of
|
|
1079
|
+
a countersignature or an approval on the same line) more than 300 seconds
|
|
1080
|
+
later than that (`dated-after-stamp`). The same holds for each page of a
|
|
1081
|
+
Show that comes with a seal (section 11).
|
|
1082
|
+
|
|
1083
|
+
The earliest time that a counted time-stamp from a service gives a seal
|
|
1084
|
+
MUST NOT be more than 300 seconds earlier than the latest such time that
|
|
1085
|
+
a service gave any seal before it (`time-went-backwards`). So the times
|
|
1086
|
+
cannot step backwards a little at a time. A block time-stamp is never
|
|
1087
|
+
reported under this rule: it is made hours after its seal, and one that
|
|
1088
|
+
states an earlier time is set aside (the second case above).
|
|
1089
|
+
|
|
1090
|
+
A checker that shows an entry's times MUST keep two apart: the time by
|
|
1091
|
+
which a seal after the entry shows that it existed, and the time that a
|
|
1092
|
+
seal's or a cancellation's own counted time-stamps give it. A
|
|
1093
|
+
cancellation does not count from the time of a seal after it (section
|
|
1094
|
+
22). A checker MUST NOT show a time of the second kind for a seal or a
|
|
1095
|
+
cancellation that did not pass its check.
|
|
1096
|
+
|
|
1097
|
+
A seal shown as a single page of a Show cannot be compared with the
|
|
1098
|
+
entries before it. A checker MUST confirm that its `size` is the page's
|
|
1099
|
+
own place in the book (`seal-mismatch`), MUST say that it could not be
|
|
1100
|
+
compared, and MUST NOT credit its time-stamp to any other page.
|
|
1101
|
+
|
|
1102
|
+
Its dates are still held against the other pages. Each page is shown to
|
|
1103
|
+
be in the book at its place, so where the dates do not fit, the whole
|
|
1104
|
+
book would fail its check one way or another. A checker MUST report:
|
|
1105
|
+
|
|
1106
|
+
- the seal, if a page that comes before it in the book states a time
|
|
1107
|
+
more than 300 seconds after the seal's counted time-stamp
|
|
1108
|
+
(`dated-after-stamp`). The finding is given for the seal and not for
|
|
1109
|
+
that page: either the page's date is not as it says, or the seal does
|
|
1110
|
+
not fit the entries before it, and single pages cannot show which;
|
|
1111
|
+
- the seal, if its `when` is more than 300 seconds earlier than a time
|
|
1112
|
+
that a page before it states, where that page is not one of the first
|
|
1113
|
+
case (`time-went-backwards`);
|
|
1114
|
+
- a seal, among the pages or come with the Show, whose `when` is earlier
|
|
1115
|
+
than that of a seal among the pages that comes before it in the book,
|
|
1116
|
+
or whose counted time-stamp from a service is more than 300 seconds
|
|
1117
|
+
earlier than such a seal's (`time-went-backwards`);
|
|
1118
|
+
- a seal, among the pages or come with the Show, that does not fit the
|
|
1119
|
+
chain of seals as far as the pages show it (`seal-chain-broken`): it
|
|
1120
|
+
has no `previous` though a seal among the pages comes before it; or
|
|
1121
|
+
its `previous` names a seal among the pages that does not come before
|
|
1122
|
+
it, or that has another seal among the pages between the two.
|
|
1123
|
+
|
|
1124
|
+
A checker MUST say how far the last counted time-stamp reaches, and that
|
|
1125
|
+
entries after it are not time-stamped.
|
|
1126
|
+
|
|
1127
|
+
What a seal and a time-stamp do not fix: the last seal of a book, with
|
|
1128
|
+
everything after it, can be removed, and what is left still checks. Only
|
|
1129
|
+
a copy of that seal, or of its top fingerprint and number of entries,
|
|
1130
|
+
held by someone else shows it. And a time-stamp service signs with a
|
|
1131
|
+
method of today's kind.
|
|
1132
|
+
|
|
1133
|
+
### 21.4 A block time-stamp
|
|
1134
|
+
|
|
1135
|
+
A second kind of time-stamp rests on no signature. It is a proof that
|
|
1136
|
+
the seal's fingerprint was written into a block of a public blockchain.
|
|
1137
|
+
The chain is used purely as a clock: no coin, no wallet, no account and
|
|
1138
|
+
no payment is involved in making such a proof or in checking one.
|
|
1139
|
+
|
|
1140
|
+
In `stamps` a block time-stamp is the object `{"block": header, "proof":
|
|
1141
|
+
proof}`, each in base64url:
|
|
1142
|
+
|
|
1143
|
+
- `proof` is a proof file of the open format OpenTimestamps, version 1,
|
|
1144
|
+
of at most 12,288 bytes;
|
|
1145
|
+
- `block` is the 80-byte header of a block of the Bitcoin blockchain;
|
|
1146
|
+
one of any other length is refused (`stamp-bad-data`).
|
|
1147
|
+
|
|
1148
|
+
A proof file holds steps that lead from a fingerprint to a value, and
|
|
1149
|
+
statements about values. A checker MUST confirm all of these, and
|
|
1150
|
+
otherwise report a problem:
|
|
1151
|
+
|
|
1152
|
+
1. The file begins with these 31 bytes, in hex: `00 4f 70 65 6e 54 69 6d
|
|
1153
|
+
65 73 74 61 6d 70 73 00 00 50 72 6f 6f 66 00 bf 89 e2 e8 84 e8 92
|
|
1154
|
+
94`; then the byte `01` (the version); then the byte `08` (SHA-256);
|
|
1155
|
+
then 32 bytes, the fingerprint that was stamped (`stamp-bad-data`).
|
|
1156
|
+
2. Then comes everything that follows from that value. Each thing is a
|
|
1157
|
+
statement or a step, and each but the last is preceded by the byte
|
|
1158
|
+
`ff` (`stamp-bad-data`):
|
|
1159
|
+
- A **statement** is the byte `00`, 8 bytes that say its kind, a
|
|
1160
|
+
length, and that many bytes (at most 8,192). The kind `05 88 96 0d
|
|
1161
|
+
73 d7 19 01` says "this value is the Merkle root of the block with
|
|
1162
|
+
this number"; its bytes are the block's number and nothing more. A
|
|
1163
|
+
statement of any other kind is passed over.
|
|
1164
|
+
- A **step** makes a new value, and is followed by everything that
|
|
1165
|
+
follows from the new value. The byte `08`: the SHA-256 of the
|
|
1166
|
+
value. The byte `f0`, a length and that many bytes: the value with
|
|
1167
|
+
those bytes joined after it. The byte `f1`, likewise: joined before
|
|
1168
|
+
it. A step joins 1 to 4,096 bytes, and no value is longer than 4,096
|
|
1169
|
+
bytes. Any other step is refused. (The format also has steps for
|
|
1170
|
+
SHA-1, RIPEMD-160 and Keccak-256, and two it no longer uses. Proofs
|
|
1171
|
+
made today do not use them.)
|
|
1172
|
+
- No more than 255 steps follow one another, as the format's own reader allows.
|
|
1173
|
+
3. A number (a length, a block's number) is written seven bits to a
|
|
1174
|
+
byte, lowest first, with the top bit of a byte saying that another
|
|
1175
|
+
follows; in its shortest form only, and in at most 5 bytes
|
|
1176
|
+
(`stamp-bad-data`).
|
|
1177
|
+
4. Nothing follows the end (`stamp-bad-data`).
|
|
1178
|
+
5. The fingerprint stamped is this seal's fingerprint
|
|
1179
|
+
(`stamp-wrong-data`).
|
|
1180
|
+
6. A statement about a block stands at a value of 32 bytes that equals
|
|
1181
|
+
bytes 36 to 67 of the header in `block`, its Merkle root
|
|
1182
|
+
(`stamp-invalid`).
|
|
1183
|
+
|
|
1184
|
+
**Whom to trust is the checker's choice.** The fingerprint of a block is
|
|
1185
|
+
SHA-256 taken twice over its 80-byte header, with the bytes then put in
|
|
1186
|
+
reverse order, in hex: 64 characters, as it is written wherever blocks
|
|
1187
|
+
are listed. The person checking gives the fingerprints of the blocks
|
|
1188
|
+
they trust to be part of the chain, at most 100,000. A block time-stamp counts only if it
|
|
1189
|
+
leads to one of those. One that leads to any other block MUST be shown,
|
|
1190
|
+
with the block's fingerprint, and MUST NOT be counted. The block's
|
|
1191
|
+
number in the proof is only what the proof says: nothing checks it, and
|
|
1192
|
+
a checker that shows it MUST say so.
|
|
1193
|
+
|
|
1194
|
+
**Finding which blocks to trust.** A checker MAY take the blocks it
|
|
1195
|
+
trusts from a chain of block headers that it checks itself, from the
|
|
1196
|
+
chain's first block, by the rules every Bitcoin node applies to headers
|
|
1197
|
+
(each names the block before it; its double SHA-256 meets the target its
|
|
1198
|
+
`bits` state; that target follows the difficulty rule; its time is later
|
|
1199
|
+
than the middle of the eleven before it, and not more than two hours
|
|
1200
|
+
ahead of the checker's clock; its version is no lower than the upgrades
|
|
1201
|
+
of 2013 and 2015 ask from their blocks on). Such a checker MUST also
|
|
1202
|
+
require that the chain hold blocks known to be part of it, at their
|
|
1203
|
+
places, and reach the last of them; MUST refuse, after the last of them,
|
|
1204
|
+
a target more than four times easier than that block's; and MUST count a
|
|
1205
|
+
block only with at least six blocks after it. This library's checker does so with `--headers`; the known blocks are
|
|
1206
|
+
listed in `src/headers.js`. A chain file holds the 80-byte headers one
|
|
1207
|
+
after another, from the chain's first block. Nothing in a record
|
|
1208
|
+
changes.
|
|
1209
|
+
|
|
1210
|
+
**The time.** The time a block states is bytes 68 to 71 of its header: a
|
|
1211
|
+
whole number of seconds since the start of 1970, lowest byte first. It
|
|
1212
|
+
is set by whoever made the block, and is right only to within about two
|
|
1213
|
+
hours. Which way that looseness is taken depends on what is asked, so
|
|
1214
|
+
that it never works in favour of whoever is being checked:
|
|
1215
|
+
|
|
1216
|
+
- For a **seal**, a counted block time-stamp is taken to state that the
|
|
1217
|
+
seal existed by the block's stated time **and 7,200 seconds**. That is
|
|
1218
|
+
the time used in section 21.3, and for a stub in section 22.
|
|
1219
|
+
- For a **cancellation** (section 22), which may carry block time-stamps
|
|
1220
|
+
in the same way, over the cancellation's fingerprint, a block
|
|
1221
|
+
time-stamp gives the block's stated time **less 7,200 seconds**: the
|
|
1222
|
+
earliest the proof could have been made. A later time would excuse
|
|
1223
|
+
stubs made after the person cancelled. There is one bound. The time
|
|
1224
|
+
given is never earlier than the cancellation's own `when`. By the
|
|
1225
|
+
person's own signed word the cancellation was not made before its
|
|
1226
|
+
`when`, so a stub shown to have existed by then was made before the
|
|
1227
|
+
person cancelled. So a cancellation cannot be moved back in time by
|
|
1228
|
+
having it put into a block before the date it gives. Where the block's
|
|
1229
|
+
stated time and 7,200 seconds is more than 300 seconds before the
|
|
1230
|
+
cancellation's `when`, the two do not agree. With no counted
|
|
1231
|
+
time-stamp from a service beside it, the cancellation is dated after
|
|
1232
|
+
its time-stamp and does not pass (`dated-after-stamp`). With one, the
|
|
1233
|
+
service settles it, and a checker MUST say that the two do not agree.
|
|
1234
|
+
|
|
1235
|
+
A checker MUST show the time the block states, say that it is right only
|
|
1236
|
+
to within two hours, and for a cancellation show the time T it used.
|
|
1237
|
+
|
|
1238
|
+
A block that states a time more than two hours behind the true time,
|
|
1239
|
+
which the chain's rules allow in rare cases, would make an honest seal
|
|
1240
|
+
or entry read as dated after its time-stamp. A counted time-stamp from a
|
|
1241
|
+
service beside it settles such a case: the service's time is then the
|
|
1242
|
+
one used. A checker MUST then say that the block time-stamp states a
|
|
1243
|
+
time more than two hours before the seal's own date: the other reading
|
|
1244
|
+
is that the seal existed before the date it gives. A counted time-stamp
|
|
1245
|
+
from a service on a seal earlier in the book settles it too (section
|
|
1246
|
+
21.3, the second case): without that, such a block would show the
|
|
1247
|
+
entries of a later seal to have existed earlier than they did.
|
|
1248
|
+
|
|
1249
|
+
What a block time-stamp does not fix: that the header is that of a real
|
|
1250
|
+
block. The person who names a block vouches for that, having compared
|
|
1251
|
+
its fingerprint with sources they trust. A proof is complete only one to
|
|
1252
|
+
several hours after it is asked for, so it is an addition to a
|
|
1253
|
+
time-stamp from a service, not a replacement.
|
|
1254
|
+
|
|
1255
|
+
## 22. Cancelling a slip
|
|
1256
|
+
|
|
1257
|
+
The person who signed a slip can end it early, with the same passkey.
|
|
1258
|
+
|
|
1259
|
+
Content: `{"id": unique number, "slip": the slip's fingerprint, "type":
|
|
1260
|
+
"provared.cancellation.v0", "when": a time}`. It is signed as a slip is
|
|
1261
|
+
(sections 4.2 and 4.3), with the cancellation label of section 3.2, and
|
|
1262
|
+
checked against the `issuer` of the slip it names
|
|
1263
|
+
(`cancellation-invalid`). The slip MUST be earlier in the book
|
|
1264
|
+
(`slip-missing`).
|
|
1265
|
+
|
|
1266
|
+
The entry that holds a cancellation MAY hold `stamps`: time-stamps over
|
|
1267
|
+
the cancellation's fingerprint, checked as section 21.2 sets out. The
|
|
1268
|
+
person can have these made at once, without waiting for the recorder.
|
|
1269
|
+
A time-stamp is counted only if the passkey signature of the
|
|
1270
|
+
cancellation, and of its slip, was checked on that device; where it was
|
|
1271
|
+
not, a checker MUST say that the time-stamp was not counted, and MUST
|
|
1272
|
+
NOT report any date against it, as for a seal (section 21.3).
|
|
1273
|
+
|
|
1274
|
+
What a checker reports, as `after-cancellation` (section 8):
|
|
1275
|
+
|
|
1276
|
+
1. Every stub under the slip that comes after the cancellation in the
|
|
1277
|
+
book.
|
|
1278
|
+
2. Where the cancellation has a counted time-stamp, at a time T: every
|
|
1279
|
+
stub under the slip that comes before the cancellation in the book,
|
|
1280
|
+
unless a counted time-stamp, on a seal that is before the cancellation
|
|
1281
|
+
in the book and covers the stub, states a time not more than 300
|
|
1282
|
+
seconds after T.
|
|
1283
|
+
|
|
1284
|
+
The second rule is strict on purpose. The time an agent writes into a
|
|
1285
|
+
stub is its own word, so an agent could otherwise escape a cancellation
|
|
1286
|
+
by writing an earlier time. A stub made honestly just before a
|
|
1287
|
+
cancellation, and not yet sealed, is reported as "not shown to have
|
|
1288
|
+
existed before the slip was cancelled", which is exactly what the record
|
|
1289
|
+
can and cannot show. A recorder that seals often keeps this rare.
|
|
1290
|
+
|
|
1291
|
+
Every cancellation of a slip that passes its check counts. The first
|
|
1292
|
+
rule is applied from the first of them in the book. The second rule is
|
|
1293
|
+
applied with the earliest time T that a counted time-stamp gives any of
|
|
1294
|
+
them, to the stubs that come before that cancellation in the book. So
|
|
1295
|
+
the order in which whoever keeps the book places two cancellations
|
|
1296
|
+
changes nothing.
|
|
1297
|
+
|
|
1298
|
+
**The time T.** Every counted time-stamp beside a cancellation is taken,
|
|
1299
|
+
of either kind, and T is the earliest time that any of them gives. A
|
|
1300
|
+
time-stamp from a service gives the time it states. A block time-stamp
|
|
1301
|
+
gives the time that section 21.4 sets out. So a later time-stamp put
|
|
1302
|
+
beside an earlier one changes nothing. (Section 21.3 sets out which
|
|
1303
|
+
time counts for a seal.)
|
|
1304
|
+
|
|
1305
|
+
Single pages of a Show apply the first rule only, by the place each page
|
|
1306
|
+
has in the book: single pages cannot show which seal covered a stub. A
|
|
1307
|
+
checker MUST say so where a cancellation among the pages has a counted
|
|
1308
|
+
time-stamp.
|
|
1309
|
+
|
|
1310
|
+
The time-stamps stand beside the cancellation, not inside what the
|
|
1311
|
+
passkey signed. Whoever keeps the book can therefore put a later
|
|
1312
|
+
time-stamp in the place of an earlier one, and no check can show that.
|
|
1313
|
+
Where the time T is more than 300 seconds after the cancellation's own
|
|
1314
|
+
`when`, a checker MUST point it out. (A later time-stamp beside a prompt
|
|
1315
|
+
one leaves no such gap, and changes nothing.) The person SHOULD keep
|
|
1316
|
+
their own copy of the cancellation, with its time-stamp.
|
|
1317
|
+
|
|
1318
|
+
A cancellation shows when the person signed it and had it time-stamped.
|
|
1319
|
+
It does not show that the agent, or whoever keeps the book, was told. A
|
|
1320
|
+
person can keep a cancellation back and hand it over later: every stub
|
|
1321
|
+
made in between is then reported, though the check before acting allowed
|
|
1322
|
+
each. Where a checker is handed a copy that the book does not hold, it
|
|
1323
|
+
cannot show whether the book's keeper left it out or was never given
|
|
1324
|
+
it, and MUST say so. An acknowledgement from the agent's side (section
|
|
1325
|
+
26), handed over with the copy, shows that it was given it, and when.
|
|
1326
|
+
|
|
1327
|
+
**The person's own copy.** A checker MAY be handed, beside a book, up to
|
|
1328
|
+
16 cancellations that the person kept, each as the entry it would be in
|
|
1329
|
+
a book: `{"cancellation": cancellation record}`, with or without
|
|
1330
|
+
`"stamps"`, and with or without `"acknowledgements"` (section 26). Each
|
|
1331
|
+
is checked as a cancellation in the book is: against the
|
|
1332
|
+
`issuer` of the slip it names, which MUST be in the book
|
|
1333
|
+
(`slip-missing`, `cancellation-invalid`), and its time-stamps as section
|
|
1334
|
+
21.2 sets out. A copy that does not pass is a problem with the check as
|
|
1335
|
+
a whole: it is never set aside silently. The same cancellation MUST NOT
|
|
1336
|
+
be handed over twice (`bad-field`). For a copy that passes:
|
|
1337
|
+
|
|
1338
|
+
1. where a counted time-stamp gives it a time T, every stub under the
|
|
1339
|
+
slip, wherever it stands in the book, is reported as
|
|
1340
|
+
`after-cancellation`, unless a counted time-stamp on a seal that
|
|
1341
|
+
covers the stub states a time not more than 300 seconds after T;
|
|
1342
|
+
2. the check before acting (section 20) allows nothing under the slip;
|
|
1343
|
+
3. a checker MUST say whether the book holds the same cancellation.
|
|
1344
|
+
|
|
1345
|
+
So a cancellation counts even where whoever keeps the book left it out,
|
|
1346
|
+
and the person's own time-stamp counts even where the book holds the
|
|
1347
|
+
cancellation with a later one. A copy with no counted time-stamp cannot
|
|
1348
|
+
be placed in time, and no stub is reported because of it. Single pages
|
|
1349
|
+
of a Show cannot use a copy, and a checker MUST say so.
|
|
1350
|
+
|
|
1351
|
+
## 23. Vouching for a name, and withdrawing
|
|
1352
|
+
|
|
1353
|
+
A name in a record is a label. A vouching record lets an organisation
|
|
1354
|
+
stand behind one: it states that a key belongs to a name.
|
|
1355
|
+
|
|
1356
|
+
Content:
|
|
1357
|
+
|
|
1358
|
+
| Member | Meaning | Form |
|
|
1359
|
+
|---|---|---|
|
|
1360
|
+
| `type` | The kind of record | `provared.vouching.v0` |
|
|
1361
|
+
| `id` | Unique number | Section 3.7 |
|
|
1362
|
+
| `by` | The organisation that vouches | `{"keys": key set, "name": text}` |
|
|
1363
|
+
| `for` | Whom it vouches for | One of the four forms below |
|
|
1364
|
+
| `validFrom`, `validUntil` | When the statement holds | Times; the second later than the first |
|
|
1365
|
+
| `when` | When it was made | A time |
|
|
1366
|
+
|
|
1367
|
+
| `for` | Form |
|
|
1368
|
+
|---|---|
|
|
1369
|
+
| A person | `{"key": the passkey's public key, "kind": "person", "name": text}` |
|
|
1370
|
+
| An agent | `{"keys": key set, "kind": "agent", "name": text}` |
|
|
1371
|
+
| A service | `{"keys": key set, "kind": "service", "name": text}` |
|
|
1372
|
+
| A recorder | `{"keys": the three keys, "kind": "recorder", "name": text}` |
|
|
1373
|
+
|
|
1374
|
+
It is signed with the key set in `by`, with the vouching labels of
|
|
1375
|
+
section 3.2.
|
|
1376
|
+
|
|
1377
|
+
**What it vouches for.** A vouching record stands behind a name in a
|
|
1378
|
+
later record only if all of these hold: it is earlier in the book; it
|
|
1379
|
+
passed its own check; it has not been withdrawn earlier in the book; its
|
|
1380
|
+
`for.kind` fits the place of the name (`person` for the issuer of a
|
|
1381
|
+
slip; `agent` for its agent, and for the helper agent a pass names in
|
|
1382
|
+
`to`; `service` for one of its services; `recorder` for the recorder of
|
|
1383
|
+
a seal); its key or keys are exactly the key or keys that record gives;
|
|
1384
|
+
its `for.name` is exactly that name; and it is in force for the whole
|
|
1385
|
+
time of that record. For a slip or a pass that means: its `validFrom` is
|
|
1386
|
+
not later than the record's `validFrom`, and its `validUntil` is not
|
|
1387
|
+
earlier than the record's `validUntil`. For a seal: the seal's `when`,
|
|
1388
|
+
and the time of a counted time-stamp on the seal where there is one, are
|
|
1389
|
+
not before its `validFrom` and are before its `validUntil`.
|
|
1390
|
+
|
|
1391
|
+
A covered name (section 24) that was not revealed is vouched for by
|
|
1392
|
+
nobody. Where several vouching records stand behind one name, a checker
|
|
1393
|
+
shows one that counts, if there is one.
|
|
1394
|
+
|
|
1395
|
+
**Whom to trust is the checker's choice.** The person checking gives the
|
|
1396
|
+
fingerprint of the key set (section 21.1) of each organisation whose
|
|
1397
|
+
vouching they trust. Only a vouching record signed by one of those
|
|
1398
|
+
counts. A checker MUST show a name as vouched for only then, with the
|
|
1399
|
+
fingerprint of the organisation's key set. A vouching record from any
|
|
1400
|
+
other organisation MUST be shown as not counted.
|
|
1401
|
+
|
|
1402
|
+
**Withdrawing.** Content: `{"id": unique number, "type":
|
|
1403
|
+
"provared.withdrawal.v0", "vouching": the vouching record's fingerprint,
|
|
1404
|
+
"when": a time}`. It is signed with the key set of the organisation that
|
|
1405
|
+
made the vouching record, with the withdrawal labels: only that
|
|
1406
|
+
organisation can withdraw. The vouching record MUST be earlier in the
|
|
1407
|
+
book (`vouching-missing`). From the withdrawal's place in the book
|
|
1408
|
+
onwards, the vouching record stands behind nothing.
|
|
1409
|
+
|
|
1410
|
+
What a vouching record does not show: that the organisation checked well,
|
|
1411
|
+
or that the organisation is who its own name says. The trust ends at keys
|
|
1412
|
+
the person checking chose.
|
|
1413
|
+
|
|
1414
|
+
## 24. Covered fields
|
|
1415
|
+
|
|
1416
|
+
A slip can be shown with its names and its purpose hidden, while
|
|
1417
|
+
everything about it still checks. The method is that of the standard
|
|
1418
|
+
"Selective Disclosure for JSON Web Tokens" (RFC 9901): the same
|
|
1419
|
+
disclosures, the same fingerprints, the same checking steps. A slip uses
|
|
1420
|
+
less than the standard allows, as this section sets out, so that no two
|
|
1421
|
+
readers can be shown slips that differ in anything a checker compares.
|
|
1422
|
+
|
|
1423
|
+
**What may be covered.** In a slip: `issuer.name`, `agent.name`, the
|
|
1424
|
+
`name` of each service in `with`, and `purpose`. Nothing else, and
|
|
1425
|
+
nothing in any other kind of record. An item of a list MUST NOT be
|
|
1426
|
+
covered anywhere in a slip (the form `{"...": fingerprint}` of RFC 9901,
|
|
1427
|
+
section 4.2.4.2; `cover-invalid`): a covered limit, condition, action,
|
|
1428
|
+
service or key would give one reader a different slip from another.
|
|
1429
|
+
|
|
1430
|
+
**How a field is covered** (RFC 9901, section 4.2). A disclosure is the
|
|
1431
|
+
JSON list `[salt, name, value]`, written in base64url, where the salt is
|
|
1432
|
+
text holding at least 128 random bits. Its fingerprint is the SHA-256
|
|
1433
|
+
hash of the characters of that base64url text, in base64url. The field
|
|
1434
|
+
is taken out of its object, and the fingerprint is added to a list named
|
|
1435
|
+
`_sd` in the same object. Every member of such a list MUST be a SHA-256 fingerprint in base64url,
|
|
1436
|
+
43 characters (`cover-invalid`). In a slip, each such list holds exactly
|
|
1437
|
+
one fingerprint: that of the one field that may be covered in that
|
|
1438
|
+
object. A decoy fingerprint, which the
|
|
1439
|
+
standard allows, is not accepted, and neither is a list that stands
|
|
1440
|
+
beside the field it would stand in for (`bad-field`). So a field is
|
|
1441
|
+
absent only where its fingerprint stands in its place.
|
|
1442
|
+
A slip's content holds `"_sd_alg": "sha-256"` at the top where it covers
|
|
1443
|
+
anything, and not otherwise (`bad-field`); no other fingerprint method
|
|
1444
|
+
is accepted.
|
|
1445
|
+
|
|
1446
|
+
The person's passkey signs the content in this covered form. The
|
|
1447
|
+
fingerprint of the slip, the chain and the tree are worked out from the
|
|
1448
|
+
covered form, so they are the same for every reader.
|
|
1449
|
+
|
|
1450
|
+
**Where disclosures are kept.** Beside the record, not inside a line of
|
|
1451
|
+
the book: a line is a leaf of the tree, and must be the same for every
|
|
1452
|
+
reader. A page of a Show MAY hold `"disclosures"`, a list of 1 to 64
|
|
1453
|
+
disclosures for the slip on that page; a page that is not a slip MUST
|
|
1454
|
+
NOT hold it (`cover-invalid`). A checker MAY also be handed disclosures
|
|
1455
|
+
by the fingerprint of the slip they belong to; where no such slip is
|
|
1456
|
+
among the entries, they are not used and a checker MUST say so. Where a
|
|
1457
|
+
page holds disclosures and others are handed over for the same slip, all
|
|
1458
|
+
are used together, and one given both ways counts once.
|
|
1459
|
+
|
|
1460
|
+
**Checking** (RFC 9901, section 7.1, steps 3 to 5). A checker MUST:
|
|
1461
|
+
|
|
1462
|
+
1. work out the fingerprint of each disclosure handed over;
|
|
1463
|
+
2. for each fingerprint in an `_sd` list that matches a disclosure, put
|
|
1464
|
+
the named field back in that object;
|
|
1465
|
+
3. refuse (`cover-invalid`) if a fingerprint appears twice in
|
|
1466
|
+
the content; if a disclosure matches nothing; if a disclosure is
|
|
1467
|
+
handed over twice; if a disclosure is not a list of a salt, a name and
|
|
1468
|
+
a value; if its name is `_sd`, `...` or `_sd_alg`; if its name is
|
|
1469
|
+
already a field of that object; if an item of a list is covered; or if
|
|
1470
|
+
a disclosure, once its base64url is decoded, is not JSON in the
|
|
1471
|
+
canonical form of section 3.4;
|
|
1472
|
+
4. refuse the record (`bad-field`) if an `_sd` list stands anywhere other
|
|
1473
|
+
than in the slip itself, its `issuer`, its `agent` or one of its
|
|
1474
|
+
services; if such a list does not hold exactly one fingerprint; if the
|
|
1475
|
+
field it stands in for is there as well; if a revealed field is not
|
|
1476
|
+
the one that may be covered there; or if `_sd_alg` is absent where a
|
|
1477
|
+
field is covered, or present where none is;
|
|
1478
|
+
5. then check the slip as section 4 sets out, with every revealed field
|
|
1479
|
+
in place. A field that may be covered is absent exactly where its
|
|
1480
|
+
fingerprint stands in its place and no disclosure for it was handed
|
|
1481
|
+
over.
|
|
1482
|
+
|
|
1483
|
+
**What a slip is does not depend on what is handed over with it.** Where
|
|
1484
|
+
a slip fails step 3, 4 or 5 with the disclosures handed over, a checker
|
|
1485
|
+
MUST check it again with no disclosure. If it then passes, the fault
|
|
1486
|
+
lies in the disclosures: they are not used, every field they would have
|
|
1487
|
+
revealed stays covered, the slip and the stubs under it are checked as
|
|
1488
|
+
they would be with no disclosure, and the checker MUST report the
|
|
1489
|
+
problem as one with what was handed over, so that the check as a whole
|
|
1490
|
+
is not a pass. Otherwise the signer of a slip could make it sound for a
|
|
1491
|
+
reader with no disclosure and unsound for a reader with one. Disclosures
|
|
1492
|
+
handed over in any other form than `{fingerprint of a slip:
|
|
1493
|
+
[disclosures]}` are refused (`bad-field`).
|
|
1494
|
+
|
|
1495
|
+
A fingerprint in an `_sd` list with no disclosure is left alone: the
|
|
1496
|
+
field is covered. A checker MUST show that fields are covered, and how
|
|
1497
|
+
many, and MUST NOT show a covered field's place as empty.
|
|
1498
|
+
|
|
1499
|
+
The standard allows any JSON in a disclosure. A slip's disclosures are
|
|
1500
|
+
narrower, as step 3 says: loose JSON (stray spaces, a repeated name, an
|
|
1501
|
+
unusual escape) could be read in two ways by two checkers.
|
|
1502
|
+
|
|
1503
|
+
A checker MUST treat every member name as a plain name. A member named
|
|
1504
|
+
`__proto__`, for example, is a member like any other: in a slip it is
|
|
1505
|
+
refused as unknown (`bad-field`), and nothing is ever taken from it.
|
|
1506
|
+
|
|
1507
|
+
The standard's key binding (its section 4.3) is not used: a Provared
|
|
1508
|
+
record is not presented by a holder who must prove possession of a key.
|
|
1509
|
+
|
|
1510
|
+
## 25. Passing a slip on to a helper agent
|
|
1511
|
+
|
|
1512
|
+
An agent may hand part of its permission to a helper agent, if the slip
|
|
1513
|
+
allows it. The slip's `passes` says how many times in a row: 1 means the
|
|
1514
|
+
slip's agent may pass on to a helper; 2 means that helper may pass on
|
|
1515
|
+
once more; and so on, up to 10. A slip with no `passes` may not be passed on.
|
|
1516
|
+
|
|
1517
|
+
Content of a pass:
|
|
1518
|
+
|
|
1519
|
+
| Member | Meaning | Form |
|
|
1520
|
+
|---|---|---|
|
|
1521
|
+
| `type` | The kind of record | `provared.pass.v0` |
|
|
1522
|
+
| `id` | Unique number | Section 3.7 |
|
|
1523
|
+
| `slip` | The slip | The slip's fingerprint |
|
|
1524
|
+
| `from` | The pass its writer itself acts under. Absent when the writer is the slip's own agent | That pass's fingerprint |
|
|
1525
|
+
| `to` | The helper agent | `{"keys": key set, "name": text}` |
|
|
1526
|
+
| `actions` | What the helper may do | A list of 1 to 64 action names, none repeated |
|
|
1527
|
+
| `limits` | Limits for the helper | A list of 0 to 64 limits, as in a slip (section 4.1) |
|
|
1528
|
+
| `validFrom`, `validUntil` | When the pass holds | Times; the second later than the first |
|
|
1529
|
+
| `when` | When it was written | A time |
|
|
1530
|
+
|
|
1531
|
+
A pass is signed with the key set of the agent that passes on: the
|
|
1532
|
+
slip's `agent.keys`, or, where it names `from`, the `to.keys` of that
|
|
1533
|
+
pass. A pass MUST come after its slip in the book, and after the pass it
|
|
1534
|
+
names in `from` (`pass-missing`), and that pass MUST be under the same
|
|
1535
|
+
slip (`pass-mismatch`). A pass MUST NOT be the eleventh in a row
|
|
1536
|
+
(`pass-too-deep`): no slip can allow more than ten, and the rule lets
|
|
1537
|
+
every stub be compared with every pass above its own at a small, fixed
|
|
1538
|
+
cost. Ten is a first-draft number, taken from the upper number commonly
|
|
1539
|
+
set for chains of delegated access between services.
|
|
1540
|
+
|
|
1541
|
+
A helper's stub names its pass in `pass`, and is signed with the
|
|
1542
|
+
`to.keys` of that pass. The stubs under one pass form a chain of their
|
|
1543
|
+
own (section 7).
|
|
1544
|
+
|
|
1545
|
+
What a checker reports about a pass:
|
|
1546
|
+
|
|
1547
|
+
| Code | Shown when |
|
|
1548
|
+
|---|---|
|
|
1549
|
+
| `pass-not-allowed` | The pass is one more in a row than the slip's `passes` allows. Every later pass that names it, and every stub under any of them, is reported too |
|
|
1550
|
+
| `pass-wider` | An action in `actions` is not one its writer holds (the slip's `actions`, or the `actions` of the pass in `from`), or `validFrom` is earlier, or `validUntil` later, than its writer's own |
|
|
1551
|
+
| `outside-valid-time` | `when` is outside the time its writer's own permission holds |
|
|
1552
|
+
| `after-cancellation` | The person had cancelled the slip (section 22) |
|
|
1553
|
+
|
|
1554
|
+
What a checker reports about a helper's stub:
|
|
1555
|
+
|
|
1556
|
+
1. Everything of section 8, compared with the **slip**, exactly as for
|
|
1557
|
+
the slip's own agent. The slip's totals, counts and periods take in
|
|
1558
|
+
the stubs of the agent and of every helper together. The slip's
|
|
1559
|
+
conditions and stated rules hold for a helper too.
|
|
1560
|
+
2. Also the findings of section 8 compared with the **pass**, taking its
|
|
1561
|
+
`actions`, its `limits` and its times as a slip's, with totals of its
|
|
1562
|
+
own.
|
|
1563
|
+
3. And the same compared with **every pass above it**: the pass that its
|
|
1564
|
+
own pass names in `from`, and so on up. The totals of a pass take in
|
|
1565
|
+
the stubs written under it and under every pass handed on from it.
|
|
1566
|
+
|
|
1567
|
+
A finding with the same code as one that the slip, or a pass nearer the
|
|
1568
|
+
stub, already gave for the stub is not given twice.
|
|
1569
|
+
|
|
1570
|
+
A pass's limits are not compared with the limits of the slip, or of the
|
|
1571
|
+
pass above it. They need not be: the limits of the slip and of every
|
|
1572
|
+
pass above always hold for a helper, so passing on cannot widen them.
|
|
1573
|
+
|
|
1574
|
+
## 26. Acknowledging a cancellation
|
|
1575
|
+
|
|
1576
|
+
A cancellation shows when the person signed it. It does not show that
|
|
1577
|
+
the agent's side was told (section 22). An acknowledgement closes that
|
|
1578
|
+
gap from the other side: the agent's own software states that it was
|
|
1579
|
+
handed the cancellation, and when. The person keeps it with their copy
|
|
1580
|
+
of the cancellation.
|
|
1581
|
+
|
|
1582
|
+
Content:
|
|
1583
|
+
|
|
1584
|
+
| Member | Meaning | Form |
|
|
1585
|
+
|---|---|---|
|
|
1586
|
+
| `type` | The kind of content | `provared.acknowledgement.v0` |
|
|
1587
|
+
| `id` | A unique number | Section 3.7 |
|
|
1588
|
+
| `slip` | The slip that was cancelled | A fingerprint |
|
|
1589
|
+
| `cancellation` | The cancellation that was handed over | A fingerprint |
|
|
1590
|
+
| `pass` | Optional. For a helper agent: the pass it acts under | A fingerprint |
|
|
1591
|
+
| `when` | When the cancellation was handed over, as the agent's side states it | A time |
|
|
1592
|
+
|
|
1593
|
+
It is signed as a stub is (section 5.2), with the acknowledgement labels
|
|
1594
|
+
of section 3.2: with the two keys of the agent the slip names or, where
|
|
1595
|
+
it holds `pass`, with the `to.keys` of that pass
|
|
1596
|
+
(`signature-invalid`). So it speaks for one agent: the slip's own, or
|
|
1597
|
+
one helper.
|
|
1598
|
+
|
|
1599
|
+
**In a book.** The slip MUST be earlier in the book (`slip-missing`),
|
|
1600
|
+
and so MUST the pass, under the same slip (`pass-missing`,
|
|
1601
|
+
`pass-mismatch`). The cancellation it names MUST be earlier in the book,
|
|
1602
|
+
MUST cancel the same slip, and MUST have passed its own check
|
|
1603
|
+
(`cancellation-not-found`): that includes a cancellation which a later
|
|
1604
|
+
seal's time-stamp shows to be dated later than it existed (section
|
|
1605
|
+
21.3). Among the pages of a Show, the slip, the
|
|
1606
|
+
pass and the cancellation MUST be among the pages. An acknowledgement in
|
|
1607
|
+
a book changes nothing that section 22 reports: every stub after the
|
|
1608
|
+
cancellation is reported already.
|
|
1609
|
+
|
|
1610
|
+
No rule ties its `when` to the cancellation's `when`. Each is one
|
|
1611
|
+
side's own word, and the two clocks may differ: an acknowledgement may
|
|
1612
|
+
be dated before the date the person's device gave.
|
|
1613
|
+
|
|
1614
|
+
**Handed over with the person's own copy.** The entry a checker is
|
|
1615
|
+
handed for the person's own copy of a cancellation (section 22) MAY hold
|
|
1616
|
+
`"acknowledgements"`: a list of 1 to 4 acknowledgement records, none
|
|
1617
|
+
twice (`bad-field`). Each MUST name that cancellation and its slip
|
|
1618
|
+
(`acknowledgement-mismatch`), and is checked against the keys of the
|
|
1619
|
+
slip's agent, or of the helper of a pass that the book holds
|
|
1620
|
+
(`pass-missing`, `signature-invalid`). One that does not pass is a
|
|
1621
|
+
problem with the check as a whole, and is not used; it MUST be reported,
|
|
1622
|
+
never set aside silently. The copy of the cancellation itself is still
|
|
1623
|
+
used: an acknowledgement that does not pass takes nothing from what the
|
|
1624
|
+
cancellation shows. One that this device could not check is not used,
|
|
1625
|
+
and a checker MUST say so; that includes every acknowledgement beside a
|
|
1626
|
+
copy, or under a slip, that this device could not confirm. For each
|
|
1627
|
+
acknowledgement that passes:
|
|
1628
|
+
|
|
1629
|
+
1. a checker MUST show it: who acknowledged (the slip's agent, or which
|
|
1630
|
+
helper), and the time it states, as the agent's side's own word;
|
|
1631
|
+
2. these are reported as `after-cancellation`, whether or not the copy
|
|
1632
|
+
has a counted time-stamp:
|
|
1633
|
+
- every stub in that agent's own chain (section 7) whose `when` is
|
|
1634
|
+
later than the acknowledgement's `when`;
|
|
1635
|
+
- every pass that agent wrote (section 25) whose `when` is later
|
|
1636
|
+
than the acknowledgement's `when`, every pass handed on from such
|
|
1637
|
+
a pass, and every stub under any of them.
|
|
1638
|
+
|
|
1639
|
+
By the agent's own dates each was made after the agent's side was
|
|
1640
|
+
told. A checker MUST word this finding so that it can be told apart
|
|
1641
|
+
from the finding of section 22 ("not shown to have existed before
|
|
1642
|
+
the slip was cancelled");
|
|
1643
|
+
3. the rule of section 22 is applied first, for every copy handed over,
|
|
1644
|
+
whatever order they were handed over in. A stub that it reports keeps
|
|
1645
|
+
that finding, which rests on an outside time-stamp; where rule 2
|
|
1646
|
+
applies to the stub as well, the finding says so in addition;
|
|
1647
|
+
4. where the book does not hold the cancellation, a checker MUST say
|
|
1648
|
+
that the agent's side acknowledged it, and when. It was then left out
|
|
1649
|
+
of the book, or was still to be written into it when the copy of the
|
|
1650
|
+
book was made.
|
|
1651
|
+
|
|
1652
|
+
What an acknowledgement does not show: when the person cancelled; that
|
|
1653
|
+
a helper agent was told, where only the slip's own agent acknowledged
|
|
1654
|
+
(a helper that held its pass before then is not reported under rule 2);
|
|
1655
|
+
or anything about a stub dated at or before its `when`. Whoever signs
|
|
1656
|
+
an acknowledgement SHOULD NOT date it before the last stub of its own
|
|
1657
|
+
chain, nor before a pass that it handed on: either may be dated a little
|
|
1658
|
+
ahead of the signer's clock, and would otherwise read as made after the
|
|
1659
|
+
agent's side was told. Where a copy holds several acknowledgements,
|
|
1660
|
+
what each agent did itself after it was told is settled first, for every
|
|
1661
|
+
acknowledgement, and then what was done under a pass handed on late: so
|
|
1662
|
+
the wording of a finding does not depend on their order. Both dates in
|
|
1663
|
+
rule 2 are the agent's own word: an agent that writes earlier dates into
|
|
1664
|
+
its stubs escapes rule 2, and is caught only by the time-stamp rule of
|
|
1665
|
+
section 22. Nothing obliges an agent's side to acknowledge: a
|
|
1666
|
+
cancellation with no acknowledgement shows nothing about whether the
|
|
1667
|
+
agent's side was told.
|
|
1668
|
+
|
|
1669
|
+
---
|
|
1670
|
+
|
|
1671
|
+
Copyright 2026 Pavel Izmaylov. This document is licensed under the
|
|
1672
|
+
Creative Commons Attribution 4.0 International licence.
|