JEP-01xx: Stanza Security

End-to-end stanza security

WARNING: This document has not yet been accepted for consideration or approved in any official manner by the Jabber Software Foundation, and this document must not be referred to as a Jabber Enhancement Proposal (JEP). If this document is accepted as a JEP by the Jabber Council, it will be published at <http://www.jabber.org/jeps/> and announced on the <standards-jig@jabber.org> mailing list.

Author Information

Justin Karneges

Email: justin@affinix.com
JID: justin@andbit.net

JEP Information

Number: 01xx
Status: Experimental
Type: Informational
JIG: Standards JIG
Dependencies: XMPP Core, RFC 2440, RFC 2633
Supersedes: JEP-0027
Superseded By: None
Short Name: secure

Legal Notice

This Jabber Enhancement Proposal is copyright 1999 - 2004 by the Jabber Software Foundation (JSF) and is in full conformance with the JSF's Intellectual Property Rights Policy <http://jabber.org/jsf/ipr-policy.php>. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at <http://www.opencontent.org/openpub/>).

Discussion Venue

The preferred venue for discussion of this document is the Standards-JIG mailing list: <https://jabberstudio.org/mailman/listinfo/standards-jig>.

Revision History

Version 0.1 (2004-03-15)

Initial version. (jk)


Table of Contents:
1. Introduction
2. Terminology
3. Requirements
4. Protocol
4.1. Encoded payload format
4.2. Stanza format
4.3. Handling received secure stanzas
5. Presence Signatures
5.1. Time-to-live
5.2. Unavailable presence
6. Jabber ID to Public Key Binding
7. Security Considerations
8. IANA Considerations
9. Jabber Registrar Considerations
9.1. Protocol Namespaces
10. XML Schema


1. Introduction

Stanza Security helps ensure confidentiality and integrity of transmitted XMPP stanzas between endpoints. It is intended for simple "one-shot" use, and it attempts to address all of the major problems in Current Jabber OpenPGP Usage [1]. The most important feature this JEP brings forth is the ability to encrypt full stanzas. This is an important upgrade over JEP-0027, as it allows arbitrary XML to be encrypted instead of simply message text, thus bringing end-to-end security beyond IM.

2. Terminology

The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [2].

3. Requirements

This JEP addresses the following requirements:

4. Protocol

4.1 Encoded payload format

Any stanza MAY be secured. To do this, a payload XML structure is created, which contains the full stanza to be secured, along with other information. The payload is then encoded into OpenPGP (RFC 2440 [3]) or S/MIME (RFC 2633 [4]) format. Before encoding, the XML to be encoded will be in the following form:

Example 1. Abstract format of payload

<payload xmlns='http://jabber.org/protocol/secure'>
  [stanza]
  <id>[some id]</id>
</payload>

The first child element of <payload> MUST be the actual stanza to be encoded, although other child elements may be in any order. Even if only signing is used, the full stanza must be present in the payload in order for the recipient to be able to properly verify the signature. In addition to the stanza, an <id> element MUST be present, which contains a unique ID for the payload. The CDATA of the <id> element MUST be constructed according to the following algorithm:

  1. concatenate the sender's full JID (user@host/resource) with the recipient's full JID
  2. concatenate the resulting string with a full ISO-8601 UTC timestamp including year, month, day, hours, minutes, seconds in the following format: yyyy-mm-dd-Thh:mm:ssZ (the timestamp must be UTC, no offsets are allowed)
  3. concatenate the resulting string with a psuedo-random 16-bit integer (in string form)
  4. hash the resulting string according to the SHA1 algorithm
  5. convert the hexidecimal SHA1 output to all lowercase

A <window> element SHOULD also be present, which contains a "Window of opportunity" value as child CDATA. This value is the number of seconds the recipient uses to account for clock drift while performing replay calculations.

A payload for a message stanza might look like this:

Example 2. Message payload with 10-minute window

