diff --git a/ssh/agent.go b/ssh/agent.go deleted file mode 100644 index a91da34..0000000 --- a/ssh/agent.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2012 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. - -package ssh - -import ( - "encoding/base64" - "errors" - "io" - "sync" -) - -// See [PROTOCOL.agent], section 3. -const ( - // 3.2 Requests from client to agent for protocol 2 key operations - agentRequestIdentities = 11 - agentSignRequest = 13 - agentAddIdentity = 17 - agentRemoveIdentity = 18 - agentRemoveAllIdentities = 19 - agentAddIdConstrained = 25 - - // 3.3 Key-type independent requests from client to agent - agentAddSmartcardKey = 20 - agentRemoveSmartcardKey = 21 - agentLock = 22 - agentUnlock = 23 - agentAddSmartcardKeyConstrained = 26 - - // 3.4 Generic replies from agent to client - agentFailure = 5 - agentSuccess = 6 - - // 3.6 Replies from agent to client for protocol 2 key operations - agentIdentitiesAnswer = 12 - agentSignResponse = 14 - - // 3.7 Key constraint identifiers - agentConstrainLifetime = 1 - agentConstrainConfirm = 2 -) - -// maxAgentResponseBytes is the maximum agent reply size that is accepted. This -// is a sanity check, not a limit in the spec. -const maxAgentResponseBytes = 16 << 20 - -// Agent messages: -// These structures mirror the wire format of the corresponding ssh agent -// messages found in [PROTOCOL.agent]. - -type failureAgentMsg struct{} - -type successAgentMsg struct{} - -// See [PROTOCOL.agent], section 2.5.2. -type requestIdentitiesAgentMsg struct{} - -// See [PROTOCOL.agent], section 2.5.2. -type identitiesAnswerAgentMsg struct { - NumKeys uint32 - Keys []byte `ssh:"rest"` -} - -// See [PROTOCOL.agent], section 2.6.2. -type signRequestAgentMsg struct { - KeyBlob []byte - Data []byte - Flags uint32 -} - -// See [PROTOCOL.agent], section 2.6.2. -type signResponseAgentMsg struct { - SigBlob []byte -} - -// AgentKey represents a protocol 2 key as defined in [PROTOCOL.agent], -// section 2.5.2. -type AgentKey struct { - blob []byte - Comment string -} - -// String returns the storage form of an agent key with the format, base64 -// encoded serialized key, and the comment if it is not empty. -func (ak *AgentKey) String() string { - algo, _, ok := parseString(ak.blob) - if !ok { - return "ssh: malformed key" - } - - s := string(algo) + " " + base64.StdEncoding.EncodeToString(ak.blob) - - if ak.Comment != "" { - s += " " + ak.Comment - } - - return s -} - -// Key returns an agent's public key as one of the supported key or certificate types. -func (ak *AgentKey) Key() (PublicKey, error) { - if key, _, ok := ParsePublicKey(ak.blob); ok { - return key, nil - } - return nil, errors.New("ssh: failed to parse key blob") -} - -func parseAgentKey(in []byte) (out *AgentKey, rest []byte, ok bool) { - ak := new(AgentKey) - - if ak.blob, in, ok = parseString(in); !ok { - return - } - - comment, in, ok := parseString(in) - if !ok { - return - } - ak.Comment = string(comment) - - return ak, in, true -} - -// AgentClient provides a means to communicate with an ssh agent process based -// on the protocol described in [PROTOCOL.agent]?rev=1.6. -type AgentClient struct { - // conn is typically represented by using a *net.UnixConn - conn io.ReadWriter - // mu is used to prevent concurrent access to the agent - mu sync.Mutex -} - -// NewAgentClient creates and returns a new *AgentClient using the -// passed in io.ReadWriter as a connection to a ssh agent. -func NewAgentClient(rw io.ReadWriter) *AgentClient { - return &AgentClient{conn: rw} -} - -// sendAndReceive sends req to the agent and waits for a reply. On success, -// the reply is unmarshaled into reply and replyType is set to the first byte of -// the reply, which contains the type of the message. -func (ac *AgentClient) sendAndReceive(req []byte) (reply interface{}, replyType uint8, err error) { - // ac.mu prevents multiple, concurrent requests. Since the agent is typically - // on the same machine, we don't attempt to pipeline the requests. - ac.mu.Lock() - defer ac.mu.Unlock() - - msg := make([]byte, stringLength(len(req))) - marshalString(msg, req) - if _, err = ac.conn.Write(msg); err != nil { - return - } - - var respSizeBuf [4]byte - if _, err = io.ReadFull(ac.conn, respSizeBuf[:]); err != nil { - return - } - respSize, _, _ := parseUint32(respSizeBuf[:]) - - if respSize > maxAgentResponseBytes { - err = errors.New("ssh: agent reply too large") - return - } - - buf := make([]byte, respSize) - if _, err = io.ReadFull(ac.conn, buf); err != nil { - return - } - return unmarshalAgentMsg(buf) -} - -// RequestIdentities queries the agent for protocol 2 keys as defined in -// [PROTOCOL.agent] section 2.5.2. -func (ac *AgentClient) RequestIdentities() ([]*AgentKey, error) { - req := marshal(agentRequestIdentities, requestIdentitiesAgentMsg{}) - - msg, msgType, err := ac.sendAndReceive(req) - if err != nil { - return nil, err - } - - switch msg := msg.(type) { - case *identitiesAnswerAgentMsg: - if msg.NumKeys > maxAgentResponseBytes/8 { - return nil, errors.New("ssh: too many keys in agent reply") - } - keys := make([]*AgentKey, msg.NumKeys) - data := msg.Keys - for i := uint32(0); i < msg.NumKeys; i++ { - var key *AgentKey - var ok bool - if key, data, ok = parseAgentKey(data); !ok { - return nil, ParseError{agentIdentitiesAnswer} - } - keys[i] = key - } - return keys, nil - case *failureAgentMsg: - return nil, errors.New("ssh: failed to list keys") - } - return nil, UnexpectedMessageError{agentIdentitiesAnswer, msgType} -} - -// SignRequest requests the signing of data by the agent using a protocol 2 key -// as defined in [PROTOCOL.agent] section 2.6.2. -func (ac *AgentClient) SignRequest(key PublicKey, data []byte) ([]byte, error) { - req := marshal(agentSignRequest, signRequestAgentMsg{ - KeyBlob: MarshalPublicKey(key), - Data: data, - }) - - msg, msgType, err := ac.sendAndReceive(req) - if err != nil { - return nil, err - } - - switch msg := msg.(type) { - case *signResponseAgentMsg: - return msg.SigBlob, nil - case *failureAgentMsg: - return nil, errors.New("ssh: failed to sign challenge") - } - return nil, UnexpectedMessageError{agentSignResponse, msgType} -} - -// unmarshalAgentMsg parses an agent message in packet, returning the parsed -// form and the message type of packet. -func unmarshalAgentMsg(packet []byte) (interface{}, uint8, error) { - if len(packet) < 1 { - return nil, 0, ParseError{0} - } - var msg interface{} - switch packet[0] { - case agentFailure: - msg = new(failureAgentMsg) - case agentSuccess: - msg = new(successAgentMsg) - case agentIdentitiesAnswer: - msg = new(identitiesAnswerAgentMsg) - case agentSignResponse: - msg = new(signResponseAgentMsg) - default: - return nil, 0, UnexpectedMessageError{0, packet[0]} - } - if err := unmarshal(msg, packet, packet[0]); err != nil { - return nil, 0, err - } - return msg, packet[0], nil -} diff --git a/ssh/common_test.go b/ssh/common_test.go deleted file mode 100644 index d9df56f..0000000 --- a/ssh/common_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2011 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. - -package ssh - -import ( - "io" - "net" - "testing" -) - -func TestSafeString(t *testing.T) { - strings := map[string]string{ - "\x20\x0d\x0a": "\x20\x0d\x0a", - "flibble": "flibble", - "new\x20line": "new\x20line", - "123456\x07789": "123456 789", - "\t\t\x10\r\n": "\t\t \r\n", - } - - for s, expected := range strings { - actual := safeString(s) - if expected != actual { - t.Errorf("expected: %v, actual: %v", []byte(expected), []byte(actual)) - } - } -} - -// Make sure Read/Write are not exposed. -func TestConnHideRWMethods(t *testing.T) { - for _, c := range []interface{}{new(ServerConn), new(ClientConn)} { - if _, ok := c.(io.Reader); ok { - t.Errorf("%T implements io.Reader", c) - } - if _, ok := c.(io.Writer); ok { - t.Errorf("%T implements io.Writer", c) - } - } -} - -func TestConnSupportsLocalRemoteMethods(t *testing.T) { - type LocalAddr interface { - LocalAddr() net.Addr - } - type RemoteAddr interface { - RemoteAddr() net.Addr - } - for _, c := range []interface{}{new(ServerConn), new(ClientConn)} { - if _, ok := c.(LocalAddr); !ok { - t.Errorf("%T does not implement LocalAddr", c) - } - if _, ok := c.(RemoteAddr); !ok { - t.Errorf("%T does not implement RemoteAddr", c) - } - } -} diff --git a/ssh/server_terminal.go b/ssh/server_terminal.go deleted file mode 100644 index 708a915..0000000 --- a/ssh/server_terminal.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2011 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. - -package ssh - -// A Terminal is capable of parsing and generating virtual terminal -// data from an SSH client. -type Terminal interface { - ReadLine() (line string, err error) - SetSize(x, y int) - Write([]byte) (int, error) -} - -// ServerTerminal contains the state for running a terminal that is capable of -// reading lines of input. -type ServerTerminal struct { - Term Terminal - Channel Channel -} - -// parsePtyRequest parses the payload of the pty-req message and extracts the -// dimensions of the terminal. See RFC 4254, section 6.2. -func parsePtyRequest(s []byte) (width, height int, ok bool) { - _, s, ok = parseString(s) - if !ok { - return - } - width32, s, ok := parseUint32(s) - if !ok { - return - } - height32, _, ok := parseUint32(s) - width = int(width32) - height = int(height32) - if width < 1 { - ok = false - } - if height < 1 { - ok = false - } - return -} - -func (ss *ServerTerminal) Write(buf []byte) (n int, err error) { - return ss.Term.Write(buf) -} - -// ReadLine returns a line of input from the terminal. -func (ss *ServerTerminal) ReadLine() (line string, err error) { - for { - if line, err = ss.Term.ReadLine(); err == nil { - return - } - - req, ok := err.(ChannelRequest) - if !ok { - return - } - - ok = false - switch req.Request { - case "pty-req": - var width, height int - width, height, ok = parsePtyRequest(req.Payload) - ss.Term.SetSize(width, height) - case "shell": - ok = true - if len(req.Payload) > 0 { - // We don't accept any commands, only the default shell. - ok = false - } - case "env": - ok = true - } - if req.WantReply { - ss.Channel.AckRequest(ok) - } - } - panic("unreachable") -} diff --git a/ssh/test/keys_test.go b/ssh/test/keys_test.go deleted file mode 100644 index b116422..0000000 --- a/ssh/test/keys_test.go +++ /dev/null @@ -1,246 +0,0 @@ -package test - -import ( - "reflect" - "strings" - "testing" - - "code.google.com/p/go.crypto/ssh" -) - -var ( - validKey = `AAAAB3NzaC1yc2EAAAADAQABAAABAQDEX/dPu4PmtvgK3La9zioCEDrJ` + - `yUr6xEIK7Pr+rLgydcqWTU/kt7w7gKjOw4vvzgHfjKl09CWyvgb+y5dCiTk` + - `9MxI+erGNhs3pwaoS+EavAbawB7iEqYyTep3YaJK+4RJ4OX7ZlXMAIMrTL+` + - `UVrK89t56hCkFYaAgo3VY+z6rb/b3bDBYtE1Y2tS7C3au73aDgeb9psIrSV` + - `86ucKBTl5X62FnYiyGd++xCnLB6uLximM5OKXfLzJQNS/QyZyk12g3D8y69` + - `Xw1GzCSKX1u1+MQboyf0HJcG2ryUCLHdcDVppApyHx2OLq53hlkQ/yxdflD` + - `qCqAE4j+doagSsIfC1T2T` - - authWithOptions = []string{ - `# comments to ignore before any keys...`, - ``, - `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + validKey + ` user@host`, - `# comments to ignore, along with a blank line`, - ``, - `env="HOME=/home/root2" ssh-rsa ` + validKey + ` user2@host2`, - ``, - `# more comments, plus a invalid entry`, - `ssh-rsa data-that-will-not-parse user@host3`, - } - - authOptions = strings.Join(authWithOptions, "\n") - authWithCRLF = strings.Join(authWithOptions, "\r\n") - authInvalid = []byte(`ssh-rsa`) - authWithQuotedCommaInEnv = []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + validKey + ` user@host`) - authWithQuotedSpaceInEnv = []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + validKey + ` user@host`) - authWithQuotedQuoteInEnv = []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + validKey + ` user@host`) - - authWithDoubleQuotedQuote = []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + validKey + "\t" + `user@host`) - authWithInvalidSpace = []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + validKey + ` user@host -#more to follow but still no valid keys`) - authWithMissingQuote = []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + validKey + ` user@host -env="HOME=/home/root",shared-control ssh-rsa ` + validKey + ` user@host`) - - testClientPrivateKey = `-----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAxF/3T7uD5rb4Cty2vc4qAhA6yclK+sRCCuz6/qy4MnXKlk1P -5Le8O4CozsOL784B34ypdPQlsr4G/suXQok5PTMSPnqxjYbN6cGqEvhGrwG2sAe4 -hKmMk3qd2GiSvuESeDl+2ZVzACDK0y/lFayvPbeeoQpBWGgIKN1WPs+q2/292wwW -LRNWNrUuwt2ru92g4Hm/abCK0lfOrnCgU5eV+thZ2IshnfvsQpyweri8YpjOTil3 -y8yUDUv0MmcpNdoNw/MuvV8NRswkil9btfjEG6Mn9ByXBtq8lAix3XA1aaQKch8d -ji6ud4ZZEP8sXX5Q6gqgBOI/naGoErCHwtU9kwIDAQABAoIBAFJRKAp0QEZmTHPB -MZk+4r0asIoFpziXLFgIHu7C2DPOzK1Umzj1DCKlPB3wOqi7Ym2jOSWdcnAK2EPW -dAGgJC5TSkKGjAcXixmB5RkumfKidUI0+lQh/puTurcMnvcEwglDkLkEvMBA/sSo -Pw9m486rOgOnmNzGPyViItURmD2+0yDdLl/vOsO/L1p76GCd0q0J3LqnmsQmawi7 -Zwj2Stm6BIrggG5GsF204Iet5219TYLo4g1Qb2AlJ9C8P1FtAWhMwJalDxH9Os2/ -KCDjnaq5n3bXbIU+3QjskjeVXL/Fnbhjnh4zs1EA7eHzl9dCGbcZ2LOimo2PRo8q -wVQmz4ECgYEA9dhiu74TxRVoaO5N2X+FsMzRO8gZdP3Z9IrV4jVN8WT4Vdp0snoF -gkVkqqbQUNKUb5K6B3Js/qNKfcjLbCNq9fewTcT6WsHQdtPbX/QA6Pa2Z29wrlA2 -wrIYaAkmVaHny7wsOmgX01aOnuf2MlUnksK43sjZHdIo/m+sDKwwY1cCgYEAzHx4 -mwUDMdRF4qpDKJhthraBNejRextNQQYsHVnNaMwZ4aeQcH5l85Cgjm7VpGlbVyBQ -h4zwFvllImp3D2U3mjVkV8Tm9ID98eWvw2YDzBnS3P3SysajD23Z+BXSG9GNv/8k -oAm+bVlvnJy4haK2AcIMk1YFuDuAOmy73abk7iUCgYEAj4qVM1sq/eKfAM1LJRfg -/jbIX+hYfMePD8pUUWygIra6jJ4tjtvSBZrwyPb3IImjY3W/KoP0AcVjxAeORohz -dkP1a6L8LiuFxSuzpdW5BkyuebxGhXCOWKVVvMDC4jLTPVCUXlHSv3GFemCjjgXM -QlNxT5rjsha4Gr8nLIsJAacCgYA4VA1Q/pd7sXKy1p37X8nD8yAyvnh+Be5I/C9I -woUP2jFC9MqYAmmJJ4ziz2swiAkuPeuQ+2Tjnz2ZtmQnrIUdiJmkh8vrDGFnshKx -q7deELsCPzVCwGcIiAUkDra7DQWUHu9y2lxHePyC0rUNst2aLF8UcvzOXC2danhx -vViQtQKBgCmZ7YavE/GNWww8N3xHBJ6UPmUuhQlnAbgNCcdyz30MevBg/JbyUTs2 -slftTH15QusJ1UoITnnZuFJ40LqDvh8UhiK09ffM/IbUx839/m2vUOdFZB/WNn9g -Cy0LzddU4KE8JZ/tlk68+hM5fjLLA0aqSunaql5CKfplwLu8x1hL ------END RSA PRIVATE KEY----- -` - keys = map[string]string{ - "ssh_host_dsa_key": `-----BEGIN DSA PRIVATE KEY----- -MIIBugIBAAKBgQDe2SIKvZdBp+InawtSXH0NotiMPhm3udyu4hh/E+icMz264kDX -v+sV7ddnSQGQWZ/eVU7Jtx29dCMD1VlFpEd7yGKzmdwJIeA+YquNWoqBRQEJsWWS -7Fsfvv83dA/DTNIQfOY3+TIs6Mb9vagbgQMU3JUWEhbLE9LCEU6UwwRlpQIVAL4p -JF83SwpE8Jx6KnDpR89npkl/AoGAAy00TdDnAXvStwrZiAFbjZi8xDmPa9WwpfhJ -Rkno45TthDLrS+WmqY8/LTwlqZdOBtoBAynMJfKkUiZM21lWWpL1hRKYdwBlIBy5 -XdR2/6wcPSuZ0tCQhDBTstX0Q3P1j198KGKvzy7q9vILKQwtSRqLS1y4JJERafdO -E+9CnGwCgYBz0WwBe2EZtGhGhBdnelTIBeo7PIsr0PzqxQj+dc8PBl8K9FfhRyOp -U39stUvoUxE9vaIFrY1P5xENjLFnPf+hlcuf40GUWEssW9YWPOaBp8afa9hY5Sxs -pvNR6eZFEFOJnx/ZgcA4g+vbrgGi5cM0W470mbGw2CkfJQUafdoIgAIUF+2I9kZe -2FTBuC9uacqczDlc+0k= ------END DSA PRIVATE KEY-----`, - "ssh_host_rsa_key": `-----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAuf76Ue2Wtae9oDtaS6rIJgO7iCFTsZUTW9LBsvx/2nli6jKU -d9tUbBRzgdbnRLJ32UljXhERuB/axlrX8/lBzUZ+oYiM0KkEEOXY1z/bcMxdRxGF -XHuf4uXvyC2XyA4+ZvBeS4j1QFyIHZ62o7gAlKMTjiek3B4AQEJAlCLmhH3jB8wc -K/IYXAOlNGM5G44/ZLQpTi8diOV6DLs7tJ7rtEQedOEJfZng5rwp0USFkqcbfDbe -9/hk0J32jZvOtZNBokYtBb4YEdIiWBzzNtHzU3Dzw61+TKVXaH5HaIvzL9iMrw9f -kJbJyogfZk9BJfemEN+xqP72jlhE8LXNhpTxFQIDAQABAoIBAHbdf+Y5+5XuNF6h -b8xpwW2h9whBnDYiOnP1VfroKWFbMB7R4lZS4joMO+FfkP8zOyqvHwTvza4pFWys -g9SUmDvy8FyVYsC7MzEFYzX0xm3o/Te898ip7P1Zy4rXsGeWysSImwqU5X+TYx3i -33/zyNM1APtZVJ+jwK9QZ+sD/uPuZK2yS03HGSMZq6ebdoOSaYhluKrxXllSLO1J -KJxDiDdy2lEFw0W8HcI3ly1lg6OI+TRqqaCcLVNF4fNJmYIFM+2VEI9BdgynIh0Q -pMZlJKgaEBcSqCymnTK81ohYD1cV4st2B0km3Sw35Rl04Ij5ITeiya3hp8VfE6UY -PljkA6UCgYEA4811FTFj+kzNZ86C4OW1T5sM4NZt8gcz6CSvVnl+bDzbEOMMyzP7 -2I9zKsR5ApdodH2m8d+RUw1Oe0bNGW5xig/DH/hn9lLQaO52JAi0we8A94dUUMSq -fUk9jKZEXpP/MlfTdJaPos9mxT7z8jREQxIiqH9AV0rLVDOCfDbSWj8CgYEA0QTE -IAUuki3UUqYKzLQrh/QmhY5KTx5amNW9XZ2VGtJvDPJrtBSBZlPEuXZAc4eBWEc7 -U3Y9QwsalzupU6Yi6+gmofaXs8xJnj+jKth1DnJvrbLLGlSmf2Ijnwt22TyFUOtt -UAknpjHutDjQPf7pUGWaCPgwwKFsdB8EBjpJF6sCgYAfXesBQAvEK08dPBJJZVfR -3kenrd71tIgxLtv1zETcIoUHjjv0vvOunhH9kZAYC0EWyTZzl5UrGmn0D4uuNMbt -e74iaNHn2P9Zc3xQ+eHp0j8P1lKFzI6tMaiH9Vz0qOw6wl0bcJ/WizhbcI+migvc -MGMVUHBLlMDqly0gbWwJgQKBgQCgtb9ut01FjANSwORQ3L8Tu3/a9Lrh9n7GQKFn -V4CLrP1BwStavOF5ojMCPo/zxF6JV8ufsqwL3n/FhFP/QyBarpb1tTqTPiHkkR2O -Ffx67TY9IdnUFv4lt3mYEiKBiW0f+MSF42Qe/wmAfKZw5IzUCirTdrFVi0huSGK5 -vxrwHQKBgHZ7RoC3I2f6F5fflA2ZAe9oJYC7XT624rY7VeOBwK0W0F47iV3euPi/ -pKvLIBLcWL1Lboo+girnmSZtIYg2iLS3b4T9VFcKWg0y4AVwmhMWe9jWIltfWAAX -9l0lNikMRGAx3eXudKXEtbGt3/cUzPVaQUHy5LiBxkxnFxgaJPXs ------END RSA PRIVATE KEY-----`, - "ssh_host_ecdsa_key": `-----BEGIN EC PRIVATE KEY----- -MHcCAQEEINGWx0zo6fhJ/0EAfrPzVFyFC9s18lBt3cRoEDhS3ARooAoGCCqGSM49 -AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+ -6/ZOXRnPmNAlLUqjShUsUBBngG0u2fqEqA== ------END EC PRIVATE KEY-----`, - "authorized_keys": `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEX/dPu4PmtvgK3La9zioCEDrJyUr6xEIK7Pr+rLgydcqWTU/kt7w7gKjOw4vvzgHfjKl09CWyvgb+y5dCiTk9MxI+erGNhs3pwaoS+EavAbawB7iEqYyTep3YaJK+4RJ4OX7ZlXMAIMrTL+UVrK89t56hCkFYaAgo3VY+z6rb/b3bDBYtE1Y2tS7C3au73aDgeb9psIrSV86ucKBTl5X62FnYiyGd++xCnLB6uLximM5OKXfLzJQNS/QyZyk12g3D8y69Xw1GzCSKX1u1+MQboyf0HJcG2ryUCLHdcDVppApyHx2OLq53hlkQ/yxdflDqCqAE4j+doagSsIfC1T2T user@host`, - } -) - -func TestMarshalParsePublicKey(t *testing.T) { - pub := getTestPublicKey(t) - - authKeys := ssh.MarshalAuthorizedKey(pub) - actualFields := strings.Fields(string(authKeys)) - if len(actualFields) == 0 { - t.Fatalf("failed authKeys: %v", authKeys) - } - - // drop the comment - expectedFields := strings.Fields(keys["authorized_keys"])[0:2] - - if !reflect.DeepEqual(actualFields, expectedFields) { - t.Errorf("got %v, expected %v", actualFields, expectedFields) - } - - actPub, _, _, _, ok := ssh.ParseAuthorizedKey([]byte(keys["authorized_keys"])) - if !ok { - t.Fatalf("cannot parse %v", keys["authorized_keys"]) - } - if !reflect.DeepEqual(actPub, pub) { - t.Errorf("got %v, expected %v", actPub, pub) - } -} - -type authResult struct { - pubKey interface{} //*rsa.PublicKey - options []string - comments string - rest string - ok bool -} - -func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) { - rest := authKeys - var values []authResult - for len(rest) > 0 { - var r authResult - r.pubKey, r.comments, r.options, rest, r.ok = ssh.ParseAuthorizedKey(rest) - r.rest = string(rest) - values = append(values, r) - } - - if !reflect.DeepEqual(values, expected) { - t.Errorf("got %q, expected %q", values, expected) - } - -} - -func getTestPublicKey(t *testing.T) ssh.PublicKey { - priv, err := ssh.ParsePrivateKey([]byte(testClientPrivateKey)) - if err != nil { - t.Fatalf("ParsePrivateKey: %v", err) - } - - return priv.PublicKey() -} - -func TestAuth(t *testing.T) { - pub := getTestPublicKey(t) - rest2 := strings.Join(authWithOptions[3:], "\n") - rest3 := strings.Join(authWithOptions[6:], "\n") - testAuthorizedKeys(t, []byte(authOptions), []authResult{ - {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}, - }) -} - -func TestAuthWithCRLF(t *testing.T) { - pub := getTestPublicKey(t) - rest2 := strings.Join(authWithOptions[3:], "\r\n") - rest3 := strings.Join(authWithOptions[6:], "\r\n") - testAuthorizedKeys(t, []byte(authWithCRLF), []authResult{ - {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}, - }) -} - -func TestAuthWithQuotedSpaceInEnv(t *testing.T) { - pub := getTestPublicKey(t) - testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{ - {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true}, - }) -} - -func TestAuthWithQuotedCommaInEnv(t *testing.T) { - pub := getTestPublicKey(t) - testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{ - {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true}, - }) -} - -func TestAuthWithQuotedQuoteInEnv(t *testing.T) { - pub := getTestPublicKey(t) - testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{ - {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true}, - }) - - testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{ - {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true}, - }) - -} - -func TestAuthWithInvalidSpace(t *testing.T) { - testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{ - {nil, nil, "", "", false}, - }) -} - -func TestAuthWithMissingQuote(t *testing.T) { - pub := getTestPublicKey(t) - testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{ - {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true}, - }) -} - -func TestInvalidEntry(t *testing.T) { - _, _, _, _, ok := ssh.ParseAuthorizedKey(authInvalid) - if ok { - t.Errorf("Expected invalid entry, returned valid entry") - } -}