Merge pull request #13841 from lsm5/main-cve-2022-27191

Bump golang.org/x/crypto to 7b82a4e
This commit is contained in:
OpenShift Merge Robot
2022-04-12 15:39:43 -04:00
committed by GitHub
30 changed files with 573 additions and 3844 deletions

2
go.mod
View File

@ -65,7 +65,7 @@ require (
github.com/vbauerster/mpb/v7 v7.4.1 github.com/vbauerster/mpb/v7 v7.4.1
github.com/vishvananda/netlink v1.1.1-0.20220115184804-dd687eb2f2d4 github.com/vishvananda/netlink v1.1.1-0.20220115184804-dd687eb2f2d4
go.etcd.io/bbolt v1.3.6 go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7

4
go.sum
View File

@ -1494,8 +1494,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=

View File

@ -15,6 +15,7 @@ const bufSize = 256
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only // xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
// be called when the vector facility is available. Implementation in asm_s390x.s. // be called when the vector facility is available. Implementation in asm_s390x.s.
//
//go:noescape //go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)

View File

@ -1,13 +1,16 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego // +build amd64,gc,!purego
package field package field
// feMul sets out = a * b. It works like feMulGeneric. // feMul sets out = a * b. It works like feMulGeneric.
//
//go:noescape //go:noescape
func feMul(out *Element, a *Element, b *Element) func feMul(out *Element, a *Element, b *Element)
// feSquare sets out = a * a. It works like feSquareGeneric. // feSquare sets out = a * a. It works like feSquareGeneric.
//
//go:noescape //go:noescape
func feSquare(out *Element, a *Element) func feSquare(out *Element, a *Element)

View File

@ -1,13 +1,7 @@
// Copyright 2016 The Go Authors. All rights reserved. // Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// In Go 1.13, the ed25519 package was promoted to the standard library as
// crypto/ed25519, and this package became a wrapper for the standard library one.
//
//go:build !go1.13
// +build !go1.13
// Package ed25519 implements the Ed25519 signature algorithm. See // Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/. // https://ed25519.cr.yp.to/.
// //
@ -16,21 +10,15 @@
// representation includes a public key suffix to make multiple signing // representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC // operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”. // 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
package ed25519 package ed25519
// This code is a port of the public domain, “ref10” implementation of ed25519
// from SUPERCOP.
import ( import (
"bytes" "crypto/ed25519"
"crypto"
cryptorand "crypto/rand"
"crypto/sha512"
"errors"
"io" "io"
"strconv"
"golang.org/x/crypto/ed25519/internal/edwards25519"
) )
const ( const (
@ -45,57 +33,21 @@ const (
) )
// PublicKey is the type of Ed25519 public keys. // PublicKey is the type of Ed25519 public keys.
type PublicKey []byte //
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. // PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
type PrivateKey []byte //
// This type is an alias for crypto/ed25519's PrivateKey type.
// Public returns the PublicKey corresponding to priv. // See the crypto/ed25519 package for the methods on this type.
func (priv PrivateKey) Public() crypto.PublicKey { type PrivateKey = ed25519.PrivateKey
publicKey := make([]byte, PublicKeySize)
copy(publicKey, priv[32:])
return PublicKey(publicKey)
}
// Seed returns the private key seed corresponding to priv. It is provided for
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
// in this package.
func (priv PrivateKey) Seed() []byte {
seed := make([]byte, SeedSize)
copy(seed, priv[:32])
return seed
}
// Sign signs the given message with priv.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
// indicate the message hasn't been hashed. This can be achieved by passing
// crypto.Hash(0) as the value for opts.
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
if opts.HashFunc() != crypto.Hash(0) {
return nil, errors.New("ed25519: cannot sign hashed message")
}
return Sign(priv, message), nil
}
// GenerateKey generates a public/private key pair using entropy from rand. // GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used. // If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
if rand == nil { return ed25519.GenerateKey(rand)
rand = cryptorand.Reader
}
seed := make([]byte, SeedSize)
if _, err := io.ReadFull(rand, seed); err != nil {
return nil, nil, err
}
privateKey := NewKeyFromSeed(seed)
publicKey := make([]byte, PublicKeySize)
copy(publicKey, privateKey[32:])
return publicKey, privateKey, nil
} }
// NewKeyFromSeed calculates a private key from a seed. It will panic if // NewKeyFromSeed calculates a private key from a seed. It will panic if
@ -103,121 +55,17 @@ func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
// with RFC 8032. RFC 8032's private keys correspond to seeds in this // with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package. // package.
func NewKeyFromSeed(seed []byte) PrivateKey { func NewKeyFromSeed(seed []byte) PrivateKey {
if l := len(seed); l != SeedSize { return ed25519.NewKeyFromSeed(seed)
panic("ed25519: bad seed length: " + strconv.Itoa(l))
}
digest := sha512.Sum512(seed)
digest[0] &= 248
digest[31] &= 127
digest[31] |= 64
var A edwards25519.ExtendedGroupElement
var hBytes [32]byte
copy(hBytes[:], digest[:])
edwards25519.GeScalarMultBase(&A, &hBytes)
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
privateKey := make([]byte, PrivateKeySize)
copy(privateKey, seed)
copy(privateKey[32:], publicKeyBytes[:])
return privateKey
} }
// Sign signs the message with privateKey and returns a signature. It will // Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize. // panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte { func Sign(privateKey PrivateKey, message []byte) []byte {
if l := len(privateKey); l != PrivateKeySize { return ed25519.Sign(privateKey, message)
panic("ed25519: bad private key length: " + strconv.Itoa(l))
}
h := sha512.New()
h.Write(privateKey[:32])
var digest1, messageDigest, hramDigest [64]byte
var expandedSecretKey [32]byte
h.Sum(digest1[:0])
copy(expandedSecretKey[:], digest1[:])
expandedSecretKey[0] &= 248
expandedSecretKey[31] &= 63
expandedSecretKey[31] |= 64
h.Reset()
h.Write(digest1[32:])
h.Write(message)
h.Sum(messageDigest[:0])
var messageDigestReduced [32]byte
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
var R edwards25519.ExtendedGroupElement
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
var encodedR [32]byte
R.ToBytes(&encodedR)
h.Reset()
h.Write(encodedR[:])
h.Write(privateKey[32:])
h.Write(message)
h.Sum(hramDigest[:0])
var hramDigestReduced [32]byte
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
var s [32]byte
edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
signature := make([]byte, SignatureSize)
copy(signature[:], encodedR[:])
copy(signature[32:], s[:])
return signature
} }
// Verify reports whether sig is a valid signature of message by publicKey. It // Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize. // will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool { func Verify(publicKey PublicKey, message, sig []byte) bool {
if l := len(publicKey); l != PublicKeySize { return ed25519.Verify(publicKey, message, sig)
panic("ed25519: bad public key length: " + strconv.Itoa(l))
}
if len(sig) != SignatureSize || sig[63]&224 != 0 {
return false
}
var A edwards25519.ExtendedGroupElement
var publicKeyBytes [32]byte
copy(publicKeyBytes[:], publicKey)
if !A.FromBytes(&publicKeyBytes) {
return false
}
edwards25519.FeNeg(&A.X, &A.X)
edwards25519.FeNeg(&A.T, &A.T)
h := sha512.New()
h.Write(sig[:32])
h.Write(publicKey[:])
h.Write(message)
var digest [64]byte
h.Sum(digest[:0])
var hReduced [32]byte
edwards25519.ScReduce(&hReduced, &digest)
var R edwards25519.ProjectiveGroupElement
var s [32]byte
copy(s[:], sig[32:])
// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
// the range [0, order) in order to prevent signature malleability.
if !edwards25519.ScMinimal(&s) {
return false
}
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)
var checkR [32]byte
R.ToBytes(&checkR)
return bytes.Equal(sig[:32], checkR[:])
} }

View File