<payload xmlns='http://jabber.org/protocol/secure'>
  <message xmlns='jabber:client' to='romeo@montague.net/orchard' type='chat'>
    <subject>Imploring</subject>
    <body>O Romeo, Romeo! Wherefore art thou Romeo?</body>
  </message>
  <id>e0ffe42b28561960c6b12b944a092794b9683a38</id>
  <window>600</window>
</payload>

If the stanza to transmit is <presence>, then a <ttl> element SHOULD be present containing a "Time to live" value as child CDATA. This value is the number of seconds that the presence packet should be considered an accurate representation of the sender's state.

Example 3. Presence payload with 5-minute TTL

<payload xmlns='http://jabber.org/protocol/secure'>
  <presence xmlns='jabber:client'>
    <show>away</show>
    <status>Up, up, and away!</status>
  </presence>
  <id>e0ffe42b28561960c6b12b944a092794b9683a38</id>
  <ttl>300</ttl>
</payload>

Note: both the Window and TTL values MUST be in the range of 1 to 86400 (one day). If any such value is missing or out of range in a received payload, the value SHOULD be assumed to be 86400.

Next, the full <payload> element (including all XML tag names and angle brackets) MUST be converted into UTF-8 text and then encoded using either OpenPGP or S/MIME. The data MUST be signed and MAY be encrypted. The output MUST be armored US-ASCII with any headers removed. The resulting cipher text is then placed inside of a 'wrapper' stanza for transmission, as described in the next section.

4.2 Stanza format

Set the encoded payload as child CDATA of the <stanza> element, which is a child of the <secure> element. Set the 'type' attribute of the <secure> element to 'openpgp' (for OpenPGP) or 'smime' (for S/MIME), depending on the method used. This element is then placed inside of a wrapper stanza. The original stanza attributes MUST be replicated in the wrapper to ensure proper delivery.

Example 4. Abstract format of a secure stanza

<[stanza-name] 
    to='recipient'
    type='[value if provided]'
    id='[value if provided]'
    xml:lang='[value if provided]'>
  <secure xmlns='http://jabber.org/protocol/secure' type='[method type]'>
    <stanza>
      [encoded data]
    </stanza>
  </secure>
</[stanza-name]>

For <message> and <presence> stanzas, other elements MAY be included as children of the top-level stanza element. While such data is not protected, this can be useful for allowing insecure clients to still process the packet. For example, a message might contain body text, "This message is encrypted". Presence stanzas might contain the complete original presence elements in addition to the secure data, useful if the packet is only signed.

Below are some examples of what secure stanzas might look like. The first stanza in each example is the original insecure version, the second is the secured form.

Example 5. message

<message to='alice@example.com'>
  <body>hello, world</body>
</message>

