Description
What version of Go are you using (go version
)?
$ go version
go version go1.19.2 linux/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="on" GOARCH="amd64" GOBIN="" GOCACHE="/home/praveen/.cache/go-build" GOENV="/home/praveen/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/local/praveen/go/pkg/mod" GONOPROXY="redacted-host" GONOSUMDB="redacted-host" GOOS="linux" GOPATH="/local/praveen/go" GOPRIVATE="redacted-host" GOPROXY="https://proxy.golang.org,direct" GOROOT="/home/praveen/sdk/go1.19.2" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/home/praveen/sdk/go1.19.2/pkg/tool/linux_amd64" GOVCS="" GOVERSION="go1.19.2" GCCGO="gccgo" GOAMD64="v1" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/local/praveen/src/crypto/go.mod" GOWORK="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3315967625=/tmp/go-build -gno-record-gcc-switches"
What did you do?
Authenticating to SSH server using rsa-sha2-512
used to work fine with in my Go program when I was using golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed
. However, after upgrading to the latest (v0.1.0) crypto, the same program is unable to authenticate successfully anymore. I narrowed down the regression to a particular commit 5d542ad81a58c89581d596f49d0ba5d435481bcf
. Key was generated using ssh-keygen -t rsa-sha2-512
. (openssh version 8.9p1-3 on Ubuntu jammy). SSH server used was Github enterprise edition (SSH-2.0-babeld-5f3a6bb
).
I have provided a test program to reproduce the issue below.
What did you expect to see?
Successful connection to the SSH server using the provided rsa-sha2-512
key.
What did you see instead?
Following error returned from the crypto library.
ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
Go Program to Reproduce/Bisect
Placed the following program in cmd/sshauthtest/main.go
under the local crypto git repo checked out based on v0.1.0 tag.
Note: I have redacted the username, hostname and key file path. Needs to be populated by the developer when reproducing the issue.
package main
import (
"fmt"
"net"
"os"
"golang.org/x/crypto/ssh"
)
func main() {
user := "***REDACTED***"
host := "***REDACTED***"
keyFilePath := "***REDACTED***"
keyBytes, err := os.ReadFile(keyFilePath)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to read private key file %s: %s", keyFilePath, err)
os.Exit(1)
}
signer, err := ssh.ParsePrivateKey(keyBytes)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to parse private key file %s: %s", keyFilePath, err)
os.Exit(1)
}
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: func(string, net.Addr, ssh.PublicKey) error {
return nil
},
}
if _, err := ssh.Dial("tcp", host, config); err != nil {
fmt.Fprintf(os.Stderr, "failed to connect to %s: %s", host, err)
os.Exit(1)
}
fmt.Printf("successfully connected to %s\n", host)
}
Git Bisection Result
$ git show --stat
commit 642fcc37f5043eadb2509c84b2769e729e7d27ef (HEAD -> master, tag: v0.1.0, origin/master, origin/HEAD)
Author: Gopher Robot <gobot@golang.org>
Date: Wed Oct 19 15:40:49 2022 +0000
go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.
Once this CL is submitted, and post-submit testing succeeds on all
first-class ports across all supported Go versions, this repository
will be tagged with its next minor version.
Change-Id: If840eea1cadc749ce55efd88eb7d9fc38472839e
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/443996
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Gopher Robot <gobot@golang.org>
go.mod | 8 ++++----
go.sum | 34 +++++++++++++++++++++++++++-------
2 files changed, 31 insertions(+), 11 deletions(-)
$ git bisect start HEAD 198e4374d7ed
Bisecting: 23 revisions left to test after this (roughly 5 steps)
[5352b09029215197cc109b46f0560d05ffab29db] acme/autocert: support External Account Binding (EAB) tokens
$ git bisect run go run ./cmd/sshauthtest
running 'go' 'run' './cmd/sshauthtest'
failed to connect to redacted-host:22: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remainexit status 1
Bisecting: 11 revisions left to test after this (roughly 4 steps)
[6068a2e6cfdc895ce524b6d2bdc8ea0cea8ea0e8] ssh: ignore MAC if AEAD ciphers negotiated
running 'go' 'run' './cmd/sshauthtest'
successfully connected to redacted-host:22
Bisecting: 5 revisions left to test after this (roughly 3 steps)
[1baeb1ce4c0b006eff0f294c47cb7617598dfb3d] ssh: don't advertise rsa-sha2 algorithms if we can't use them
running 'go' 'run' './cmd/sshauthtest'
successfully connected to redacted-host:22
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[3147a52a75dda54ac3a611ef8978640d85188a2a] ssh: support rsa-sha2-256/512 for client certificates
running 'go' 'run' './cmd/sshauthtest'
failed to connect to redacted-host:22: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remainexit status 1
Bisecting: 0 revisions left to test after this (roughly 1 step)
[5d542ad81a58c89581d596f49d0ba5d435481bcf] ssh: support rsa-sha2-256/512 for client authentication
running 'go' 'run' './cmd/sshauthtest'
failed to connect to redacted-host:22: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remainexit status 1
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[a5774263c1e06050d4c71b5794b2b5a321289a8f] ssh: send (and rename) keyboard-interactive name field to the client
running 'go' 'run' './cmd/sshauthtest'
successfully connected to redacted-host:22
5d542ad81a58c89581d596f49d0ba5d435481bcf is the first bad commit
commit 5d542ad81a58c89581d596f49d0ba5d435481bcf
Author: Filippo Valsorda <filippo@golang.org>
Date: Mon Mar 14 10:48:13 2022 -0400
ssh: support rsa-sha2-256/512 for client authentication
CL 220037 had implemented support for host authentication using
rsa-sha2-256/512, but not client public key authentication. OpenSSH
disabled the SHA-1 based ssh-rsa by default in version 8.8 (after
pre-announcing it in versions 8.2, 8.3, 8.4, 8.5, 8.6, and 8.7) although
some distributions re-enable it. GitHub will start rejecting ssh-rsa for
keys uploaded before November 2, 2021 on March 15, 2022.
https://github.blog/2021-09-01-improving-git-protocol-security-github/
The server side already worked, as long as the client selected one of
the SHA-2 algorithms, because the signature flowed freely to Verify.
There was however nothing verifying that the signature algorithm matched
the advertised one. The comment suggested the check was being performed,
but it got lost back in CL 86190043. Not a security issue because the
signature had to pass the callback's Verify method regardless, and both
values were checked to be acceptable.
Tested with OpenSSH 8.8 configured with "PubkeyAcceptedKeyTypes -ssh-rsa"
and no application-side changes.
The Signers returned by ssh/agent (when backed by an agent client)
didn't actually implement AlgorithmSigner but ParameterizedSigner, an
interface defined in an earlier version of CL 123955.
Updates golang/go#49269
Fixes golang/go#39885
For golang/go#49952
Change-Id: I13b41db8041f1112a70f106c55f077b904b12cb8
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/392394
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
ssh/agent/client.go | 24 ++++++----
ssh/client_auth.go | 116 +++++++++++++++++++++++++++++++++++++++---------
ssh/client_auth_test.go | 54 +++++++++++++++++++++-
ssh/common.go | 7 +--
ssh/handshake.go | 7 +++
ssh/messages.go | 11 +++++
ssh/server.go | 8 +++-
7 files changed, 192 insertions(+), 35 deletions(-)
bisect found first bad commit
Additional Debug Information
CC: @FiloSottile
I tried to debug further and narrowed down the difference in behavior to x/crypto/ssh.confirmKeyAck
function, which thinks that there is a mismatch between the algorithm used by the client and responded by the server. Note the additional fmt.Printf
that I added under case msgUserAuthPubKeyOk
.
func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) {
pubKey := key.Marshal()
for {
packet, err := c.readPacket()
if err != nil {
return false, err
}
switch packet[0] {
case msgUserAuthBanner:
if err := handleBannerResponse(c, packet); err != nil {
return false, err
}
case msgUserAuthPubKeyOk:
var msg userAuthPubKeyOkMsg
if err := Unmarshal(packet, &msg); err != nil {
return false, err
}
fmt.Printf("msg.Algo: %s, algo: %s\n", msg.Algo, algo)
if msg.Algo != algo || !bytes.Equal(msg.PubKey, pubKey) {
return false, nil
}
return true, nil
case msgUserAuthFailure:
return false, nil
default:
return false, unexpectedMessageError(msgUserAuthPubKeyOk, packet[0])
}
}
}
In the failing case, it produces the following output.
msg.Algo: ssh-rsa, algo: rsa-sha2-256
What is even more interesting is that the algo
was reported as rsa-sha2-256
even though it was generated as rsa-sha2-512
!
In the succeeding case, both are of value ssh-rsa
.
ssh-ed25519
works fine with both the new and old versions of crypto library. As a workaround for now, we are recommending our users to stick with ed25519
keys because of this issue.