From 0135904f7d3e1c0e763adaefe267c736616e3d26 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Wed, 16 Nov 2016 19:28:52 -0500 Subject: Upgrading server dependancies (#4566) --- .../golang.org/x/crypto/ssh/agent/client_test.go | 24 +++++-- vendor/golang.org/x/crypto/ssh/agent/keyring.go | 53 +++++++++++---- .../golang.org/x/crypto/ssh/agent/keyring_test.go | 4 +- vendor/golang.org/x/crypto/ssh/client_auth_test.go | 2 +- vendor/golang.org/x/crypto/ssh/example_test.go | 75 ++++++++++++++-------- vendor/golang.org/x/crypto/ssh/kex.go | 30 ++++++--- vendor/golang.org/x/crypto/ssh/keys.go | 38 ++++++++++- vendor/golang.org/x/crypto/ssh/keys_test.go | 36 ++++++++--- .../x/crypto/ssh/terminal/util_solaris.go | 73 +++++++++++++++++++++ vendor/golang.org/x/crypto/ssh/testdata/keys.go | 63 ++++++++++++++++++ 10 files changed, 331 insertions(+), 67 deletions(-) create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go (limited to 'vendor/golang.org/x/crypto/ssh') 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,22 +74,24 @@ 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 @@ -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----- +`), + }, +} -- cgit v1.2.3-1-g7c22