@derec-alliance/nodejs 0.0.3 → 0.0.5
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/README.md +18 -0
- package/derec_descriptor.bin +0 -0
- package/derec_library.js +1 -1
- package/derec_library_bg.wasm +0 -0
- package/derec_library_bg.wasm.d.ts +23 -23
- package/index.d.ts +11 -0
- package/package.json +3 -1
- package/proto/committedderecshare.proto +79 -0
- package/proto/communicationinfo.proto +104 -0
- package/proto/contact.proto +264 -0
- package/proto/derecmessage.proto +213 -0
- package/proto/derecsecret.proto +163 -0
- package/proto/derectransport.proto +38 -0
- package/proto/error.proto +60 -0
- package/proto/getshare.proto +194 -0
- package/proto/pair.proto +284 -0
- package/proto/parameterrange.proto +36 -0
- package/proto/prepair.proto +177 -0
- package/proto/result.proto +194 -0
- package/proto/secretidsversions.proto +209 -0
- package/proto/storeshare.proto +274 -0
- package/proto/transportprotocol.proto +100 -0
- package/proto/unpair.proto +140 -0
- package/proto/updatechannelinfo.proto +129 -0
- package/proto/verify.proto +170 -0
package/proto/pair.proto
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) DeRec Alliance and its Contributors.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
syntax = "proto3";
|
|
7
|
+
|
|
8
|
+
import "google/protobuf/timestamp.proto";
|
|
9
|
+
import "communicationinfo.proto";
|
|
10
|
+
import "parameterrange.proto";
|
|
11
|
+
import "result.proto";
|
|
12
|
+
import "transportprotocol.proto";
|
|
13
|
+
|
|
14
|
+
package org.derecalliance.derec.protobuf;
|
|
15
|
+
|
|
16
|
+
// SenderKind identifies the logical role of the sender in the pairing flow.
|
|
17
|
+
//
|
|
18
|
+
// The role determines how the receiver interprets the message and what
|
|
19
|
+
// role each party takes in the resulting channel. Pairs are formed by
|
|
20
|
+
// matching complementary kinds: Owner↔Helper, ReplicaSource↔ReplicaDestination.
|
|
21
|
+
enum SenderKind {
|
|
22
|
+
// Sender is an Owner.
|
|
23
|
+
//
|
|
24
|
+
// Used for all Owner-initiated pairings, whether establishing a new
|
|
25
|
+
// relationship or re-pairing during recovery. There is no protocol-level
|
|
26
|
+
// distinction between the two cases.
|
|
27
|
+
OWNER = 0;
|
|
28
|
+
|
|
29
|
+
// Sender is acting as a Helper.
|
|
30
|
+
//
|
|
31
|
+
// Helpers may initiate pairing in some application flows, though the
|
|
32
|
+
// Owner typically acts as the initiator.
|
|
33
|
+
HELPER = 1;
|
|
34
|
+
|
|
35
|
+
// Sender is the Source side of a replica pair — the device that owns
|
|
36
|
+
// the secrets and pushes them to a destination for backup. The matching
|
|
37
|
+
// peer kind is REPLICA_DESTINATION.
|
|
38
|
+
//
|
|
39
|
+
// Replica pairing follows the same cryptographic handshake as Helper
|
|
40
|
+
// pairing but adds a mandatory fingerprint-verify step before the
|
|
41
|
+
// channel transitions out of `Pending`. After verification, the Source
|
|
42
|
+
// calls ProtectSecret targeting the Destination channel; the library
|
|
43
|
+
// sends a `ReplicaSecretPayload` (full secret + share map) to the
|
|
44
|
+
// Destination via a normal channel-mode `StoreShareRequest`.
|
|
45
|
+
REPLICA_SOURCE = 3;
|
|
46
|
+
|
|
47
|
+
// Sender is the Destination side of a replica pair — the device that
|
|
48
|
+
// receives and stores full secret copies from a Source for backup or
|
|
49
|
+
// recovery purposes. The matching peer kind is REPLICA_SOURCE.
|
|
50
|
+
//
|
|
51
|
+
// The Destination never initiates ProtectSecret on this channel; it
|
|
52
|
+
// only receives `ReplicaSecretPayload` messages and surfaces them to
|
|
53
|
+
// the application via the `ReplicaSecretReceived` event.
|
|
54
|
+
REPLICA_DESTINATION = 4;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// PairRequestMessage is the first message in the pairing protocol,
|
|
58
|
+
// sent from the initiator to the responder after receiving a ContactMessage.
|
|
59
|
+
//
|
|
60
|
+
// # Preconditions
|
|
61
|
+
//
|
|
62
|
+
// Before sending this message:
|
|
63
|
+
//
|
|
64
|
+
// - The initiator MUST have received a valid ContactMessage from the responder
|
|
65
|
+
// - The initiator MUST use the responder's public encryption material from
|
|
66
|
+
// the ContactMessage to construct this request
|
|
67
|
+
//
|
|
68
|
+
// # Purpose
|
|
69
|
+
//
|
|
70
|
+
// This message establishes:
|
|
71
|
+
//
|
|
72
|
+
// - the initiator's identity and role (Owner/Helper, recovery mode or not)
|
|
73
|
+
// - fresh cryptographic material for the responder to use in subsequent messages
|
|
74
|
+
// - agreement negotiation inputs (parameter ranges)
|
|
75
|
+
// - binding between the out-of-band contact exchange and this pairing attempt
|
|
76
|
+
// - transport information for future communication
|
|
77
|
+
//
|
|
78
|
+
// # Security Properties
|
|
79
|
+
//
|
|
80
|
+
// - The nonce binds this request to the ContactMessage exchange
|
|
81
|
+
// - The ciphertext and public keys bootstrap a secure communication channel
|
|
82
|
+
// - The message is encrypted and authenticated at the DeRecMessage layer
|
|
83
|
+
//
|
|
84
|
+
// # Outcome
|
|
85
|
+
//
|
|
86
|
+
// Upon successful processing, the responder replies with PairResponseMessage.
|
|
87
|
+
// After this exchange:
|
|
88
|
+
//
|
|
89
|
+
// - both parties know each other's public keys
|
|
90
|
+
// - a secure communication channel is established for subsequent protocol flows
|
|
91
|
+
message PairRequestMessage {
|
|
92
|
+
|
|
93
|
+
// The role of the sender of this message.
|
|
94
|
+
//
|
|
95
|
+
// This informs the responder whether the initiator is:
|
|
96
|
+
//
|
|
97
|
+
// - an Owner (normal or recovery mode), or
|
|
98
|
+
// - a Helper
|
|
99
|
+
//
|
|
100
|
+
// Recovery mode has special semantics for how Helpers associate this
|
|
101
|
+
// pairing with existing stored secrets.
|
|
102
|
+
SenderKind senderKind = 1;
|
|
103
|
+
|
|
104
|
+
// ML-KEM-768 ciphertext.
|
|
105
|
+
//
|
|
106
|
+
// This ciphertext is generated using the responder's ML-KEM public key
|
|
107
|
+
// obtained from the ContactMessage. It is used to establish shared
|
|
108
|
+
// cryptographic material for securing subsequent communication.
|
|
109
|
+
bytes mlkemCiphertext = 2;
|
|
110
|
+
|
|
111
|
+
// Serialized ECIES public key of the sender.
|
|
112
|
+
//
|
|
113
|
+
// This key is provided to the responder so that future messages can be
|
|
114
|
+
// encrypted toward the initiator.
|
|
115
|
+
bytes eciesPublicKey = 3;
|
|
116
|
+
|
|
117
|
+
// Sender's application-level identifying information.
|
|
118
|
+
//
|
|
119
|
+
// This field is intended for user-facing identification and may include
|
|
120
|
+
// data such as name, phone number, or account identifiers.
|
|
121
|
+
//
|
|
122
|
+
// It is not used directly by the protocol for security decisions.
|
|
123
|
+
CommunicationInfo communicationInfo = 5;
|
|
124
|
+
|
|
125
|
+
// Nonce binding this request to the ContactMessage exchange.
|
|
126
|
+
//
|
|
127
|
+
// This value MUST match the nonce provided in the ContactMessage.
|
|
128
|
+
// It allows the responder to verify that the pairing request corresponds
|
|
129
|
+
// to the same out-of-band interaction, preventing mismatched or spoofed
|
|
130
|
+
// pairing attempts.
|
|
131
|
+
uint64 nonce = 6;
|
|
132
|
+
|
|
133
|
+
// Parameter range supported by the sender.
|
|
134
|
+
//
|
|
135
|
+
// This defines the acceptable configuration space (e.g., thresholds,
|
|
136
|
+
// limits) that the sender is willing to operate under.
|
|
137
|
+
//
|
|
138
|
+
// The responder combines this with its own parameter range to determine
|
|
139
|
+
// whether pairing is possible and which parameters to use.
|
|
140
|
+
ParameterRange parameterRange = 7;
|
|
141
|
+
|
|
142
|
+
// Transport information for reaching the initiator.
|
|
143
|
+
//
|
|
144
|
+
// This specifies:
|
|
145
|
+
//
|
|
146
|
+
// - the endpoint where the initiator can receive messages
|
|
147
|
+
// - the protocol required to deliver those messages
|
|
148
|
+
//
|
|
149
|
+
// After pairing, the responder uses this information to send responses
|
|
150
|
+
// and all subsequent protocol messages to the initiator.
|
|
151
|
+
// Deprecated: superseded by `supportedTransports`, which carries every
|
|
152
|
+
// endpoint rather than one.
|
|
153
|
+
//
|
|
154
|
+
// **Reading this field directly is now incorrect.** Its meaning narrowed
|
|
155
|
+
// from "the endpoint" to "one entry of a list, and possibly absent": an
|
|
156
|
+
// initiator that has moved past this field advertises only
|
|
157
|
+
// `supportedTransports`. A reader that was correct before this release is
|
|
158
|
+
// a bug now — it rejects, or fails to reach, a peer that is offering it a
|
|
159
|
+
// perfectly good endpoint. Resolve both spellings instead of reading
|
|
160
|
+
// either: `advertised_endpoints()` (Rust and TypeScript),
|
|
161
|
+
// `AdvertisedEndpoints()` (Go), `AdvertisedEndpoints()` (.NET).
|
|
162
|
+
//
|
|
163
|
+
// Senders still populate it: a sender that sets `supportedTransports`
|
|
164
|
+
// MUST also set this to a single best-compatibility choice, so
|
|
165
|
+
// implementations predating the list still pair.
|
|
166
|
+
//
|
|
167
|
+
// **Scheduled for removal in v0.0.5.**
|
|
168
|
+
TransportProtocol transportProtocol = 8 [deprecated = true];
|
|
169
|
+
|
|
170
|
+
// Timestamp indicating when this message was created.
|
|
171
|
+
//
|
|
172
|
+
// Used for observability and may assist in replay detection or timeout
|
|
173
|
+
// handling, depending on the implementation.
|
|
174
|
+
google.protobuf.Timestamp timestamp = 9;
|
|
175
|
+
|
|
176
|
+
// Every transport endpoint the initiator can be reached on, in the
|
|
177
|
+
// initiator's own preference order.
|
|
178
|
+
//
|
|
179
|
+
// Same semantics as `ContactMessage.supportedTransports`: the responder
|
|
180
|
+
// selects by its own preference, and absent means "only
|
|
181
|
+
// `transportProtocol` is offered".
|
|
182
|
+
repeated TransportProtocol supportedTransports = 10;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// PairResponseMessage is the response to a PairRequestMessage.
|
|
186
|
+
//
|
|
187
|
+
// # Purpose
|
|
188
|
+
//
|
|
189
|
+
// This message completes the pairing handshake. It informs the initiator:
|
|
190
|
+
//
|
|
191
|
+
// - whether the pairing was accepted or rejected
|
|
192
|
+
// - the responder's role and identity information
|
|
193
|
+
// - the responder's supported parameter range
|
|
194
|
+
//
|
|
195
|
+
// # Differences from PairRequestMessage
|
|
196
|
+
//
|
|
197
|
+
// - Does not include encryption public keys, as those were already exchanged
|
|
198
|
+
// via ContactMessage and PairRequestMessage
|
|
199
|
+
// - Includes a Result field indicating success or failure
|
|
200
|
+
//
|
|
201
|
+
// # Semantics
|
|
202
|
+
//
|
|
203
|
+
// - If `result` indicates success, a secure channel is considered established
|
|
204
|
+
// - If `result` indicates failure, the pairing MUST be treated as unsuccessful
|
|
205
|
+
// and no further protocol messages should be exchanged on this channel
|
|
206
|
+
//
|
|
207
|
+
// The nonce MUST match the value provided in the request, ensuring that the
|
|
208
|
+
// response corresponds to the same pairing session.
|
|
209
|
+
message PairResponseMessage {
|
|
210
|
+
|
|
211
|
+
// Result of processing the pairing request.
|
|
212
|
+
//
|
|
213
|
+
// Indicates whether the pairing was successful or failed.
|
|
214
|
+
// Failure may occur due to:
|
|
215
|
+
//
|
|
216
|
+
// - incompatible parameter ranges
|
|
217
|
+
// - failed authentication at the application layer
|
|
218
|
+
// - invalid or malformed request data
|
|
219
|
+
DeRecResult result = 1;
|
|
220
|
+
|
|
221
|
+
// Application-level identifying information of the responder.
|
|
222
|
+
//
|
|
223
|
+
// Intended for user-facing identification and display purposes.
|
|
224
|
+
CommunicationInfo communicationInfo = 4;
|
|
225
|
+
|
|
226
|
+
// Nonce identifying the pairing session.
|
|
227
|
+
//
|
|
228
|
+
// This value MUST exactly match the nonce received in the
|
|
229
|
+
// PairRequestMessage. A mismatch indicates an invalid or unrelated
|
|
230
|
+
// pairing attempt and SHOULD result in rejection.
|
|
231
|
+
uint64 nonce = 5;
|
|
232
|
+
|
|
233
|
+
// Parameter range supported by the responder.
|
|
234
|
+
//
|
|
235
|
+
// The initiator combines this with its own parameter range to determine
|
|
236
|
+
// the final agreed configuration for the channel.
|
|
237
|
+
ParameterRange parameterRange = 6;
|
|
238
|
+
|
|
239
|
+
// Timestamp indicating when this message was created.
|
|
240
|
+
//
|
|
241
|
+
// Used for observability and may assist in replay detection or timeout
|
|
242
|
+
// handling, depending on the implementation.
|
|
243
|
+
google.protobuf.Timestamp timestamp = 7;
|
|
244
|
+
|
|
245
|
+
// Derived channel identifier the two parties switch to immediately after
|
|
246
|
+
// the pairing handshake completes. This message is the only place this
|
|
247
|
+
// value travels on the wire, and it travels encrypted (inside the pairing
|
|
248
|
+
// envelope), so a passive observer who only sees the pre-rekey traffic
|
|
249
|
+
// cannot link the now-paired session to its long-running successor.
|
|
250
|
+
//
|
|
251
|
+
// # Derivation
|
|
252
|
+
//
|
|
253
|
+
// The responder computes:
|
|
254
|
+
//
|
|
255
|
+
// ```text
|
|
256
|
+
// channelId = u64::from_be_bytes(
|
|
257
|
+
// SHA-384(
|
|
258
|
+
// u64_be(originalChannelId) || sharedKeyBytes
|
|
259
|
+
// )[0..8]
|
|
260
|
+
// )
|
|
261
|
+
// ```
|
|
262
|
+
//
|
|
263
|
+
// where `originalChannelId` is the channelId from the contact / pairing
|
|
264
|
+
// envelopes and `sharedKeyBytes` is the freshly-derived pairing shared
|
|
265
|
+
// key.
|
|
266
|
+
//
|
|
267
|
+
// # Validation
|
|
268
|
+
//
|
|
269
|
+
// The requester MUST recompute the same hash with its own derivation of
|
|
270
|
+
// the shared key and reject the response (closing the would-be channel)
|
|
271
|
+
// if the value here does not match. A non-matching value indicates either
|
|
272
|
+
// a key-derivation mismatch (the channel would be unusable anyway) or
|
|
273
|
+
// tampering by a peer that somehow forged a valid envelope but cannot
|
|
274
|
+
// produce the SHA-384 preimage.
|
|
275
|
+
//
|
|
276
|
+
// # Effect
|
|
277
|
+
//
|
|
278
|
+
// Both parties atomically rekey their local channel record from
|
|
279
|
+
// `originalChannelId` to this value once the handshake is accepted. All
|
|
280
|
+
// subsequent envelopes on this channel — including the
|
|
281
|
+
// UpdateChannelInfo handover for the long-term transport — route on the
|
|
282
|
+
// new id.
|
|
283
|
+
uint64 channelId = 8;
|
|
284
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) DeRec Alliance and its Contributors.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
syntax = "proto3";
|
|
7
|
+
|
|
8
|
+
package org.derecalliance.derec.protobuf;
|
|
9
|
+
|
|
10
|
+
message ParameterRange {
|
|
11
|
+
|
|
12
|
+
// Minimum and maximum number of bytes the party is willing to store
|
|
13
|
+
// at any given time.
|
|
14
|
+
int64 minShareSize = 1;
|
|
15
|
+
int64 maxShareSize = 2;
|
|
16
|
+
|
|
17
|
+
// Minimum and maximum interval between verification requests that
|
|
18
|
+
// will be accepted.
|
|
19
|
+
int64 minTimeBetweenVerifications = 3;
|
|
20
|
+
int64 maxTimeBetweenVerifications = 4;
|
|
21
|
+
|
|
22
|
+
// Minimum and maximum interval between accepting new share updates.
|
|
23
|
+
int64 minTimeBetweenShareUpdates = 5;
|
|
24
|
+
int64 maxTimeBetweenShareUpdates = 6;
|
|
25
|
+
|
|
26
|
+
// Minimum and maximum timeout period (in seconds) after which the
|
|
27
|
+
// other party is considered unresponsive and the pairing may be
|
|
28
|
+
// removed along with all associated data.
|
|
29
|
+
int64 minUnresponsiveDeletionTimeout = 7;
|
|
30
|
+
int64 maxUnresponsiveDeletionTimeout = 8;
|
|
31
|
+
|
|
32
|
+
// Minimum and maximum timeout period (in seconds) after which the
|
|
33
|
+
// other party is considered inactive.
|
|
34
|
+
int64 minUnresponsiveDeactivationTimeout = 9;
|
|
35
|
+
int64 maxUnresponsiveDeactivationTimeout = 10;
|
|
36
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) DeRec Alliance and its Contributors.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
syntax = "proto3";
|
|
7
|
+
|
|
8
|
+
import "google/protobuf/timestamp.proto";
|
|
9
|
+
import "result.proto";
|
|
10
|
+
import "transportprotocol.proto";
|
|
11
|
+
|
|
12
|
+
package org.derecalliance.derec.protobuf;
|
|
13
|
+
|
|
14
|
+
// PrePairRequestMessage is sent by the recipient of a ContactMessage whose
|
|
15
|
+
// `contactMode == CONTACT_MODE_HASHED_KEYS`. It asks the contact creator for
|
|
16
|
+
// the actual ML-KEM and ECIES public keys that the contact's
|
|
17
|
+
// `contactBindingHash` commits to.
|
|
18
|
+
//
|
|
19
|
+
// # When this is sent
|
|
20
|
+
//
|
|
21
|
+
// `CONTACT_MODE_HASHED_KEYS` contacts carry only a hash of the public keys
|
|
22
|
+
// so they fit in size-constrained out-of-band channels (e.g. QR codes,
|
|
23
|
+
// short URLs). The recipient must obtain the actual keys before it can
|
|
24
|
+
// construct the first encrypted `PairRequestMessage`.
|
|
25
|
+
//
|
|
26
|
+
// # Security
|
|
27
|
+
//
|
|
28
|
+
// This message is plaintext — no shared key has been established yet. The
|
|
29
|
+
// scanner-side integrity check happens after the `PrePairResponseMessage`
|
|
30
|
+
// arrives, by recomputing the hash and matching it against the original
|
|
31
|
+
// `contactBindingHash`. An attacker who intercepts the transport cannot
|
|
32
|
+
// substitute different keys without producing a hash collision.
|
|
33
|
+
//
|
|
34
|
+
// # Envelope
|
|
35
|
+
//
|
|
36
|
+
// The message is wrapped in a `DeRecMessage` envelope just like every
|
|
37
|
+
// other protocol message. The envelope's `channelId` carries the routing
|
|
38
|
+
// key; the envelope's `message` field carries the serialized
|
|
39
|
+
// `PrePairRequestMessage` bytes unencrypted (because no symmetric key
|
|
40
|
+
// exists yet).
|
|
41
|
+
//
|
|
42
|
+
// # Security: transport endpoint is observable
|
|
43
|
+
//
|
|
44
|
+
// Because the envelope is plaintext, the `transportProtocol` field in both
|
|
45
|
+
// `PrePairRequestMessage` and `PrePairResponseMessage` is visible to any
|
|
46
|
+
// passive observer on the network path. The same applies to the
|
|
47
|
+
// `transportProtocol` carried in the `HASHED_KEYS`-mode `ContactMessage`
|
|
48
|
+
// itself if its out-of-band channel can be observed.
|
|
49
|
+
//
|
|
50
|
+
// The protocol relies on this contract from the application to preserve
|
|
51
|
+
// the security guarantees of `HASHED_KEYS` mode:
|
|
52
|
+
//
|
|
53
|
+
// - The `transportProtocol` used during pairing (the one advertised in the
|
|
54
|
+
// `ContactMessage` and echoed in `PrePairRequestMessage`) MUST be
|
|
55
|
+
// ephemeral and short-lived — bound to the pairing attempt, not to the
|
|
56
|
+
// long-term identity of either peer.
|
|
57
|
+
// - Once pairing completes, the application MUST swap to a long-term
|
|
58
|
+
// endpoint via an `UpdateChannelInfoRequestMessage`. The ephemeral
|
|
59
|
+
// pairing endpoint is retired after the changeover (see the endpoint-
|
|
60
|
+
// changeover discipline on `UpdateChannelInfoRequestMessage`).
|
|
61
|
+
//
|
|
62
|
+
// `INLINE_KEYS`-mode contacts do not have this constraint because the
|
|
63
|
+
// `PairRequestMessage` is asymmetrically encrypted; only the
|
|
64
|
+
// `ContactMessage` itself crosses an unencrypted channel, which is by
|
|
65
|
+
// definition the trusted out-of-band one.
|
|
66
|
+
message PrePairRequestMessage {
|
|
67
|
+
|
|
68
|
+
// The same `nonce` the original `ContactMessage` advertised. Bound to
|
|
69
|
+
// the contact session; mismatches indicate a stale or spoofed request
|
|
70
|
+
// and the receiver MUST refuse to serve the keys.
|
|
71
|
+
uint64 nonce = 1;
|
|
72
|
+
|
|
73
|
+
// Transport endpoint at which the sender expects to receive the
|
|
74
|
+
// `PrePairResponseMessage`.
|
|
75
|
+
//
|
|
76
|
+
// Deprecated: superseded by `supportedTransports`, which carries every
|
|
77
|
+
// endpoint rather than one.
|
|
78
|
+
//
|
|
79
|
+
// **Reading this field directly is now incorrect.** Its meaning narrowed
|
|
80
|
+
// from "the endpoint" to "one entry of a list, and possibly absent": a
|
|
81
|
+
// sender that has moved past this field advertises only
|
|
82
|
+
// `supportedTransports`. A reader that was correct before this release is
|
|
83
|
+
// a bug now — it rejects, or fails to reply to, a peer that is offering it
|
|
84
|
+
// a perfectly good endpoint. Resolve both spellings instead of reading
|
|
85
|
+
// either: `advertised_endpoints()` (Rust and TypeScript),
|
|
86
|
+
// `AdvertisedEndpoints()` (Go), `AdvertisedEndpoints()` (.NET).
|
|
87
|
+
//
|
|
88
|
+
// Senders still populate it: a sender that sets `supportedTransports`
|
|
89
|
+
// MUST also set this to a single best-compatibility choice, so
|
|
90
|
+
// implementations predating the list still receive a reply.
|
|
91
|
+
//
|
|
92
|
+
// **Scheduled for removal in v0.0.5.**
|
|
93
|
+
TransportProtocol transportProtocol = 2 [deprecated = true];
|
|
94
|
+
|
|
95
|
+
// Timestamp indicating when this message was created.
|
|
96
|
+
//
|
|
97
|
+
// This value is expressed in UTC and is used for envelope-vs-body
|
|
98
|
+
// timestamp validation, replay detection, and observability.
|
|
99
|
+
google.protobuf.Timestamp timestamp = 3;
|
|
100
|
+
|
|
101
|
+
// Every transport endpoint the sender of this PrePair request can be
|
|
102
|
+
// reached on for the `PrePairResponseMessage`.
|
|
103
|
+
//
|
|
104
|
+
// Each entry is a complete endpoint: a URI plus the protocol that says
|
|
105
|
+
// how to interpret it. The list is written in the sender's own
|
|
106
|
+
// preference order.
|
|
107
|
+
//
|
|
108
|
+
// # Selection is the recipient's
|
|
109
|
+
//
|
|
110
|
+
// A recipient picks whichever entry suits it, ordered by its **own**
|
|
111
|
+
// preference rather than the sender's. The order here expresses
|
|
112
|
+
// availability, not a ranking the recipient must honor.
|
|
113
|
+
//
|
|
114
|
+
// # Compatibility
|
|
115
|
+
//
|
|
116
|
+
// Absent means "only `transportProtocol` is offered", which is how every
|
|
117
|
+
// implementation predating this field behaves. A sender populating this
|
|
118
|
+
// list MUST also set `transportProtocol` to a single best-compatibility
|
|
119
|
+
// choice so those implementations still reply.
|
|
120
|
+
//
|
|
121
|
+
// At least one of the two MUST be present: a request naming no endpoint
|
|
122
|
+
// gives the recipient nowhere to send the response.
|
|
123
|
+
//
|
|
124
|
+
// # Security
|
|
125
|
+
//
|
|
126
|
+
// PrePair traffic is plaintext — no shared key exists yet — so these
|
|
127
|
+
// endpoints are visible to a passive observer, exactly as
|
|
128
|
+
// `transportProtocol` already was. The recipient's transport policy still
|
|
129
|
+
// refuses plaintext entries unless plaintext has been opted into.
|
|
130
|
+
repeated TransportProtocol supportedTransports = 4;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// PrePairResponseMessage is the contact creator's reply to a
|
|
134
|
+
// `PrePairRequestMessage`. On success it carries the real public keys; on
|
|
135
|
+
// failure it carries only a non-`Ok` `DeRecResult`.
|
|
136
|
+
//
|
|
137
|
+
// # Validation by the receiver
|
|
138
|
+
//
|
|
139
|
+
// The recipient (the original scanner of the `ContactMessage`) MUST:
|
|
140
|
+
//
|
|
141
|
+
// - Confirm `result.status == OK`. On non-`Ok`, surface a typed error to
|
|
142
|
+
// the application and do not proceed.
|
|
143
|
+
// - Recompute
|
|
144
|
+
//
|
|
145
|
+
// ```text
|
|
146
|
+
// SHA-384(mlkemEncapsulationKey || eciesPublicKey
|
|
147
|
+
// || u64_be(nonce) || u64_be(channelId))
|
|
148
|
+
// ```
|
|
149
|
+
//
|
|
150
|
+
// and verify it matches the original `ContactMessage.contactBindingHash`.
|
|
151
|
+
// - Only on a match, proceed to construct and send a normal
|
|
152
|
+
// `PairRequestMessage`.
|
|
153
|
+
//
|
|
154
|
+
// # Envelope
|
|
155
|
+
//
|
|
156
|
+
// Plaintext-in-`DeRecMessage`-envelope, same as `PrePairRequestMessage`.
|
|
157
|
+
message PrePairResponseMessage {
|
|
158
|
+
|
|
159
|
+
// Result of processing the `PrePairRequestMessage`. On `OK`, the two
|
|
160
|
+
// key fields below are present. On any non-`Ok` status, the key fields
|
|
161
|
+
// MUST be absent.
|
|
162
|
+
DeRecResult result = 1;
|
|
163
|
+
|
|
164
|
+
// Serialized ML-KEM-768 encapsulation key. Present only when
|
|
165
|
+
// `result.status == OK`.
|
|
166
|
+
optional bytes mlkemEncapsulationKey = 2;
|
|
167
|
+
|
|
168
|
+
// Serialized ECIES public key. Present only when
|
|
169
|
+
// `result.status == OK`.
|
|
170
|
+
optional bytes eciesPublicKey = 3;
|
|
171
|
+
|
|
172
|
+
// Echoed from the request for session correlation.
|
|
173
|
+
uint64 nonce = 4;
|
|
174
|
+
|
|
175
|
+
// Timestamp indicating when this message was created.
|
|
176
|
+
google.protobuf.Timestamp timestamp = 5;
|
|
177
|
+
}
|