[Standards] serious bugs in XEP-0220 (Server Dialback)

Peter Saint-Andre stpeter at stpeter.im
Thu Apr 21 22:23:21 UTC 2011

I just completed a review of XEP-0220, which went through a Last Call in
late 2010 and is now under consideration by the XMPP Council for
advancement from Experimental to Draft (whether it should have been
Experimental after we copied it from RFC 3920 is another question...).

I think this spec contains serious bugs. I am writing this message to
the standards at xmpp.org list before making changes to the spec so that my
co-authors (really Philipp Hancke because Jer isn't on this list
anymore, although I've cc'd him), Council members, and others can check
my reading of the spec. I don't think I'm wrong about what follows, but
if I am wrong then we've all missed some serious bugs.

There are two basic problems:

1. In all of the examples of XEP-0220, the dialback key should be the
same key -- but the key varies across examples.

2. The 'id' of the <db:verify/> element should always be the StreamID of
the response stream header sent from the Receiving Server to the
Originating Server -- but sometimes the 'id' is the StreamID of the
response stream header sent from the Authoritative Server to the
Receiving Server.

Let's roll the video tape...

### SECTION 2.1.1 ###

Example 1. Originating Server Sends Dialback Key (step 1)

send: <db:result
==>     1e701f120f66824b57303384e83b51feba858024fd2221d39f7acc52dcf767a9

The key sent is generated as described in Dialback Key Generation and
Validation [6]:

key = HMAC-SHA256(
          { 'target.tld', ' ', 'sender.tld', ' ', 'D60000229F' }

[Philipp, can you verify that the key in Example 1 is correct based on
the inputs?]

### SECTION 2.1.2 ###

Example 5. Receiving Server Sends Verification Request to Authoritative
Server (step 2)

send: <db:verify
==>       id='417GAF25'
==>    38b501ec606752318f72ad53de17ac6d15f86257485b0d8f5d54e1f619e6b869

### SECTION 2.2.1 ###

Example 9. Receiving Server Receives Dialback Key from Originating
Server (step 1)

recv: <db:result
==>    1e701f120f66824b57303384e83b51feba858024fd2221d39f7acc52dcf767a9

### SECTION 2.2.2 ###

Example 13. Authoritative Server Receives Verification Request from
Receiving Server (step 2)

recv: <db:verify
==>       id='417GAF25'
==>    fed84f34d39682fd80bd04e01894f98c4149cf9df47575b134eeb6d2c7fe9fee


Upon receiving this <db:verify/> element, the Authoritative Server
determines the validity of the dialback key provided in the XML
character data of the element. This can be achieved for example by
comparing the character data with the output of applying the same key
generation mechanism that was (presumably) used for the generation of
the key, using as input the values of the 'from', 'to', and 'id'
attributes contained in the verification request and the secret known
only to the Sender Domain:

key = HMAC-SHA256(
          { 'sender.tld', ' ', 'target.tld', ' ', '417GAF25' }
    = fed84f34d39682fd80bd04e01894f98c4149cf9df47575b134eeb6d2c7fe9fee


What the heck is going on here?!?

(And yes, I'm to blame because I am the primary author of this spec.)

Look at that last text snippet. It shows the Authoritative Server
checking a dialback key that is generated using the secret key of the
*Target Domain* ("d14lb4ck43v3r") instead of the secret key of the
*Sender Domain* ("s3cr3tf0rd14lb4ck"), and using the StreamID of the
response stream header from the Authoritative Server to the Receiving
Server ("417GAF25") instead of the StreamID of the response stream
header from the Receiving Server to the Originating Server
("D60000229F"). This is utter nonsense!

Also nonsensical are Examples 5 and 13, which show the Receiving Server
sending a dialback key different from the dialback key that the
Originating Server sent in Example 1. But the Receiving Server does not
generate a dialback key -- it just sends to the Authoritative Server
whatever it has received from the Originating Server!

I also think that the <db:verify/> element in Examples 5 and 13 needs to
include the StreamID of the response stream header that the Receiving
Server has sent to the Originating Server. This ensures that the
Authoritative Server has the right StreamID to use as input to its
calculation of the key:

key = HMAC-SHA256(
          { 'target.tld', ' ', 'sender.tld', ' ', 'D60000229F' }

If the Authoritative server doesn't know about that StreamID, then
obviously it needs to return "invalid" to the Receiving Server:


(Naturally the Authoritative Server would also return "invalid" if its
secret is different from whatever the Originating Server used.)

But wait, there's more! These errors about the dialback key and StreamID
needlessly stray from RFC 3920, which has the following...


   3.  The Receiving Server SHOULD send a stream header back to the
       Originating Server, including a unique ID for this interaction:

==>    id='457F9224A0...'>


   4.  The Originating Server sends a dialback key to the Receiving

       to='Receiving Server'
       from='Originating Server'>
==>  98AF014EDC0...


   8.  The Receiving Server sends the Authoritative Server a request for
       verification of a key:

       from='Receiving Server'
       to='Originating Server'
==>    id='457F9224A0...'>
==>  98AF014EDC0...

[Same key, same 'id'!]


This mess is fairly easy to clean up, but the bugs are so fundamental
that I'd like a sanity check from folks on this list to ensure that I'm
not way off base here!

Thanks for listening.


Peter Saint-Andre

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 6105 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://mail.jabber.org/pipermail/standards/attachments/20110421/7b904de3/attachment.bin>

More information about the Standards mailing list