XMPP: _isOwnPresence vergelijkt MUC-nick met XMPP-resource — eigen keyshare wordt niet gedropt, andermans kan worden gedropt #1415

Closed
opened 2026-08-09 18:23:55 +00:00 by brenno · 0 comments
Owner

Bevinding

lib/xmpp/xmpp_key_exchange.darthandleKeyshare (regels 238–271) gebruikt _isOwnPresence (regels 275–283) om de autoriteit's eigen gereflecteerde keyshare te droppen. De methode vergelijkt echter twee verschillende dingen:

bool _isOwnPresence(String from) {
  final slash = from.indexOf('/');
  final nick = slash < 0 ? '' : from.substring(slash + 1);       // MUC-nick uit room@conf/nick
  final ownNick = _channel.boundJid;                              // user@domain/resource
  final ownNickResource = ownNick == null
      ? ''
      : ownNick.substring(ownNick.indexOf('/') + 1);            // XMPP-resource (bijv. "ocid-xxx")
  return nick == ownNickResource && nick.isNotEmpty;
}

nick is de MUC-nick — de resource van de in-room JID (room@conf/nick), die door de MUC-server op de stanza's from wordt gezet.

ownNickResource is de XMPP-resource — het resource-deel van de bound JID (user@domain/resource), die door de server bij bind wordt toegekend (of door OciDeck aangevraagd).

Deze twee hebben geen relatie. De MUC-nick wordt afgeleid uit de bound JID's localpart (via _nickFrom in xmpp_test_connection_dialog.dart regel 116–121: user@domain/resource → nick user), niet uit het resource-deel.

Wat er gebeurt

Geval 1 (waarschijnlijk): _isOwnPresence retourneert vrijwel altijd false — de MUC-nick (user) matcht nooit de XMPP-resource (ocid-xxx of server-toegewezen random). De autoriteit's eigen gereflecteerde keyshare wordt niet gedropt. handleKeyshare trial-opent tegen de autoriteit's eigen devices. installEpochKey probeert de epoch-sleutel te installeren die de autoriteit al heeft — verspild werk, maar waarschijnlijk onschadelijk.

Geval 2 (zeldzaam maar reëel): Als een andere occupant toevallig een MUC-nick kiest die gelijk is aan de autoriteit's XMPP-resource, retourneert _isOwnPresence true voor die occupant's stanzas. Hun keyshares worden incorrect gedropt als "eigen". De autoriteit verwerkt hun keyshare nooit — die deelnemer wordt nooit gesleuteld en kan niet meedoen.

Trust boundary

Interne logica — geen externe aanvaller nodig, maar een toevallige nick-botsing kan een deelnemer blokkeren.

Impact

  • De eigen-echo-detectie werkt niet — de autoriteit verwerkt zijn eigen keyshare (verspild werk).
  • Een deelnemer met een nick die toevallig gelijk is aan de autoriteit's XMPP-resource wordt permanent uitgesloten van keying.