<message to='alice@example.com'>
  <body>This message is encrypted.</body>
  <secure xmlns='http://jabber.org/protocol/secure' type='smime'>
    <stanza>
      hQIOAzvrdC3HvR3xEAgAhvN7grKZzC70OBHD/to2F0kz2Z3zQ3GDtzRK7hBGS0Zg
      oRJS3dEPgwViluVIWJWB1kHmrrjHPi5P0Nf1kRp5oFB2ZztOL/Ag04dMUuaSg1ga
      GCssRgp6WB1foDTgkXWSdj58fPhJV48uiXPzjUI7HdV8yScfZfMdG7m5GLH5KlEk
      +O5KMEBr6mSYsi7TIu30ezV/ZqmCLB3eF0+Ha+cx93Eczls4HVfSbIBR33on/mRE
      okZOhq0B4F3CixhtpNoQSwFKm2oZkdfdZCl4/GWQrcnv1r4jyvzXDw11cvALyaDP
      HhOxSjod0d6zdzUTOnjQCWrYE3IcfhcBxno47ha5lwf/W8g3DTkJhKNZLQoh5rY0
      y2WKdecpAW2tmztTLxupHHnfvW6U2OYv1TRD+hCe9/oEb/JgyhIwfaFeDX0VlJR3
      3M+F2oiOQHVEzLOFEMKouOCzsxzy7qZGaggh5lnjxj/OgxHYgioAwcw9db6U6XvC
      bA1anPXWpjl532xaW2d1TDot/0m1/aq0/dT5glNe+E+tS0NvEgsMr4t6qyLkkwmV
      ttUCXi/gTaD16FbFExtzt1lIPYJ2YmiiCX5WAG1FO0JV8BelMrbCD3EP3X4lbGTS
      ea30eB1dd07x9+KwB6XMNhJLBhNJNyLYqisRWy0fu2mfxtoKpB8xLBV33RWWvEb4
      DtJ7AZQ8s62nK0TIrHVml+IV3b+kyfMQs4LWKhORy5OPClxecqIn0QskezFE9+zT
      yCC/3kZJBn9lSYrpLUTBAEf8QwlttHRncXtAEjgJC+b1rmRK8drViBSRvc0ITOZO
      SiqUJBaVOFnyEQYY3oIoNKifMUnUKHbWBSsjEdCy
      =Sd66
    </stanza>
  </secure>
</message>

Example 6. presence

<presence>
  <show>away</show>
  <status>Up, up, and away!</status>
</presence>

<presence>
  <show>away</show>
  <status>Up, up, and away!</status>
  <secure xmlns='http://jabber.org/protocol/secure' type='openpgp'>
    <stanza>
      owGbwMvMwCT4+XHsM8mvJfMYT4clMTiEWSnYFBSlFqfmJafacSko2BRn5JfbJZYn
      Vtrog5lgsZLEktJiu9ACHYVSIE7MS1EAqVAEKoHIcNnoIwzpsGdmBRsMs0mQSXkD
      w3z/y6m7G7/w72Msj0udIN7w5RabM1A0jeea/KpnVnwv19d+5+TIuTLrq3k3AA==
      =dL9W
    </stanza>
  </secure>
</presence>

Example 7. iq

<iq to='alice@example.com/Home' type='get' id='iq_1'>
  <query xmlns='jabber:iq:version'/>
</iq>

<iq to='alice@example.com/Home' type='get' id='iq_1'>
  <secure xmlns='http://jabber.org/protocol/secure' type='openpgp'>
    <stanza>
      hQIOAzvrdC3HvR3xEAf/eEghJxnNU3N33PkkBBNCNfH1ckP5XSG0ZtgF15lh+djk
      NXfCdH0FABzgLZOjiP/+cbfnIGLUbVgexZ5g45f+u5nwE98m/E1JxHfLSA7bRr7B
      Sc7tDKgkPtjTpbW1OwDJAszqb4Km8bd7apHCrWGaYrEPWBVXqY01Os7vBE4BMFYb
      cpqnNuDY2YouA5YhmG3mZq465Bl9lTfKmh9msraT7wiAqyWZOk9elWK558ZG+opZ
      gUWqepaHuw1YVNX5AD99q4MMKJjZ25qSXOA0RaFLhfkAjvFCy45Dubg+x+4COuFj
      ia4Hhe+VPiXZBW1wf4i1hNLSSn/7wz3ZExlUtlW4Egf/YttRyMjHXQkU5uI18zfs
      WqPkzMpX6jGd+nhVSYaQWVixYeOLXHdpk5hdOSxKQ75fDt+qFGUSVZ+Eoq4eToz9
      rXV+Kz4Yke4gjRLNTsyJWq87rl+RN0T4jSCDE6uwFyU3G0YYcgAJFNwPp0WZPTJU
      hzWN+QyqNfQHrBX1tMwMWfcUnl6x6uHW2I1BqhdDZn3Rg25MeFri6YusyGj7U1GE
      FK3XHTNxTLSbDrHxeYwXpiPZy3yFeKUc3/daeAL5l/IK2bRqUtvAA0iJTjNmaPFF
      7EQOcRyWwNUjb2pRECYSvRlEqEkJHTFxvTkfY/psXnPu+cn9GJMD8St0tI4qxzEX
      HNKYAe2dxNeY578Z1CvDr95JILoX4cSvc1DfT9LNL+D54ahb1ClIIz5hEi6Blf4M
      rMdoKzU12sK+VBNg71PDU4ukSKgd12FpokZ0fthYwaHdGZJcSd3ix5sN1bAjgVpx
      EtMBsvfzCK6pSHqCKAH4R7dH7okmaZOEb1Lxo7evxR/97cJpnm7637wtkzB6BiJu
      dWXKifb7RW4ynDo=
      =O27w
    </stanza>
  </secure>
