Deps update, gopkg.lock fix, flagger initialization fix.
This commit is contained in:
122
vendor/golang.org/x/crypto/ssh/agent/client.go
generated
vendored
122
vendor/golang.org/x/crypto/ssh/agent/client.go
generated
vendored
@@ -8,7 +8,7 @@
|
||||
// ssh-agent process using the sample server.
|
||||
//
|
||||
// References:
|
||||
// [PROTOCOL.agent]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
|
||||
// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00
|
||||
package agent // import "golang.org/x/crypto/ssh/agent"
|
||||
|
||||
import (
|
||||
@@ -25,10 +25,22 @@ import (
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"crypto"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// SignatureFlags represent additional flags that can be passed to the signature
|
||||
// requests an defined in [PROTOCOL.agent] section 4.5.1.
|
||||
type SignatureFlags uint32
|
||||
|
||||
// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3.
|
||||
const (
|
||||
SignatureFlagReserved SignatureFlags = 1 << iota
|
||||
SignatureFlagRsaSha256
|
||||
SignatureFlagRsaSha512
|
||||
)
|
||||
|
||||
// Agent represents the capabilities of an ssh-agent.
|
||||
type Agent interface {
|
||||
// List returns the identities known to the agent.
|
||||
@@ -57,6 +69,26 @@ type Agent interface {
|
||||
Signers() ([]ssh.Signer, error)
|
||||
}
|
||||
|
||||
type ExtendedAgent interface {
|
||||
Agent
|
||||
|
||||
// SignWithFlags signs like Sign, but allows for additional flags to be sent/received
|
||||
SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error)
|
||||
|
||||
// Extension processes a custom extension request. Standard-compliant agents are not
|
||||
// required to support any extensions, but this method allows agents to implement
|
||||
// vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7.
|
||||
// If agent extensions are unsupported entirely this method MUST return an
|
||||
// ErrExtensionUnsupported error. Similarly, if just the specific extensionType in
|
||||
// the request is unsupported by the agent then ErrExtensionUnsupported MUST be
|
||||
// returned.
|
||||
//
|
||||
// In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents
|
||||
// of the response are unspecified (including the type of the message), the complete
|
||||
// response will be returned as a []byte slice, including the "type" byte of the message.
|
||||
Extension(extensionType string, contents []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// ConstraintExtension describes an optional constraint defined by users.
|
||||
type ConstraintExtension struct {
|
||||
// ExtensionName consist of a UTF-8 string suffixed by the
|
||||
@@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct {
|
||||
Rest []byte `ssh:"rest"`
|
||||
}
|
||||
|
||||
// See [PROTOCOL.agent], section 4.7
|
||||
const agentExtension = 27
|
||||
const agentExtensionFailure = 28
|
||||
|
||||
// ErrExtensionUnsupported indicates that an extension defined in
|
||||
// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this
|
||||
// error indicates that the agent returned a standard SSH_AGENT_FAILURE message
|
||||
// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol
|
||||
// specification (and therefore this error) does not distinguish between a
|
||||
// specific extension being unsupported and extensions being unsupported entirely.
|
||||
var ErrExtensionUnsupported = errors.New("agent: extension unsupported")
|
||||
|
||||
type extensionAgentMsg struct {
|
||||
ExtensionType string `sshtype:"27"`
|
||||
Contents []byte
|
||||
}
|
||||
|
||||
// Key represents a protocol 2 public key as defined in
|
||||
// [PROTOCOL.agent], section 2.5.2.
|
||||
type Key struct {
|
||||
@@ -260,7 +309,7 @@ type client struct {
|
||||
|
||||
// NewClient returns an Agent that talks to an ssh-agent process over
|
||||
// the given connection.
|
||||
func NewClient(rw io.ReadWriter) Agent {
|
||||
func NewClient(rw io.ReadWriter) ExtendedAgent {
|
||||
return &client{conn: rw}
|
||||
}
|
||||
|
||||
@@ -268,6 +317,21 @@ func NewClient(rw io.ReadWriter) Agent {
|
||||
// unmarshaled into reply and replyType is set to the first byte of
|
||||
// the reply, which contains the type of the message.
|
||||
func (c *client) call(req []byte) (reply interface{}, err error) {
|
||||
buf, err := c.callRaw(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reply, err = unmarshal(buf)
|
||||
if err != nil {
|
||||
return nil, clientErr(err)
|
||||
}
|
||||
return reply, nil
|
||||
}
|
||||
|
||||
// callRaw sends an RPC to the agent. On success, the raw
|
||||
// bytes of the response are returned; no unmarshalling is
|
||||
// performed on the response.
|
||||
func (c *client) callRaw(req []byte) (reply []byte, err error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) {
|
||||
}
|
||||
respSize := binary.BigEndian.Uint32(respSizeBuf[:])
|
||||
if respSize > maxAgentResponseBytes {
|
||||
return nil, clientErr(err)
|
||||
return nil, clientErr(errors.New("response too large"))
|
||||
}
|
||||
|
||||
buf := make([]byte, respSize)
|
||||
if _, err = io.ReadFull(c.conn, buf); err != nil {
|
||||
return nil, clientErr(err)
|
||||
}
|
||||
reply, err = unmarshal(buf)
|
||||
if err != nil {
|
||||
return nil, clientErr(err)
|
||||
}
|
||||
return reply, err
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (c *client) simpleCall(req []byte) error {
|
||||
@@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) {
|
||||
// Sign has the agent sign the data using a protocol 2 key as defined
|
||||
// in [PROTOCOL.agent] section 2.6.2.
|
||||
func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
|
||||
return c.SignWithFlags(key, data, 0)
|
||||
}
|
||||
|
||||
func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) {
|
||||
req := ssh.Marshal(signRequestAgentMsg{
|
||||
KeyBlob: key.Marshal(),
|
||||
Data: data,
|
||||
Flags: uint32(flags),
|
||||
})
|
||||
|
||||
msg, err := c.call(req)
|
||||
@@ -681,3 +746,44 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature,
|
||||
// The agent has its own entropy source, so the rand argument is ignored.
|
||||
return s.agent.Sign(s.pub, data)
|
||||
}
|
||||
|
||||
func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) {
|
||||
var flags SignatureFlags
|
||||
if opts != nil {
|
||||
switch opts.HashFunc() {
|
||||
case crypto.SHA256:
|
||||
flags = SignatureFlagRsaSha256
|
||||
case crypto.SHA512:
|
||||
flags = SignatureFlagRsaSha512
|
||||
}
|
||||
}
|
||||
return s.agent.SignWithFlags(s.pub, data, flags)
|
||||
}
|
||||
|
||||
// Calls an extension method. It is up to the agent implementation as to whether or not
|
||||
// any particular extension is supported and may always return an error. Because the
|
||||
// type of the response is up to the implementation, this returns the bytes of the
|
||||
// response and does not attempt any type of unmarshalling.
|
||||
func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) {
|
||||
req := ssh.Marshal(extensionAgentMsg{
|
||||
ExtensionType: extensionType,
|
||||
Contents: contents,
|
||||
})
|
||||
buf, err := c.callRaw(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(buf) == 0 {
|
||||
return nil, errors.New("agent: failure; empty response")
|
||||
}
|
||||
// [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message
|
||||
// represents an agent that does not support the extension
|
||||
if buf[0] == agentFailure {
|
||||
return nil, ErrExtensionUnsupported
|
||||
}
|
||||
if buf[0] == agentExtensionFailure {
|
||||
return nil, errors.New("agent: generic extension failure")
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
97
vendor/golang.org/x/crypto/ssh/agent/client_test.go
generated
vendored
97
vendor/golang.org/x/crypto/ssh/agent/client_test.go
generated
vendored
@@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
// startOpenSSHAgent executes ssh-agent, and returns an Agent interface to it.
|
||||
func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func()) {
|
||||
func startOpenSSHAgent(t *testing.T) (client ExtendedAgent, socket string, cleanup func()) {
|
||||
if testing.Short() {
|
||||
// ssh-agent is not always available, and the key
|
||||
// types supported vary by platform.
|
||||
@@ -79,13 +79,12 @@ func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func(
|
||||
}
|
||||
}
|
||||
|
||||
// startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client.
|
||||
func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) {
|
||||
func startAgent(t *testing.T, agent Agent) (client ExtendedAgent, cleanup func()) {
|
||||
c1, c2, err := netPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("netPipe: %v", err)
|
||||
}
|
||||
go ServeAgent(NewKeyring(), c2)
|
||||
go ServeAgent(agent, c2)
|
||||
|
||||
return NewClient(c1), func() {
|
||||
c1.Close()
|
||||
@@ -93,6 +92,11 @@ func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) {
|
||||
}
|
||||
}
|
||||
|
||||
// startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client.
|
||||
func startKeyringAgent(t *testing.T) (client ExtendedAgent, cleanup func()) {
|
||||
return startAgent(t, NewKeyring())
|
||||
}
|
||||
|
||||
func testOpenSSHAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
|
||||
agent, _, cleanup := startOpenSSHAgent(t)
|
||||
defer cleanup()
|
||||
@@ -107,7 +111,7 @@ func testKeyringAgent(t *testing.T, key interface{}, cert *ssh.Certificate, life
|
||||
testAgentInterface(t, agent, key, cert, lifetimeSecs)
|
||||
}
|
||||
|
||||
func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
|
||||
func testAgentInterface(t *testing.T, agent ExtendedAgent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
|
||||
signer, err := ssh.NewSignerFromKey(key)
|
||||
if err != nil {
|
||||
t.Fatalf("NewSignerFromKey(%T): %v", key, err)
|
||||
@@ -159,6 +163,25 @@ func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Ce
|
||||
t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
|
||||
}
|
||||
|
||||
// For tests on RSA keys, try signing with SHA-256 and SHA-512 flags
|
||||
if pubKey.Type() == "ssh-rsa" {
|
||||
sshFlagTest := func(flag SignatureFlags, expectedSigFormat string) {
|
||||
sig, err = agent.SignWithFlags(pubKey, data, flag)
|
||||
if err != nil {
|
||||
t.Fatalf("SignWithFlags(%s): %v", pubKey.Type(), err)
|
||||
}
|
||||
if sig.Format != expectedSigFormat {
|
||||
t.Fatalf("Signature format didn't match expected value: %s != %s", sig.Format, expectedSigFormat)
|
||||
}
|
||||
if err := pubKey.Verify(data, sig); err != nil {
|
||||
t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
|
||||
}
|
||||
}
|
||||
sshFlagTest(0, ssh.SigAlgoRSA)
|
||||
sshFlagTest(SignatureFlagRsaSha256, ssh.SigAlgoRSASHA2256)
|
||||
sshFlagTest(SignatureFlagRsaSha512, ssh.SigAlgoRSASHA2512)
|
||||
}
|
||||
|
||||
// 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)
|
||||
@@ -218,6 +241,35 @@ func netPipe() (net.Conn, net.Conn, error) {
|
||||
return c1, c2, nil
|
||||
}
|
||||
|
||||
func TestServerResponseTooLarge(t *testing.T) {
|
||||
a, b, err := netPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("netPipe: %v", err)
|
||||
}
|
||||
|
||||
defer a.Close()
|
||||
defer b.Close()
|
||||
|
||||
var response identitiesAnswerAgentMsg
|
||||
response.NumKeys = 1
|
||||
response.Keys = make([]byte, maxAgentResponseBytes+1)
|
||||
|
||||
agent := NewClient(a)
|
||||
go func() {
|
||||
n, _ := b.Write(ssh.Marshal(response))
|
||||
if n < 4 {
|
||||
t.Fatalf("At least 4 bytes (the response size) should have been successfully written: %d < 4", n)
|
||||
}
|
||||
}()
|
||||
_, err = agent.List()
|
||||
if err == nil {
|
||||
t.Fatal("Did not get error result")
|
||||
}
|
||||
if err.Error() != "agent: client error: response too large" {
|
||||
t.Fatal("Did not get expected error result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
agent, _, cleanup := startOpenSSHAgent(t)
|
||||
defer cleanup()
|
||||
@@ -377,3 +429,38 @@ func testAgentLifetime(t *testing.T, agent Agent) {
|
||||
t.Errorf("Want 0 keys, got %v", len(keys))
|
||||
}
|
||||
}
|
||||
|
||||
type keyringExtended struct {
|
||||
*keyring
|
||||
}
|
||||
|
||||
func (r *keyringExtended) Extension(extensionType string, contents []byte) ([]byte, error) {
|
||||
if extensionType != "my-extension@example.com" {
|
||||
return []byte{agentExtensionFailure}, nil
|
||||
}
|
||||
return append([]byte{agentSuccess}, contents...), nil
|
||||
}
|
||||
|
||||
func TestAgentExtensions(t *testing.T) {
|
||||
agent, _, cleanup := startOpenSSHAgent(t)
|
||||
defer cleanup()
|
||||
_, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
|
||||
if err == nil {
|
||||
t.Fatal("should have gotten agent extension failure")
|
||||
}
|
||||
|
||||
agent, cleanup = startAgent(t, &keyringExtended{})
|
||||
defer cleanup()
|
||||
result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
|
||||
if err != nil {
|
||||
t.Fatalf("agent extension failure: %v", err)
|
||||
}
|
||||
if len(result) != 4 || !bytes.Equal(result, []byte{agentSuccess, 0x00, 0x01, 0x02}) {
|
||||
t.Fatalf("agent extension result invalid: %v", result)
|
||||
}
|
||||
|
||||
_, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02})
|
||||
if err == nil {
|
||||
t.Fatal("should have gotten agent extension failure")
|
||||
}
|
||||
}
|
||||
|
30
vendor/golang.org/x/crypto/ssh/agent/keyring.go
generated
vendored
30
vendor/golang.org/x/crypto/ssh/agent/keyring.go
generated
vendored
@@ -102,7 +102,7 @@ func (r *keyring) Unlock(passphrase []byte) error {
|
||||
if !r.locked {
|
||||
return errors.New("agent: not locked")
|
||||
}
|
||||
if len(passphrase) != len(r.passphrase) || 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) {
|
||||
if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) {
|
||||
return fmt.Errorf("agent: incorrect passphrase")
|
||||
}
|
||||
|
||||
@@ -182,6 +182,10 @@ func (r *keyring) Add(key AddedKey) error {
|
||||
|
||||
// Sign returns a signature for the data.
|
||||
func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
|
||||
return r.SignWithFlags(key, data, 0)
|
||||
}
|
||||
|
||||
func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if r.locked {
|
||||
@@ -192,7 +196,24 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
|
||||
wanted := key.Marshal()
|
||||
for _, k := range r.keys {
|
||||
if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) {
|
||||
return k.signer.Sign(rand.Reader, data)
|
||||
if flags == 0 {
|
||||
return k.signer.Sign(rand.Reader, data)
|
||||
} else {
|
||||
if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok {
|
||||
return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer)
|
||||
} else {
|
||||
var algorithm string
|
||||
switch flags {
|
||||
case SignatureFlagRsaSha256:
|
||||
algorithm = ssh.SigAlgoRSASHA2256
|
||||
case SignatureFlagRsaSha512:
|
||||
algorithm = ssh.SigAlgoRSASHA2512
|
||||
default:
|
||||
return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags)
|
||||
}
|
||||
return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, errors.New("not found")
|
||||
@@ -213,3 +234,8 @@ func (r *keyring) Signers() ([]ssh.Signer, error) {
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// The keyring does not support any extensions
|
||||
func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) {
|
||||
return nil, ErrExtensionUnsupported
|
||||
}
|
||||
|
46
vendor/golang.org/x/crypto/ssh/agent/server.go
generated
vendored
46
vendor/golang.org/x/crypto/ssh/agent/server.go
generated
vendored
@@ -128,7 +128,14 @@ func (s *server) processRequest(data []byte) (interface{}, error) {
|
||||
Blob: req.KeyBlob,
|
||||
}
|
||||
|
||||
sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags.
|
||||
var sig *ssh.Signature
|
||||
var err error
|
||||
if extendedAgent, ok := s.agent.(ExtendedAgent); ok {
|
||||
sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags))
|
||||
} else {
|
||||
sig, err = s.agent.Sign(k, req.Data)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) {
|
||||
|
||||
case agentAddIDConstrained, agentAddIdentity:
|
||||
return nil, s.insertIdentity(data)
|
||||
|
||||
case agentExtension:
|
||||
// Return a stub object where the whole contents of the response gets marshaled.
|
||||
var responseStub struct {
|
||||
Rest []byte `ssh:"rest"`
|
||||
}
|
||||
|
||||
if extendedAgent, ok := s.agent.(ExtendedAgent); !ok {
|
||||
// If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7
|
||||
// requires that we return a standard SSH_AGENT_FAILURE message.
|
||||
responseStub.Rest = []byte{agentFailure}
|
||||
} else {
|
||||
var req extensionAgentMsg
|
||||
if err := ssh.Unmarshal(data, &req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := extendedAgent.Extension(req.ExtensionType, req.Contents)
|
||||
if err != nil {
|
||||
// If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE
|
||||
// message as required by [PROTOCOL.agent] section 4.7.
|
||||
if err == ErrExtensionUnsupported {
|
||||
responseStub.Rest = []byte{agentFailure}
|
||||
} else {
|
||||
// As the result of any other error processing an extension request,
|
||||
// [PROTOCOL.agent] section 4.7 requires that we return a
|
||||
// SSH_AGENT_EXTENSION_FAILURE code.
|
||||
responseStub.Rest = []byte{agentExtensionFailure}
|
||||
}
|
||||
} else {
|
||||
if len(res) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
responseStub.Rest = res
|
||||
}
|
||||
}
|
||||
|
||||
return responseStub, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown opcode %d", data[0])
|
||||
|
3
vendor/golang.org/x/crypto/ssh/benchmark_test.go
generated
vendored
3
vendor/golang.org/x/crypto/ssh/benchmark_test.go
generated
vendored
@@ -93,6 +93,9 @@ func BenchmarkEndToEnd(b *testing.B) {
|
||||
b.Fatalf("Client: %v", err)
|
||||
}
|
||||
ch, incoming, err := newCh.Accept()
|
||||
if err != nil {
|
||||
b.Fatalf("Accept: %v", err)
|
||||
}
|
||||
go DiscardRequests(incoming)
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := io.ReadFull(ch, output); err != nil {
|
||||
|
20
vendor/golang.org/x/crypto/ssh/certs.go
generated
vendored
20
vendor/golang.org/x/crypto/ssh/certs.go
generated
vendored
@@ -44,7 +44,9 @@ type Signature struct {
|
||||
const CertTimeInfinity = 1<<64 - 1
|
||||
|
||||
// An Certificate represents an OpenSSH certificate as defined in
|
||||
// [PROTOCOL.certkeys]?rev=1.8.
|
||||
// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the
|
||||
// PublicKey interface, so it can be unmarshaled using
|
||||
// ParsePublicKey.
|
||||
type Certificate struct {
|
||||
Nonce []byte
|
||||
Key PublicKey
|
||||
@@ -220,6 +222,11 @@ type openSSHCertSigner struct {
|
||||
signer Signer
|
||||
}
|
||||
|
||||
type algorithmOpenSSHCertSigner struct {
|
||||
*openSSHCertSigner
|
||||
algorithmSigner AlgorithmSigner
|
||||
}
|
||||
|
||||
// NewCertSigner returns a Signer that signs with the given Certificate, whose
|
||||
// private key is held by signer. It returns an error if the public key in cert
|
||||
// doesn't match the key used by signer.
|
||||
@@ -228,7 +235,12 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
|
||||
return nil, errors.New("ssh: signer and cert have different public key")
|
||||
}
|
||||
|
||||
return &openSSHCertSigner{cert, signer}, nil
|
||||
if algorithmSigner, ok := signer.(AlgorithmSigner); ok {
|
||||
return &algorithmOpenSSHCertSigner{
|
||||
&openSSHCertSigner{cert, signer}, algorithmSigner}, nil
|
||||
} else {
|
||||
return &openSSHCertSigner{cert, signer}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
|
||||
@@ -239,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey {
|
||||
return s.pub
|
||||
}
|
||||
|
||||
func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
|
||||
return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm)
|
||||
}
|
||||
|
||||
const sourceAddressCriticalOption = "source-address"
|
||||
|
||||
// CertChecker does the work of verifying a certificate. Its methods
|
||||
|
43
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
43
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
@@ -16,6 +16,7 @@ import (
|
||||
"hash"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/bits"
|
||||
|
||||
"golang.org/x/crypto/internal/chacha20"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
@@ -641,8 +642,8 @@ const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
|
||||
// the methods here also implement padding, which RFC4253 Section 6
|
||||
// also requires of stream ciphers.
|
||||
type chacha20Poly1305Cipher struct {
|
||||
lengthKey [32]byte
|
||||
contentKey [32]byte
|
||||
lengthKey [8]uint32
|
||||
contentKey [8]uint32
|
||||
buf []byte
|
||||
}
|
||||
|
||||
@@ -655,20 +656,21 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA
|
||||
buf: make([]byte, 256),
|
||||
}
|
||||
|
||||
copy(c.contentKey[:], key[:32])
|
||||
copy(c.lengthKey[:], key[32:])
|
||||
for i := range c.contentKey {
|
||||
c.contentKey[i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4])
|
||||
}
|
||||
for i := range c.lengthKey {
|
||||
c.lengthKey[i] = binary.LittleEndian.Uint32(key[(i+8)*4 : (i+9)*4])
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// The Poly1305 key is obtained by encrypting 32 0-bytes.
|
||||
var chacha20PolyKeyInput [32]byte
|
||||
|
||||
func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
|
||||
var counter [16]byte
|
||||
binary.BigEndian.PutUint64(counter[8:], uint64(seqNum))
|
||||
|
||||
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
|
||||
s := chacha20.New(c.contentKey, nonce)
|
||||
var polyKey [32]byte
|
||||
chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey)
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.Advance() // skip next 32 bytes
|
||||
|
||||
encryptedLength := c.buf[:4]
|
||||
if _, err := io.ReadFull(r, encryptedLength); err != nil {
|
||||
@@ -676,7 +678,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
|
||||
}
|
||||
|
||||
var lenBytes [4]byte
|
||||
chacha20.XORKeyStream(lenBytes[:], encryptedLength, &counter, &c.lengthKey)
|
||||
chacha20.New(c.lengthKey, nonce).XORKeyStream(lenBytes[:], encryptedLength)
|
||||
|
||||
length := binary.BigEndian.Uint32(lenBytes[:])
|
||||
if length > maxPacket {
|
||||
@@ -702,10 +704,8 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
|
||||
return nil, errors.New("ssh: MAC failure")
|
||||
}
|
||||
|
||||
counter[0] = 1
|
||||
|
||||
plain := c.buf[4:contentEnd]
|
||||
chacha20.XORKeyStream(plain, plain, &counter, &c.contentKey)
|
||||
s.XORKeyStream(plain, plain)
|
||||
|
||||
padding := plain[0]
|
||||
if padding < 4 {
|
||||
@@ -724,11 +724,11 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte,
|
||||
}
|
||||
|
||||
func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
|
||||
var counter [16]byte
|
||||
binary.BigEndian.PutUint64(counter[8:], uint64(seqNum))
|
||||
|
||||
nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)}
|
||||
s := chacha20.New(c.contentKey, nonce)
|
||||
var polyKey [32]byte
|
||||
chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey)
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.Advance() // skip next 32 bytes
|
||||
|
||||
// There is no blocksize, so fall back to multiple of 8 byte
|
||||
// padding, as described in RFC 4253, Sec 6.
|
||||
@@ -748,7 +748,7 @@ func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding))
|
||||
chacha20.XORKeyStream(c.buf, c.buf[:4], &counter, &c.lengthKey)
|
||||
chacha20.New(c.lengthKey, nonce).XORKeyStream(c.buf, c.buf[:4])
|
||||
c.buf[4] = byte(padding)
|
||||
copy(c.buf[5:], payload)
|
||||
packetEnd := 5 + len(payload) + padding
|
||||
@@ -756,8 +756,7 @@ func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io
|
||||
return err
|
||||
}
|
||||
|
||||
counter[0] = 1
|
||||
chacha20.XORKeyStream(c.buf[4:], c.buf[4:packetEnd], &counter, &c.contentKey)
|
||||
s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd])
|
||||
|
||||
var mac [poly1305.TagSize]byte
|
||||
poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey)
|
||||
|
6
vendor/golang.org/x/crypto/ssh/client.go
generated
vendored
6
vendor/golang.org/x/crypto/ssh/client.go
generated
vendored
@@ -19,6 +19,8 @@ import (
|
||||
type Client struct {
|
||||
Conn
|
||||
|
||||
handleForwardsOnce sync.Once // guards calling (*Client).handleForwards
|
||||
|
||||
forwards forwardList // forwarded tcpip connections from the remote side
|
||||
mu sync.Mutex
|
||||
channelHandlers map[string]chan NewChannel
|
||||
@@ -60,8 +62,6 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
|
||||
conn.Wait()
|
||||
conn.forwards.closeAll()
|
||||
}()
|
||||
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
|
||||
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
|
||||
return conn
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) {
|
||||
// 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.
|
||||
// net.Conn underlying the SSH connection.
|
||||
type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
|
||||
|
||||
// BannerCallback is the function type used for treat the banner sent by
|
||||
|
95
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
95
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
@@ -11,6 +11,14 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type authResult int
|
||||
|
||||
const (
|
||||
authFailure authResult = iota
|
||||
authPartialSuccess
|
||||
authSuccess
|
||||
)
|
||||
|
||||
// clientAuthenticate authenticates with the remote server. See RFC 4252.
|
||||
func (c *connection) clientAuthenticate(config *ClientConfig) error {
|
||||
// initiate user auth session
|
||||
@@ -37,11 +45,12 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
if ok == authSuccess {
|
||||
// success
|
||||
return nil
|
||||
} else if ok == authFailure {
|
||||
tried[auth.method()] = true
|
||||
}
|
||||
tried[auth.method()] = true
|
||||
if methods == nil {
|
||||
methods = lastMethods
|
||||
}
|
||||
@@ -82,7 +91,7 @@ type AuthMethod interface {
|
||||
// If authentication is not successful, a []string of alternative
|
||||
// method names is returned. If the slice is nil, it will be ignored
|
||||
// and the previous set of possible methods will be reused.
|
||||
auth(session []byte, user string, p packetConn, rand io.Reader) (bool, []string, error)
|
||||
auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error)
|
||||
|
||||
// method returns the RFC 4252 method name.
|
||||
method() string
|
||||
@@ -91,13 +100,13 @@ type AuthMethod interface {
|
||||
// "none" authentication, RFC 4252 section 5.2.
|
||||
type noneAuth int
|
||||
|
||||
func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
|
||||
func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
||||
if err := c.writePacket(Marshal(&userAuthRequestMsg{
|
||||
User: user,
|
||||
Service: serviceSSH,
|
||||
Method: "none",
|
||||
})); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
return handleAuthResponse(c)
|
||||
@@ -111,7 +120,7 @@ func (n *noneAuth) method() string {
|
||||
// a function call, e.g. by prompting the user.
|
||||
type passwordCallback func() (password string, err error)
|
||||
|
||||
func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
|
||||
func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
||||
type passwordAuthMsg struct {
|
||||
User string `sshtype:"50"`
|
||||
Service string
|
||||
@@ -125,7 +134,7 @@ func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand
|
||||
// The program may only find out that the user doesn't have a password
|
||||
// when prompting.
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
if err := c.writePacket(Marshal(&passwordAuthMsg{
|
||||
@@ -135,7 +144,7 @@ func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand
|
||||
Reply: false,
|
||||
Password: pw,
|
||||
})); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
return handleAuthResponse(c)
|
||||
@@ -178,7 +187,7 @@ func (cb publicKeyCallback) method() string {
|
||||
return "publickey"
|
||||
}
|
||||
|
||||
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
|
||||
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
||||
// 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
|
||||
@@ -186,13 +195,13 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
|
||||
|
||||
signers, err := cb()
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
var methods []string
|
||||
for _, signer := range signers {
|
||||
ok, err := validateKey(signer.PublicKey(), user, c)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
@@ -206,7 +215,7 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
|
||||
Method: cb.method(),
|
||||
}, []byte(pub.Type()), pubKey))
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
// manually wrap the serialized signature in a string
|
||||
@@ -224,24 +233,24 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
|
||||
}
|
||||
p := Marshal(&msg)
|
||||
if err := c.writePacket(p); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
var success bool
|
||||
var success authResult
|
||||
success, methods, err = handleAuthResponse(c)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
if success == authSuccess || !containsMethod(methods, cb.method()) {
|
||||
return success, methods, err
|
||||
}
|
||||
}
|
||||
|
||||
return false, methods, nil
|
||||
return authFailure, methods, nil
|
||||
}
|
||||
|
||||
func containsMethod(methods []string, method string) bool {
|
||||
@@ -318,28 +327,31 @@ func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMet
|
||||
// handleAuthResponse returns whether the preceding authentication request succeeded
|
||||
// along with a list of remaining authentication methods to try next and
|
||||
// an error if an unexpected response was received.
|
||||
func handleAuthResponse(c packetConn) (bool, []string, error) {
|
||||
func handleAuthResponse(c packetConn) (authResult, []string, error) {
|
||||
for {
|
||||
packet, err := c.readPacket()
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
switch packet[0] {
|
||||
case msgUserAuthBanner:
|
||||
if err := handleBannerResponse(c, packet); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
case msgUserAuthFailure:
|
||||
var msg userAuthFailureMsg
|
||||
if err := Unmarshal(packet, &msg); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
return false, msg.Methods, nil
|
||||
if msg.PartialSuccess {
|
||||
return authPartialSuccess, msg.Methods, nil
|
||||
}
|
||||
return authFailure, msg.Methods, nil
|
||||
case msgUserAuthSuccess:
|
||||
return true, nil, nil
|
||||
return authSuccess, nil, nil
|
||||
default:
|
||||
return false, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
|
||||
return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,7 +393,7 @@ func (cb KeyboardInteractiveChallenge) method() string {
|
||||
return "keyboard-interactive"
|
||||
}
|
||||
|
||||
func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
|
||||
func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) {
|
||||
type initiateMsg struct {
|
||||
User string `sshtype:"50"`
|
||||
Service string
|
||||
@@ -395,20 +407,20 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
|
||||
Service: serviceSSH,
|
||||
Method: "keyboard-interactive",
|
||||
})); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
packet, err := c.readPacket()
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
// like handleAuthResponse, but with less options.
|
||||
switch packet[0] {
|
||||
case msgUserAuthBanner:
|
||||
if err := handleBannerResponse(c, packet); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
continue
|
||||
case msgUserAuthInfoRequest:
|
||||
@@ -416,18 +428,21 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
|
||||
case msgUserAuthFailure:
|
||||
var msg userAuthFailureMsg
|
||||
if err := Unmarshal(packet, &msg); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
return false, msg.Methods, nil
|
||||
if msg.PartialSuccess {
|
||||
return authPartialSuccess, msg.Methods, nil
|
||||
}
|
||||
return authFailure, msg.Methods, nil
|
||||
case msgUserAuthSuccess:
|
||||
return true, nil, nil
|
||||
return authSuccess, nil, nil
|
||||
default:
|
||||
return false, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
|
||||
return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
|
||||
}
|
||||
|
||||
var msg userAuthInfoRequestMsg
|
||||
if err := Unmarshal(packet, &msg); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
// Manually unpack the prompt/echo pairs.
|
||||
@@ -437,7 +452,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
|
||||
for i := 0; i < int(msg.NumPrompts); i++ {
|
||||
prompt, r, ok := parseString(rest)
|
||||
if !ok || len(r) == 0 {
|
||||
return false, nil, errors.New("ssh: prompt format error")
|
||||
return authFailure, nil, errors.New("ssh: prompt format error")
|
||||
}
|
||||
prompts = append(prompts, string(prompt))
|
||||
echos = append(echos, r[0] != 0)
|
||||
@@ -445,16 +460,16 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
|
||||
}
|
||||
|
||||
if len(rest) != 0 {
|
||||
return false, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
|
||||
return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
|
||||
}
|
||||
|
||||
answers, err := cb(msg.User, msg.Instruction, prompts, echos)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
|
||||
if len(answers) != len(prompts) {
|
||||
return false, nil, errors.New("ssh: not enough answers from keyboard-interactive callback")
|
||||
return authFailure, nil, errors.New("ssh: not enough answers from keyboard-interactive callback")
|
||||
}
|
||||
responseLength := 1 + 4
|
||||
for _, a := range answers {
|
||||
@@ -470,7 +485,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
|
||||
}
|
||||
|
||||
if err := c.writePacket(serialized); err != nil {
|
||||
return false, nil, err
|
||||
return authFailure, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,10 +495,10 @@ type retryableAuthMethod struct {
|
||||
maxTries int
|
||||
}
|
||||
|
||||
func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok bool, methods []string, err error) {
|
||||
func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok authResult, methods []string, err error) {
|
||||
for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ {
|
||||
ok, methods, err = r.authMethod.auth(session, user, c, rand)
|
||||
if ok || err != nil { // either success or error terminate
|
||||
if ok != authFailure || err != nil { // either success, partial success or error terminate
|
||||
return ok, methods, err
|
||||
}
|
||||
}
|
||||
|
58
vendor/golang.org/x/crypto/ssh/client_auth_test.go
generated
vendored
58
vendor/golang.org/x/crypto/ssh/client_auth_test.go
generated
vendored
@@ -9,6 +9,7 @@ import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -28,8 +29,14 @@ func (cr keyboardInteractive) Challenge(user string, instruction string, questio
|
||||
var clientPassword = "tiger"
|
||||
|
||||
// tryAuth runs a handshake with a given config against an SSH server
|
||||
// with config serverConfig
|
||||
// with config serverConfig. Returns both client and server side errors.
|
||||
func tryAuth(t *testing.T, config *ClientConfig) error {
|
||||
err, _ := tryAuthBothSides(t, config)
|
||||
return err
|
||||
}
|
||||
|
||||
// tryAuthBothSides runs the handshake and returns the resulting errors from both sides of the connection.
|
||||
func tryAuthBothSides(t *testing.T, config *ClientConfig) (clientError error, serverAuthErrors []error) {
|
||||
c1, c2, err := netPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("netPipe: %v", err)
|
||||
@@ -79,9 +86,13 @@ func tryAuth(t *testing.T, config *ClientConfig) error {
|
||||
}
|
||||
serverConfig.AddHostKey(testSigners["rsa"])
|
||||
|
||||
serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
|
||||
serverAuthErrors = append(serverAuthErrors, err)
|
||||
}
|
||||
|
||||
go newServer(c1, serverConfig)
|
||||
_, _, _, err = NewClientConn(c2, "", config)
|
||||
return err
|
||||
return err, serverAuthErrors
|
||||
}
|
||||
|
||||
func TestClientAuthPublicKey(t *testing.T) {
|
||||
@@ -213,6 +224,45 @@ func TestAuthMethodRSAandDSA(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type invalidAlgSigner struct {
|
||||
Signer
|
||||
}
|
||||
|
||||
func (s *invalidAlgSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
|
||||
sig, err := s.Signer.Sign(rand, data)
|
||||
if sig != nil {
|
||||
sig.Format = "invalid"
|
||||
}
|
||||
return sig, err
|
||||
}
|
||||
|
||||
func TestMethodInvalidAlgorithm(t *testing.T) {
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []AuthMethod{
|
||||
PublicKeys(&invalidAlgSigner{testSigners["rsa"]}),
|
||||
},
|
||||
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
err, serverErrors := tryAuthBothSides(t, config)
|
||||
if err == nil {
|
||||
t.Fatalf("login succeeded")
|
||||
}
|
||||
|
||||
found := false
|
||||
want := "algorithm \"invalid\""
|
||||
|
||||
var errStrings []string
|
||||
for _, err := range serverErrors {
|
||||
found = found || (err != nil && strings.Contains(err.Error(), want))
|
||||
errStrings = append(errStrings, err.Error())
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("server got error %q, want substring %q", errStrings, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientHMAC(t *testing.T) {
|
||||
for _, mac := range supportedMACs {
|
||||
config := &ClientConfig{
|
||||
@@ -614,8 +664,8 @@ func TestClientAuthErrorList(t *testing.T) {
|
||||
for i, e := range authErrs.Errors {
|
||||
switch i {
|
||||
case 0:
|
||||
if e.Error() != "no auth passed yet" {
|
||||
t.Fatalf("errors: got %v, want no auth passed yet", e.Error())
|
||||
if e != ErrNoAuth {
|
||||
t.Fatalf("errors: got error %v, want ErrNoAuth", e)
|
||||
}
|
||||
case 1:
|
||||
if e != publicKeyErr {
|
||||
|
101
vendor/golang.org/x/crypto/ssh/keys.go
generated
vendored
101
vendor/golang.org/x/crypto/ssh/keys.go
generated
vendored
@@ -38,6 +38,16 @@ const (
|
||||
KeyAlgoED25519 = "ssh-ed25519"
|
||||
)
|
||||
|
||||
// These constants represent non-default signature algorithms that are supported
|
||||
// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See
|
||||
// [PROTOCOL.agent] section 4.5.1 and
|
||||
// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10
|
||||
const (
|
||||
SigAlgoRSA = "ssh-rsa"
|
||||
SigAlgoRSASHA2256 = "rsa-sha2-256"
|
||||
SigAlgoRSASHA2512 = "rsa-sha2-512"
|
||||
)
|
||||
|
||||
// parsePubKey parses a public key of the given algorithm.
|
||||
// Use ParsePublicKey for keys with prepended algorithm.
|
||||
func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) {
|
||||
@@ -276,7 +286,8 @@ type PublicKey interface {
|
||||
Type() string
|
||||
|
||||
// Marshal returns the serialized key data in SSH wire format,
|
||||
// with the name prefix.
|
||||
// with the name prefix. To unmarshal the returned data, use
|
||||
// the ParsePublicKey function.
|
||||
Marshal() []byte
|
||||
|
||||
// Verify that sig is a signature on the given data using this
|
||||
@@ -300,6 +311,19 @@ type Signer interface {
|
||||
Sign(rand io.Reader, data []byte) (*Signature, error)
|
||||
}
|
||||
|
||||
// A AlgorithmSigner is a Signer that also supports specifying a specific
|
||||
// algorithm to use for signing.
|
||||
type AlgorithmSigner interface {
|
||||
Signer
|
||||
|
||||
// SignWithAlgorithm is like Signer.Sign, but allows specification of a
|
||||
// non-default signing algorithm. See the SigAlgo* constants in this
|
||||
// package for signature algorithms supported by this package. Callers may
|
||||
// pass an empty string for the algorithm in which case the AlgorithmSigner
|
||||
// will use its default algorithm.
|
||||
SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
|
||||
}
|
||||
|
||||
type rsaPublicKey rsa.PublicKey
|
||||
|
||||
func (r *rsaPublicKey) Type() string {
|
||||
@@ -348,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte {
|
||||
}
|
||||
|
||||
func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
|
||||
if sig.Format != r.Type() {
|
||||
var hash crypto.Hash
|
||||
switch sig.Format {
|
||||
case SigAlgoRSA:
|
||||
hash = crypto.SHA1
|
||||
case SigAlgoRSASHA2256:
|
||||
hash = crypto.SHA256
|
||||
case SigAlgoRSASHA2512:
|
||||
hash = crypto.SHA512
|
||||
default:
|
||||
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
|
||||
}
|
||||
h := crypto.SHA1.New()
|
||||
h := hash.New()
|
||||
h.Write(data)
|
||||
digest := h.Sum(nil)
|
||||
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob)
|
||||
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob)
|
||||
}
|
||||
|
||||
func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
|
||||
@@ -458,6 +490,14 @@ func (k *dsaPrivateKey) PublicKey() PublicKey {
|
||||
}
|
||||
|
||||
func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
|
||||
return k.SignWithAlgorithm(rand, data, "")
|
||||
}
|
||||
|
||||
func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
|
||||
if algorithm != "" && algorithm != k.PublicKey().Type() {
|
||||
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
|
||||
}
|
||||
|
||||
h := crypto.SHA1.New()
|
||||
h.Write(data)
|
||||
digest := h.Sum(nil)
|
||||
@@ -690,16 +730,42 @@ func (s *wrappedSigner) PublicKey() PublicKey {
|
||||
}
|
||||
|
||||
func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
|
||||
return s.SignWithAlgorithm(rand, data, "")
|
||||
}
|
||||
|
||||
func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
|
||||
var hashFunc crypto.Hash
|
||||
|
||||
switch key := s.pubKey.(type) {
|
||||
case *rsaPublicKey, *dsaPublicKey:
|
||||
hashFunc = crypto.SHA1
|
||||
case *ecdsaPublicKey:
|
||||
hashFunc = ecHash(key.Curve)
|
||||
case ed25519PublicKey:
|
||||
default:
|
||||
return nil, fmt.Errorf("ssh: unsupported key type %T", key)
|
||||
if _, ok := s.pubKey.(*rsaPublicKey); ok {
|
||||
// RSA keys support a few hash functions determined by the requested signature algorithm
|
||||
switch algorithm {
|
||||
case "", SigAlgoRSA:
|
||||
algorithm = SigAlgoRSA
|
||||
hashFunc = crypto.SHA1
|
||||
case SigAlgoRSASHA2256:
|
||||
hashFunc = crypto.SHA256
|
||||
case SigAlgoRSASHA2512:
|
||||
hashFunc = crypto.SHA512
|
||||
default:
|
||||
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
|
||||
}
|
||||
} else {
|
||||
// The only supported algorithm for all other key types is the same as the type of the key
|
||||
if algorithm == "" {
|
||||
algorithm = s.pubKey.Type()
|
||||
} else if algorithm != s.pubKey.Type() {
|
||||
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
|
||||
}
|
||||
|
||||
switch key := s.pubKey.(type) {
|
||||
case *dsaPublicKey:
|
||||
hashFunc = crypto.SHA1
|
||||
case *ecdsaPublicKey:
|
||||
hashFunc = ecHash(key.Curve)
|
||||
case ed25519PublicKey:
|
||||
default:
|
||||
return nil, fmt.Errorf("ssh: unsupported key type %T", key)
|
||||
}
|
||||
}
|
||||
|
||||
var digest []byte
|
||||
@@ -744,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
|
||||
}
|
||||
|
||||
return &Signature{
|
||||
Format: s.pubKey.Type(),
|
||||
Format: algorithm,
|
||||
Blob: signature,
|
||||
}, nil
|
||||
}
|
||||
@@ -802,7 +868,7 @@ func encryptedBlock(block *pem.Block) bool {
|
||||
}
|
||||
|
||||
// ParseRawPrivateKey returns a private key from a PEM encoded private key. It
|
||||
// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys.
|
||||
// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys.
|
||||
func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
if block == nil {
|
||||
@@ -816,6 +882,9 @@ func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
|
||||
switch block.Type {
|
||||
case "RSA PRIVATE KEY":
|
||||
return x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
// RFC5208 - https://tools.ietf.org/html/rfc5208
|
||||
case "PRIVATE KEY":
|
||||
return x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
case "EC PRIVATE KEY":
|
||||
return x509.ParseECPrivateKey(block.Bytes)
|
||||
case "DSA PRIVATE KEY":
|
||||
@@ -899,8 +968,8 @@ 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) (crypto.PrivateKey, error) {
|
||||
magic := append([]byte("openssh-key-v1"), 0)
|
||||
if !bytes.Equal(magic, key[0:len(magic)]) {
|
||||
const magic = "openssh-key-v1\x00"
|
||||
if len(key) < len(magic) || string(key[:len(magic)]) != magic {
|
||||
return nil, errors.New("ssh: invalid openssh private key format")
|
||||
}
|
||||
remaining := key[len(magic):]
|
||||
|
98
vendor/golang.org/x/crypto/ssh/keys_test.go
generated
vendored
98
vendor/golang.org/x/crypto/ssh/keys_test.go
generated
vendored
@@ -13,7 +13,9 @@ import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -107,6 +109,49 @@ func TestKeySignVerify(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeySignWithAlgorithmVerify(t *testing.T) {
|
||||
for _, priv := range testSigners {
|
||||
if algorithmSigner, ok := priv.(AlgorithmSigner); !ok {
|
||||
t.Errorf("Signers constructed by ssh package should always implement the AlgorithmSigner interface: %T", priv)
|
||||
} else {
|
||||
pub := priv.PublicKey()
|
||||
data := []byte("sign me")
|
||||
|
||||
signWithAlgTestCase := func(algorithm string, expectedAlg string) {
|
||||
sig, err := algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm)
|
||||
if err != nil {
|
||||
t.Fatalf("Sign(%T): %v", priv, err)
|
||||
}
|
||||
if sig.Format != expectedAlg {
|
||||
t.Errorf("signature format did not match requested signature algorithm: %s != %s", sig.Format, expectedAlg)
|
||||
}
|
||||
|
||||
if err := pub.Verify(data, sig); err != nil {
|
||||
t.Errorf("publicKey.Verify(%T): %v", priv, err)
|
||||
}
|
||||
sig.Blob[5]++
|
||||
if err := pub.Verify(data, sig); err == nil {
|
||||
t.Errorf("publicKey.Verify on broken sig did not fail")
|
||||
}
|
||||
}
|
||||
|
||||
// Using the empty string as the algorithm name should result in the same signature format as the algorithm-free Sign method.
|
||||
defaultSig, err := priv.Sign(rand.Reader, data)
|
||||
if err != nil {
|
||||
t.Fatalf("Sign(%T): %v", priv, err)
|
||||
}
|
||||
signWithAlgTestCase("", defaultSig.Format)
|
||||
|
||||
// RSA keys are the only ones which currently support more than one signing algorithm
|
||||
if pub.Type() == KeyAlgoRSA {
|
||||
for _, algorithm := range []string{SigAlgoRSA, SigAlgoRSASHA2256, SigAlgoRSASHA2512} {
|
||||
signWithAlgTestCase(algorithm, algorithm)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRSAPrivateKey(t *testing.T) {
|
||||
key := testPrivateKeys["rsa"]
|
||||
|
||||
@@ -234,7 +279,7 @@ func TestMarshalParsePublicKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type authResult struct {
|
||||
type testAuthResult struct {
|
||||
pubKey PublicKey
|
||||
options []string
|
||||
comments string
|
||||
@@ -242,11 +287,11 @@ type authResult struct {
|
||||
ok bool
|
||||
}
|
||||
|
||||
func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) {
|
||||
func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []testAuthResult) {
|
||||
rest := authKeys
|
||||
var values []authResult
|
||||
var values []testAuthResult
|
||||
for len(rest) > 0 {
|
||||
var r authResult
|
||||
var r testAuthResult
|
||||
var err error
|
||||
r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
|
||||
r.ok = (err == nil)
|
||||
@@ -264,7 +309,7 @@ func TestAuthorizedKeyBasic(t *testing.T) {
|
||||
pub, pubSerialized := getTestKey()
|
||||
line := "ssh-rsa " + pubSerialized + " user@host"
|
||||
testAuthorizedKeys(t, []byte(line),
|
||||
[]authResult{
|
||||
[]testAuthResult{
|
||||
{pub, nil, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
@@ -286,7 +331,7 @@ func TestAuth(t *testing.T) {
|
||||
authOptions := strings.Join(authWithOptions, eol)
|
||||
rest2 := strings.Join(authWithOptions[3:], eol)
|
||||
rest3 := strings.Join(authWithOptions[6:], eol)
|
||||
testAuthorizedKeys(t, []byte(authOptions), []authResult{
|
||||
testAuthorizedKeys(t, []byte(authOptions), []testAuthResult{
|
||||
{pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
|
||||
{pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
|
||||
{nil, nil, "", "", false},
|
||||
@@ -297,7 +342,7 @@ func TestAuth(t *testing.T) {
|
||||
func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
|
||||
pub, pubSerialized := getTestKey()
|
||||
authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []testAuthResult{
|
||||
{pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
@@ -305,7 +350,7 @@ func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
|
||||
func TestAuthWithQuotedCommaInEnv(t *testing.T) {
|
||||
pub, pubSerialized := getTestKey()
|
||||
authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []testAuthResult{
|
||||
{pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
@@ -314,11 +359,11 @@ func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
|
||||
pub, pubSerialized := getTestKey()
|
||||
authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + ` user@host`)
|
||||
authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []testAuthResult{
|
||||
{pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
|
||||
})
|
||||
|
||||
testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{
|
||||
testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []testAuthResult{
|
||||
{pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
@@ -327,7 +372,7 @@ func TestAuthWithInvalidSpace(t *testing.T) {
|
||||
_, pubSerialized := getTestKey()
|
||||
authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
|
||||
#more to follow but still no valid keys`)
|
||||
testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{
|
||||
testAuthorizedKeys(t, []byte(authWithInvalidSpace), []testAuthResult{
|
||||
{nil, nil, "", "", false},
|
||||
})
|
||||
}
|
||||
@@ -337,7 +382,7 @@ func TestAuthWithMissingQuote(t *testing.T) {
|
||||
authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
|
||||
env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
|
||||
|
||||
testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{
|
||||
testAuthorizedKeys(t, []byte(authWithMissingQuote), []testAuthResult{
|
||||
{pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
@@ -498,3 +543,32 @@ func TestFingerprintSHA256(t *testing.T) {
|
||||
t.Errorf("got fingerprint %q want %q", fingerprint, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidKeys(t *testing.T) {
|
||||
keyTypes := []string{
|
||||
"RSA PRIVATE KEY",
|
||||
"PRIVATE KEY",
|
||||
"EC PRIVATE KEY",
|
||||
"DSA PRIVATE KEY",
|
||||
"OPENSSH PRIVATE KEY",
|
||||
}
|
||||
|
||||
for _, keyType := range keyTypes {
|
||||
for _, dataLen := range []int{0, 1, 2, 5, 10, 20} {
|
||||
data := make([]byte, dataLen)
|
||||
if _, err := io.ReadFull(rand.Reader, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
pem.Encode(&buf, &pem.Block{
|
||||
Type: keyType,
|
||||
Bytes: data,
|
||||
})
|
||||
|
||||
// This test is just to ensure that the function
|
||||
// doesn't panic so the return value is ignored.
|
||||
ParseRawPrivateKey(buf.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
62
vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go
generated
vendored
62
vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go
generated
vendored
@@ -2,8 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package knownhosts implements a parser for the OpenSSH
|
||||
// known_hosts host key database.
|
||||
// Package knownhosts implements a parser for the OpenSSH known_hosts
|
||||
// host key database, and provides utility functions for writing
|
||||
// OpenSSH compliant known_hosts files.
|
||||
package knownhosts
|
||||
|
||||
import (
|
||||
@@ -38,7 +39,7 @@ func (a *addr) String() string {
|
||||
}
|
||||
|
||||
type matcher interface {
|
||||
match([]addr) bool
|
||||
match(addr) bool
|
||||
}
|
||||
|
||||
type hostPattern struct {
|
||||
@@ -57,19 +58,16 @@ func (p *hostPattern) String() string {
|
||||
|
||||
type hostPatterns []hostPattern
|
||||
|
||||
func (ps hostPatterns) match(addrs []addr) bool {
|
||||
func (ps hostPatterns) match(a addr) bool {
|
||||
matched := false
|
||||
for _, p := range ps {
|
||||
for _, a := range addrs {
|
||||
m := p.match(a)
|
||||
if !m {
|
||||
continue
|
||||
}
|
||||
if p.negate {
|
||||
return false
|
||||
}
|
||||
matched = true
|
||||
if !p.match(a) {
|
||||
continue
|
||||
}
|
||||
if p.negate {
|
||||
return false
|
||||
}
|
||||
matched = true
|
||||
}
|
||||
return matched
|
||||
}
|
||||
@@ -122,8 +120,8 @@ func serialize(k ssh.PublicKey) string {
|
||||
return k.Type() + " " + base64.StdEncoding.EncodeToString(k.Marshal())
|
||||
}
|
||||
|
||||
func (l *keyDBLine) match(addrs []addr) bool {
|
||||
return l.matcher.match(addrs)
|
||||
func (l *keyDBLine) match(a addr) bool {
|
||||
return l.matcher.match(a)
|
||||
}
|
||||
|
||||
type hostKeyDB struct {
|
||||
@@ -153,7 +151,7 @@ func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool
|
||||
a := addr{host: h, port: p}
|
||||
|
||||
for _, l := range db.lines {
|
||||
if l.cert && keyEq(l.knownKey.Key, remote) && l.match([]addr{a}) {
|
||||
if l.cert && keyEq(l.knownKey.Key, remote) && l.match(a) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -338,26 +336,24 @@ func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.Public
|
||||
return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", remote, err)
|
||||
}
|
||||
|
||||
addrs := []addr{
|
||||
{host, port},
|
||||
}
|
||||
|
||||
hostToCheck := addr{host, port}
|
||||
if address != "" {
|
||||
// Give preference to the hostname if available.
|
||||
host, port, err := net.SplitHostPort(address)
|
||||
if err != nil {
|
||||
return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", address, err)
|
||||
}
|
||||
|
||||
addrs = append(addrs, addr{host, port})
|
||||
hostToCheck = addr{host, port}
|
||||
}
|
||||
|
||||
return db.checkAddrs(addrs, remoteKey)
|
||||
return db.checkAddr(hostToCheck, remoteKey)
|
||||
}
|
||||
|
||||
// checkAddrs checks if we can find the given public key for any of
|
||||
// the given addresses. If we only find an entry for the IP address,
|
||||
// checkAddr checks if we can find the given public key for the
|
||||
// given address. If we only find an entry for the IP address,
|
||||
// or only the hostname, then this still succeeds.
|
||||
func (db *hostKeyDB) checkAddrs(addrs []addr, remoteKey ssh.PublicKey) error {
|
||||
func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error {
|
||||
// TODO(hanwen): are these the right semantics? What if there
|
||||
// is just a key for the IP address, but not for the
|
||||
// hostname?
|
||||
@@ -365,7 +361,7 @@ func (db *hostKeyDB) checkAddrs(addrs []addr, remoteKey ssh.PublicKey) error {
|
||||
// Algorithm => key.
|
||||
knownKeys := map[string]KnownKey{}
|
||||
for _, l := range db.lines {
|
||||
if l.match(addrs) {
|
||||
if l.match(a) {
|
||||
typ := l.knownKey.Key.Type()
|
||||
if _, ok := knownKeys[typ]; !ok {
|
||||
knownKeys[typ] = l.knownKey
|
||||
@@ -414,7 +410,10 @@ func (db *hostKeyDB) Read(r io.Reader, filename string) error {
|
||||
|
||||
// New creates a host key callback from the given OpenSSH host key
|
||||
// files. The returned callback is for use in
|
||||
// ssh.ClientConfig.HostKeyCallback.
|
||||
// ssh.ClientConfig.HostKeyCallback. By preference, the key check
|
||||
// operates on the hostname if available, i.e. if a server changes its
|
||||
// IP address, the host key check will still succeed, even though a
|
||||
// record of the new IP address is not available.
|
||||
func New(files ...string) (ssh.HostKeyCallback, error) {
|
||||
db := newHostKeyDB()
|
||||
for _, fn := range files {
|
||||
@@ -536,11 +535,6 @@ func newHashedHost(encoded string) (*hashedHost, error) {
|
||||
return &hashedHost{salt: salt, hash: hash}, nil
|
||||
}
|
||||
|
||||
func (h *hashedHost) match(addrs []addr) bool {
|
||||
for _, a := range addrs {
|
||||
if bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (h *hashedHost) match(a addr) bool {
|
||||
return bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash)
|
||||
}
|
||||
|
29
vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts_test.go
generated
vendored
29
vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts_test.go
generated
vendored
@@ -166,7 +166,7 @@ func TestBasic(t *testing.T) {
|
||||
str := fmt.Sprintf("#comment\n\nserver.org,%s %s\notherhost %s", testAddr, edKeyStr, ecKeyStr)
|
||||
db := testDB(t, str)
|
||||
if err := db.check("server.org:22", testAddr, edKey); err != nil {
|
||||
t.Errorf("got error %q, want none", err)
|
||||
t.Errorf("got error %v, want none", err)
|
||||
}
|
||||
|
||||
want := KnownKey{
|
||||
@@ -185,6 +185,33 @@ func TestBasic(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostNamePrecedence(t *testing.T) {
|
||||
var evilAddr = &net.TCPAddr{
|
||||
IP: net.IP{66, 66, 66, 66},
|
||||
Port: 22,
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("server.org,%s %s\nevil.org,%s %s", testAddr, edKeyStr, evilAddr, ecKeyStr)
|
||||
db := testDB(t, str)
|
||||
|
||||
if err := db.check("server.org:22", evilAddr, ecKey); err == nil {
|
||||
t.Errorf("check succeeded")
|
||||
} else if _, ok := err.(*KeyError); !ok {
|
||||
t.Errorf("got %T, want *KeyError", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDBOrderingPrecedenceKeyType(t *testing.T) {
|
||||
str := fmt.Sprintf("server.org,%s %s\nserver.org,%s %s", testAddr, edKeyStr, testAddr, alternateEdKeyStr)
|
||||
db := testDB(t, str)
|
||||
|
||||
if err := db.check("server.org:22", testAddr, alternateEdKey); err == nil {
|
||||
t.Errorf("check succeeded")
|
||||
} else if _, ok := err.(*KeyError); !ok {
|
||||
t.Errorf("got %T, want *KeyError", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegate(t *testing.T) {
|
||||
str := fmt.Sprintf("%s,!server.org %s", testAddr, edKeyStr)
|
||||
db := testDB(t, str)
|
||||
|
6
vendor/golang.org/x/crypto/ssh/mux_test.go
generated
vendored
6
vendor/golang.org/x/crypto/ssh/mux_test.go
generated
vendored
@@ -20,7 +20,7 @@ func muxPair() (*mux, *mux) {
|
||||
return s, c
|
||||
}
|
||||
|
||||
// Returns both ends of a channel, and the mux for the the 2nd
|
||||
// Returns both ends of a channel, and the mux for the 2nd
|
||||
// channel.
|
||||
func channelPair(t *testing.T) (*channel, *channel, *mux) {
|
||||
c, s := muxPair()
|
||||
@@ -108,10 +108,6 @@ func TestMuxReadWrite(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Write: %v", err)
|
||||
}
|
||||
err = s.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Close: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var buf [1024]byte
|
||||
|
24
vendor/golang.org/x/crypto/ssh/server.go
generated
vendored
24
vendor/golang.org/x/crypto/ssh/server.go
generated
vendored
@@ -166,6 +166,9 @@ type ServerConn struct {
|
||||
// unsuccessful, it closes the connection and returns an error. The
|
||||
// Request and NewChannel channels must be serviced, or the connection
|
||||
// will hang.
|
||||
//
|
||||
// The returned error may be of type *ServerAuthError for
|
||||
// authentication errors.
|
||||
func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
|
||||
fullConf := *config
|
||||
fullConf.SetDefaults()
|
||||
@@ -292,12 +295,13 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
|
||||
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
|
||||
}
|
||||
|
||||
// ServerAuthError implements the error interface. It appends any authentication
|
||||
// errors that may occur, and is returned if all of the authentication methods
|
||||
// provided by the user failed to authenticate.
|
||||
// ServerAuthError represents server authentication errors and is
|
||||
// sometimes returned by NewServerConn. It appends any authentication
|
||||
// errors that may occur, and is returned if all of the authentication
|
||||
// methods provided by the user failed to authenticate.
|
||||
type ServerAuthError struct {
|
||||
// Errors contains authentication errors returned by the authentication
|
||||
// callback methods.
|
||||
// callback methods. The first entry is typically ErrNoAuth.
|
||||
Errors []error
|
||||
}
|
||||
|
||||
@@ -309,6 +313,13 @@ func (l ServerAuthError) Error() string {
|
||||
return "[" + strings.Join(errs, ", ") + "]"
|
||||
}
|
||||
|
||||
// ErrNoAuth is the error value returned if no
|
||||
// authentication method has been passed yet. This happens as a normal
|
||||
// part of the authentication loop, since the client first tries
|
||||
// 'none' authentication to discover available methods.
|
||||
// It is returned in ServerAuthError.Errors from NewServerConn.
|
||||
var ErrNoAuth = errors.New("ssh: no auth passed yet")
|
||||
|
||||
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
|
||||
sessionID := s.transport.getSessionID()
|
||||
var cache pubKeyCache
|
||||
@@ -363,7 +374,7 @@ userAuthLoop:
|
||||
}
|
||||
|
||||
perms = nil
|
||||
authErr := errors.New("no auth passed yet")
|
||||
authErr := ErrNoAuth
|
||||
|
||||
switch userAuthReq.Method {
|
||||
case "none":
|
||||
@@ -393,7 +404,7 @@ userAuthLoop:
|
||||
perms, authErr = config.PasswordCallback(s, password)
|
||||
case "keyboard-interactive":
|
||||
if config.KeyboardInteractiveCallback == nil {
|
||||
authErr = errors.New("ssh: keyboard-interactive auth not configubred")
|
||||
authErr = errors.New("ssh: keyboard-interactive auth not configured")
|
||||
break
|
||||
}
|
||||
|
||||
@@ -473,6 +484,7 @@ userAuthLoop:
|
||||
// sig.Format. This is usually the same, but
|
||||
// for certs, the names differ.
|
||||
if !isAcceptableAlgo(sig.Format) {
|
||||
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
|
||||
break
|
||||
}
|
||||
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData)
|
||||
|
1
vendor/golang.org/x/crypto/ssh/streamlocal.go
generated
vendored
1
vendor/golang.org/x/crypto/ssh/streamlocal.go
generated
vendored
@@ -32,6 +32,7 @@ type streamLocalChannelForwardMsg struct {
|
||||
|
||||
// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
|
||||
func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
|
||||
c.handleForwardsOnce.Do(c.handleForwards)
|
||||
m := streamLocalChannelForwardMsg{
|
||||
socketPath,
|
||||
}
|
||||
|
9
vendor/golang.org/x/crypto/ssh/tcpip.go
generated
vendored
9
vendor/golang.org/x/crypto/ssh/tcpip.go
generated
vendored
@@ -90,10 +90,19 @@ type channelForwardMsg struct {
|
||||
rport uint32
|
||||
}
|
||||
|
||||
// handleForwards starts goroutines handling forwarded connections.
|
||||
// It's called on first use by (*Client).ListenTCP to not launch
|
||||
// goroutines until needed.
|
||||
func (c *Client) handleForwards() {
|
||||
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip"))
|
||||
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
|
||||
}
|
||||
|
||||
// ListenTCP requests the remote peer open a listening socket
|
||||
// on laddr. Incoming connections will be available by calling
|
||||
// Accept on the returned net.Listener.
|
||||
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
|
||||
c.handleForwardsOnce.Do(c.handleForwards)
|
||||
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
|
||||
return c.autoPortListenWorkaround(laddr)
|
||||
}
|
||||
|
4
vendor/golang.org/x/crypto/ssh/terminal/terminal.go
generated
vendored
4
vendor/golang.org/x/crypto/ssh/terminal/terminal.go
generated
vendored
@@ -159,6 +159,10 @@ func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
|
||||
return keyClearScreen, b[1:]
|
||||
case 23: // ^W
|
||||
return keyDeleteWord, b[1:]
|
||||
case 14: // ^N
|
||||
return keyDown, b[1:]
|
||||
case 16: // ^P
|
||||
return keyUp, b[1:]
|
||||
}
|
||||
}
|
||||
|
||||
|
14
vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
generated
vendored
14
vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
generated
vendored
@@ -2,12 +2,15 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd windows plan9 solaris
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -88,6 +91,12 @@ var keyPressTests = []struct {
|
||||
{
|
||||
in: "\x1b[B\r", // down
|
||||
},
|
||||
{
|
||||
in: "\016\r", // ^P
|
||||
},
|
||||
{
|
||||
in: "\014\r", // ^N
|
||||
},
|
||||
{
|
||||
in: "line\x1b[A\x1b[B\r", // up then down
|
||||
line: "line",
|
||||
@@ -324,6 +333,11 @@ func TestMakeRawState(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get terminal state from GetState: %s", err)
|
||||
}
|
||||
|
||||
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
|
||||
t.Skip("MakeRaw not allowed on iOS; skipping test")
|
||||
}
|
||||
|
||||
defer Restore(fd, st)
|
||||
raw, err := MakeRaw(fd)
|
||||
if err != nil {
|
||||
|
8
vendor/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
8
vendor/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
|
||||
// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd
|
||||
|
||||
// Package terminal provides support functions for dealing with terminals, as
|
||||
// commonly found on UNIX systems.
|
||||
@@ -25,7 +25,7 @@ type State struct {
|
||||
termios unix.Termios
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||
return err == nil
|
||||
@@ -108,9 +108,7 @@ func ReadPassword(fd int) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
|
||||
}()
|
||||
defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
|
||||
|
||||
return readPasswordLine(passwordReader(fd))
|
||||
}
|
||||
|
2
vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
generated
vendored
2
vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
generated
vendored
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
type State struct{}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
return false
|
||||
}
|
||||
|
38
vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
generated
vendored
38
vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
generated
vendored
@@ -14,10 +14,10 @@ import (
|
||||
|
||||
// State contains the state of a terminal.
|
||||
type State struct {
|
||||
state *unix.Termios
|
||||
termios unix.Termios
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
|
||||
return err == nil
|
||||
@@ -75,47 +75,43 @@ func ReadPassword(fd int) ([]byte, error) {
|
||||
// restored.
|
||||
// see http://cr.illumos.org/~webrev/andy_js/1060/
|
||||
func MakeRaw(fd int) (*State, error) {
|
||||
oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
termios, 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
|
||||
oldState := State{termios: *termios}
|
||||
|
||||
if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
|
||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||
termios.Oflag &^= unix.OPOST
|
||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||
termios.Cflag |= unix.CS8
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
|
||||
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &State{
|
||||
state: oldTermiosPtr,
|
||||
}, nil
|
||||
return &oldState, 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)
|
||||
return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
|
||||
}
|
||||
|
||||
// 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)
|
||||
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &State{
|
||||
state: oldTermiosPtr,
|
||||
}, nil
|
||||
return &State{termios: *termios}, nil
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
|
6
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
generated
vendored
6
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
generated
vendored
@@ -26,7 +26,7 @@ type State struct {
|
||||
mode uint32
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
var st uint32
|
||||
err := windows.GetConsoleMode(windows.Handle(fd), &st)
|
||||
@@ -89,9 +89,7 @@ func ReadPassword(fd int) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
windows.SetConsoleMode(windows.Handle(fd), old)
|
||||
}()
|
||||
defer windows.SetConsoleMode(windows.Handle(fd), old)
|
||||
|
||||
var h windows.Handle
|
||||
p, _ := windows.GetCurrentProcess()
|
||||
|
80
vendor/golang.org/x/crypto/ssh/test/test_unix_test.go
generated
vendored
80
vendor/golang.org/x/crypto/ssh/test/test_unix_test.go
generated
vendored
@@ -10,6 +10,8 @@ package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@@ -25,7 +27,8 @@ import (
|
||||
"golang.org/x/crypto/ssh/testdata"
|
||||
)
|
||||
|
||||
const sshdConfig = `
|
||||
const (
|
||||
defaultSshdConfig = `
|
||||
Protocol 2
|
||||
Banner {{.Dir}}/banner
|
||||
HostKey {{.Dir}}/id_rsa
|
||||
@@ -50,8 +53,17 @@ RhostsRSAAuthentication no
|
||||
HostbasedAuthentication no
|
||||
PubkeyAcceptedKeyTypes=*
|
||||
`
|
||||
multiAuthSshdConfigTail = `
|
||||
UsePAM yes
|
||||
PasswordAuthentication yes
|
||||
ChallengeResponseAuthentication yes
|
||||
AuthenticationMethods {{.AuthMethods}}
|
||||
`
|
||||
)
|
||||
|
||||
var configTmpl = template.Must(template.New("").Parse(sshdConfig))
|
||||
var configTmpl = map[string]*template.Template{
|
||||
"default": template.Must(template.New("").Parse(defaultSshdConfig)),
|
||||
"MultiAuth": template.Must(template.New("").Parse(defaultSshdConfig + multiAuthSshdConfigTail))}
|
||||
|
||||
type server struct {
|
||||
t *testing.T
|
||||
@@ -60,6 +72,10 @@ type server struct {
|
||||
cmd *exec.Cmd
|
||||
output bytes.Buffer // holds stderr from sshd process
|
||||
|
||||
testUser string // test username for sshd
|
||||
testPasswd string // test password for sshd
|
||||
sshdTestPwSo string // dynamic library to inject a custom password into sshd
|
||||
|
||||
// Client half of the network connection.
|
||||
clientConn net.Conn
|
||||
}
|
||||
@@ -186,6 +202,20 @@ func (s *server) TryDialWithAddr(config *ssh.ClientConfig, addr string) (*ssh.Cl
|
||||
s.cmd.Stdin = f
|
||||
s.cmd.Stdout = f
|
||||
s.cmd.Stderr = &s.output
|
||||
|
||||
if s.sshdTestPwSo != "" {
|
||||
if s.testUser == "" {
|
||||
s.t.Fatal("user missing from sshd_test_pw.so config")
|
||||
}
|
||||
if s.testPasswd == "" {
|
||||
s.t.Fatal("password missing from sshd_test_pw.so config")
|
||||
}
|
||||
s.cmd.Env = append(os.Environ(),
|
||||
fmt.Sprintf("LD_PRELOAD=%s", s.sshdTestPwSo),
|
||||
fmt.Sprintf("TEST_USER=%s", s.testUser),
|
||||
fmt.Sprintf("TEST_PASSWD=%s", s.testPasswd))
|
||||
}
|
||||
|
||||
if err := s.cmd.Start(); err != nil {
|
||||
s.t.Fail()
|
||||
s.Shutdown()
|
||||
@@ -236,11 +266,49 @@ func writeFile(path string, contents []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// generate random password
|
||||
func randomPassword() (string, error) {
|
||||
b := make([]byte, 12)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
// setTestPassword is used for setting user and password data for sshd_test_pw.so
|
||||
// This function also checks that ./sshd_test_pw.so exists and if not calls s.t.Skip()
|
||||
func (s *server) setTestPassword(user, passwd string) error {
|
||||
wd, _ := os.Getwd()
|
||||
wrapper := filepath.Join(wd, "sshd_test_pw.so")
|
||||
if _, err := os.Stat(wrapper); err != nil {
|
||||
s.t.Skip(fmt.Errorf("sshd_test_pw.so is not available"))
|
||||
return err
|
||||
}
|
||||
|
||||
s.sshdTestPwSo = wrapper
|
||||
s.testUser = user
|
||||
s.testPasswd = passwd
|
||||
return nil
|
||||
}
|
||||
|
||||
// newServer returns a new mock ssh server.
|
||||
func newServer(t *testing.T) *server {
|
||||
return newServerForConfig(t, "default", map[string]string{})
|
||||
}
|
||||
|
||||
// newServerForConfig returns a new mock ssh server.
|
||||
func newServerForConfig(t *testing.T, config string, configVars map[string]string) *server {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test due to -short")
|
||||
}
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
t.Fatalf("user.Current: %v", err)
|
||||
}
|
||||
if u.Name == "root" {
|
||||
t.Skip("skipping test because current user is root")
|
||||
}
|
||||
dir, err := ioutil.TempDir("", "sshtest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -249,9 +317,11 @@ func newServer(t *testing.T) *server {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = configTmpl.Execute(f, map[string]string{
|
||||
"Dir": dir,
|
||||
})
|
||||
if _, ok := configTmpl[config]; ok == false {
|
||||
t.Fatal(fmt.Errorf("Invalid server config '%s'", config))
|
||||
}
|
||||
configVars["Dir"] = dir
|
||||
err = configTmpl[config].Execute(f, configVars)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
31
vendor/golang.org/x/crypto/ssh/testdata/keys.go
generated
vendored
31
vendor/golang.org/x/crypto/ssh/testdata/keys.go
generated
vendored
@@ -60,6 +60,35 @@ NDvRS0rjwt6lJGv7zPZoqDc65VfrK2aNyHx2PgFyzwrEOtuF57bu7pnvEIxpLTeM
|
||||
z26i6XVMeYXAWZMTloMCQBbpGgEERQpeUknLBqUHhg/wXF6+lFA+vEGnkY+Dwab2
|
||||
KCXFGd+SQ5GdUcEMe9isUH6DYj/6/yCDoFrXXmpQb+M=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`),
|
||||
"pkcs8": []byte(`-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCitzS2KiRQTccf
|
||||
VApb0mbPpo1lt29JjeLBYAehXHWfQ+w8sXpd8e04n/020spx1R94yg+v0NjXyh2R
|
||||
NFXNBYdhNei33VJxUeKNlExaecvW2yxfuZqka+ZxT1aI8zrAsjh3Rwc6wayAJS4R
|
||||
wZuzlDv4jZitWqwD+mb/22Zwq/WSs4YX5dUHDklfdWSVnoBfue8K/00n8f5yMTdJ
|
||||
vFF0qAJwf9spPEHla0lYcozJk64CO5lRkqfLor4UnsXXOiA7aRIoaUSKa+rlhiqt
|
||||
1EMGYiBjblPt4SwMelGGU2UfywPb4d85gpQ/s8SBARbpPxNVs2IbHDMwj70P3uZc
|
||||
74M3c4VJAgMBAAECggEAFIzY3mziGzZHgMBncoNXMsCRORh6uKpvygZr0EhSHqRA
|
||||
cMXlc3n7gNxL6aGjqc7F48Z5RrY0vMQtCcq3T2Z0W6WoV5hfMiqqV0E0h3S8ds1F
|
||||
hG13h26NMyBXCILXl8Cqev4Afr45IBISCHIQTRTaoiCX+MTr1rDIU2YNQQumvzkz
|
||||
fMw2XiFTFTgxAtJUAgKoTqLtm7/T+az7TKw+Hesgbx7yaJoMh9DWGBh4Y61DnIDA
|
||||
fcxJboAfxxnFiXvdBVmzo72pCsRXrWOsjW6WxQmCKuXHvyB1FZTmMaEFNCGSJDa6
|
||||
U+OCzA3m65loAZAE7ffFHhYgssz/h9TBaOjKO0BX1QKBgQDZiCBvu+bFh9pEodcS
|
||||
VxaI+ATlsYcmGdLtnZw5pxuEdr60iNWhpEcV6lGkbdiv5aL43QaGFDLagqeHI77b
|
||||
+ITFbPPdCiYNaqlk6wyiXv4pdN7V683EDmGWSQlPeC9IhUilt2c+fChK2EB/XlkO
|
||||
q8c3Vk1MsC6JOxDXNgJxylNpswKBgQC/fYBTb9iD+uM2n3SzJlct/ZlPaONKnNDR
|
||||
pbTOdxBFHsu2VkfY858tfnEPkmSRX0yKmjHni6e8/qIzfzLwWBY4NmxhNZE5v+qJ
|
||||
qZF26ULFdrZB4oWXAOliy/1S473OpQnp2MZp2asd0LPcg/BNaMuQrz44hxHb76R7
|
||||
qWD0ebIfEwKBgQCRCIiP1pjbVGN7ZOgPS080DSC+wClahtcyI+ZYLglTvRQTLDQ7
|
||||
LFtUykCav748MIADKuJBnM/3DiuCF5wV71EejDDfS/fo9BdyuKBY1brhixFTUX+E
|
||||
Ww5Hc/SoLnpgALVZ/7jvWTpIBHykLxRziqYtR/YLzl+IkX/97P2ePoZ0rwKBgHNC
|
||||
/7M5Z4JJyepfIMeVFHTCaT27TNTkf20x6Rs937U7TDN8y9JzEiU4LqXI4HAAhPoI
|
||||
xnExRs4kF04YCnlRDE7Zs3Lv43J3ap1iTATfcymYwyv1RaQXEGQ/lUQHgYCZJtZz
|
||||
fTrJoo5XyWu6nzJ5Gc8FLNaptr5ECSXGVm3Rsr2xAoGBAJWqEEQS/ejhO05QcPqh
|
||||
y4cUdLr0269ILVsvic4Ot6zgfPIntXAK6IsHGKcg57kYm6W9k1CmmlA4ENGryJnR
|
||||
vxyyqA9eyTFc1CQNuc2frKFA9It49JzjXahKc0aDHEHmTR787Tmk1LbuT0/gm9kA
|
||||
L4INU6g+WqF0fatJxd+IJPrp
|
||||
-----END PRIVATE KEY-----
|
||||
`),
|
||||
"ed25519": []byte(`-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
@@ -126,7 +155,7 @@ var SSHCertificates = map[string][]byte{
|
||||
// Generated by the following commands:
|
||||
//
|
||||
// 1. Assumes "rsa" key above in file named "rsa", write out the public key to "rsa.pub":
|
||||
// ssh-keygen -y -f rsa > rsa.pu
|
||||
// ssh-keygen -y -f rsa > rsa.pub
|
||||
//
|
||||
// 2. Assumes "ca" key above in file named "ca", sign a cert for "rsa.pub":
|
||||
// ssh-keygen -s ca -h -n host.example.com -V +500w -I host.example.com-key rsa.pub
|
||||
|
Reference in New Issue
Block a user