Skip to content

Commit 13dc197

Browse files
committed
update rfc
1 parent d36fa11 commit 13dc197

File tree

1 file changed

+27
-24
lines changed

1 file changed

+27
-24
lines changed

rfcs/2025-03-16-smp-queues.md

+27-24
Original file line numberDiff line numberDiff line change
@@ -62,29 +62,21 @@ data QueueIdsKeys = QIK
6262

6363
Proposed NEW command replaces SenderCanSecure with QueueMode, adds link data, and combines NKEY command:
6464

65-
The problem: at a point of preparing immutable data we do not yet have sender_id for the primary queue (the only queue at the moment), and we cannot simply use ID returned from the server in LINK response, as it would not mitigate server changing it. Which was the original reason to supply sender_id. So it seems that the only option is to either accept that the sender_id existence can be checked (by creating the queue with passed ID) or that the link data will be passed in a separate command, requiring additional roundtrip.
66-
67-
For contact addresses we could user-generate sender_id, but for 1-time invitations it is a bad trade-off - sending the additional command is better. It also simplifies the protocol, as adding link data at the point of creating the queue does not need to be supported.
68-
69-
Is server changing the ID in the response a risk? Does the queue recipient even need to know sender_id? Potentially the server could return sender_id in LINK response, and the queue recipient would include some placeholder in the address that the queue sender would replace with ID from LINK response. This would avoid both the extra roundtrip to save queue data and the possibility of checking for queue existense (by creating the queue using sender-defined ID).
70-
71-
So, possibly, for contact addresses user will provide both sender_id and link_id, as it's possible to check address existense anyway, without creating the queue, and for 1-time invitations it may be ok to use placeholder ID for primary queue in the address. It may be "cleaner" from protocol design point of view to have the extra roundtrip though.
72-
7365
```haskell
7466
NEW :: NewQueueRequest -> Command Recipient
7567

76-
data NewQueueRequest = NewQueueRequest
68+
data NewQueueReq = NewQueueReq
7769
{ rcvAuthKey :: RcvPublicAuthKey,
7870
rcvDhKey :: RcvPublicDhKey,
79-
basicAuth :: Maybe BasicAuth,
71+
auth_ :: Maybe BasicAuth,
8072
subMode :: SubscriptionMode,
81-
ntfRequest :: Maybe NtfRequest,
82-
queueLink :: Maybe QueueLink -- it is Maybe to allow testing and staged roll-out
73+
queueData :: Maybe QueueModeData,
74+
ntfCreds :: Maybe NewNtfCreds
8375
}
8476

8577
-- To allow updating the existing contact addresses without changing them.
86-
-- This command would fail on queues that support sndSecure and also on new queues created with QLMessaging.
87-
-- RecipientId is entity ID.
78+
-- This command would fail on queues that support sndSecure and also on new queues created with QDMessaging.
79+
-- RecipientId is entity ID for this command.
8880
-- The response to this command is `OK`.
8981
LNEW :: LinkId -> QueueLinkData -> Command Recipient
9082

@@ -93,16 +85,18 @@ LNEW :: LinkId -> QueueLinkData -> Command Recipient
9385
-- Further changes would move NotifierId generation to the client, and including a signed and encrypted command to be forwarded by SMP server to notification server.
9486
data NtfRequest = NtfRequest NtfPublicAuthKey RcvNtfPublicDhKey
9587

96-
-- QLMessaging implies that sender can secure the queue.
97-
-- LinkId is not used with QLMessaging, to prevent the possibility of checking when connection is established by re-using the same link ID when creating another queue – the creating would have to fail if it is used.
98-
-- LinkId is required with QLContact, to have shorter link - it will be derived from the link_uri. And in this case we do not need to prevent checks that this queue exists.
99-
data QueueLink = QLMessaging QueueLinkData | QLContact LinkId QueueLinkData
88+
-- QDMessaging implies that sender can secure the queue.
89+
-- LinkId is not used with QDMessaging, to prevent the possibility of checking when connection is established by re-using the same link ID when creating another queue – the creating would have to fail if it is used.
90+
-- LinkId is required with QDContact, to have shorter link - it will be derived from the link_uri. And in this case we do not need to prevent checks that this queue exists.
91+
data QueueModeData = QDMessaging (Maybe QueueLinkData) | QDContact (Maybe (LinkId, QueueLinkData))
10092

101-
data QueueLinkData = QueueLinkData EncImmutableDataBytes EncUserDataBytes
93+
-- SenderId should be computed client-side as sha3-256(correlation_id),
94+
-- The server must verify it and reject if it is not.
95+
type QueueLinkData = (SenderId, EncImmutableDataBytes, EncUserDataBytes)
10296

103-
newtype EncImmutableDataBytes = EncImmutableDataBytes ByteString
97+
type EncImmutableDataBytes = ByteString
10498

105-
newtype EncUserDataBytes = EncUserDataBytes ByteString
99+
type EncUserDataBytes = ByteString
106100

107101
-- We need to use binary encoding for AConnectionRequestUri to reduce its size
108102
-- connReq including the full link allows connection redundancy.
@@ -142,13 +136,13 @@ LSET :: EncUserDataBytes -> Command Recipient
142136

143137
-- To be used with 1-time links.
144138
-- Sender's key provided on the first request prevents observers from undetectably accessing 1-time link data.
145-
-- If queue mode is QLContact (and queue does NOT allow sndSecure) the command will fail, same as SKEY.
139+
-- If queue mode is QDContact (and queue does NOT allow sndSecure) the command will fail, same as SKEY.
146140
-- Once queue is secured, the key must be the same in subsequent requests - to allow retries in case of network failures, and to prevent passive attacks.
147141
-- The difference with securing queues is that queues allow sending unsecured messages to queues that allow sndSecure (for backwards compatibility), and 1-time links will NOT allow retrieving link data without securing the queue at the same time, preventing undetected access by observers.
148142
-- Entity ID is LinkId here
149143
LKEY :: SndPublicAuthKey -> Command Sender
150144

151-
-- If queue mode is QLMessaging the command will fail.
145+
-- If queue mode is QDMessaging the command will fail.
152146
-- Entity ID is LinkId here
153147
LGET :: Command Sender
154148

@@ -157,6 +151,15 @@ LGET :: Command Sender
157151
LINK :: SenderId -> QueueLinkData -> BrokerMsg
158152
```
159153

