Subject: Re: rsa-sha2-256/512: handling of incorrect signature encoding

From: "denis bider \(Bitvise\)" <[email-masked]>
Date: Tue, 2 Aug 2016 13:54:45 -0600

> Yeah, so my code does use "rsa-sha2-256" after all for the auth and sig type,

OK, that sounds right. :-)

> What we actually need is interop test servers,

I did set up a test server for the new rsa-sha2-XXX signature types; I posted connection information here, and included instructions to test both server and client authentication. I was under the impression that you might have used it, but I’m not sure if you did.

At this point, the implementation is available in our published latest release, which can be downloaded and tested free of charge (though it does require a Windows VM or computer).

> Make it one again, it did use the correct string, 
> it was only the mix of SHA-256 + SHA-1 at the 
> same time that would have caused problems.

That’s a relief. Sounds great. :-)

From: Peter Gutmann 
Sent: Tuesday, August 2, 2016 03:07
To: denis bider (Bitvise) ; [email-masked] 
Subject: RE: rsa-sha2-256/512: handling of incorrect signature encoding

denis bider (Bitvise) <[email-masked]> writes:

>This is actually exactly contrary to what the current draft says, and what it
>has said for 9 months in its latest version.
>
>If you are sending an rsa-sha2-XXX signature, you cannot set all 3 fields in
>the authentication request to "ssh-rsa", because then this makes for a SHA-1
>signature as it was done traditionally, not a SHA-2 signature. To send a
>SHA-2 signature, at least one field has to contain "rsa-sha2-XXX".

I've looked through my code and saw why it works currently, I assume that if
you've negotiated SHA-256 in the client/server hello (keyex) then the auth
will also use SHA-256 (it would seem a bit strange to use a strong hash
everywhere else in the exchange and then fall back to a weak one for the
auth).  So in my case unless you use SHA-256 everywhere but then decide to use
SHA-1 in the auth, things will work.

>The draft specifically says the signature format names are "rsa-sha2-XXX",
>but the public key format name stays "ssh-rsa", which it must stay in order
>to preserve existing RSA key fingerprints.

Yeah, so my code does use "rsa-sha2-256" after all for the auth and sig type,
it just wasn't obvious at first glance because the hash is implied.  I've made
the one-line change to allow use of SHA-256 everywhere but then SHA-1 for the
auth.

>My strong preference would have been for implementations - especially the
>early implementations - to verify this strictly, and to not accept signatures
>that depart from this spec. 

What we actually need is interop test servers, with everyone doing this more
or less in isolation (there was nothing to test against when I did this, and
for the ECC stuff it wasn't much better, was it you that set up an SSH-ECC
server for testing when the draft was published?) you end up with
implementations that do all sorts of things.

>Unfortunately, we now appear to be in a situation where not only one, but
>potentially two implementations depart from the above spec. 

Make it one again, it did use the correct string, it was only the mix of
SHA-256 + SHA-1 at the same time that would have caused problems.

Peter.

---

From: "denis bider \(Bitvise\)" <[email-masked]>
Date: Mon, 1 Aug 2016 15:27:14 -0600

> I would change the rsa-sha2 draft to say
> that the same ID string should be used
> throughout, i.e. "ssh-rsa" for RSA sigs and keys.

This is actually exactly contrary to what the current draft says, and what it has said for 9 months in its latest version.

If you are sending an rsa-sha2-XXX signature, you cannot set all 3 fields in the authentication request to "ssh-rsa", because then this makes for a SHA-1 signature as it was done traditionally, not a SHA-2 signature. To send a SHA-2 signature, at least one field has to contain "rsa-sha2-XXX".

The draft specifically says the signature format names are "rsa-sha2-XXX", but the public key format name stays "ssh-rsa", which it must stay in order to preserve existing RSA key fingerprints.

The signature format is defined thus:

  string    "rsa-sha2-256" / "rsa-sha2-512"
  string    rsa_signature_blob

These specifications seem to me very clear and unambiguous. In a user authentication request, when sending a SHA-2 signature, the only correct encoding of algorithm names is as follows:

byte      SSH_MSG_USERAUTH_REQUEST
string    user name
string    service name
string    "publickey"
boolean   TRUE
string    "rsa-sha2-256" / "rsa-sha2-512"
string    public key blob:
  string    "ssh-rsa"
  mpint     e
  mpint     n
string    signature:
  string    "rsa-sha2-256" / "rsa-sha2-512"
  string    rsa_signature_blob
 
If your implementation does not encode the algorithm names this way, it is incorrect. The latest OpenSSH versions encode the algorithm names this way, though a previous version used "ssh-rsa" in the third field by mistake.

Bitvise SSH Client encodes the fields this way also, and the current version of Bitvise SSH Server expects the algorithm names this way, and only this way.

My strong preference would have been for implementations - especially the early implementations - to verify this strictly, and to not accept signatures that depart from this spec. Once a deployed based of strict and correct implementations is in place, it would have been difficult for later implementations to do anything incorrectly.

