diff --git a/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go
index 34fbc566dc3bc00c58f700a850eea6bcf74786ea..93668945c0d8f6218a8581e773ce8d4f965efffc 100644
--- a/cmd/puppeth/ssh.go
+++ b/cmd/puppeth/ssh.go
@@ -17,6 +17,8 @@
 package main
 
 import (
+	"bufio"
+	"bytes"
 	"errors"
 	"fmt"
 	"io/ioutil"
@@ -37,18 +39,26 @@ import (
 type sshClient struct {
 	server  string // Server name or IP without port number
 	address string // IP address of the remote server
+	pubkey  []byte // RSA public key to authenticate the server
 	client  *ssh.Client
 	logger  log.Logger
 }
 
 // dial establishes an SSH connection to a remote node using the current user and
-// the user's configured private RSA key.
-func dial(server string) (*sshClient, error) {
+// the user's configured private RSA key. If that fails, password authentication
+// is fallen back to. The caller may override the login user via user@server:port.
+func dial(server string, pubkey []byte) (*sshClient, error) {
 	// Figure out a label for the server and a logger
 	label := server
 	if strings.Contains(label, ":") {
 		label = label[:strings.Index(label, ":")]
 	}
+	login := ""
+	if strings.Contains(server, "@") {
+		login = label[:strings.Index(label, "@")]
+		label = label[strings.Index(label, "@")+1:]
+		server = server[strings.Index(server, "@")+1:]
+	}
 	logger := log.New("server", label)
 	logger.Debug("Attempting to establish SSH connection")
 
@@ -56,6 +66,9 @@ func dial(server string) (*sshClient, error) {
 	if err != nil {
 		return nil, err
 	}
+	if login == "" {
+		login = user.Username
+	}
 	// Configure the supported authentication methods (private key and password)
 	var auths []ssh.AuthMethod
 
@@ -71,7 +84,7 @@ func dial(server string) (*sshClient, error) {
 		}
 	}
 	auths = append(auths, ssh.PasswordCallback(func() (string, error) {
-		fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", user.Username, server)
+		fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", login, server)
 		blob, err := terminal.ReadPassword(int(syscall.Stdin))
 
 		fmt.Println()
@@ -86,11 +99,36 @@ func dial(server string) (*sshClient, error) {
 		return nil, errors.New("no IPs associated with domain")
 	}
 	// Try to dial in to the remote server
-	logger.Trace("Dialing remote SSH server", "user", user.Username, "key", path)
+	logger.Trace("Dialing remote SSH server", "user", login)
 	if !strings.Contains(server, ":") {
 		server += ":22"
 	}
-	client, err := ssh.Dial("tcp", server, &ssh.ClientConfig{User: user.Username, Auth: auths})
+	keycheck := func(hostname string, remote net.Addr, key ssh.PublicKey) error {
+		// If no public key is known for SSH, ask the user to confirm
+		if pubkey == nil {
+			fmt.Printf("The authenticity of host '%s (%s)' can't be established.\n", hostname, remote)
+			fmt.Printf("SSH key fingerprint is %s [MD5]\n", ssh.FingerprintLegacyMD5(key))
+			fmt.Printf("Are you sure you want to continue connecting (yes/no)? ")
+
+			text, err := bufio.NewReader(os.Stdin).ReadString('\n')
+			switch {
+			case err != nil:
+				return err
+			case strings.TrimSpace(text) == "yes":
+				pubkey = key.Marshal()
+				return nil
+			default:
+				return fmt.Errorf("unknown auth choice: %v", text)
+			}
+		}
+		// If a public key exists for this SSH server, check that it matches
+		if bytes.Compare(pubkey, key.Marshal()) == 0 {
+			return nil
+		}
+		// We have a mismatch, forbid connecting
+		return errors.New("ssh key mismatch, readd the machine to update")
+	}
+	client, err := ssh.Dial("tcp", server, &ssh.ClientConfig{User: login, Auth: auths, HostKeyCallback: keycheck})
 	if err != nil {
 		return nil, err
 	}
@@ -98,6 +136,7 @@ func dial(server string) (*sshClient, error) {
 	c := &sshClient{
 		server:  label,
 		address: addr[0],
+		pubkey:  pubkey,
 		client:  client,
 		logger:  logger,
 	}
diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go
index 92d7962a04ee33ad35968b877d26d5cd67cf8516..9687d5e0db11b477e18daf5d0922a9b019c2e74d 100644
--- a/cmd/puppeth/wizard.go
+++ b/cmd/puppeth/wizard.go
@@ -44,14 +44,24 @@ type config struct {
 	bootLight []string      // Bootnodes to always connect to by light nodes
 	ethstats  string        // Ethstats settings to cache for node deploys
 
-	Servers []string `json:"servers,omitempty"`
+	Servers map[string][]byte `json:"servers,omitempty"`
+}
+
+// servers retrieves an alphabetically sorted list of servers.
+func (c config) servers() []string {
+	servers := make([]string, 0, len(c.Servers))
+	for server := range c.Servers {
+		servers = append(servers, server)
+	}
+	sort.Strings(servers)
+
+	return servers
 }
 
 // flush dumps the contents of config to disk.
 func (c config) flush() {
 	os.MkdirAll(filepath.Dir(c.path), 0755)
 
-	sort.Strings(c.Servers)
 	out, _ := json.MarshalIndent(c, "", "  ")
 	if err := ioutil.WriteFile(c.path, out, 0644); err != nil {
 		log.Warn("Failed to save puppeth configs", "file", c.path, "err", err)
diff --git a/cmd/puppeth/wizard_intro.go b/cmd/puppeth/wizard_intro.go
index 46383bb549ce3b1e22c838226b7c953d8157b7e1..c3eaf532447c55e1e4e44d30a4b169a8929a2e24 100644
--- a/cmd/puppeth/wizard_intro.go
+++ b/cmd/puppeth/wizard_intro.go
@@ -31,7 +31,10 @@ import (
 // makeWizard creates and returns a new puppeth wizard.
 func makeWizard(network string) *wizard {
 	return &wizard{
-		network:  network,
+		network: network,
+		conf: config{
+			Servers: make(map[string][]byte),
+		},
 		servers:  make(map[string]*sshClient),
 		services: make(map[string][]string),
 		in:       bufio.NewReader(os.Stdin),
@@ -77,9 +80,9 @@ func (w *wizard) run() {
 	} else if err := json.Unmarshal(blob, &w.conf); err != nil {
 		log.Crit("Previous configuration corrupted", "path", w.conf.path, "err", err)
 	} else {
-		for _, server := range w.conf.Servers {
+		for server, pubkey := range w.conf.Servers {
 			log.Info("Dialing previously configured server", "server", server)
-			client, err := dial(server)
+			client, err := dial(server, pubkey)
 			if err != nil {
 				log.Error("Previous server unreachable", "server", server, "err", err)
 			}
diff --git a/cmd/puppeth/wizard_netstats.go b/cmd/puppeth/wizard_netstats.go
index c2a933a557ea7002ff637eeca78817971aceab73..1225abb758cb90c3c5160dc9956785769b778322 100644
--- a/cmd/puppeth/wizard_netstats.go
+++ b/cmd/puppeth/wizard_netstats.go
@@ -41,14 +41,14 @@ func (w *wizard) networkStats(tips bool) {
 	stats.SetHeader([]string{"Server", "IP", "Status", "Service", "Details"})
 	stats.SetColWidth(128)
 
-	for _, server := range w.conf.Servers {
+	for server, pubkey := range w.conf.Servers {
 		client := w.servers[server]
 		logger := log.New("server", server)
 		logger.Info("Starting remote server health-check")
 
 		// If the server is not connected, try to connect again
 		if client == nil {
-			conn, err := dial(server)
+			conn, err := dial(server, pubkey)
 			if err != nil {
 				logger.Error("Failed to establish remote connection", "err", err)
 				stats.Append([]string{server, "", err.Error(), "", ""})
diff --git a/cmd/puppeth/wizard_network.go b/cmd/puppeth/wizard_network.go
index 001d4e5b4d04067c5060b89a5e4d720368fcc7e0..0455e1ef3bc9ac6845f34b65eebc18d9cf74bfe0 100644
--- a/cmd/puppeth/wizard_network.go
+++ b/cmd/puppeth/wizard_network.go
@@ -28,7 +28,9 @@ import (
 func (w *wizard) manageServers() {
 	// List all the servers we can disconnect, along with an entry to connect a new one
 	fmt.Println()
-	for i, server := range w.conf.Servers {
+
+	servers := w.conf.servers()
+	for i, server := range servers {
 		fmt.Printf(" %d. Disconnect %s\n", i+1, server)
 	}
 	fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1)
@@ -40,14 +42,14 @@ func (w *wizard) manageServers() {
 	}
 	// If the user selected an existing server, drop it
 	if choice <= len(w.conf.Servers) {
-		server := w.conf.Servers[choice-1]
+		server := servers[choice-1]
 		client := w.servers[server]
 
 		delete(w.servers, server)
 		if client != nil {
 			client.Close()
 		}
-		w.conf.Servers = append(w.conf.Servers[:choice-1], w.conf.Servers[choice:]...)
+		delete(w.conf.Servers, server)
 		w.conf.flush()
 
 		log.Info("Disconnected existing server", "server", server)
@@ -73,14 +75,14 @@ func (w *wizard) makeServer() string {
 		// Read and fial the server to ensure docker is present
 		input := w.readString()
 
-		client, err := dial(input)
+		client, err := dial(input, nil)
 		if err != nil {
 			log.Error("Server not ready for puppeth", "err", err)
 			return ""
 		}
 		// All checks passed, start tracking the server
 		w.servers[input] = client
-		w.conf.Servers = append(w.conf.Servers, input)
+		w.conf.Servers[input] = client.pubkey
 		w.conf.flush()
 
 		return input
@@ -93,7 +95,9 @@ func (w *wizard) selectServer() string {
 	// List the available server to the user and wait for a choice
 	fmt.Println()
 	fmt.Println("Which server do you want to interact with?")
-	for i, server := range w.conf.Servers {
+
+	servers := w.conf.servers()
+	for i, server := range servers {
 		fmt.Printf(" %d. %s\n", i+1, server)
 	}
 	fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1)
@@ -105,7 +109,7 @@ func (w *wizard) selectServer() string {
 	}
 	// If the user requested connecting to a new server, go for it
 	if choice <= len(w.conf.Servers) {
-		return w.conf.Servers[choice-1]
+		return servers[choice-1]
 	}
 	return w.makeServer()
 }
diff --git a/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s b/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
index 45484d1b596f07092c1db2f3b33bdb13dd95551d..cd793a5b5f2eb00a97e3a9374c03a5f71c879e19 100644
--- a/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
+++ b/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
@@ -2,87 +2,64 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This code was translated into a form compatible with 6a from the public
-// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
-
 // +build amd64,!gccgo,!appengine
 
-// func cswap(inout *[5]uint64, v uint64)
+// func cswap(inout *[4][5]uint64, v uint64)
 TEXT ·cswap(SB),7,$0
 	MOVQ inout+0(FP),DI
 	MOVQ v+8(FP),SI
 
-	CMPQ SI,$1
-	MOVQ 0(DI),SI
-	MOVQ 80(DI),DX
-	MOVQ 8(DI),CX
-	MOVQ 88(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,0(DI)
-	MOVQ DX,80(DI)
-	MOVQ CX,8(DI)
-	MOVQ R8,88(DI)
-	MOVQ 16(DI),SI
-	MOVQ 96(DI),DX
-	MOVQ 24(DI),CX
-	MOVQ 104(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,16(DI)
-	MOVQ DX,96(DI)
-	MOVQ CX,24(DI)
-	MOVQ R8,104(DI)
-	MOVQ 32(DI),SI
-	MOVQ 112(DI),DX
-	MOVQ 40(DI),CX
-	MOVQ 120(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,32(DI)
-	MOVQ DX,112(DI)
-	MOVQ CX,40(DI)
-	MOVQ R8,120(DI)
-	MOVQ 48(DI),SI
-	MOVQ 128(DI),DX
-	MOVQ 56(DI),CX
-	MOVQ 136(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,48(DI)
-	MOVQ DX,128(DI)
-	MOVQ CX,56(DI)
-	MOVQ R8,136(DI)
-	MOVQ 64(DI),SI
-	MOVQ 144(DI),DX
-	MOVQ 72(DI),CX
-	MOVQ 152(DI),R8
-	MOVQ SI,R9
-	CMOVQEQ DX,SI
-	CMOVQEQ R9,DX
-	MOVQ CX,R9
-	CMOVQEQ R8,CX
-	CMOVQEQ R9,R8
-	MOVQ SI,64(DI)
-	MOVQ DX,144(DI)
-	MOVQ CX,72(DI)
-	MOVQ R8,152(DI)
-	MOVQ DI,AX
-	MOVQ SI,DX
+	SUBQ $1, SI
+	NOTQ SI
+	MOVQ SI, X15
+	PSHUFD $0x44, X15, X15
+
+	MOVOU 0(DI), X0
+	MOVOU 16(DI), X2
+	MOVOU 32(DI), X4
+	MOVOU 48(DI), X6
+	MOVOU 64(DI), X8
+	MOVOU 80(DI), X1
+	MOVOU 96(DI), X3
+	MOVOU 112(DI), X5
+	MOVOU 128(DI), X7
+	MOVOU 144(DI), X9
+
+	MOVO X1, X10
+	MOVO X3, X11
+	MOVO X5, X12
+	MOVO X7, X13
+	MOVO X9, X14
+
+	PXOR X0, X10
+	PXOR X2, X11
+	PXOR X4, X12
+	PXOR X6, X13
+	PXOR X8, X14
+	PAND X15, X10
+	PAND X15, X11
+	PAND X15, X12
+	PAND X15, X13
+	PAND X15, X14
+	PXOR X10, X0
+	PXOR X10, X1
+	PXOR X11, X2
+	PXOR X11, X3
+	PXOR X12, X4
+	PXOR X12, X5
+	PXOR X13, X6
+	PXOR X13, X7
+	PXOR X14, X8
+	PXOR X14, X9
+
+	MOVOU X0, 0(DI)
+	MOVOU X2, 16(DI)
+	MOVOU X4, 32(DI)
+	MOVOU X6, 48(DI)
+	MOVOU X8, 64(DI)
+	MOVOU X1, 80(DI)
+	MOVOU X3, 96(DI)
+	MOVOU X5, 112(DI)
+	MOVOU X7, 128(DI)
+	MOVOU X9, 144(DI)
 	RET
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go
index 6918c47fc2eceeaf07a08dc0251efcb2e9af5958..2d14c2a78acfde963ff49901d5b7b037841cedac 100644
--- a/vendor/golang.org/x/crypto/curve25519/curve25519.go
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go
@@ -8,6 +8,10 @@
 
 package curve25519
 
+import (
+	"encoding/binary"
+)
+
 // This code is a port of the public domain, "ref10" implementation of
 // curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
 
@@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
 //
 // Preconditions: b in {0,1}.
 func feCSwap(f, g *fieldElement, b int32) {
-	var x fieldElement
 	b = -b
-	for i := range x {
-		x[i] = b & (f[i] ^ g[i])
-	}
-
 	for i := range f {
-		f[i] ^= x[i]
-	}
-	for i := range g {
-		g[i] ^= x[i]
+		t := b & (f[i] ^ g[i])
+		f[i] ^= t
+		g[i] ^= t
 	}
 }
 
@@ -75,12 +73,7 @@ func load3(in []byte) int64 {
 
 // load4 reads a 32-bit, little-endian value from in.
 func load4(in []byte) int64 {
-	var r int64
-	r = int64(in[0])
-	r |= int64(in[1]) << 8
-	r |= int64(in[2]) << 16
-	r |= int64(in[3]) << 24
-	return r
+	return int64(binary.LittleEndian.Uint32(in))
 }
 
 func feFromBytes(dst *fieldElement, src *[32]byte) {
diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go
index 6331c94d53bc991332064fb0cfbd62075337f6a5..67600e2402377a1af7118e5b3cf5e811a071866d 100644
--- a/vendor/golang.org/x/crypto/ssh/certs.go
+++ b/vendor/golang.org/x/crypto/ssh/certs.go
@@ -268,7 +268,7 @@ type CertChecker struct {
 	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
 	// public key that is not a certificate. It must implement host key
 	// validation or else, if nil, all such keys are rejected.
-	HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error
+	HostKeyFallback HostKeyCallback
 
 	// IsRevoked is called for each certificate so that revocation checking
 	// can be implemented. It should return true if the given certificate
diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go
index c97f2978e8f6c61a771d0e36ddc5ab8f9daf6758..a7e3263bcab29f9e85ab6bb25ac019290fa0053f 100644
--- a/vendor/golang.org/x/crypto/ssh/client.go
+++ b/vendor/golang.org/x/crypto/ssh/client.go
@@ -5,6 +5,7 @@
 package ssh
 
 import (
+	"bytes"
 	"errors"
 	"fmt"
 	"net"
@@ -13,7 +14,7 @@ import (
 )
 
 // Client implements a traditional SSH client that supports shells,
-// subprocesses, port forwarding and tunneled dialing.
+// subprocesses, TCP port/streamlocal forwarding and tunneled dialing.
 type Client struct {
 	Conn
 
@@ -59,6 +60,7 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
 		conn.forwards.closeAll()
 	}()
 	go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
+	go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
 	return conn
 }
 
@@ -68,6 +70,11 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
 func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
 	fullConf := *config
 	fullConf.SetDefaults()
+	if fullConf.HostKeyCallback == nil {
+		c.Close()
+		return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback")
+	}
+
 	conn := &connection{
 		sshConn: sshConn{conn: c},
 	}
@@ -173,6 +180,13 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) {
 	return NewClient(c, chans, reqs), nil
 }
 
+// HostKeyCallback is the function type used for verifying server
+// keys.  A HostKeyCallback must return nil if the host key is OK, or
+// an error to reject it. It receives the hostname as passed to Dial
+// or NewClientConn. The remote address is the RemoteAddr of the
+// net.Conn underlying the the SSH connection.
+type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+
 // A ClientConfig structure is used to configure a Client. It must not be
 // modified after having been passed to an SSH function.
 type ClientConfig struct {
@@ -188,10 +202,12 @@ type ClientConfig struct {
 	// be used during authentication.
 	Auth []AuthMethod
 
-	// HostKeyCallback, if not nil, is called during the cryptographic
-	// handshake to validate the server's host key. A nil HostKeyCallback
-	// implies that all host keys are accepted.
-	HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+	// HostKeyCallback is called during the cryptographic
+	// handshake to validate the server's host key. The client
+	// configuration must supply this callback for the connection
+	// to succeed. The functions InsecureIgnoreHostKey or
+	// FixedHostKey can be used for simplistic host key checks.
+	HostKeyCallback HostKeyCallback
 
 	// ClientVersion contains the version identification string that will
 	// be used for the connection. If empty, a reasonable default is used.
@@ -209,3 +225,33 @@ type ClientConfig struct {
 	// A Timeout of zero means no timeout.
 	Timeout time.Duration
 }
+
+// InsecureIgnoreHostKey returns a function that can be used for
+// ClientConfig.HostKeyCallback to accept any host key. It should
+// not be used for production code.
+func InsecureIgnoreHostKey() HostKeyCallback {
+	return func(hostname string, remote net.Addr, key PublicKey) error {
+		return nil
+	}
+}
+
+type fixedHostKey struct {
+	key PublicKey
+}
+
+func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error {
+	if f.key == nil {
+		return fmt.Errorf("ssh: required host key was nil")
+	}
+	if !bytes.Equal(key.Marshal(), f.key.Marshal()) {
+		return fmt.Errorf("ssh: host key mismatch")
+	}
+	return nil
+}
+
+// FixedHostKey returns a function for use in
+// ClientConfig.HostKeyCallback to accept only a specific host key.
+func FixedHostKey(key PublicKey) HostKeyCallback {
+	hk := &fixedHostKey{key}
+	return hk.check
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go
index fd1ec5dda6e6e06cdb46aee18e750358f1ca80aa..b882da0863a342a16f614e5d011f66bef61db83f 100644
--- a/vendor/golang.org/x/crypto/ssh/client_auth.go
+++ b/vendor/golang.org/x/crypto/ssh/client_auth.go
@@ -179,31 +179,26 @@ func (cb publicKeyCallback) method() string {
 }
 
 func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
-	// Authentication is performed in two stages. The first stage sends an
-	// enquiry to test if each key is acceptable to the remote. The second
-	// stage attempts to authenticate with the valid keys obtained in the
-	// first stage.
+	// 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
+	// attempt to authenticate with the valid key.  If not the client will repeat
+	// the process with the remaining keys.
 
 	signers, err := cb()
 	if err != nil {
 		return false, nil, err
 	}
-	var validKeys []Signer
+	var methods []string
 	for _, signer := range signers {
-		if ok, err := validateKey(signer.PublicKey(), user, c); ok {
-			validKeys = append(validKeys, signer)
-		} else {
-			if err != nil {
-				return false, nil, err
-			}
+		ok, err := validateKey(signer.PublicKey(), user, c)
+		if err != nil {
+			return false, nil, err
+		}
+		if !ok {
+			continue
 		}
-	}
 
-	// methods that may continue if this auth is not successful.
-	var methods []string
-	for _, signer := range validKeys {
 		pub := signer.PublicKey()
-
 		pubKey := pub.Marshal()
 		sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{
 			User:    user,
@@ -236,13 +231,29 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
 		if err != nil {
 			return false, nil, err
 		}
-		if success {
+
+		// If authentication succeeds or the list of available methods does not
+		// 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 || !containsMethod(methods, cb.method()) {
 			return success, methods, err
 		}
 	}
+
 	return false, methods, nil
 }
 
+func containsMethod(methods []string, method string) bool {
+	for _, m := range methods {
+		if m == method {
+			return true
+		}
+	}
+
+	return false
+}
+
 // validateKey validates the key provided is acceptable to the server.
 func validateKey(key PublicKey, user string, c packetConn) (bool, error) {
 	pubKey := key.Marshal()
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
index 8656d0f85d2cb9c2428a8a2306220ba55f9a6625..dc39e4d2318294d8ac3db54f9a67f49207209224 100644
--- a/vendor/golang.org/x/crypto/ssh/common.go
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -9,6 +9,7 @@ import (
 	"crypto/rand"
 	"fmt"
 	"io"
+	"math"
 	"sync"
 
 	_ "crypto/sha1"
@@ -40,7 +41,7 @@ var supportedKexAlgos = []string{
 	kexAlgoDH14SHA1, kexAlgoDH1SHA1,
 }
 
-// supportedKexAlgos 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.
 var supportedHostKeyAlgos = []string{
 	CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
@@ -186,7 +187,7 @@ type Config struct {
 
 	// The maximum number of bytes sent or received after which a
 	// new key is negotiated. It must be at least 256. If
-	// unspecified, 1 gigabyte is used.
+	// unspecified, a size suitable for the chosen cipher is used.
 	RekeyThreshold uint64
 
 	// The allowed key exchanges algorithms. If unspecified then a
@@ -230,11 +231,12 @@ func (c *Config) SetDefaults() {
 	}
 
 	if c.RekeyThreshold == 0 {
-		// RFC 4253, section 9 suggests rekeying after 1G.
-		c.RekeyThreshold = 1 << 30
-	}
-	if c.RekeyThreshold < minRekeyThreshold {
+		// cipher specific default
+	} else if c.RekeyThreshold < minRekeyThreshold {
 		c.RekeyThreshold = minRekeyThreshold
+	} else if c.RekeyThreshold >= math.MaxInt64 {
+		// Avoid weirdness if somebody uses -1 as a threshold.
+		c.RekeyThreshold = math.MaxInt64
 	}
 }
 
diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go
index d6be8946629210740906a38f1f00fd9bff358122..67b7322c058058f4f794aab619d49b68b7289bd6 100644
--- a/vendor/golang.org/x/crypto/ssh/doc.go
+++ b/vendor/golang.org/x/crypto/ssh/doc.go
@@ -14,5 +14,8 @@ others.
 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
+
+This package does not fall under the stability promise of the Go language itself,
+so its API may be changed when pressing needs arise.
 */
 package ssh // import "golang.org/x/crypto/ssh"
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
index 8de650644a5ba818ae13fad5a01d6a62fe093e5d..932ce8393ea899758d6519e31fe3f30ca64d5e74 100644
--- a/vendor/golang.org/x/crypto/ssh/handshake.go
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -74,7 +74,7 @@ type handshakeTransport struct {
 	startKex chan *pendingKex
 
 	// data for host key checking
-	hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+	hostKeyCallback HostKeyCallback
 	dialAddress     string
 	remoteAddr      net.Addr
 
@@ -107,6 +107,8 @@ func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion,
 
 		config: config,
 	}
+	t.resetReadThresholds()
+	t.resetWriteThresholds()
 
 	// We always start with a mandatory key exchange.
 	t.requestKex <- struct{}{}
@@ -237,6 +239,17 @@ func (t *handshakeTransport) requestKeyExchange() {
 	}
 }
 
+func (t *handshakeTransport) resetWriteThresholds() {
+	t.writePacketsLeft = packetRekeyThreshold
+	if t.config.RekeyThreshold > 0 {
+		t.writeBytesLeft = int64(t.config.RekeyThreshold)
+	} else if t.algorithms != nil {
+		t.writeBytesLeft = t.algorithms.w.rekeyBytes()
+	} else {
+		t.writeBytesLeft = 1 << 30
+	}
+}
+
 func (t *handshakeTransport) kexLoop() {
 
 write:
@@ -285,12 +298,8 @@ write:
 		t.writeError = err
 		t.sentInitPacket = nil
 		t.sentInitMsg = nil
-		t.writePacketsLeft = packetRekeyThreshold
-		if t.config.RekeyThreshold > 0 {
-			t.writeBytesLeft = int64(t.config.RekeyThreshold)
-		} else if t.algorithms != nil {
-			t.writeBytesLeft = t.algorithms.w.rekeyBytes()
-		}
+
+		t.resetWriteThresholds()
 
 		// we have completed the key exchange. Since the
 		// reader is still blocked, it is safe to clear out
@@ -344,6 +353,17 @@ write:
 // key exchange itself.
 const packetRekeyThreshold = (1 << 31)
 
+func (t *handshakeTransport) resetReadThresholds() {
+	t.readPacketsLeft = packetRekeyThreshold
+	if t.config.RekeyThreshold > 0 {
+		t.readBytesLeft = int64(t.config.RekeyThreshold)
+	} else if t.algorithms != nil {
+		t.readBytesLeft = t.algorithms.r.rekeyBytes()
+	} else {
+		t.readBytesLeft = 1 << 30
+	}
+}
+
 func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
 	p, err := t.conn.readPacket()
 	if err != nil {
@@ -391,12 +411,7 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
 		return nil, err
 	}
 
-	t.readPacketsLeft = packetRekeyThreshold
-	if t.config.RekeyThreshold > 0 {
-		t.readBytesLeft = int64(t.config.RekeyThreshold)
-	} else {
-		t.readBytesLeft = t.algorithms.r.rekeyBytes()
-	}
+	t.resetReadThresholds()
 
 	// By default, a key exchange is hidden from higher layers by
 	// translating it into msgIgnore.
@@ -574,7 +589,9 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
 	}
 	result.SessionID = t.sessionID
 
-	t.conn.prepareKeyChange(t.algorithms, result)
+	if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil {
+		return err
+	}
 	if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
 		return err
 	}
@@ -614,11 +631,9 @@ func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *
 		return nil, err
 	}
 
-	if t.hostKeyCallback != nil {
-		err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
-		if err != nil {
-			return nil, err
-		}
+	err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
+	if err != nil {
+		return nil, err
 	}
 
 	return result, nil
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index f38de9898ca2c0258085c6fe301e2ee8aea6bf4e..cf6853232bdfa7082596ccc7c92b5762829b6e7c 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -824,7 +824,7 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
 
 // Implemented based on the documentation at
 // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
-func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
+func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) {
 	magic := append([]byte("openssh-key-v1"), 0)
 	if !bytes.Equal(magic, key[0:len(magic)]) {
 		return nil, errors.New("ssh: invalid openssh private key format")
@@ -844,14 +844,15 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
 		return nil, err
 	}
 
+	if w.KdfName != "none" || w.CipherName != "none" {
+		return nil, errors.New("ssh: cannot decode encrypted private keys")
+	}
+
 	pk1 := struct {
 		Check1  uint32
 		Check2  uint32
 		Keytype string
-		Pub     []byte
-		Priv    []byte
-		Comment string
-		Pad     []byte `ssh:"rest"`
+		Rest    []byte `ssh:"rest"`
 	}{}
 
 	if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil {
@@ -862,24 +863,75 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
 		return nil, errors.New("ssh: checkint mismatch")
 	}
 
-	// we only handle ed25519 keys currently
-	if pk1.Keytype != KeyAlgoED25519 {
-		return nil, errors.New("ssh: unhandled key type")
-	}
+	// we only handle ed25519 and rsa keys currently
+	switch pk1.Keytype {
+	case KeyAlgoRSA:
+		// https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773
+		key := struct {
+			N       *big.Int
+			E       *big.Int
+			D       *big.Int
+			Iqmp    *big.Int
+			P       *big.Int
+			Q       *big.Int
+			Comment string
+			Pad     []byte `ssh:"rest"`
+		}{}
+
+		if err := Unmarshal(pk1.Rest, &key); err != nil {
+			return nil, err
+		}
 
-	for i, b := range pk1.Pad {
-		if int(b) != i+1 {
-			return nil, errors.New("ssh: padding not as expected")
+		for i, b := range key.Pad {
+			if int(b) != i+1 {
+				return nil, errors.New("ssh: padding not as expected")
+			}
 		}
-	}
 
-	if len(pk1.Priv) != ed25519.PrivateKeySize {
-		return nil, errors.New("ssh: private key unexpected length")
-	}
+		pk := &rsa.PrivateKey{
+			PublicKey: rsa.PublicKey{
+				N: key.N,
+				E: int(key.E.Int64()),
+			},
+			D:      key.D,
+			Primes: []*big.Int{key.P, key.Q},
+		}
 
-	pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
-	copy(pk, pk1.Priv)
-	return &pk, nil
+		if err := pk.Validate(); err != nil {
+			return nil, err
+		}
+
+		pk.Precompute()
+
+		return pk, nil
+	case KeyAlgoED25519:
+		key := struct {
+			Pub     []byte
+			Priv    []byte
+			Comment string
+			Pad     []byte `ssh:"rest"`
+		}{}
+
+		if err := Unmarshal(pk1.Rest, &key); err != nil {
+			return nil, err
+		}
+
+		if len(key.Priv) != ed25519.PrivateKeySize {
+			return nil, errors.New("ssh: private key unexpected length")
+		}
+
+		for i, b := range key.Pad {
+			if int(b) != i+1 {
+				return nil, errors.New("ssh: padding not as expected")
+			}
+		}
+
+		pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
+		copy(pk, key.Priv)
+		return &pk, nil
+	default:
+		return nil, errors.New("ssh: unhandled key type")
+	}
 }
 
 // FingerprintLegacyMD5 returns the user presentation of the key's
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
index 77c84d165caa5a7e202989121dab26264f8b5638..8e95acc6ac35cf62c1934be8e58d17f5de1273c6 100644
--- a/vendor/golang.org/x/crypto/ssh/server.go
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -45,6 +45,12 @@ type ServerConfig struct {
 	// authenticating.
 	NoClientAuth bool
 
+	// MaxAuthTries specifies the maximum number of authentication attempts
+	// permitted per connection. If set to a negative number, the number of
+	// attempts are unlimited. If set to zero, the number of attempts are limited
+	// to 6.
+	MaxAuthTries int
+
 	// PasswordCallback, if non-nil, is called when a user
 	// attempts to authenticate using a password.
 	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
@@ -141,6 +147,10 @@ type ServerConn struct {
 // Request and NewChannel channels must be serviced, or the connection
 // will hang.
 func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
+	if config.MaxAuthTries == 0 {
+		config.MaxAuthTries = 6
+	}
+
 	fullConf := *config
 	fullConf.SetDefaults()
 	s := &connection{
@@ -267,8 +277,23 @@ func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, err
 	var cache pubKeyCache
 	var perms *Permissions
 
+	authFailures := 0
+
 userAuthLoop:
 	for {
+		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
+			discMsg := &disconnectMsg{
+				Reason:  2,
+				Message: "too many authentication failures",
+			}
+
+			if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
+				return nil, err
+			}
+
+			return nil, discMsg
+		}
+
 		var userAuthReq userAuthRequestMsg
 		if packet, err := s.transport.readPacket(); err != nil {
 			return nil, err
@@ -289,6 +314,11 @@ userAuthLoop:
 			if config.NoClientAuth {
 				authErr = nil
 			}
+
+			// allow initial attempt of 'none' without penalty
+			if authFailures == 0 {
+				authFailures--
+			}
 		case "password":
 			if config.PasswordCallback == nil {
 				authErr = errors.New("ssh: password auth not configured")
@@ -360,6 +390,7 @@ userAuthLoop:
 			if isQuery {
 				// The client can query if the given public key
 				// would be okay.
+
 				if len(payload) > 0 {
 					return nil, parseError(msgUserAuthRequest)
 				}
@@ -409,6 +440,8 @@ userAuthLoop:
 			break userAuthLoop
 		}
 
+		authFailures++
+
 		var failureMsg userAuthFailureMsg
 		if config.PasswordCallback != nil {
 			failureMsg.Methods = append(failureMsg.Methods, "password")
diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go
new file mode 100644
index 0000000000000000000000000000000000000000..a2dccc64c7efd70c57fff8003fd938169e522bae
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go
@@ -0,0 +1,115 @@
+package ssh
+
+import (
+	"errors"
+	"io"
+	"net"
+)
+
+// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
+// with "direct-streamlocal@openssh.com" string.
+//
+// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
+// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
+type streamLocalChannelOpenDirectMsg struct {
+	socketPath string
+	reserved0  string
+	reserved1  uint32
+}
+
+// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
+// with "forwarded-streamlocal@openssh.com" string.
+type forwardedStreamLocalPayload struct {
+	SocketPath string
+	Reserved0  string
+}
+
+// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
+// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
+type streamLocalChannelForwardMsg struct {
+	socketPath string
+}
+
+// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
+func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
+	m := streamLocalChannelForwardMsg{
+		socketPath,
+	}
+	// send message
+	ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
+	if err != nil {
+		return nil, err
+	}
+	if !ok {
+		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
+	}
+	ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"})
+
+	return &unixListener{socketPath, c, ch}, nil
+}
+
+func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
+	msg := streamLocalChannelOpenDirectMsg{
+		socketPath: socketPath,
+	}
+	ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
+	if err != nil {
+		return nil, err
+	}
+	go DiscardRequests(in)
+	return ch, err
+}
+
+type unixListener struct {
+	socketPath string
+
+	conn *Client
+	in   <-chan forward
+}
+
+// Accept waits for and returns the next connection to the listener.
+func (l *unixListener) Accept() (net.Conn, error) {
+	s, ok := <-l.in
+	if !ok {
+		return nil, io.EOF
+	}
+	ch, incoming, err := s.newCh.Accept()
+	if err != nil {
+		return nil, err
+	}
+	go DiscardRequests(incoming)
+
+	return &chanConn{
+		Channel: ch,
+		laddr: &net.UnixAddr{
+			Name: l.socketPath,
+			Net:  "unix",
+		},
+		raddr: &net.UnixAddr{
+			Name: "@",
+			Net:  "unix",
+		},
+	}, nil
+}
+
+// Close closes the listener.
+func (l *unixListener) Close() error {
+	// this also closes the listener.
+	l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"})
+	m := streamLocalChannelForwardMsg{
+		l.socketPath,
+	}
+	ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
+	if err == nil && !ok {
+		err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
+	}
+	return err
+}
+
+// Addr returns the listener's network address.
+func (l *unixListener) Addr() net.Addr {
+	return &net.UnixAddr{
+		Name: l.socketPath,
+		Net:  "unix",
+	}
+}
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go
index 6151241ff08e3fd4d5b9ad6c66159ba044ced239..acf17175dffb1f504dc64f668e5b2cfe0a6ebb6a 100644
--- a/vendor/golang.org/x/crypto/ssh/tcpip.go
+++ b/vendor/golang.org/x/crypto/ssh/tcpip.go
@@ -20,12 +20,20 @@ import (
 // addr. Incoming connections will be available by calling Accept on
 // the returned net.Listener. The listener must be serviced, or the
 // SSH connection may hang.
+// N must be "tcp", "tcp4", "tcp6", or "unix".
 func (c *Client) Listen(n, addr string) (net.Listener, error) {
-	laddr, err := net.ResolveTCPAddr(n, addr)
-	if err != nil {
-		return nil, err
+	switch n {
+	case "tcp", "tcp4", "tcp6":
+		laddr, err := net.ResolveTCPAddr(n, addr)
+		if err != nil {
+			return nil, err
+		}
+		return c.ListenTCP(laddr)
+	case "unix":
+		return c.ListenUnix(addr)
+	default:
+		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
 	}
-	return c.ListenTCP(laddr)
 }
 
 // Automatic port allocation is broken with OpenSSH before 6.0. See
@@ -116,7 +124,7 @@ func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
 	}
 
 	// Register this forward, using the port number we obtained.
-	ch := c.forwards.add(*laddr)
+	ch := c.forwards.add(laddr)
 
 	return &tcpListener{laddr, c, ch}, nil
 }
@@ -131,7 +139,7 @@ type forwardList struct {
 // forwardEntry represents an established mapping of a laddr on a
 // remote ssh server to a channel connected to a tcpListener.
 type forwardEntry struct {
-	laddr net.TCPAddr
+	laddr net.Addr
 	c     chan forward
 }
 
@@ -139,16 +147,16 @@ type forwardEntry struct {
 // arguments to add/remove/lookup should be address as specified in
 // the original forward-request.
 type forward struct {
-	newCh NewChannel   // the ssh client channel underlying this forward
-	raddr *net.TCPAddr // the raddr of the incoming connection
+	newCh NewChannel // the ssh client channel underlying this forward
+	raddr net.Addr   // the raddr of the incoming connection
 }
 
-func (l *forwardList) add(addr net.TCPAddr) chan forward {
+func (l *forwardList) add(addr net.Addr) chan forward {
 	l.Lock()
 	defer l.Unlock()
 	f := forwardEntry{
-		addr,
-		make(chan forward, 1),
+		laddr: addr,
+		c:     make(chan forward, 1),
 	}
 	l.entries = append(l.entries, f)
 	return f.c
@@ -176,44 +184,69 @@ func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
 
 func (l *forwardList) handleChannels(in <-chan NewChannel) {
 	for ch := range in {
-		var payload forwardedTCPPayload
-		if err := Unmarshal(ch.ExtraData(), &payload); err != nil {
-			ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
-			continue
+		var (
+			laddr net.Addr
+			raddr net.Addr
+			err   error
+		)
+		switch channelType := ch.ChannelType(); channelType {
+		case "forwarded-tcpip":
+			var payload forwardedTCPPayload
+			if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
+				ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
+				continue
+			}
+
+			// RFC 4254 section 7.2 specifies that incoming
+			// addresses should list the address, in string
+			// format. It is implied that this should be an IP
+			// address, as it would be impossible to connect to it
+			// otherwise.
+			laddr, err = parseTCPAddr(payload.Addr, payload.Port)
+			if err != nil {
+				ch.Reject(ConnectionFailed, err.Error())
+				continue
+			}
+			raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort)
+			if err != nil {
+				ch.Reject(ConnectionFailed, err.Error())
+				continue
+			}
+
+		case "forwarded-streamlocal@openssh.com":
+			var payload forwardedStreamLocalPayload
+			if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
+				ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error())
+				continue
+			}
+			laddr = &net.UnixAddr{
+				Name: payload.SocketPath,
+				Net:  "unix",
+			}
+			raddr = &net.UnixAddr{
+				Name: "@",
+				Net:  "unix",
+			}
+		default:
+			panic(fmt.Errorf("ssh: unknown channel type %s", channelType))
 		}
-
-		// RFC 4254 section 7.2 specifies that incoming
-		// addresses should list the address, in string
-		// format. It is implied that this should be an IP
-		// address, as it would be impossible to connect to it
-		// otherwise.
-		laddr, err := parseTCPAddr(payload.Addr, payload.Port)
-		if err != nil {
-			ch.Reject(ConnectionFailed, err.Error())
-			continue
-		}
-		raddr, err := parseTCPAddr(payload.OriginAddr, payload.OriginPort)
-		if err != nil {
-			ch.Reject(ConnectionFailed, err.Error())
-			continue
-		}
-
-		if ok := l.forward(*laddr, *raddr, ch); !ok {
+		if ok := l.forward(laddr, raddr, ch); !ok {
 			// Section 7.2, implementations MUST reject spurious incoming
 			// connections.
 			ch.Reject(Prohibited, "no forward for address")
 			continue
 		}
+
 	}
 }
 
 // remove removes the forward entry, and the channel feeding its
 // listener.
-func (l *forwardList) remove(addr net.TCPAddr) {
+func (l *forwardList) remove(addr net.Addr) {
 	l.Lock()
 	defer l.Unlock()
 	for i, f := range l.entries {
-		if addr.IP.Equal(f.laddr.IP) && addr.Port == f.laddr.Port {
+		if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() {
 			l.entries = append(l.entries[:i], l.entries[i+1:]...)
 			close(f.c)
 			return
@@ -231,12 +264,12 @@ func (l *forwardList) closeAll() {
 	l.entries = nil
 }
 
-func (l *forwardList) forward(laddr, raddr net.TCPAddr, ch NewChannel) bool {
+func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool {
 	l.Lock()
 	defer l.Unlock()
 	for _, f := range l.entries {
-		if laddr.IP.Equal(f.laddr.IP) && laddr.Port == f.laddr.Port {
-			f.c <- forward{ch, &raddr}
+		if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() {
+			f.c <- forward{newCh: ch, raddr: raddr}
 			return true
 		}
 	}
@@ -262,7 +295,7 @@ func (l *tcpListener) Accept() (net.Conn, error) {
 	}
 	go DiscardRequests(incoming)
 
-	return &tcpChanConn{
+	return &chanConn{
 		Channel: ch,
 		laddr:   l.laddr,
 		raddr:   s.raddr,
@@ -277,7 +310,7 @@ func (l *tcpListener) Close() error {
 	}
 
 	// this also closes the listener.
-	l.conn.forwards.remove(*l.laddr)
+	l.conn.forwards.remove(l.laddr)
 	ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m))
 	if err == nil && !ok {
 		err = errors.New("ssh: cancel-tcpip-forward failed")
@@ -293,29 +326,52 @@ func (l *tcpListener) Addr() net.Addr {
 // Dial initiates a connection to the addr from the remote host.
 // The resulting connection has a zero LocalAddr() and RemoteAddr().
 func (c *Client) Dial(n, addr string) (net.Conn, error) {
-	// Parse the address into host and numeric port.
-	host, portString, err := net.SplitHostPort(addr)
-	if err != nil {
-		return nil, err
-	}
-	port, err := strconv.ParseUint(portString, 10, 16)
-	if err != nil {
-		return nil, err
-	}
-	// Use a zero address for local and remote address.
-	zeroAddr := &net.TCPAddr{
-		IP:   net.IPv4zero,
-		Port: 0,
-	}
-	ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port))
-	if err != nil {
-		return nil, err
+	var ch Channel
+	switch n {
+	case "tcp", "tcp4", "tcp6":
+		// Parse the address into host and numeric port.
+		host, portString, err := net.SplitHostPort(addr)
+		if err != nil {
+			return nil, err
+		}
+		port, err := strconv.ParseUint(portString, 10, 16)
+		if err != nil {
+			return nil, err
+		}
+		ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port))
+		if err != nil {
+			return nil, err
+		}
+		// Use a zero address for local and remote address.
+		zeroAddr := &net.TCPAddr{
+			IP:   net.IPv4zero,
+			Port: 0,
+		}
+		return &chanConn{
+			Channel: ch,
+			laddr:   zeroAddr,
+			raddr:   zeroAddr,
+		}, nil
+	case "unix":
+		var err error
+		ch, err = c.dialStreamLocal(addr)
+		if err != nil {
+			return nil, err
+		}
+		return &chanConn{
+			Channel: ch,
+			laddr: &net.UnixAddr{
+				Name: "@",
+				Net:  "unix",
+			},
+			raddr: &net.UnixAddr{
+				Name: addr,
+				Net:  "unix",
+			},
+		}, nil
+	default:
+		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
 	}
-	return &tcpChanConn{
-		Channel: ch,
-		laddr:   zeroAddr,
-		raddr:   zeroAddr,
-	}, nil
 }
 
 // DialTCP connects to the remote address raddr on the network net,
@@ -332,7 +388,7 @@ func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error)
 	if err != nil {
 		return nil, err
 	}
-	return &tcpChanConn{
+	return &chanConn{
 		Channel: ch,
 		laddr:   laddr,
 		raddr:   raddr,
@@ -366,26 +422,26 @@ type tcpChan struct {
 	Channel // the backing channel
 }
 
-// tcpChanConn fulfills the net.Conn interface without
+// chanConn fulfills the net.Conn interface without
 // the tcpChan having to hold laddr or raddr directly.
-type tcpChanConn struct {
+type chanConn struct {
 	Channel
 	laddr, raddr net.Addr
 }
 
 // LocalAddr returns the local network address.
-func (t *tcpChanConn) LocalAddr() net.Addr {
+func (t *chanConn) LocalAddr() net.Addr {
 	return t.laddr
 }
 
 // RemoteAddr returns the remote network address.
-func (t *tcpChanConn) RemoteAddr() net.Addr {
+func (t *chanConn) RemoteAddr() net.Addr {
 	return t.raddr
 }
 
 // SetDeadline sets the read and write deadlines associated
 // with the connection.
-func (t *tcpChanConn) SetDeadline(deadline time.Time) error {
+func (t *chanConn) SetDeadline(deadline time.Time) error {
 	if err := t.SetReadDeadline(deadline); err != nil {
 		return err
 	}
@@ -396,12 +452,14 @@ func (t *tcpChanConn) SetDeadline(deadline time.Time) error {
 // A zero value for t means Read will not time out.
 // After the deadline, the error from Read will implement net.Error
 // with Timeout() == true.
-func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error {
+func (t *chanConn) SetReadDeadline(deadline time.Time) error {
+	// for compatibility with previous version,
+	// the error message contains "tcpChan"
 	return errors.New("ssh: tcpChan: deadline not supported")
 }
 
 // SetWriteDeadline exists to satisfy the net.Conn interface
 // but is not implemented by this type.  It always returns an error.
-func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error {
+func (t *chanConn) SetWriteDeadline(deadline time.Time) error {
 	return errors.New("ssh: tcpChan: deadline not supported")
 }
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
index 07eb5edd779db2dc140dbe5a745fe8e969a787b1..a2e1b57dc1486a0478d4d0b753122da4228ed1aa 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
@@ -14,14 +14,12 @@ import (
 
 // State contains the state of a terminal.
 type State struct {
-	termios syscall.Termios
+	state *unix.Termios
 }
 
 // IsTerminal returns true if the given file descriptor is a terminal.
 func IsTerminal(fd int) bool {
-	// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
-	var termio unix.Termio
-	err := unix.IoctlSetTermio(fd, unix.TCGETA, &termio)
+	_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
 	return err == nil
 }
 
@@ -71,3 +69,60 @@ func ReadPassword(fd int) ([]byte, error) {
 
 	return ret, nil
 }
+
+// MakeRaw puts the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+// see http://cr.illumos.org/~webrev/andy_js/1060/
+func MakeRaw(fd int) (*State, error) {
+	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+	if err != nil {
+		return nil, err
+	}
+	oldTermios := *oldTermiosPtr
+
+	newTermios := oldTermios
+	newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
+	newTermios.Oflag &^= syscall.OPOST
+	newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
+	newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
+	newTermios.Cflag |= syscall.CS8
+	newTermios.Cc[unix.VMIN] = 1
+	newTermios.Cc[unix.VTIME] = 0
+
+	if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
+		return nil, err
+	}
+
+	return &State{
+		state: oldTermiosPtr,
+	}, nil
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func Restore(fd int, oldState *State) error {
+	return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state)
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd int) (*State, error) {
+	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+	if err != nil {
+		return nil, err
+	}
+
+	return &State{
+		state: oldTermiosPtr,
+	}, nil
+}
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
+	if err != nil {
+		return 0, 0, err
+	}
+	return int(ws.Col), int(ws.Row), nil
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index d79c80a67ac328a45bc0643552a7844ba4dcd1a9..607f193a38af371089434e6f721cff42bcbf05c0 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -384,92 +384,92 @@
 		{
 			"checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=",
 			"path": "golang.org/x/crypto/cast5",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
-			"checksumSHA1": "C1KKOxFoW7/W/NFNpiXK+boguNo=",
+			"checksumSHA1": "nAu0XmCeC6WnUySyI8R7w4cxAqU=",
 			"path": "golang.org/x/crypto/curve25519",
-			"revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
-			"revisionTime": "2017-03-17T13:29:17Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "wGb//LjBPNxYHqk+dcLo7BjPXK8=",
 			"path": "golang.org/x/crypto/ed25519",
-			"revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
-			"revisionTime": "2017-03-17T13:29:17Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "LXFcVx8I587SnWmKycSDEq9yvK8=",
 			"path": "golang.org/x/crypto/ed25519/internal/edwards25519",
-			"revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
-			"revisionTime": "2017-03-17T13:29:17Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "IIhFTrLlmlc6lEFSitqi4aw2lw0=",
 			"path": "golang.org/x/crypto/openpgp",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "olOKkhrdkYQHZ0lf1orrFQPQrv4=",
 			"path": "golang.org/x/crypto/openpgp/armor",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "eo/KtdjieJQXH7Qy+faXFcF70ME=",
 			"path": "golang.org/x/crypto/openpgp/elgamal",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "rlxVSaGgqdAgwblsErxTxIfuGfg=",
 			"path": "golang.org/x/crypto/openpgp/errors",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "LWdaR8Q9yn6eBCcnGl0HvJRDUBE=",
 			"path": "golang.org/x/crypto/openpgp/packet",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "s2qT4UwvzBSkzXuiuMkowif1Olw=",
 			"path": "golang.org/x/crypto/openpgp/s2k",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=",
 			"path": "golang.org/x/crypto/pbkdf2",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "y/oIaxq2d3WPizRZfVjo8RCRYTU=",
 			"path": "golang.org/x/crypto/ripemd160",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "E8pDMGySfy5Mw+jzXOkOxo35bww=",
 			"path": "golang.org/x/crypto/scrypt",
-			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
-			"revisionTime": "2017-02-08T20:51:15Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
-			"checksumSHA1": "fsrFs762jlaILyqqQImS1GfvIvw=",
+			"checksumSHA1": "8sVsMTphul+B0sI0qAv4TE1ZxUk=",
 			"path": "golang.org/x/crypto/ssh",
-			"revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
-			"revisionTime": "2017-03-17T13:29:17Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
-			"checksumSHA1": "xiderUuvye8Kpn7yX3niiJg32bE=",
+			"checksumSHA1": "ZaU56svwLgiJD0y8JOB3+/mpYBA=",
 			"path": "golang.org/x/crypto/ssh/terminal",
-			"revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
-			"revisionTime": "2017-03-17T13:29:17Z"
+			"revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+			"revisionTime": "2017-04-25T18:31:00Z"
 		},
 		{
 			"checksumSHA1": "Y+HGqEkYM15ir+J93MEaHdyFy0c=",