Subject: Publish ID draft-openssh-secsh-compression-delayed-00.txt

From: Damien Miller <[email-masked]>
Date: Mon, 20 Nov 2006 23:30:39 +1100 (EST)

Hi,

Please publish the attached I-D: draft-openssh-secsh-compression-delayed-00.txt

Thanks,
Damien Miller

---

From: Joseph Galbraith <[email-masked]>
Date: Mon, 20 Nov 2006 08:15:40 -0700

> Please publish the attached I-D: draft-openssh-secsh-compression-delayed-00.txt

Thanks for publishing this; just FYI: I believe we have
an inter-operable implementation of this.

>    The "zlib" compression in method defined in [RFC4253] for the SSH
>    protocol uses ZLIB (LZ77) compression (as described in [RFC1950] and
>    [RFC1951]).  This method activates compression after the completion
>    of the key exchange algorithm, upon the receipt of the
>    SSH_MSG_NEWKEYS message.  This step occurs before user authentication
>    [RFC4252] completes, so a bug in the underlying compression code
>    could be exposed to unauthenticated users.
> 
>    This new compression method "[email-masked]" addresses this risk by
>    delaying the start of compression until the completion of the user
>    authentication exchange.

An additional benefit of this is that it prevents sensitive
information such as the username and password from becoming
part of the internal zlib state where it is hard to scrub
it from memory.

> 3.  Delayed Compression
> 
>    The "[email-masked]" method operates identically to the "zlib"
>    method described in [RFC4252] except that packet compression does not

I believe you probably meant to reference RFC4253 (transport)
here?

>    start until the server sends a SSH_MSG_USERAUTH_SUCCESS packet,
>    replacing the "zlib" method's start of compression when the server
>    sends SSH_MSG_NEWKEYS.
> 
>    Specifically, this means that a server selecting this method MUST
>    compress the first packet after SSH_MSG_USERAUTH_SUCCESS and all
>    subsequent packets.  The client MUST compress all packets it sends
>    after the time that it receives SSH_MSG_USERAUTH_SUCCESS.

Isn't this problematic on the client side?  The server doesn't
know when the client will receive the SSH_MSG_USERAUTH_SUCCESS.

In fact, I RFC4352 allows the client to send multiple
auth requests with out waiting for a response.  The server
is suppose to ignore any auth requests after success:

>    The client MAY send several authentication requests without waiting
>    for responses from previous requests.  The server MUST process each
>    request completely and acknowledge any failed requests with a
>    SSH_MSG_USERAUTH_FAILURE message before processing the next request.
> 
>    A request that requires further messages to be exchanged will be
>    aborted by a subsequent request.  A client MUST NOT send a subsequent
>    request if it has not received a response from the server for a
>    previous request.  A SSH_MSG_USERAUTH_FAILURE message MUST NOT be
>    sent for an aborted method.
> 
>    SSH_MSG_USERAUTH_SUCCESS MUST be sent only once.  When
>    SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication
>    requests received after that SHOULD be silently ignored.

In this case (or possibly in the case of DEBUG, IGNORE, or even
a KEXINIT packet) the server might receive uncompressed packets
after it sends the SSH_MSG_USERAUTH_SUCCESS-- the server really
has no way of determining at what point the packet stream became
compressed.

Of course in most implementations, it is okay since clients tend
to send one auth method at a time and wait for the response.

Thanks,

Joseph

---

From: Simon Tatham <[email-masked]>
Date: Mon, 20 Nov 2006 14:58:18 +0000

>    after the time that it receives SSH_MSG_USERAUTH_SUCCESS.

(I've already said this to Damien, but I'll say it here as well now
this is published.)

I believe this specification includes an inherent race condition,
causing the server to be unable to unambiguously determine whether a
given packet from the client is compressed or not.

The last userauth-layer packet sent by the client (say,
SSH_MSG_USERAUTH_REQUEST) is clearly uncompressed, because the
server hasn't sent SSH_MSG_USERAUTH_SUCCESS in response to it yet.
And the first connection-layer packet is clearly compressed, because
the client wouldn't have sent it except in response _to_
SSH_MSG_USERAUTH_SUCCESS. But what about transport-layer packets in
between?

If the client sends SSH_MSG_IGNORE, or initiates a rekey, in between
the last userauth-layer packet and the first connection-layer
packet, then the server might easily be unable to tell whether that
client packet was sent before or after the client received
SSH_MSG_USERAUTH_SUCCESS. The packet contains no flag to indicate
whether it's compressed; you can't go by the packet type code
because that's part of the potentially compressed payload; as far as
I can see there is no reliable way to resolve this race condition.

