ssh: support RSA SHA-2 (RFC8332) signatures

This change adds support for RSA SHA-2 based signatures for host keys and certificates. It also switches the default certificate signature algorithm for RSA to use SHA-512. This is implemented by treating ssh.Signer specially when the key type is `ssh-rsa` by also allowing SHA-256 and SHA-512 signatures.

Fixes golang/go#37278

Change-Id: I2ee1ac4ae4c9c1de441a2d6cf1e806357ef18910
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/220037
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
Hans Nielsen
2021-11-15 23:45:14 +00:00
committed by Jason A. Donenfeld
parent ceb1ce70b4
commit b4de73f9ec
12 changed files with 213 additions and 69 deletions
+31 -47
View File
@@ -9,12 +9,12 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"io"
"net"
"reflect"
"testing"
"time"
"golang.org/x/crypto/ssh/testdata"
)
// Cert generated by ssh-keygen 6.0p1 Debian-4.
@@ -226,53 +226,33 @@ func TestHostKeyCert(t *testing.T) {
}
}
type legacyRSASigner struct {
Signer
}
func (s *legacyRSASigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
v, ok := s.Signer.(AlgorithmSigner)
if !ok {
return nil, fmt.Errorf("invalid signer")
}
return v.SignWithAlgorithm(rand, data, SigAlgoRSA)
}
func TestCertTypes(t *testing.T) {
var testVars = []struct {
name string
keys func() Signer
name string
signer Signer
algo string
}{
{
name: CertAlgoECDSA256v01,
keys: func() Signer {
s, _ := ParsePrivateKey(testdata.PEMBytes["ecdsap256"])
return s
},
},
{
name: CertAlgoECDSA384v01,
keys: func() Signer {
s, _ := ParsePrivateKey(testdata.PEMBytes["ecdsap384"])
return s
},
},
{
name: CertAlgoECDSA521v01,
keys: func() Signer {
s, _ := ParsePrivateKey(testdata.PEMBytes["ecdsap521"])
return s
},
},
{
name: CertAlgoED25519v01,
keys: func() Signer {
s, _ := ParsePrivateKey(testdata.PEMBytes["ed25519"])
return s
},
},
{
name: CertAlgoRSAv01,
keys: func() Signer {
s, _ := ParsePrivateKey(testdata.PEMBytes["rsa"])
return s
},
},
{
name: CertAlgoDSAv01,
keys: func() Signer {
s, _ := ParsePrivateKey(testdata.PEMBytes["dsa"])
return s
},
},
{CertAlgoECDSA256v01, testSigners["ecdsap256"], ""},
{CertAlgoECDSA384v01, testSigners["ecdsap384"], ""},
{CertAlgoECDSA521v01, testSigners["ecdsap521"], ""},
{CertAlgoED25519v01, testSigners["ed25519"], ""},
{CertAlgoRSAv01, testSigners["rsa"], SigAlgoRSASHA2512},
{CertAlgoRSAv01, &legacyRSASigner{testSigners["rsa"]}, SigAlgoRSA},
{CertAlgoRSAv01, testSigners["rsa-sha2-256"], SigAlgoRSASHA2512},
{CertAlgoRSAv01, testSigners["rsa-sha2-512"], SigAlgoRSASHA2512},
{CertAlgoDSAv01, testSigners["dsa"], ""},
}
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
@@ -304,7 +284,7 @@ func TestCertTypes(t *testing.T) {
go NewServerConn(c1, conf)
priv := m.keys()
priv := m.signer
if err != nil {
t.Fatalf("error generating ssh pubkey: %v", err)
}
@@ -320,6 +300,10 @@ func TestCertTypes(t *testing.T) {
t.Fatalf("error generating cert signer: %v", err)
}
if m.algo != "" && cert.Signature.Format != m.algo {
t.Errorf("expected %q signature format, got %q", m.algo, cert.Signature.Format)
}
config := &ClientConfig{
User: "user",
HostKeyCallback: func(h string, r net.Addr, k PublicKey) error { return nil },