Description
Go version
go version go1.20.13 linux/amd64
Output of go env
in your module/workspace:
GO111MODULE=""
GOARCH="amd64"
GOVERSION="go1.20.13"
GCCGO="gccgo"
GOAMD64="v1"
What did you do?
Connect a lot of times to the SSH server with an RSA public key using PuTTY.
What did you see happen?
Occasional login failures with crypto/rsa: verification error
What did you expect to see?
All successes.
The issue is due to a short signature, rejected by rsa.VerifyPKCS1v15
.
https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
The resulting signature is encoded as follows:
string "ssh-rsa" string rsa_signature_blob
The value for 'rsa_signature_blob' is encoded as a string containing
s (which is an integer, without lengths or padding, unsigned, and in
network byte order).
Which requires the signature to be unpadded.
I spoke with the PuTTY maintainer about this, Simon Tatham. His view is that the SSH RFC supercedes the PKCS RFC (8017), so the short signature is OK (in fact required).
However this approach is reversed in
https://datatracker.ietf.org/doc/html/rfc8332#section-3
The resulting signature is encoded as follows:
string "rsa-sha2-256" / "rsa-sha2-512"
string rsa_signature_blobThe value for 'rsa_signature_blob' is encoded as a string that
contains an octet string S (which is the output of RSASSA-PKCS1-v1_5)
and that has the same length (in octets) as the RSA modulus. When S
contains leading zeros, there exist signers that will send a shorter
encoding of S that omits them. A verifier MAY accept shorter
encodings of S with one or more leading zeros omitted.
and I believe that PuTTY may be fixed for this when using the new signature types (or even always). But even if it is, lots of PuTTY installs out there that will not be updated for a long time. (And WinSCP embeds PuTTY, thus has a similar issue... FileZilla as well potentially.)
In practice, the OpenSSH verify logic always allows unpadded signatures, while the sign logic always pads them (at least based on a quick read of https://github.com/openssh/openssh-portable/blob/master/ssh-rsa.c ssh_rsa_sign and ssh_rsa_verify). The current Go implementation is out of spec for ssh-rsa
signatures, but it would be the flexible thing to do to also always allow the short signatures, as this is allowed by the RFC and (arguably) the most popular SSH server.
I'm happy to write up a patch if there are any prospects of it being accepted (past experience suggests this is best left to the core team though).