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_test.go24
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/keyring.go53
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/keyring_test.go4
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth_test.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/example_test.go75
-rw-r--r--vendor/golang.org/x/crypto/ssh/kex.go30
-rw-r--r--vendor/golang.org/x/crypto/ssh/keys.go38
-rw-r--r--vendor/golang.org/x/crypto/ssh/keys_test.go36
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go73
-rw-r--r--vendor/golang.org/x/crypto/ssh/testdata/keys.go63
10 files changed, 331 insertions, 67 deletions
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 230351fd2..e33d47138 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/client_test.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/client_test.go
@@ -86,6 +86,11 @@ func testAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSec
testAgentInterface(t, agent, key, cert, lifetimeSecs)
}
+func testKeyring(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
+ a := NewKeyring()
+ testAgentInterface(t, a, key, cert, lifetimeSecs)
+}
+
func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
signer, err := ssh.NewSignerFromKey(key)
if err != nil {
@@ -137,11 +142,25 @@ func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Ce
if err := pubKey.Verify(data, sig); err != nil {
t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
}
+
+ // If the key has a lifetime, is it removed when it should be?
+ if lifetimeSecs > 0 {
+ time.Sleep(time.Second*time.Duration(lifetimeSecs) + 100*time.Millisecond)
+ keys, err := agent.List()
+ if err != nil {
+ t.Fatalf("List: %v", err)
+ }
+ if len(keys) > 0 {
+ t.Fatalf("key not expired")
+ }
+ }
+
}
func TestAgent(t *testing.T) {
for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
testAgent(t, testPrivateKeys[keyType], nil, 0)
+ testKeyring(t, testPrivateKeys[keyType], nil, 1)
}
}
@@ -154,10 +173,7 @@ func TestCert(t *testing.T) {
cert.SignCert(rand.Reader, testSigners["ecdsa"])
testAgent(t, testPrivateKeys["rsa"], cert, 0)
-}
-
-func TestConstraints(t *testing.T) {
- testAgent(t, testPrivateKeys["rsa"], nil, 3600 /* lifetime in seconds */)
+ testKeyring(t, testPrivateKeys["rsa"], cert, 1)
}
// netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
index 12ffa82b1..a6ba06ab3 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/keyring.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"sync"
+ "time"
"golang.org/x/crypto/ssh"
)
@@ -18,6 +19,7 @@ import (
type privKey struct {
signer ssh.Signer
comment string
+ expire *time.Time
}
type keyring struct {
@@ -48,15 +50,9 @@ func (r *keyring) RemoveAll() error {
return nil
}
-// Remove removes all identities with the given public key.
-func (r *keyring) Remove(key ssh.PublicKey) error {
- r.mu.Lock()
- defer r.mu.Unlock()
- if r.locked {
- return errLocked
- }
-
- want := key.Marshal()
+// removeLocked does the actual key removal. The caller must already be holding the
+// keyring mutex.
+func (r *keyring) removeLocked(want []byte) error {
found := false
for i := 0; i < len(r.keys); {
if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) {
@@ -75,7 +71,18 @@ func (r *keyring) Remove(key ssh.PublicKey) error {
return nil
}
-// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
+// Remove removes all identities with the given public key.
+func (r *keyring) Remove(key ssh.PublicKey) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+
+ return r.removeLocked(key.Marshal())
+}
+
+// Lock locks the agent. Sign and Remove will fail, and List will return an empty list.
func (r *keyring) Lock(passphrase []byte) error {
r.mu.Lock()
defer r.mu.Unlock()
@@ -104,6 +111,17 @@ func (r *keyring) Unlock(passphrase []byte) error {
return nil
}
+// expireKeysLocked removes expired keys from the keyring. If a key was added
+// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have
+// ellapsed, it is removed. The caller *must* be holding the keyring mutex.
+func (r *keyring) expireKeysLocked() {
+ for _, k := range r.keys {
+ if k.expire != nil && time.Now().After(*k.expire) {
+ r.removeLocked(k.signer.PublicKey().Marshal())
+ }
+ }
+}
+
// List returns the identities known to the agent.
func (r *keyring) List() ([]*Key, error) {
r.mu.Lock()
@@ -113,6 +131,7 @@ func (r *keyring) List() ([]*Key, error) {
return nil, nil
}
+ r.expireKeysLocked()
var ids []*Key
for _, k := range r.keys {
pub := k.signer.PublicKey()
@@ -146,7 +165,17 @@ func (r *keyring) Add(key AddedKey) error {
}
}
- r.keys = append(r.keys, privKey{signer, key.Comment})
+ p := privKey{
+ signer: signer,
+ comment: key.Comment,
+ }
+
+ if key.LifetimeSecs > 0 {
+ t := time.Now().Add(time.Duration(key.LifetimeSecs) * time.Second)
+ p.expire = &t
+ }
+
+ r.keys = append(r.keys, p)
return nil
}
@@ -159,6 +188,7 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
return nil, errLocked
}
+ r.expireKeysLocked()
wanted := key.Marshal()
for _, k := range r.keys {
if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) {
@@ -176,6 +206,7 @@ func (r *keyring) Signers() ([]ssh.Signer, error) {
return nil, errLocked
}
+ r.expireKeysLocked()
s := make([]ssh.Signer, 0, len(r.keys))
for _, k := range r.keys {
s = append(s, k.signer)
diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring_test.go b/vendor/golang.org/x/crypto/ssh/agent/keyring_test.go
index 7f0590571..e5d50e7e0 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/keyring_test.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/keyring_test.go
@@ -4,9 +4,7 @@
package agent
-import (
- "testing"
-)
+import "testing"
func addTestKey(t *testing.T, a Agent, keyName string) {
err := a.Add(AddedKey{
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 55833e57d..1409276ec 100644
--- a/vendor/golang.org/x/crypto/ssh/client_auth_test.go
+++ b/vendor/golang.org/x/crypto/ssh/client_auth_test.go
@@ -464,7 +464,7 @@ func TestClientAuthNone(t *testing.T) {
go NewClientConn(c2, "", clientConfig)
serverConn, err := newServer(c1, serverConfig)
if err != nil {
- t.Fatal("newServer: %v", err)
+ t.Fatalf("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/example_test.go b/vendor/golang.org/x/crypto/ssh/example_test.go
index 25f995146..4d2eabd0f 100644
--- a/vendor/golang.org/x/crypto/ssh/example_test.go
+++ b/vendor/golang.org/x/crypto/ssh/example_test.go
@@ -17,9 +17,29 @@ import (
)
func ExampleNewServerConn() {
+ // Public key authentication is done by comparing
+ // the public key of a received connection
+ // with the entries in the authorized_keys file.
+ authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
+ if err != nil {
+ log.Fatalf("Failed to load authorized_keys, err: %v", err)
+ }
+
+ authorizedKeysMap := map[string]bool{}
+ for len(authorizedKeysBytes) > 0 {
+ pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ authorizedKeysMap[string(pubKey.Marshal())] = true
+ authorizedKeysBytes = rest
+ }
+
// An SSH server is represented by a ServerConfig, which holds
// certificate details and handles authentication of ServerConns.
config := &ssh.ServerConfig{
+ // Remove to disable password auth.
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
// Should use constant-time compare (or better, salt+hash) in
// a production setting.
@@ -28,16 +48,24 @@ func ExampleNewServerConn() {
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
+
+ // Remove to disable public key auth.
+ PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
+ if authorizedKeysMap[string(pubKey.Marshal())] {
+ return nil, nil
+ }
+ return nil, fmt.Errorf("unknown public key for %q", c.User())
+ },
}
privateBytes, err := ioutil.ReadFile("id_rsa")
if err != nil {
- panic("Failed to load private key")
+ log.Fatal("Failed to load private key: ", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
- panic("Failed to parse private key")
+ log.Fatal("Failed to parse private key: ", err)
}
config.AddHostKey(private)
@@ -46,23 +74,25 @@ func ExampleNewServerConn() {
// accepted.
listener, err := net.Listen("tcp", "0.0.0.0:2022")
if err != nil {
- panic("failed to listen for connection")
+ log.Fatal("failed to listen for connection: ", err)
}
nConn, err := listener.Accept()
if err != nil {
- panic("failed to accept incoming connection")
+ log.Fatal("failed to accept incoming connection: ", err)
}
// Before use, a handshake must be performed on the incoming
// net.Conn.
_, chans, reqs, err := ssh.NewServerConn(nConn, config)
if err != nil {
- panic("failed to handshake")
+ log.Fatal("failed to handshake: ", err)
}
// The incoming Request channel must be serviced.
go ssh.DiscardRequests(reqs)
// Service the incoming Channel channel.
+
+ // Service the incoming Channel channel.
for newChannel := range chans {
// Channels have a type, depending on the application level
// protocol intended. In the case of a shell, the type is
@@ -74,7 +104,7 @@ func ExampleNewServerConn() {
}
channel, requests, err := newChannel.Accept()
if err != nil {
- panic("could not accept channel.")
+ log.Fatalf("Could not accept channel: %v", err)
}
// Sessions have out-of-band requests such as "shell",
@@ -82,18 +112,7 @@ func ExampleNewServerConn() {
// "shell" request.
go func(in <-chan *ssh.Request) {
for req := range in {
- ok := false
- switch req.Type {
- case "shell":
- ok = true
- if len(req.Payload) > 0 {
- // We don't accept any
- // commands, only the
- // default shell.
- ok = false
- }
- }
- req.Reply(ok, nil)
+ req.Reply(req.Type == "shell", nil)
}
}(requests)
@@ -125,14 +144,14 @@ func ExampleDial() {
}
client, err := ssh.Dial("tcp", "yourserver.com:22", config)
if err != nil {
- panic("Failed to dial: " + err.Error())
+ log.Fatal("Failed to dial: ", err)
}
// Each ClientConn can support multiple interactive sessions,
// represented by a Session.
session, err := client.NewSession()
if err != nil {
- panic("Failed to create session: " + err.Error())
+ log.Fatal("Failed to create session: ", err)
}
defer session.Close()
@@ -141,7 +160,7 @@ func ExampleDial() {
var b bytes.Buffer
session.Stdout = &b
if err := session.Run("/usr/bin/whoami"); err != nil {
- panic("Failed to run: " + err.Error())
+ log.Fatal("Failed to run: " + err.Error())
}
fmt.Println(b.String())
}
@@ -189,14 +208,14 @@ func ExampleClient_Listen() {
// Dial your ssh server.
conn, err := ssh.Dial("tcp", "localhost:22", config)
if err != nil {
- log.Fatalf("unable to connect: %s", err)
+ log.Fatal("unable to connect: ", err)
}
defer conn.Close()
// Request the remote side to open port 8080 on all interfaces.
l, err := conn.Listen("tcp", "0.0.0.0:8080")
if err != nil {
- log.Fatalf("unable to register tcp forward: %v", err)
+ log.Fatal("unable to register tcp forward: ", err)
}
defer l.Close()
@@ -217,13 +236,13 @@ func ExampleSession_RequestPty() {
// Connect to ssh server
conn, err := ssh.Dial("tcp", "localhost:22", config)
if err != nil {
- log.Fatalf("unable to connect: %s", err)
+ log.Fatal("unable to connect: ", err)
}
defer conn.Close()
// Create a session
session, err := conn.NewSession()
if err != nil {
- log.Fatalf("unable to create session: %s", err)
+ log.Fatal("unable to create session: ", err)
}
defer session.Close()
// Set up terminal modes
@@ -233,11 +252,11 @@ func ExampleSession_RequestPty() {
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
- if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
- log.Fatalf("request for pseudo terminal failed: %s", err)
+ if err := session.RequestPty("xterm", 40, 80, modes); err != nil {
+ log.Fatal("request for pseudo terminal failed: ", err)
}
// Start remote shell
if err := session.Shell(); err != nil {
- log.Fatalf("failed to start shell: %s", err)
+ log.Fatal("failed to start shell: ", err)
}
}
diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go
index 9285ee31d..c87fbebfd 100644
--- a/vendor/golang.org/x/crypto/ssh/kex.go
+++ b/vendor/golang.org/x/crypto/ssh/kex.go
@@ -77,11 +77,11 @@ type kexAlgorithm interface {
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
type dhGroup struct {
- g, p *big.Int
+ g, p, pMinus1 *big.Int
}
func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
- if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
+ if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 {
return nil, errors.New("ssh: DH parameter out of bounds")
}
return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
@@ -90,10 +90,17 @@ func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int,
func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
hashFunc := crypto.SHA1
- x, err := rand.Int(randSource, group.p)
- if err != nil {
- return nil, err
+ var x *big.Int
+ for {
+ var err error
+ if x, err = rand.Int(randSource, group.pMinus1); err != nil {
+ return nil, err
+ }
+ if x.Sign() > 0 {
+ break
+ }
}
+
X := new(big.Int).Exp(group.g, x, group.p)
kexDHInit := kexDHInitMsg{
X: X,
@@ -146,9 +153,14 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha
return
}
- y, err := rand.Int(randSource, group.p)
- if err != nil {
- return
+ var y *big.Int
+ for {
+ if y, err = rand.Int(randSource, group.pMinus1); err != nil {
+ return
+ }
+ if y.Sign() > 0 {
+ break
+ }
}
Y := new(big.Int).Exp(group.g, y, group.p)
@@ -373,6 +385,7 @@ func init() {
kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
+ pMinus1: new(big.Int).Sub(p, bigOne),
}
// This is the group called diffie-hellman-group14-sha1 in RFC
@@ -382,6 +395,7 @@ func init() {
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
+ pMinus1: new(big.Int).Sub(p, bigOne),
}
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index 0324e1235..f2fc9b6c9 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -281,6 +281,12 @@ type PublicKey interface {
Verify(data []byte, sig *Signature) error
}
+// CryptoPublicKey, if implemented by a PublicKey,
+// returns the underlying crypto.PublicKey form of the key.
+type CryptoPublicKey interface {
+ CryptoPublicKey() crypto.PublicKey
+}
+
// A Signer can create signatures that verify against a public key.
type Signer interface {
// PublicKey returns an associated PublicKey instance.
@@ -348,6 +354,10 @@ func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob)
}
+func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
+ return (*rsa.PublicKey)(r)
+}
+
type dsaPublicKey dsa.PublicKey
func (r *dsaPublicKey) Type() string {
@@ -416,6 +426,10 @@ func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
return errors.New("ssh: signature did not verify")
}
+func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey {
+ return (*dsa.PublicKey)(k)
+}
+
type dsaPrivateKey struct {
*dsa.PrivateKey
}
@@ -509,6 +523,10 @@ func (key ed25519PublicKey) Verify(b []byte, sig *Signature) error {
return nil
}
+func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey {
+ return ed25519.PublicKey(k)
+}
+
func supportedEllipticCurve(curve elliptic.Curve) bool {
return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
}
@@ -604,6 +622,10 @@ func (key *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
return errors.New("ssh: signature did not verify")
}
+func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey {
+ return (*ecdsa.PublicKey)(k)
+}
+
// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
// *ecdsa.PrivateKey or any other crypto.Signer and returns a corresponding
// Signer instance. ECDSA keys must use P-256, P-384 or P-521.
@@ -700,8 +722,8 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
}
// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey,
-// ed25519.PublicKey, or any other crypto.Signer and returns a corresponding
-// Signer instance. ECDSA keys must use P-256, P-384 or P-521.
+// or ed25519.PublicKey returns a corresponding PublicKey instance.
+// ECDSA keys must use P-256, P-384 or P-521.
func NewPublicKey(key interface{}) (PublicKey, error) {
switch key := key.(type) {
case *rsa.PublicKey:
@@ -731,6 +753,14 @@ func ParsePrivateKey(pemBytes []byte) (Signer, error) {
return NewSignerFromKey(key)
}
+// encryptedBlock tells whether a private key is
+// encrypted by examining its Proc-Type header
+// for a mention of ENCRYPTED
+// according to RFC 1421 Section 4.6.1.1.
+func encryptedBlock(block *pem.Block) bool {
+ return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED")
+}
+
// ParseRawPrivateKey returns a private key from a PEM encoded private key. It
// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys.
func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
@@ -739,6 +769,10 @@ func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
return nil, errors.New("ssh: no key found")
}
+ if encryptedBlock(block) {
+ return nil, errors.New("ssh: cannot decode encrypted private keys")
+ }
+
switch block.Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(block.Bytes)
diff --git a/vendor/golang.org/x/crypto/ssh/keys_test.go b/vendor/golang.org/x/crypto/ssh/keys_test.go
index 4c4c5bef6..0739c6627 100644
--- a/vendor/golang.org/x/crypto/ssh/keys_test.go
+++ b/vendor/golang.org/x/crypto/ssh/keys_test.go
@@ -132,6 +132,22 @@ func TestParseECPrivateKey(t *testing.T) {
}
}
+// See Issue https://github.com/golang/go/issues/6650.
+func TestParseEncryptedPrivateKeysFails(t *testing.T) {
+ const wantSubstring = "encrypted"
+ for i, tt := range testdata.PEMEncryptedKeys {
+ _, err := ParsePrivateKey(tt.PEMBytes)
+ if err == nil {
+ t.Errorf("#%d key %s: ParsePrivateKey successfully parsed, expected an error", i, tt.Name)
+ continue
+ }
+
+ if !strings.Contains(err.Error(), wantSubstring) {
+ t.Errorf("#%d key %s: got error %q, want substring %q", i, tt.Name, err, wantSubstring)
+ }
+ }
+}
+
func TestParseDSA(t *testing.T) {
// We actually exercise the ParsePrivateKey codepath here, as opposed to
// using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
@@ -309,14 +325,14 @@ func TestInvalidEntry(t *testing.T) {
}
var knownHostsParseTests = []struct {
- input string
- err string
-
- marker string
- comment string
- hosts []string
- rest string
-} {
+ input string
+ err string
+
+ marker string
+ comment string
+ hosts []string
+ rest string
+}{
{
"",
"EOF",
@@ -375,13 +391,13 @@ var knownHostsParseTests = []struct {
"localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment",
"",
- "", "comment comment", []string{"localhost","[host2:123]"}, "",
+ "", "comment comment", []string{"localhost", "[host2:123]"}, "",
},
{
"@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}",
"",
- "marker", "", []string{"localhost","[host2:123]"}, "",
+ "marker", "", []string{"localhost", "[host2:123]"}, "",
},
{
"@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
new file mode 100644
index 000000000..07eb5edd7
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
@@ -0,0 +1,73 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package terminal // import "golang.org/x/crypto/ssh/terminal"
+
+import (
+ "golang.org/x/sys/unix"
+ "io"
+ "syscall"
+)
+
+// State contains the state of a terminal.
+type State struct {
+ termios syscall.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)
+ return err == nil
+}
+
+// ReadPassword reads a line of input from a terminal without local echo. This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd int) ([]byte, error) {
+ // see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
+ val, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+ if err != nil {
+ return nil, err
+ }
+ oldState := *val
+
+ newState := oldState
+ newState.Lflag &^= syscall.ECHO
+ newState.Lflag |= syscall.ICANON | syscall.ISIG
+ newState.Iflag |= syscall.ICRNL
+ err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState)
+ if err != nil {
+ return nil, err
+ }
+
+ defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState)
+
+ var buf [16]byte
+ var ret []byte
+ for {
+ n, err := syscall.Read(fd, buf[:])
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ if len(ret) == 0 {
+ return nil, io.EOF
+ }
+ break
+ }
+ if buf[n-1] == '\n' {
+ n--
+ }
+ ret = append(ret, buf[:n]...)
+ if n < len(buf) {
+ break
+ }
+ }
+
+ return ret, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/testdata/keys.go b/vendor/golang.org/x/crypto/ssh/testdata/keys.go
index 9b76905f2..736dad951 100644
--- a/vendor/golang.org/x/crypto/ssh/testdata/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/testdata/keys.go
@@ -55,3 +55,66 @@ PLL8IEwvYu2wq+lpXfGQnNMbzYf9gspG0w==
-----END EC PRIVATE KEY-----
`),
}
+
+var PEMEncryptedKeys = []struct {
+ Name string
+ EncryptionKey string
+ PEMBytes []byte
+}{
+ 0: {
+ Name: "rsa-encrypted",
+ EncryptionKey: "r54-G0pher_t3st$",
+ PEMBytes: []byte(`-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,3E1714DE130BC5E81327F36564B05462
+
+MqW88sud4fnWk/Jk3fkjh7ydu51ZkHLN5qlQgA4SkAXORPPMj2XvqZOv1v2LOgUV
+dUevUn8PZK7a9zbZg4QShUSzwE5k6wdB7XKPyBgI39mJ79GBd2U4W3h6KT6jIdWA
+goQpluxkrzr2/X602IaxLEre97FT9mpKC6zxKCLvyFWVIP9n3OSFS47cTTXyFr+l
+7PdRhe60nn6jSBgUNk/Q1lAvEQ9fufdPwDYY93F1wyJ6lOr0F1+mzRrMbH67NyKs
+rG8J1Fa7cIIre7ueKIAXTIne7OAWqpU9UDgQatDtZTbvA7ciqGsSFgiwwW13N+Rr
+hN8MkODKs9cjtONxSKi05s206A3NDU6STtZ3KuPDjFE1gMJODotOuqSM+cxKfyFq
+wxpk/CHYCDdMAVBSwxb/vraOHamylL4uCHpJdBHypzf2HABt+lS8Su23uAmL87DR
+yvyCS/lmpuNTndef6qHPRkoW2EV3xqD3ovosGf7kgwGJUk2ZpCLVteqmYehKlZDK
+r/Jy+J26ooI2jIg9bjvD1PZq+Mv+2dQ1RlDrPG3PB+rEixw6vBaL9x3jatCd4ej7
+XG7lb3qO9xFpLsx89tkEcvpGR+broSpUJ6Mu5LBCVmrvqHjvnDhrZVz1brMiQtU9
+iMZbgXqDLXHd6ERWygk7OTU03u+l1gs+KGMfmS0h0ZYw6KGVLgMnsoxqd6cFSKNB
+8Ohk9ZTZGCiovlXBUepyu8wKat1k8YlHSfIHoRUJRhhcd7DrmojC+bcbMIZBU22T
+Pl2ftVRGtcQY23lYd0NNKfebF7ncjuLWQGy+vZW+7cgfI6wPIbfYfP6g7QAutk6W
+KQx0AoX5woZ6cNxtpIrymaVjSMRRBkKQrJKmRp3pC/lul5E5P2cueMs1fj4OHTbJ
+lAUv88ywr+R+mRgYQlFW/XQ653f6DT4t6+njfO9oBcPrQDASZel3LjXLpjjYG/N5
++BWnVexuJX9ika8HJiFl55oqaKb+WknfNhk5cPY+x7SDV9ywQeMiDZpr0ffeYAEP
+LlwwiWRDYpO+uwXHSFF3+JjWwjhs8m8g99iFb7U93yKgBB12dCEPPa2ZeH9wUHMJ
+sreYhNuq6f4iWWSXpzN45inQqtTi8jrJhuNLTT543ErW7DtntBO2rWMhff3aiXbn
+Uy3qzZM1nPbuCGuBmP9L2dJ3Z5ifDWB4JmOyWY4swTZGt9AVmUxMIKdZpRONx8vz
+I9u9nbVPGZBcou50Pa0qTLbkWsSL94MNXrARBxzhHC9Zs6XNEtwN7mOuii7uMkVc
+adrxgknBH1J1N+NX/eTKzUwJuPvDtA+Z5ILWNN9wpZT/7ed8zEnKHPNUexyeT5g3
+uw9z9jH7ffGxFYlx87oiVPHGOrCXYZYW5uoZE31SCBkbtNuffNRJRKIFeipmpJ3P
+7bpAG+kGHMelQH6b+5K1Qgsv4tpuSyKeTKpPFH9Av5nN4P1ZBm9N80tzbNWqjSJm
+S7rYdHnuNEVnUGnRmEUMmVuYZnNBEVN/fP2m2SEwXcP3Uh7TiYlcWw10ygaGmOr7
+MvMLGkYgQ4Utwnd98mtqa0jr0hK2TcOSFir3AqVvXN3XJj4cVULkrXe4Im1laWgp
+-----END RSA PRIVATE KEY-----
+`),
+ },
+
+ 1: {
+ Name: "dsa-encrypted",
+ EncryptionKey: "qG0pher-dsa_t3st$",
+ PEMBytes: []byte(`-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,7CE7A6E4A647DC01AF860210B15ADE3E
+
+hvnBpI99Hceq/55pYRdOzBLntIEis02JFNXuLEydWL+RJBFDn7tA+vXec0ERJd6J
+G8JXlSOAhmC2H4uK3q2xR8/Y3yL95n6OIcjvCBiLsV+o3jj1MYJmErxP6zRtq4w3
+JjIjGHWmaYFSxPKQ6e8fs74HEqaeMV9ONUoTtB+aISmgaBL15Fcoayg245dkBvVl
+h5Kqspe7yvOBmzA3zjRuxmSCqKJmasXM7mqs3vIrMxZE3XPo1/fWKcPuExgpVQoT
+HkJZEoIEIIPnPMwT2uYbFJSGgPJVMDT84xz7yvjCdhLmqrsXgs5Qw7Pw0i0c0BUJ
+b7fDJ2UhdiwSckWGmIhTLlJZzr8K+JpjCDlP+REYBI5meB7kosBnlvCEHdw2EJkH
+0QDc/2F4xlVrHOLbPRFyu1Oi2Gvbeoo9EsM/DThpd1hKAlb0sF5Y0y0d+owv0PnE
+R/4X3HWfIdOHsDUvJ8xVWZ4BZk9Zk9qol045DcFCehpr/3hslCrKSZHakLt9GI58
+vVQJ4L0aYp5nloLfzhViZtKJXRLkySMKdzYkIlNmW1oVGl7tce5UCNI8Nok4j6yn
+IiHM7GBn+0nJoKTXsOGMIBe3ulKlKVxLjEuk9yivh/8=
+-----END DSA PRIVATE KEY-----
+`),
+ },
+}