ssh: export supported algorithms

Fixes golang/go#61537

Change-Id: If3478121e3ae445391e3faeceeb889d75e9e3214
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/531935
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
Nicola Murino
2025-05-15 10:43:30 -07:00
committed by Gopher Robot
parent 9dbbcf002b
commit ac58737d25
23 changed files with 482 additions and 213 deletions
+11 -11
View File
@@ -555,7 +555,7 @@ func (c *client) insertKey(s interface{}, comment string, constraints []byte) er
})
case *dsa.PrivateKey:
req = ssh.Marshal(dsaKeyMsg{
Type: ssh.KeyAlgoDSA,
Type: ssh.InsecureKeyAlgoDSA,
P: k.P,
Q: k.Q,
G: k.G,
@@ -803,16 +803,16 @@ var _ ssh.AlgorithmSigner = &agentKeyringSigner{}
//
// This map must be kept in sync with the one in certs.go.
var certKeyAlgoNames = map[string]string{
ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA,
ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256,
ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512,
ssh.CertAlgoDSAv01: ssh.KeyAlgoDSA,
ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256,
ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384,
ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521,
ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256,
ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519,
ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519,
ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA,
ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256,
ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512,
ssh.InsecureCertAlgoDSAv01: ssh.InsecureKeyAlgoDSA,
ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256,
ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384,
ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521,
ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256,
ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519,
ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519,
}
// underlyingAlgo returns the signature algorithm associated with algo (which is
+2 -2
View File
@@ -506,7 +506,7 @@ func (s *server) insertIdentity(req []byte) error {
switch record.Type {
case ssh.KeyAlgoRSA:
addedKey, err = parseRSAKey(req)
case ssh.KeyAlgoDSA:
case ssh.InsecureKeyAlgoDSA:
addedKey, err = parseDSAKey(req)
case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
addedKey, err = parseECDSAKey(req)
@@ -514,7 +514,7 @@ func (s *server) insertIdentity(req []byte) error {
addedKey, err = parseEd25519Key(req)
case ssh.CertAlgoRSAv01:
addedKey, err = parseRSACert(req)
case ssh.CertAlgoDSAv01:
case ssh.InsecureCertAlgoDSAv01:
addedKey, err = parseDSACert(req)
case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
addedKey, err = parseECDSACert(req)
+23 -18
View File
@@ -20,14 +20,19 @@ import (
// returned by MultiAlgorithmSigner and don't appear in the Signature.Format
// field.
const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
CertAlgoDSAv01 = InsecureCertAlgoDSAv01
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
InsecureCertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
// CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a
// Certificate.Type (or PublicKey.Type), but only in
@@ -485,16 +490,16 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
//
// This map must be kept in sync with the one in agent/client.go.
var certKeyAlgoNames = map[string]string{
CertAlgoRSAv01: KeyAlgoRSA,
CertAlgoRSASHA256v01: KeyAlgoRSASHA256,
CertAlgoRSASHA512v01: KeyAlgoRSASHA512,
CertAlgoDSAv01: KeyAlgoDSA,
CertAlgoECDSA256v01: KeyAlgoECDSA256,
CertAlgoECDSA384v01: KeyAlgoECDSA384,
CertAlgoECDSA521v01: KeyAlgoECDSA521,
CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
CertAlgoED25519v01: KeyAlgoED25519,
CertAlgoSKED25519v01: KeyAlgoSKED25519,
CertAlgoRSAv01: KeyAlgoRSA,
CertAlgoRSASHA256v01: KeyAlgoRSASHA256,
CertAlgoRSASHA512v01: KeyAlgoRSASHA512,
InsecureCertAlgoDSAv01: InsecureKeyAlgoDSA,
CertAlgoECDSA256v01: KeyAlgoECDSA256,
CertAlgoECDSA384v01: KeyAlgoECDSA384,
CertAlgoECDSA521v01: KeyAlgoECDSA521,
CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
CertAlgoED25519v01: KeyAlgoED25519,
CertAlgoSKED25519v01: KeyAlgoSKED25519,
}
// underlyingAlgo returns the signature algorithm associated with algo (which is
+1 -1
View File
@@ -297,7 +297,7 @@ func TestCertTypes(t *testing.T) {
{"legacyRSASigner", &legacyRSASigner{testSigners["rsa"]}, KeyAlgoRSA},
{"multiAlgoRSASignerSHA256", multiAlgoSignerSHA256, KeyAlgoRSASHA256},
{"multiAlgoRSASignerSHA512", multiAlgoSignerSHA512, KeyAlgoRSASHA512},
{CertAlgoDSAv01, testSigners["dsa"], ""},
{InsecureCertAlgoDSAv01, testSigners["dsa"], ""},
}
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+11 -13
View File
@@ -98,36 +98,36 @@ func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream,
var cipherModes = map[string]*cipherMode{
// Ciphers from RFC 4344, which introduced many CTR-based ciphers. Algorithms
// are defined in the order specified in the RFC.
"aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
"aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
"aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
CipherAES128CTR: {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
CipherAES192CTR: {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
CipherAES256CTR: {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
// Ciphers from RFC 4345, which introduces security-improved arcfour ciphers.
// They are defined in the order specified in the RFC.
"arcfour128": {16, 0, streamCipherMode(1536, newRC4)},
"arcfour256": {32, 0, streamCipherMode(1536, newRC4)},
InsecureCipherRC4128: {16, 0, streamCipherMode(1536, newRC4)},
InsecureCipherRC4256: {32, 0, streamCipherMode(1536, newRC4)},
// Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol.
// Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and
// RC4) has problems with weak keys, and should be used with caution."
// RFC 4345 introduces improved versions of Arcfour.
"arcfour": {16, 0, streamCipherMode(0, newRC4)},
InsecureCipherRC4: {16, 0, streamCipherMode(0, newRC4)},
// AEAD ciphers
gcm128CipherID: {16, 12, newGCMCipher},
gcm256CipherID: {32, 12, newGCMCipher},
chacha20Poly1305ID: {64, 0, newChaCha20Cipher},
CipherAES128GCM: {16, 12, newGCMCipher},
CipherAES256GCM: {32, 12, newGCMCipher},
CipherChaCha20Poly1305: {64, 0, newChaCha20Cipher},
// CBC mode is insecure and so is not included in the default config.
// (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely
// needed, it's possible to specify a custom Config to enable it.
// You should expect that an active attacker can recover plaintext if
// you do.
aes128cbcID: {16, aes.BlockSize, newAESCBCCipher},
InsecureCipherAES128CBC: {16, aes.BlockSize, newAESCBCCipher},
// 3des-cbc is insecure and is not included in the default
// config.
tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher},
InsecureCipherTripleDESCBC: {24, des.BlockSize, newTripleDESCBCCipher},
}
// prefixLen is the length of the packet prefix that contains the packet length
@@ -635,8 +635,6 @@ func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader
return nil
}
const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
// AEAD, which is described here:
//
+11 -11
View File
@@ -22,7 +22,7 @@ func TestDefaultCiphersExist(t *testing.T) {
t.Errorf("supported cipher %q is unknown", cipherAlgo)
}
}
for _, cipherAlgo := range preferredCiphers {
for _, cipherAlgo := range defaultCiphers {
if _, ok := cipherModes[cipherAlgo]; !ok {
t.Errorf("preferred cipher %q is unknown", cipherAlgo)
}
@@ -30,8 +30,8 @@ func TestDefaultCiphersExist(t *testing.T) {
}
func TestPacketCiphers(t *testing.T) {
defaultMac := "hmac-sha2-256"
defaultCipher := "aes128-ctr"
defaultMac := HMACSHA256
defaultCipher := CipherAES128CTR
for cipher := range cipherModes {
t.Run("cipher="+cipher,
func(t *testing.T) { testPacketCipher(t, cipher, defaultMac) })
@@ -47,7 +47,7 @@ func testPacketCipher(t *testing.T, cipher, mac string) {
algs := directionAlgorithms{
Cipher: cipher,
MAC: mac,
Compression: "none",
Compression: compressionNone,
}
client, err := newPacketCipher(clientKeys, algs, kr)
if err != nil {
@@ -78,9 +78,9 @@ func testPacketCipher(t *testing.T, cipher, mac string) {
func TestCBCOracleCounterMeasure(t *testing.T) {
kr := &kexResult{Hash: crypto.SHA1}
algs := directionAlgorithms{
Cipher: aes128cbcID,
MAC: "hmac-sha1",
Compression: "none",
Cipher: InsecureCipherAES128CBC,
MAC: HMACSHA1,
Compression: compressionNone,
}
client, err := newPacketCipher(clientKeys, algs, kr)
if err != nil {
@@ -141,7 +141,7 @@ func TestCVE202143565(t *testing.T) {
constructPacket func(packetCipher) io.Reader
}{
{
cipher: gcm128CipherID,
cipher: CipherAES128GCM,
constructPacket: func(client packetCipher) io.Reader {
internalCipher := client.(*gcmCipher)
b := &bytes.Buffer{}
@@ -159,7 +159,7 @@ func TestCVE202143565(t *testing.T) {
},
},
{
cipher: chacha20Poly1305ID,
cipher: CipherChaCha20Poly1305,
constructPacket: func(client packetCipher) io.Reader {
internalCipher := client.(*chacha20Poly1305Cipher)
b := &bytes.Buffer{}
@@ -201,13 +201,13 @@ func TestCVE202143565(t *testing.T) {
}
for _, tc := range tests {
mac := "hmac-sha2-256"
mac := HMACSHA256
kr := &kexResult{Hash: crypto.SHA1}
algs := directionAlgorithms{
Cipher: tc.cipher,
MAC: mac,
Compression: "none",
Compression: compressionNone,
}
client, err := newPacketCipher(clientKeys, algs, kr)
if err != nil {
+4 -1
View File
@@ -324,6 +324,9 @@ func TestMethodInvalidAlgorithm(t *testing.T) {
}
func TestClientHMAC(t *testing.T) {
supportedAlgos := SupportedAlgorithms()
insecureAlgos := InsecureAlgorithms()
supportedMACs := append(supportedAlgos.MACs, insecureAlgos.MACs...)
for _, mac := range supportedMACs {
config := &ClientConfig{
User: "testuser",
@@ -349,7 +352,7 @@ func TestClientUnsupportedCipher(t *testing.T) {
PublicKeys(),
},
Config: Config{
Ciphers: []string{"aes128-cbc"}, // not currently supported
Ciphers: []string{"unsupported-cipher"}, // not currently supported
},
}
if err := tryAuth(t, config); err == nil {
+5 -5
View File
@@ -292,7 +292,7 @@ func TestUnsupportedAlgorithm(t *testing.T) {
{
"unsupported and supported KEXs",
Config{
KeyExchanges: []string{"unsupported", kexAlgoCurve25519SHA256},
KeyExchanges: []string{"unsupported", KeyExchangeCurve25519},
},
"",
},
@@ -306,7 +306,7 @@ func TestUnsupportedAlgorithm(t *testing.T) {
{
"unsupported and supported ciphers",
Config{
Ciphers: []string{"unsupported", chacha20Poly1305ID},
Ciphers: []string{"unsupported", CipherChaCha20Poly1305},
},
"",
},
@@ -315,16 +315,16 @@ func TestUnsupportedAlgorithm(t *testing.T) {
Config{
MACs: []string{"unsupported"},
// MAC is used for non AAED ciphers.
Ciphers: []string{"aes256-ctr"},
Ciphers: []string{CipherAES256CTR},
},
"no common algorithm",
},
{
"unsupported and supported MACs",
Config{
MACs: []string{"unsupported", "hmac-sha2-256-etm@openssh.com"},
MACs: []string{"unsupported", HMACSHA256ETM},
// MAC is used for non AAED ciphers.
Ciphers: []string{"aes256-ctr"},
Ciphers: []string{CipherAES256CTR},
},
"",
},
+257 -80
View File
@@ -10,6 +10,7 @@ import (
"fmt"
"io"
"math"
"slices"
"sync"
_ "crypto/sha1"
@@ -24,69 +25,257 @@ const (
serviceSSH = "ssh-connection"
)
// supportedCiphers lists ciphers we support but might not recommend.
var supportedCiphers = []string{
"aes128-ctr", "aes192-ctr", "aes256-ctr",
"aes128-gcm@openssh.com", gcm256CipherID,
chacha20Poly1305ID,
"arcfour256", "arcfour128", "arcfour",
aes128cbcID,
tripledescbcID,
// The ciphers currently or previously implemented by this library, to use in
// [Config.Ciphers]. For a list, see the [Algorithms.Ciphers] returned by
// [SupportedAlgorithms] or [InsecureAlgorithms].
const (
CipherAES128GCM = "aes128-gcm@openssh.com"
CipherAES256GCM = "aes256-gcm@openssh.com"
CipherChaCha20Poly1305 = "chacha20-poly1305@openssh.com"
CipherAES128CTR = "aes128-ctr"
CipherAES192CTR = "aes192-ctr"
CipherAES256CTR = "aes256-ctr"
InsecureCipherAES128CBC = "aes128-cbc"
InsecureCipherTripleDESCBC = "3des-cbc"
InsecureCipherRC4 = "arcfour"
InsecureCipherRC4128 = "arcfour128"
InsecureCipherRC4256 = "arcfour256"
)
// The key exchanges currently or previously implemented by this library, to use
// in [Config.KeyExchanges]. For a list, see the
// [Algorithms.KeyExchanges] returned by [SupportedAlgorithms] or
// [InsecureAlgorithms].
const (
InsecureKeyExchangeDH1SHA1 = "diffie-hellman-group1-sha1"
InsecureKeyExchangeDH14SHA1 = "diffie-hellman-group14-sha1"
KeyExchangeDH14SHA256 = "diffie-hellman-group14-sha256"
KeyExchangeDH16SHA512 = "diffie-hellman-group16-sha512"
KeyExchangeECDHP256 = "ecdh-sha2-nistp256"
KeyExchangeECDHP384 = "ecdh-sha2-nistp384"
KeyExchangeECDHP521 = "ecdh-sha2-nistp521"
KeyExchangeCurve25519 = "curve25519-sha256"
InsecureKeyExchangeDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
KeyExchangeDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
// KeyExchangeMLKEM768X25519 is supported from Go 1.24.
KeyExchangeMLKEM768X25519 = "mlkem768x25519-sha256"
// An alias for KeyExchangeCurve25519SHA256.
keyExchangeCurve25519LibSSH = "curve25519-sha256@libssh.org"
)
// The message authentication code (MAC) currently or previously implemented by
// this library, to use in [Config.MACs]. For a list, see the
// [Algorithms.MACs] returned by [SupportedAlgorithms] or
// [InsecureAlgorithms].
const (
HMACSHA256ETM = "hmac-sha2-256-etm@openssh.com"
HMACSHA512ETM = "hmac-sha2-512-etm@openssh.com"
HMACSHA256 = "hmac-sha2-256"
HMACSHA512 = "hmac-sha2-512"
HMACSHA1 = "hmac-sha1"
InsecureHMACSHA196 = "hmac-sha1-96"
)
var (
// supportedKexAlgos specifies key-exchange algorithms implemented by this
// package in preference order, excluding those with security issues.
supportedKexAlgos = []string{
KeyExchangeCurve25519,
keyExchangeCurve25519LibSSH,
KeyExchangeECDHP256,
KeyExchangeECDHP384,
KeyExchangeECDHP521,
KeyExchangeDH14SHA256,
KeyExchangeDH16SHA512,
KeyExchangeDHGEXSHA256,
}
// defaultKexAlgos specifies the default preference for key-exchange
// algorithms in preference order.
defaultKexAlgos = []string{
KeyExchangeCurve25519,
keyExchangeCurve25519LibSSH,
KeyExchangeECDHP256,
KeyExchangeECDHP384,
KeyExchangeECDHP521,
KeyExchangeDH14SHA256,
InsecureKeyExchangeDH14SHA1,
}
// insecureKexAlgos specifies key-exchange algorithms implemented by this
// package and which have security issues.
insecureKexAlgos = []string{
InsecureKeyExchangeDH14SHA1,
InsecureKeyExchangeDH1SHA1,
InsecureKeyExchangeDHGEXSHA1,
}
// supportedCiphers specifies cipher algorithms implemented by this package
// in preference order, excluding those with security issues.
supportedCiphers = []string{
CipherAES128GCM,
CipherAES256GCM,
CipherChaCha20Poly1305,
CipherAES128CTR,
CipherAES192CTR,
CipherAES256CTR,
}
// defaultCiphers specifies the default preference for ciphers algorithms
// in preference order.
defaultCiphers = supportedCiphers
// insecureCiphers specifies cipher algorithms implemented by this
// package and which have security issues.
insecureCiphers = []string{
InsecureCipherAES128CBC,
InsecureCipherTripleDESCBC,
InsecureCipherRC4256,
InsecureCipherRC4128,
InsecureCipherRC4,
}
// supportedMACs specifies MAC algorithms implemented by this package in
// preference order, excluding those with security issues.
supportedMACs = []string{
HMACSHA256ETM,
HMACSHA512ETM,
HMACSHA256,
HMACSHA512,
HMACSHA1,
}
// defaultMACs specifies the default preference for MAC algorithms in
// preference order.
defaultMACs = []string{
HMACSHA256ETM,
HMACSHA512ETM,
HMACSHA256,
HMACSHA512,
HMACSHA1,
InsecureHMACSHA196,
}
// insecureMACs specifies MAC algorithms implemented by this
// package and which have security issues.
insecureMACs = []string{
InsecureHMACSHA196,
}
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e.
// methods of authenticating servers) implemented by this package in
// preference order, excluding those with security issues.
supportedHostKeyAlgos = []string{
CertAlgoRSASHA256v01,
CertAlgoRSASHA512v01,
CertAlgoECDSA256v01,
CertAlgoECDSA384v01,
CertAlgoECDSA521v01,
CertAlgoED25519v01,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoED25519,
}
// defaultHostKeyAlgos specifies the default preference for host-key
// algorithms in preference order.
defaultHostKeyAlgos = []string{
CertAlgoRSASHA256v01,
CertAlgoRSASHA512v01,
CertAlgoRSAv01,
InsecureCertAlgoDSAv01,
CertAlgoECDSA256v01,
CertAlgoECDSA384v01,
CertAlgoECDSA521v01,
CertAlgoED25519v01,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
KeyAlgoRSA,
InsecureKeyAlgoDSA,
KeyAlgoED25519,
}
// insecureHostKeyAlgos specifies host-key algorithms implemented by this
// package and which have security issues.
insecureHostKeyAlgos = []string{
KeyAlgoRSA,
InsecureKeyAlgoDSA,
CertAlgoRSAv01,
InsecureCertAlgoDSAv01,
}
// supportedPubKeyAuthAlgos specifies the supported client public key
// authentication algorithms. Note that this doesn't include certificate
// types since those use the underlying algorithm. Order is irrelevant.
supportedPubKeyAuthAlgos = []string{
KeyAlgoED25519,
KeyAlgoSKED25519,
KeyAlgoSKECDSA256,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
}
// defaultPubKeyAuthAlgos specifies the preferred client public key
// authentication algorithms. This list is sent to the client if it supports
// the server-sig-algs extension. Order is irrelevant.
defaultPubKeyAuthAlgos = []string{
KeyAlgoED25519,
KeyAlgoSKED25519,
KeyAlgoSKECDSA256,
KeyAlgoECDSA256,
KeyAlgoECDSA384,
KeyAlgoECDSA521,
KeyAlgoRSASHA256,
KeyAlgoRSASHA512,
KeyAlgoRSA,
InsecureKeyAlgoDSA,
}
// insecurePubKeyAuthAlgos specifies client public key authentication
// algorithms implemented by this package and which have security issues.
insecurePubKeyAuthAlgos = []string{
KeyAlgoRSA,
InsecureKeyAlgoDSA,
}
)
// Algorithms defines a set of algorithms that can be configured in the client
// or server config for negotiation during a handshake.
type Algorithms struct {
KeyExchanges []string
Ciphers []string
MACs []string
HostKeys []string
PublicKeyAuths []string
}
// preferredCiphers specifies the default preference for ciphers.
var preferredCiphers = []string{
"aes128-gcm@openssh.com", gcm256CipherID,
chacha20Poly1305ID,
"aes128-ctr", "aes192-ctr", "aes256-ctr",
// SupportedAlgorithms returns algorithms currently implemented by this package,
// excluding those with security issues, which are returned by
// InsecureAlgorithms. The algorithms listed here are in preference order.
func SupportedAlgorithms() Algorithms {
return Algorithms{
Ciphers: slices.Clone(supportedCiphers),
MACs: slices.Clone(supportedMACs),
KeyExchanges: slices.Clone(supportedKexAlgos),
HostKeys: slices.Clone(supportedHostKeyAlgos),
PublicKeyAuths: slices.Clone(supportedPubKeyAuthAlgos),
}
}
// supportedKexAlgos specifies the supported key-exchange algorithms in
// preference order.
var supportedKexAlgos = []string{
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
// P384 and P521 are not constant-time yet, but since we don't
// reuse ephemeral keys, using them for ECDH should be OK.
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
kexAlgoDH14SHA256, kexAlgoDH16SHA512, kexAlgoDH14SHA1,
kexAlgoDH1SHA1,
// InsecureAlgorithms returns algorithms currently implemented by this package
// and which have security issues.
func InsecureAlgorithms() Algorithms {
return Algorithms{
KeyExchanges: slices.Clone(insecureKexAlgos),
Ciphers: slices.Clone(insecureCiphers),
MACs: slices.Clone(insecureMACs),
HostKeys: slices.Clone(insecureHostKeyAlgos),
PublicKeyAuths: slices.Clone(insecurePubKeyAuthAlgos),
}
}
// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden
// for the server half.
var serverForbiddenKexAlgos = map[string]struct{}{
kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests
kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
}
// preferredKexAlgos specifies the default preference for key-exchange
// algorithms in preference order. The diffie-hellman-group16-sha512 algorithm
// is disabled by default because it is a bit slower than the others.
var preferredKexAlgos = []string{
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
kexAlgoDH14SHA256, kexAlgoDH14SHA1,
}
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
// of authenticating servers) in preference order.
var supportedHostKeyAlgos = []string{
CertAlgoRSASHA256v01, CertAlgoRSASHA512v01,
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01,
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
KeyAlgoRSASHA256, KeyAlgoRSASHA512,
KeyAlgoRSA, KeyAlgoDSA,
KeyAlgoED25519,
}
// supportedMACs specifies a default set of MAC algorithms in preference order.
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
// because they have reached the end of their useful life.
var supportedMACs = []string{
"hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", "hmac-sha1-96",
InsecureKeyExchangeDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests
KeyExchangeDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
}
var supportedCompressions = []string{compressionNone}
@@ -94,13 +283,13 @@ var supportedCompressions = []string{compressionNone}
// hashFuncs keeps the mapping of supported signature algorithms to their
// respective hashes needed for signing and verification.
var hashFuncs = map[string]crypto.Hash{
KeyAlgoRSA: crypto.SHA1,
KeyAlgoRSASHA256: crypto.SHA256,
KeyAlgoRSASHA512: crypto.SHA512,
KeyAlgoDSA: crypto.SHA1,
KeyAlgoECDSA256: crypto.SHA256,
KeyAlgoECDSA384: crypto.SHA384,
KeyAlgoECDSA521: crypto.SHA512,
KeyAlgoRSA: crypto.SHA1,
KeyAlgoRSASHA256: crypto.SHA256,
KeyAlgoRSASHA512: crypto.SHA512,
InsecureKeyAlgoDSA: crypto.SHA1,
KeyAlgoECDSA256: crypto.SHA256,
KeyAlgoECDSA384: crypto.SHA384,
KeyAlgoECDSA521: crypto.SHA512,
// KeyAlgoED25519 doesn't pre-hash.
KeyAlgoSKECDSA256: crypto.SHA256,
KeyAlgoSKED25519: crypto.SHA256,
@@ -135,18 +324,6 @@ func isRSACert(algo string) bool {
return isRSA(algo)
}
// supportedPubKeyAuthAlgos specifies the supported client public key
// authentication algorithms. Note that this doesn't include certificate types
// since those use the underlying algorithm. This list is sent to the client if
// it supports the server-sig-algs extension. Order is irrelevant.
var supportedPubKeyAuthAlgos = []string{
KeyAlgoED25519,
KeyAlgoSKED25519, KeyAlgoSKECDSA256,
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA,
KeyAlgoDSA,
}
// unexpectedMessageError results when the SSH message that we received didn't
// match what we wanted.
func unexpectedMessageError(expected, got uint8) error {
@@ -182,7 +359,7 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
// 128.
switch a.Cipher {
case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcm128CipherID, gcm256CipherID, aes128cbcID:
case CipherAES128CTR, CipherAES192CTR, CipherAES256CTR, CipherAES128GCM, CipherAES256GCM, InsecureCipherAES128CBC:
return 16 * (1 << 32)
}
@@ -192,9 +369,9 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
}
var aeadCiphers = map[string]bool{
gcm128CipherID: true,
gcm256CipherID: true,
chacha20Poly1305ID: true,
CipherAES128GCM: true,
CipherAES256GCM: true,
CipherChaCha20Poly1305: true,
}
type algorithms struct {
@@ -297,7 +474,7 @@ func (c *Config) SetDefaults() {
c.Rand = rand.Reader
}
if c.Ciphers == nil {
c.Ciphers = preferredCiphers
c.Ciphers = defaultCiphers
}
var ciphers []string
for _, c := range c.Ciphers {
@@ -309,7 +486,7 @@ func (c *Config) SetDefaults() {
c.Ciphers = ciphers
if c.KeyExchanges == nil {
c.KeyExchanges = preferredKexAlgos
c.KeyExchanges = defaultKexAlgos
}
var kexs []string
for _, k := range c.KeyExchanges {
@@ -321,7 +498,7 @@ func (c *Config) SetDefaults() {
c.KeyExchanges = kexs
if c.MACs == nil {
c.MACs = supportedMACs
c.MACs = defaultMACs
}
var macs []string
for _, m := range c.MACs {
+110
View File
@@ -154,6 +154,75 @@ func ExampleNewServerConn() {
}
}
func ExampleServerConfig() {
// Minimal ServerConfig with SHA-1 algoritms disabled and supporting only
// public key authentication.
// The algorithms returned by ssh.SupportedAlgorithms() are different from
// the default ones and do not include algorithms that are considered
// insecure, such as those using SHA-1, returned by
// ssh.InsecureAlgorithms().
algorithms := ssh.SupportedAlgorithms()
// Public key authentication is done by comparing
// the public key of a received connection
// with the entries in the authorized_keys file.
authorizedKeysBytes, err := os.ReadFile("authorized_keys")
if err != nil {
log.Fatalf("Failed to load authorized_keys, err: %v", err)
}
authorizedKeysMap := map[string]bool{}
for len(authorizedKeysBytes) > 0 {
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
if err != nil {
log.Fatal(err)
}
authorizedKeysMap[string(pubKey.Marshal())] = true
authorizedKeysBytes = rest
}
config := &ssh.ServerConfig{
Config: ssh.Config{
KeyExchanges: algorithms.KeyExchanges,
Ciphers: algorithms.Ciphers,
MACs: algorithms.MACs,
},
// The configured PublicKeyAuthAlgorithms do not contain SHA-1 based
// signature formats, so if the client attempts to use them the
// authentication will fail before calling the defined callback.
PublicKeyAuthAlgorithms: algorithms.PublicKeyAuths,
PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
if authorizedKeysMap[string(pubKey.Marshal())] {
return &ssh.Permissions{
// Record the public key used for authentication.
Extensions: map[string]string{
"pubkey-fp": ssh.FingerprintSHA256(pubKey),
},
}, nil
}
return nil, fmt.Errorf("unknown public key for %q", c.User())
},
}
privateBytes, err := os.ReadFile("id_rsa")
if err != nil {
log.Fatal("Failed to load private key: ", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatal("Failed to parse private key: ", err)
}
// Restrict host key algorithms to disable ssh-rsa.
signer, err := ssh.NewSignerWithAlgorithms(private.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256, ssh.KeyAlgoRSASHA512})
if err != nil {
log.Fatal("Failed to create private key with restricted algorithms: ", err)
}
config.AddHostKey(signer)
}
func ExampleServerConfig_AddHostKey() {
// Minimal ServerConfig supporting only password authentication.
config := &ssh.ServerConfig{
@@ -262,6 +331,47 @@ func ExampleDial() {
fmt.Println(b.String())
}
func ExampleClientConfig() {
var hostKey ssh.PublicKey
key, err := os.ReadFile("/home/user/.ssh/id_rsa")
if err != nil {
log.Fatalf("unable to read private key: %v", err)
}
// Create the Signer for this private key.
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
log.Fatalf("unable to parse private key: %v", err)
}
// Minimal ClientConfig with SHA-1 algoritms disabled.
// The algorithms returned by ssh.SupportedAlgorithms() are different from
// the default ones and do not include algorithms that are considered
// insecure, such as those using SHA-1, returned by
// ssh.InsecureAlgorithms().
algorithms := ssh.SupportedAlgorithms()
config := &ssh.ClientConfig{
Config: ssh.Config{
KeyExchanges: algorithms.KeyExchanges,
Ciphers: algorithms.Ciphers,
MACs: algorithms.MACs,
},
User: "username",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.FixedHostKey(hostKey),
// We should check that hostKey algorithm is inlcuded in
// algorithms.HostKeys.
HostKeyAlgorithms: algorithms.HostKeys,
}
client, err := ssh.Dial("tcp", "yourserver.com:22", config)
if err != nil {
log.Fatal("Failed to dial: ", err)
}
defer client.Close()
}
func ExamplePublicKeys() {
var hostKey ssh.PublicKey
// A public key may be used to authenticate against the remote
+1 -1
View File
@@ -164,7 +164,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
if config.HostKeyAlgorithms != nil {
t.hostKeyAlgorithms = config.HostKeyAlgorithms
} else {
t.hostKeyAlgorithms = supportedHostKeyAlgos
t.hostKeyAlgorithms = defaultHostKeyAlgos
}
go t.readLoop()
go t.kexLoop()
+2 -2
View File
@@ -762,7 +762,7 @@ func TestHandshakePendingPacketsError(t *testing.T) {
func TestHandshakeRekeyDefault(t *testing.T) {
clientConf := &ClientConfig{
Config: Config{
Ciphers: []string{"aes128-ctr"},
Ciphers: []string{CipherAES128CTR},
},
HostKeyCallback: InsecureIgnoreHostKey(),
}
@@ -788,7 +788,7 @@ func TestHandshakeRekeyDefault(t *testing.T) {
}
func TestHandshakeAEADCipherNoMAC(t *testing.T) {
for _, cipher := range []string{chacha20Poly1305ID, gcm128CipherID} {
for _, cipher := range []string{CipherChaCha20Poly1305, CipherAES128GCM} {
checker := &syncChecker{
called: make(chan int, 1),
}
+11 -29
View File
@@ -19,24 +19,6 @@ import (
"golang.org/x/crypto/curve25519"
)
const (
kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
kexAlgoDH14SHA256 = "diffie-hellman-group14-sha256"
kexAlgoDH16SHA512 = "diffie-hellman-group16-sha512"
kexAlgoECDH256 = "ecdh-sha2-nistp256"
kexAlgoECDH384 = "ecdh-sha2-nistp384"
kexAlgoECDH521 = "ecdh-sha2-nistp521"
kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org"
kexAlgoCurve25519SHA256 = "curve25519-sha256"
// For the following kex only the client half contains a production
// ready implementation. The server half only consists of a minimal
// implementation to satisfy the automated tests.
kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
)
// kexResult captures the outcome of a key exchange.
type kexResult struct {
// Session hash. See also RFC 4253, section 8.
@@ -405,7 +387,7 @@ func init() {
// This is the group called diffie-hellman-group1-sha1 in
// RFC 4253 and Oakley Group 2 in RFC 2409.
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
kexAlgoMap[InsecureKeyExchangeDH1SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
pMinus1: new(big.Int).Sub(p, bigOne),
@@ -422,11 +404,11 @@ func init() {
pMinus1: new(big.Int).Sub(p, bigOne),
}
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
kexAlgoMap[InsecureKeyExchangeDH14SHA1] = &dhGroup{
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
hashFunc: crypto.SHA1,
}
kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{
kexAlgoMap[KeyExchangeDH14SHA256] = &dhGroup{
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
hashFunc: crypto.SHA256,
}
@@ -435,20 +417,20 @@ func init() {
// 8268 and Oakley Group 16 in RFC 3526.
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", 16)
kexAlgoMap[kexAlgoDH16SHA512] = &dhGroup{
kexAlgoMap[KeyExchangeDH16SHA512] = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
pMinus1: new(big.Int).Sub(p, bigOne),
hashFunc: crypto.SHA512,
}
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{}
kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()}
kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()}
kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()}
kexAlgoMap[KeyExchangeCurve25519] = &curve25519sha256{}
kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{}
kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
}
// curve25519sha256 implements the curve25519-sha256 (formerly known as
+15 -10
View File
@@ -36,14 +36,19 @@ import (
// ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner
// arguments.
const (
KeyAlgoRSA = "ssh-rsa"
KeyAlgoDSA = "ssh-dss"
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
KeyAlgoED25519 = "ssh-ed25519"
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
KeyAlgoRSA = "ssh-rsa"
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
KeyAlgoDSA = InsecureKeyAlgoDSA
// Deprecated: DSA is only supported at insecure key sizes, and was removed
// from major implementations.
InsecureKeyAlgoDSA = "ssh-dss"
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
KeyAlgoED25519 = "ssh-ed25519"
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
// KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not
// public key formats, so they can't appear as a PublicKey.Type. The
@@ -67,7 +72,7 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err
switch algo {
case KeyAlgoRSA:
return parseRSA(in)
case KeyAlgoDSA:
case InsecureKeyAlgoDSA:
return parseDSA(in)
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
return parseECDSA(in)
@@ -77,7 +82,7 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err
return parseED25519(in)
case KeyAlgoSKED25519:
return parseSKEd25519(in)
case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
case CertAlgoRSAv01, InsecureCertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
cert, err := parseCert(in, certKeyAlgoNames[algo])
if err != nil {
return nil, nil, err
+6 -6
View File
@@ -47,22 +47,22 @@ func (t truncatingMAC) Size() int {
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
var macModes = map[string]*macMode{
"hmac-sha2-512-etm@openssh.com": {64, true, func(key []byte) hash.Hash {
HMACSHA512ETM: {64, true, func(key []byte) hash.Hash {
return hmac.New(sha512.New, key)
}},
"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash {
HMACSHA256ETM: {32, true, func(key []byte) hash.Hash {
return hmac.New(sha256.New, key)
}},
"hmac-sha2-512": {64, false, func(key []byte) hash.Hash {
HMACSHA512: {64, false, func(key []byte) hash.Hash {
return hmac.New(sha512.New, key)
}},
"hmac-sha2-256": {32, false, func(key []byte) hash.Hash {
HMACSHA256: {32, false, func(key []byte) hash.Hash {
return hmac.New(sha256.New, key)
}},
"hmac-sha1": {20, false, func(key []byte) hash.Hash {
HMACSHA1: {20, false, func(key []byte) hash.Hash {
return hmac.New(sha1.New, key)
}},
"hmac-sha1-96": {20, false, func(key []byte) hash.Hash {
InsecureHMACSHA196: {20, false, func(key []byte) hash.Hash {
return truncatingMAC{12, hmac.New(sha1.New, key)}
}},
}
+3 -7
View File
@@ -19,19 +19,15 @@ import (
"golang.org/x/crypto/curve25519"
)
const (
kexAlgoMLKEM768xCurve25519SHA256 = "mlkem768x25519-sha256"
)
func init() {
// After Go 1.24rc1 mlkem swapped the order of return values of Encapsulate.
// See #70950.
if runtime.Version() == "go1.24rc1" {
return
}
supportedKexAlgos = slices.Insert(supportedKexAlgos, 0, kexAlgoMLKEM768xCurve25519SHA256)
preferredKexAlgos = slices.Insert(preferredKexAlgos, 0, kexAlgoMLKEM768xCurve25519SHA256)
kexAlgoMap[kexAlgoMLKEM768xCurve25519SHA256] = &mlkem768WithCurve25519sha256{}
supportedKexAlgos = slices.Insert(supportedKexAlgos, 0, KeyExchangeMLKEM768X25519)
defaultKexAlgos = slices.Insert(defaultKexAlgos, 0, KeyExchangeMLKEM768X25519)
kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{}
}
// mlkem768WithCurve25519sha256 implements the hybrid ML-KEM768 with
+2 -2
View File
@@ -243,10 +243,10 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
fullConf.MaxAuthTries = 6
}
if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
fullConf.PublicKeyAuthAlgorithms = defaultPubKeyAuthAlgos
} else {
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
if !contains(supportedPubKeyAuthAlgos, algo) {
if !contains(SupportedAlgorithms().PublicKeyAuths, algo) && !contains(InsecureAlgorithms().PublicKeyAuths, algo) {
c.Close()
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
}
+1 -1
View File
@@ -212,7 +212,7 @@ func TestNewServerConnValidationErrors(t *testing.T) {
serverConf = &ServerConfig{
Config: Config{
KeyExchanges: []string{kexAlgoDHGEXSHA256},
KeyExchanges: []string{KeyExchangeDHGEXSHA256},
},
}
c = &markerConn{}
+2 -2
View File
@@ -236,7 +236,7 @@ func recordingsClientConfig() *ssh.ClientConfig {
config := clientConfig()
config.SetDefaults()
// Remove ML-KEM since it only works with Go 1.24.
if config.KeyExchanges[0] == "mlkem768x25519-sha256" {
if config.KeyExchanges[0] == ssh.KeyExchangeMLKEM768X25519 {
config.KeyExchanges = config.KeyExchanges[1:]
}
config.Auth = []ssh.AuthMethod{
@@ -352,7 +352,7 @@ func TestHostKeyCheck(t *testing.T) {
// change the keys.
hostDB.keys[ssh.KeyAlgoRSA][25]++
hostDB.keys[ssh.KeyAlgoDSA][25]++
hostDB.keys[ssh.InsecureKeyAlgoDSA][25]++
hostDB.keys[ssh.KeyAlgoECDSA256][25]++
test := clientTest{
+1 -1
View File
@@ -219,7 +219,7 @@ func recordingsServerConfig() *ssh.ServerConfig {
config.SetDefaults()
// Remove ML-KEM since it only works with Go 1.24.
config.SetDefaults()
if config.KeyExchanges[0] == "mlkem768x25519-sha256" {
if config.KeyExchanges[0] == ssh.KeyExchangeMLKEM768X25519 {
config.KeyExchanges = config.KeyExchanges[1:]
}
config.AddHostKey(testSigners["rsa"])
+1 -1
View File
@@ -128,7 +128,7 @@ func clientConfig() *ssh.ClientConfig {
HostKeyCallback: hostKeyDB().Check,
HostKeyAlgorithms: []string{ // by default, don't allow certs as this affects the hostKeyDB checker
ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521,
ssh.KeyAlgoRSA, ssh.KeyAlgoDSA,
ssh.KeyAlgoRSA, ssh.InsecureKeyAlgoDSA,
ssh.KeyAlgoED25519,
},
}
+2 -2
View File
@@ -224,8 +224,8 @@ func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
}
var deprecatedCiphers = []string{
"aes128-cbc", "3des-cbc",
"arcfour128", "arcfour256",
ssh.InsecureCipherAES128CBC, ssh.InsecureCipherTripleDESCBC,
ssh.InsecureCipherRC4128, ssh.InsecureCipherRC4256,
}
func TestCiphers(t *testing.T) {
-7
View File
@@ -16,13 +16,6 @@ import (
// wire. No message decoding is done, to minimize the impact on timing.
const debugTransport = false
const (
gcm128CipherID = "aes128-gcm@openssh.com"
gcm256CipherID = "aes256-gcm@openssh.com"
aes128cbcID = "aes128-cbc"
tripledescbcID = "3des-cbc"
)
// packetConn represents a transport that implements packet based
// operations.
type packetConn interface {