summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh')
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/client.go55
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/client_test.go42
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/server.go35
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/server_test.go21
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/testdata_test.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/channel.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher.go39
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher_test.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth.go34
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth_test.go81
-rw-r--r--vendor/golang.org/x/crypto/ssh/common.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/connection.go1
-rw-r--r--vendor/golang.org/x/crypto/ssh/handshake.go43
-rw-r--r--vendor/golang.org/x/crypto/ssh/keys.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/server.go1
-rw-r--r--vendor/golang.org/x/crypto/ssh/session.go33
-rw-r--r--vendor/golang.org/x/crypto/ssh/session_test.go8
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util.go9
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/session_test.go10
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/testdata_test.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/testdata_test.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/transport.go9
22 files changed, 368 insertions, 67 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go
index 3f798e719..ecfd7c58d 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/client.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/client.go
@@ -25,6 +25,7 @@ import (
"math/big"
"sync"
+ "golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh"
)
@@ -423,6 +424,14 @@ type ecdsaKeyMsg struct {
Constraints []byte `ssh:"rest"`
}
+type ed25519KeyMsg struct {
+ Type string `sshtype:"17|25"`
+ Pub []byte
+ Priv []byte
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
// Insert adds a private key to the agent.
func (c *client) insertKey(s interface{}, comment string, constraints []byte) error {
var req []byte
@@ -464,6 +473,14 @@ func (c *client) insertKey(s interface{}, comment string, constraints []byte) er
Comments: comment,
Constraints: constraints,
})
+ case *ed25519.PrivateKey:
+ req = ssh.Marshal(ed25519KeyMsg{
+ Type: ssh.KeyAlgoED25519,
+ Pub: []byte(*k)[32:],
+ Priv: []byte(*k),
+ Comments: comment,
+ Constraints: constraints,
+ })
default:
return fmt.Errorf("agent: unsupported key type %T", s)
}
@@ -510,7 +527,16 @@ type ecdsaCertMsg struct {
Constraints []byte `ssh:"rest"`
}
-// Insert adds a private key to the agent. If a certificate is given,
+type ed25519CertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ Pub []byte
+ Priv []byte
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+// Add adds a private key to the agent. If a certificate is given,
// that certificate is added instead as public key.
func (c *client) Add(key AddedKey) error {
var constraints []byte
@@ -554,17 +580,28 @@ func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string
})
case *dsa.PrivateKey:
req = ssh.Marshal(dsaCertMsg{
- Type: cert.Type(),
- CertBytes: cert.Marshal(),
- X: k.X,
- Comments: comment,
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ X: k.X,
+ Comments: comment,
+ Constraints: constraints,
})
case *ecdsa.PrivateKey:
req = ssh.Marshal(ecdsaCertMsg{
- Type: cert.Type(),
- CertBytes: cert.Marshal(),
- D: k.D,
- Comments: comment,
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ D: k.D,
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *ed25519.PrivateKey:
+ req = ssh.Marshal(ed25519CertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ Pub: []byte(*k)[32:],
+ Priv: []byte(*k),
+ Comments: comment,
+ Constraints: constraints,
})
default:
return fmt.Errorf("agent: unsupported key type %T", s)
diff --git a/vendor/golang.org/x/crypto/ssh/agent/client_test.go b/vendor/golang.org/x/crypto/ssh/agent/client_test.go
index ec7198d54..230351fd2 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/client_test.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/client_test.go
@@ -14,6 +14,7 @@ import (
"path/filepath"
"strconv"
"testing"
+ "time"
"golang.org/x/crypto/ssh"
)
@@ -139,7 +140,7 @@ func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Ce
}
func TestAgent(t *testing.T) {
- for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
+ for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
testAgent(t, testPrivateKeys[keyType], nil, 0)
}
}
@@ -285,3 +286,42 @@ func testLockAgent(agent Agent, t *testing.T) {
t.Errorf("Want 1 keys, got %v", keys)
}
}
+
+func TestAgentLifetime(t *testing.T) {
+ agent, _, cleanup := startAgent(t)
+ defer cleanup()
+
+ for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
+ // Add private keys to the agent.
+ err := agent.Add(AddedKey{
+ PrivateKey: testPrivateKeys[keyType],
+ Comment: "comment",
+ LifetimeSecs: 1,
+ })
+ if err != nil {
+ t.Fatalf("add: %v", err)
+ }
+ // Add certs to the agent.
+ cert := &ssh.Certificate{
+ Key: testPublicKeys[keyType],
+ ValidBefore: ssh.CertTimeInfinity,
+ CertType: ssh.UserCert,
+ }
+ cert.SignCert(rand.Reader, testSigners[keyType])
+ err = agent.Add(AddedKey{
+ PrivateKey: testPrivateKeys[keyType],
+ Certificate: cert,
+ Comment: "comment",
+ LifetimeSecs: 1,
+ })
+ if err != nil {
+ t.Fatalf("add: %v", err)
+ }
+ }
+ time.Sleep(1100 * time.Millisecond)
+ if keys, err := agent.List(); err != nil {
+ t.Errorf("List: %v", err)
+ } else if len(keys) != 0 {
+ t.Errorf("Want 0 keys, got %v", len(keys))
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go
index c562fa6e8..68a333fa5 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/server.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/server.go
@@ -16,6 +16,7 @@ import (
"log"
"math/big"
+ "golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh"
)
@@ -175,6 +176,15 @@ func parseRSAKey(req []byte) (*AddedKey, error) {
return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
}
+func parseEd25519Key(req []byte) (*AddedKey, error) {
+ var k ed25519KeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ priv := ed25519.PrivateKey(k.Priv)
+ return &AddedKey{PrivateKey: &priv, Comment: k.Comments}, nil
+}
+
func parseDSAKey(req []byte) (*AddedKey, error) {
var k dsaKeyMsg
if err := ssh.Unmarshal(req, &k); err != nil {
@@ -219,6 +229,23 @@ func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (pri
return priv, nil
}
+func parseEd25519Cert(req []byte) (*AddedKey, error) {
+ var k ed25519CertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+ priv := ed25519.PrivateKey(k.Priv)
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad ED25519 certificate")
+ }
+ return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil
+}
+
func parseECDSAKey(req []byte) (*AddedKey, error) {
var k ecdsaKeyMsg
if err := ssh.Unmarshal(req, &k); err != nil {
@@ -230,7 +257,7 @@ func parseECDSAKey(req []byte) (*AddedKey, error) {
return nil, err
}
- return &AddedKey{PrivateKey: &priv, Comment: k.Comments}, nil
+ return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
}
func parseRSACert(req []byte) (*AddedKey, error) {
@@ -366,13 +393,17 @@ func (s *server) insertIdentity(req []byte) error {
case ssh.KeyAlgoDSA:
addedKey, err = parseDSAKey(req)
case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
- addedKey, err = parseECDSACert(req)
+ addedKey, err = parseECDSAKey(req)
+ case ssh.KeyAlgoED25519:
+ addedKey, err = parseEd25519Key(req)
case ssh.CertAlgoRSAv01:
addedKey, err = parseRSACert(req)
case ssh.CertAlgoDSAv01:
addedKey, err = parseDSACert(req)
case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
addedKey, err = parseECDSACert(req)
+ case ssh.CertAlgoED25519v01:
+ addedKey, err = parseEd25519Cert(req)
default:
return fmt.Errorf("agent: not implemented: %q", record.Type)
}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/server_test.go b/vendor/golang.org/x/crypto/ssh/agent/server_test.go
index c324d6c5a..ec9cdeeb5 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/server_test.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/server_test.go
@@ -150,7 +150,25 @@ func TestKeyTypes(t *testing.T) {
if err := addKeyToAgent(v); err != nil {
t.Errorf("error adding key type %s, %v", k, err)
}
+ if err := addCertToAgentSock(v, nil); err != nil {
+ t.Errorf("error adding key type %s, %v", k, err)
+ }
+ }
+}
+
+func addCertToAgentSock(key crypto.PrivateKey, cert *ssh.Certificate) error {
+ a, b, err := netPipe()
+ if err != nil {
+ return err
+ }
+ agentServer := NewKeyring()
+ go ServeAgent(agentServer, a)
+
+ agentClient := NewClient(b)
+ if err := agentClient.Add(AddedKey{PrivateKey: key, Certificate: cert}); err != nil {
+ return fmt.Errorf("add: %v", err)
}
+ return verifyKey(agentClient)
}
func addCertToAgent(key crypto.PrivateKey, cert *ssh.Certificate) error {
@@ -182,5 +200,8 @@ func TestCertTypes(t *testing.T) {
if err := addCertToAgent(testPrivateKeys[keyType], cert); err != nil {
t.Fatalf("%v", err)
}
+ if err := addCertToAgentSock(testPrivateKeys[keyType], cert); err != nil {
+ t.Fatalf("%v", err)
+ }
}
}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/testdata_test.go b/vendor/golang.org/x/crypto/ssh/agent/testdata_test.go
index b7a8781e1..cc42a87cb 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/testdata_test.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/testdata_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places:
+// IMPLEMENTATION NOTE: To avoid a package loop, this file is in three places:
// ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three
// instances.
diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go
index 6671c98c2..6d709b50b 100644
--- a/vendor/golang.org/x/crypto/ssh/channel.go
+++ b/vendor/golang.org/x/crypto/ssh/channel.go
@@ -67,6 +67,8 @@ type Channel interface {
// boolean, otherwise the return value will be false. Channel
// requests are out-of-band messages so they may be sent even
// if the data stream is closed or blocked by flow control.
+ // If the channel is closed before a reply is returned, io.EOF
+ // is returned.
SendRequest(name string, wantReply bool, payload []byte) (bool, error)
// Stderr returns an io.ReadWriter that writes to this channel
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go
index 2732963f3..34d3917c4 100644
--- a/vendor/golang.org/x/crypto/ssh/cipher.go
+++ b/vendor/golang.org/x/crypto/ssh/cipher.go
@@ -7,6 +7,7 @@ package ssh
import (
"crypto/aes"
"crypto/cipher"
+ "crypto/des"
"crypto/rc4"
"crypto/subtle"
"encoding/binary"
@@ -121,6 +122,9 @@ var cipherModes = map[string]*streamCipherMode{
// You should expect that an active attacker can recover plaintext if
// you do.
aes128cbcID: {16, aes.BlockSize, 0, nil},
+
+ // 3des-cbc is insecure and is disabled by default.
+ tripledescbcID: {24, des.BlockSize, 0, nil},
}
// prefixLen is the length of the packet prefix that contains the packet length
@@ -368,12 +372,7 @@ type cbcCipher struct {
oracleCamouflage uint32
}
-func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
- c, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
-
+func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
cbc := &cbcCipher{
mac: macModes[algs.MAC].new(macKey),
decrypter: cipher.NewCBCDecrypter(c, iv),
@@ -387,6 +386,34 @@ func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCi
return cbc, nil
}
+func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ cbc, err := newCBCCipher(c, iv, key, macKey, algs)
+ if err != nil {
+ return nil, err
+ }
+
+ return cbc, nil
+}
+
+func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+ c, err := des.NewTripleDESCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ cbc, err := newCBCCipher(c, iv, key, macKey, algs)
+ if err != nil {
+ return nil, err
+ }
+
+ return cbc, nil
+}
+
func maxUInt32(a, b int) uint32 {
if a > b {
return uint32(a)
diff --git a/vendor/golang.org/x/crypto/ssh/cipher_test.go b/vendor/golang.org/x/crypto/ssh/cipher_test.go
index 54b92b6ed..eced8d851 100644
--- a/vendor/golang.org/x/crypto/ssh/cipher_test.go
+++ b/vendor/golang.org/x/crypto/ssh/cipher_test.go
@@ -21,7 +21,7 @@ func TestDefaultCiphersExist(t *testing.T) {
}
func TestPacketCiphers(t *testing.T) {
- // Still test aes128cbc cipher althought it's commented out.
+ // Still test aes128cbc cipher although it's commented out.
cipherModes[aes128cbcID] = &streamCipherMode{16, aes.BlockSize, 0, nil}
defer delete(cipherModes, aes128cbcID)
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go
index 6956ce451..294af0d48 100644
--- a/vendor/golang.org/x/crypto/ssh/client_auth.go
+++ b/vendor/golang.org/x/crypto/ssh/client_auth.go
@@ -437,3 +437,37 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
}
}
}
+
+type retryableAuthMethod struct {
+ authMethod AuthMethod
+ maxTries int
+}
+
+func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok bool, methods []string, err error) {
+ for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ {
+ ok, methods, err = r.authMethod.auth(session, user, c, rand)
+ if ok || err != nil { // either success or error terminate
+ return ok, methods, err
+ }
+ }
+ return ok, methods, err
+}
+
+func (r *retryableAuthMethod) method() string {
+ return r.authMethod.method()
+}
+
+// RetryableAuthMethod is a decorator for other auth methods enabling them to
+// be retried up to maxTries before considering that AuthMethod itself failed.
+// If maxTries is <= 0, will retry indefinitely
+//
+// This is useful for interactive clients using challenge/response type
+// authentication (e.g. Keyboard-Interactive, Password, etc) where the user
+// could mistype their response resulting in the server issuing a
+// SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4
+// [keyboard-interactive]); Without this decorator, the non-retryable
+// AuthMethod would be removed from future consideration, and never tried again
+// (and so the user would never be able to retry their entry).
+func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod {
+ return &retryableAuthMethod{authMethod: auth, maxTries: maxTries}
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth_test.go b/vendor/golang.org/x/crypto/ssh/client_auth_test.go
index 2ea44624f..55833e57d 100644
--- a/vendor/golang.org/x/crypto/ssh/client_auth_test.go
+++ b/vendor/golang.org/x/crypto/ssh/client_auth_test.go
@@ -9,6 +9,7 @@ import (
"crypto/rand"
"errors"
"fmt"
+ "os"
"strings"
"testing"
)
@@ -243,6 +244,9 @@ func TestClientUnsupportedCipher(t *testing.T) {
}
func TestClientUnsupportedKex(t *testing.T) {
+ if os.Getenv("GO_BUILDER_NAME") != "" {
+ t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198")
+ }
config := &ClientConfig{
User: "testuser",
Auth: []AuthMethod{
@@ -296,7 +300,7 @@ func TestClientLoginCert(t *testing.T) {
t.Log("sign with wrong key")
cert.SignCert(rand.Reader, testSigners["dsa"])
if err := tryAuth(t, clientConfig); err == nil {
- t.Errorf("cert login passed with non-authoritive key")
+ t.Errorf("cert login passed with non-authoritative key")
}
t.Log("host cert")
@@ -391,3 +395,78 @@ func TestPermissionsPassing(t *testing.T) {
func TestNoPermissionsPassing(t *testing.T) {
testPermissionsPassing(false, t)
}
+
+func TestRetryableAuth(t *testing.T) {
+ n := 0
+ passwords := []string{"WRONG1", "WRONG2"}
+
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ RetryableAuthMethod(PasswordCallback(func() (string, error) {
+ p := passwords[n]
+ n++
+ return p, nil
+ }), 2),
+ PublicKeys(testSigners["rsa"]),
+ },
+ }
+
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+ if n != 2 {
+ t.Fatalf("Did not try all passwords")
+ }
+}
+
+func ExampleRetryableAuthMethod(t *testing.T) {
+ user := "testuser"
+ NumberOfPrompts := 3
+
+ // Normally this would be a callback that prompts the user to answer the
+ // provided questions
+ Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
+ return []string{"answer1", "answer2"}, nil
+ }
+
+ config := &ClientConfig{
+ User: user,
+ Auth: []AuthMethod{
+ RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts),
+ },
+ }
+
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+}
+
+// Test if username is received on server side when NoClientAuth is used
+func TestClientAuthNone(t *testing.T) {
+ user := "testuser"
+ serverConfig := &ServerConfig{
+ NoClientAuth: true,
+ }
+ serverConfig.AddHostKey(testSigners["rsa"])
+
+ clientConfig := &ClientConfig{
+ User: user,
+ }
+
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ go NewClientConn(c2, "", clientConfig)
+ serverConn, err := newServer(c1, serverConfig)
+ if err != nil {
+ t.Fatal("newServer: %v", err)
+ }
+ if serverConn.User() != user {
+ t.Fatalf("server: got %q, want %q", serverConn.User(), user)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
index de029d6db..2c72ab544 100644
--- a/vendor/golang.org/x/crypto/ssh/common.go
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -44,7 +44,7 @@ var supportedKexAlgos = []string{
// of authenticating servers) in preference order.
var supportedHostKeyAlgos = []string{
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
- CertAlgoECDSA384v01, CertAlgoECDSA521v01,
+ CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01,
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
KeyAlgoRSA, KeyAlgoDSA,
diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go
index 979d919e8..e786f2f9a 100644
--- a/vendor/golang.org/x/crypto/ssh/connection.go
+++ b/vendor/golang.org/x/crypto/ssh/connection.go
@@ -23,7 +23,6 @@ func (e *OpenChannelError) Error() string {
// ConnMetadata holds metadata for the connection.
type ConnMetadata interface {
// User returns the user ID for this connection.
- // It is empty if no authentication is used.
User() string
// SessionID returns the sesson hash, also denoted by H.
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
index 86e2755f9..37d42e47f 100644
--- a/vendor/golang.org/x/crypto/ssh/handshake.go
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -174,15 +174,7 @@ func (t *handshakeTransport) readOnePacket() ([]byte, error) {
t.mu.Lock()
- // By default, a key exchange is hidden from higher layers by
- // translating it into msgIgnore.
- successPacket := []byte{msgIgnore}
- if t.sessionID == nil {
- // sendKexInit() for the first kex waits for
- // msgNewKeys so the authentication process is
- // guaranteed to happen over an encrypted transport.
- successPacket = []byte{msgNewKeys}
- }
+ firstKex := t.sessionID == nil
err = t.enterKeyExchangeLocked(p)
if err != nil {
@@ -192,7 +184,7 @@ func (t *handshakeTransport) readOnePacket() ([]byte, error) {
}
if debugHandshake {
- log.Printf("%s exited key exchange, err %v", t.id(), err)
+ log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err)
}
// Unblock writers.
@@ -207,6 +199,17 @@ func (t *handshakeTransport) readOnePacket() ([]byte, error) {
}
t.readSinceKex = 0
+
+ // By default, a key exchange is hidden from higher layers by
+ // translating it into msgIgnore.
+ successPacket := []byte{msgIgnore}
+ if firstKex {
+ // sendKexInit() for the first kex waits for
+ // msgNewKeys so the authentication process is
+ // guaranteed to happen over an encrypted transport.
+ successPacket = []byte{msgNewKeys}
+ }
+
return successPacket, nil
}
@@ -225,16 +228,15 @@ const (
// close the underlying transport. This function is safe for
// concurrent use by multiple goroutines.
func (t *handshakeTransport) sendKexInit(isFirst keyChangeCategory) error {
+ var err error
+
t.mu.Lock()
// If this is the initial key change, but we already have a sessionID,
// then do nothing because the key exchange has already completed
// asynchronously.
- if isFirst && t.sessionID != nil {
- t.mu.Unlock()
- return nil
+ if !isFirst || t.sessionID == nil {
+ _, _, err = t.sendKexInitLocked(isFirst)
}
-
- _, _, err := t.sendKexInitLocked(isFirst)
t.mu.Unlock()
if err != nil {
return err
@@ -369,7 +371,16 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro
}
// We don't send FirstKexFollows, but we handle receiving it.
- if otherInit.FirstKexFollows && algs.kex != otherInit.KexAlgos[0] {
+ //
+ // RFC 4253 section 7 defines the kex and the agreement method for
+ // first_kex_packet_follows. It states that the guessed packet
+ // should be ignored if the "kex algorithm and/or the host
+ // key algorithm is guessed wrong (server and client have
+ // different preferred algorithm), or if any of the other
+ // algorithms cannot be agreed upon". The other algorithms have
+ // already been checked above so the kex algorithm and host key
+ // algorithm are checked here.
+ if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) {
// other side sent a kex message for the wrong algorithm,
// which we have to ignore.
if _, err := t.conn.readPacket(); err != nil {
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index d6167e783..0324e1235 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -125,7 +125,7 @@ func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey
continue
}
- // Strip out the begining of the known_host key.
+ // Strip out the beginning of the known_host key.
// This is either an optional marker or a (set of) hostname(s).
keyFields := bytes.Fields(in)
if len(keyFields) < 3 || len(keyFields) > 5 {
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
index e73a1c1ae..37df1b302 100644
--- a/vendor/golang.org/x/crypto/ssh/server.go
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -284,7 +284,6 @@ userAuthLoop:
switch userAuthReq.Method {
case "none":
if config.NoClientAuth {
- s.user = ""
authErr = nil
}
case "password":
diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go
index 09eb00919..17e2aa85c 100644
--- a/vendor/golang.org/x/crypto/ssh/session.go
+++ b/vendor/golang.org/x/crypto/ssh/session.go
@@ -9,6 +9,7 @@ package ssh
import (
"bytes"
+ "encoding/binary"
"errors"
"fmt"
"io"
@@ -281,9 +282,10 @@ func (s *Session) Start(cmd string) error {
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
-// If the command fails to run or doesn't complete successfully, the
-// error is of type *ExitError. Other error types may be
-// returned for I/O problems.
+// If the remote server does not send an exit status, an error of type
+// *ExitMissingError is returned. If the command completes
+// unsuccessfully or is interrupted by a signal, the error is of type
+// *ExitError. Other error types may be returned for I/O problems.
func (s *Session) Run(cmd string) error {
err := s.Start(cmd)
if err != nil {
@@ -370,9 +372,10 @@ func (s *Session) start() error {
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
-// If the command fails to run or doesn't complete successfully, the
-// error is of type *ExitError. Other error types may be
-// returned for I/O problems.
+// If the remote server does not send an exit status, an error of type
+// *ExitMissingError is returned. If the command completes
+// unsuccessfully or is interrupted by a signal, the error is of type
+// *ExitError. Other error types may be returned for I/O problems.
func (s *Session) Wait() error {
if !s.started {
return errors.New("ssh: session not started")
@@ -400,8 +403,7 @@ func (s *Session) wait(reqs <-chan *Request) error {
for msg := range reqs {
switch msg.Type {
case "exit-status":
- d := msg.Payload
- wm.status = int(d[0])<<24 | int(d[1])<<16 | int(d[2])<<8 | int(d[3])
+ wm.status = int(binary.BigEndian.Uint32(msg.Payload))
case "exit-signal":
var sigval struct {
Signal string
@@ -431,16 +433,29 @@ func (s *Session) wait(reqs <-chan *Request) error {
if wm.status == -1 {
// exit-status was never sent from server
if wm.signal == "" {
- return errors.New("wait: remote command exited without exit status or exit signal")
+ // signal was not sent either. RFC 4254
+ // section 6.10 recommends against this
+ // behavior, but it is allowed, so we let
+ // clients handle it.
+ return &ExitMissingError{}
}
wm.status = 128
if _, ok := signals[Signal(wm.signal)]; ok {
wm.status += signals[Signal(wm.signal)]
}
}
+
return &ExitError{wm}
}
+// ExitMissingError is returned if a session is torn down cleanly, but
+// the server sends no confirmation of the exit status.
+type ExitMissingError struct{}
+
+func (e *ExitMissingError) Error() string {
+ return "wait: remote command exited without exit status or exit signal"
+}
+
func (s *Session) stdin() {
if s.stdinpipe {
return
diff --git a/vendor/golang.org/x/crypto/ssh/session_test.go b/vendor/golang.org/x/crypto/ssh/session_test.go
index f7f0f7642..f35a378f2 100644
--- a/vendor/golang.org/x/crypto/ssh/session_test.go
+++ b/vendor/golang.org/x/crypto/ssh/session_test.go
@@ -297,7 +297,6 @@ func TestUnknownExitSignal(t *testing.T) {
}
}
-// Test WaitMsg is not returned if the channel closes abruptly.
func TestExitWithoutStatusOrSignal(t *testing.T) {
conn := dial(exitWithoutSignalOrStatus, t)
defer conn.Close()
@@ -313,11 +312,8 @@ func TestExitWithoutStatusOrSignal(t *testing.T) {
if err == nil {
t.Fatalf("expected command to fail but it didn't")
}
- _, ok := err.(*ExitError)
- if ok {
- // you can't actually test for errors.errorString
- // because it's not exported.
- t.Fatalf("expected *errorString but got %T", err)
+ if _, ok := err.(*ExitMissingError); !ok {
+ t.Fatalf("got %T want *ExitMissingError", err)
}
}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go
index 598e3df77..c869213ec 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go
@@ -44,8 +44,13 @@ func MakeRaw(fd int) (*State, error) {
}
newState := oldState.termios
- newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
- newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
+ // This attempts to replicate the behaviour documented for cfmakeraw in
+ // the termios(3) manpage.
+ newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
+ newState.Oflag &^= syscall.OPOST
+ newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
+ newState.Cflag &^= syscall.CSIZE | syscall.PARENB
+ newState.Cflag |= syscall.CS8
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return nil, err
}
diff --git a/vendor/golang.org/x/crypto/ssh/test/session_test.go b/vendor/golang.org/x/crypto/ssh/test/session_test.go
index d27ade76b..fc7e4715b 100644
--- a/vendor/golang.org/x/crypto/ssh/test/session_test.go
+++ b/vendor/golang.org/x/crypto/ssh/test/session_test.go
@@ -280,16 +280,16 @@ func TestCiphers(t *testing.T) {
var config ssh.Config
config.SetDefaults()
cipherOrder := config.Ciphers
- // This cipher will not be tested when commented out in cipher.go it will
+ // These ciphers will not be tested when commented out in cipher.go it will
// fallback to the next available as per line 292.
- cipherOrder = append(cipherOrder, "aes128-cbc")
+ cipherOrder = append(cipherOrder, "aes128-cbc", "3des-cbc")
for _, ciph := range cipherOrder {
server := newServer(t)
defer server.Shutdown()
conf := clientConfig()
conf.Ciphers = []string{ciph}
- // Don't fail if sshd doesnt have the cipher.
+ // Don't fail if sshd doesn't have the cipher.
conf.Ciphers = append(conf.Ciphers, cipherOrder...)
conn, err := server.TryDial(conf)
if err == nil {
@@ -310,7 +310,7 @@ func TestMACs(t *testing.T) {
defer server.Shutdown()
conf := clientConfig()
conf.MACs = []string{mac}
- // Don't fail if sshd doesnt have the MAC.
+ // Don't fail if sshd doesn't have the MAC.
conf.MACs = append(conf.MACs, macOrder...)
if conn, err := server.TryDial(conf); err == nil {
conn.Close()
@@ -328,7 +328,7 @@ func TestKeyExchanges(t *testing.T) {
server := newServer(t)
defer server.Shutdown()
conf := clientConfig()
- // Don't fail if sshd doesnt have the kex.
+ // Don't fail if sshd doesn't have the kex.
conf.KeyExchanges = append([]string{kex}, kexOrder...)
conn, err := server.TryDial(conf)
if err == nil {
diff --git a/vendor/golang.org/x/crypto/ssh/test/testdata_test.go b/vendor/golang.org/x/crypto/ssh/test/testdata_test.go
index ae48c7516..a053f67ea 100644
--- a/vendor/golang.org/x/crypto/ssh/test/testdata_test.go
+++ b/vendor/golang.org/x/crypto/ssh/test/testdata_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places:
+// IMPLEMENTATION NOTE: To avoid a package loop, this file is in three places:
// ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three
// instances.
diff --git a/vendor/golang.org/x/crypto/ssh/testdata_test.go b/vendor/golang.org/x/crypto/ssh/testdata_test.go
index f2828c1b5..2da8c79dc 100644
--- a/vendor/golang.org/x/crypto/ssh/testdata_test.go
+++ b/vendor/golang.org/x/crypto/ssh/testdata_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places:
+// IMPLEMENTATION NOTE: To avoid a package loop, this file is in three places:
// ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three
// instances.
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go
index bf7dd61fc..62fba629e 100644
--- a/vendor/golang.org/x/crypto/ssh/transport.go
+++ b/vendor/golang.org/x/crypto/ssh/transport.go
@@ -11,8 +11,9 @@ import (
)
const (
- gcmCipherID = "aes128-gcm@openssh.com"
- aes128cbcID = "aes128-cbc"
+ gcmCipherID = "aes128-gcm@openssh.com"
+ aes128cbcID = "aes128-cbc"
+ tripledescbcID = "3des-cbc"
)
// packetConn represents a transport that implements packet based
@@ -219,6 +220,10 @@ func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (pac
return newAESCBCCipher(iv, key, macKey, algs)
}
+ if algs.Cipher == tripledescbcID {
+ return newTripleDESCBCCipher(iv, key, macKey, algs)
+ }
+
c := &streamPacketCipher{
mac: macModes[algs.MAC].new(macKey),
}