summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto/ssh/handshake.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/handshake.go')
-rw-r--r--vendor/golang.org/x/crypto/ssh/handshake.go98
1 files changed, 66 insertions, 32 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
index 05ad49c3..f815cdb4 100644
--- a/vendor/golang.org/x/crypto/ssh/handshake.go
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -455,21 +455,36 @@ func (t *handshakeTransport) sendKexInit() error {
}
io.ReadFull(rand.Reader, msg.Cookie[:])
- if len(t.hostKeys) > 0 {
+ isServer := len(t.hostKeys) > 0
+ if isServer {
for _, k := range t.hostKeys {
- algo := k.PublicKey().Type()
- switch algo {
- case KeyAlgoRSA:
- msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{SigAlgoRSASHA2512, SigAlgoRSASHA2256, SigAlgoRSA}...)
- case CertAlgoRSAv01:
- msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{CertSigAlgoRSASHA2512v01, CertSigAlgoRSASHA2256v01, CertSigAlgoRSAv01}...)
- default:
- msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo)
+ // If k is an AlgorithmSigner, presume it supports all signature algorithms
+ // associated with the key format. (Ideally AlgorithmSigner would have a
+ // method to advertise supported algorithms, but it doesn't. This means that
+ // adding support for a new algorithm is a breaking change, as we will
+ // immediately negotiate it even if existing implementations don't support
+ // it. If that ever happens, we'll have to figure something out.)
+ // If k is not an AlgorithmSigner, we can only assume it only supports the
+ // 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 {
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
+ // 8303, Section 2.1.
+ 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)
// writePacket destroys the contents, so save a copy.
@@ -589,9 +604,9 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
var result *kexResult
if len(t.hostKeys) > 0 {
- result, err = t.server(kex, t.algorithms, &magics)
+ result, err = t.server(kex, &magics)
} else {
- result, err = t.client(kex, t.algorithms, &magics)
+ result, err = t.client(kex, &magics)
}
if err != nil {
@@ -618,33 +633,52 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
return nil
}
-func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) {
- var hostKey Signer
- for _, k := range t.hostKeys {
- kt := k.PublicKey().Type()
- if kt == algs.hostKey {
- hostKey = k
- } else if signer, ok := k.(AlgorithmSigner); ok {
- // Some signature algorithms don't show up as key types
- // so we have to manually check for a compatible host key.
- switch kt {
- case KeyAlgoRSA:
- if algs.hostKey == SigAlgoRSASHA2256 || algs.hostKey == SigAlgoRSASHA2512 {
- hostKey = &rsaSigner{signer, algs.hostKey}
- }
- case CertAlgoRSAv01:
- if algs.hostKey == CertSigAlgoRSASHA2256v01 || algs.hostKey == CertSigAlgoRSASHA2512v01 {
- hostKey = &rsaSigner{signer, certToPrivAlgo(algs.hostKey)}
- }
+// algorithmSignerWrapper is an AlgorithmSigner that only supports the default
+// key format algorithm.
+//
+// This is technically a violation of the AlgorithmSigner interface, but it
+// should be unreachable given where we use this. Anyway, at least it returns an
+// error instead of panicing or producing an incorrect signature.
+type algorithmSignerWrapper struct {
+ Signer
+}
+
+func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+ if algorithm != underlyingAlgo(a.PublicKey().Type()) {
+ return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm")
+ }
+ return a.Sign(rand, data)
+}
+
+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
+}
+
+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)
+ r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.hostKey)
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)
if err != nil {
return nil, err
@@ -655,7 +689,7 @@ func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *
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
}