Oplossingsrichting

  1. Vergelijk de MUC-nick, niet de XMPP-resource. De MUC-nick moet expliciet worden doorgegeven aan XmppKeyExchange (of afgeleid uit de bound JID's localpart, zoals _nickFrom dat doet). Vergelijk dan nick == ownMucNick.
  2. Beter: track de MUC-nick als een expliciete parameter op XmppKeyExchange (net als XmppMuc die heeft). De nick is bekend bij join-tijd en heeft niets met de bound JID te maken.
  3. Nog beter: daal de eigen-echo-check af op sealed.senderDevice == _e2ee.deviceId (dat doet handleDevicePresence al op regel 210). Dat is betrouwbaarder dan een nick-vergelijking en heeft geen MUC-nick nodig.

Locatie

  • lib/xmpp/xmpp_key_exchange.dart regels 252, 275–283 (_isOwnPresence)
  • lib/widgets/dialogs/xmpp_test_connection_dialog.dart regels 94, 116–121 (_nickFrom — toont hoe de nick werkelijk wordt afgeleid)

Severity

MEDIUM — de eigen-echo-detectie is defect; de randcase kan een deelnemer blokkeren.

## Bevinding `lib/xmpp/xmpp_key_exchange.dart` — `handleKeyshare` (regels 238–271) gebruikt `_isOwnPresence` (regels 275–283) om de autoriteit's eigen gereflecteerde keyshare te droppen. De methode vergelijkt echter twee verschillende dingen: ```dart bool _isOwnPresence(String from) { final slash = from.indexOf('/'); final nick = slash < 0 ? '' : from.substring(slash + 1); // MUC-nick uit room@conf/nick final ownNick = _channel.boundJid; // user@domain/resource final ownNickResource = ownNick == null ? '' : ownNick.substring(ownNick.indexOf('/') + 1); // XMPP-resource (bijv. "ocid-xxx") return nick == ownNickResource && nick.isNotEmpty; } ``` `nick` is de **MUC-nick** — de resource van de in-room JID (`room@conf/nick`), die door de MUC-server op de stanza's `from` wordt gezet. `ownNickResource` is de **XMPP-resource** — het resource-deel van de bound JID (`user@domain/resource`), die door de server bij bind wordt toegekend (of door OciDeck aangevraagd). Deze twee hebben **geen relatie**. De MUC-nick wordt afgeleid uit de bound JID's *localpart* (via `_nickFrom` in `xmpp_test_connection_dialog.dart` regel 116–121: `user@domain/resource` → nick `user`), niet uit het *resource*-deel. ### Wat er gebeurt **Geval 1 (waarschijnlijk):** `_isOwnPresence` retourneert vrijwel altijd `false` — de MUC-nick (`user`) matcht nooit de XMPP-resource (`ocid-xxx` of server-toegewezen random). De autoriteit's eigen gereflecteerde keyshare wordt **niet gedropt**. `handleKeyshare` trial-opent tegen de autoriteit's eigen devices. `installEpochKey` probeert de epoch-sleutel te installeren die de autoriteit al heeft — verspild werk, maar waarschijnlijk onschadelijk. **Geval 2 (zeldzaam maar reëel):** Als een andere occupant toevallig een MUC-nick kiest die gelijk is aan de autoriteit's XMPP-resource, retourneert `_isOwnPresence` `true` voor die occupant's stanzas. Hun keyshares worden **incorrect gedropt** als "eigen". De autoriteit verwerkt hun keyshare nooit — die deelnemer wordt nooit gesleuteld en kan niet meedoen. ### Trust boundary Interne logica — geen externe aanvaller nodig, maar een toevallige nick-botsing kan een deelnemer blokkeren. ### Impact - De eigen-echo-detectie werkt niet — de autoriteit verwerkt zijn eigen keyshare (verspild werk). - Een deelnemer met een nick die toevallig gelijk is aan de autoriteit's XMPP-resource wordt permanent uitgesloten van keying. ### Oplossingsrichting 1. **Vergelijk de MUC-nick, niet de XMPP-resource.** De MUC-nick moet expliciet worden doorgegeven aan `XmppKeyExchange` (of afgeleid uit de bound JID's localpart, zoals `_nickFrom` dat doet). Vergelijk dan `nick == ownMucNick`. 2. **Beter:** track de MUC-nick als een expliciete parameter op `XmppKeyExchange` (net als `XmppMuc` die heeft). De nick is bekend bij join-tijd en heeft niets met de bound JID te maken. 3. **Nog beter:** daal de eigen-echo-check af op `sealed.senderDevice == _e2ee.deviceId` (dat doet `handleDevicePresence` al op regel 210). Dat is betrouwbaarder dan een nick-vergelijking en heeft geen MUC-nick nodig. ### Locatie - `lib/xmpp/xmpp_key_exchange.dart` regels 252, 275–283 (`_isOwnPresence`) - `lib/widgets/dialogs/xmpp_test_connection_dialog.dart` regels 94, 116–121 (`_nickFrom` — toont hoe de nick werkelijk wordt afgeleid) ### Severity MEDIUM — de eigen-echo-detectie is defect; de randcase kan een deelnemer blokkeren.
brenno 2026-08-09 20:56:25 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#1415
No description provided.