@ -1,74 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.13
// +build go1.13
// Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
package ed25519
import (
"crypto/ed25519"
"io"
)
const (
// PublicKeySize is the size, in bytes, of public keys as used in this package.
PublicKeySize = 32
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
//
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
//
// This type is an alias for crypto/ed25519's PrivateKey type.
// See the crypto/ed25519 package for the methods on this type.
type PrivateKey = ed25519.PrivateKey
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
return ed25519.GenerateKey(rand)
}
// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
return ed25519.NewKeyFromSeed(seed)
}
// Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte {
return ed25519.Sign(privateKey, message)
}
// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
return ed25519.Verify(publicKey, message, sig)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -136,7 +136,7 @@ func shiftRightBy2(a uint128) uint128 {
// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of // updateGeneric absorbs msg into the state.h accumulator. For each chunk m of
// 128 bits of message, it computes // 128 bits of message, it computes
// //
// h₊ = (h + m) * r mod 2¹³⁰ - 5 // h₊ = (h + m) * r mod 2¹³⁰ - 5
// //
// If the msg length is not a multiple of TagSize, it assumes the last // If the msg length is not a multiple of TagSize, it assumes the last
// incomplete chunk is the final one. // incomplete chunk is the final one.
@ -278,8 +278,7 @@ const (
// finalize completes the modular reduction of h and computes // finalize completes the modular reduction of h and computes
// //
// out = h + s mod 2¹²⁸ // out = h + s mod 2¹²⁸
//
func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
h0, h1, h2 := h[0], h[1], h[2] h0, h1, h2 := h[0], h[1], h[2]

View File

@ -14,6 +14,7 @@ import (
// updateVX is an assembly implementation of Poly1305 that uses vector // updateVX is an assembly implementation of Poly1305 that uses vector
// instructions. It must only be called if the vector facility (vx) is // instructions. It must only be called if the vector facility (vx) is
// available. // available.
//
//go:noescape //go:noescape
func updateVX(state *macState, msg []byte) func updateVX(state *macState, msg []byte)

View File

@ -23,12 +23,14 @@ import (
// A Block represents an OpenPGP armored structure. // A Block represents an OpenPGP armored structure.
// //
// The encoded form is: // The encoded form is:
// -----BEGIN Type-----
// Headers
// //
// base64-encoded Bytes // -----BEGIN Type-----
// '=' base64 encoded checksum // Headers
// -----END Type----- //
// base64-encoded Bytes
// '=' base64 encoded checksum
// -----END Type-----
//
// where Headers is a possibly empty sequence of Key: Value lines. // where Headers is a possibly empty sequence of Key: Value lines.
// //
// Since the armored data can be very large, this package presents a streaming // Since the armored data can be very large, this package presents a streaming

View File

@ -96,7 +96,8 @@ func (l *lineBreaker) Close() (err error) {
// trailer. // trailer.
// //
// It's built into a stack of io.Writers: // It's built into a stack of io.Writers:
// encoding -> base64 encoder -> lineBreaker -> out //
// encoding -> base64 encoder -> lineBreaker -> out
type encoding struct { type encoding struct {
out io.Writer out io.Writer
breaker *lineBreaker breaker *lineBreaker

View File

@ -77,8 +77,8 @@ func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err
// returns the plaintext of the message. An error can result only if the // returns the plaintext of the message. An error can result only if the
// ciphertext is invalid. Users should keep in mind that this is a padding // ciphertext is invalid. Users should keep in mind that this is a padding
// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can // oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks // be used to break the cryptosystem. See Chosen Ciphertext Attacks
// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel // Against Protocols Based on the RSA Encryption Standard PKCS #1, Daniel
// Bleichenbacher, Advances in Cryptology (Crypto '98), // Bleichenbacher, Advances in Cryptology (Crypto '98),
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
s := new(big.Int).Exp(c1, priv.X, priv.P) s := new(big.Int).Exp(c1, priv.X, priv.P)

View File

@ -32,7 +32,7 @@ import (
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by // can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
// doing: // doing:
// //
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) // dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
// //
// Remember to get a good random salt. At least 8 bytes is recommended by the // Remember to get a good random salt. At least 8 bytes is recommended by the
// RFC. // RFC.

View File

@ -8,7 +8,8 @@
// ssh-agent process using the sample server. // ssh-agent process using the sample server.
// //
// References: // References:
// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00 //
// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00
package agent // import "golang.org/x/crypto/ssh/agent" package agent // import "golang.org/x/crypto/ssh/agent"
import ( import (
@ -25,7 +26,6 @@ import (
"math/big" "math/big"
"sync" "sync"
"crypto"
"golang.org/x/crypto/ed25519" "golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
@ -771,19 +771,26 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature,
return s.agent.Sign(s.pub, data) return s.agent.Sign(s.pub, data)
} }
func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) { func (s *agentKeyringSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*ssh.Signature, error) {
var flags SignatureFlags if algorithm == "" || algorithm == s.pub.Type() {
if opts != nil { return s.Sign(rand, data)
switch opts.HashFunc() {
case crypto.SHA256:
flags = SignatureFlagRsaSha256
case crypto.SHA512:
flags = SignatureFlagRsaSha512
}
} }
var flags SignatureFlags
switch algorithm {
case ssh.KeyAlgoRSASHA256:
flags = SignatureFlagRsaSha256
case ssh.KeyAlgoRSASHA512:
flags = SignatureFlagRsaSha512
default:
return nil, fmt.Errorf("agent: unsupported algorithm %q", algorithm)
}
return s.agent.SignWithFlags(s.pub, data, flags) return s.agent.SignWithFlags(s.pub, data, flags)
} }
var _ ssh.AlgorithmSigner = &agentKeyringSigner{}
// Calls an extension method. It is up to the agent implementation as to whether or not // Calls an extension method. It is up to the agent implementation as to whether or not
// any particular extension is supported and may always return an error. Because the // any particular extension is supported and may always return an error. Because the
// type of the response is up to the implementation, this returns the bytes of the // type of the response is up to the implementation, this returns the bytes of the

View File

@ -113,7 +113,7 @@ func (r *keyring) Unlock(passphrase []byte) error {
// expireKeysLocked removes expired keys from the keyring. If a key was added // expireKeysLocked removes expired keys from the keyring. If a key was added
// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have // with a lifetimesecs contraint and seconds >= lifetimesecs seconds have
// ellapsed, it is removed. The caller *must* be holding the keyring mutex. // elapsed, it is removed. The caller *must* be holding the keyring mutex.
func (r *keyring) expireKeysLocked() { func (r *keyring) expireKeysLocked() {
for _, k := range r.keys { for _, k := range r.keys {
if k.expire != nil && time.Now().After(*k.expire) { if k.expire != nil && time.Now().After(*k.expire) {
@ -205,9 +205,9 @@ func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureF
var algorithm string var algorithm string
switch flags { switch flags {
case SignatureFlagRsaSha256: case SignatureFlagRsaSha256:
algorithm = ssh.SigAlgoRSASHA2256 algorithm = ssh.KeyAlgoRSASHA256
case SignatureFlagRsaSha512: case SignatureFlagRsaSha512:
algorithm = ssh.SigAlgoRSASHA2512 algorithm = ssh.KeyAlgoRSASHA512
default: default:
return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags)
} }

View File

@ -14,8 +14,10 @@ import (
"time" "time"
) )
// These constants from [PROTOCOL.certkeys] represent the key algorithm names // Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear
// for certificate types supported by this package. // in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms.
// Unlike key algorithm names, these are not passed to AlgorithmSigner and don't
// appear in the Signature.Format field.
const ( const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com" CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
@ -25,14 +27,21 @@ const (
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com" CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
CertAlgoSKED25519v01 = "sk-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
// ClientConfig.HostKeyAlgorithms.
CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com"
CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com"
) )
// These constants from [PROTOCOL.certkeys] represent additional signature
// algorithm names for certificate types supported by this package.
const ( const (
CertSigAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" // Deprecated: use CertAlgoRSAv01.
CertSigAlgoRSASHA2256v01 = "rsa-sha2-256-cert-v01@openssh.com" CertSigAlgoRSAv01 = CertAlgoRSAv01
CertSigAlgoRSASHA2512v01 = "rsa-sha2-512-cert-v01@openssh.com" // Deprecated: use CertAlgoRSASHA256v01.
CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01
// Deprecated: use CertAlgoRSASHA512v01.
CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01
) )
// Certificate types distinguish between host and user // Certificate types distinguish between host and user
@ -431,10 +440,14 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
} }
c.SignatureKey = authority.PublicKey() c.SignatureKey = authority.PublicKey()
if v, ok := authority.(AlgorithmSigner); ok { // Default to KeyAlgoRSASHA512 for ssh-rsa signers.
if v.PublicKey().Type() == KeyAlgoRSA { if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
authority = &rsaSigner{v, SigAlgoRSASHA2512} sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512)
if err != nil {
return err
} }
c.Signature = sig
return nil
} }
sig, err := authority.Sign(rand, c.bytesForSigning()) sig, err := authority.Sign(rand, c.bytesForSigning())
@ -445,32 +458,40 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
return nil return nil
} }
// certAlgoNames includes a mapping from signature algorithms to the // certKeyAlgoNames is a mapping from known certificate algorithm names to the
// corresponding certificate signature algorithm. When a key type (such // corresponding public key signature algorithm.
// as ED25516) is associated with only one algorithm, the KeyAlgo var certKeyAlgoNames = map[string]string{
// constant is used instead of the SigAlgo. CertAlgoRSAv01: KeyAlgoRSA,
var certAlgoNames = map[string]string{ CertAlgoRSASHA256v01: KeyAlgoRSASHA256,
SigAlgoRSA: CertSigAlgoRSAv01, CertAlgoRSASHA512v01: KeyAlgoRSASHA512,
SigAlgoRSASHA2256: CertSigAlgoRSASHA2256v01, CertAlgoDSAv01: KeyAlgoDSA,
SigAlgoRSASHA2512: CertSigAlgoRSASHA2512v01, CertAlgoECDSA256v01: KeyAlgoECDSA256,
KeyAlgoDSA: CertAlgoDSAv01, CertAlgoECDSA384v01: KeyAlgoECDSA384,
KeyAlgoECDSA256: CertAlgoECDSA256v01, CertAlgoECDSA521v01: KeyAlgoECDSA521,
KeyAlgoECDSA384: CertAlgoECDSA384v01, CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
KeyAlgoECDSA521: CertAlgoECDSA521v01, CertAlgoED25519v01: KeyAlgoED25519,
KeyAlgoSKECDSA256: CertAlgoSKECDSA256v01, CertAlgoSKED25519v01: KeyAlgoSKED25519,
KeyAlgoED25519: CertAlgoED25519v01,
KeyAlgoSKED25519: CertAlgoSKED25519v01,
} }
// certToPrivAlgo returns the underlying algorithm for a certificate algorithm. // underlyingAlgo returns the signature algorithm associated with algo (which is
// Panics if a non-certificate algorithm is passed. // an advertised or negotiated public key or host key algorithm). These are
func certToPrivAlgo(algo string) string { // usually the same, except for certificate algorithms.
for privAlgo, pubAlgo := range certAlgoNames { func underlyingAlgo(algo string) string {
if pubAlgo == algo { if a, ok := certKeyAlgoNames[algo]; ok {
return privAlgo return a
}
return algo
}
// certificateAlgo returns the certificate algorithms that uses the provided
// underlying signature algorithm.
func certificateAlgo(algo string) (certAlgo string, ok bool) {
for certName, algoName := range certKeyAlgoNames {
if algoName == algo {
return certName, true
} }
} }
panic("unknown cert algorithm") return "", false
} }
func (cert *Certificate) bytesForSigning() []byte { func (cert *Certificate) bytesForSigning() []byte {
@ -514,13 +535,13 @@ func (c *Certificate) Marshal() []byte {
return result return result
} }
// Type returns the key name. It is part of the PublicKey interface. // Type returns the certificate algorithm name. It is part of the PublicKey interface.
func (c *Certificate) Type() string { func (c *Certificate) Type() string {
algo, ok := certAlgoNames[c.Key.Type()] certName, ok := certificateAlgo(c.Key.Type())
if !ok { if !ok {
panic("unknown cert key type " + c.Key.Type()) panic("unknown certificate type for key type " + c.Key.Type())
} }
return algo return certName
} }
// Verify verifies a signature against the certificate's public // Verify verifies a signature against the certificate's public

View File

@ -640,7 +640,7 @@ const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com // chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
// AEAD, which is described here: // AEAD, which is described here:
// //
// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00 // https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00
// //
// the methods here also implement padding, which RFC4253 Section 6 // the methods here also implement padding, which RFC4253 Section 6
// also requires of stream ciphers. // also requires of stream ciphers.

View File

@ -113,25 +113,16 @@ func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) e
return c.clientAuthenticate(config) return c.clientAuthenticate(config)
} }
// verifyHostKeySignature verifies the host key obtained in the key // verifyHostKeySignature verifies the host key obtained in the key exchange.
// exchange. // algo is the negotiated algorithm, and may be a certificate type.
func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error { func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error {
sig, rest, ok := parseSignatureBody(result.Signature) sig, rest, ok := parseSignatureBody(result.Signature)
if len(rest) > 0 || !ok { if len(rest) > 0 || !ok {
return errors.New("ssh: signature parse error") return errors.New("ssh: signature parse error")
} }
// For keys, underlyingAlgo is exactly algo. For certificates, if a := underlyingAlgo(algo); sig.Format != a {
// we have to look up the underlying key algorithm that SSH return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, a)
// uses to evaluate signatures.
underlyingAlgo := algo
for sigAlgo, certAlgo := range certAlgoNames {
if certAlgo == algo {
underlyingAlgo = sigAlgo
}
}
if sig.Format != underlyingAlgo {
return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, underlyingAlgo)
} }
return hostKey.Verify(result.H, sig) return hostKey.Verify(result.H, sig)
@ -237,11 +228,11 @@ type ClientConfig struct {
// be used for the connection. If empty, a reasonable default is used. // be used for the connection. If empty, a reasonable default is used.
ClientVersion string ClientVersion string
// HostKeyAlgorithms lists the key types that the client will // HostKeyAlgorithms lists the public key algorithms that the client will
// accept from the server as host key, in order of // accept from the server for host key authentication, in order of
// preference. If empty, a reasonable default is used. Any // preference. If empty, a reasonable default is used. Any
// string returned from PublicKey.Type method may be used, or // string returned from a PublicKey.Type method may be used, or
// any of the CertAlgoXxxx and KeyAlgoXxxx constants. // any of the CertAlgo and KeyAlgo constants.
HostKeyAlgorithms []string HostKeyAlgorithms []string
// Timeout is the maximum amount of time for the TCP connection to establish. // Timeout is the maximum amount of time for the TCP connection to establish.

View File

@ -9,6 +9,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"strings"
) )
type authResult int type authResult int
@ -29,6 +30,33 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
if err != nil { if err != nil {
return err return err
} }
// The server may choose to send a SSH_MSG_EXT_INFO at this point (if we
// advertised willingness to receive one, which we always do) or not. See
// RFC 8308, Section 2.4.
extensions := make(map[string][]byte)
if len(packet) > 0 && packet[0] == msgExtInfo {
var extInfo extInfoMsg
if err := Unmarshal(packet, &extInfo); err != nil {
return err
}
payload := extInfo.Payload
for i := uint32(0); i < extInfo.NumExtensions; i++ {
name, rest, ok := parseString(payload)
if !ok {
return parseError(msgExtInfo)
}
value, rest, ok := parseString(rest)
if !ok {
return parseError(msgExtInfo)
}
extensions[string(name)] = value
payload = rest
}
packet, err = c.transport.readPacket()
if err != nil {
return err
}
}
var serviceAccept serviceAcceptMsg var serviceAccept serviceAcceptMsg
if err := Unmarshal(packet, &serviceAccept); err != nil { if err := Unmarshal(packet, &serviceAccept); err != nil {
return err return err
@ -41,7 +69,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
sessionID := c.transport.getSessionID() sessionID := c.transport.getSessionID()
for auth := AuthMethod(new(noneAuth)); auth != nil; { for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand) ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
if err != nil { if err != nil {
return err return err
} }
@ -93,7 +121,7 @@ type AuthMethod interface {
// If authentication is not successful, a []string of alternative // If authentication is not successful, a []string of alternative
// method names is returned. If the slice is nil, it will be ignored // method names is returned. If the slice is nil, it will be ignored
// and the previous set of possible methods will be reused. // and the previous set of possible methods will be reused.
auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error) auth(session []byte, user string, p packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error)
// method returns the RFC 4252 method name. // method returns the RFC 4252 method name.
method() string method() string
@ -102,7 +130,7 @@ type AuthMethod interface {
// "none" authentication, RFC 4252 section 5.2. // "none" authentication, RFC 4252 section 5.2.
type noneAuth int type noneAuth int
func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
if err := c.writePacket(Marshal(&userAuthRequestMsg{ if err := c.writePacket(Marshal(&userAuthRequestMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
@ -122,7 +150,7 @@ func (n *noneAuth) method() string {
// a function call, e.g. by prompting the user. // a function call, e.g. by prompting the user.
type passwordCallback func() (password string, err error) type passwordCallback func() (password string, err error)
func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
type passwordAuthMsg struct { type passwordAuthMsg struct {
User string `sshtype:"50"` User string `sshtype:"50"`
Service string Service string
@ -189,7 +217,46 @@ func (cb publicKeyCallback) method() string {
return "publickey" return "publickey"
} }
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as AlgorithmSigner, algo string) {
keyFormat := signer.PublicKey().Type()
// Like in sendKexInit, if the public key implements AlgorithmSigner we
// assume it supports all algorithms, otherwise only the key format one.
as, ok := signer.(AlgorithmSigner)
if !ok {
return algorithmSignerWrapper{signer}, keyFormat
}
extPayload, ok := extensions["server-sig-algs"]
if !ok {
// If there is no "server-sig-algs" extension, fall back to the key
// format algorithm.
return as, keyFormat
}
// The server-sig-algs extension only carries underlying signature
// algorithm, but we are trying to select a protocol-level public key
// algorithm, which might be a certificate type. Extend the list of server
// supported algorithms to include the corresponding certificate algorithms.
serverAlgos := strings.Split(string(extPayload), ",")
for _, algo := range serverAlgos {
if certAlgo, ok := certificateAlgo(algo); ok {
serverAlgos = append(serverAlgos, certAlgo)
}
}
keyAlgos := algorithmsForKeyFormat(keyFormat)
algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos)
if err != nil {
// If there is no overlap, try the key anyway with the key format
// algorithm, to support servers that fail to list all supported
// algorithms.
return as, keyFormat
}
return as, algo
}
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
// Authentication is performed by sending an enquiry to test if a key is // Authentication is performed by sending an enquiry to test if a key is
// acceptable to the remote. If the key is acceptable, the client will // acceptable to the remote. If the key is acceptable, the client will
// attempt to authenticate with the valid key. If not the client will repeat // attempt to authenticate with the valid key. If not the client will repeat
@ -201,7 +268,10 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
} }
var methods []string var methods []string
for _, signer := range signers { for _, signer := range signers {
ok, err := validateKey(signer.PublicKey(), user, c) pub := signer.PublicKey()
as, algo := pickSignatureAlgorithm(signer, extensions)
ok, err := validateKey(pub, algo, user, c)
if err != nil { if err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
@ -209,13 +279,13 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
continue continue
} }
pub := signer.PublicKey()
pubKey := pub.Marshal() pubKey := pub.Marshal()
sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{ data := buildDataSignedForAuth(session, userAuthRequestMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
Method: cb.method(), Method: cb.method(),
}, []byte(pub.Type()), pubKey)) }, algo, pubKey)
sign, err := as.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
if err != nil { if err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
@ -229,7 +299,7 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
Service: serviceSSH, Service: serviceSSH,
Method: cb.method(), Method: cb.method(),
HasSig: true, HasSig: true,
Algoname: pub.Type(), Algoname: algo,
PubKey: pubKey, PubKey: pubKey,
Sig: sig, Sig: sig,
} }
@ -266,26 +336,25 @@ func containsMethod(methods []string, method string) bool {
} }
// validateKey validates the key provided is acceptable to the server. // validateKey validates the key provided is acceptable to the server.
func validateKey(key PublicKey, user string, c packetConn) (bool, error) { func validateKey(key PublicKey, algo string, user string, c packetConn) (bool, error) {
pubKey := key.Marshal() pubKey := key.Marshal()
msg := publickeyAuthMsg{ msg := publickeyAuthMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
Method: "publickey", Method: "publickey",
HasSig: false, HasSig: false,
Algoname: key.Type(), Algoname: algo,
PubKey: pubKey, PubKey: pubKey,
} }
if err := c.writePacket(Marshal(&msg)); err != nil { if err := c.writePacket(Marshal(&msg)); err != nil {
return false, err return false, err
} }
return confirmKeyAck(key, c) return confirmKeyAck(key, algo, c)
} }
func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) {
pubKey := key.Marshal() pubKey := key.Marshal()
algoname := key.Type()
for { for {
packet, err := c.readPacket() packet, err := c.readPacket()
@ -302,14 +371,14 @@ func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
if err := Unmarshal(packet, &msg); err != nil { if err := Unmarshal(packet, &msg); err != nil {
return false, err return false, err
} }
if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) { if msg.Algo != algo || !bytes.Equal(msg.PubKey, pubKey) {
return false, nil return false, nil
} }
return true, nil return true, nil
case msgUserAuthFailure: case msgUserAuthFailure:
return false, nil return false, nil
default: default:
return false, unexpectedMessageError(msgUserAuthSuccess, packet[0]) return false, unexpectedMessageError(msgUserAuthPubKeyOk, packet[0])
} }
} }
} }
@ -330,6 +399,7 @@ func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMet
// along with a list of remaining authentication methods to try next and // along with a list of remaining authentication methods to try next and
// an error if an unexpected response was received. // an error if an unexpected response was received.
func handleAuthResponse(c packetConn) (authResult, []string, error) { func handleAuthResponse(c packetConn) (authResult, []string, error) {
gotMsgExtInfo := false
for { for {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
@ -341,6 +411,12 @@ func handleAuthResponse(c packetConn) (authResult, []string, error) {
if err := handleBannerResponse(c, packet); err != nil { if err := handleBannerResponse(c, packet); err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
case msgExtInfo:
// Ignore post-authentication RFC 8308 extensions, once.
if gotMsgExtInfo {
return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
}
gotMsgExtInfo = true
case msgUserAuthFailure: case msgUserAuthFailure:
var msg userAuthFailureMsg var msg userAuthFailureMsg
if err := Unmarshal(packet, &msg); err != nil { if err := Unmarshal(packet, &msg); err != nil {
@ -380,10 +456,10 @@ func handleBannerResponse(c packetConn, packet []byte) error {
// disabling echoing (e.g. for passwords), and return all the answers. // disabling echoing (e.g. for passwords), and return all the answers.
// Challenge may be called multiple times in a single session. After // Challenge may be called multiple times in a single session. After
// successful authentication, the server may send a challenge with no // successful authentication, the server may send a challenge with no
// questions, for which the user and instruction messages should be // questions, for which the name and instruction messages should be
// printed. RFC 4256 section 3.3 details how the UI should behave for // printed. RFC 4256 section 3.3 details how the UI should behave for
// both CLI and GUI environments. // both CLI and GUI environments.
type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) type KeyboardInteractiveChallenge func(name, instruction string, questions []string, echos []bool) (answers []string, err error)
// KeyboardInteractive returns an AuthMethod using a prompt/response // KeyboardInteractive returns an AuthMethod using a prompt/response
// sequence controlled by the server. // sequence controlled by the server.
@ -395,7 +471,7 @@ func (cb KeyboardInteractiveChallenge) method() string {
return "keyboard-interactive" return "keyboard-interactive"
} }
func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
type initiateMsg struct { type initiateMsg struct {
User string `sshtype:"50"` User string `sshtype:"50"`
Service string Service string
@ -412,6 +488,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
return authFailure, nil, err return authFailure, nil, err
} }
gotMsgExtInfo := false
for { for {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
@ -425,6 +502,13 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
return authFailure, nil, err return authFailure, nil, err
} }
continue continue
case msgExtInfo:
// Ignore post-authentication RFC 8308 extensions, once.
if gotMsgExtInfo {
return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
}
gotMsgExtInfo = true
continue
case msgUserAuthInfoRequest: case msgUserAuthInfoRequest:
// OK // OK
case msgUserAuthFailure: case msgUserAuthFailure:
@ -465,7 +549,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs") return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
} }
answers, err := cb(msg.User, msg.Instruction, prompts, echos) answers, err := cb(msg.Name, msg.Instruction, prompts, echos)
if err != nil { if err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
@ -497,9 +581,9 @@ type retryableAuthMethod struct {
maxTries int maxTries int
} }
func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok authResult, methods []string, err error) { func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (ok authResult, methods []string, err error) {
for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ {
ok, methods, err = r.authMethod.auth(session, user, c, rand) ok, methods, err = r.authMethod.auth(session, user, c, rand, extensions)
if ok != authFailure || err != nil { // either success, partial success or error terminate if ok != authFailure || err != nil { // either success, partial success or error terminate
return ok, methods, err return ok, methods, err
} }
@ -542,7 +626,7 @@ type gssAPIWithMICCallback struct {
target string target string
} }
func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
m := &userAuthRequestMsg{ m := &userAuthRequestMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,

View File

@ -44,11 +44,11 @@ var preferredCiphers = []string{
// supportedKexAlgos specifies the supported key-exchange algorithms in // supportedKexAlgos specifies the supported key-exchange algorithms in
// preference order. // preference order.
var supportedKexAlgos = []string{ var supportedKexAlgos = []string{
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
// P384 and P521 are not constant-time yet, but since we don't // P384 and P521 are not constant-time yet, but since we don't
// reuse ephemeral keys, using them for ECDH should be OK. // reuse ephemeral keys, using them for ECDH should be OK.
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
kexAlgoDH14SHA1, kexAlgoDH1SHA1, kexAlgoDH14SHA256, kexAlgoDH14SHA1, kexAlgoDH1SHA1,
} }
// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden // serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden
@ -61,21 +61,21 @@ var serverForbiddenKexAlgos = map[string]struct{}{
// preferredKexAlgos specifies the default preference for key-exchange algorithms // preferredKexAlgos specifies the default preference for key-exchange algorithms
// in preference order. // in preference order.
var preferredKexAlgos = []string{ var preferredKexAlgos = []string{
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
kexAlgoDH14SHA1, kexAlgoDH14SHA256, kexAlgoDH14SHA1,
} }
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
// of authenticating servers) in preference order. // of authenticating servers) in preference order.
var supportedHostKeyAlgos = []string{ var supportedHostKeyAlgos = []string{
CertSigAlgoRSASHA2512v01, CertSigAlgoRSASHA2256v01, CertAlgoRSASHA512v01, CertAlgoRSASHA256v01,
CertSigAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01,
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
SigAlgoRSASHA2512, SigAlgoRSASHA2256, KeyAlgoRSASHA512, KeyAlgoRSASHA256,
SigAlgoRSA, KeyAlgoDSA, KeyAlgoRSA, KeyAlgoDSA,
KeyAlgoED25519, KeyAlgoED25519,
} }
@ -89,23 +89,33 @@ var supportedMACs = []string{
var supportedCompressions = []string{compressionNone} var supportedCompressions = []string{compressionNone}
// hashFuncs keeps the mapping of supported algorithms to their respective // hashFuncs keeps the mapping of supported signature algorithms to their
// hashes needed for signature verification. // respective hashes needed for signing and verification.
var hashFuncs = map[string]crypto.Hash{ var hashFuncs = map[string]crypto.Hash{
SigAlgoRSA: crypto.SHA1, KeyAlgoRSA: crypto.SHA1,
SigAlgoRSASHA2256: crypto.SHA256, KeyAlgoRSASHA256: crypto.SHA256,
SigAlgoRSASHA2512: crypto.SHA512, KeyAlgoRSASHA512: crypto.SHA512,
KeyAlgoDSA: crypto.SHA1, KeyAlgoDSA: crypto.SHA1,
KeyAlgoECDSA256: crypto.SHA256, KeyAlgoECDSA256: crypto.SHA256,
KeyAlgoECDSA384: crypto.SHA384, KeyAlgoECDSA384: crypto.SHA384,
KeyAlgoECDSA521: crypto.SHA512, KeyAlgoECDSA521: crypto.SHA512,
CertSigAlgoRSAv01: crypto.SHA1, // KeyAlgoED25519 doesn't pre-hash.
CertSigAlgoRSASHA2256v01: crypto.SHA256, KeyAlgoSKECDSA256: crypto.SHA256,
CertSigAlgoRSASHA2512v01: crypto.SHA512, KeyAlgoSKED25519: crypto.SHA256,
CertAlgoDSAv01: crypto.SHA1, }
CertAlgoECDSA256v01: crypto.SHA256,
CertAlgoECDSA384v01: crypto.SHA384, // algorithmsForKeyFormat returns the supported signature algorithms for a given
CertAlgoECDSA521v01: crypto.SHA512, // public key format (PublicKey.Type), in order of preference. See RFC 8332,
// Section 2. See also the note in sendKexInit on backwards compatibility.
func algorithmsForKeyFormat(keyFormat string) []string {
switch keyFormat {
case KeyAlgoRSA:
return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA}
case CertAlgoRSAv01:
return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01}
default:
return []string{keyFormat}
}
} }
// unexpectedMessageError results when the SSH message that we received didn't // unexpectedMessageError results when the SSH message that we received didn't
@ -152,6 +162,11 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
return 1 << 30 return 1 << 30
} }
var aeadCiphers = map[string]bool{
gcmCipherID: true,
chacha20Poly1305ID: true,
}
type algorithms struct { type algorithms struct {
kex string kex string
hostKey string hostKey string
@ -187,14 +202,18 @@ func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMs
return return
} }
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) if !aeadCiphers[ctos.Cipher] {
if err != nil { ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
return if err != nil {
return
}
} }
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) if !aeadCiphers[stoc.Cipher] {
if err != nil { stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
return if err != nil {
return
}
} }
ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
@ -278,8 +297,9 @@ func (c *Config) SetDefaults() {
} }
// buildDataSignedForAuth returns the data that is signed in order to prove // buildDataSignedForAuth returns the data that is signed in order to prove
// possession of a private key. See RFC 4252, section 7. // possession of a private key. See RFC 4252, section 7. algo is the advertised
func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { // algorithm, and may be a certificate type.
func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte {
data := struct { data := struct {
Session []byte Session []byte
Type byte Type byte
@ -287,7 +307,7 @@ func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubK
Service string Service string
Method string Method string
Sign bool Sign bool
Algo []byte Algo string
PubKey []byte PubKey []byte
}{ }{
sessionID, sessionID,

View File

@ -12,8 +12,9 @@ the multiplexed nature of SSH is exposed to users that wish to support
others. others.
References: References:
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
This package does not fall under the stability promise of the Go language itself, This package does not fall under the stability promise of the Go language itself,
so its API may be changed when pressing needs arise. so its API may be changed when pressing needs arise.

View File

@ -455,21 +455,38 @@ func (t *handshakeTransport) sendKexInit() error {
} }
io.ReadFull(rand.Reader, msg.Cookie[:]) io.ReadFull(rand.Reader, msg.Cookie[:])
if len(t.hostKeys) > 0 { isServer := len(t.hostKeys) > 0
if isServer {
for _, k := range t.hostKeys { for _, k := range t.hostKeys {
algo := k.PublicKey().Type() // If k is an AlgorithmSigner, presume it supports all signature algorithms
switch algo { // associated with the key format. (Ideally AlgorithmSigner would have a
case KeyAlgoRSA: // method to advertise supported algorithms, but it doesn't. This means that
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{SigAlgoRSASHA2512, SigAlgoRSASHA2256, SigAlgoRSA}...) // adding support for a new algorithm is a breaking change, as we will
case CertAlgoRSAv01: // immediately negotiate it even if existing implementations don't support
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{CertSigAlgoRSASHA2512v01, CertSigAlgoRSASHA2256v01, CertSigAlgoRSAv01}...) // it. If that ever happens, we'll have to figure something out.)
default: // If k is not an AlgorithmSigner, we can only assume it only supports the
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo) // algorithms that matches the key format. (This means that Sign can't pick
// a different default.)
keyFormat := k.PublicKey().Type()
if _, ok := k.(AlgorithmSigner); ok {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...)
} else {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
} }
} }
} else { } else {
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
// algorithms the server supports for public key authentication. See RFC
// 8308, Section 2.1.
if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1)
msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
}
} }
packet := Marshal(msg) packet := Marshal(msg)
// writePacket destroys the contents, so save a copy. // writePacket destroys the contents, so save a copy.
@ -589,9 +606,9 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
var result *kexResult var result *kexResult
if len(t.hostKeys) > 0 { if len(t.hostKeys) > 0 {
result, err = t.server(kex, t.algorithms, &magics) result, err = t.server(kex, &magics)
} else { } else {
result, err = t.client(kex, t.algorithms, &magics) result, err = t.client(kex, &magics)
} }
if err != nil { if err != nil {
@ -618,33 +635,52 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
return nil return nil
} }
func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { // algorithmSignerWrapper is an AlgorithmSigner that only supports the default
var hostKey Signer // key format algorithm.
for _, k := range t.hostKeys { //
kt := k.PublicKey().Type() // This is technically a violation of the AlgorithmSigner interface, but it
if kt == algs.hostKey { // should be unreachable given where we use this. Anyway, at least it returns an
hostKey = k // error instead of panicing or producing an incorrect signature.
} else if signer, ok := k.(AlgorithmSigner); ok { type algorithmSignerWrapper struct {
// Some signature algorithms don't show up as key types Signer
// so we have to manually check for a compatible host key. }
switch kt {
case KeyAlgoRSA: func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algs.hostKey == SigAlgoRSASHA2256 || algs.hostKey == SigAlgoRSASHA2512 { if algorithm != underlyingAlgo(a.PublicKey().Type()) {
hostKey = &rsaSigner{signer, algs.hostKey} return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm")
} }
case CertAlgoRSAv01: return a.Sign(rand, data)
if algs.hostKey == CertSigAlgoRSASHA2256v01 || algs.hostKey == CertSigAlgoRSASHA2512v01 { }
hostKey = &rsaSigner{signer, certToPrivAlgo(algs.hostKey)}
} func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
for _, k := range hostKeys {
if algo == k.PublicKey().Type() {
return algorithmSignerWrapper{k}
}
k, ok := k.(AlgorithmSigner)
if !ok {
continue
}
for _, a := range algorithmsForKeyFormat(k.PublicKey().Type()) {
if algo == a {
return k
} }
} }
} }
return nil
}
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
hostKey := pickHostKey(t.hostKeys, t.algorithms.hostKey)
if hostKey == nil {
return nil, errors.New("ssh: internal error: negotiated unsupported signature type")
}
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.hostKey)
return r, err return r, err
} }
func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
result, err := kex.Client(t.conn, t.config.Rand, magics) result, err := kex.Client(t.conn, t.config.Rand, magics)
if err != nil { if err != nil {
return nil, err return nil, err
@ -655,7 +691,7 @@ func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *
return nil, err return nil, err
} }
if err := verifyHostKeySignature(hostKey, algs.hostKey, result); err != nil { if err := verifyHostKeySignature(hostKey, t.algorithms.hostKey, result); err != nil {
return nil, err return nil, err
} }

