1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
//! Minting outbound frames, and refusing inbound ones that cannot prove who
//! sent them.
//!
//! # The gate
//!
//! Every control frame in this protocol carries an Ed25519 signature in two
//! metadata keys, over a domain-separated canonical payload built from the
//! sender, the id, the recipient, the content and the frame's timestamp. A
//! leaf verifies four things and refuses on any of them:
//!
//! 1. the signature metadata is present and complete,
//! 2. the signature verifies under the key the frame presents,
//! 3. **the presented key derives to the address the frame claims to be from**,
//! 4. **the frame is not older, or further ahead of this device's clock, than
//! the window allows**.
//!
//! The third is the one that says *who*. The first two prove a key signed
//! this; only the third proves it is the peer's key. Both halves of a
//! mismatch, and an identifier that is not an address at all, are the same
//! refusal: an identifier with no derivation to check is not a claim that
//! needs waving through, it is the bypass, and answering "acceptable" for it
//! is how an attacker skips the gate by claiming a nickname.
//!
//! The fourth says *when*, and without it the other three are a signature that
//! never expires: a frame captured off the air verifies as well on its tenth
//! delivery as on its first, and a key package carrying `session_reset` tears
//! down a live session on each one (issue 403).
//!
//! # Which signing payload a leaf verifies
//!
//! Two payloads exist: the older one, which binds the sender, the id, the
//! recipient and the content, and the freshness-bound one, which additionally
//! binds the frame's timestamp. A leaf verifies the freshness-bound payload on
//! every control frame, and the older one on exactly one: `__MLS_KEY_PKG__`.
//!
//! The exception is required rather than permitted, and the reason is not that
//! some phones are old. A sender builds the freshness-bound payload for a
//! recipient that has advertised it and the older one for a recipient that has
//! not, and capabilities arrive **in a key package**, so the first key package
//! to a peer never met is signed under the older payload no matter how new the
//! sender is. That is inherent to the negotiation rather than a gap to close
//! (ADR 0023, "First contact necessarily signs v1"). The same shape recurs
//! later: a peer whose record of this device was evicted or lost signs the
//! older payload again, because it no longer knows what this device accepts,
//! and a key package is the only frame that can re-teach it.
//!
//! So refusing the older payload here does not harden the device, it makes a
//! phone-initiated pairing impossible: the frame is refused, the device never
//! learns the phone exists, and the phone's retry ladder delivers the same
//! refusal ten times over, which reaches firmware as a run of signature
//! failures indistinguishable from an attack.
//!
//! What the exception costs is nothing an attacker wants. **A frame accepted
//! under the older payload has its `session_reset` ignored**, so the one
//! directive that destroys state still requires a stamp inside the signature,
//! and the replay closed by issue 403 stays closed. What survives is
//! capability advertisement, which this protocol treats as unauthenticated
//! hint data everywhere else. The frame's age is not judged either, because
//! the older payload leaves the timestamp outside the signature and judging it
//! would be judging a number an attacker chose.
//!
//! Every other control frame a leaf accepts is refused under the older
//! payload, and none of them needs it: a Welcome and a confirmation probe can
//! only follow this device's own key package reaching the peer, which is the
//! frame that teaches the peer to sign the newer payload.
use ;
use ;
use ;
use ;
use crate;
use crate;
use crateArc;
use crate;
const KEY_ID_COUNTER: &str = "send_counter";
/// Reads, advances and persists the device's send counter.
///
/// One counter serves both jobs a phone uses entropy and a clock for: it makes
/// a unique [`MessageId`] without drawing randomness, and it is the Lamport
/// value that orders this device's sends. Ids here are compared for equality
/// by a receiver's deduplicator and are never assumed unpredictable, so a
/// counter is the right primitive rather than a weaker substitute for one.
///
/// It is persisted **before** the frame it numbers exists, so a power cut
/// costs a skipped id rather than a repeated one. A repeated id would be
/// silently swallowed by the peer's deduplicator, which is a message that
/// vanishes with nothing anywhere reporting it.
/// Builds a message id that no other device mints.
///
/// The first eight bytes come from the device's own address, which is a hash
/// of its identity key, and the last eight are the send counter. Two devices
/// collide only if their addresses collide, which is the same margin every
/// other identity claim in this protocol rests on.
/// Mints an outbound message with no clock and no entropy.
pub
/// Mints the delivery acknowledgement a leaf owes for a frame it received.
///
/// # Why a device answers at all
///
/// A phone marks its frames as needing an acknowledgement and settles them
/// against the answer. Against a device that never answered, every one of them
/// ran the full retry ladder: ten retransmissions of a sealed frame over about
/// thirteen minutes, on the link this crate exists to be careful with. Each
/// retransmission arrived here as a replay of a generation the ratchet had
/// already spent, so it was correctly refused, and firmware saw a run of
/// [`LeafError::Mls`](crate::LeafError::Mls) indistinguishable from somebody
/// replaying frames at the device on purpose. The one signal that would tell
/// an integrator they are under attack was buried under traffic the protocol
/// generated itself (issue 402).
///
/// The arithmetic is what decides it. An acknowledgement is empty content and
/// a single metadata entry; the frames it prevents are ten full sealed
/// envelopes. Answering costs a fraction of staying quiet, and it is also the
/// only way the phone's application ever learns that the command it sent to a
/// lock arrived.
///
/// # What it is not
///
/// It carries no prefix and no signature, and it is not evidence of anything.
/// A peer reads it as "the frame with this id reached its recipient" and
/// nothing more: the engine that receives it checks only that the answer comes
/// from the address the message was addressed to, which a forger who saw the
/// frame saw too. Session confirmation is a different frame with a different
/// meaning ([`prefixes::SESSION_CONFIRM_ACK`]), and this one must never be read
/// as standing in for it.
///
/// [`prefixes::SESSION_CONFIRM_ACK`]: offline_protocol_sealed::prefixes::SESSION_CONFIRM_ACK
pub
/// Seconds to milliseconds, saturating rather than wrapping.
///
/// A device whose time source hands back something absurd gets a clamped
/// timestamp rather than a negative one. The timestamp is display metadata
/// and is not a security input, so clamping loses nothing that matters.
/// Stamps a control frame with a signature and the key that made it.
///
/// The canonical payload comes from the sealed layer, which is the same
/// function the phone's producer and verifier both call, so there is no
/// second construction here to get subtly wrong. Metadata is deliberately
/// outside the signature because relays rewrite it, which is also why the
/// order of these two inserts does not matter.
///
/// Always the freshness-bound payload, unconditionally. A phone chooses per
/// recipient, because it talks to installs that predate it; a leaf has no such
/// peer and no capability to consult, so there is nothing here to decide.
/// The frame's timestamp is inside this signature, so whatever `mint` stamped
/// is now covered: a device with a wrong clock produces frames its peer
/// refuses, which is the direction that fails safely.
pub
/// Verifies a control frame and returns the key that signed it.
///
/// Unsigned is a refusal, not a downgrade. Every control frame in this
/// protocol is signed, so one that is not is either an implementation that
/// skipped the step or an injection, and there is no third reading that would
/// make accepting it safe.
///
/// `now_unix_secs` is this device's clock, and it is a parameter for the same
/// reason it is one everywhere else in this crate: a leaf has no clock of its
/// own to reach for, so the caller that has one supplies it. A device that
/// supplies a wrong one refuses its peer, which is loud; a device that was
/// allowed to skip supplying one would accept anything, which is silent.
/// Which signing payload a control frame proved itself under.
///
/// Carried out of [`verify_control_frame`] rather than inferred again, because
/// the one caller that admits the older payload has to treat what it carries
/// differently: a `session_reset` under it is ignored.
pub
/// Whether a frame class may carry the older payload.
///
/// Named rather than passed as a bare flag, because the call site is where
/// this has to be readable: [`Admitted`](UndatedPayload::Admitted) appears
/// once in this crate and every other control frame refuses it.
pub
/// Verifies a control frame, admitting the older payload only when the caller
/// says this frame class may carry it.
///
/// See this module's documentation for why `__MLS_KEY_PKG__` is required to
/// admit it and why the rest are required not to.
pub
/// Requires the presented key to derive to the address the frame claims.
///
/// # Why an unparseable sender is an error rather than a skip
///
/// A sender that is not an address has no derivation to check, and the
/// tempting answer, pass because there is nothing to compare, hands over the
/// whole gate: an attacker claims a nickname and the check that distinguishes
/// them from its owner never runs. Refusing outright is what makes this
/// unconditional in the sense that matters, which is that there is no input
/// for which it declines to run.
pub
/// Splits a reserved prefix off a frame's content.
///
/// Returns the body, or `None` when the content does not carry this prefix.
pub