1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-10 11:25:00 -05:00
xeps/xep-0384.xml
2020-03-08 13:07:09 +01:00

554 lines
35 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY content "&lt;content/&gt;">
<!ENTITY payload "&lt;payload/&gt;">
<!ENTITY % ents SYSTEM "xep.ent">
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>OMEMO Encryption</title>
<abstract>This specification defines a protocol for end-to-end encryption in one-to-one chats, as well as group chats where each participant may have multiple clients per account.</abstract>
&LEGALNOTICE;
<number>0384</number>
<status>Deferred</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0163</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>OMEMO</shortname>
<author>
<firstname>Andreas</firstname>
<surname>Straub</surname>
<email>andy@strb.org</email>
<jid>andy@strb.org</jid>
</author>
<revision>
<version>0.3.0</version>
<date>2018-07-31</date>
<initials>egp</initials>
<remark><p>Make examples show items published to the id "current", as per <cite>XEP-0060</cite> §12.20.</p></remark>
</revision>
<revision>
<version>0.2.2</version>
<date>2018-11-03</date>
<initials>pep</initials>
<remark>Fix a bunch of typos, batch-style.</remark>
</revision>
<revision>
<version>0.2.1</version>
<date>2018-05-21</date>
<initials>mb</initials>
<remark>Fix attribute names in schema</remark>
</revision>
<revision>
<version>0.2</version>
<date>2017-06-02</date>
<initials>dg</initials>
<remark>
<p>Depend on SignalProtocol instead of Olm.</p>
<p>Changed to eu.siacs.conversations.axolotl Namespace which is currently used in the wild</p>
</remark>
</revision>
<revision>
<version>0.1</version>
<date>2016-12-07</date>
<initials>XEP Editor: ssw</initials>
<remark><p>Initial version approved by the council.</p></remark>
</revision>
<revision>
<version>0.0.2</version>
<date>2016-09-22</date>
<initials>ssw, dg</initials>
<remark><p>Depend on Olm instead of Axolotl.</p></remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2015-10-25</date>
<initials>as</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<section2 topic='Motivation' anchor='intro-motivation'>
<p>
There are two main end-to-end encryption schemes in common use in the XMPP
ecosystem, Off-the-Record (OTR) messaging (&xep0364;) and OpenPGP
(&xep0027;). Older OTR versions have had significant usability drawbacks for inter-client
mobility. As OTR sessions existed between exactly two clients, the chat
history would not be synchronized across other clients of the involved
parties. Furthermore, OTR chats were only possible if both participants were
online at the same time, due to how the rolling key agreement scheme of OTR
worked. Some of those problems have been addressed in OTRv4.
OpenPGP, while not suffering from these mobility issues, does not
provide any kind of forward secrecy and is vulnerable to replay attacks.
Additionally, PGP over XMPP uses a custom wireformat which is defined by
convention rather than standardization, and involves quite a bit of
external complexity.
</p>
<p>
This XEP defines a protocol that leverages the Double Ratchet Algorithm to provide
multi-end to multi-end encryption, allowing messages to be synchronized
securely across multiple clients, even if some of them are offline.
The Double Ratched protocol is based on work by Trevor Perrin
and Moxie Marlinspike and was first published as the Axolotl protocol.
The specification for the protocol is available in the public domain.
</p>
</section2>
<section2 topic='Overview' anchor='intro-overview'>
<p>
The general idea behind this protocol is to maintain separate,
long-standing Double Ratchet-encrypted sessions with each device of each contact
(as well as with each of our other devices), which are used as secure key
transport channels. In this scheme, each message is encrypted with a
fresh, randomly generated encryption key. An encrypted header is added to
the message for each device that is supposed to receive it. These headers
simply contain the key that the payload message is encrypted with, and
they are separately encrypted using the session corresponding to the
counterpart device. The encrypted payload is sent together with the
headers as a &lt;message&gt; stanza. Individual recipient devices can
decrypt the header item intended for them, and use the contained payload
key to decrypt the payload message.
</p>
<p>
As the encrypted payload is common to all recipients, it only has to be
included once, reducing overhead. Furthermore, SignalProtocolss transparent handling
of messages that were lost or received out of order, as well as those sent
while the recipient was offline, is maintained by this protocol. As a
result, in combination with &xep0280; and &xep0313;, the desired property
of inter-client history synchronization is achieved.
</p>
<p>
While in the future a dedicated key server component could be used to distribute
key material for session creation, the current specification relies on PEP to publish
and acquire key bundles.
</p>
</section2>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<ul>
<li>Provide forward secrecy</li>
<li>Ensure chat messages can be deciphered by all (capable) clients of both parties</li>
<li>Be usable regardless of the participants' online statuses</li>
<li>Provide a method to exchange auxilliary keying material. This could for example be used to secure encrypted file transfers.</li>
</ul>
</section1>
<section1 topic='Glossary' anchor='glossary'>
<section2 topic='General Terms' anchor='glossary-general'>
<dl>
<di><dt>Device</dt><dd>A communication end point, i.e. a specific client instance</dd></di>
<di><dt>OMEMO element</dt><dd>An &lt;encrypted&gt; element in the urn:xmpp:omemo:1 namespace.</dd></di>
<di><dt>MessageElement</dt><dd>An OMEMO element that contains a chat message. Its &lt;payload&gt;, when decrypted, corresponds to a &lt;message&gt;'s &lt;body&gt;.</dd></di>
<di><dt>Bundle</dt><dd>A collection of publicly accessible data that can be used to build a session with a device, namely its public IdentityKey, a signed PreKey with corresponding signature, and a list of (single use) PreKeys.</dd></di>
<di><dt>rid</dt><dd>The device id of the intended recipient of the containing &lt;key&gt;</dd></di>
<di><dt>sid</dt><dd>The device id of the sender of the containing OMEMO element</dd></di>
</dl>
</section2>
<section2 topic='SignalProtocol-specific' anchor='glossary-signalprotocol'>
<dl>
<di><dt>IdentityKey</dt><dd>Per-device public/private key pair used to authenticate communications</dd></di>
<di><dt>PreKey</dt><dd>A Diffie-Hellman public key, published in bulk and ahead of time</dd></di>
<di><dt>PreKeySignalMessage</dt><dd>An encrypted message that includes the initial key exchange. This is used to transparently build sessions with the first exchanged message.</dd></di>
<di><dt>SignalMessage</dt><dd>An encrypted message</dd></di>
</dl>
</section2>
</section1>
<section1 topic='Protocol Definition' anchor='protocol'>
<section2 topic='Overview' anchor='protocol-overview'>
<p>
This protocol uses the DoubleRatchet encryption mechanism in conjunction with the X3DH key exchange. The following section provides detailed technical information about the protocol that should be sufficient to build a compatible OMEMO implementation. Readers who do not intend to build an OMEMO-compatible library can safely skip this section, relevant details are repeated where needed.
</p>
</section2>
<section2 topic='Key Exchange' anchor='protocol-key_exchange'>
<p>
The X3DH key exchange is specified <link url="https://signal.org/docs/specifications/x3dh/">here</link> and placed under the public domain. OMEMO uses this key exchange mechanism with the following parameters/settings:
</p>
<dl>
<di><dt>curve</dt><dd>X25519</dd></di>
<di><dt>hash function</dt><dd>SHA-256</dd></di>
<di><dt>info string</dt><dd>&quot;OMEMO X3DH&quot;</dd></di>
<di><dt>byte-encoding of the public keys</dt><dd>the default as used by most crypto libraries TODO</dd></di>
<di><dt>signed pre-key rotation period</dt><dd>Signed pre-keys SHOULD be rotated periodically once a week to once a month. A faster or slower rotation period should not be required.</dd></di>
<di><dt>time to keep the private key of the old signed pre-key after rotating it</dt><dd>The private key of the old signed pre-key SHOULD be kept for another rotation period as defined above, to account for delayed messages using the old signed pre-key.</dd></di>
<di><dt>number of pre-keys to provide in the bundle</dt><dd>The bundle SHOULD always contain around 100 pre-keys.</dd></di>
<di><dt>minimum number of pre-keys to provide in the bundle</dt><dd>The bundle MUST always contain at least 25 pre-keys.</dd></di>
<di><dt>associated data</dt><dd>The associated data is created by concatenating the identity keys of Alice and Bob: <tt>AD = Encode(IK_A) || Encode(IK_B)</tt></dd></di>
<di><dt>XEdDSA</dt><dd>To reduce the amount of bytes that have to be transferred, the key exchange uses <link url="https://signal.org/docs/specifications/xeddsa/">XEdDSA</link> on curves X25519/Ed25519 (aka XEd25519) to derive signing keys from encryption keys.</dd></di>
</dl>
</section2>
<section2 topic='Double Ratchet' anchor='protocol-double_ratchet'>
<p>NOTE: <tt>OMEMOMessage.proto</tt> and <tt>OMEMOAuthenticatedMessage.proto</tt> refer to the protobuf structures as defined <link url="#protobuf-schema">here</link>.</p>
<p>
The DoubleRatchet protocol is specified <link url="https://signal.org/docs/specifications/doubleratchet/">here</link> and placed under the public domain. OMEMO uses this protocol with the following parameters/settings:
</p>
<dl>
<di><dt>ratchet initialization</dt><dd>The double ratchet is initialized using the shared secret, ad and public keys as yielded by the X3DH key exchange, as explained in the double ratchet specification.</dd></di>
<di><dt>MAX_SKIP</dt><dd>It is RECOMMENDED to keep around 1000 skipped message keys.</dd></di>
<di><dt>deletion policy for skipped message keys</dt><dd>Skipped message keys MUST be stored until MAX_SKIP message keys are stored. At that point, keys are discarded on a LRU basis to make space for new message keys. Implementations SHOULD not keep skipped message keys around forever, but discard old keys on a different implementation-defined policy. It is RECOMMENDED to base this policy on deterministic events rather than time.</dd></di>
<di><dt>authentication tag truncation</dt><dd>Authentication tags are truncated to 16 bytes/128 bits.</dd></di>
<di><dt>CONCAT(ad, header)</dt><dd><tt>CONCAT(ad, header) = ad || OMEMOMessage.proto(header)</tt> NOTE: the <tt>OMEMOMessage.proto</tt> is initialized without the ciphertext, which is optional. NOTE: Implementations are not strictly required to return a parseable byte array here, as the unpacked/parsed data is required later in the protocol.</dd></di>
<di><dt>KDF_RK(rk, dh_out)</dt><dd>HKDF-SHA-256 using the rk as HKDF salt, dh_out as HKDF input material and &quot;OMEMO Root Chain&quot; as HKDF info.</dd></di>
<di><dt>KDF_CK(ck)</dt><dd>HMAC-SHA-256 using ck as the HMAC key, a single byte constant <tt>0x01</tt> as HMAC input to produce the next message key and a single byte constant <tt>0x02</tt> as HMAC input to produce the next chain key.</dd></di>
<di><dt>ENCRYPT(mk, plaintext, associated_data)</dt><dd>
The encryption step uses authenticated encryption consisting of AES-256-CBC with HMAC-SHA-256.
<ol>
<li>Use HKDF-SHA-256 to generate 80 bytes of output from the message key by providing mk as HKDF input, 256 zero-bits as HKDF salt and &quot;OMEMO Message Key Material&quot; as HKDF info.</li>
<li>Divide the HKDF output into a 32-byte encryption key, a 32-byte authentication key and a 16 byte IV.</li>
<li>Encrypt the plaintext (which is a 16 bytes key as specified <link url="#protocol-message_encryption">here</link>) using AES-256-CBC with PKCS#7 padding, using the encryption key and IV derived in the previous step.</li>
<li>Split the associated data as returned by <tt>CONCAT</tt> into the original ad and the <tt>OMEMOMessage.proto</tt> structure.</li>
<li>Add the ciphertext to the <tt>OMEMOMessage.proto</tt> structure.</li>
<li>Serialize the ad and the <tt>OMEMOMessage.proto</tt> structure into a parseable byte array by concatenating ad and the serialized protobuf structure.</li>
<li>Calculate the HMAC-SHA-256 using the authentication key and the input material as derived in the steps above.</li>
<li>Put the <tt>OMEMOMessage.proto</tt> structure and the HMAC into a new <tt>OMEMOAuthenticatedMessage.proto</tt> structure.</li>
</ol>
</dd></di>
</dl>
</section2>
<section2 topic='Message Encryption' anchor='protocol-message_encryption'>
<p>
The contents are encrypted and authenticated using a combination of AES-256-CBC and HMAC-SHA-256.
</p>
<ol>
<li>Generate 16 bytes of cryptographically secure random data, called <tt>key</tt> in the remainder of this algorithm.</li>
<li>Encrypt this key using the double ratchet as specified above, once for each intended recipient.</li>
<li>Use HKDF-SHA-256 to generate 80 bytes of output from the key by providing the key as HKDF input, 256 zero-bits as HKDF salt and &quot;OMEMO Payload&quot; as HKDF info.</li>
<li>Divide the HKDF output into a 32-byte encryption key, a 32-byte authentication key and a 16 byte IV.</li>
<li>Encrypt the plaintext using AES-256-CBC with PKCS#7 padding, using the encryption key and IV derived in the previous step.</li>
<li>Calculate the HMAC-SHA-256 using the authentication key and the ciphertext from the previous steps.</li>
</ol>
</section2>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Setup' anchor='usecases-setup'>
<p>
The first thing that needs to happen if a client wants to start using
OMEMO is they need to generate an IdentityKey and a Device ID. The
IdentityKey is a &curve25519; public/private Key pair. The Device ID is a
randomly generated integer between 1 and 2^31 - 1.
</p>
</section2>
<section2 topic='Discovering peer support' anchor='usecases-discovering'>
<p>In order to determine whether a given contact has devices that support OMEMO, the devicelist node in PEP is consulted. Devices MUST subscribe to 'urn:xmpp:omemo:1:devices' via PEP, so that they are informed whenever their contacts add a new device. They MUST cache the most up-to-date version of the devicelist.</p>
<example caption='Devicelist update received by subscribed clients'><![CDATA[
<message from='juliet@capulet.lit'
to='romeo@montague.lit'
type='headline'
id='update_01'>
<event xmlns='http://jabber.org/protocol/pubsub#event'>
<items node='urn:xmpp:omemo:1:devices'>
<item id='current'>
<devices xmlns='urn:xmpp:omemo:1'>
<device id='12345' />
<device id='4223' />
</devices>
</item>
</items>
</event>
</message>]]></example>
</section2>
<section2 topic='Announcing support' anchor='usecases-announcing'>
<section3 topic='Device list' anchor='devices'>
<p>In order for other devices to be able to initiate a session with a given device, it first has to announce itself by adding its device ID to the devicelist PEP node. </p>
<p>It is RECOMMENDED to set the access model of the urn:xmpp:omemo:1:devices node to open to give entities without presence subscription read access to the devices and allow them to establish an OMEMO session. Not having presence subscription is a common occurrence on the first few messages between two contacts and can also happen fairly frequently in group chats as not every participant had prior communication with every other participant.</p>
<p>The access model can be changed efficiently by using publish-options.</p>
<example caption='Adding the own device ID to the list'><![CDATA[
<iq from='juliet@capulet.lit' type='set' id='announce1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:omemo:1:devices'>
<item id='current'>
<devices xmlns='urn:xmpp:omemo:1'>
<device id='12345' />
<device id='4223' />
<device id='31415' />
</devices>
</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>]]></example>
<p>NOTE: as per <link url='https://xmpp.org/extensions/xep-0060.html#impl-singleton'><cite>XEP-0060</cite> §12.20</link>, it is RECOMMENDED for the publisher to specify an ItemID of "current" to ensure that the publication of a new item will overwrite the existing item.</p>
<p>This step presents the risk of introducing a race condition: Two devices might simultaneously try to announce themselves, unaware of the other's existence. The second device would overwrite the first one. To mitigate this, devices MUST check that their own device ID is contained in the list whenever they receive a PEP update from their own account. If they have been removed, they MUST reannounce themselves.</p>
</section3>
<section3 topic='Bundles' anchor='bundles'>
<p>Furthermore, a device MUST publish its IdentityKey, a signed PreKey, and a list of PreKeys. This tuple is called a bundle. Bundles are maintained as multiple items in a PEP node called urn:xmpp:omemo:1:bundles. Each bundle MUST be stored in a seperate item. The item id MUST be set to the device id.</p>
<p>A bundle is an element called 'bundle' in the 'urn:xmpp:omomo:1' namespace. It has a child element called spk that contains the signed PreKey as base64 encoded data, a child element called spks that contains the signed PreKey signature as base64 encoded data and a child element called ik that contains the identity key as base64 encoded data. PreKeys are multiple elements called pk that each contain one PreKey as base64 encoded data. PreKeys are wrapped in an element called prekeys which is a child of the bundle element.</p>
<p>The bundle element MAY contain an attribute called label, which is a user defined string describing the device that published that bundle.</p>
<p>When publishing bundles a client MUST make sure that the 'urn:xmpp:omemo:1' node is configured to store multiple items. This is not the default with &xep0163;. If the node doesnt exist yet it can be configured on the fly by using publish-options as described in <link url="https://xmpp.org/extensions/xep-0060.html#publisher-publish-options"><cite>XEP-0060</cite> §7.1.5</link>. The value for 'pubsub#max_items' in publish_options MUST be set to 'max'. If the node did exist and was configured differently the bundle publication will fail. Clients MUST then reconfigure the node as described in <link url="https://xmpp.org/extensions/xep-0060.html#owner-configure"><cite>XEP-0060</cite> §8.2</link>.</p>
<example caption='Publishing bundle information'><![CDATA[
<iq from='juliet@capulet.lit' type='set' id='annouce2'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:omemo:1:bundles'>
<item id='31415'>
<bundle xmlns='urn:xmpp:omemo:1'
label='My desktop client'>
<spk id='0'>BASE64ENCODED</spk>
<spks>BASE64ENCODED</spks>
<ik>BASE64ENCODED</ik>
<prekeys>
<pk id='0'>BASE64ENCODED</pk>
<pk id='1'>BASE64ENCODED</pk>
<!-- … -->
<pk id='99'>BASE64ENCODED</pk>
</prekeys>
</bundle>
</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#max_items'>
<value>max</value>
</field>
</x>
</publish-options>
</pubsub>
</iq>]]></example>
<p>As with the 'urn:xmpp:omemo:1:devices' node it is RECOMMENDED to set the access model of the 'urn:xmpp:omemo:1:bundles' to open. Clients that do not adhere to the recommended access model (and for example want to stick to the default 'presence') are highly encouraged to configure the same access model for 'urn:xmpp:omemo:1:devices' and 'urn:xmpp:omemo:1:bundles', otherwise remote entities might end up in a situation where they are able to retrieve the device list but not the bundle or vice versa.</p>
<p>The access model can be changed efficiently by using publish-options.</p>
<example caption='Publishing bundle information with an open access model'><![CDATA[
<iq from='juliet@capulet.lit' type='set' id='annouce2'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:omemo:1:bundles'>
<item id='31415'>
<bundle xmlns='urn:xmpp:omemo:1'>
<!-- … -->
</bundle>
</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#max_items'>
<value>max</value>
</field>
<field var='pubsub#access_model'>
<value>open</value>
</field>
</x>
</publish-options>
</pubsub>
</iq>]]></example>
</section3>
</section2>
<section2 topic='Building a session' anchor='usecases-building'>
<p>In order to build a session with a device, their bundle information is fetched.</p>
<example caption="Fetching a device's bundle information"><![CDATA[
<iq type='get'
from='romeo@montague.lit'
to='juliet@capulet.lit'
id='fetch1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:omemo:1:bundles'>
<item id='31415'/>
<items>
</pubsub>
</iq>]]></example>
<p>A random preKeyPublic entry is selected, and used to build a SignalProtocol session.</p>
</section2>
<section2 topic='Ending a session' anchor='usecases-ending'>
<p>In order to signal a contact that you like to terminate a session, your
device MUST send an &lt;terminate&gt; element to all intended recipient devices
inside an encrypted stanza. A user or client MAY tag the element with a
reason. If a device is receiving a stanza containing a &lt;terminate&gt; element,
it MUST show an information that the peer has ended the session. To prevent
that the user is accidentally sending plaintext messages, the client MUST
block all outgoing message until the user switched to plaintext.</p>
</section2>
<section2 topic='Sending a message' anchor='usecases-messagesend'>
<p>
In order to send a chat message, extension elements that are deemed sensible first have to be
encrypted. For this purpose, extensions that are only intended to be accessible to the recipient
are placed inside a &xep0420; &content; element, which is then encrypted using a message key.
For this reason OMEMO defines its own SCE profile.
</p>
<section3 topic='SCE Profile' anchor='sce'>
<p>
An OMEMO SCE &content; element
</p>
<ul>
<li>MUST contain an &lt;rpad/&gt; affix element. This is used to prevent an attacker from gaining insights about the content of a message based on the length of the ciphertext.</li>
<li>MAY contain a &lt;time/&gt; affix element. This can be used to prevent the server from modifying the order in which messages from different sending devices have been sent.</li>
<li>SHOULD contain a &lt;from/&gt; affix element.</li>
<li>MUST contain a &lt;to/&gt; affix element whenever a message is sent via a group chat (MUC/MIX). This is used to prevent the server from silently converting a group message into a private message and vice versa.</li>
</ul>
</section3>
<p>
The ciphertext that is the encrypted &content; element is then encoded using base64 and placed as text content into the &payload; element.
</p>
<example caption="Plaintext SCE content element"><![CDATA[
<content xmlns='urn:xmpp:sce:0'>
<payload>
<body xmlns='jabber:client'>
Hello World!
</body>
</payload>
<rpad>...</rpad>
<from jid='romeo@montague.lit'/>
</content>]]>
</example>
<example caption="Sending a message"><![CDATA[
<message to='juliet@capulet.lit' from='romeo@montague.lit' id='send1'>
<encrypted xmlns='urn:xmpp:omemo:1'>
<header sid='27183'>
<keys jid='juliet@capulet.lit'>
<key rid='31415'>BASE64ENCODED...</key>
</keys>
<keys jid='remeo@montague.lit'>
<key rid='1337'>BASE64ENCODED...</key>
<key prekey="true" rid='12321'>BASE64ENCODED...</key>
<!-- ... -->
</keys>
</header>
<payload>
-- MESSAGE-KEY-ENCRYPTED CONTENT ELEMENT --
</payload>
</encrypted>
<store xmlns='urn:xmpp:hints'/>
</message>]]></example>
</section2>
<section2 topic='Receiving a message' anchor='usecases-receiving'>
<p>When an OMEMO element is received, the client MUST check whether there is a &lt;keys&gt; element with a jid attribute matching its own bare jid and an inner &lt;key&gt; element with an rid attribute matching its own device ID. If this is not the case the message was not encrypted for this particular device and a warning message SHOULD be displayed instead. If such an element exists, the client checks whether the element's contents are a PreKeySignalMessage.</p>
<p>If this is the case, a new session is built from this received element. The client SHOULD then republish their bundle information, replacing the used PreKey, such that it won't be used again by a different client. If the client already has a session with the sender's device, it MUST replace this session with the newly built session. The client MUST delete the private key belonging to the PreKey after use.</p>
<p>If the element's contents are a SignalMessage, and the client has a session with the sender's device, it tries to decrypt the SignalMessage using this session. If the decryption fails or if the element's contents are not a SignalMessage either, the OMEMO element MUST be silently discarded.</p>
<p>If the OMEMO element contains a &lt;payload&gt;, it is an OMEMO message element. The client tries to decrypt the base64 encoded contents using the key and the authentication tag extracted from the &lt;key&gt; element. If the decryption fails, the client MUST silently discard the OMEMO message. If it succeeds, the decrypted contents are treated as the &lt;body&gt; of the received message.</p>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>Before publishing a freshly generated Device ID for the first time, a device MUST check whether that Device ID already exists, and if so, generate a new one.</p>
<p>Clients SHOULD NOT immediately fetch the bundle and build a session as soon as a new device is announced. Before the first message is exchanged, the contact does not know which PreKey has been used (or, in fact, that any PreKey was used at all). As they have not had a chance to remove the used PreKey from their bundle announcement, this could lead to collisions where both Alice and Bob pick the same PreKey to build a session with a specific device. As each PreKey SHOULD only be used once, the party that sends their initial PreKeySignalMessage later loses this race condition. This means that they think they have a valid session with the contact, when in reality their messages MAY be ignored by the other end. By postponing building sessions, the chance of such issues occurring can be drastically reduced. It is RECOMMENDED to construct sessions only immediately before sending a message. </p>
<p>As there are no explicit error messages in this protocol, if a client does receive a PreKeySignalMessage using an invalid PreKey, they SHOULD respond with a normal OMEMO encrypted message with a potentially empty SCE payload. By building a new session with the original sender this way, the invalid session of the original sender will get overwritten with this newly created, valid session.</p>
<p>If a PreKeySignalMessage is received as part of a &xep0313; catch-up and used to establish a new session with the sender, the client SHOULD postpone deletion of the private key corresponding to the used PreKey until after MAM catch-up is completed. If this is done, the client MUST then also send a normal OMEMO encrypted message with an empty SCE payload before sending any payloads using this session, to trigger re-keying. (as above) This practice can mitigate the previously mentioned race condition by preventing message loss.</p>
<p>As the asynchronous nature of OMEMO allows decryption at a later time to currently offline devices client SHOULD include a &xep0334; &lt;store /&gt; hint in their OMEMO messages. Otherwise, server implementations of &xep0313; will generally not retain OMEMO messages, since they do not contain a &lt;body /&gt;</p>
<p>When a client receives the first message for a given ratchet key with a counter of 53 or higher, it MUST send a heartbeat message. Heartbeat messages are normal OMEMO encrypted messages where they SCE payload does not include any elements. These heartbeat messages cause the ratchet to forward, thus consequent messages will have the counter restarted from 0.</p>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<!-- TODO: I think this is still true? -->
<p>
The SignalProtocol-library uses a trust model that doesn't work very well with
OMEMO. For this reason it may be desirable to have the library consider all
keys trusted, effectively disabling its trust management. This makes it
necessary to implement trust handling oneself.
</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Clients MUST NOT use a newly built session to transmit data without user intervention. If a client were to opportunistically start using sessions for sending without asking the user whether to trust a device first, an attacker could publish a fake device for this user, which would then receive copies of all messages sent by/to this user. A client MAY use such "not (yet) trusted" sessions for decryption of received messages, but in that case it SHOULD indicate the untrusted nature of such messages to the user.</p>
<p>When prompting the user for a trust decision regarding a key, the client SHOULD present the user with a fingerprint in the form of a hex string, QR code, or other unique representation, such that it can be compared by the user.</p>
<p>While it is RECOMMENDED that clients postpone private key deletion until after MAM catch-up and this standards mandates that clients MUST NOT use duplicate-PreKey sessions for sending, clients MAY delete such keys immediately for security reasons. For additional information on potential security impacts of this decision, refer to <note>Menezes, Alfred, and Berkant Ustaoglu. "On reusing ephemeral keys in Diffie-Hellman key agreement protocols." International Journal of Applied Cryptography 2, no. 2 (2010): 154-158.</note>.</p>
<p>
In order to be able to handle out-of-order messages, the SignalProtocol stack has to
cache the keys belonging to "skipped" messages that have not been seen yet.
It is up to the implementor to decide how long and how many of such keys to
keep around.
</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with the Internet Assigned Numbers Authority (IANA). </p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<section2 topic='Protocol Namespaces' anchor='namespaces'>
<p>This specification defines the following XMPP namespaces:</p>
<ul>
<li>urn:xmpp:omemo:1</li>
</ul>
</section2>
<section2 topic='Protocol Versioning' anchor='versioning'>
&NSVER;
</section2>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<code><![CDATA[
<xml version="1.0" encoding="utf8">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="eu.siacs.conversations.axolotl"
xmlns="eu.siacs.conversations.axolotl">
<xs:element name="encrypted">
<xs:element name="header">
<xs:attribute name="sid" type="xs:integer"/>
<xs:complexType>
<xs:sequence>
<xs:element name="key" type="xs:base64Binary" maxOccurs="unbounded">
<xs:attribute name="rid" type="xs:integer" use="required"/>
<xs:attribute name="prekey" type="xs:boolean"/>
</xs:element>
<xs:element name="iv" type="xs:base64Binary"/>
</xs:complexType>
</xs:element>
<xs:element name="payload" type="xs:base64Binary" minOccurs="0"/>
</xs:element>
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="device" maxOccurs="unbounded">
<xs:attribute name="id" type="integer" use="required"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="bundle">
<xs:complexType>
<xs:sequence>
<xs:element name="signedPreKeyPublic" type="base64Binary">
<xs:attribute name="signedPreKeyId" type="integer"/>
</xs:element>
<xs:element name="signedPreKeySignature" type="base64Binary"/>
<xs:element name="identityKey" type="base64Binary"/>
<xs:element name="prekeys">
<xs:complexType>
<xs:sequence>
<xs:element name="preKeyPublic" type="base64Binary" maxOccurs="unbounded">
<xs:attribute name="preKeyId" type="integer" use="required"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
]]></code>
</section1>
<section1 topic='Protobuf Schema' anchor='protobuf-schema'>
<code><![CDATA[
message OMEMOMessage {
bytes dh_pub;
uint32 n;
uint32 pn;
optional bytes ciphertext;
}
message OMEMOAuthenticatedMessage {
bytes omemo_message;
bytes mac;
}
]]></code>
</section1>
<section1 topic='Acknowledgements' anchor='ack'>
<p>Big thanks to Daniel Gultsch for mentoring me during the development of this protocol. Thanks to Thijs Alkemade and Cornelius Aschermann for talking through some of the finer points of the protocol with me. And lastly I would also like to thank Sam Whited, Holger Weiss, and Florian Schmaus for their input on the standard.</p>
</section1>
</xep>