1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-21 08:45:04 -05:00

Thanks vanitasvitae

This commit is contained in:
Tim Henkes 2020-09-08 10:22:52 +02:00
parent c2d541917d
commit 0bbedd0375

View File

@ -295,7 +295,7 @@
</dd></di>
<di><dt>MAX_SKIP</dt><dd>Storing skipped message keys introduces two potential DoS attacks. First, the maximum number of skipped message keys to store has to be limited, otherwise an attacker could fill the storage of the receiving device with skipped message keys. It is RECOMMENDED to keep 1000 skipped message keys around per session. Second, the maximum number of skipped message keys in a single message has to be limited, otherwise, with just a single malicious message, an attacker could make the receiving device calculate up to around 2^32 skipped message keys. The choice of this limit depends on the hardware capabilities of the device, though modern hardware is safe to choose values of around 1000 here too.</dd></di>
<di><dt>deletion policy for skipped message keys</dt><dd>As soon as the maximum number of skipped message keys are stored for a session, keys for that session are discarded on a FIFO basis to make space for new skipped 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>authentication tag truncation</dt><dd>Authentication tags are truncated to 16 bytes/128 bits by cutting off excess bytes from the end.</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, 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 root key (rk) as HKDF salt, the output of a Diffie-Hellman (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 a chain key (ck) as the HMAC key, a single byte constant <tt>0x01</tt> as HMAC input to produce the next message key (mk) and a single byte constant <tt>0x02</tt> as HMAC input to produce the next chain key.</dd></di>
@ -309,7 +309,7 @@
<li>Add the ciphertext to the <tt>OMEMOMessage.proto</tt> structure.</li>
<li>Serialize the <tt>OMEMOMessage.proto</tt> structure into a parseable byte array. To avoid potential problems regarding non-uniqueness of the serialization, make sure to only serialize <em>once</em> and to use that exact byte sequence in the following steps.</li>
<li>Concatenate the ad and the <tt>OMEMOMessage.proto</tt> structure into a parseable byte array. The result builds the HMAC input material for the next step.</li>
<li>Calculate the HMAC-SHA-256 using the authentication key and the input material as derived in the steps above. Truncate the output of the HMAC to 16 bytes/128 bits.</li>
<li>Calculate the HMAC-SHA-256 using the authentication key and the input material as derived in the steps above. Truncate the output of the HMAC to 16 bytes/128 bits by cutting off excess bytes from the end.</li>
<li>Put the serialized <tt>OMEMOMessage.proto</tt> structure and the HMAC into a new <tt>OMEMOAuthenticatedMessage.proto</tt> structure.</li>
</ol>
</dd></di>
@ -338,7 +338,7 @@
<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. Truncate the output of the HMAC to 16 bytes/128 bits.</li>
<li>Calculate the HMAC-SHA-256 using the authentication key and the ciphertext from the previous steps. Truncate the output of the HMAC to 16 bytes/128 bits by cutting off excess bytes from the end.</li>
<li>Concatenate the key and the HMAC, encrypt them using the Double Ratchet as specified above, once for each intended recipient. This yields one OMEMOKeyExchange or OMEMOAuthenticatedMessage per recipient device.</li>
</ol>
</section2>
@ -530,12 +530,13 @@
</section3>
<section3 topic='Message structure description' anchor='message-structure-description'>
<p>
An OMEMO encrypted message is specified to include an &lt;encrypted&gt; element in the <tt>&ns;</tt> namespace. It contains up to two child nodes, the &lt;header&gt; and the &payload; element. The &lt;header&gt; element must always be present, the &payload; element must be present unless an empty message is sent, as described below.
An OMEMO encrypted message is specified to include an &lt;encrypted&gt; element in the <tt>&ns;</tt> namespace. It contains up to two child nodes, the &lt;header&gt; and the &payload; element. The &lt;header&gt; element must always be present, the &payload; element must be present unless an empty OMEMO message is sent, as described below.
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 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>
<p>A special case are <em>empty</em> messages, which are used in various places throughout the protocol purely to manage sessions and not to transfer content. With empty messages, the step of creating and encrypting the &payload; element is skipped. Instead of encrypting the key and authentication tag of the &payload; ciphertext with the Double Ratchet session, 32 zero-bytes are encrypted with the Double Ratchet session directly. The resulting OMEMOKeyExchange or OMEMOAuthenticatedMessage are put into &lt;key&gt; elements as usual, but the &payload; element is omitted altogether, so that the &lt;encrypted&gt; element only contains a &lt;header&gt;.</p>
<!-- TODO: <p>Note that following &rfc6120; (section 8.4.), clients MUST ignore XML attributes and elements that are qualified with an unknown namespace, in order to allow for protocol extensions.</p> (qualified attributes are evil, right?) -->
<p>A special case are <em>empty</em> OMEMO messages, which are used in various places throughout the protocol purely to manage sessions and not to transfer content. With empty OMEMO messages, the step of creating and encrypting the &payload; element is skipped. Instead of encrypting the key and authentication tag of the &payload; ciphertext with the Double Ratchet session, 32 zero-bytes are encrypted with the Double Ratchet session directly. The resulting OMEMOKeyExchange or OMEMOAuthenticatedMessage are put into &lt;key&gt; elements as usual, but the &payload; element is omitted altogether, so that the &lt;encrypted&gt; element only contains a &lt;header&gt;.</p>
<example caption='Sending a message'><![CDATA[
<message to='juliet@capulet.lit' from='romeo@montague.lit' id='send1'>
<encrypted xmlns=']]>&ns;<![CDATA['>
@ -658,12 +659,12 @@
<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 OMEMOKeyExchange 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>After receiving an OMEMOKeyExchange and successfully building a new session, the receiving device SHOULD automatically respond with an empty message to the source of the OMEMOKeyExchange. This is to notify the device that the session initiation was completed successfully and that the device can stop sending OMEMOKeyExchanges.</p>
<p>When receiving a message that is not an OMEMOKeyExchange from a device there is no session with, clients SHOULD create a session with that device and notify it about the new session by responding with an empty (encrypted) message.</p>
<p>After receiving an OMEMOKeyExchange and successfully building a new session, the receiving device SHOULD automatically respond with an empty OMEMO message (as per <link url='#usecases-messagesend'>Sending a message</link>) to the source of the OMEMOKeyExchange. This is to notify the device that the session initiation was completed successfully and that the device can stop sending OMEMOKeyExchanges.</p>
<p>When receiving a message that is not an OMEMOKeyExchange from a device there is no session with, clients SHOULD create a session with that device and notify it about the new session by responding with an empty OMEMO message as per <link url='#usecases-messagesend'>Sending a message</link>.</p>
<p>There are various reasons why decryption of an OMEMOKeyExchange or an OMEMOAuthenticatedMessage could fail. One reason is if the message was received twice and already decrypted once, in this case the client MUST ignore the decryption failure and not show any warnings/errors. In all other cases of decryption failure, clients SHOULD notify their users (if applicable), so that the users know they potentially missed a message.</p>
<p>If an OMEMOKeyExchange is received as part of a message catch-up mechanism (like &xep0313;) 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 the catch-up is completed. If this is done, the client MUST send an OMEMO encrypted message with empty SCE payload right after the key exchange is completed, to forward the ratchet and to move away from the possibly double-used PreKey. This practice can mitigate the previously mentioned race condition by preventing message loss.</p>
<p>OMEMO's forward secrecy and backup/restore mechanisms don't play well together. Restoring old data can lead to desynchronized, "broken" sessions. Because these cases exist, clients MUST offer a way to manually replace broken sessions. It is advisable to have a session replacement option per recipient/per chat, if applicable. Otherwise, at least an application-global session reset MUST be available.</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 empty as messages as per <link url='#usecases-messagesend'>Sending a message</link>. These heartbeat messages cause the ratchet to forward, thus consequent messages will have the counter restarted from 0.</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 empty OMEMO messages as per <link url='#usecases-messagesend'>Sending a message</link>. These heartbeat messages cause the ratchet to forward, thus consequent messages will have the counter restarted from 0.</p>
<p>When a client receives a message from a device id that is not on the device list, it SHOULD try to retrieve that user's devices node directly to ensure their local cached version of the devices list is up-to-date.</p>
<p>When the user of a client deactivates OMEMO for an account or globally, the client SHOULD delete the corresponding bundles and device ids from the PEP nodes. That way other clients should stop encrypting for that account.</p>
</section1>
@ -679,7 +680,7 @@
</section2>
</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. This rule does not apply to <em>empty</em> messages that are used purely to transfer key material, e.g. as part of heartbeat messages or automatic key exchange completion.</p>
<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. This rule does not apply to empty OMEMO messages (as per <link url='#usecases-messagesend'>Sending a message</link>) that are used purely to transfer key material, e.g. as part of heartbeat messages or automatic key exchange completion.</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. To ensure interoperability between clients and older versions of OMEMO, the fingerprint SHOULD be chosen to be the public part of the IdentityKey in its byte-encoded Curve25519 form (see the notes on XEdDSA and the byte-encoding of public keys in the <link url="#protocol-key_exchange">X3DH protocol section</link> for details). When displaying the fingerprint as a hex-string, the RECOMMENDED way to make it easier to compare the fingerprint is to split the lowercase hex-string into 8 substrings of 8 chars each, then coloring each group of 8 lowercase hex chars using &xep0392;.</p>
<p>Clients MUST NOT react to decryption errors by initiating new sessions automatically and without user interaction. An exception to this rule is specified for clients that support automatic session healing as per XEP-XXXX. TODO: Refer to the omemo-session-healing XEP as soon as it is accepted.</p>
<p>While it is RECOMMENDED that clients postpone private key deletion until after message catch-up, the X3DH standard mandates that clients should not use duplicate-PreKey sessions for sending, so 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>