Subject: Re: [Curdle] SSH/QUIC draft

From: Benjamin Kaduk <[email-masked]>
Date: Tue, 4 Aug 2020 14:40:38 -0700

On Sat, Jul 11, 2020 at 09:02:50PM -0500, denis bider wrote:
> Ilari:
> 
> 
> > I presume server authentication should be done using the TLS server
> certificate.
> 
> Server authentication needs to happen using existing SSH host keys with no
> change for users. Users should be able to update to new SSH software
> versions that support SSH/QUIC and everything should work out of the box
> without the user noticing a difference. Server admins may need to open a
> UDP port in the firewall, and that's it.
[...]
> 
> > For client authentication, one probably should use SSH-layer mechanisms
> 
> For client authentication, we use the exact same mechanisms currently used
> in SSH.  Anything less than "no change for the user" does not fly.

I'd be interested in hearing what (if anything) Ilari has to say about the
potential for cross-protocol attacks when reusing ssh host and client keys
for this related-but-not-exactly-the-same protocol.  On the face of it it
seems like something that "requires careful analysis" and quickly skimming
draft-bider-ssh-quic didn't give me enough context to be able to say
anything useful.

-Ben

---

From: denis bider <[email-masked]>
Date: Tue, 4 Aug 2020 22:29:25 -0500

Benjamin:

Security of SSH signatures, both client and server-side, hinges on the
security of the exchange hash H. The manner in which H is calculated is
specified independently by each class of SSH key exchange method, but it
generally follows the same concept in all cases.

For example, Diffie Hellman key exchange is defined here:

https://tools.ietf.org/html/rfc4253#section-8

Each version of DH key exchange specifies a hash function that's used with
it. This hash function is used to calculate H as a digest of the following:

string V_C, the client's identification string (CR and LF excluded)
string V_S, the server's identification string (CR and LF excluded)
string I_C, the payload of the client's SSH_MSG_KEXINIT
string I_S, the payload of the server's SSH_MSG_KEXINIT
string K_S, the host key
mpint  e, exchange value sent by the client
mpint  f, exchange value sent by the server
mpint  K, the shared secret

For straightforward, one-roundtrip key exchanges such as DH – and same for
ECC, which is similar – the SSH/QUIC proposal instead replaces the
calculation of H as a digest of the following:

string Unencrypted "obfs-payload" content of SSH_QUIC_INIT
string Unencrypted "obfs-payload" content of SSH_QUIC_REPLY, excluding the
entire field "server-kex-alg-data"
The fields of "server-kex-alg-data", excluding signature field
mpint  K

https://www.ietf.org/id/draft-bider-ssh-quic-05.html#figure-9

For a cross-protocol attack, you'd want to manipulate one of these formats
to be not necessarily valid, but practically tolerated, by some reasonable
implementation, as an encoding of the other. This is a priori impossible
for implementations that meet the requirements to insert random data that
exist both in SSH (the KEXINIT cookie field) and in SSH/QUIC (section 2.6 -
Random Elements). However, let's consider an implementation that does not
meet this requirement because of resource constraints, for example software
that is running on a clothing tag.

In this case, the formats (for encoding data to calculate H) will not
collide because in SSH, the encoded blob starts like this:

00 00 00 nn 'S' 'S' 'H' '-' ...

The "nn" is the length of the SSH version string, and "SSH-" is a required
prefix of the SSH version string that will appear here.

On the other hand, in SSH/QUIC, the encoded blob starts like this:

00 00 jj kk 01 ...

The byte at offset 4 will have value 1, which is the packet number for
SSH_QUIC_INIT.

As far as I know, no SSH implementation will interoperate with one whose
version string does not start with "SSH-", and no as per the SSH/QUIC spec,
no implementation should interoperate with one that uses a value other than
specified for the SSH_QUIC_INIT packet number. Therefore the encodings are
strictly distinct.

Each side also performs the encoding of the binary blob to calculate H
separately, i.e. the encoding is not done by one side and blindly accepted
by the other. Therefore, there is no way to generate an encoding for SSH
that would also be accepted by a reasonable implementation in SSH/QUIC, or
vice versa.

While this does hinge on possibly non-obvious properties of the content
that's being encoded, these properties are fundamental enough that I don't
expect that they would be missed. If someone has concerns though, it's easy
enough to add a few non-zero bytes to the start of the SSH/QUIC encoding of
the blob to calculate H. For example, if we insert:

byte[8] "SSH/QUIC"

... before the other fields, then the distinctness of the encodings will be
even more obvious.

I will update the draft to insert that. While not strictly necessary, it's
good hygiene.

denis