Unfortunately, we now appear to be in a situation where not only one, but potentially two implementations depart from the above spec. Therefore, it definitely seems to me that we need a section about this in the draft, and current and future implementations might need to err on the side of being permissive. :( :-/

----- Original Message -----
From: Peter Gutmann 
Sent: Monday, August 1, 2016 06:30
To: denis bider (Bitvise) ; [email-masked] 
Subject: RE: rsa-sha2-256/512: handling of incorrect signature encoding

denis bider (Bitvise) <[email-masked]> writes:

>The invariants our implementation currently expects are:
>- name 1, in the USERAUTH request, can be any of the RSA signature algorithm names
>- name 2, in the public key blob, must be "ssh-rsa"
>- name 3, in the signature blob, must match name 1

My code writes "ssh-rsa" for all three, and accepts whatever it finds (along
with a sarcastic comment about why you need to specify the same thing three
times in a row in case the server has gone deaf or something :-).  For the
first one:

/* Skip the first of the three copies of the algorithm name (see the comment
   in ssh2_cli.c for more on this).  We don't do anything with it because
   we're about to get two more copies of the same thing, and the key and
   signature information take precedence over anything that we find here */

Then for the second one it looks for ssh-rsa (or ssh-dss, or whatever, since
it's needed to decode the key), and finally it again ignores the last one
because it already knows what it should be.

Why is there a need for "rsa-sha2-256" and other complications when "ssh-rsa"
is perfectly OK for everything else?

>My questions are:
>[...]

I would use (C) ignore everything except the key blob name.  This situation is
confusing enough that you're going to get implementations screwing things up
in all sorts of ways, meaning you'll find who knows what in those ID strings.
Apart from having to know what format the key is in the rest is irrelevant,
you know the key is RSA, you've been hashing with SHA-1 or SHA-256 or
whatever, it doesn't matter what the ID strings say.

>Regardless of what we think is best - should we put a paragraph about this in
>the rsa-sha2 draft?

I would change the rsa-sha2 draft to say that the same ID string should be
used throughout, i.e. "ssh-rsa" for RSA sigs and keys.

Peter.

---

From: Peter Gutmann <[email-masked]>
Date: Mon, 1 Aug 2016 12:30:58 +0000

Peter.

---

From: Peter Gutmann <[email-masked]>
Date: Tue, 2 Aug 2016 09:07:23 +0000

Peter.

---

From: Peter Gutmann <[email-masked]>
Date: Wed, 3 Aug 2016 10:49:17 +0000

denis bider (Bitvise) <[email-masked]> writes:

>I did set up a test server for the new rsa-sha2-XXX signature types; I posted
>connection information here, and included instructions to test both server and
>client authentication. I was under the impression that you might have used it,
>but I’m not sure if you did.

I did, but not for pubkey auth, for lack of a key to auth with.

Is it worth stating, in the draft, that if you use sha256 everywhere else then
you should also use it for pubkey auth?  I can't see any reason why you'd want
to use SHA-1 for that when you're using SHA-2 for everything else.  Then you
could also use the server's advertising SHA-2 to indicate that it'll take a
SHA-2 sig for auth.

Peter.

---

From: "denis bider \(Bitvise\)" <[email-masked]>
Date: Wed, 3 Aug 2016 14:10:10 -0600

What type of “advertising SHA-2” do you mean? If the server advertises rsa-sha2-256 or -512 for server authentication, then it also needs to have an RSA host key. But the server might not have an RSA host key, it might only have an ECDSA or Curve25519 host key. However, the server still wants to permit a client to configure an RSA key for user authentication, and to use SHA-2 signatures for this.

In this situation, the server cannot advertise an rsa-sha2-XXX algorithm for host authentication. The mechanism for the server to announce support for SHA-2 signatures in client authentication is using the EXT_INFO message, specifically the “server-sig-algs” extension described here:

https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info-00

If the server sends an EXT_INFO message with the “server-sig-algs” extension indicating support for rsa-sha2-256 or rsa-sha2-512, then the client can assume the server will accept an RSA SHA-2 signature during user authentication. However, such a signature still has to be correctly encoded (with the algorithm names as discussed in this thread).

From: Peter Gutmann 
Sent: Wednesday, August 3, 2016 04:49
To: denis bider (Bitvise) ; [email-masked] 
Subject: RE: rsa-sha2-256/512: handling of incorrect signature encoding

Peter.

---

From: Peter Gutmann <[email-masked]>
Date: Thu, 4 Aug 2016 04:04:16 +0000

denis bider (Bitvise) <[email-masked]> writes:

>What type of “advertising SHA-2” do you mean? If the server advertises rsa-
>sha2-256 or -512 for server authentication, then it also needs to have an RSA
>host key. But the server might not have an RSA host key, it might only have
>an ECDSA or Curve25519 host key. 

I was thinking of it in an opportunistic-upgrade sense, for example for PGP
and S/MIME the mandatory algorithm is SHA-1 but if you receive a message
signed with SHA-2 you can switch to that because the client will be able to
process it.  So if you see ecdsa-sha2... or rsa-sha2... in the keyex then you
know the other side can do SHA2, and should do the auth with SHA2 as well.

>In this situation, the server cannot advertise an rsa-sha2-XXX algorithm for
>host authentication. 

It's not so much can it do RSA-SHA2, but can it do SHA2 in general rather than
SHA1.

Peter.

---

From: Matt Johnston <[email-masked]>
Date: Thu, 4 Aug 2016 18:51:04 +0800

> process it.  So if you see ecdsa-sha2... or rsa-sha2... in the keyex then you

The pubkey signature could have come from a ssh-agent (only
supporting rsa-sha1) that's elsewhere to the SSH client.

Cheers,
Matt