1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-21 16:55:07 -05:00

Merge XEP-0384 editorial changes

This commit is contained in:
Maxime “pep” Buquet 2020-03-26 16:32:40 +01:00
commit 8d5c240f39

View File

@ -173,14 +173,14 @@
</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 &xep0163; to publish
key material for session creation, the current specification relies on &xep0060; and &xep0163; to publish
and acquire key bundles.
</p>
</section2>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>It is a result of XMPP's federated nature that a message may pass more than just one server. Therefore it is in the users' interest to secure their communication from any intermediate host. End-to-end encryption is an efficient way to protect any data exchanged between sender and receiver against passive and active attackers such as servers and network nodes.</p>
<p>OMEMO is an end-to-end encryption protocol based on the Double Ratchet specified in section <link url="#protocol-double_ratchet">Double Ratchet</link>. It provides the following guarantees under the threat model described in the next section:</p>
<p>OMEMO is an end-to-end encryption protocol based on the Double Ratchet specified in section <link url='#protocol-double_ratchet'>Double Ratchet</link>. It provides the following guarantees under the threat model described in the next section:</p>
<ul>
<li>Confidentiality: Nobody else except sender and receiver is able to read the content of a message.</li>
<li>Perfect forward secrecy: Compromised key material does not compromise previous or future message exchanges.</li>
@ -221,28 +221,28 @@
</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:
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 little-endian encoding of the u-coordinate as specified <link url="http://www.ietf.org/rfc/rfc7748.txt">here</link> (this is the default way most crypto-libraries encode the public key).</dd></di>
<di><dt>byte-encoding of the public keys</dt><dd>The little-endian encoding of the u-coordinate as specified <link url='http://www.ietf.org/rfc/rfc7748.txt'>here</link> (this is the default way most crypto-libraries encode the public key).</dd></di>
<di><dt>signed PreKey rotation period</dt><dd>Signed PreKeys 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 PreKey after rotating it</dt><dd>The private key of the old signed PreKey SHOULD be kept for another rotation period as defined above, to account for delayed messages using the old signed PreKey.</dd></di>
<di><dt>number of PreKeys to provide in the bundle</dt><dd>The bundle SHOULD always contain around 100 PreKeys.</dd></di>
<di><dt>minimum number of PreKeys to provide in the bundle</dt><dd>The bundle MUST always contain at least 25 PreKeys.</dd></di>
<di><dt>associated data</dt><dd>The associated data is created by concatenating the IdentityKeys 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 build and verify signatures using encryption key pairs.</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 build and verify signatures using encryption key pairs.</dd></di>
</dl>
<p>
The key exchange is done just-in-time when sending the first message to a device. Thus, each key exchange message always also contains encrypted content as produced by the Double Ratchet encryption scheme below.
</p>
</section2>
<section2 topic='Double Ratchet' anchor='protocol-double_ratchet'>
<p>NOTE: <tt>OMEMOMessage.proto</tt>, <tt>OMEMOAuthenticatedMessage.proto</tt> and <tt>OMEMOKeyExchange.proto</tt> refer to the protobuf structures as defined <link url="#protobuf-schema">here</link>.</p>
<p>NOTE: <tt>OMEMOMessage.proto</tt>, <tt>OMEMOAuthenticatedMessage.proto</tt> and <tt>OMEMOKeyExchange.proto</tt> refer to the protobuf structures as defined <link url='#protobuf-schema'>here</link>.</p>
<p>
The Double Ratchet encryption scheme 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:
The Double Ratchet encryption scheme 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>
@ -257,7 +257,7 @@
<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 consists of a 32 bytes key and a 32 bytes HMAC 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>Encrypt the plaintext (which consists of a 32 bytes key and a 32 bytes HMAC 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>
@ -364,7 +364,7 @@
<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 and is provided by OMEMO libraries. Bundles are maintained as multiple items in a PEP node called <tt>&nsbundles;</tt>. 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 <tt>&ns;</tt> namespace. It has a child element called spk that contains the public part of 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 public part of the IdentityKey as base64 encoded data. PreKeys are multiple elements called pk that each contain the public part of one PreKey as base64 encoded data. PreKeys are wrapped in an element called prekeys which is a child of the bundle element. The spk and the pks are tagged with an id-attribute which is a positive integer that uniquely identifies the keys. The spk and the pks are considered separate, which means that an spk can have the same id as a pk. These ids are used to save bandwidth during key exchanges, which refer to the keys using their id instead of their full public parts.</p>
<p>When publishing bundles a client MUST make sure that the <tt>&nsbundles;</tt> 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>
<p>When publishing bundles a client MUST make sure that the <tt>&nsbundles;</tt> 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'>
@ -426,7 +426,7 @@
</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[
<example caption='Fetching a device&apos;s bundle information'><![CDATA[
<iq type='get'
from='romeo@montague.lit'
to='juliet@capulet.lit'
@ -457,7 +457,7 @@
<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>
<example caption="Plaintext SCE content element"><![CDATA[
<example caption='Plaintext SCE content element'><![CDATA[
<content xmlns='urn:xmpp:sce:0'>
<payload>
<body xmlns='jabber:client'>
@ -471,7 +471,7 @@
</section3>
<section3 topic='Encryption' anchor='encrypt'>
<p>
The &content; element is encrypted as described in the section about <link url="#protocol-message_encryption">Message Encryption</link>.
The &content; element is encrypted as described in the section about <link url='#protocol-message_encryption'>Message Encryption</link>.
</p>
<p>
Clients MUST only consider the devices on the <tt>&nsdevices;</tt> node of each recipient (i.e. including their own devices node, but excluding itself).
@ -481,10 +481,10 @@
<p>
An OMEMO encrypted message is specified to include an &lt;encrypted&gt; element in the 'urn:xmpp:omemo:1' namespace. It always contains two child nodes, the &lt;header&gt; and the &payload; element.
The &lt;header&gt; element has an attribute named 'sid' referencing the device id of the sending device and contains one or multiple &lt;keys&gt; elements, each with an attribute 'jid' of one of the recipients bare JIDs as well as one or multiple &lt;key&gt; elements.
A &lt;key&gt; element has an attribute named 'rid' referencing the device id of the recipient device, and an attribute named 'kex' which defaults to 'false' and indicates if the enclosed encrypted message includes a key exchange. The ciphertext that is the key and HMAC encrypted using the long-standing OMEMO session for that recipient device is encoded using base64 and placed as text content into the &lt;key&gt; element.
The ciphertext that is the encrypted &content; element is encoded using base64 and placed as text content into the &payload; element.
A &lt;key&gt; element has an attribute named 'rid' referencing the device id of the recipient device, and an attribute named 'kex' which defaults to 'false' and indicates if the enclosed encrypted message includes a key exchange. The key and HMAC encrypted using the long-standing OMEMO session for that recipient device are encoded using base64 and placed as text content into the &lt;key&gt; element.
The encrypted &content; element is encoded using base64 and placed as text content into the &payload; element.
</p>
<example caption="Sending a message"><![CDATA[
<example caption='Sending a message'><![CDATA[
<message to='juliet@capulet.lit' from='romeo@montague.lit' id='send1'>
<encrypted xmlns=']]>&ns;<![CDATA['>
<header sid='27183'>
@ -493,7 +493,7 @@
</keys>
<keys jid='romeo@montague.lit'>
<key rid='1337'>b64/encoded/data</key>
<key kex="true" rid='12321'>b64/encoded/data</key>
<key kex='true' rid='12321'>b64/encoded/data</key>
<!-- ... -->
</keys>
</header>
@ -507,10 +507,10 @@
</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 a 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 an OMEMOKeyExchange.</p>
<p>If this is the case, a new session is built from this received element. The client MUST 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 eventually delete the private key belonging to the PreKey after use (this is subject to the <link url="#business-rules">Business rules</link>).</p>
<p>If the element's contents are a OMEMOAuthenticatedMessage, and the client has a session with the sender's device, it tries to decrypt the OMEMOAuthenticatedMessage using this session. If the decryption fails or there is no session with the sending device, a warning message SHOULD be displayed instead. Also refer to the section about recovering from broken sessions in the <link url="#business-rules">Business Rules</link>.</p>
<p>If this is the case, a new session is built from this received element. The client MUST 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 eventually delete the private key belonging to the PreKey after use (this is subject to the <link url='#business-rules'>Business rules</link>).</p>
<p>If the element's contents are an OMEMOAuthenticatedMessage, and the client has a session with the sender's device, it tries to decrypt the OMEMOAuthenticatedMessage using this session. If the decryption fails or there is no session with the sending device, a warning message SHOULD be displayed instead. Also refer to the section about recovering from broken sessions in the <link url='#business-rules'>Business Rules</link>.</p>
<p>
After either the OMEMOKeyExchange or the OMEMOAuthenticatedMessage is decrypted, the content is decrypted as described in the section about <link url="#protocol-message_decryption">Message Decryption</link>.
After either the OMEMOKeyExchange or the OMEMOAuthenticatedMessage is decrypted, the content is decrypted as described in the section about <link url='#protocol-message_decryption'>Message Decryption</link>.
</p>
</section2>
<section2 topic='Opt-out' anchor='opt-out'>
@ -547,7 +547,7 @@
</section3>
<section3 topic='Fetching devices and bundles' anchor='group-fetch'>
<p>Before sending a message a participant MUST explicitly fetch device lists (if not already cached) for each of the members.</p>
<example caption='Juliet fetching devices for Remeo and Mercutio'><![CDATA[
<example caption='Juliet fetching devices for Romeo and Mercutio'><![CDATA[
<iq type='get' from='juliet@capulet.lit' to='romeo@montague.lit' id='gfetch0'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node=']]>&nsdevices;<![CDATA['/>
@ -644,103 +644,103 @@
</section1>
<section1 topic='XML Schema' anchor='schema'>
<code><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="]]>&ns;<![CDATA["
xmlns="]]>&ns;<![CDATA[">
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace=']]>&ns;<![CDATA['
xmlns=']]>&ns;<![CDATA['>
<xs:element name="encrypted">
<xs:element name='encrypted'>
<xs:complexType>
<xs:all>
<xs:element ref="header"/>
<xs:element ref="payload"/>
<xs:element ref='header'/>
<xs:element ref='payload'/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="payload" type="xs:base64Binary"/>
<xs:element name='payload' type='xs:base64Binary'/>
<xs:element name="header">
<xs:element name='header'>
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="keys"/>
<xs:sequence maxOccurs='unbounded'>
<xs:element ref='keys'/>
</xs:sequence>
<xs:attribute name="sid" type="xs:unsignedInt"/>
<xs:attribute name='sid' type='xs:unsignedInt'/>
</xs:complexType>
</xs:element>
<xs:element name="keys">
<xs:element name='keys'>
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="key"/>
<xs:sequence maxOccurs='unbounded'>
<xs:element ref='key'/>
</xs:sequence>
<xs:attribute name="jid" type="xs:string" use="required"/>
<xs:attribute name='jid' type='xs:string' use='required'/>
</xs:complexType>
</xs:element>
<xs:element name="key">
<xs:element name='key'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:base64Binary">
<xs:attribute name="rid" type="xs:unsignedInt" use="required"/>
<xs:attribute name="kex" type="xs:boolean" default="false"/>
<xs:extension base='xs:base64Binary'>
<xs:attribute name='rid' type='xs:unsignedInt' use='required'/>
<xs:attribute name='kex' type='xs:boolean' default='false'/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="devices">
<xs:element name='devices'>
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="device"/>
<xs:sequence maxOccurs='unbounded'>
<xs:element ref='device'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="device">
<xs:element name='device'>
<xs:complexType>
<xs:attribute name="id" type="xs:unsignedInt" use="required"/>
<xs:attribute name="label" type="xs:string"/>
<xs:attribute name='id' type='xs:unsignedInt' use='required'/>
<xs:attribute name='label' type='xs:string'/>
</xs:complexType>
</xs:element>
<xs:element name="bundle">
<xs:element name='bundle'>
<xs:complexType>
<xs:all>
<xs:element ref="spk"/>
<xs:element ref="spks"/>
<xs:element ref="ik"/>
<xs:element ref="prekeys"/>
<xs:element ref='spk'/>
<xs:element ref='spks'/>
<xs:element ref='ik'/>
<xs:element ref='prekeys'/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="spk">
<xs:element name='spk'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:base64Binary">
<xs:attribute name="id" type="xs:unsignedInt" use="required"/>
<xs:extension base='xs:base64Binary'>
<xs:attribute name='id' type='xs:unsignedInt' use='required'/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="spks" type="xs:base64Binary"/>
<xs:element name="ik" type="xs:base64Binary"/>
<xs:element name='spks' type='xs:base64Binary'/>
<xs:element name='ik' type='xs:base64Binary'/>
<xs:element name="prekeys">
<xs:element name='prekeys'>
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="pk"/>
<xs:sequence maxOccurs='unbounded'>
<xs:element ref='pk'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="pk">
<xs:element name='pk'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:base64Binary">
<xs:attribute name="id" type="xs:unsignedInt" use="required"/>
<xs:extension base='xs:base64Binary'>
<xs:attribute name='id' type='xs:unsignedInt' use='required'/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>