summaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/crypto/ssh/client_auth.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/client_auth.go')
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth.go96
1 files changed, 66 insertions, 30 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go
index 409b5ea1d..5c3bc2572 100644
--- a/vendor/golang.org/x/crypto/ssh/client_auth.go
+++ b/vendor/golang.org/x/crypto/ssh/client_auth.go
@@ -71,7 +71,9 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
if err != nil {
- return err
+ // We return the error later if there is no other method left to
+ // try.
+ ok = authFailure
}
if ok == authSuccess {
// success
@@ -101,6 +103,12 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
}
}
}
+
+ if auth == nil && err != nil {
+ // We have an error and there are no other authentication methods to
+ // try, so we return it.
+ return err
+ }
}
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
}
@@ -217,21 +225,45 @@ func (cb publicKeyCallback) method() string {
return "publickey"
}
-func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as AlgorithmSigner, algo string) {
+func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiAlgorithmSigner, string, error) {
+ var as MultiAlgorithmSigner
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
+ // If the signer implements MultiAlgorithmSigner we use the algorithms it
+ // support, if it implements AlgorithmSigner we assume it supports all
+ // algorithms, otherwise only the key format one.
+ switch s := signer.(type) {
+ case MultiAlgorithmSigner:
+ as = s
+ case AlgorithmSigner:
+ as = &multiAlgorithmSigner{
+ AlgorithmSigner: s,
+ supportedAlgorithms: algorithmsForKeyFormat(underlyingAlgo(keyFormat)),
+ }
+ default:
+ as = &multiAlgorithmSigner{
+ AlgorithmSigner: algorithmSignerWrapper{signer},
+ supportedAlgorithms: []string{underlyingAlgo(keyFormat)},
+ }
+ }
+
+ getFallbackAlgo := func() (string, error) {
+ // Fallback to use if there is no "server-sig-algs" extension or a
+ // common algorithm cannot be found. We use the public key format if the
+ // MultiAlgorithmSigner supports it, otherwise we return an error.
+ if !contains(as.Algorithms(), underlyingAlgo(keyFormat)) {
+ return "", fmt.Errorf("ssh: no common public key signature algorithm, server only supports %q for key type %q, signer only supports %v",
+ underlyingAlgo(keyFormat), keyFormat, as.Algorithms())
+ }
+ return keyFormat, nil
}
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
+ // If there is no "server-sig-algs" extension use the fallback
+ // algorithm.
+ algo, err := getFallbackAlgo()
+ return as, algo, err
}
// The server-sig-algs extension only carries underlying signature
@@ -245,15 +277,22 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as Alg
}
}
- keyAlgos := algorithmsForKeyFormat(keyFormat)
+ // Filter algorithms based on those supported by MultiAlgorithmSigner.
+ var keyAlgos []string
+ for _, algo := range algorithmsForKeyFormat(keyFormat) {
+ if contains(as.Algorithms(), underlyingAlgo(algo)) {
+ keyAlgos = append(keyAlgos, algo)
+ }
+ }
+
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
+ // If there is no overlap, return the fallback algorithm to support
+ // servers that fail to list all supported algorithms.
+ algo, err := getFallbackAlgo()
+ return as, algo, err
}
- return as, algo
+ return as, algo, nil
}
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
@@ -267,10 +306,17 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
return authFailure, nil, err
}
var methods []string
+ var errSigAlgo error
for _, signer := range signers {
pub := signer.PublicKey()
- as, algo := pickSignatureAlgorithm(signer, extensions)
-
+ as, algo, err := pickSignatureAlgorithm(signer, extensions)
+ if err != nil && errSigAlgo == nil {
+ // If we cannot negotiate a signature algorithm store the first
+ // error so we can return it to provide a more meaningful message if
+ // no other signers work.
+ errSigAlgo = err
+ continue
+ }
ok, err := validateKey(pub, algo, user, c)
if err != nil {
return authFailure, nil, err
@@ -317,22 +363,12 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
// contain the "publickey" method, do not attempt to authenticate with any
// other keys. According to RFC 4252 Section 7, the latter can occur when
// additional authentication methods are required.
- if success == authSuccess || !containsMethod(methods, cb.method()) {
+ if success == authSuccess || !contains(methods, cb.method()) {
return success, methods, err
}
}
- return authFailure, methods, nil
-}
-
-func containsMethod(methods []string, method string) bool {
- for _, m := range methods {
- if m == method {
- return true
- }
- }
-
- return false
+ return authFailure, methods, errSigAlgo
}
// validateKey validates the key provided is acceptable to the server.