154+
To both include sender_id into the full link before the server response, and to prevent "oracle attack" when a failure to create the queue with the supplied `sender_id` can be used as a proof of queue existense, it is proposed that `sender_id` is computed client-side as `sha3-256(correlation_id)` and validated server-side, where `corelation_id` is the transmission correlation ID.
155+
156+
To allow retries and to avoid regenerating all queue data, NEW command must be idempotent, and `correlation_id` must be preserved in command for queue creation, so that the same `correlation_id` and all other data is used in retries. `correlation_id` should be removed after queue creation success.
157+
158+
Alternative solutions considered and rejected:
159+
- additional request to save queue data, after `sender_id` is returned by the server.
160+
- include empty sender_id in the immutable data and have it replaced by the accepting party with `sender_id` received in `LINK` response - both a weird design, and might create possibility for some attacks via server, especially for contact addresses.
161+
- use random `correlation_id` and new `sender_id` in retries. While it would remove the need for `NEW` command to be idempotent, it would increase the cost of retries and would require regenerating the whole immutable data of the queue on each retry.
162+
160163
## Algorithm to prepare and to interpret queue link data.
161164

162165
For contact addresses this approach follows the design proposed in [Short links](./2024-06-21-short-links.md) RFC - when link id is derived from the same random binary as key. For 1-time invitations link ID is independent and server-generated, to prevent existense checks.
@@ -208,7 +211,7 @@ Link recipient:
208211
6. Decrypt: `signed_used_data = decrypt(nonce2, ct2, tag2)`
209212
7. Verify signature with key in immutable data.
210213

211-
While using content hash as encryption key is unconventional, it is not completely unheard of - e.g., it is used in convergent encryption (although in our case using random nonce makes it not convergent, but it means that it preserves encryption security). It is particularly acceptable for our use case, as `immutable_data` contains mostly random keys.
214+
While using content hash as encryption key is unconventional, it is not completely unheard of - e.g., it is used in convergent encryption (although in our case using random nonce makes it not convergent, but other use cases suggest that this approach preserves encryption security). It is particularly acceptable for our use case, as `immutable_data` contains mostly random keys.
212215

213216
## Threat model
214217

0 commit comments

Comments
 (0)