There should be a packet sent from the client which explicitly
indicates that subsequent packets will be compressed, as there is in
the normal KEX procedure (SSH_MSG_NEWKEYS is sent in _both_
directions). The server-to-client side is unambiguous, of course,
because SSH_MSG_USERAUTH_SUCCESS itself doubles as that packet.

As far as I can see, the only _safe_ way for a client to implement
this compression method as currently specified is to note it being
offered in the initial kex, but not to accept that offer, and then
to initiate a rekey after authentication in which we enable it.
-- 
Simon Tatham         These are my opinions. There are many
<[email-masked]>   like them but these ones are mine.

---

From: Bill Sommerfeld <[email-masked]>
Date: Mon, 20 Nov 2006 13:04:58 -0500

> know when the client will receive the SSH_MSG_USERAUTH_SUCCESS.

Indeed.  Seems to me like you'd need a client message saying
"compression starts after this message" to avoid this ambiguity.

						- Bill

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Mon, 20 Nov 2006 17:53:53 -0500

> to initiate a rekey after authentication in which we enable it.

... at which point, compression would start after SSH_MSG_NEWKEYS :-)

---

From: Damien Miller <[email-masked]>
Date: Tue, 21 Nov 2006 12:21:48 +1100 (EST)

[removing internet-drafts@ from the Cc]

> "compression starts after this message" to avoid this ambiguity.

That is a good idea. As other have observed, OpenSSH doesn't suffer from
the race because it doesn't send other packets after authentication.

So we could define a global message with no "payload":

SSH_MSG_CLIENT_AUTHDONE	62

The client would send this message upon receipt of the SSH_MSG_USERAUTH_SUCCESS.
If the client has selected the delayed compression mode, it will be the
last uncompressed message it sends.

-d

---

From: Nicolas Williams <[email-masked]>
Date: Mon, 20 Nov 2006 21:28:32 -0600

> SSH_MSG_CLIENT_AUTHDONE	62

SSH_MSG_NEW_COMPRESSION, make its payload the name of the compression
algorithm.  Or re-use KEX, see below.

> The client would send this message upon receipt of the SSH_MSG_USERAUTH_SUCCESS.

Or whenever it wants, but NOT before then (since the whole point is not
to have compression in use prior to dropping privileges needed to
perform authentication on the server side).

> last uncompressed message it sends.

The nice thing about using a KEX for negotiating a new compression
algorithm is that both peers are in control -- the server can continue
to not offer compression until authentication is completed, for example.

With SSH_MSG_NEW_COMPRESSION the client can't know whether the server is
ready for it.  And the whole we-need-this-so-we-can-do-compression-
after-dropping-privs thing smacks me as rather implementation specific.

KEX doesn't have that problem.

What's not nice about using KEX to negotiate a new compression algorithm
is that KEX is not cheap.  If there was a no-op key exchange algorithm
for use in re-keying whose purpose was to allow re-negotiation of things
other than session keys (and could not be used for initial KEX, but
could be advertised in initial KEX) then we could just use
KEXINIT/KEX*/NEWKEYS to negotiate compression and all would be fine.

Nico
--

---

From: Damien Miller <[email-masked]>
Date: Tue, 21 Nov 2006 16:12:01 +1100 (EST)

> after-dropping-privs thing smacks me as rather implementation specific.

Which is why I suggested a "client authentication complete" and not a
"I'm starting compression" message. The message will only have meaning
to a server that is using a delayed compression method, and the server
can respond appropriately if it is sent at an inappropriate time, such
as before it has sent a SSH_MSG_USERAUTH_SUCCESS.

> KEXINIT/KEX*/NEWKEYS to negotiate compression and all would be fine.

Well, the only things that can be safely renegotiated in KEX are 
compression and languages - I don't think it would be safe to 
renegotiate MACs/ciphers whilst retaining the same keys. I don't see
much practicality in renegotiating languages, so you would effectively 
be defining a whole new KEX exchange just to negotiate the compression
method.

-d

---

From: Ben Harris <[email-masked]>
Date: Tue, 21 Nov 2006 13:38:51 +0000

>last uncompressed message it sends.

You probably don't want to use 62, since that's in the range reserved
for the current userauth method.  Somewhere in 54-59 would be more
appropriate (and would require a Standards Action to get it allocated).

It seems to me, though, that allocating a whole new message number is
overkill here.  If you're happy to overload existing messages, you could
just say that the last uncompressed packets are the
SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT for "ssh-connection".

-- 
Ben Harris

---

From: Ben Harris <[email-masked]>
Date: Tue, 21 Nov 2006 15:17:17 +0000

>SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT for "ssh-connection".

Simon's just pointed out that I'm being an idiot and this isn't how 
ssh-connection starts.  Sorry about that.

-- 
Ben Harris