Difference between revisions of "Tech pages/OMEMO/Quickstart"

From XMPP WIKI
Jump to navigation Jump to search
m (Fix another link.)
 
(4 intermediate revisions by 3 users not shown)
Line 1: Line 1:
PubSub—and by inheritence PEP—supports [https://xmpp.org/extensions/xep-0060.html#accessmodels|five access models] for a node. This document describes an algorithm for setting the access model of a PEP node safely and securely with minimal round trip times. Especially in a scenario where a node is supposed to be private, a publish first and configure access model later approach must be avoided as this could leak information in between those requests.
This is a short tutorial on how to get started with OMEMO. This is not to replace the XEP but to extend it and give you some clear steps to follow instead of a having to read through a formal specification.


===Publish with publish-options===
===Step-by-Step===
Assuming we want to publish <code><content xmlns="com.example.dummy"/></code> to a node called <code>com.example.dummy</code> that should be available to everyone and not just our contacts.
# Add <code>eu.siacs.conversations.axolotl.devicelist+notify</code> to your disco features. That will subscribe you to the device list updates of your contacts.
# On every login publish your bundle information. (Your publickey and pre keys.) Keep the used device id consistent. You have to republish this because you don't know if the server was restarted or might have otherwise lost the information.
# After publishing the information and getting an IQ-result back retrieve your own devicelist. (You might also get this automatically due to the subscription in step one but that might fail if you don't have one yet. Retrieving the list manually makes you know for sure.) If the device list does ''not'' contain your own device id publish the device list with your device id added. (Also deduplicate device ids in the list just for good measure and to counter act potential errors in other implementations)
# Since you subscribed to the device list you will now be receiving device ids from your contacts. Save the jid-device id tuples for later use. Each tuple will have an active flag. If a device id is no longer in the list you set it to inactive. If it re-appears later you set it to active again.
# Treat the device ids of your other devices the same.
# Due to bugs (or weird behaviour) in ejabberd you might not always get the device list from offline contacts. So before login you should restore the tuples from your own database. But incoming PEP events will always override the database. The restore from your database is only to have a fallback in case you don't get the PEP list.
# When you first write a message to someone look up all active device tuples and create sessions with them by retrieving the corresponding bundles. (Explicitly query the nodes <code>eu.siacs.conversations.bundles:$id</code>.)
# On subsequent messages you have to check if you already have sessions for all device tuples and only query the bundle for missing sessions.
# Retrieving a message from a device id will set that device id to active again.


'''Warning:''' We must ensure that the server annouces the namespace <code>http://jabber.org/protocol/pubsub#publish-options</code> on the account jid. Otherwise we risk the server just ignoring the <code>publish-options</code> in the following request which would be especially dangerous when trying to set a node to <code>whitelist</code>.
===Trust===
Every session has a fingerprint. (The identity key) Offer the user the abiltiy to decide wether to trust each fingerprint. You only send messages to trusted fingerprints where the device id is active. If there are no trusted fingerprints display a dialog offering the user to trust them. If there are new fingerprints (from new devices) offer the user to trust them. So essentially every jid-deviceid-fingerprint tuple has two values (inactive/active and undecided/trusted/untrusted)


<pre>
A good trust model to implement is [https://gultsch.de/trust.html Blind Trust Before Verification (BTBV)]
<iq to="account@server.tld" type="set" id="1">
  <pubsub xmlns="http://jabber.org/protocol/pubsub">
    <publish node="com.example.dummy">
      <item>
        <content xmlns="com.example.dummy"/>
      <item>
    </publish>
    <publish-options>
      <x xmlns='jabber:x:data' type='submit'>
        <field var='FORM_TYPE' type='hidden'>
          <value>http://jabber.org/protocol/pubsub#publish-options</value>
        </field>
        <field var='pubsub#access_model'>
          <value>open</value>
        </field>
      </x>
    </publish-options>
  <pubsub>
</iq>
</pre>
When parsing the response we have differentiate three cases:
# The server responses with <code>type="result"</code>. This happens either when the node was previously configured to be <code>open</code> or when the node did not exist, in which case the server must create that node automatically with the given access model.
# The server responses with <code>type="error"</code> and a pubsub error of <code>precondition-not-met</code>. (The <code>error</code> element will have a child element called <code>precondition-not-met</code>. ([https://github.com/siacs/Conversations/blob/9a57673130cab2794e4ea46b77826dbe962d7046/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java#L521-L522|Example code in Conversations])
# The server responses with another, more generic error. The handling of that is out of scope of this document.


In case of (2) we will continue with the node-configuration
===Further Reading / Background===
Some explanatory articles about the encryption behind the OMEMO protocol can be found below:
* [https://blog.jabberhead.tk/2019/04/04/shaking-hands-with-omemo-x3dh/ Shaking Hands With OMEMO - About the X3DH Handshake]
* [https://blog.jabberhead.tk/2019/04/15/closer-look-at-the-double-ratchet/ Closer Look at the Double Ratchet]


===Node configuration===
Some hints about possible pitfalls:
Node configuration is a two step process that involves downloading the current node configuration and setting a new one with a changed access model. The detailed process is described in [https://xmpp.org/extensions/xep-0060.html#owner-configure|XEP-0060 section 8.2].
* [https://blog.jabberhead.tk/2019/12/13/pitfalls-for-omemo-implementations-part-1-inactive-devices/ Pitfalls for OMEMO Implementations - Part 1: Inactive Devices]
Essentially the following request will return a data form which can be resubmitted after changing the value of <code>pubsub#access_model</code>.
<pre>
<iq type="get" to="account@server.tld" id="2">
  <pubsub xmlns="http://jabber.org/protocol/pubsub">
    <configure node="com.example.dummy"/>
  </pubsub>
</iq>
</pre>
===Retry step one===
After a successful node configuration the client should retry to publish with publish-options. Appropriate steps should be taken to not end up in an infinite loop in case the server is misbehaving. This primarily means the publication should only be retried once.
 
===OMEMO considerations===
Since there is no security risk involved in ''not'' changing the access model to open OMEMO clients should work with servers that support publish-options and with servers that do not. Changing the access model should be considered optional but highly recommended.
Support for publish-options is just starting to roll out to servers while support for node configuration has been around for quite some time in ejabberd. When setting the access model to ''open'' publish-options is merely a traffic optimization. One could theoretically reconfigure the node after every publish. However that creates extra traffic and does not work when setting the access mode to whitelist due to the security risks outlined in the first paragraph. In an attempt to force server operators to offer publish-options ASAP (and thus opening the door for things like Bookmarks in private pep nodes) it is not advisable to go down that road.

Latest revision as of 12:48, 15 April 2023

This is a short tutorial on how to get started with OMEMO. This is not to replace the XEP but to extend it and give you some clear steps to follow instead of a having to read through a formal specification.

Step-by-Step

  1. Add eu.siacs.conversations.axolotl.devicelist+notify to your disco features. That will subscribe you to the device list updates of your contacts.
  2. On every login publish your bundle information. (Your publickey and pre keys.) Keep the used device id consistent. You have to republish this because you don't know if the server was restarted or might have otherwise lost the information.
  3. After publishing the information and getting an IQ-result back retrieve your own devicelist. (You might also get this automatically due to the subscription in step one but that might fail if you don't have one yet. Retrieving the list manually makes you know for sure.) If the device list does not contain your own device id publish the device list with your device id added. (Also deduplicate device ids in the list just for good measure and to counter act potential errors in other implementations)
  4. Since you subscribed to the device list you will now be receiving device ids from your contacts. Save the jid-device id tuples for later use. Each tuple will have an active flag. If a device id is no longer in the list you set it to inactive. If it re-appears later you set it to active again.
  5. Treat the device ids of your other devices the same.
  6. Due to bugs (or weird behaviour) in ejabberd you might not always get the device list from offline contacts. So before login you should restore the tuples from your own database. But incoming PEP events will always override the database. The restore from your database is only to have a fallback in case you don't get the PEP list.
  7. When you first write a message to someone look up all active device tuples and create sessions with them by retrieving the corresponding bundles. (Explicitly query the nodes eu.siacs.conversations.bundles:$id.)
  8. On subsequent messages you have to check if you already have sessions for all device tuples and only query the bundle for missing sessions.
  9. Retrieving a message from a device id will set that device id to active again.

Trust

Every session has a fingerprint. (The identity key) Offer the user the abiltiy to decide wether to trust each fingerprint. You only send messages to trusted fingerprints where the device id is active. If there are no trusted fingerprints display a dialog offering the user to trust them. If there are new fingerprints (from new devices) offer the user to trust them. So essentially every jid-deviceid-fingerprint tuple has two values (inactive/active and undecided/trusted/untrusted)

A good trust model to implement is Blind Trust Before Verification (BTBV)

Further Reading / Background

Some explanatory articles about the encryption behind the OMEMO protocol can be found below:

Some hints about possible pitfalls: