Search code examples
ejabberdsmackmultiuserchatomemo

Sending messages to unknown users in XMPP MultiUserChat with OMEMO encryption


I'm trying to build a MUC platform with OMEMO encryption to be used on an Android app. I'm using Ejabberd (v17.11) and Smack library (v4.2.1).

MUC rooms are persistent and they allow_subscription for Muc/Sub support, for offline messages.

When a client starts a new room as 'owner' and adds 'member's from his roster; all the clients join the room and everything seem fine. The owner can send messages to the group and it is delivered to every member.

But when a group member tries to send a message, if he doesn't 'know' all the members of the group (if they are not in his roster) he cannot send message!

I found out that, when sending OMEMO message to the group, it is necessary to encrypt the message separately for every member and this necessitates getting every members' devicelist!

On this step:

mOmemoManager.encrypt(muc, msgBody);

It tries to encrypt for all recipients but fetching an unknown user's device list causes crash.

SENT:

<iq to='[email protected]' id='141' type='get'><query xmlns='http://jabber.org/protocol/disco#info' node='eu.siacs.conversations.axolotl.devicelist'></query></iq>

RECV:

<iq xml:lang='en' to='[email protected]/mobile' from='[email protected]' type='error' id='141'><query node='eu.siacs.conversations.axolotl.devicelist' xmlns='http://jabber.org/protocol/disco#info'/><error code='407' type='auth'><subscription-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Not subscribed</text></error></iq>

Smack's error:

Could not fetch device list of [email protected]: .....
XMPPError: subscription-required - auth

So, how I can solve this? In chat groups every user don't have to meet each other. Should I add everyone to everyone's roster when they come together on a group?

Or is this something about room affiliations or roles?

Or something about Ejabberd configuration?

[{title,<<"groupName">>},  
{allow_query_users,true},  
{allow_private_messages,true},
{allow_private_messages_from_visitors,anyone},
{allow_visitor_status,true},  
{allow_visitor_nickchange,true},  
{public,false},  
{public_list,false},  
{persistent,true},  
{moderated,true},  
{members_by_default,true},  
{members_only,true},  
{allow_user_invites,true},
{anonymous,false},
{logging,false},
{allow_voice_requests,true},
{allow_subscription,true},
{mam,true},
{presence_broadcast,[moderator,participant,visitor]},
{voice_request_min_interval,1800},
{vcard,<<>>},
{captcha_whitelist,[]},
{affiliations,[{{<<"user1">>,<<"server.com">>,<<>>},{member,<<>>}},                 {{<<"user2">>,<<"server.com">>,<<>>},{owner,<<>>}},                 {{<<"user3">>,<<"server.com">>,<<>>},{member,<<>>}}]},
{subject,[]},
{subject_author,<<>>}]

Solution

  • OMEMO requires the sender to be able to read the recipients OMEMO pubsub node. This is necessary to fetch the recipients preKey bundle to build a session.

    Modern implementations configure the OMEMO pubsub node to be public - there is also an ejabberd config to force this for legacy clients.

    Most client implementations of OMEMO therefore restrict the encryption feature to be available in private group chats only. In this scenario all contacts are in each others rosters and have access to each others OMEMO nodes. Encrypting publicly available group chats doesn't make sense anyways as an attacker could simply join the chat in order to read messages.

    If you want to configure your OMEMO pubsub nodes to be public from within your client, take a look at how smack-openpgp does change to access model.