</iq>

4.3 Handling received secure stanzas

Upon receiving a stanza, first check to see if it is secure. For <iq> this should be immediately obvious, as the first namespaced child element will be the <secure> element. For <message> and <presence> there might be many child elements, and so the <secure> element must be located.

Now, based on the 'type' specified in the <secure> element, decode the child CDATA of <stanza>. If this data is being passed to an external application or library, it might be necessary to reconstruct the appropriate headers first. If there is an error decoding the information, the recipient SHOULD report an error:

Example 8. Error decoding a message

<message to='bob@example.com' from='alice@example.com' type='error'>
  <error type='cancel'>
    <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
    <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>
      Cannot decode secure stanza
    </text>
  </error>
</message>

Note that such errors MUST NOT be sent in response to any stanza of type 'error' or of an iq stanza of type 'result', for compliance with XMPP-Core.

The result of the decoding operation should yield a payload structure in UTF-8 format. It should be parsed using a separate parser instance than the one used for the XMPP session, as an error decoding the payload should not indicate an error in the entire XMPP session. Ensure that the stanza and id are present in the structure. If there is an error parsing the payload or retrieving its content, inform the sender:

Example 9. Error parsing a message

<message to='bob@example.com' from='alice@example.com' type='error'>
  <error type='cancel'>
    <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
    <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>
      Cannot parse payload
    </text>
  </error>
</message>

Next, ensure the decoded stanza is kosher:

  1. The the decoded stanza MUST have the same element name and namespace as the wrapper stanza.
  2. The 'to' address MUST be valid for this endpoint according to the following guideline:
    • <message> - bare-JID match
    • <presence> - bare-JID match, or no JID specified (lack of a JID indicates a presence broadcast)
    • <iq> - exact JID match
  3. The 'from' address MUST be a bare-JID match of the owner of the encoded signature.

If any of these checks fail, the packet MUST be dropped and not used.

Next, ensure this stanza is not a potentially 'replayed' stanza from earlier. The following terms are defined:

Procedure:

  1. The signature timestamp MUST be later than lowerBound (if known) and earlier than upperBound.
  2. The payload id MUST be unique among any other known ids from this sender, in which (expirationBase + [window * 2]) for such ids does not exceed the current time (but only if offline message history retrieval is not complete for the current XMPP session). In order for this check to be performed, the receiver MUST record the necessary information from all payloads (sender, id, signature timestamp, window) so that they may be referred to later. This information SHOULD be retained between XMPP sessions.

If any of these checks fail, the stanza might have been replayed. Therefore, the stanza SHOULD NOT be processed. However, the receiver MAY ignore this indication if the stanza is known to be legitimately replayable in the given scenario (such as groupchat history playback or normal presence usage).

If these checks prove successful, then the stanza within the payload should be treated as a successfully received stanza, with the additional knowledge that it was transmitted securely. The insecure data within the wrapper stanza SHOULD NOT be used.

5. Presence Signatures

5.1 Time-to-live

