First draft.
XMPP applications often face choices based on the disco#info (see &xep0030;) exposed by other entities. For example, for a client, knowledge about whether a roster entry is a &xep0369; entity or a normal client is important for user experience. It may also be desirable to provide indicators on the type of client a contact is using (mobile or not).
The canonical way to do so has been issueing XEP-0030 requests to the entities emitting presence. This, with the evergrowing featureset of XMPP, induces a lot of traffic for all involed parties, especially during startup. This is a waste of resources, as XEP-0030 information rarely changes and even more, common client configurations and versions share exactly the same information.
&xep0115; has provided the XMPP ecosystem with a way to share this information with less bandwith. Entities using that protocol send a hash of their disco#info result along with presence or stream features. As those hashes can be cached, entities receiving these hashes only need to query the information for each hash once, greatly reducing the Service Discovery traffic.
However, XEP-0115 has two main flaws:
The ∩︀ protocol aims to satisfy the following requirements:
The following algorithms provide data which is sent using this protocol.
The input to this algorithm is a &xep0030; disco#info <query/> response. The output is an octet string which can be used as input to a hash function or an error.
General remarks:
The algorithm strongly distinguishes between character data (sequences of Unicode code points) and octet strings (sequences of 8-bit bytes). Whenever character data is encoded to octet strings in the following algorithm, the UTF-8 as specified in &rfc3629; encoding is used. Whenever octet strings are sorted in the following algorithm, the i;octet collation as specified in &rfc4790; is used.
The algorithm uses the xml:lang attribute. Implementations must take implicit values for the xml:lang attribute into account, for example those inherited from the disco#info, the IQ element, or from the root <stream> tag.
Processing of <feature/> elements:
The result of this step is referenced as Features String later.
Processing of <identity/> nodes:
For each <identity/> node:
The result of this step is referenced as Identities String later.
Processing of &xep0128; <x/> elements:
For each <x/> element:
For each <field/> element:
The result of this step is referenced as Extensions String later.
The entity picks a set of hash functions it wishes to use. The set of hash functions MUST include at least one hash function which MUST be implemented according to &xep0300; and SHOULD NOT include any hash functions which MUST NOT be supported according to XEP-0300.
Using the algorithm from the previous subsection, the entity calculates the input for the hash functions. It then runs the input through each hash function individually. The resulting tuples of hash algorithm and hash values constitute the &hashset;.
The &hashnode; is obtained from a &hash; with the following simple algorithm:
The &hashnode; can be decomposed into its original components with the following algorithm:
The algorithm takes a &hashset; as input and returns successfully if the hash matches and an error otherwise.
The two examples walk through the process of constructing a &hashset; for SHA-256 and SHA3-256. The full algorithm for generating the hash function input is explained.
The data from the example was the first entry in the &capsdb; hashes subdirectory which had no data forms at the time of writing. The features have been shuffled to show the sorting step in the algorithm.
The algorithm starts by constructing the Features String. For this, the values of the 'var' attributes of the feature nodes are encoded as UTF-8 and suffixed with &sepl4;. The first three of those features are shown as a hexdump below:
00000000 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 |http://jabber.or|
00000010 67 2f 70 72 6f 74 6f 63 6f 6c 2f 73 69 1f |g/protocol/si.|
0000001e
00000000 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 |http://jabber.or|
00000010 67 2f 70 72 6f 74 6f 63 6f 6c 2f 62 79 74 65 73 |g/protocol/bytes|
00000020 74 72 65 61 6d 73 1f |treams.|
00000027
00000000 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 |http://jabber.or|
00000010 67 2f 70 72 6f 74 6f 63 6f 6c 2f 63 68 61 74 73 |g/protocol/chats|
00000020 74 61 74 65 73 1f |tates.|
00000026
Note the appended 0x1f octet for each of the three strings. Now the strings are ordered using the i;octet collation and concatenated. The result is suffixed with &sepl1;, which gives the following hexdump of the final Features String:
00000000 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 |http://jabber.or|
00000010 67 2f 70 72 6f 74 6f 63 6f 6c 2f 62 79 74 65 73 |g/protocol/bytes|
00000020 74 72 65 61 6d 73 1f 68 74 74 70 3a 2f 2f 6a 61 |treams.http://ja|
00000030 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f 63 6f |bber.org/protoco|
00000040 6c 2f 63 68 61 74 73 74 61 74 65 73 1f 68 74 74 |l/chatstates.htt|
00000050 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 |p://jabber.org/p|
00000060 72 6f 74 6f 63 6f 6c 2f 64 69 73 63 6f 23 69 6e |rotocol/disco#in|
00000070 66 6f 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 |fo.http://jabber|
00000080 2e 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f 64 69 |.org/protocol/di|
00000090 73 63 6f 23 69 74 65 6d 73 1f 68 74 74 70 3a 2f |sco#items.http:/|
000000a0 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 |/jabber.org/prot|
000000b0 6f 63 6f 6c 2f 69 62 62 1f 68 74 74 70 3a 2f 2f |ocol/ibb.http://|
000000c0 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f |jabber.org/proto|
000000d0 63 6f 6c 2f 72 6f 73 74 65 72 78 1f 68 74 74 70 |col/rosterx.http|
000000e0 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 |://jabber.org/pr|
000000f0 6f 74 6f 63 6f 6c 2f 73 69 1f 68 74 74 70 3a 2f |otocol/si.http:/|
00000100 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 |/jabber.org/prot|
00000110 6f 63 6f 6c 2f 73 69 2f 70 72 6f 66 69 6c 65 2f |ocol/si/profile/|
00000120 66 69 6c 65 2d 74 72 61 6e 73 66 65 72 1f 6a 61 |file-transfer.ja|
00000130 62 62 65 72 3a 69 71 3a 6c 61 73 74 1f 6a 61 62 |bber:iq:last.jab|
00000140 62 65 72 3a 69 71 3a 70 72 69 76 61 63 79 1f 6a |ber:iq:privacy.j|
00000150 61 62 62 65 72 3a 69 71 3a 72 6f 73 74 65 72 1f |abber:iq:roster.|
00000160 6a 61 62 62 65 72 3a 69 71 3a 74 69 6d 65 1f 6a |jabber:iq:time.j|
00000170 61 62 62 65 72 3a 69 71 3a 76 65 72 73 69 6f 6e |abber:iq:version|
00000180 1f 6a 61 62 62 65 72 3a 78 3a 6f 6f 62 1f 75 72 |.jabber:x:oob.ur|
00000190 6e 3a 78 6d 70 70 3a 70 69 6e 67 1f 75 72 6e 3a |n:xmpp:ping.urn:|
000001a0 78 6d 70 70 3a 72 65 63 65 69 70 74 73 1f 75 72 |xmpp:receipts.ur|
000001b0 6e 3a 78 6d 70 70 3a 74 69 6d 65 1f 1c |n:xmpp:time..|
000001bd
For the Identities String, first the character data of the 'category', 'type', 'xml:lang' and 'name' attributes is encoded as UTF-8 and suffixed with &sepl4;. The resulting individual strings have the following hexdumps:
00000000 63 6c 69 65 6e 74 1f |client.|
00000007
00000000 6d 6f 62 69 6c 65 1f |mobile.|
00000007
00000000 1f |.|
00000001
00000000 42 6f 6d 62 75 73 4d 6f 64 1f |BombusMod.|
0000000a
The strings are now joined together and the result is suffixed with &sepl3;:
00000000 63 6c 69 65 6e 74 1f 6d 6f 62 69 6c 65 1f 1f 42 |client.mobile..B|
00000010 6f 6d 62 75 73 4d 6f 64 1f 1e |ombusMod..|
0000001a
Normally, a sorting step would occur here. As the example only has a single string, the sorting and joining is a no-op. The string is now suffixed with &sepl1; to get the Identities String:
00000000 63 6c 69 65 6e 74 1f 6d 6f 62 69 6c 65 1f 1f 42 |client.mobile..B|
00000010 6f 6d 62 75 73 4d 6f 64 1f 1e 1c |ombusMod...|
0000001b
The Extensions String is simply the &sepl1; used to terminate it as no extensions are contained in the example. Thus, the final input for the hash function is, as hexdump:
00000000 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 |http://jabber.or|
00000010 67 2f 70 72 6f 74 6f 63 6f 6c 2f 62 79 74 65 73 |g/protocol/bytes|
00000020 74 72 65 61 6d 73 1f 68 74 74 70 3a 2f 2f 6a 61 |treams.http://ja|
00000030 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f 63 6f |bber.org/protoco|
00000040 6c 2f 63 68 61 74 73 74 61 74 65 73 1f 68 74 74 |l/chatstates.htt|
00000050 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 |p://jabber.org/p|
00000060 72 6f 74 6f 63 6f 6c 2f 64 69 73 63 6f 23 69 6e |rotocol/disco#in|
00000070 66 6f 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 |fo.http://jabber|
00000080 2e 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f 64 69 |.org/protocol/di|
00000090 73 63 6f 23 69 74 65 6d 73 1f 68 74 74 70 3a 2f |sco#items.http:/|
000000a0 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 |/jabber.org/prot|
000000b0 6f 63 6f 6c 2f 69 62 62 1f 68 74 74 70 3a 2f 2f |ocol/ibb.http://|
000000c0 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f |jabber.org/proto|
000000d0 63 6f 6c 2f 72 6f 73 74 65 72 78 1f 68 74 74 70 |col/rosterx.http|
000000e0 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 |://jabber.org/pr|
000000f0 6f 74 6f 63 6f 6c 2f 73 69 1f 68 74 74 70 3a 2f |otocol/si.http:/|
00000100 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 |/jabber.org/prot|
00000110 6f 63 6f 6c 2f 73 69 2f 70 72 6f 66 69 6c 65 2f |ocol/si/profile/|
00000120 66 69 6c 65 2d 74 72 61 6e 73 66 65 72 1f 6a 61 |file-transfer.ja|
00000130 62 62 65 72 3a 69 71 3a 6c 61 73 74 1f 6a 61 62 |bber:iq:last.jab|
00000140 62 65 72 3a 69 71 3a 70 72 69 76 61 63 79 1f 6a |ber:iq:privacy.j|
00000150 61 62 62 65 72 3a 69 71 3a 72 6f 73 74 65 72 1f |abber:iq:roster.|
00000160 6a 61 62 62 65 72 3a 69 71 3a 74 69 6d 65 1f 6a |jabber:iq:time.j|
00000170 61 62 62 65 72 3a 69 71 3a 76 65 72 73 69 6f 6e |abber:iq:version|
00000180 1f 6a 61 62 62 65 72 3a 78 3a 6f 6f 62 1f 75 72 |.jabber:x:oob.ur|
00000190 6e 3a 78 6d 70 70 3a 70 69 6e 67 1f 75 72 6e 3a |n:xmpp:ping.urn:|
000001a0 78 6d 70 70 3a 72 65 63 65 69 70 74 73 1f 75 72 |xmpp:receipts.ur|
000001b0 6e 3a 78 6d 70 70 3a 74 69 6d 65 1f 1c 63 6c 69 |n:xmpp:time..cli|
000001c0 65 6e 74 1f 6d 6f 62 69 6c 65 1f 1f 42 6f 6d 62 |ent.mobile..Bomb|
000001d0 75 73 4d 6f 64 1f 1e 1c 1c |usMod....|
000001d9
Running this octet string through the hash functions leads as to the following &hashset;:
kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=
79mdYAfU9rEdTOcWDO7UEAt6E56SUzk/g6TnqUeuD9Q=
]]>
The data from the example is the shortest entry from the &capsdb; hashes subdirectory which had data forms and multiple identities at the time of writing. The features have been shuffled to show the sorting step in the algorithm.
We skip over the process for the Features String and only present the final result encoded as base64 for reference:
Z2FtZXM6Ym9hcmQfaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvYWN0aXZpdHkfaHR0cDovL2ph
YmJlci5vcmcvcHJvdG9jb2wvYWN0aXZpdHkrbm90aWZ5H2h0dHA6Ly9qYWJiZXIub3JnL3Byb3Rv
Y29sL2J5dGVzdHJlYW1zH2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL2NoYXRzdGF0ZXMfaHR0
cDovL2phYmJlci5vcmcvcHJvdG9jb2wvY29tbWFuZHMfaHR0cDovL2phYmJlci5vcmcvcHJvdG9j
b2wvZGlzY28jaW5mbx9odHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9kaXNjbyNpdGVtcx9odHRw
Oi8vamFiYmVyLm9yZy9wcm90b2NvbC9ldmlsH2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL2Zl
YXR1cmUtbmVnH2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL2dlb2xvYx9odHRwOi8vamFiYmVy
Lm9yZy9wcm90b2NvbC9nZW9sb2Mrbm90aWZ5H2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL2li
Yh9odHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9pcWliYh9odHRwOi8vamFiYmVyLm9yZy9wcm90
b2NvbC9tb29kH2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL21vb2Qrbm90aWZ5H2h0dHA6Ly9q
YWJiZXIub3JnL3Byb3RvY29sL3Jvc3RlcngfaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvc2kf
aHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvc2kvcHJvZmlsZS9maWxlLXRyYW5zZmVyH2h0dHA6
Ly9qYWJiZXIub3JnL3Byb3RvY29sL3R1bmUfaHR0cDovL3d3dy5mYWNlYm9vay5jb20veG1wcC9t
ZXNzYWdlcx9odHRwOi8vd3d3LnhtcHAub3JnL2V4dGVuc2lvbnMveGVwLTAwODQuaHRtbCNucy1t
ZXRhZGF0YStub3RpZnkfamFiYmVyOmlxOmF2YXRhch9qYWJiZXI6aXE6YnJvd3NlH2phYmJlcjpp
cTpkdGNwH2phYmJlcjppcTpmaWxleGZlch9qYWJiZXI6aXE6aWJiH2phYmJlcjppcTppbmJhbmQf
amFiYmVyOmlxOmppZGxpbmsfamFiYmVyOmlxOmxhc3QfamFiYmVyOmlxOm9vYh9qYWJiZXI6aXE6
cHJpdmFjeR9qYWJiZXI6aXE6cm9zdGVyH2phYmJlcjppcTp0aW1lH2phYmJlcjppcTp2ZXJzaW9u
H2phYmJlcjp4OmRhdGEfamFiYmVyOng6ZXZlbnQfamFiYmVyOng6b29iH3Vybjp4bXBwOmF2YXRh
cjptZXRhZGF0YStub3RpZnkfdXJuOnhtcHA6cGluZx91cm46eG1wcDpyZWNlaXB0cx91cm46eG1w
cDp0aW1lHxw=
In the previous example, it was already shown how the individual parts of each <identity/> element are combined. We get the following octet strings as hexdumps:
00000000 63 6c 69 65 6e 74 1f 70 63 1f 72 75 1f d0 a2 d0 |client.pc.ru....|
00000010 ba d0 b0 d0 b1 d0 b1 d0 b5 d1 80 1f 1e |.............|
0000001d
00000000 63 6c 69 65 6e 74 1f 70 63 1f 65 6e 1f 54 6b 61 |client.pc.en.Tka|
00000010 62 62 65 72 1f 1e |bber..|
00000016
The second string is ordered before the first string in the i;octet collation and afterwards the strings are joined and the result is suffixed with &sepl1; to close the identities part of the input. The final Identities String is thus, as hexdump:
00000000 63 6c 69 65 6e 74 1f 70 63 1f 65 6e 1f 54 6b 61 |client.pc.en.Tka|
00000010 62 62 65 72 1f 1e 63 6c 69 65 6e 74 1f 70 63 1f |bber..client.pc.|
00000020 72 75 1f d0 a2 d0 ba d0 b0 d0 b1 d0 b1 d0 b5 d1 |ru..............|
00000030 80 1f 1e 1c |....|
00000034
The example has a &xep0128; form. For each field, a string consisting of the 'var' attributes character data and the values is created as per the algorithm:
00000000 46 4f 52 4d 5f 54 59 50 45 1f 75 72 6e 3a 78 6d |FORM_TYPE.urn:xm|
00000010 70 70 3a 64 61 74 61 66 6f 72 6d 73 3a 73 6f 66 |pp:dataforms:sof|
00000020 74 77 61 72 65 69 6e 66 6f 1f 1e |twareinfo..|
0000002b
00000000 73 6f 66 74 77 61 72 65 1f 54 6b 61 62 62 65 72 |software.Tkabber|
00000010 1f 1e |..|
00000012
00000000 73 6f 66 74 77 61 72 65 5f 76 65 72 73 69 6f 6e |software_version|
00000010 1f 30 2e 31 31 2e 31 2d 73 76 6e 2d 32 30 31 31 |.0.11.1-svn-2011|
00000020 31 32 31 36 2d 6d 6f 64 20 28 54 63 6c 2f 54 6b |1216-mod (Tcl/Tk|
00000030 20 38 2e 36 62 32 29 1f 1e | 8.6b2)..|
00000039
00000000 6f 73 1f 57 69 6e 64 6f 77 73 1f 1e |os.Windows..|
0000000c
The strings need to be sorted using i;octet and joined together. The result is suffixed with &sepl2;, which closes the form. As this is the only form, the resulting Extensions String is obtained by adding a &sepl1; to close the extensions section of the hash input:
00000000 46 4f 52 4d 5f 54 59 50 45 1f 75 72 6e 3a 78 6d |FORM_TYPE.urn:xm|
00000010 70 70 3a 64 61 74 61 66 6f 72 6d 73 3a 73 6f 66 |pp:dataforms:sof|
00000020 74 77 61 72 65 69 6e 66 6f 1f 1e 6f 73 1f 57 69 |twareinfo..os.Wi|
00000030 6e 64 6f 77 73 1f 1e 6f 73 5f 76 65 72 73 69 6f |ndows..os_versio|
00000040 6e 1f 58 50 1f 1e 73 6f 66 74 77 61 72 65 1f 54 |n.XP..software.T|
00000050 6b 61 62 62 65 72 1f 1e 73 6f 66 74 77 61 72 65 |kabber..software|
00000060 5f 76 65 72 73 69 6f 6e 1f 30 2e 31 31 2e 31 2d |_version.0.11.1-|
00000070 73 76 6e 2d 32 30 31 31 31 32 31 36 2d 6d 6f 64 |svn-20111216-mod|
00000080 20 28 54 63 6c 2f 54 6b 20 38 2e 36 62 32 29 1f | (Tcl/Tk 8.6b2).|
00000090 1e 1d 1c |...|
00000093
Note the "os" field is now before the other fields but after "FORM_TYPE", due to the sorting.
The final hash function input is obtained by concatenating the Features String, Identities String and Extensions String:
00000000 67 61 6d 65 73 3a 62 6f 61 72 64 1f 68 74 74 70 |games:board.http|
00000010 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 |://jabber.org/pr|
00000020 6f 74 6f 63 6f 6c 2f 61 63 74 69 76 69 74 79 1f |otocol/activity.|
00000030 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 |http://jabber.or|
00000040 67 2f 70 72 6f 74 6f 63 6f 6c 2f 61 63 74 69 76 |g/protocol/activ|
00000050 69 74 79 2b 6e 6f 74 69 66 79 1f 68 74 74 70 3a |ity+notify.http:|
00000060 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f |//jabber.org/pro|
00000070 74 6f 63 6f 6c 2f 62 79 74 65 73 74 72 65 61 6d |tocol/bytestream|
00000080 73 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e |s.http://jabber.|
00000090 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f 63 68 61 |org/protocol/cha|
000000a0 74 73 74 61 74 65 73 1f 68 74 74 70 3a 2f 2f 6a |tstates.http://j|
000000b0 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f 63 |abber.org/protoc|
000000c0 6f 6c 2f 63 6f 6d 6d 61 6e 64 73 1f 68 74 74 70 |ol/commands.http|
000000d0 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 |://jabber.org/pr|
000000e0 6f 74 6f 63 6f 6c 2f 64 69 73 63 6f 23 69 6e 66 |otocol/disco#inf|
000000f0 6f 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e |o.http://jabber.|
00000100 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f 64 69 73 |org/protocol/dis|
00000110 63 6f 23 69 74 65 6d 73 1f 68 74 74 70 3a 2f 2f |co#items.http://|
00000120 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f |jabber.org/proto|
00000130 63 6f 6c 2f 65 76 69 6c 1f 68 74 74 70 3a 2f 2f |col/evil.http://|
00000140 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f |jabber.org/proto|
00000150 63 6f 6c 2f 66 65 61 74 75 72 65 2d 6e 65 67 1f |col/feature-neg.|
00000160 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e 6f 72 |http://jabber.or|
00000170 67 2f 70 72 6f 74 6f 63 6f 6c 2f 67 65 6f 6c 6f |g/protocol/geolo|
00000180 63 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e |c.http://jabber.|
00000190 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f 67 65 6f |org/protocol/geo|
000001a0 6c 6f 63 2b 6e 6f 74 69 66 79 1f 68 74 74 70 3a |loc+notify.http:|
000001b0 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f |//jabber.org/pro|
000001c0 74 6f 63 6f 6c 2f 69 62 62 1f 68 74 74 70 3a 2f |tocol/ibb.http:/|
000001d0 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 |/jabber.org/prot|
000001e0 6f 63 6f 6c 2f 69 71 69 62 62 1f 68 74 74 70 3a |ocol/iqibb.http:|
000001f0 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f |//jabber.org/pro|
00000200 74 6f 63 6f 6c 2f 6d 6f 6f 64 1f 68 74 74 70 3a |tocol/mood.http:|
00000210 2f 2f 6a 61 62 62 65 72 2e 6f 72 67 2f 70 72 6f |//jabber.org/pro|
00000220 74 6f 63 6f 6c 2f 6d 6f 6f 64 2b 6e 6f 74 69 66 |tocol/mood+notif|
00000230 79 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 2e |y.http://jabber.|
00000240 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f 72 6f 73 |org/protocol/ros|
00000250 74 65 72 78 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 |terx.http://jabb|
00000260 65 72 2e 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f |er.org/protocol/|
00000270 73 69 1f 68 74 74 70 3a 2f 2f 6a 61 62 62 65 72 |si.http://jabber|
00000280 2e 6f 72 67 2f 70 72 6f 74 6f 63 6f 6c 2f 73 69 |.org/protocol/si|
00000290 2f 70 72 6f 66 69 6c 65 2f 66 69 6c 65 2d 74 72 |/profile/file-tr|
000002a0 61 6e 73 66 65 72 1f 68 74 74 70 3a 2f 2f 6a 61 |ansfer.http://ja|
000002b0 62 62 65 72 2e 6f 72 67 2f 70 72 6f 74 6f 63 6f |bber.org/protoco|
000002c0 6c 2f 74 75 6e 65 1f 68 74 74 70 3a 2f 2f 77 77 |l/tune.http://ww|
000002d0 77 2e 66 61 63 65 62 6f 6f 6b 2e 63 6f 6d 2f 78 |w.facebook.com/x|
000002e0 6d 70 70 2f 6d 65 73 73 61 67 65 73 1f 68 74 74 |mpp/messages.htt|
000002f0 70 3a 2f 2f 77 77 77 2e 78 6d 70 70 2e 6f 72 67 |p://www.xmpp.org|
00000300 2f 65 78 74 65 6e 73 69 6f 6e 73 2f 78 65 70 2d |/extensions/xep-|
00000310 30 30 38 34 2e 68 74 6d 6c 23 6e 73 2d 6d 65 74 |0084.html#ns-met|
00000320 61 64 61 74 61 2b 6e 6f 74 69 66 79 1f 6a 61 62 |adata+notify.jab|
00000330 62 65 72 3a 69 71 3a 61 76 61 74 61 72 1f 6a 61 |ber:iq:avatar.ja|
00000340 62 62 65 72 3a 69 71 3a 62 72 6f 77 73 65 1f 6a |bber:iq:browse.j|
00000350 61 62 62 65 72 3a 69 71 3a 64 74 63 70 1f 6a 61 |abber:iq:dtcp.ja|
00000360 62 62 65 72 3a 69 71 3a 66 69 6c 65 78 66 65 72 |bber:iq:filexfer|
00000370 1f 6a 61 62 62 65 72 3a 69 71 3a 69 62 62 1f 6a |.jabber:iq:ibb.j|
00000380 61 62 62 65 72 3a 69 71 3a 69 6e 62 61 6e 64 1f |abber:iq:inband.|
00000390 6a 61 62 62 65 72 3a 69 71 3a 6a 69 64 6c 69 6e |jabber:iq:jidlin|
000003a0 6b 1f 6a 61 62 62 65 72 3a 69 71 3a 6c 61 73 74 |k.jabber:iq:last|
000003b0 1f 6a 61 62 62 65 72 3a 69 71 3a 6f 6f 62 1f 6a |.jabber:iq:oob.j|
000003c0 61 62 62 65 72 3a 69 71 3a 70 72 69 76 61 63 79 |abber:iq:privacy|
000003d0 1f 6a 61 62 62 65 72 3a 69 71 3a 72 6f 73 74 65 |.jabber:iq:roste|
000003e0 72 1f 6a 61 62 62 65 72 3a 69 71 3a 74 69 6d 65 |r.jabber:iq:time|
000003f0 1f 6a 61 62 62 65 72 3a 69 71 3a 76 65 72 73 69 |.jabber:iq:versi|
00000400 6f 6e 1f 6a 61 62 62 65 72 3a 78 3a 64 61 74 61 |on.jabber:x:data|
00000410 1f 6a 61 62 62 65 72 3a 78 3a 65 76 65 6e 74 1f |.jabber:x:event.|
00000420 6a 61 62 62 65 72 3a 78 3a 6f 6f 62 1f 75 72 6e |jabber:x:oob.urn|
00000430 3a 78 6d 70 70 3a 61 76 61 74 61 72 3a 6d 65 74 |:xmpp:avatar:met|
00000440 61 64 61 74 61 2b 6e 6f 74 69 66 79 1f 75 72 6e |adata+notify.urn|
00000450 3a 78 6d 70 70 3a 70 69 6e 67 1f 75 72 6e 3a 78 |:xmpp:ping.urn:x|
00000460 6d 70 70 3a 72 65 63 65 69 70 74 73 1f 75 72 6e |mpp:receipts.urn|
00000470 3a 78 6d 70 70 3a 74 69 6d 65 1f 1c 63 6c 69 65 |:xmpp:time..clie|
00000480 6e 74 1f 70 63 1f 65 6e 1f 54 6b 61 62 62 65 72 |nt.pc.en.Tkabber|
00000490 1f 1e 63 6c 69 65 6e 74 1f 70 63 1f 72 75 1f d0 |..client.pc.ru..|
000004a0 a2 d0 ba d0 b0 d0 b1 d0 b1 d0 b5 d1 80 1f 1e 1c |................|
000004b0 46 4f 52 4d 5f 54 59 50 45 1f 75 72 6e 3a 78 6d |FORM_TYPE.urn:xm|
000004c0 70 70 3a 64 61 74 61 66 6f 72 6d 73 3a 73 6f 66 |pp:dataforms:sof|
000004d0 74 77 61 72 65 69 6e 66 6f 1f 1e 6f 73 1f 57 69 |twareinfo..os.Wi|
000004e0 6e 64 6f 77 73 1f 1e 6f 73 5f 76 65 72 73 69 6f |ndows..os_versio|
000004f0 6e 1f 58 50 1f 1e 73 6f 66 74 77 61 72 65 1f 54 |n.XP..software.T|
00000500 6b 61 62 62 65 72 1f 1e 73 6f 66 74 77 61 72 65 |kabber..software|
00000510 5f 76 65 72 73 69 6f 6e 1f 30 2e 31 31 2e 31 2d |_version.0.11.1-|
00000520 73 76 6e 2d 32 30 31 31 31 32 31 36 2d 6d 6f 64 |svn-20111216-mod|
00000530 20 28 54 63 6c 2f 54 6b 20 38 2e 36 62 32 29 1f | (Tcl/Tk 8.6b2).|
00000540 1e 1d 1c |...|
00000543
Feeding the concatenated octet string as input to the hash functions yields the following &hashset;:
u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=
XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg=
]]>
If an entity supports ∩︀, it MUST advertise the fact by returning a feature of "urn:xmpp:caps".
A server MAY advertise its support for this protocol as well as the current hashes in the stream features.
When a connected client or peer server sends a service discovery information request to determine the entity capabilities of a server that advertises capabilities via the stream feature, the requesting entity MUST send the disco#info request to the server's JID as provided in the 'from' attribute of the response stream header. To enable this functionality, a server that advertises support for entity capabilities MUST provide a 'from' address in its response stream headers, in accordance with &rfc6120;.
If a server supports Caps Optimizations, it MUST advertise the fact by returning a feature of "urn:xmpp:caps:optimize".
An entity publishes the current &hashset; in presence stanzas it sends:
The <hash/> element is specified by &xep0300; and is used to transport the &hashes;.
To query the &xep0030; information for a specific &hash; value, an entity MUST query a Service Discovery node equal to the &hashnode;
An entity is free to choose for which &hash; of a &hashset; the request is sent.
A server MAY support pushing of &hashes; from clients before sending initial presence. This allows servers to discover capabilities of clients before those have sent initial presence, which may be useful or important for some protocols (such as &xep0369;). This feature is called &gratcaps;.
To advertise support, the server publishes the urn:xmpp:caps:gratuitous feature:
After determining server support, a client can send &hashes; via &gratcaps; before sending initial presence:
The server replies with an empty result on success.
The server MUST NOT broadcast the &hashes; submitted via &gratcaps; using presence.
Clients SHOULD NOT send &gratcaps; after they have sent initial presence; instead, they SHOULD re-send presence to update the &hashes;. Otherwise, entities subscribed to the presence will not receive the updated &hashes;.
A &hash; MAY be stored alongside with its disco#info in a &hashcache;. A received &hash; which has not been verified MUST NOT be stored.
Instead of issuing a &xep0030; disco#info <query/> with absent 'node' attribute to a target entity, an entity MAY use a &hashcache; to obtain the response. To look up the disco#info response in the &hashcache;, an entity MUST use a hash from the &hashset; which was most recently received from the entity to which the <query/> would have been sent otherwise. If none of the most recently received &hashes; are found in the &hashcache;, the entity MUST fall back to sending the request.
An entity MUST NOT use &hashes; which were not included in the most recent &hashset; received from the target entity.
An entity MAY use external data sources to fill the &hashcache;.
An entity MUST ensure that implicit values for xml:lang attributes is preserved when disco#info data is cached. This can for example happen by making the implicit values explicit in the storage.
Servers MAY implement &queryintercept; to further optimise bandwidth consumption. The idea is that servers intercept &xep0030; disco#info queries sent to clients if they already know the answer from &hashes; published by the client. The rules for &queryintercept; are the following (to be applied in this order):
It is RECOMMENDED that entities use the caching mechanisms outlined in the Caching Business Rules. Entities MAY share caches among connections and accounts.
&genents; are encouraged to also emit &xep0115; <c/> elements in their presence updates (as specified in XEP-0115) for a reasonable transition period.
When receiving a &hashset; along with XEP-0115 capabilities, a &procent; MAY obtain the disco#info <query/> for verification from a XEP-0115 based cache instead of querying the &genent; directly. A &procent; MUST NOT use disco#info data from a XEP-0115 cache without verification if a ∩︀ <c/> element is available.
The codepoints used for separating the different parts in the Hash Function Input Algortihm (&sepl1; through &sepl4;) are not allowed in well-formed XML character data. As entities are, per &xmppcore;, required to close a stream if non-well-formed XML data is received, these codepoints cannot occur in the input to the algorithm and their use as separators is safe.
If the algorithm for constructing the input to the hash function or the used hash function itself allow for cheap collisions, caching the hashes will become dangerous as it allows for cache poisoning. This in turn allows entities to effectively fake disco#info responses of other entities.
This was an issue with &xep0115; and has been addressed with a new algorithm for generating the hash function input which keeps the structural information of the disco#info input.
An entity MUST NOT ever use disco#info which has not been verified to belong to a &hash; obtained from a cache using that &hash;. Using cache contents from a trusted source (at the discretion of the entity) counts as verifying.
A malicious entity could send a large amount of &hashsets; in short intervals, while making sure that it provides matching disco#info responses. If a &procent; uses caching, this can overflow or thrash the caches. &procents; should be aware of this risk and apply proper rate-limiting for processing &hashsets;. To reduce the attack surface, an entity MAY choose to not cache &hashes; obtained from entities not in its roster.
As mentioned earlier, when storing disco#info data in a cache for later retrieval, implementations MUST ensure that implicit values for xml:lang attributes are reconstructed correctly when the disco#info is restored.
Entities MAY choose to not send &hashsets; with directed presence (for example to increase privacy). In that case, entities SHOULD also refuse direct &xep0030; queries.
The server replies to certain disco#info queries on behalf of the client. This means that the client has no choice on to whom they reply. Otherwise, a client could choose to reply with <service-unavailable/> to mask its existence. We consider two effects of this:
A remote entity could attempt to detect that an entity exists behind a resource. For this, they send a disco#info query to the resource since nearly everyone implements disco#info. As the client responds with <service-unavailable/>, it looks as if no client was present at this resource.
With &queryintercept;, the server would reply on behalf of the client. However, the consensus in the community is that by measuring the difference between the reply from the server of the resource and the reply from the actual resource, it would generally be possible to detect the existence of a resource.
A remote entity can obtain the disco#info information of any resource which supports ∩︀ and of which the entity knows the resource.
This cannot be mitigated with &queryintercept;. The risk is deemed acceptable considering that resources should generally be chosen randomly.
The following alternatives to the custom algorithm were considered and eventually rejected:
A common way to canonicalize XML which could be used is &w3canon;. It was decided not to use Canonical XML for the following reasons:
Thus, using Canonical XML would require additional, non-trivial software support and still require non-trivial additional canonicalization rules.
This document requires no interaction with &IANA;.
The ®ISTRAR; includes "urn:xmpp:caps" in its registry of protocol namespaces (see &NAMESPACES;).
urn:xmpp:caps
&xep0390;
]]>
The XMPP Registrar includes "urn:xmpp:caps" and "urn:xmpp:caps:optimize" in its registry of service discovery features (see &DISCOFEATURES;).
urn:xmpp:caps
Indicate support for Entity Capabilities 2.0
&xep0390;
urn:xmpp:caps:optimize
Indicate support for optimisation of Entity Capabilities 2.0 broadcast.
&xep0390;
]]>
The XMPP Registrar includes "urn:xmpp:caps" in its registry of stream features (see &STREAMFEATURES;).
urn:xmpp:caps
ecaps2
c
Indicate support for Entity Capabilities 2.0 and publish capabilities to peer.
&xep0390;
]]>
The protocol documented by this schema is defined in XEP-0390:
http://www.xmpp.org/extensions/xep-0390.html
]]>
Thanks to the authors of &xep0115; for coming up with the original idea of using presence broadcast to convey service discovery information, as well as the optimization strategies.
The note below the example in Advertisement of Support and Capabilities by Servers has been copied verbatimly from XEP-0115.
Thanks to Waqas Hussain for originally (to my knowledge) pointing out the security flaws in XEP-0115 (see &mlwaqas1;).
Thanks to Dave Cridland, Georg Lukas, Link Mauve, Sebastian Riese, Florian Schmaus and Sam Whited for their input, editorial and otherwise.