Subject: Application data during key re-exchange

From: [email-masked] (Niels Möller)
Date: 12 Mar 2002 16:51:46 +0100

I'm sorry if this has been discussed before, but I don't remember the
outcome.

Consider a key re-exchange, and for simplicity, assume we're using the
diffie-hellman-group1-sha1 method. This is what happens:

  Client sends  Server sends
1 KEXINIT       KEXINIT       (in arbitrary order, or simultaneously)
2 KEXDH_INIT
3               KEXDH_REPLY
4               NEWKEYS
5 NEWKEYS

Can this message exchange be interleaved with other messages? More
precicely, is the server allowed to send other messages between 1 and
3, or between 3 and 4? Is the client allowed to send other messages
between 1 and 2, and 2 and 5?

My current code allows other messages between 1 and 2/3, but not
between 2/3 and 4/5. That doesn't seem quite right. The spec says:

: Key exchange ends by each side sending an SSH_MSG_NEWKEYS message.
: This message is sent with the old keys and algorithms. All messages
: sent after this message MUST use the new keys and algorithms.
: 
: When this message is received, the new keys and algorithms MUST be
: taken into use for receiving.
: 
: This message is the only valid message after key exchange, in
: addition to SSH_MSG_DEBUG, SSH_MSG_DISCONNECT and SSH_MSG_IGNORE
: messages. The purpose of this message is to ensure that a party is
: able to respond with a disconnect message that the other party can
: understand if something goes wrong with the key exchange.
: Implementations MUST NOT accept any other messages after key
: exchange before receiving SSH_MSG_NEWKEYS.

It's not entirely clear what is meant by "after key exchange" in the
final paragraph above. My interpretation is "after KEX_DHINIT" (in the
stream from the client) and "after KEX_DHREPLY" (in the stream from
the server).

Another possible interpretation is that the only messages that can be
sent between KEXINIT and NEWKEYS are key-exchange messages and DEBUG,
DISCONNECT and IGNORE. Then all channels on the connection will freeze
completely during the entire key exchange process, which seems
undesirable, in particular with slow connections and machines. For
client-initiated key exchange, it's two roundtrips.

How do you handle this?

Regards,
/Niels

---

From: "Joseph Galbraith" <[email-masked]>
Date: Tue, 12 Mar 2002 08:56:46 -0700

> client-initiated key exchange, it's two roundtrips.

Our interpretation is between KEXINIT and NEWKEYS
nothing is allowed.  So after sending a KEXINIT
packet, an implementation (client or server)
must not send any non-key-exchange packets
other than DEBUG, DISCONNECT, and IGNORE until
it has sent a NEWKEYS packet.

- Joseph

---

From: Markus Friedl <[email-masked]>
Date: Tue, 12 Mar 2002 17:04:07 +0100

> it has sent a NEWKEYS packet.

Yes, this is what OpenSSH does (or tries).

---

From: Bill Sommerfeld <[email-masked]>
Date: Tue, 12 Mar 2002 11:25:47 -0500

I simply don't see this as a showstopper.

> Then all channels on the connection will freeze
> undesirable, in particular with slow connections and machines. 

In many cases, the same sort of "freeze" will often happen if a TCP
segment is dropped (particularly when the traffic flow is
character-at-a-time interactive traffic); tcp falls back to the
retransmission timeout, which is typically several hundred ms.

Over a high latency path, you'll probably get more than one TCP
segment drop per hour.  Will the end user be able to tell the
difference between rekey and dropped packets?

Worrying too much about slow machines is historically not a good use
of people's engineering efforts.

						- Bill

---

From: [email-masked] (Niels Möller)
Date: 12 Mar 2002 19:38:43 +0100

> Yes, this is what OpenSSH does (or tries).

Ok, I guess I just have to do the same then.

/Niels

---

From: [email-masked] (Niels Möller)
Date: 12 Mar 2002 19:50:48 +0100

> I simply don't see this as a showstopper.

The primary reason my current code behaves the way it does is that it
was a lot simpler, and I didn't see any security reasons to disallow
other messages during key re-exchange, not that I have experienced
freezes during key re-exchange and found them unacceptable.

While waiting for the remote end to do its part of the key (re)exchange,
my code spends its time in its select loop. When events occur (say,
the user typed some characters, or a shell died and sent SIGCHLD
to the server), ssh messages are generated and they are encrypted and put
into the same write queue as all other messages on that connection.

To get this right, and make sure I never send any application messages
during key exchange, I will have to introduce another queue where any
"application" messages generated during key key-exchange are put, to
be sent after the keyexchange is finished. And I must also arrange
that I temporarily stop reading channel sources that can generate a
lot of data, to keep the size of the new queue from growing large.

Not a big deal, but it makes the code more complex.

Regards,
/Niels

---

From: "Andersson, Mats" <[email-masked]>
Date: Wed, 13 Mar 2002 08:38:32 +0100 (CET)

> undesirable, in particular with slow connections and machines. For

This is my interpretation. And how our implementation works (seems
cleanest doesn't it?). In our case it's also the most sensible thing to do
to disallow traffic from higher layers during keyexchange since we have a
multi-threaded implementation which would end up more complex and with
some extra unnecessary synchronization (i.e. checks for keyexchange in
progress). Given that the key-reexchange comes once an hour (or after one
GB data) it doesn't seem much of an issue IMHO.

Cheers,

/Mats