Signing of presence is useful not only for protecting the integrity of such status information, but also for proving one's availability at a given moment. At the same time, broadcasted presence is often replayed legitimately by the server, and so normal replay protection processing is not desirable. In this instance, an implementation may wish to skip the replay attack checks and utilize the "Time to live" value instead. Presence data should only be considered accurate if the TTL has not yet expired based on the signature timestamp. A sender should re-sign and transmit a new secure presence packet before the previous TTL expires. The TTL is meaningless for unavailable presence.

5.2 Unavailable presence

Proving one's availability can sometimes be impossible, due to network conditions or an attacker preventing packet transmission. Worse yet, the lack of available presence indicates one's unavailability, despite that there may be no signature to prove this. Therefore, all unavailable presence stanzas should be considered to be a true indication of a contact's unavailability, whether or not they are signed. Of course, signed unavailable presence is still useful, for determining the integrity of possible packet content (like a logoff string).

6. Jabber ID to Public Key Binding

In order to be able to match public keys to their respective Jabber IDs, the JID is to be specified in the key itself. For X.509 certificates, the same rules detailed in XMPP-Core are to be followed. For OpenPGP, the JID should be stored in a user-id field, either using the 'xmpp' prefix: "Alice <xmpp:alice@example.com>" or not: "Alice <alice@example.com>". Implementations should prefer an OpenPGP key that has an 'xmpp' prefix over one that does not.

7. Security Considerations

8. IANA Considerations

This JEP requires no interaction with the Internet Assigned Numbers Authority (IANA) [7].

9. Jabber Registrar Considerations

9.1 Protocol Namespaces

The Jabber Registrar [8] shall register the 'http://jabber.org/protocol/secure' namespace as a result of this JEP.

10. XML Schema

<?xml version='1.0' encoding='UTF-8'?>

<xs:schema
    xmlns:xs='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://jabber.org/protocol/secure'
    xmlns='http://jabber.org/protocol/secure'
    elementFormDefault='qualified'>

  <xs:element name='secure'>
    <xs:complexType>
      <xs:element ref='stanza' maxOccurs='1'/>
      <xs:attribute name='type' use='required'/>
        <xs:simpleType>
          <xs:restriction base='xs:NCName'>
            <xs:enumeration value='openpgp'/>
            <xs:enumeration value='smime'/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>

  <xs:element name='payload'>
    <xs:complexType>
      <xs:any namespace='jabber:client' maxOccurs='1'>
      <xs:element ref='id' maxOccurs='1'/>
      <xs:element ref='window' minOccurs='0' maxOccurs='1'/>
      <xs:element ref='ttl' minOccurs='0' maxOccurs='1'/>
    </xs:complexType>
  </xs:element>

  <xs:element name='stanza' type='xs:string'/>
  <xs:element name='id' type='xs:string'/>
  <xs:element name='window' type='xs:string'/>
  <xs:element name='ttl' type='xs:string'/>

</xs:schema>
    


Notes

1. JEP-0027: Current Jabber OpenPGP Usage <http://www.jabber.org/jeps/jep-0027.html>.

2. RFC 2119: Key words for use in RFCs to Indicate Requirement Levels <http://www.ietf.org/rfc/rfc2119.txt>.

3. RFC 2440: OpenPGP Message Format <http://www.ietf.org/rfc/rfc2440.txt>.

4. RFC 2633: S/MIME Version 3 Message Specification <http://www.ietf.org/rfc/rfc2633.txt>.

5. JEP-0091: Delayed Delivery <http://www.jabber.org/jeps/jep-0091.html>.

6. JEP-0013: Flexible Offline Message Retrieval <http://www.jabber.org/jeps/jep-0013.html>.

7. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols. For further information, see <http://www.iana.org/>.

8. The Jabber Registrar maintains a list of reserved Jabber protocol namespaces as well as registries of parameters used in the context of protocols approved by the Jabber Software Foundation. For further information, see <http://www.jabber.org/registrar/>.