diff --git a/ssh/client.go b/ssh/client.go index e607610..72bd27f 100644 --- a/ssh/client.go +++ b/ssh/client.go @@ -105,6 +105,10 @@ func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) e } else if packet[0] != msgNewKeys { return unexpectedMessageError(msgNewKeys, packet[0]) } + + // We just did the key change, so the session ID is established. + c.sessionID = c.transport.getSessionID() + return c.clientAuthenticate(config) } diff --git a/ssh/server.go b/ssh/server.go index ee2eeab..52aee11 100644 --- a/ssh/server.go +++ b/ssh/server.go @@ -192,6 +192,9 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) return nil, unexpectedMessageError(msgNewKeys, packet[0]) } + // We just did the key change, so the session ID is established. + s.sessionID = s.transport.getSessionID() + var packet []byte if packet, err = s.transport.readPacket(); err != nil { return nil, err diff --git a/ssh/session_test.go b/ssh/session_test.go index fce9868..88e66bf 100644 --- a/ssh/session_test.go +++ b/ssh/session_test.go @@ -626,3 +626,55 @@ func simpleEchoHandler(ch Channel, in <-chan *Request, t *testing.T) { t.Errorf("handler write error: %v", err) } } + +func TestSessionID(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverID := make(chan []byte, 1) + clientID := make(chan []byte, 1) + + serverConf := &ServerConfig{ + NoClientAuth: true, + } + serverConf.AddHostKey(testSigners["ecdsa"]) + clientConf := &ClientConfig{ + User: "user", + } + + go func() { + conn, chans, reqs, err := NewServerConn(c1, serverConf) + if err != nil { + t.Fatalf("server handshake: %v", err) + } + serverID <- conn.SessionID() + go DiscardRequests(reqs) + for ch := range chans { + ch.Reject(Prohibited, "") + } + }() + + go func() { + conn, chans, reqs, err := NewClientConn(c2, "", clientConf) + if err != nil { + t.Fatalf("client handshake: %v", err) + } + clientID <- conn.SessionID() + go DiscardRequests(reqs) + for ch := range chans { + ch.Reject(Prohibited, "") + } + }() + + s := <-serverID + c := <-clientID + if bytes.Compare(s, c) != 0 { + t.Errorf("server session ID (%x) != client session ID (%x)", s, c) + } else if len(s) == 0 { + t.Errorf("client and server SessionID were empty.") + } +} diff --git a/ssh/transport.go b/ssh/transport.go index 4f68b04..0f19478 100644 --- a/ssh/transport.go +++ b/ssh/transport.go @@ -44,13 +44,13 @@ type transport struct { sessionID []byte } +// getSessionID returns the ID of the SSH connection. The return value +// should not be modified. func (t *transport) getSessionID() []byte { if t.sessionID == nil { panic("session ID not set yet") } - s := make([]byte, len(t.sessionID)) - copy(s, t.sessionID) - return s + return t.sessionID } // packetCipher represents a combination of SSH encryption/MAC