186
vendor/golang.org/x/crypto/ssh/kex.go generated vendored
View File

@ -20,12 +20,14 @@ import (
) )
const ( const (
kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
kexAlgoECDH256 = "ecdh-sha2-nistp256" kexAlgoDH14SHA256 = "diffie-hellman-group14-sha256"
kexAlgoECDH384 = "ecdh-sha2-nistp384" kexAlgoECDH256 = "ecdh-sha2-nistp256"
kexAlgoECDH521 = "ecdh-sha2-nistp521" kexAlgoECDH384 = "ecdh-sha2-nistp384"
kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" kexAlgoECDH521 = "ecdh-sha2-nistp521"
kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org"
kexAlgoCurve25519SHA256 = "curve25519-sha256"
// For the following kex only the client half contains a production // For the following kex only the client half contains a production
// ready implementation. The server half only consists of a minimal // ready implementation. The server half only consists of a minimal
@ -75,8 +77,9 @@ func (m *handshakeMagics) write(w io.Writer) {
// kexAlgorithm abstracts different key exchange algorithms. // kexAlgorithm abstracts different key exchange algorithms.
type kexAlgorithm interface { type kexAlgorithm interface {
// Server runs server-side key agreement, signing the result // Server runs server-side key agreement, signing the result
// with a hostkey. // with a hostkey. algo is the negotiated algorithm, and may
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) // be a certificate type.
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error)
// Client runs the client-side key agreement. Caller is // Client runs the client-side key agreement. Caller is
// responsible for verifying the host key signature. // responsible for verifying the host key signature.
@ -86,6 +89,7 @@ type kexAlgorithm interface {
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
type dhGroup struct { type dhGroup struct {
g, p, pMinus1 *big.Int g, p, pMinus1 *big.Int
hashFunc crypto.Hash
} }
func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
@ -96,8 +100,6 @@ func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int,
} }
func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
hashFunc := crypto.SHA1
var x *big.Int var x *big.Int
for { for {
var err error var err error
@ -132,7 +134,7 @@ func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha
return nil, err return nil, err
} }
h := hashFunc.New() h := group.hashFunc.New()
magics.write(h) magics.write(h)
writeString(h, kexDHReply.HostKey) writeString(h, kexDHReply.HostKey)
writeInt(h, X) writeInt(h, X)
@ -146,12 +148,11 @@ func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha
K: K, K: K,
HostKey: kexDHReply.HostKey, HostKey: kexDHReply.HostKey,
Signature: kexDHReply.Signature, Signature: kexDHReply.Signature,
Hash: crypto.SHA1, Hash: group.hashFunc,
}, nil }, nil
} }
func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
hashFunc := crypto.SHA1
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return return
@ -179,7 +180,7 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha
hostKeyBytes := priv.PublicKey().Marshal() hostKeyBytes := priv.PublicKey().Marshal()
h := hashFunc.New() h := group.hashFunc.New()
magics.write(h) magics.write(h)
writeString(h, hostKeyBytes) writeString(h, hostKeyBytes)
writeInt(h, kexDHInit.X) writeInt(h, kexDHInit.X)
@ -193,7 +194,7 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha
// H is already a hash, but the hostkey signing will apply its // H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm. // own key-specific hash algorithm.
sig, err := signAndMarshal(priv, randSource, H) sig, err := signAndMarshal(priv, randSource, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -211,7 +212,7 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha
K: K, K: K,
HostKey: hostKeyBytes, HostKey: hostKeyBytes,
Signature: sig, Signature: sig,
Hash: crypto.SHA1, Hash: group.hashFunc,
}, err }, err
} }
@ -314,7 +315,7 @@ func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
return true return true
} }
func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return nil, err return nil, err
@ -359,7 +360,7 @@ func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, p
// H is already a hash, but the hostkey signing will apply its // H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm. // own key-specific hash algorithm.
sig, err := signAndMarshal(priv, rand, H) sig, err := signAndMarshal(priv, rand, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -384,39 +385,62 @@ func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, p
}, nil }, nil
} }
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case bitSize <= 384:
return crypto.SHA384
}
return crypto.SHA512
}
var kexAlgoMap = map[string]kexAlgorithm{} var kexAlgoMap = map[string]kexAlgorithm{}
func init() { func init() {
// This is the group called diffie-hellman-group1-sha1 in RFC // This is the group called diffie-hellman-group1-sha1 in
// 4253 and Oakley Group 2 in RFC 2409. // RFC 4253 and Oakley Group 2 in RFC 2409.
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
pMinus1: new(big.Int).Sub(p, bigOne),
hashFunc: crypto.SHA1,
}
// This are the groups called diffie-hellman-group14-sha1 and
// diffie-hellman-group14-sha256 in RFC 4253 and RFC 8268,
// and Oakley Group 14 in RFC 3526.
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
group14 := &dhGroup{
g: new(big.Int).SetInt64(2), g: new(big.Int).SetInt64(2),
p: p, p: p,
pMinus1: new(big.Int).Sub(p, bigOne), pMinus1: new(big.Int).Sub(p, bigOne),
} }
// This is the group called diffie-hellman-group14-sha1 in RFC
// 4253 and Oakley Group 14 in RFC 3526.
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2), g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
p: p, hashFunc: crypto.SHA1,
pMinus1: new(big.Int).Sub(p, bigOne), }
kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
hashFunc: crypto.SHA256,
} }
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{}
kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
} }
// curve25519sha256 implements the curve25519-sha256@libssh.org key // curve25519sha256 implements the curve25519-sha256 (formerly known as
// agreement protocol, as described in // curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731.
// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
type curve25519sha256 struct{} type curve25519sha256 struct{}
type curve25519KeyPair struct { type curve25519KeyPair struct {
@ -486,7 +510,7 @@ func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handsh
}, nil }, nil
} }
func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return return
@ -527,7 +551,7 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh
H := h.Sum(nil) H := h.Sum(nil)
sig, err := signAndMarshal(priv, rand, H) sig, err := signAndMarshal(priv, rand, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -553,7 +577,6 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh
// diffie-hellman-group-exchange-sha256 key agreement protocols, // diffie-hellman-group-exchange-sha256 key agreement protocols,
// as described in RFC 4419 // as described in RFC 4419
type dhGEXSHA struct { type dhGEXSHA struct {
g, p *big.Int
hashFunc crypto.Hash hashFunc crypto.Hash
} }
@ -563,14 +586,7 @@ const (
dhGroupExchangeMaximumBits = 8192 dhGroupExchangeMaximumBits = 8192
) )
func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
if theirPublic.Sign() <= 0 || theirPublic.Cmp(gex.p) >= 0 {
return nil, fmt.Errorf("ssh: DH parameter out of bounds")
}
return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil
}
func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
// Send GexRequest // Send GexRequest
kexDHGexRequest := kexDHGexRequestMsg{ kexDHGexRequest := kexDHGexRequestMsg{
MinBits: dhGroupExchangeMinimumBits, MinBits: dhGroupExchangeMinimumBits,
@ -587,35 +603,29 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
return nil, err return nil, err
} }
var kexDHGexGroup kexDHGexGroupMsg var msg kexDHGexGroupMsg
if err = Unmarshal(packet, &kexDHGexGroup); err != nil { if err = Unmarshal(packet, &msg); err != nil {
return nil, err return nil, err
} }
// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
if kexDHGexGroup.P.BitLen() < dhGroupExchangeMinimumBits || kexDHGexGroup.P.BitLen() > dhGroupExchangeMaximumBits { if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits {
return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", kexDHGexGroup.P.BitLen()) return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen())
} }
gex.p = kexDHGexGroup.P // Check if g is safe by verifying that 1 < g < p-1
gex.g = kexDHGexGroup.G pMinusOne := new(big.Int).Sub(msg.P, bigOne)
if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 {
// Check if g is safe by verifing that g > 1 and g < p - 1
one := big.NewInt(1)
var pMinusOne = &big.Int{}
pMinusOne.Sub(gex.p, one)
if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 {
return nil, fmt.Errorf("ssh: server provided gex g is not safe") return nil, fmt.Errorf("ssh: server provided gex g is not safe")
} }
// Send GexInit // Send GexInit
var pHalf = &big.Int{} pHalf := new(big.Int).Rsh(msg.P, 1)
pHalf.Rsh(gex.p, 1)
x, err := rand.Int(randSource, pHalf) x, err := rand.Int(randSource, pHalf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
X := new(big.Int).Exp(gex.g, x, gex.p) X := new(big.Int).Exp(msg.G, x, msg.P)
kexDHGexInit := kexDHGexInitMsg{ kexDHGexInit := kexDHGexInitMsg{
X: X, X: X,
} }
@ -634,13 +644,13 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
return nil, err return nil, err
} }
kInt, err := gex.diffieHellman(kexDHGexReply.Y, x) if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 {
if err != nil { return nil, errors.New("ssh: DH parameter out of bounds")
return nil, err
} }
kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P)
// Check if k is safe by verifing that k > 1 and k < p - 1 // Check if k is safe by verifying that k > 1 and k < p - 1
if kInt.Cmp(one) != 1 && kInt.Cmp(pMinusOne) != -1 { if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 {
return nil, fmt.Errorf("ssh: derived k is not safe") return nil, fmt.Errorf("ssh: derived k is not safe")
} }
@ -650,8 +660,8 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
writeInt(h, gex.p) writeInt(h, msg.P)
writeInt(h, gex.g) writeInt(h, msg.G)
writeInt(h, X) writeInt(h, X)
writeInt(h, kexDHGexReply.Y) writeInt(h, kexDHGexReply.Y)
K := make([]byte, intLength(kInt)) K := make([]byte, intLength(kInt))
@ -670,7 +680,7 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. // Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
// //
// This is a minimal implementation to satisfy the automated tests. // This is a minimal implementation to satisfy the automated tests.
func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
// Receive GexRequest // Receive GexRequest
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
@ -681,35 +691,17 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
return return
} }
// smoosh the user's preferred size into our own limits
if kexDHGexRequest.PreferedBits > dhGroupExchangeMaximumBits {
kexDHGexRequest.PreferedBits = dhGroupExchangeMaximumBits
}
if kexDHGexRequest.PreferedBits < dhGroupExchangeMinimumBits {
kexDHGexRequest.PreferedBits = dhGroupExchangeMinimumBits
}
// fix min/max if they're inconsistent. technically, we could just pout
// and hang up, but there's no harm in giving them the benefit of the
// doubt and just picking a bitsize for them.
if kexDHGexRequest.MinBits > kexDHGexRequest.PreferedBits {
kexDHGexRequest.MinBits = kexDHGexRequest.PreferedBits
}
if kexDHGexRequest.MaxBits < kexDHGexRequest.PreferedBits {
kexDHGexRequest.MaxBits = kexDHGexRequest.PreferedBits
}
// Send GexGroup // Send GexGroup
// This is the group called diffie-hellman-group14-sha1 in RFC // This is the group called diffie-hellman-group14-sha1 in RFC
// 4253 and Oakley Group 14 in RFC 3526. // 4253 and Oakley Group 14 in RFC 3526.
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
gex.p = p g := big.NewInt(2)
gex.g = big.NewInt(2)
kexDHGexGroup := kexDHGexGroupMsg{ msg := &kexDHGexGroupMsg{
P: gex.p, P: p,
G: gex.g, G: g,
} }
if err := c.writePacket(Marshal(&kexDHGexGroup)); err != nil { if err := c.writePacket(Marshal(msg)); err != nil {
return nil, err return nil, err
} }
@ -723,19 +715,19 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
return return
} }
var pHalf = &big.Int{} pHalf := new(big.Int).Rsh(p, 1)
pHalf.Rsh(gex.p, 1)
y, err := rand.Int(randSource, pHalf) y, err := rand.Int(randSource, pHalf)
if err != nil { if err != nil {
return return
} }
Y := new(big.Int).Exp(g, y, p)
Y := new(big.Int).Exp(gex.g, y, gex.p) pMinusOne := new(big.Int).Sub(p, bigOne)
kInt, err := gex.diffieHellman(kexDHGexInit.X, y) if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 {
if err != nil { return nil, errors.New("ssh: DH parameter out of bounds")
return nil, err
} }
kInt := new(big.Int).Exp(kexDHGexInit.X, y, p)
hostKeyBytes := priv.PublicKey().Marshal() hostKeyBytes := priv.PublicKey().Marshal()
@ -745,8 +737,8 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
writeInt(h, gex.p) writeInt(h, p)
writeInt(h, gex.g) writeInt(h, g)
writeInt(h, kexDHGexInit.X) writeInt(h, kexDHGexInit.X)
writeInt(h, Y) writeInt(h, Y)
@ -758,7 +750,7 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
// H is already a hash, but the hostkey signing will apply its // H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm. // own key-specific hash algorithm.
sig, err := signAndMarshal(priv, randSource, H) sig, err := signAndMarshal(priv, randSource, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -30,8 +30,9 @@ import (
"golang.org/x/crypto/ssh/internal/bcrypt_pbkdf" "golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
) )
// These constants represent the algorithm names for key types supported by this // Public key algorithms names. These values can appear in PublicKey.Type,
// package. // ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner
// arguments.
const ( const (
KeyAlgoRSA = "ssh-rsa" KeyAlgoRSA = "ssh-rsa"
KeyAlgoDSA = "ssh-dss" KeyAlgoDSA = "ssh-dss"
@ -41,16 +42,21 @@ const (
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
KeyAlgoED25519 = "ssh-ed25519" KeyAlgoED25519 = "ssh-ed25519"
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com" 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
// corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2.
KeyAlgoRSASHA256 = "rsa-sha2-256"
KeyAlgoRSASHA512 = "rsa-sha2-512"
) )
// These constants represent non-default signature algorithms that are supported
// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See
// [PROTOCOL.agent] section 4.5.1 and
// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10
const ( const (
SigAlgoRSA = "ssh-rsa" // Deprecated: use KeyAlgoRSA.
SigAlgoRSASHA2256 = "rsa-sha2-256" SigAlgoRSA = KeyAlgoRSA
SigAlgoRSASHA2512 = "rsa-sha2-512" // Deprecated: use KeyAlgoRSASHA256.
SigAlgoRSASHA2256 = KeyAlgoRSASHA256
// Deprecated: use KeyAlgoRSASHA512.
SigAlgoRSASHA2512 = KeyAlgoRSASHA512
) )
// parsePubKey parses a public key of the given algorithm. // parsePubKey parses a public key of the given algorithm.
@ -70,7 +76,7 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err
case KeyAlgoSKED25519: case KeyAlgoSKED25519:
return parseSKEd25519(in) return parseSKEd25519(in)
case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
cert, err := parseCert(in, certToPrivAlgo(algo)) cert, err := parseCert(in, certKeyAlgoNames[algo])
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -289,18 +295,21 @@ func MarshalAuthorizedKey(key PublicKey) []byte {
return b.Bytes() return b.Bytes()
} }
// PublicKey is an abstraction of different types of public keys. // PublicKey represents a public key using an unspecified algorithm.
//
// Some PublicKeys provided by this package also implement CryptoPublicKey.
type PublicKey interface { type PublicKey interface {
// Type returns the key's type, e.g. "ssh-rsa". // Type returns the key format name, e.g. "ssh-rsa".
Type() string Type() string
// Marshal returns the serialized key data in SSH wire format, // Marshal returns the serialized key data in SSH wire format, with the name
// with the name prefix. To unmarshal the returned data, use // prefix. To unmarshal the returned data, use the ParsePublicKey function.
// the ParsePublicKey function.
Marshal() []byte Marshal() []byte
// Verify that sig is a signature on the given data using this // Verify that sig is a signature on the given data using this key. This
// key. This function will hash the data appropriately first. // method will hash the data appropriately first. sig.Format is allowed to
// be any signature algorithm compatible with the key type, the caller
// should check if it has more stringent requirements.
Verify(data []byte, sig *Signature) error Verify(data []byte, sig *Signature) error
} }
@ -311,25 +320,32 @@ type CryptoPublicKey interface {
} }
// A Signer can create signatures that verify against a public key. // A Signer can create signatures that verify against a public key.
//
// Some Signers provided by this package also implement AlgorithmSigner.
type Signer interface { type Signer interface {
// PublicKey returns an associated PublicKey instance. // PublicKey returns the associated PublicKey.
PublicKey() PublicKey PublicKey() PublicKey
// Sign returns raw signature for the given data. This method // Sign returns a signature for the given data. This method will hash the
// will apply the hash specified for the keytype to the data. // data appropriately first. The signature algorithm is expected to match
// the key format returned by the PublicKey.Type method (and not to be any
// alternative algorithm supported by the key format).
Sign(rand io.Reader, data []byte) (*Signature, error) Sign(rand io.Reader, data []byte) (*Signature, error)
} }
// A AlgorithmSigner is a Signer that also supports specifying a specific // An AlgorithmSigner is a Signer that also supports specifying an algorithm to
// algorithm to use for signing. // use for signing.
//
// An AlgorithmSigner can't advertise the algorithms it supports, so it should
// be prepared to be invoked with every algorithm supported by the public key
// format.
type AlgorithmSigner interface { type AlgorithmSigner interface {
Signer Signer
// SignWithAlgorithm is like Signer.Sign, but allows specification of a // SignWithAlgorithm is like Signer.Sign, but allows specifying a desired
// non-default signing algorithm. See the SigAlgo* constants in this // signing algorithm. Callers may pass an empty string for the algorithm in
// package for signature algorithms supported by this package. Callers may // which case the AlgorithmSigner will use a default algorithm. This default
// pass an empty string for the algorithm in which case the AlgorithmSigner // doesn't currently control any behavior in this package.
// will use its default algorithm.
SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
} }
@ -381,17 +397,11 @@ func (r *rsaPublicKey) Marshal() []byte {
} }
func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
var hash crypto.Hash supportedAlgos := algorithmsForKeyFormat(r.Type())
switch sig.Format { if !contains(supportedAlgos, sig.Format) {
case SigAlgoRSA:
hash = crypto.SHA1
case SigAlgoRSASHA2256:
hash = crypto.SHA256
case SigAlgoRSASHA2512:
hash = crypto.SHA512
default:
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
} }
hash := hashFuncs[sig.Format]
h := hash.New() h := hash.New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
@ -466,7 +476,7 @@ func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
if sig.Format != k.Type() { if sig.Format != k.Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
} }
h := crypto.SHA1.New() h := hashFuncs[sig.Format].New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
@ -499,7 +509,7 @@ func (k *dsaPrivateKey) PublicKey() PublicKey {
} }
func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
return k.SignWithAlgorithm(rand, data, "") return k.SignWithAlgorithm(rand, data, k.PublicKey().Type())
} }
func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
@ -507,7 +517,7 @@ func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
} }
h := crypto.SHA1.New() h := hashFuncs[k.PublicKey().Type()].New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
r, s, err := dsa.Sign(rand, k.PrivateKey, digest) r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
@ -603,19 +613,6 @@ func supportedEllipticCurve(curve elliptic.Curve) bool {
return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
} }
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case bitSize <= 384:
return crypto.SHA384
}
return crypto.SHA512
}
// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. // parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
var w struct { var w struct {
@ -671,7 +668,7 @@ func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
} }
h := ecHash(k.Curve).New() h := hashFuncs[sig.Format].New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
@ -775,7 +772,7 @@ func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
} }
h := ecHash(k.Curve).New() h := hashFuncs[sig.Format].New()
h.Write([]byte(k.application)) h.Write([]byte(k.application))
appDigest := h.Sum(nil) appDigest := h.Sum(nil)
@ -874,7 +871,7 @@ func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
return fmt.Errorf("invalid size %d for Ed25519 public key", l) return fmt.Errorf("invalid size %d for Ed25519 public key", l)
} }
h := sha256.New() h := hashFuncs[sig.Format].New()
h.Write([]byte(k.application)) h.Write([]byte(k.application))
appDigest := h.Sum(nil) appDigest := h.Sum(nil)
@ -939,15 +936,6 @@ func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) {
return &dsaPrivateKey{key}, nil return &dsaPrivateKey{key}, nil
} }
type rsaSigner struct {
AlgorithmSigner
defaultAlgorithm string
}
func (s *rsaSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.AlgorithmSigner.SignWithAlgorithm(rand, data, s.defaultAlgorithm)
}
type wrappedSigner struct { type wrappedSigner struct {
signer crypto.Signer signer crypto.Signer
pubKey PublicKey pubKey PublicKey
@ -970,44 +958,20 @@ func (s *wrappedSigner) PublicKey() PublicKey {
} }
func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.SignWithAlgorithm(rand, data, "") return s.SignWithAlgorithm(rand, data, s.pubKey.Type())
} }
func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
var hashFunc crypto.Hash if algorithm == "" {
algorithm = s.pubKey.Type()
if _, ok := s.pubKey.(*rsaPublicKey); ok {
// RSA keys support a few hash functions determined by the requested signature algorithm
switch algorithm {
case "", SigAlgoRSA:
algorithm = SigAlgoRSA
hashFunc = crypto.SHA1
case SigAlgoRSASHA2256:
hashFunc = crypto.SHA256
case SigAlgoRSASHA2512:
hashFunc = crypto.SHA512
default:
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
}
} else {
// The only supported algorithm for all other key types is the same as the type of the key
if algorithm == "" {
algorithm = s.pubKey.Type()
} else if algorithm != s.pubKey.Type() {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
}
switch key := s.pubKey.(type) {
case *dsaPublicKey:
hashFunc = crypto.SHA1
case *ecdsaPublicKey:
hashFunc = ecHash(key.Curve)
case ed25519PublicKey:
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", key)
}
} }
supportedAlgos := algorithmsForKeyFormat(s.pubKey.Type())
if !contains(supportedAlgos, algorithm) {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
}
hashFunc := hashFuncs[algorithm]
var digest []byte var digest []byte
if hashFunc != 0 { if hashFunc != 0 {
h := hashFunc.New() h := hashFunc.New()

View File

@ -141,6 +141,14 @@ type serviceAcceptMsg struct {
Service string `sshtype:"6"` Service string `sshtype:"6"`
} }
// See RFC 8308, section 2.3
const msgExtInfo = 7
type extInfoMsg struct {
NumExtensions uint32 `sshtype:"7"`
Payload []byte `ssh:"rest"`
}
// See RFC 4252, section 5. // See RFC 4252, section 5.
const msgUserAuthRequest = 50 const msgUserAuthRequest = 50
@ -180,11 +188,11 @@ const msgUserAuthInfoRequest = 60
const msgUserAuthInfoResponse = 61 const msgUserAuthInfoResponse = 61
type userAuthInfoRequestMsg struct { type userAuthInfoRequestMsg struct {
User string `sshtype:"60"` Name string `sshtype:"60"`
Instruction string Instruction string
DeprecatedLanguage string Language string
NumPrompts uint32 NumPrompts uint32
Prompts []byte `ssh:"rest"` Prompts []byte `ssh:"rest"`
} }
// See RFC 4254, section 5.1. // See RFC 4254, section 5.1.
@ -782,6 +790,8 @@ func decode(packet []byte) (interface{}, error) {
msg = new(serviceRequestMsg) msg = new(serviceRequestMsg)
case msgServiceAccept: case msgServiceAccept:
msg = new(serviceAcceptMsg) msg = new(serviceAcceptMsg)
case msgExtInfo:
msg = new(extInfoMsg)
case msgKexInit: case msgKexInit:
msg = new(kexInitMsg) msg = new(kexInitMsg)
case msgKexDHInit: case msgKexDHInit:
@ -843,6 +853,7 @@ var packetTypeNames = map[byte]string{
msgDisconnect: "disconnectMsg", msgDisconnect: "disconnectMsg",
msgServiceRequest: "serviceRequestMsg", msgServiceRequest: "serviceRequestMsg",
msgServiceAccept: "serviceAcceptMsg", msgServiceAccept: "serviceAcceptMsg",
msgExtInfo: "extInfoMsg",
msgKexInit: "kexInitMsg", msgKexInit: "kexInitMsg",
msgKexDHInit: "kexDHInitMsg", msgKexDHInit: "kexDHInitMsg",
msgKexDHReply: "kexDHReplyMsg", msgKexDHReply: "kexDHReplyMsg",

View File

@ -120,7 +120,7 @@ type ServerConfig struct {
} }
// AddHostKey adds a private key as a host key. If an existing host // AddHostKey adds a private key as a host key. If an existing host
// key exists with the same algorithm, it is overwritten. Each server // key exists with the same public key format, it is replaced. Each server
// config must have at least one host key. // config must have at least one host key.
func (s *ServerConfig) AddHostKey(key Signer) { func (s *ServerConfig) AddHostKey(key Signer) {
for i, k := range s.hostKeys { for i, k := range s.hostKeys {
@ -212,9 +212,10 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
} }
// signAndMarshal signs the data with the appropriate algorithm, // signAndMarshal signs the data with the appropriate algorithm,
// and serializes the result in SSH wire format. // and serializes the result in SSH wire format. algo is the negotiate
func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { // algorithm and may be a certificate type.
sig, err := k.Sign(rand, data) func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -284,7 +285,7 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error)
func isAcceptableAlgo(algo string) bool { func isAcceptableAlgo(algo string) bool {
switch algo { switch algo {
case SigAlgoRSA, SigAlgoRSASHA2256, SigAlgoRSASHA2512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519, case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519,
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
return true return true
} }
@ -553,6 +554,7 @@ userAuthLoop:
if !ok || len(payload) > 0 { if !ok || len(payload) > 0 {
return nil, parseError(msgUserAuthRequest) return nil, parseError(msgUserAuthRequest)
} }
// Ensure the public key algo and signature algo // Ensure the public key algo and signature algo
// are supported. Compare the private key // are supported. Compare the private key
// algorithm name that corresponds to algo with // algorithm name that corresponds to algo with
@ -562,7 +564,12 @@ userAuthLoop:
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
break break
} }
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) if underlyingAlgo(algo) != sig.Format {
authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
break
}
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
if err := pubKey.Verify(signedData, sig); err != nil { if err := pubKey.Verify(signedData, sig); err != nil {
return nil, err return nil, err
@ -633,6 +640,30 @@ userAuthLoop:
} }
authFailures++ authFailures++
if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
// If we have hit the max attempts, don't bother sending the
// final SSH_MSG_USERAUTH_FAILURE message, since there are
// no more authentication methods which can be attempted,
// and this message may cause the client to re-attempt
// authentication while we send the disconnect message.
// Continue, and trigger the disconnect at the start of
// the loop.
//
// The SSH specification is somewhat confusing about this,
// RFC 4252 Section 5.1 requires each authentication failure
// be responded to with a respective SSH_MSG_USERAUTH_FAILURE
// message, but Section 4 says the server should disconnect
// after some number of attempts, but it isn't explicit which
// message should take precedence (i.e. should there be a failure
// message than a disconnect message, or if we are going to
// disconnect, should we only send that message.)
//
// Either way, OpenSSH disconnects immediately after the last
// failed authnetication attempt, and given they are typically
// considered the golden implementation it seems reasonable
// to match that behavior.
continue
}
var failureMsg userAuthFailureMsg var failureMsg userAuthFailureMsg
if config.PasswordCallback != nil { if config.PasswordCallback != nil {
@ -670,7 +701,7 @@ type sshClientKeyboardInteractive struct {
*connection *connection
} }
func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
if len(questions) != len(echos) { if len(questions) != len(echos) {
return nil, errors.New("ssh: echos and questions must have equal length") return nil, errors.New("ssh: echos and questions must have equal length")
} }
@ -682,6 +713,7 @@ func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, quest
} }
if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
Name: name,
Instruction: instruction, Instruction: instruction,
NumPrompts: uint32(len(questions)), NumPrompts: uint32(len(questions)),
Prompts: prompts, Prompts: prompts,

View File

@ -85,6 +85,7 @@ const (
IXANY = 39 IXANY = 39
IXOFF = 40 IXOFF = 40
IMAXBEL = 41 IMAXBEL = 41
IUTF8 = 42 // RFC 8160
ISIG = 50 ISIG = 50
ICANON = 51 ICANON = 51
XCASE = 52 XCASE = 52

View File

@ -238,15 +238,19 @@ var (
// (to setup server->client keys) or clientKeys (for client->server keys). // (to setup server->client keys) or clientKeys (for client->server keys).
func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
cipherMode := cipherModes[algs.Cipher] cipherMode := cipherModes[algs.Cipher]
macMode := macModes[algs.MAC]
iv := make([]byte, cipherMode.ivSize) iv := make([]byte, cipherMode.ivSize)
key := make([]byte, cipherMode.keySize) key := make([]byte, cipherMode.keySize)
macKey := make([]byte, macMode.keySize)
generateKeyMaterial(iv, d.ivTag, kex) generateKeyMaterial(iv, d.ivTag, kex)
generateKeyMaterial(key, d.keyTag, kex) generateKeyMaterial(key, d.keyTag, kex)
generateKeyMaterial(macKey, d.macKeyTag, kex)
var macKey []byte
if !aeadCiphers[algs.Cipher] {
macMode := macModes[algs.MAC]
macKey = make([]byte, macMode.keySize)
generateKeyMaterial(macKey, d.macKeyTag, kex)
}
return cipherModes[algs.Cipher].create(key, iv, macKey, algs) return cipherModes[algs.Cipher].create(key, iv, macKey, algs)
} }

3
vendor/modules.txt vendored
View File

@ -699,7 +699,7 @@ go.opencensus.io/internal
go.opencensus.io/trace go.opencensus.io/trace
go.opencensus.io/trace/internal go.opencensus.io/trace/internal
go.opencensus.io/trace/tracestate go.opencensus.io/trace/tracestate
# golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce # golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
## explicit ## explicit
golang.org/x/crypto/blowfish golang.org/x/crypto/blowfish
golang.org/x/crypto/cast5 golang.org/x/crypto/cast5
@ -707,7 +707,6 @@ golang.org/x/crypto/chacha20
golang.org/x/crypto/curve25519 golang.org/x/crypto/curve25519
golang.org/x/crypto/curve25519/internal/field golang.org/x/crypto/curve25519/internal/field
golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519
golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/crypto/internal/poly1305 golang.org/x/crypto/internal/poly1305
golang.org/x/crypto/internal/subtle golang.org/x/crypto/internal/subtle
golang.org/x/crypto/openpgp golang.org/x/crypto/openpgp