summaryrefslogtreecommitdiffstats
path: root/libgo/go/exp/ssh
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-01 19:26:59 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-01 19:26:59 +0000
commit86babf4bfda7c2c2e9be4abc20e4d8073e05e5be (patch)
tree7e7e6083ebe59999943a211a17f8ef6f07f17c2f /libgo/go/exp/ssh
parentdf9ff8bf53f716508a120d15cc144e628fd2e9b5 (diff)
downloadppe42-gcc-86babf4bfda7c2c2e9be4abc20e4d8073e05e5be.tar.gz
ppe42-gcc-86babf4bfda7c2c2e9be4abc20e4d8073e05e5be.zip
libgo: Update to weekly.2012-01-27.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@183810 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/exp/ssh')
-rw-r--r--libgo/go/exp/ssh/channel.go318
-rw-r--r--libgo/go/exp/ssh/cipher.go88
-rw-r--r--libgo/go/exp/ssh/cipher_test.go62
-rw-r--r--libgo/go/exp/ssh/client.go505
-rw-r--r--libgo/go/exp/ssh/client_auth.go316
-rw-r--r--libgo/go/exp/ssh/client_auth_test.go257
-rw-r--r--libgo/go/exp/ssh/client_func_test.go61
-rw-r--r--libgo/go/exp/ssh/common.go239
-rw-r--r--libgo/go/exp/ssh/common_test.go26
-rw-r--r--libgo/go/exp/ssh/doc.go127
-rw-r--r--libgo/go/exp/ssh/messages.go640
-rw-r--r--libgo/go/exp/ssh/messages_test.go125
-rw-r--r--libgo/go/exp/ssh/server.go676
-rw-r--r--libgo/go/exp/ssh/server_terminal.go81
-rw-r--r--libgo/go/exp/ssh/session.go494
-rw-r--r--libgo/go/exp/ssh/session_test.go374
-rw-r--r--libgo/go/exp/ssh/tcpip.go132
-rw-r--r--libgo/go/exp/ssh/tcpip_func_test.go59
-rw-r--r--libgo/go/exp/ssh/transport.go369
-rw-r--r--libgo/go/exp/ssh/transport_test.go51
20 files changed, 0 insertions, 5000 deletions
diff --git a/libgo/go/exp/ssh/channel.go b/libgo/go/exp/ssh/channel.go
deleted file mode 100644
index 9d75f37de74..00000000000
--- a/libgo/go/exp/ssh/channel.go
+++ /dev/null
@@ -1,318 +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 (
- "errors"
- "io"
- "sync"
-)
-
-// A Channel is an ordered, reliable, duplex stream that is multiplexed over an
-// SSH connection.
-type Channel interface {
- // Accept accepts the channel creation request.
- Accept() error
- // Reject rejects the channel creation request. After calling this, no
- // other methods on the Channel may be called. If they are then the
- // peer is likely to signal a protocol error and drop the connection.
- Reject(reason RejectionReason, message string) error
-
- // Read may return a ChannelRequest as an error.
- Read(data []byte) (int, error)
- Write(data []byte) (int, error)
- Close() error
-
- // AckRequest either sends an ack or nack to the channel request.
- AckRequest(ok bool) error
-
- // ChannelType returns the type of the channel, as supplied by the
- // client.
- ChannelType() string
- // ExtraData returns the arbitary payload for this channel, as supplied
- // by the client. This data is specific to the channel type.
- ExtraData() []byte
-}
-
-// ChannelRequest represents a request sent on a channel, outside of the normal
-// stream of bytes. It may result from calling Read on a Channel.
-type ChannelRequest struct {
- Request string
- WantReply bool
- Payload []byte
-}
-
-func (c ChannelRequest) Error() string {
- return "channel request received"
-}
-
-// RejectionReason is an enumeration used when rejecting channel creation
-// requests. See RFC 4254, section 5.1.
-type RejectionReason int
-
-const (
- Prohibited RejectionReason = iota + 1
- ConnectionFailed
- UnknownChannelType
- ResourceShortage
-)
-
-type channel struct {
- // immutable once created
- chanType string
- extraData []byte
-
- theyClosed bool
- theySentEOF bool
- weClosed bool
- dead bool
-
- serverConn *ServerConn
- myId, theirId uint32
- myWindow, theirWindow uint32
- maxPacketSize uint32
- err error
-
- pendingRequests []ChannelRequest
- pendingData []byte
- head, length int
-
- // This lock is inferior to serverConn.lock
- lock sync.Mutex
- cond *sync.Cond
-}
-
-func (c *channel) Accept() error {
- c.serverConn.lock.Lock()
- defer c.serverConn.lock.Unlock()
-
- if c.serverConn.err != nil {
- return c.serverConn.err
- }
-
- confirm := channelOpenConfirmMsg{
- PeersId: c.theirId,
- MyId: c.myId,
- MyWindow: c.myWindow,
- MaxPacketSize: c.maxPacketSize,
- }
- return c.serverConn.writePacket(marshal(msgChannelOpenConfirm, confirm))
-}
-
-func (c *channel) Reject(reason RejectionReason, message string) error {
- c.serverConn.lock.Lock()
- defer c.serverConn.lock.Unlock()
-
- if c.serverConn.err != nil {
- return c.serverConn.err
- }
-
- reject := channelOpenFailureMsg{
- PeersId: c.theirId,
- Reason: uint32(reason),
- Message: message,
- Language: "en",
- }
- return c.serverConn.writePacket(marshal(msgChannelOpenFailure, reject))
-}
-
-func (c *channel) handlePacket(packet interface{}) {
- c.lock.Lock()
- defer c.lock.Unlock()
-
- switch packet := packet.(type) {
- case *channelRequestMsg:
- req := ChannelRequest{
- Request: packet.Request,
- WantReply: packet.WantReply,
- Payload: packet.RequestSpecificData,
- }
-
- c.pendingRequests = append(c.pendingRequests, req)
- c.cond.Signal()
- case *channelCloseMsg:
- c.theyClosed = true
- c.cond.Signal()
- case *channelEOFMsg:
- c.theySentEOF = true
- c.cond.Signal()
- default:
- panic("unknown packet type")
- }
-}
-
-func (c *channel) handleData(data []byte) {
- c.lock.Lock()
- defer c.lock.Unlock()
-
- // The other side should never send us more than our window.
- if len(data)+c.length > len(c.pendingData) {
- // TODO(agl): we should tear down the channel with a protocol
- // error.
- return
- }
-
- c.myWindow -= uint32(len(data))
- for i := 0; i < 2; i++ {
- tail := c.head + c.length
- if tail > len(c.pendingData) {
- tail -= len(c.pendingData)
- }
- n := copy(c.pendingData[tail:], data)
- data = data[n:]
- c.length += n
- }
-
- c.cond.Signal()
-}
-
-func (c *channel) Read(data []byte) (n int, err error) {
- c.lock.Lock()
- defer c.lock.Unlock()
-
- if c.err != nil {
- return 0, c.err
- }
-
- if c.myWindow <= uint32(len(c.pendingData))/2 {
- packet := marshal(msgChannelWindowAdjust, windowAdjustMsg{
- PeersId: c.theirId,
- AdditionalBytes: uint32(len(c.pendingData)) - c.myWindow,
- })
- if err := c.serverConn.writePacket(packet); err != nil {
- return 0, err
- }
- }
-
- for {
- if c.theySentEOF || c.theyClosed || c.dead {
- return 0, io.EOF
- }
-
- if len(c.pendingRequests) > 0 {
- req := c.pendingRequests[0]
- if len(c.pendingRequests) == 1 {
- c.pendingRequests = nil
- } else {
- oldPendingRequests := c.pendingRequests
- c.pendingRequests = make([]ChannelRequest, len(oldPendingRequests)-1)
- copy(c.pendingRequests, oldPendingRequests[1:])
- }
-
- return 0, req
- }
-
- if c.length > 0 {
- tail := c.head + c.length
- if tail > len(c.pendingData) {
- tail -= len(c.pendingData)
- }
- n = copy(data, c.pendingData[c.head:tail])
- c.head += n
- c.length -= n
- if c.head == len(c.pendingData) {
- c.head = 0
- }
- return
- }
-
- c.cond.Wait()
- }
-
- panic("unreachable")
-}
-
-func (c *channel) Write(data []byte) (n int, err error) {
- for len(data) > 0 {
- c.lock.Lock()
- if c.dead || c.weClosed {
- return 0, io.EOF
- }
-
- if c.theirWindow == 0 {
- c.cond.Wait()
- continue
- }
- c.lock.Unlock()
-
- todo := data
- if uint32(len(todo)) > c.theirWindow {
- todo = todo[:c.theirWindow]
- }
-
- packet := make([]byte, 1+4+4+len(todo))
- packet[0] = msgChannelData
- packet[1] = byte(c.theirId >> 24)
- packet[2] = byte(c.theirId >> 16)
- packet[3] = byte(c.theirId >> 8)
- packet[4] = byte(c.theirId)
- packet[5] = byte(len(todo) >> 24)
- packet[6] = byte(len(todo) >> 16)
- packet[7] = byte(len(todo) >> 8)
- packet[8] = byte(len(todo))
- copy(packet[9:], todo)
-
- c.serverConn.lock.Lock()
- if err = c.serverConn.writePacket(packet); err != nil {
- c.serverConn.lock.Unlock()
- return
- }
- c.serverConn.lock.Unlock()
-
- n += len(todo)
- data = data[len(todo):]
- }
-
- return
-}
-
-func (c *channel) Close() error {
- c.serverConn.lock.Lock()
- defer c.serverConn.lock.Unlock()
-
- if c.serverConn.err != nil {
- return c.serverConn.err
- }
-
- if c.weClosed {
- return errors.New("ssh: channel already closed")
- }
- c.weClosed = true
-
- closeMsg := channelCloseMsg{
- PeersId: c.theirId,
- }
- return c.serverConn.writePacket(marshal(msgChannelClose, closeMsg))
-}
-
-func (c *channel) AckRequest(ok bool) error {
- c.serverConn.lock.Lock()
- defer c.serverConn.lock.Unlock()
-
- if c.serverConn.err != nil {
- return c.serverConn.err
- }
-
- if ok {
- ack := channelRequestSuccessMsg{
- PeersId: c.theirId,
- }
- return c.serverConn.writePacket(marshal(msgChannelSuccess, ack))
- } else {
- ack := channelRequestFailureMsg{
- PeersId: c.theirId,
- }
- return c.serverConn.writePacket(marshal(msgChannelFailure, ack))
- }
- panic("unreachable")
-}
-
-func (c *channel) ChannelType() string {
- return c.chanType
-}
-
-func (c *channel) ExtraData() []byte {
- return c.extraData
-}
diff --git a/libgo/go/exp/ssh/cipher.go b/libgo/go/exp/ssh/cipher.go
deleted file mode 100644
index d91929aa99a..00000000000
--- a/libgo/go/exp/ssh/cipher.go
+++ /dev/null
@@ -1,88 +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 (
- "crypto/aes"
- "crypto/cipher"
- "crypto/rc4"
-)
-
-// streamDump is used to dump the initial keystream for stream ciphers. It is a
-// a write-only buffer, and not intended for reading so do not require a mutex.
-var streamDump [512]byte
-
-// noneCipher implements cipher.Stream and provides no encryption. It is used
-// by the transport before the first key-exchange.
-type noneCipher struct{}
-
-func (c noneCipher) XORKeyStream(dst, src []byte) {
- copy(dst, src)
-}
-
-func newAESCTR(key, iv []byte) (cipher.Stream, error) {
- c, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- return cipher.NewCTR(c, iv), nil
-}
-
-func newRC4(key, iv []byte) (cipher.Stream, error) {
- return rc4.NewCipher(key)
-}
-
-type cipherMode struct {
- keySize int
- ivSize int
- skip int
- createFn func(key, iv []byte) (cipher.Stream, error)
-}
-
-func (c *cipherMode) createCipher(key, iv []byte) (cipher.Stream, error) {
- if len(key) < c.keySize {
- panic("ssh: key length too small for cipher")
- }
- if len(iv) < c.ivSize {
- panic("ssh: iv too small for cipher")
- }
-
- stream, err := c.createFn(key[:c.keySize], iv[:c.ivSize])
- if err != nil {
- return nil, err
- }
-
- for remainingToDump := c.skip; remainingToDump > 0; {
- dumpThisTime := remainingToDump
- if dumpThisTime > len(streamDump) {
- dumpThisTime = len(streamDump)
- }
- stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
- remainingToDump -= dumpThisTime
- }
-
- return stream, nil
-}
-
-// Specifies a default set of ciphers and a preference order. This is based on
-// OpenSSH's default client preference order, minus algorithms that are not
-// implemented.
-var DefaultCipherOrder = []string{
- "aes128-ctr", "aes192-ctr", "aes256-ctr",
- "arcfour256", "arcfour128",
-}
-
-var cipherModes = map[string]*cipherMode{
- // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms
- // are defined in the order specified in the RFC.
- "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR},
- "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR},
- "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR},
-
- // Ciphers from RFC4345, which introduces security-improved arcfour ciphers.
- // They are defined in the order specified in the RFC.
- "arcfour128": {16, 0, 1536, newRC4},
- "arcfour256": {32, 0, 1536, newRC4},
-}
diff --git a/libgo/go/exp/ssh/cipher_test.go b/libgo/go/exp/ssh/cipher_test.go
deleted file mode 100644
index ea27bd8a803..00000000000
--- a/libgo/go/exp/ssh/cipher_test.go
+++ /dev/null
@@ -1,62 +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 (
- "bytes"
- "testing"
-)
-
-// TestCipherReversal tests that each cipher factory produces ciphers that can
-// encrypt and decrypt some data successfully.
-func TestCipherReversal(t *testing.T) {
- testData := []byte("abcdefghijklmnopqrstuvwxyz012345")
- testKey := []byte("AbCdEfGhIjKlMnOpQrStUvWxYz012345")
- testIv := []byte("sdflkjhsadflkjhasdflkjhsadfklhsa")
-
- cryptBuffer := make([]byte, 32)
-
- for name, cipherMode := range cipherModes {
- encrypter, err := cipherMode.createCipher(testKey, testIv)
- if err != nil {
- t.Errorf("failed to create encrypter for %q: %s", name, err)
- continue
- }
- decrypter, err := cipherMode.createCipher(testKey, testIv)
- if err != nil {
- t.Errorf("failed to create decrypter for %q: %s", name, err)
- continue
- }
-
- copy(cryptBuffer, testData)
-
- encrypter.XORKeyStream(cryptBuffer, cryptBuffer)
- if name == "none" {
- if !bytes.Equal(cryptBuffer, testData) {
- t.Errorf("encryption made change with 'none' cipher")
- continue
- }
- } else {
- if bytes.Equal(cryptBuffer, testData) {
- t.Errorf("encryption made no change with %q", name)
- continue
- }
- }
-
- decrypter.XORKeyStream(cryptBuffer, cryptBuffer)
- if !bytes.Equal(cryptBuffer, testData) {
- t.Errorf("decrypted bytes not equal to input with %q", name)
- continue
- }
- }
-}
-
-func TestDefaultCiphersExist(t *testing.T) {
- for _, cipherAlgo := range DefaultCipherOrder {
- if _, ok := cipherModes[cipherAlgo]; !ok {
- t.Errorf("default cipher %q is unknown", cipherAlgo)
- }
- }
-}
diff --git a/libgo/go/exp/ssh/client.go b/libgo/go/exp/ssh/client.go
deleted file mode 100644
index eb6c0352210..00000000000
--- a/libgo/go/exp/ssh/client.go
+++ /dev/null
@@ -1,505 +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 (
- "crypto"
- "crypto/rand"
- "errors"
- "fmt"
- "io"
- "math/big"
- "net"
- "sync"
-)
-
-// clientVersion is the fixed identification string that the client will use.
-var clientVersion = []byte("SSH-2.0-Go\r\n")
-
-// ClientConn represents the client side of an SSH connection.
-type ClientConn struct {
- *transport
- config *ClientConfig
- chanlist
-}
-
-// Client returns a new SSH client connection using c as the underlying transport.
-func Client(c net.Conn, config *ClientConfig) (*ClientConn, error) {
- conn := &ClientConn{
- transport: newTransport(c, config.rand()),
- config: config,
- }
- if err := conn.handshake(); err != nil {
- conn.Close()
- return nil, err
- }
- go conn.mainLoop()
- return conn, nil
-}
-
-// handshake performs the client side key exchange. See RFC 4253 Section 7.
-func (c *ClientConn) handshake() error {
- var magics handshakeMagics
-
- if _, err := c.Write(clientVersion); err != nil {
- return err
- }
- if err := c.Flush(); err != nil {
- return err
- }
- magics.clientVersion = clientVersion[:len(clientVersion)-2]
-
- // read remote server version
- version, err := readVersion(c)
- if err != nil {
- return err
- }
- magics.serverVersion = version
- clientKexInit := kexInitMsg{
- KexAlgos: supportedKexAlgos,
- ServerHostKeyAlgos: supportedHostKeyAlgos,
- CiphersClientServer: c.config.Crypto.ciphers(),
- CiphersServerClient: c.config.Crypto.ciphers(),
- MACsClientServer: supportedMACs,
- MACsServerClient: supportedMACs,
- CompressionClientServer: supportedCompressions,
- CompressionServerClient: supportedCompressions,
- }
- kexInitPacket := marshal(msgKexInit, clientKexInit)
- magics.clientKexInit = kexInitPacket
-
- if err := c.writePacket(kexInitPacket); err != nil {
- return err
- }
- packet, err := c.readPacket()
- if err != nil {
- return err
- }
-
- magics.serverKexInit = packet
-
- var serverKexInit kexInitMsg
- if err = unmarshal(&serverKexInit, packet, msgKexInit); err != nil {
- return err
- }
-
- kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(c.transport, &clientKexInit, &serverKexInit)
- if !ok {
- return errors.New("ssh: no common algorithms")
- }
-
- if serverKexInit.FirstKexFollows && kexAlgo != serverKexInit.KexAlgos[0] {
- // The server sent a Kex message for the wrong algorithm,
- // which we have to ignore.
- if _, err := c.readPacket(); err != nil {
- return err
- }
- }
-
- var H, K []byte
- var hashFunc crypto.Hash
- switch kexAlgo {
- case kexAlgoDH14SHA1:
- hashFunc = crypto.SHA1
- dhGroup14Once.Do(initDHGroup14)
- H, K, err = c.kexDH(dhGroup14, hashFunc, &magics, hostKeyAlgo)
- default:
- err = fmt.Errorf("ssh: unexpected key exchange algorithm %v", kexAlgo)
- }
- if err != nil {
- return err
- }
-
- if err = c.writePacket([]byte{msgNewKeys}); err != nil {
- return err
- }
- if err = c.transport.writer.setupKeys(clientKeys, K, H, H, hashFunc); err != nil {
- return err
- }
- if packet, err = c.readPacket(); err != nil {
- return err
- }
- if packet[0] != msgNewKeys {
- return UnexpectedMessageError{msgNewKeys, packet[0]}
- }
- if err := c.transport.reader.setupKeys(serverKeys, K, H, H, hashFunc); err != nil {
- return err
- }
- return c.authenticate(H)
-}
-
-// kexDH performs Diffie-Hellman key agreement on a ClientConn. The
-// returned values are given the same names as in RFC 4253, section 8.
-func (c *ClientConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) ([]byte, []byte, error) {
- x, err := rand.Int(c.config.rand(), group.p)
- if err != nil {
- return nil, nil, err
- }
- X := new(big.Int).Exp(group.g, x, group.p)
- kexDHInit := kexDHInitMsg{
- X: X,
- }
- if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil {
- return nil, nil, err
- }
-
- packet, err := c.readPacket()
- if err != nil {
- return nil, nil, err
- }
-
- var kexDHReply = new(kexDHReplyMsg)
- if err = unmarshal(kexDHReply, packet, msgKexDHReply); err != nil {
- return nil, nil, err
- }
-
- if kexDHReply.Y.Sign() == 0 || kexDHReply.Y.Cmp(group.p) >= 0 {
- return nil, nil, errors.New("server DH parameter out of bounds")
- }
-
- kInt := new(big.Int).Exp(kexDHReply.Y, x, group.p)
- h := hashFunc.New()
- writeString(h, magics.clientVersion)
- writeString(h, magics.serverVersion)
- writeString(h, magics.clientKexInit)
- writeString(h, magics.serverKexInit)
- writeString(h, kexDHReply.HostKey)
- writeInt(h, X)
- writeInt(h, kexDHReply.Y)
- K := make([]byte, intLength(kInt))
- marshalInt(K, kInt)
- h.Write(K)
-
- H := h.Sum(nil)
-
- return H, K, nil
-}
-
-// mainLoop reads incoming messages and routes channel messages
-// to their respective ClientChans.
-func (c *ClientConn) mainLoop() {
- // TODO(dfc) signal the underlying close to all channels
- defer c.Close()
- for {
- packet, err := c.readPacket()
- if err != nil {
- break
- }
- // TODO(dfc) A note on blocking channel use.
- // The msg, win, data and dataExt channels of a clientChan can
- // cause this loop to block indefinately if the consumer does
- // not service them.
- switch packet[0] {
- case msgChannelData:
- if len(packet) < 9 {
- // malformed data packet
- break
- }
- peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
- if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 {
- packet = packet[9:]
- c.getChan(peersId).stdout.handleData(packet[:length])
- }
- case msgChannelExtendedData:
- if len(packet) < 13 {
- // malformed data packet
- break
- }
- peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
- datatype := uint32(packet[5])<<24 | uint32(packet[6])<<16 | uint32(packet[7])<<8 | uint32(packet[8])
- if length := int(packet[9])<<24 | int(packet[10])<<16 | int(packet[11])<<8 | int(packet[12]); length > 0 {
- packet = packet[13:]
- // RFC 4254 5.2 defines data_type_code 1 to be data destined
- // for stderr on interactive sessions. Other data types are
- // silently discarded.
- if datatype == 1 {
- c.getChan(peersId).stderr.handleData(packet[:length])
- }
- }
- default:
- switch msg := decode(packet).(type) {
- case *channelOpenMsg:
- c.getChan(msg.PeersId).msg <- msg
- case *channelOpenConfirmMsg:
- c.getChan(msg.PeersId).msg <- msg
- case *channelOpenFailureMsg:
- c.getChan(msg.PeersId).msg <- msg
- case *channelCloseMsg:
- ch := c.getChan(msg.PeersId)
- ch.theyClosed = true
- close(ch.stdin.win)
- ch.stdout.eof()
- ch.stderr.eof()
- close(ch.msg)
- if !ch.weClosed {
- ch.weClosed = true
- ch.sendClose()
- }
- c.chanlist.remove(msg.PeersId)
- case *channelEOFMsg:
- ch := c.getChan(msg.PeersId)
- ch.stdout.eof()
- // RFC 4254 is mute on how EOF affects dataExt messages but
- // it is logical to signal EOF at the same time.
- ch.stderr.eof()
- case *channelRequestSuccessMsg:
- c.getChan(msg.PeersId).msg <- msg
- case *channelRequestFailureMsg:
- c.getChan(msg.PeersId).msg <- msg
- case *channelRequestMsg:
- c.getChan(msg.PeersId).msg <- msg
- case *windowAdjustMsg:
- c.getChan(msg.PeersId).stdin.win <- int(msg.AdditionalBytes)
- case *disconnectMsg:
- break
- default:
- fmt.Printf("mainLoop: unhandled message %T: %v\n", msg, msg)
- }
- }
- }
-}
-
-// Dial connects to the given network address using net.Dial and
-// then initiates a SSH handshake, returning the resulting client connection.
-func Dial(network, addr string, config *ClientConfig) (*ClientConn, error) {
- conn, err := net.Dial(network, addr)
- if err != nil {
- return nil, err
- }
- return Client(conn, config)
-}
-
-// A ClientConfig structure is used to configure a ClientConn. After one has
-// been passed to an SSH function it must not be modified.
-type ClientConfig struct {
- // Rand provides the source of entropy for key exchange. If Rand is
- // nil, the cryptographic random reader in package crypto/rand will
- // be used.
- Rand io.Reader
-
- // The username to authenticate.
- User string
-
- // A slice of ClientAuth methods. Only the first instance
- // of a particular RFC 4252 method will be used during authentication.
- Auth []ClientAuth
-
- // Cryptographic-related configuration.
- Crypto CryptoConfig
-}
-
-func (c *ClientConfig) rand() io.Reader {
- if c.Rand == nil {
- return rand.Reader
- }
- return c.Rand
-}
-
-// A clientChan represents a single RFC 4254 channel that is multiplexed
-// over a single SSH connection.
-type clientChan struct {
- packetWriter
- id, peersId uint32
- stdin *chanWriter // receives window adjustments
- stdout *chanReader // receives the payload of channelData messages
- stderr *chanReader // receives the payload of channelExtendedData messages
- msg chan interface{} // incoming messages
- theyClosed bool // indicates the close msg has been received from the remote side
- weClosed bool // incidates the close msg has been sent from our side
-}
-
-// newClientChan returns a partially constructed *clientChan
-// using the local id provided. To be usable clientChan.peersId
-// needs to be assigned once known.
-func newClientChan(t *transport, id uint32) *clientChan {
- c := &clientChan{
- packetWriter: t,
- id: id,
- msg: make(chan interface{}, 16),
- }
- c.stdin = &chanWriter{
- win: make(chan int, 16),
- clientChan: c,
- }
- c.stdout = &chanReader{
- data: make(chan []byte, 16),
- clientChan: c,
- }
- c.stderr = &chanReader{
- data: make(chan []byte, 16),
- clientChan: c,
- }
- return c
-}
-
-// waitForChannelOpenResponse, if successful, fills out
-// the peerId and records any initial window advertisement.
-func (c *clientChan) waitForChannelOpenResponse() error {
- switch msg := (<-c.msg).(type) {
- case *channelOpenConfirmMsg:
- // fixup peersId field
- c.peersId = msg.MyId
- c.stdin.win <- int(msg.MyWindow)
- return nil
- case *channelOpenFailureMsg:
- return errors.New(safeString(msg.Message))
- }
- return errors.New("unexpected packet")
-}
-
-// sendEOF sends EOF to the server. RFC 4254 Section 5.3
-func (c *clientChan) sendEOF() error {
- return c.writePacket(marshal(msgChannelEOF, channelEOFMsg{
- PeersId: c.peersId,
- }))
-}
-
-// sendClose signals the intent to close the channel.
-func (c *clientChan) sendClose() error {
- return c.writePacket(marshal(msgChannelClose, channelCloseMsg{
- PeersId: c.peersId,
- }))
-}
-
-// Close closes the channel. This does not close the underlying connection.
-func (c *clientChan) Close() error {
- if !c.weClosed {
- c.weClosed = true
- return c.sendClose()
- }
- return nil
-}
-
-// Thread safe channel list.
-type chanlist struct {
- // protects concurrent access to chans
- sync.Mutex
- // chans are indexed by the local id of the channel, clientChan.id.
- // The PeersId value of messages received by ClientConn.mainLoop is
- // used to locate the right local clientChan in this slice.
- chans []*clientChan
-}
-
-// Allocate a new ClientChan with the next avail local id.
-func (c *chanlist) newChan(t *transport) *clientChan {
- c.Lock()
- defer c.Unlock()
- for i := range c.chans {
- if c.chans[i] == nil {
- ch := newClientChan(t, uint32(i))
- c.chans[i] = ch
- return ch
- }
- }
- i := len(c.chans)
- ch := newClientChan(t, uint32(i))
- c.chans = append(c.chans, ch)
- return ch
-}
-
-func (c *chanlist) getChan(id uint32) *clientChan {
- c.Lock()
- defer c.Unlock()
- return c.chans[int(id)]
-}
-
-func (c *chanlist) remove(id uint32) {
- c.Lock()
- defer c.Unlock()
- c.chans[int(id)] = nil
-}
-
-// A chanWriter represents the stdin of a remote process.
-type chanWriter struct {
- win chan int // receives window adjustments
- rwin int // current rwin size
- clientChan *clientChan // the channel backing this writer
-}
-
-// Write writes data to the remote process's standard input.
-func (w *chanWriter) Write(data []byte) (written int, err error) {
- for len(data) > 0 {
- for w.rwin < 1 {
- win, ok := <-w.win
- if !ok {
- return 0, io.EOF
- }
- w.rwin += win
- }
- n := min(len(data), w.rwin)
- peersId := w.clientChan.peersId
- packet := []byte{
- msgChannelData,
- byte(peersId >> 24), byte(peersId >> 16), byte(peersId >> 8), byte(peersId),
- byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n),
- }
- if err = w.clientChan.writePacket(append(packet, data[:n]...)); err != nil {
- break
- }
- data = data[n:]
- w.rwin -= n
- written += n
- }
- return
-}
-
-func min(a, b int) int {
- if a < b {
- return a
- }
- return b
-}
-
-func (w *chanWriter) Close() error {
- return w.clientChan.sendEOF()
-}
-
-// A chanReader represents stdout or stderr of a remote process.
-type chanReader struct {
- // TODO(dfc) a fixed size channel may not be the right data structure.
- // If writes to this channel block, they will block mainLoop, making
- // it unable to receive new messages from the remote side.
- data chan []byte // receives data from remote
- dataClosed bool // protects data from being closed twice
- clientChan *clientChan // the channel backing this reader
- buf []byte
-}
-
-// eof signals to the consumer that there is no more data to be received.
-func (r *chanReader) eof() {
- if !r.dataClosed {
- r.dataClosed = true
- close(r.data)
- }
-}
-
-// handleData sends buf to the reader's consumer. If r.data is closed
-// the data will be silently discarded
-func (r *chanReader) handleData(buf []byte) {
- if !r.dataClosed {
- r.data <- buf
- }
-}
-
-// Read reads data from the remote process's stdout or stderr.
-func (r *chanReader) Read(data []byte) (int, error) {
- var ok bool
- for {
- if len(r.buf) > 0 {
- n := copy(data, r.buf)
- r.buf = r.buf[n:]
- msg := windowAdjustMsg{
- PeersId: r.clientChan.peersId,
- AdditionalBytes: uint32(n),
- }
- return n, r.clientChan.writePacket(marshal(msgChannelWindowAdjust, msg))
- }
- r.buf, ok = <-r.data
- if !ok {
- return 0, io.EOF
- }
- }
- panic("unreachable")
-}
diff --git a/libgo/go/exp/ssh/client_auth.go b/libgo/go/exp/ssh/client_auth.go
deleted file mode 100644
index 3a7e9fb9801..00000000000
--- a/libgo/go/exp/ssh/client_auth.go
+++ /dev/null
@@ -1,316 +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 (
- "errors"
- "io"
-)
-
-// authenticate authenticates with the remote server. See RFC 4252.
-func (c *ClientConn) authenticate(session []byte) error {
- // initiate user auth session
- if err := c.writePacket(marshal(msgServiceRequest, serviceRequestMsg{serviceUserAuth})); err != nil {
- return err
- }
- packet, err := c.readPacket()
- if err != nil {
- return err
- }
- var serviceAccept serviceAcceptMsg
- if err := unmarshal(&serviceAccept, packet, msgServiceAccept); err != nil {
- return err
- }
- // during the authentication phase the client first attempts the "none" method
- // then any untried methods suggested by the server.
- tried, remain := make(map[string]bool), make(map[string]bool)
- for auth := ClientAuth(new(noneAuth)); auth != nil; {
- ok, methods, err := auth.auth(session, c.config.User, c.transport, c.config.rand())
- if err != nil {
- return err
- }
- if ok {
- // success
- return nil
- }
- tried[auth.method()] = true
- delete(remain, auth.method())
- for _, meth := range methods {
- if tried[meth] {
- // if we've tried meth already, skip it.
- continue
- }
- remain[meth] = true
- }
- auth = nil
- for _, a := range c.config.Auth {
- if remain[a.method()] {
- auth = a
- break
- }
- }
- }
- return errors.New("ssh: unable to authenticate, no supported methods remain")
-}
-
-// A ClientAuth represents an instance of an RFC 4252 authentication method.
-type ClientAuth interface {
- // auth authenticates user over transport t.
- // Returns true if authentication is successful.
- // If authentication is not successful, a []string of alternative
- // method names is returned.
- auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error)
-
- // method returns the RFC 4252 method name.
- method() string
-}
-
-// "none" authentication, RFC 4252 section 5.2.
-type noneAuth int
-
-func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
- if err := t.writePacket(marshal(msgUserAuthRequest, userAuthRequestMsg{
- User: user,
- Service: serviceSSH,
- Method: "none",
- })); err != nil {
- return false, nil, err
- }
-
- return handleAuthResponse(t)
-}
-
-func (n *noneAuth) method() string {
- return "none"
-}
-
-// "password" authentication, RFC 4252 Section 8.
-type passwordAuth struct {
- ClientPassword
-}
-
-func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
- type passwordAuthMsg struct {
- User string
- Service string
- Method string
- Reply bool
- Password string
- }
-
- pw, err := p.Password(user)
- if err != nil {
- return false, nil, err
- }
-
- if err := t.writePacket(marshal(msgUserAuthRequest, passwordAuthMsg{
- User: user,
- Service: serviceSSH,
- Method: "password",
- Reply: false,
- Password: pw,
- })); err != nil {
- return false, nil, err
- }
-
- return handleAuthResponse(t)
-}
-
-func (p *passwordAuth) method() string {
- return "password"
-}
-
-// A ClientPassword implements access to a client's passwords.
-type ClientPassword interface {
- // Password returns the password to use for user.
- Password(user string) (password string, err error)
-}
-
-// ClientAuthPassword returns a ClientAuth using password authentication.
-func ClientAuthPassword(impl ClientPassword) ClientAuth {
- return &passwordAuth{impl}
-}
-
-// ClientKeyring implements access to a client key ring.
-type ClientKeyring interface {
- // Key returns the i'th rsa.Publickey or dsa.Publickey, or nil if
- // no key exists at i.
- Key(i int) (key interface{}, err error)
-
- // Sign returns a signature of the given data using the i'th key
- // and the supplied random source.
- Sign(i int, rand io.Reader, data []byte) (sig []byte, err error)
-}
-
-// "publickey" authentication, RFC 4252 Section 7.
-type publickeyAuth struct {
- ClientKeyring
-}
-
-type publickeyAuthMsg struct {
- User string
- Service string
- Method string
- // HasSig indicates to the reciver packet that the auth request is signed and
- // should be used for authentication of the request.
- HasSig bool
- Algoname string
- Pubkey string
- // Sig is defined as []byte so marshal will exclude it during validateKey
- Sig []byte `ssh:"rest"`
-}
-
-func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
-
- // Authentication is performed in two stages. The first stage sends an
- // enquiry to test if each key is acceptable to the remote. The second
- // stage attempts to authenticate with the valid keys obtained in the
- // first stage.
-
- var index int
- // a map of public keys to their index in the keyring
- validKeys := make(map[int]interface{})
- for {
- key, err := p.Key(index)
- if err != nil {
- return false, nil, err
- }
- if key == nil {
- // no more keys in the keyring
- break
- }
-
- if ok, err := p.validateKey(key, user, t); ok {
- validKeys[index] = key
- } else {
- if err != nil {
- return false, nil, err
- }
- }
- index++
- }
-
- // methods that may continue if this auth is not successful.
- var methods []string
- for i, key := range validKeys {
- pubkey := serializePublickey(key)
- algoname := algoName(key)
- sign, err := p.Sign(i, rand, buildDataSignedForAuth(session, userAuthRequestMsg{
- User: user,
- Service: serviceSSH,
- Method: p.method(),
- }, []byte(algoname), pubkey))
- if err != nil {
- return false, nil, err
- }
- // manually wrap the serialized signature in a string
- s := serializeSignature(algoname, sign)
- sig := make([]byte, stringLength(s))
- marshalString(sig, s)
- msg := publickeyAuthMsg{
- User: user,
- Service: serviceSSH,
- Method: p.method(),
- HasSig: true,
- Algoname: algoname,
- Pubkey: string(pubkey),
- Sig: sig,
- }
- p := marshal(msgUserAuthRequest, msg)
- if err := t.writePacket(p); err != nil {
- return false, nil, err
- }
- success, methods, err := handleAuthResponse(t)
- if err != nil {
- return false, nil, err
- }
- if success {
- return success, methods, err
- }
- }
- return false, methods, nil
-}
-
-// validateKey validates the key provided it is acceptable to the server.
-func (p *publickeyAuth) validateKey(key interface{}, user string, t *transport) (bool, error) {
- pubkey := serializePublickey(key)
- algoname := algoName(key)
- msg := publickeyAuthMsg{
- User: user,
- Service: serviceSSH,
- Method: p.method(),
- HasSig: false,
- Algoname: algoname,
- Pubkey: string(pubkey),
- }
- if err := t.writePacket(marshal(msgUserAuthRequest, msg)); err != nil {
- return false, err
- }
-
- return p.confirmKeyAck(key, t)
-}
-
-func (p *publickeyAuth) confirmKeyAck(key interface{}, t *transport) (bool, error) {
- pubkey := serializePublickey(key)
- algoname := algoName(key)
-
- for {
- packet, err := t.readPacket()
- if err != nil {
- return false, err
- }
- switch packet[0] {
- case msgUserAuthBanner:
- // TODO(gpaul): add callback to present the banner to the user
- case msgUserAuthPubKeyOk:
- msg := decode(packet).(*userAuthPubKeyOkMsg)
- if msg.Algo != algoname || msg.PubKey != string(pubkey) {
- return false, nil
- }
- return true, nil
- case msgUserAuthFailure:
- return false, nil
- default:
- return false, UnexpectedMessageError{msgUserAuthSuccess, packet[0]}
- }
- }
- panic("unreachable")
-}
-
-func (p *publickeyAuth) method() string {
- return "publickey"
-}
-
-// ClientAuthKeyring returns a ClientAuth using public key authentication.
-func ClientAuthKeyring(impl ClientKeyring) ClientAuth {
- return &publickeyAuth{impl}
-}
-
-// 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(t *transport) (bool, []string, error) {
- for {
- packet, err := t.readPacket()
- if err != nil {
- return false, nil, err
- }
-
- switch packet[0] {
- case msgUserAuthBanner:
- // TODO: add callback to present the banner to the user
- case msgUserAuthFailure:
- msg := decode(packet).(*userAuthFailureMsg)
- return false, msg.Methods, nil
- case msgUserAuthSuccess:
- return true, nil, nil
- case msgDisconnect:
- return false, nil, io.EOF
- default:
- return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]}
- }
- }
- panic("unreachable")
-}
diff --git a/libgo/go/exp/ssh/client_auth_test.go b/libgo/go/exp/ssh/client_auth_test.go
deleted file mode 100644
index c41a93b5c7d..00000000000
--- a/libgo/go/exp/ssh/client_auth_test.go
+++ /dev/null
@@ -1,257 +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 (
- "bytes"
- "crypto"
- "crypto/dsa"
- "crypto/rsa"
- _ "crypto/sha1"
- "crypto/x509"
- "encoding/pem"
- "errors"
- "io"
- "io/ioutil"
- "math/big"
- "testing"
-)
-
-// private key for mock server
-const testServerPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU
-70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx
-9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF
-tupdMODN064vd3gyMKTwrlQ8tZM6aYuyOPsutLlUY7M5x5FwMDYvnPDSeyT/Iw0z
-s3B+NCyqeeMd2T7YzQFnRATj0M7rM5LoSs7DVqVriOEABssFyLj31PboaoLhOKgc
-qoM9khkNzr7FHVvi+DhYM2jD0DwvqZLN6NmnLwIDAQABAoIBAQCGVj+kuSFOV1lT
-+IclQYA6bM6uY5mroqcSBNegVxCNhWU03BxlW//BE9tA/+kq53vWylMeN9mpGZea
-riEMIh25KFGWXqXlOOioH8bkMsqA8S7sBmc7jljyv+0toQ9vCCtJ+sueNPhxQQxH
-D2YvUjfzBQ04I9+wn30BByDJ1QA/FoPsunxIOUCcRBE/7jxuLYcpR+JvEF68yYIh
-atXRld4W4in7T65YDR8jK1Uj9XAcNeDYNpT/M6oFLx1aPIlkG86aCWRO19S1jLPT
-b1ZAKHHxPMCVkSYW0RqvIgLXQOR62D0Zne6/2wtzJkk5UCjkSQ2z7ZzJpMkWgDgN
-ifCULFPBAoGBAPoMZ5q1w+zB+knXUD33n1J+niN6TZHJulpf2w5zsW+m2K6Zn62M
-MXndXlVAHtk6p02q9kxHdgov34Uo8VpuNjbS1+abGFTI8NZgFo+bsDxJdItemwC4
-KJ7L1iz39hRN/ZylMRLz5uTYRGddCkeIHhiG2h7zohH/MaYzUacXEEy3AoGBANz8
-e/msleB+iXC0cXKwds26N4hyMdAFE5qAqJXvV3S2W8JZnmU+sS7vPAWMYPlERPk1
-D8Q2eXqdPIkAWBhrx4RxD7rNc5qFNcQWEhCIxC9fccluH1y5g2M+4jpMX2CT8Uv+
-3z+NoJ5uDTXZTnLCfoZzgZ4nCZVZ+6iU5U1+YXFJAoGBANLPpIV920n/nJmmquMj
-orI1R/QXR9Cy56cMC65agezlGOfTYxk5Cfl5Ve+/2IJCfgzwJyjWUsFx7RviEeGw
-64o7JoUom1HX+5xxdHPsyZ96OoTJ5RqtKKoApnhRMamau0fWydH1yeOEJd+TRHhc
-XStGfhz8QNa1dVFvENczja1vAoGABGWhsd4VPVpHMc7lUvrf4kgKQtTC2PjA4xoc
-QJ96hf/642sVE76jl+N6tkGMzGjnVm4P2j+bOy1VvwQavKGoXqJBRd5Apppv727g
-/SM7hBXKFc/zH80xKBBgP/i1DR7kdjakCoeu4ngeGywvu2jTS6mQsqzkK+yWbUxJ
-I7mYBsECgYB/KNXlTEpXtz/kwWCHFSYA8U74l7zZbVD8ul0e56JDK+lLcJ0tJffk
-gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl
-NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw==
------END RSA PRIVATE KEY-----`
-
-const testClientPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
-MIIBOwIBAAJBALdGZxkXDAjsYk10ihwU6Id2KeILz1TAJuoq4tOgDWxEEGeTrcld
-r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ
-tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC
-nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW
-2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB
-y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr
-rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg==
------END RSA PRIVATE KEY-----`
-
-// keychain implements the ClientPublickey interface
-type keychain struct {
- keys []interface{}
-}
-
-func (k *keychain) Key(i int) (interface{}, error) {
- if i < 0 || i >= len(k.keys) {
- return nil, nil
- }
- switch key := k.keys[i].(type) {
- case *rsa.PrivateKey:
- return key.PublicKey, nil
- case *dsa.PrivateKey:
- return key.PublicKey, nil
- }
- panic("unknown key type")
-}
-
-func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
- hashFunc := crypto.SHA1
- h := hashFunc.New()
- h.Write(data)
- digest := h.Sum(nil)
- switch key := k.keys[i].(type) {
- case *rsa.PrivateKey:
- return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
- }
- return nil, errors.New("unknown key type")
-}
-
-func (k *keychain) loadPEM(file string) error {
- buf, err := ioutil.ReadFile(file)
- if err != nil {
- return err
- }
- block, _ := pem.Decode(buf)
- if block == nil {
- return errors.New("ssh: no key found")
- }
- r, err := x509.ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- return err
- }
- k.keys = append(k.keys, r)
- return nil
-}
-
-// password implements the ClientPassword interface
-type password string
-
-func (p password) Password(user string) (string, error) {
- return string(p), nil
-}
-
-// reused internally by tests
-var (
- rsakey *rsa.PrivateKey
- dsakey *dsa.PrivateKey
- clientKeychain = new(keychain)
- clientPassword = password("tiger")
- serverConfig = &ServerConfig{
- PasswordCallback: func(user, pass string) bool {
- return user == "testuser" && pass == string(clientPassword)
- },
- PublicKeyCallback: func(user, algo string, pubkey []byte) bool {
- key := clientKeychain.keys[0].(*rsa.PrivateKey).PublicKey
- expected := []byte(serializePublickey(key))
- algoname := algoName(key)
- return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected)
- },
- }
-)
-
-func init() {
- if err := serverConfig.SetRSAPrivateKey([]byte(testServerPrivateKey)); err != nil {
- panic("unable to set private key: " + err.Error())
- }
-
- block, _ := pem.Decode([]byte(testClientPrivateKey))
- rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
-
- clientKeychain.keys = append(clientKeychain.keys, rsakey)
- dsakey = new(dsa.PrivateKey)
- // taken from crypto/dsa/dsa_test.go
- dsakey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
- dsakey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16)
- dsakey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16)
- dsakey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16)
- dsakey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16)
-}
-
-// newMockAuthServer creates a new Server bound to
-// the loopback interface. The server exits after
-// processing one handshake.
-func newMockAuthServer(t *testing.T) string {
- l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
- if err != nil {
- t.Fatalf("unable to newMockAuthServer: %s", err)
- }
- go func() {
- defer l.Close()
- c, err := l.Accept()
- defer c.Close()
- if err != nil {
- t.Errorf("Unable to accept incoming connection: %v", err)
- return
- }
- if err := c.Handshake(); err != nil {
- // not Errorf because this is expected to
- // fail for some tests.
- t.Logf("Handshaking error: %v", err)
- return
- }
- }()
- return l.Addr().String()
-}
-
-func TestClientAuthPublickey(t *testing.T) {
- config := &ClientConfig{
- User: "testuser",
- Auth: []ClientAuth{
- ClientAuthKeyring(clientKeychain),
- },
- }
- c, err := Dial("tcp", newMockAuthServer(t), config)
- if err != nil {
- t.Fatalf("unable to dial remote side: %s", err)
- }
- c.Close()
-}
-
-func TestClientAuthPassword(t *testing.T) {
- config := &ClientConfig{
- User: "testuser",
- Auth: []ClientAuth{
- ClientAuthPassword(clientPassword),
- },
- }
-
- c, err := Dial("tcp", newMockAuthServer(t), config)
- if err != nil {
- t.Fatalf("unable to dial remote side: %s", err)
- }
- c.Close()
-}
-
-func TestClientAuthWrongPassword(t *testing.T) {
- wrongPw := password("wrong")
- config := &ClientConfig{
- User: "testuser",
- Auth: []ClientAuth{
- ClientAuthPassword(wrongPw),
- ClientAuthKeyring(clientKeychain),
- },
- }
-
- c, err := Dial("tcp", newMockAuthServer(t), config)
- if err != nil {
- t.Fatalf("unable to dial remote side: %s", err)
- }
- c.Close()
-}
-
-// the mock server will only authenticate ssh-rsa keys
-func TestClientAuthInvalidPublickey(t *testing.T) {
- kc := new(keychain)
- kc.keys = append(kc.keys, dsakey)
- config := &ClientConfig{
- User: "testuser",
- Auth: []ClientAuth{
- ClientAuthKeyring(kc),
- },
- }
-
- c, err := Dial("tcp", newMockAuthServer(t), config)
- if err == nil {
- c.Close()
- t.Fatalf("dsa private key should not have authenticated with rsa public key")
- }
-}
-
-// the client should authenticate with the second key
-func TestClientAuthRSAandDSA(t *testing.T) {
- kc := new(keychain)
- kc.keys = append(kc.keys, dsakey, rsakey)
- config := &ClientConfig{
- User: "testuser",
- Auth: []ClientAuth{
- ClientAuthKeyring(kc),
- },
- }
- c, err := Dial("tcp", newMockAuthServer(t), config)
- if err != nil {
- t.Fatalf("client could not authenticate with rsa key: %v", err)
- }
- c.Close()
-}
diff --git a/libgo/go/exp/ssh/client_func_test.go b/libgo/go/exp/ssh/client_func_test.go
deleted file mode 100644
index b4bdba95396..00000000000
--- a/libgo/go/exp/ssh/client_func_test.go
+++ /dev/null
@@ -1,61 +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
-
-// ClientConn functional tests.
-// These tests require a running ssh server listening on port 22
-// on the local host. Functional tests will be skipped unless
-// -ssh.user and -ssh.pass must be passed to gotest.
-
-import (
- "flag"
- "testing"
-)
-
-var (
- sshuser = flag.String("ssh.user", "", "ssh username")
- sshpass = flag.String("ssh.pass", "", "ssh password")
- sshprivkey = flag.String("ssh.privkey", "", "ssh privkey file")
-)
-
-func TestFuncPasswordAuth(t *testing.T) {
- if *sshuser == "" {
- t.Log("ssh.user not defined, skipping test")
- return
- }
- config := &ClientConfig{
- User: *sshuser,
- Auth: []ClientAuth{
- ClientAuthPassword(password(*sshpass)),
- },
- }
- conn, err := Dial("tcp", "localhost:22", config)
- if err != nil {
- t.Fatalf("Unable to connect: %s", err)
- }
- defer conn.Close()
-}
-
-func TestFuncPublickeyAuth(t *testing.T) {
- if *sshuser == "" {
- t.Log("ssh.user not defined, skipping test")
- return
- }
- kc := new(keychain)
- if err := kc.loadPEM(*sshprivkey); err != nil {
- t.Fatalf("unable to load private key: %s", err)
- }
- config := &ClientConfig{
- User: *sshuser,
- Auth: []ClientAuth{
- ClientAuthKeyring(kc),
- },
- }
- conn, err := Dial("tcp", "localhost:22", config)
- if err != nil {
- t.Fatalf("unable to connect: %s", err)
- }
- defer conn.Close()
-}
diff --git a/libgo/go/exp/ssh/common.go b/libgo/go/exp/ssh/common.go
deleted file mode 100644
index 6844fb89b79..00000000000
--- a/libgo/go/exp/ssh/common.go
+++ /dev/null
@@ -1,239 +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 (
- "crypto/dsa"
- "crypto/rsa"
- "math/big"
- "strconv"
- "sync"
-)
-
-// These are string constants in the SSH protocol.
-const (
- kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
- hostAlgoRSA = "ssh-rsa"
- macSHA196 = "hmac-sha1-96"
- compressionNone = "none"
- serviceUserAuth = "ssh-userauth"
- serviceSSH = "ssh-connection"
-)
-
-var supportedKexAlgos = []string{kexAlgoDH14SHA1}
-var supportedHostKeyAlgos = []string{hostAlgoRSA}
-var supportedMACs = []string{macSHA196}
-var supportedCompressions = []string{compressionNone}
-
-// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
-type dhGroup struct {
- g, p *big.Int
-}
-
-// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
-// Oakley Group 14 in RFC 3526.
-var dhGroup14 *dhGroup
-
-var dhGroup14Once sync.Once
-
-func initDHGroup14() {
- p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
-
- dhGroup14 = &dhGroup{
- g: new(big.Int).SetInt64(2),
- p: p,
- }
-}
-
-// UnexpectedMessageError results when the SSH message that we received didn't
-// match what we wanted.
-type UnexpectedMessageError struct {
- expected, got uint8
-}
-
-func (u UnexpectedMessageError) Error() string {
- return "ssh: unexpected message type " + strconv.Itoa(int(u.got)) + " (expected " + strconv.Itoa(int(u.expected)) + ")"
-}
-
-// ParseError results from a malformed SSH message.
-type ParseError struct {
- msgType uint8
-}
-
-func (p ParseError) Error() string {
- return "ssh: parse error in message type " + strconv.Itoa(int(p.msgType))
-}
-
-type handshakeMagics struct {
- clientVersion, serverVersion []byte
- clientKexInit, serverKexInit []byte
-}
-
-func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
- for _, clientAlgo := range clientAlgos {
- for _, serverAlgo := range serverAlgos {
- if clientAlgo == serverAlgo {
- return clientAlgo, true
- }
- }
- }
-
- return
-}
-
-func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) {
- kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
- if !ok {
- return
- }
-
- hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
- if !ok {
- return
- }
-
- transport.writer.cipherAlgo, ok = findCommonAlgorithm(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
- if !ok {
- return
- }
-
- transport.reader.cipherAlgo, ok = findCommonAlgorithm(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
- if !ok {
- return
- }
-
- transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
- if !ok {
- return
- }
-
- transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
- if !ok {
- return
- }
-
- transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
- if !ok {
- return
- }
-
- transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
- if !ok {
- return
- }
-
- ok = true
- return
-}
-
-// Cryptographic configuration common to both ServerConfig and ClientConfig.
-type CryptoConfig struct {
- // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
- // used.
- Ciphers []string
-}
-
-func (c *CryptoConfig) ciphers() []string {
- if c.Ciphers == nil {
- return DefaultCipherOrder
- }
- return c.Ciphers
-}
-
-// serialize a signed slice according to RFC 4254 6.6.
-func serializeSignature(algoname string, sig []byte) []byte {
- length := stringLength([]byte(algoname))
- length += stringLength(sig)
-
- ret := make([]byte, length)
- r := marshalString(ret, []byte(algoname))
- r = marshalString(r, sig)
-
- return ret
-}
-
-// serialize an rsa.PublicKey or dsa.PublicKey according to RFC 4253 6.6.
-func serializePublickey(key interface{}) []byte {
- algoname := algoName(key)
- switch key := key.(type) {
- case rsa.PublicKey:
- e := new(big.Int).SetInt64(int64(key.E))
- length := stringLength([]byte(algoname))
- length += intLength(e)
- length += intLength(key.N)
- ret := make([]byte, length)
- r := marshalString(ret, []byte(algoname))
- r = marshalInt(r, e)
- marshalInt(r, key.N)
- return ret
- case dsa.PublicKey:
- length := stringLength([]byte(algoname))
- length += intLength(key.P)
- length += intLength(key.Q)
- length += intLength(key.G)
- length += intLength(key.Y)
- ret := make([]byte, length)
- r := marshalString(ret, []byte(algoname))
- r = marshalInt(r, key.P)
- r = marshalInt(r, key.Q)
- r = marshalInt(r, key.G)
- marshalInt(r, key.Y)
- return ret
- }
- panic("unexpected key type")
-}
-
-func algoName(key interface{}) string {
- switch key.(type) {
- case rsa.PublicKey:
- return "ssh-rsa"
- case dsa.PublicKey:
- return "ssh-dss"
- }
- panic("unexpected key type")
-}
-
-// buildDataSignedForAuth returns the data that is signed in order to prove
-// posession of a private key. See RFC 4252, section 7.
-func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
- user := []byte(req.User)
- service := []byte(req.Service)
- method := []byte(req.Method)
-
- length := stringLength(sessionId)
- length += 1
- length += stringLength(user)
- length += stringLength(service)
- length += stringLength(method)
- length += 1
- length += stringLength(algo)
- length += stringLength(pubKey)
-
- ret := make([]byte, length)
- r := marshalString(ret, sessionId)
- r[0] = msgUserAuthRequest
- r = r[1:]
- r = marshalString(r, user)
- r = marshalString(r, service)
- r = marshalString(r, method)
- r[0] = 1
- r = r[1:]
- r = marshalString(r, algo)
- r = marshalString(r, pubKey)
- return ret
-}
-
-// safeString sanitises s according to RFC 4251, section 9.2.
-// All control characters except tab, carriage return and newline are
-// replaced by 0x20.
-func safeString(s string) string {
- out := []byte(s)
- for i, c := range out {
- if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
- out[i] = 0x20
- }
- }
- return string(out)
-}
diff --git a/libgo/go/exp/ssh/common_test.go b/libgo/go/exp/ssh/common_test.go
deleted file mode 100644
index 058fb04fe1b..00000000000
--- a/libgo/go/exp/ssh/common_test.go
+++ /dev/null
@@ -1,26 +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 (
- "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))
- }
- }
-}
diff --git a/libgo/go/exp/ssh/doc.go b/libgo/go/exp/ssh/doc.go
deleted file mode 100644
index e7deb5ec168..00000000000
--- a/libgo/go/exp/ssh/doc.go
+++ /dev/null
@@ -1,127 +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 implements an SSH client and server.
-
-SSH is a transport security protocol, an authentication protocol and a
-family of application protocols. The most typical application level
-protocol is a remote shell and this is specifically implemented. However,
-the multiplexed nature of SSH is exposed to users that wish to support
-others.
-
-An SSH server is represented by a ServerConfig, which holds certificate
-details and handles authentication of ServerConns.
-
- config := new(ssh.ServerConfig)
- config.PubKeyCallback = pubKeyAuth
- config.PasswordCallback = passwordAuth
-
- pemBytes, err := ioutil.ReadFile("id_rsa")
- if err != nil {
- panic("Failed to load private key")
- }
- err = config.SetRSAPrivateKey(pemBytes)
- if err != nil {
- panic("Failed to parse private key")
- }
-
-Once a ServerConfig has been configured, connections can be accepted.
-
- listener := Listen("tcp", "0.0.0.0:2022", config)
- sConn, err := listener.Accept()
- if err != nil {
- panic("failed to accept incoming connection")
- }
- if err := sConn.Handshake(conn); err != nil {
- panic("failed to handshake")
- }
-
-An SSH connection multiplexes several channels, which must be accepted themselves:
-
- for {
- channel, err := sConn.Accept()
- if err != nil {
- panic("error from Accept")
- }
-
- ...
- }
-
-Accept reads from the connection, demultiplexes packets to their corresponding
-channels and returns when a new channel request is seen. Some goroutine must
-always be calling Accept; otherwise no messages will be forwarded to the
-channels.
-
-Channels have a type, depending on the application level protocol intended. In
-the case of a shell, the type is "session" and ServerShell may be used to
-present a simple terminal interface.
-
- if channel.ChannelType() != "session" {
- channel.Reject(UnknownChannelType, "unknown channel type")
- return
- }
- channel.Accept()
-
- term := terminal.NewTerminal(channel, "> ")
- serverTerm := &ssh.ServerTerminal{
- Term: term,
- Channel: channel,
- }
- go func() {
- defer channel.Close()
- for {
- line, err := serverTerm.ReadLine()
- if err != nil {
- break
- }
- println(line)
- }
- return
- }()
-
-To authenticate with the remote server you must pass at least one implementation of
-ClientAuth via the Auth field in ClientConfig.
-
- // password implements the ClientPassword interface
- type password string
-
- func (p password) Password(user string) (string, error) {
- return string(p), nil
- }
-
- config := &ssh.ClientConfig {
- User: "username",
- Auth: []ClientAuth {
- // ClientAuthPassword wraps a ClientPassword implementation
- // in a type that implements ClientAuth.
- ClientAuthPassword(password("yourpassword")),
- }
- }
-
-An SSH client is represented with a ClientConn. Currently only the "password"
-authentication method is supported.
-
- config := &ClientConfig{
- User: "username",
- Auth: []ClientAuth{ ... },
- }
- client, err := Dial("yourserver.com:22", config)
-
-Each ClientConn can support multiple interactive sessions, represented by a Session.
-
- session, err := client.NewSession()
-
-Once a Session is created, you can execute a single command on the remote side
-using the Exec method.
-
- b := bytes.NewBuffer()
- session.Stdin = b
- if err := session.Run("/usr/bin/whoami"); err != nil {
- panic("Failed to exec: " + err.String())
- }
- fmt.Println(bytes.String())
- session.Close()
-*/
-package ssh
diff --git a/libgo/go/exp/ssh/messages.go b/libgo/go/exp/ssh/messages.go
deleted file mode 100644
index 34ad131ff64..00000000000
--- a/libgo/go/exp/ssh/messages.go
+++ /dev/null
@@ -1,640 +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 (
- "bytes"
- "io"
- "math/big"
- "reflect"
-)
-
-// These are SSH message type numbers. They are scattered around several
-// documents but many were taken from
-// http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
-const (
- msgDisconnect = 1
- msgIgnore = 2
- msgUnimplemented = 3
- msgDebug = 4
- msgServiceRequest = 5
- msgServiceAccept = 6
-
- msgKexInit = 20
- msgNewKeys = 21
-
- msgKexDHInit = 30
- msgKexDHReply = 31
-
- msgUserAuthRequest = 50
- msgUserAuthFailure = 51
- msgUserAuthSuccess = 52
- msgUserAuthBanner = 53
- msgUserAuthPubKeyOk = 60
-
- msgGlobalRequest = 80
- msgRequestSuccess = 81
- msgRequestFailure = 82
-
- msgChannelOpen = 90
- msgChannelOpenConfirm = 91
- msgChannelOpenFailure = 92
- msgChannelWindowAdjust = 93
- msgChannelData = 94
- msgChannelExtendedData = 95
- msgChannelEOF = 96
- msgChannelClose = 97
- msgChannelRequest = 98
- msgChannelSuccess = 99
- msgChannelFailure = 100
-)
-
-// SSH messages:
-//
-// These structures mirror the wire format of the corresponding SSH messages.
-// They are marshaled using reflection with the marshal and unmarshal functions
-// in this file. The only wrinkle is that a final member of type []byte with a
-// ssh tag of "rest" receives the remainder of a packet when unmarshaling.
-
-// See RFC 4253, section 11.1.
-type disconnectMsg struct {
- Reason uint32
- Message string
- Language string
-}
-
-// See RFC 4253, section 7.1.
-type kexInitMsg struct {
- Cookie [16]byte
- KexAlgos []string
- ServerHostKeyAlgos []string
- CiphersClientServer []string
- CiphersServerClient []string
- MACsClientServer []string
- MACsServerClient []string
- CompressionClientServer []string
- CompressionServerClient []string
- LanguagesClientServer []string
- LanguagesServerClient []string
- FirstKexFollows bool
- Reserved uint32
-}
-
-// See RFC 4253, section 8.
-type kexDHInitMsg struct {
- X *big.Int
-}
-
-type kexDHReplyMsg struct {
- HostKey []byte
- Y *big.Int
- Signature []byte
-}
-
-// See RFC 4253, section 10.
-type serviceRequestMsg struct {
- Service string
-}
-
-// See RFC 4253, section 10.
-type serviceAcceptMsg struct {
- Service string
-}
-
-// See RFC 4252, section 5.
-type userAuthRequestMsg struct {
- User string
- Service string
- Method string
- Payload []byte `ssh:"rest"`
-}
-
-// See RFC 4252, section 5.1
-type userAuthFailureMsg struct {
- Methods []string
- PartialSuccess bool
-}
-
-// See RFC 4254, section 5.1.
-type channelOpenMsg struct {
- ChanType string
- PeersId uint32
- PeersWindow uint32
- MaxPacketSize uint32
- TypeSpecificData []byte `ssh:"rest"`
-}
-
-// See RFC 4254, section 5.1.
-type channelOpenConfirmMsg struct {
- PeersId uint32
- MyId uint32
- MyWindow uint32
- MaxPacketSize uint32
- TypeSpecificData []byte `ssh:"rest"`
-}
-
-// See RFC 4254, section 5.1.
-type channelOpenFailureMsg struct {
- PeersId uint32
- Reason uint32
- Message string
- Language string
-}
-
-type channelRequestMsg struct {
- PeersId uint32
- Request string
- WantReply bool
- RequestSpecificData []byte `ssh:"rest"`
-}
-
-// See RFC 4254, section 5.4.
-type channelRequestSuccessMsg struct {
- PeersId uint32
-}
-
-// See RFC 4254, section 5.4.
-type channelRequestFailureMsg struct {
- PeersId uint32
-}
-
-// See RFC 4254, section 5.3
-type channelCloseMsg struct {
- PeersId uint32
-}
-
-// See RFC 4254, section 5.3
-type channelEOFMsg struct {
- PeersId uint32
-}
-
-// See RFC 4254, section 4
-type globalRequestMsg struct {
- Type string
- WantReply bool
-}
-
-// See RFC 4254, section 5.2
-type windowAdjustMsg struct {
- PeersId uint32
- AdditionalBytes uint32
-}
-
-// See RFC 4252, section 7
-type userAuthPubKeyOkMsg struct {
- Algo string
- PubKey string
-}
-
-// unmarshal parses the SSH wire data in packet into out using reflection.
-// expectedType is the expected SSH message type. It either returns nil on
-// success, or a ParseError or UnexpectedMessageError on error.
-func unmarshal(out interface{}, packet []byte, expectedType uint8) error {
- if len(packet) == 0 {
- return ParseError{expectedType}
- }
- if packet[0] != expectedType {
- return UnexpectedMessageError{expectedType, packet[0]}
- }
- packet = packet[1:]
-
- v := reflect.ValueOf(out).Elem()
- structType := v.Type()
- var ok bool
- for i := 0; i < v.NumField(); i++ {
- field := v.Field(i)
- t := field.Type()
- switch t.Kind() {
- case reflect.Bool:
- if len(packet) < 1 {
- return ParseError{expectedType}
- }
- field.SetBool(packet[0] != 0)
- packet = packet[1:]
- case reflect.Array:
- if t.Elem().Kind() != reflect.Uint8 {
- panic("array of non-uint8")
- }
- if len(packet) < t.Len() {
- return ParseError{expectedType}
- }
- for j := 0; j < t.Len(); j++ {
- field.Index(j).Set(reflect.ValueOf(packet[j]))
- }
- packet = packet[t.Len():]
- case reflect.Uint32:
- var u32 uint32
- if u32, packet, ok = parseUint32(packet); !ok {
- return ParseError{expectedType}
- }
- field.SetUint(uint64(u32))
- case reflect.String:
- var s []byte
- if s, packet, ok = parseString(packet); !ok {
- return ParseError{expectedType}
- }
- field.SetString(string(s))
- case reflect.Slice:
- switch t.Elem().Kind() {
- case reflect.Uint8:
- if structType.Field(i).Tag.Get("ssh") == "rest" {
- field.Set(reflect.ValueOf(packet))
- packet = nil
- } else {
- var s []byte
- if s, packet, ok = parseString(packet); !ok {
- return ParseError{expectedType}
- }
- field.Set(reflect.ValueOf(s))
- }
- case reflect.String:
- var nl []string
- if nl, packet, ok = parseNameList(packet); !ok {
- return ParseError{expectedType}
- }
- field.Set(reflect.ValueOf(nl))
- default:
- panic("slice of unknown type")
- }
- case reflect.Ptr:
- if t == bigIntType {
- var n *big.Int
- if n, packet, ok = parseInt(packet); !ok {
- return ParseError{expectedType}
- }
- field.Set(reflect.ValueOf(n))
- } else {
- panic("pointer to unknown type")
- }
- default:
- panic("unknown type")
- }
- }
-
- if len(packet) != 0 {
- return ParseError{expectedType}
- }
-
- return nil
-}
-
-// marshal serializes the message in msg, using the given message type.
-func marshal(msgType uint8, msg interface{}) []byte {
- var out []byte
- out = append(out, msgType)
-
- v := reflect.ValueOf(msg)
- structType := v.Type()
- for i := 0; i < v.NumField(); i++ {
- field := v.Field(i)
- t := field.Type()
- switch t.Kind() {
- case reflect.Bool:
- var v uint8
- if field.Bool() {
- v = 1
- }
- out = append(out, v)
- case reflect.Array:
- if t.Elem().Kind() != reflect.Uint8 {
- panic("array of non-uint8")
- }
- for j := 0; j < t.Len(); j++ {
- out = append(out, byte(field.Index(j).Uint()))
- }
- case reflect.Uint32:
- u32 := uint32(field.Uint())
- out = append(out, byte(u32>>24))
- out = append(out, byte(u32>>16))
- out = append(out, byte(u32>>8))
- out = append(out, byte(u32))
- case reflect.String:
- s := field.String()
- out = append(out, byte(len(s)>>24))
- out = append(out, byte(len(s)>>16))
- out = append(out, byte(len(s)>>8))
- out = append(out, byte(len(s)))
- out = append(out, s...)
- case reflect.Slice:
- switch t.Elem().Kind() {
- case reflect.Uint8:
- length := field.Len()
- if structType.Field(i).Tag.Get("ssh") != "rest" {
- out = append(out, byte(length>>24))
- out = append(out, byte(length>>16))
- out = append(out, byte(length>>8))
- out = append(out, byte(length))
- }
- for j := 0; j < length; j++ {
- out = append(out, byte(field.Index(j).Uint()))
- }
- case reflect.String:
- var length int
- for j := 0; j < field.Len(); j++ {
- if j != 0 {
- length++ /* comma */
- }
- length += len(field.Index(j).String())
- }
-
- out = append(out, byte(length>>24))
- out = append(out, byte(length>>16))
- out = append(out, byte(length>>8))
- out = append(out, byte(length))
- for j := 0; j < field.Len(); j++ {
- if j != 0 {
- out = append(out, ',')
- }
- out = append(out, field.Index(j).String()...)
- }
- default:
- panic("slice of unknown type")
- }
- case reflect.Ptr:
- if t == bigIntType {
- var n *big.Int
- nValue := reflect.ValueOf(&n)
- nValue.Elem().Set(field)
- needed := intLength(n)
- oldLength := len(out)
-
- if cap(out)-len(out) < needed {
- newOut := make([]byte, len(out), 2*(len(out)+needed))
- copy(newOut, out)
- out = newOut
- }
- out = out[:oldLength+needed]
- marshalInt(out[oldLength:], n)
- } else {
- panic("pointer to unknown type")
- }
- }
- }
-
- return out
-}
-
-var bigOne = big.NewInt(1)
-
-func parseString(in []byte) (out, rest []byte, ok bool) {
- if len(in) < 4 {
- return
- }
- length := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3])
- if uint32(len(in)) < 4+length {
- return
- }
- out = in[4 : 4+length]
- rest = in[4+length:]
- ok = true
- return
-}
-
-var (
- comma = []byte{','}
- emptyNameList = []string{}
-)
-
-func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
- contents, rest, ok := parseString(in)
- if !ok {
- return
- }
- if len(contents) == 0 {
- out = emptyNameList
- return
- }
- parts := bytes.Split(contents, comma)
- out = make([]string, len(parts))
- for i, part := range parts {
- out[i] = string(part)
- }
- return
-}
-
-func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
- contents, rest, ok := parseString(in)
- if !ok {
- return
- }
- out = new(big.Int)
-
- if len(contents) > 0 && contents[0]&0x80 == 0x80 {
- // This is a negative number
- notBytes := make([]byte, len(contents))
- for i := range notBytes {
- notBytes[i] = ^contents[i]
- }
- out.SetBytes(notBytes)
- out.Add(out, bigOne)
- out.Neg(out)
- } else {
- // Positive number
- out.SetBytes(contents)
- }
- ok = true
- return
-}
-
-func parseUint32(in []byte) (out uint32, rest []byte, ok bool) {
- if len(in) < 4 {
- return
- }
- out = uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3])
- rest = in[4:]
- ok = true
- return
-}
-
-func nameListLength(namelist []string) int {
- length := 4 /* uint32 length prefix */
- for i, name := range namelist {
- if i != 0 {
- length++ /* comma */
- }
- length += len(name)
- }
- return length
-}
-
-func intLength(n *big.Int) int {
- length := 4 /* length bytes */
- if n.Sign() < 0 {
- nMinus1 := new(big.Int).Neg(n)
- nMinus1.Sub(nMinus1, bigOne)
- bitLen := nMinus1.BitLen()
- if bitLen%8 == 0 {
- // The number will need 0xff padding
- length++
- }
- length += (bitLen + 7) / 8
- } else if n.Sign() == 0 {
- // A zero is the zero length string
- } else {
- bitLen := n.BitLen()
- if bitLen%8 == 0 {
- // The number will need 0x00 padding
- length++
- }
- length += (bitLen + 7) / 8
- }
-
- return length
-}
-
-func marshalUint32(to []byte, n uint32) []byte {
- to[0] = byte(n >> 24)
- to[1] = byte(n >> 16)
- to[2] = byte(n >> 8)
- to[3] = byte(n)
- return to[4:]
-}
-
-func marshalUint64(to []byte, n uint64) []byte {
- to[0] = byte(n >> 56)
- to[1] = byte(n >> 48)
- to[2] = byte(n >> 40)
- to[3] = byte(n >> 32)
- to[4] = byte(n >> 24)
- to[5] = byte(n >> 16)
- to[6] = byte(n >> 8)
- to[7] = byte(n)
- return to[8:]
-}
-
-func marshalInt(to []byte, n *big.Int) []byte {
- lengthBytes := to
- to = to[4:]
- length := 0
-
- if n.Sign() < 0 {
- // A negative number has to be converted to two's-complement
- // form. So we'll subtract 1 and invert. If the
- // most-significant-bit isn't set then we'll need to pad the
- // beginning with 0xff in order to keep the number negative.
- nMinus1 := new(big.Int).Neg(n)
- nMinus1.Sub(nMinus1, bigOne)
- bytes := nMinus1.Bytes()
- for i := range bytes {
- bytes[i] ^= 0xff
- }
- if len(bytes) == 0 || bytes[0]&0x80 == 0 {
- to[0] = 0xff
- to = to[1:]
- length++
- }
- nBytes := copy(to, bytes)
- to = to[nBytes:]
- length += nBytes
- } else if n.Sign() == 0 {
- // A zero is the zero length string
- } else {
- bytes := n.Bytes()
- if len(bytes) > 0 && bytes[0]&0x80 != 0 {
- // We'll have to pad this with a 0x00 in order to
- // stop it looking like a negative number.
- to[0] = 0
- to = to[1:]
- length++
- }
- nBytes := copy(to, bytes)
- to = to[nBytes:]
- length += nBytes
- }
-
- lengthBytes[0] = byte(length >> 24)
- lengthBytes[1] = byte(length >> 16)
- lengthBytes[2] = byte(length >> 8)
- lengthBytes[3] = byte(length)
- return to
-}
-
-func writeInt(w io.Writer, n *big.Int) {
- length := intLength(n)
- buf := make([]byte, length)
- marshalInt(buf, n)
- w.Write(buf)
-}
-
-func writeString(w io.Writer, s []byte) {
- var lengthBytes [4]byte
- lengthBytes[0] = byte(len(s) >> 24)
- lengthBytes[1] = byte(len(s) >> 16)
- lengthBytes[2] = byte(len(s) >> 8)
- lengthBytes[3] = byte(len(s))
- w.Write(lengthBytes[:])
- w.Write(s)
-}
-
-func stringLength(s []byte) int {
- return 4 + len(s)
-}
-
-func marshalString(to []byte, s []byte) []byte {
- to[0] = byte(len(s) >> 24)
- to[1] = byte(len(s) >> 16)
- to[2] = byte(len(s) >> 8)
- to[3] = byte(len(s))
- to = to[4:]
- copy(to, s)
- return to[len(s):]
-}
-
-var bigIntType = reflect.TypeOf((*big.Int)(nil))
-
-// Decode a packet into it's corresponding message.
-func decode(packet []byte) interface{} {
- var msg interface{}
- switch packet[0] {
- case msgDisconnect:
- msg = new(disconnectMsg)
- case msgServiceRequest:
- msg = new(serviceRequestMsg)
- case msgServiceAccept:
- msg = new(serviceAcceptMsg)
- case msgKexInit:
- msg = new(kexInitMsg)
- case msgKexDHInit:
- msg = new(kexDHInitMsg)
- case msgKexDHReply:
- msg = new(kexDHReplyMsg)
- case msgUserAuthRequest:
- msg = new(userAuthRequestMsg)
- case msgUserAuthFailure:
- msg = new(userAuthFailureMsg)
- case msgUserAuthPubKeyOk:
- msg = new(userAuthPubKeyOkMsg)
- case msgGlobalRequest:
- msg = new(globalRequestMsg)
- case msgRequestSuccess:
- msg = new(channelRequestSuccessMsg)
- case msgRequestFailure:
- msg = new(channelRequestFailureMsg)
- case msgChannelOpen:
- msg = new(channelOpenMsg)
- case msgChannelOpenConfirm:
- msg = new(channelOpenConfirmMsg)
- case msgChannelOpenFailure:
- msg = new(channelOpenFailureMsg)
- case msgChannelWindowAdjust:
- msg = new(windowAdjustMsg)
- case msgChannelEOF:
- msg = new(channelEOFMsg)
- case msgChannelClose:
- msg = new(channelCloseMsg)
- case msgChannelRequest:
- msg = new(channelRequestMsg)
- case msgChannelSuccess:
- msg = new(channelRequestSuccessMsg)
- case msgChannelFailure:
- msg = new(channelRequestFailureMsg)
- default:
- return UnexpectedMessageError{0, packet[0]}
- }
- if err := unmarshal(msg, packet, packet[0]); err != nil {
- return err
- }
- return msg
-}
diff --git a/libgo/go/exp/ssh/messages_test.go b/libgo/go/exp/ssh/messages_test.go
deleted file mode 100644
index fe4c397dc3a..00000000000
--- a/libgo/go/exp/ssh/messages_test.go
+++ /dev/null
@@ -1,125 +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 (
- "math/big"
- "math/rand"
- "reflect"
- "testing"
- "testing/quick"
-)
-
-var intLengthTests = []struct {
- val, length int
-}{
- {0, 4 + 0},
- {1, 4 + 1},
- {127, 4 + 1},
- {128, 4 + 2},
- {-1, 4 + 1},
-}
-
-func TestIntLength(t *testing.T) {
- for _, test := range intLengthTests {
- v := new(big.Int).SetInt64(int64(test.val))
- length := intLength(v)
- if length != test.length {
- t.Errorf("For %d, got length %d but expected %d", test.val, length, test.length)
- }
- }
-}
-
-var messageTypes = []interface{}{
- &kexInitMsg{},
- &kexDHInitMsg{},
- &serviceRequestMsg{},
- &serviceAcceptMsg{},
- &userAuthRequestMsg{},
- &channelOpenMsg{},
- &channelOpenConfirmMsg{},
- &channelRequestMsg{},
- &channelRequestSuccessMsg{},
-}
-
-func TestMarshalUnmarshal(t *testing.T) {
- rand := rand.New(rand.NewSource(0))
- for i, iface := range messageTypes {
- ty := reflect.ValueOf(iface).Type()
-
- n := 100
- if testing.Short() {
- n = 5
- }
- for j := 0; j < n; j++ {
- v, ok := quick.Value(ty, rand)
- if !ok {
- t.Errorf("#%d: failed to create value", i)
- break
- }
-
- m1 := v.Elem().Interface()
- m2 := iface
-
- marshaled := marshal(msgIgnore, m1)
- if err := unmarshal(m2, marshaled, msgIgnore); err != nil {
- t.Errorf("#%d failed to unmarshal %#v: %s", i, m1, err)
- break
- }
-
- if !reflect.DeepEqual(v.Interface(), m2) {
- t.Errorf("#%d\ngot: %#v\nwant:%#v\n%x", i, m2, m1, marshaled)
- break
- }
- }
- }
-}
-
-func randomBytes(out []byte, rand *rand.Rand) {
- for i := 0; i < len(out); i++ {
- out[i] = byte(rand.Int31())
- }
-}
-
-func randomNameList(rand *rand.Rand) []string {
- ret := make([]string, rand.Int31()&15)
- for i := range ret {
- s := make([]byte, 1+(rand.Int31()&15))
- for j := range s {
- s[j] = 'a' + uint8(rand.Int31()&15)
- }
- ret[i] = string(s)
- }
- return ret
-}
-
-func randomInt(rand *rand.Rand) *big.Int {
- return new(big.Int).SetInt64(int64(int32(rand.Uint32())))
-}
-
-func (*kexInitMsg) Generate(rand *rand.Rand, size int) reflect.Value {
- ki := &kexInitMsg{}
- randomBytes(ki.Cookie[:], rand)
- ki.KexAlgos = randomNameList(rand)
- ki.ServerHostKeyAlgos = randomNameList(rand)
- ki.CiphersClientServer = randomNameList(rand)
- ki.CiphersServerClient = randomNameList(rand)
- ki.MACsClientServer = randomNameList(rand)
- ki.MACsServerClient = randomNameList(rand)
- ki.CompressionClientServer = randomNameList(rand)
- ki.CompressionServerClient = randomNameList(rand)
- ki.LanguagesClientServer = randomNameList(rand)
- ki.LanguagesServerClient = randomNameList(rand)
- if rand.Int31()&1 == 1 {
- ki.FirstKexFollows = true
- }
- return reflect.ValueOf(ki)
-}
-
-func (*kexDHInitMsg) Generate(rand *rand.Rand, size int) reflect.Value {
- dhi := &kexDHInitMsg{}
- dhi.X = randomInt(rand)
- return reflect.ValueOf(dhi)
-}
diff --git a/libgo/go/exp/ssh/server.go b/libgo/go/exp/ssh/server.go
deleted file mode 100644
index 31011c66176..00000000000
--- a/libgo/go/exp/ssh/server.go
+++ /dev/null
@@ -1,676 +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 (
- "bytes"
- "crypto"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "encoding/pem"
- "errors"
- "io"
- "math/big"
- "net"
- "sync"
-)
-
-type ServerConfig struct {
- rsa *rsa.PrivateKey
- rsaSerialized []byte
-
- // Rand provides the source of entropy for key exchange. If Rand is
- // nil, the cryptographic random reader in package crypto/rand will
- // be used.
- Rand io.Reader
-
- // NoClientAuth is true if clients are allowed to connect without
- // authenticating.
- NoClientAuth bool
-
- // PasswordCallback, if non-nil, is called when a user attempts to
- // authenticate using a password. It may be called concurrently from
- // several goroutines.
- PasswordCallback func(user, password string) bool
-
- // PublicKeyCallback, if non-nil, is called when a client attempts public
- // key authentication. It must return true iff the given public key is
- // valid for the given user.
- PublicKeyCallback func(user, algo string, pubkey []byte) bool
-
- // Cryptographic-related configuration.
- Crypto CryptoConfig
-}
-
-func (c *ServerConfig) rand() io.Reader {
- if c.Rand == nil {
- return rand.Reader
- }
- return c.Rand
-}
-
-// SetRSAPrivateKey sets the private key for a Server. A Server must have a
-// private key configured in order to accept connections. The private key must
-// be in the form of a PEM encoded, PKCS#1, RSA private key. The file "id_rsa"
-// typically contains such a key.
-func (s *ServerConfig) SetRSAPrivateKey(pemBytes []byte) error {
- block, _ := pem.Decode(pemBytes)
- if block == nil {
- return errors.New("ssh: no key found")
- }
- var err error
- s.rsa, err = x509.ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- return err
- }
-
- s.rsaSerialized = marshalRSA(s.rsa)
- return nil
-}
-
-// marshalRSA serializes an RSA private key according to RFC 4256, section 6.6.
-func marshalRSA(priv *rsa.PrivateKey) []byte {
- e := new(big.Int).SetInt64(int64(priv.E))
- length := stringLength([]byte(hostAlgoRSA))
- length += intLength(e)
- length += intLength(priv.N)
-
- ret := make([]byte, length)
- r := marshalString(ret, []byte(hostAlgoRSA))
- r = marshalInt(r, e)
- r = marshalInt(r, priv.N)
-
- return ret
-}
-
-// parseRSA parses an RSA key according to RFC 4256, section 6.6.
-func parseRSA(in []byte) (pubKey *rsa.PublicKey, ok bool) {
- algo, in, ok := parseString(in)
- if !ok || string(algo) != hostAlgoRSA {
- return nil, false
- }
- bigE, in, ok := parseInt(in)
- if !ok || bigE.BitLen() > 24 {
- return nil, false
- }
- e := bigE.Int64()
- if e < 3 || e&1 == 0 {
- return nil, false
- }
- N, in, ok := parseInt(in)
- if !ok || len(in) > 0 {
- return nil, false
- }
- return &rsa.PublicKey{
- N: N,
- E: int(e),
- }, true
-}
-
-func parseRSASig(in []byte) (sig []byte, ok bool) {
- algo, in, ok := parseString(in)
- if !ok || string(algo) != hostAlgoRSA {
- return nil, false
- }
- sig, in, ok = parseString(in)
- if len(in) > 0 {
- ok = false
- }
- return
-}
-
-// cachedPubKey contains the results of querying whether a public key is
-// acceptable for a user. The cache only applies to a single ServerConn.
-type cachedPubKey struct {
- user, algo string
- pubKey []byte
- result bool
-}
-
-const maxCachedPubKeys = 16
-
-// A ServerConn represents an incomming connection.
-type ServerConn struct {
- *transport
- config *ServerConfig
-
- channels map[uint32]*channel
- nextChanId uint32
-
- // lock protects err and also allows Channels to serialise their writes
- // to out.
- lock sync.RWMutex
- err error
-
- // cachedPubKeys contains the cache results of tests for public keys.
- // Since SSH clients will query whether a public key is acceptable
- // before attempting to authenticate with it, we end up with duplicate
- // queries for public key validity.
- cachedPubKeys []cachedPubKey
-}
-
-// Server returns a new SSH server connection
-// using c as the underlying transport.
-func Server(c net.Conn, config *ServerConfig) *ServerConn {
- conn := &ServerConn{
- transport: newTransport(c, config.rand()),
- channels: make(map[uint32]*channel),
- config: config,
- }
- return conn
-}
-
-// kexDH performs Diffie-Hellman key agreement on a ServerConnection. The
-// returned values are given the same names as in RFC 4253, section 8.
-func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) (H, K []byte, err error) {
- packet, err := s.readPacket()
- if err != nil {
- return
- }
- var kexDHInit kexDHInitMsg
- if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil {
- return
- }
-
- if kexDHInit.X.Sign() == 0 || kexDHInit.X.Cmp(group.p) >= 0 {
- return nil, nil, errors.New("client DH parameter out of bounds")
- }
-
- y, err := rand.Int(s.config.rand(), group.p)
- if err != nil {
- return
- }
-
- Y := new(big.Int).Exp(group.g, y, group.p)
- kInt := new(big.Int).Exp(kexDHInit.X, y, group.p)
-
- var serializedHostKey []byte
- switch hostKeyAlgo {
- case hostAlgoRSA:
- serializedHostKey = s.config.rsaSerialized
- default:
- return nil, nil, errors.New("internal error")
- }
-
- h := hashFunc.New()
- writeString(h, magics.clientVersion)
- writeString(h, magics.serverVersion)
- writeString(h, magics.clientKexInit)
- writeString(h, magics.serverKexInit)
- writeString(h, serializedHostKey)
- writeInt(h, kexDHInit.X)
- writeInt(h, Y)
- K = make([]byte, intLength(kInt))
- marshalInt(K, kInt)
- h.Write(K)
-
- H = h.Sum(nil)
-
- h.Reset()
- h.Write(H)
- hh := h.Sum(nil)
-
- var sig []byte
- switch hostKeyAlgo {
- case hostAlgoRSA:
- sig, err = rsa.SignPKCS1v15(s.config.rand(), s.config.rsa, hashFunc, hh)
- if err != nil {
- return
- }
- default:
- return nil, nil, errors.New("internal error")
- }
-
- serializedSig := serializeSignature(hostAlgoRSA, sig)
-
- kexDHReply := kexDHReplyMsg{
- HostKey: serializedHostKey,
- Y: Y,
- Signature: serializedSig,
- }
- packet = marshal(msgKexDHReply, kexDHReply)
-
- err = s.writePacket(packet)
- return
-}
-
-// serverVersion is the fixed identification string that Server will use.
-var serverVersion = []byte("SSH-2.0-Go\r\n")
-
-// Handshake performs an SSH transport and client authentication on the given ServerConn.
-func (s *ServerConn) Handshake() error {
- var magics handshakeMagics
- if _, err := s.Write(serverVersion); err != nil {
- return err
- }
- if err := s.Flush(); err != nil {
- return err
- }
- magics.serverVersion = serverVersion[:len(serverVersion)-2]
-
- version, err := readVersion(s)
- if err != nil {
- return err
- }
- magics.clientVersion = version
-
- serverKexInit := kexInitMsg{
- KexAlgos: supportedKexAlgos,
- ServerHostKeyAlgos: supportedHostKeyAlgos,
- CiphersClientServer: s.config.Crypto.ciphers(),
- CiphersServerClient: s.config.Crypto.ciphers(),
- MACsClientServer: supportedMACs,
- MACsServerClient: supportedMACs,
- CompressionClientServer: supportedCompressions,
- CompressionServerClient: supportedCompressions,
- }
- kexInitPacket := marshal(msgKexInit, serverKexInit)
- magics.serverKexInit = kexInitPacket
-
- if err := s.writePacket(kexInitPacket); err != nil {
- return err
- }
-
- packet, err := s.readPacket()
- if err != nil {
- return err
- }
-
- magics.clientKexInit = packet
-
- var clientKexInit kexInitMsg
- if err = unmarshal(&clientKexInit, packet, msgKexInit); err != nil {
- return err
- }
-
- kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(s.transport, &clientKexInit, &serverKexInit)
- if !ok {
- return errors.New("ssh: no common algorithms")
- }
-
- if clientKexInit.FirstKexFollows && kexAlgo != clientKexInit.KexAlgos[0] {
- // The client sent a Kex message for the wrong algorithm,
- // which we have to ignore.
- if _, err := s.readPacket(); err != nil {
- return err
- }
- }
-
- var H, K []byte
- var hashFunc crypto.Hash
- switch kexAlgo {
- case kexAlgoDH14SHA1:
- hashFunc = crypto.SHA1
- dhGroup14Once.Do(initDHGroup14)
- H, K, err = s.kexDH(dhGroup14, hashFunc, &magics, hostKeyAlgo)
- default:
- err = errors.New("ssh: unexpected key exchange algorithm " + kexAlgo)
- }
- if err != nil {
- return err
- }
-
- if err = s.writePacket([]byte{msgNewKeys}); err != nil {
- return err
- }
- if err = s.transport.writer.setupKeys(serverKeys, K, H, H, hashFunc); err != nil {
- return err
- }
- if packet, err = s.readPacket(); err != nil {
- return err
- }
-
- if packet[0] != msgNewKeys {
- return UnexpectedMessageError{msgNewKeys, packet[0]}
- }
- if err = s.transport.reader.setupKeys(clientKeys, K, H, H, hashFunc); err != nil {
- return err
- }
- if packet, err = s.readPacket(); err != nil {
- return err
- }
-
- var serviceRequest serviceRequestMsg
- if err = unmarshal(&serviceRequest, packet, msgServiceRequest); err != nil {
- return err
- }
- if serviceRequest.Service != serviceUserAuth {
- return errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
- }
- serviceAccept := serviceAcceptMsg{
- Service: serviceUserAuth,
- }
- if err = s.writePacket(marshal(msgServiceAccept, serviceAccept)); err != nil {
- return err
- }
-
- if err = s.authenticate(H); err != nil {
- return err
- }
- return nil
-}
-
-func isAcceptableAlgo(algo string) bool {
- return algo == hostAlgoRSA
-}
-
-// testPubKey returns true if the given public key is acceptable for the user.
-func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
- if s.config.PublicKeyCallback == nil || !isAcceptableAlgo(algo) {
- return false
- }
-
- for _, c := range s.cachedPubKeys {
- if c.user == user && c.algo == algo && bytes.Equal(c.pubKey, pubKey) {
- return c.result
- }
- }
-
- result := s.config.PublicKeyCallback(user, algo, pubKey)
- if len(s.cachedPubKeys) < maxCachedPubKeys {
- c := cachedPubKey{
- user: user,
- algo: algo,
- pubKey: make([]byte, len(pubKey)),
- result: result,
- }
- copy(c.pubKey, pubKey)
- s.cachedPubKeys = append(s.cachedPubKeys, c)
- }
-
- return result
-}
-
-func (s *ServerConn) authenticate(H []byte) error {
- var userAuthReq userAuthRequestMsg
- var err error
- var packet []byte
-
-userAuthLoop:
- for {
- if packet, err = s.readPacket(); err != nil {
- return err
- }
- if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); err != nil {
- return err
- }
-
- if userAuthReq.Service != serviceSSH {
- return errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
- }
-
- switch userAuthReq.Method {
- case "none":
- if s.config.NoClientAuth {
- break userAuthLoop
- }
- case "password":
- if s.config.PasswordCallback == nil {
- break
- }
- payload := userAuthReq.Payload
- if len(payload) < 1 || payload[0] != 0 {
- return ParseError{msgUserAuthRequest}
- }
- payload = payload[1:]
- password, payload, ok := parseString(payload)
- if !ok || len(payload) > 0 {
- return ParseError{msgUserAuthRequest}
- }
-
- if s.config.PasswordCallback(userAuthReq.User, string(password)) {
- break userAuthLoop
- }
- case "publickey":
- if s.config.PublicKeyCallback == nil {
- break
- }
- payload := userAuthReq.Payload
- if len(payload) < 1 {
- return ParseError{msgUserAuthRequest}
- }
- isQuery := payload[0] == 0
- payload = payload[1:]
- algoBytes, payload, ok := parseString(payload)
- if !ok {
- return ParseError{msgUserAuthRequest}
- }
- algo := string(algoBytes)
-
- pubKey, payload, ok := parseString(payload)
- if !ok {
- return ParseError{msgUserAuthRequest}
- }
- if isQuery {
- // The client can query if the given public key
- // would be ok.
- if len(payload) > 0 {
- return ParseError{msgUserAuthRequest}
- }
- if s.testPubKey(userAuthReq.User, algo, pubKey) {
- okMsg := userAuthPubKeyOkMsg{
- Algo: algo,
- PubKey: string(pubKey),
- }
- if err = s.writePacket(marshal(msgUserAuthPubKeyOk, okMsg)); err != nil {
- return err
- }
- continue userAuthLoop
- }
- } else {
- sig, payload, ok := parseString(payload)
- if !ok || len(payload) > 0 {
- return ParseError{msgUserAuthRequest}
- }
- if !isAcceptableAlgo(algo) {
- break
- }
- rsaSig, ok := parseRSASig(sig)
- if !ok {
- return ParseError{msgUserAuthRequest}
- }
- signedData := buildDataSignedForAuth(H, userAuthReq, algoBytes, pubKey)
- switch algo {
- case hostAlgoRSA:
- hashFunc := crypto.SHA1
- h := hashFunc.New()
- h.Write(signedData)
- digest := h.Sum(nil)
- rsaKey, ok := parseRSA(pubKey)
- if !ok {
- return ParseError{msgUserAuthRequest}
- }
- if rsa.VerifyPKCS1v15(rsaKey, hashFunc, digest, rsaSig) != nil {
- return ParseError{msgUserAuthRequest}
- }
- default:
- return errors.New("ssh: isAcceptableAlgo incorrect")
- }
- if s.testPubKey(userAuthReq.User, algo, pubKey) {
- break userAuthLoop
- }
- }
- }
-
- var failureMsg userAuthFailureMsg
- if s.config.PasswordCallback != nil {
- failureMsg.Methods = append(failureMsg.Methods, "password")
- }
- if s.config.PublicKeyCallback != nil {
- failureMsg.Methods = append(failureMsg.Methods, "publickey")
- }
-
- if len(failureMsg.Methods) == 0 {
- return errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
- }
-
- if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil {
- return err
- }
- }
-
- packet = []byte{msgUserAuthSuccess}
- if err = s.writePacket(packet); err != nil {
- return err
- }
-
- return nil
-}
-
-const defaultWindowSize = 32768
-
-// Accept reads and processes messages on a ServerConn. It must be called
-// in order to demultiplex messages to any resulting Channels.
-func (s *ServerConn) Accept() (Channel, error) {
- if s.err != nil {
- return nil, s.err
- }
-
- for {
- packet, err := s.readPacket()
- if err != nil {
-
- s.lock.Lock()
- s.err = err
- s.lock.Unlock()
-
- for _, c := range s.channels {
- c.dead = true
- c.handleData(nil)
- }
-
- return nil, err
- }
-
- switch packet[0] {
- case msgChannelData:
- if len(packet) < 9 {
- // malformed data packet
- return nil, ParseError{msgChannelData}
- }
- peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
- s.lock.Lock()
- c, ok := s.channels[peersId]
- if !ok {
- s.lock.Unlock()
- continue
- }
- if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 {
- packet = packet[9:]
- c.handleData(packet[:length])
- }
- s.lock.Unlock()
- default:
- switch msg := decode(packet).(type) {
- case *channelOpenMsg:
- c := new(channel)
- c.chanType = msg.ChanType
- c.theirId = msg.PeersId
- c.theirWindow = msg.PeersWindow
- c.maxPacketSize = msg.MaxPacketSize
- c.extraData = msg.TypeSpecificData
- c.myWindow = defaultWindowSize
- c.serverConn = s
- c.cond = sync.NewCond(&c.lock)
- c.pendingData = make([]byte, c.myWindow)
-
- s.lock.Lock()
- c.myId = s.nextChanId
- s.nextChanId++
- s.channels[c.myId] = c
- s.lock.Unlock()
- return c, nil
-
- case *channelRequestMsg:
- s.lock.Lock()
- c, ok := s.channels[msg.PeersId]
- if !ok {
- s.lock.Unlock()
- continue
- }
- c.handlePacket(msg)
- s.lock.Unlock()
-
- case *channelEOFMsg:
- s.lock.Lock()
- c, ok := s.channels[msg.PeersId]
- if !ok {
- s.lock.Unlock()
- continue
- }
- c.handlePacket(msg)
- s.lock.Unlock()
-
- case *channelCloseMsg:
- s.lock.Lock()
- c, ok := s.channels[msg.PeersId]
- if !ok {
- s.lock.Unlock()
- continue
- }
- c.handlePacket(msg)
- s.lock.Unlock()
-
- case *globalRequestMsg:
- if msg.WantReply {
- if err := s.writePacket([]byte{msgRequestFailure}); err != nil {
- return nil, err
- }
- }
-
- case UnexpectedMessageError:
- return nil, msg
- case *disconnectMsg:
- return nil, io.EOF
- default:
- // Unknown message. Ignore.
- }
- }
- }
-
- panic("unreachable")
-}
-
-// A Listener implements a network listener (net.Listener) for SSH connections.
-type Listener struct {
- listener net.Listener
- config *ServerConfig
-}
-
-// Accept waits for and returns the next incoming SSH connection.
-// The receiver should call Handshake() in another goroutine
-// to avoid blocking the accepter.
-func (l *Listener) Accept() (*ServerConn, error) {
- c, err := l.listener.Accept()
- if err != nil {
- return nil, err
- }
- conn := Server(c, l.config)
- return conn, nil
-}
-
-// Addr returns the listener's network address.
-func (l *Listener) Addr() net.Addr {
- return l.listener.Addr()
-}
-
-// Close closes the listener.
-func (l *Listener) Close() error {
- return l.listener.Close()
-}
-
-// Listen creates an SSH listener accepting connections on
-// the given network address using net.Listen.
-func Listen(network, addr string, config *ServerConfig) (*Listener, error) {
- l, err := net.Listen(network, addr)
- if err != nil {
- return nil, err
- }
- return &Listener{
- l,
- config,
- }, nil
-}
diff --git a/libgo/go/exp/ssh/server_terminal.go b/libgo/go/exp/ssh/server_terminal.go
deleted file mode 100644
index 708a9159ec8..00000000000
--- a/libgo/go/exp/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/libgo/go/exp/ssh/session.go b/libgo/go/exp/ssh/session.go
deleted file mode 100644
index ea4addbd50b..00000000000
--- a/libgo/go/exp/ssh/session.go
+++ /dev/null
@@ -1,494 +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
-
-// Session implements an interactive session described in
-// "RFC 4254, section 6".
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
-)
-
-type Signal string
-
-// POSIX signals as listed in RFC 4254 Section 6.10.
-const (
- SIGABRT Signal = "ABRT"
- SIGALRM Signal = "ALRM"
- SIGFPE Signal = "FPE"
- SIGHUP Signal = "HUP"
- SIGILL Signal = "ILL"
- SIGINT Signal = "INT"
- SIGKILL Signal = "KILL"
- SIGPIPE Signal = "PIPE"
- SIGQUIT Signal = "QUIT"
- SIGSEGV Signal = "SEGV"
- SIGTERM Signal = "TERM"
- SIGUSR1 Signal = "USR1"
- SIGUSR2 Signal = "USR2"
-)
-
-var signals = map[Signal]int{
- SIGABRT: 6,
- SIGALRM: 14,
- SIGFPE: 8,
- SIGHUP: 1,
- SIGILL: 4,
- SIGINT: 2,
- SIGKILL: 9,
- SIGPIPE: 13,
- SIGQUIT: 3,
- SIGSEGV: 11,
- SIGTERM: 15,
-}
-
-// A Session represents a connection to a remote command or shell.
-type Session struct {
- // Stdin specifies the remote process's standard input.
- // If Stdin is nil, the remote process reads from an empty
- // bytes.Buffer.
- Stdin io.Reader
-
- // Stdout and Stderr specify the remote process's standard
- // output and error.
- //
- // If either is nil, Run connects the corresponding file
- // descriptor to an instance of ioutil.Discard. There is a
- // fixed amount of buffering that is shared for the two streams.
- // If either blocks it may eventually cause the remote
- // command to block.
- Stdout io.Writer
- Stderr io.Writer
-
- *clientChan // the channel backing this session
-
- started bool // true once Start, Run or Shell is invoked.
- copyFuncs []func() error
- errors chan error // one send per copyFunc
-
- // true if pipe method is active
- stdinpipe, stdoutpipe, stderrpipe bool
-}
-
-// RFC 4254 Section 6.4.
-type setenvRequest struct {
- PeersId uint32
- Request string
- WantReply bool
- Name string
- Value string
-}
-
-// Setenv sets an environment variable that will be applied to any
-// command executed by Shell or Run.
-func (s *Session) Setenv(name, value string) error {
- req := setenvRequest{
- PeersId: s.peersId,
- Request: "env",
- WantReply: true,
- Name: name,
- Value: value,
- }
- if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil {
- return err
- }
- return s.waitForResponse()
-}
-
-// An empty mode list, see RFC 4254 Section 8.
-var emptyModelist = "\x00"
-
-// RFC 4254 Section 6.2.
-type ptyRequestMsg struct {
- PeersId uint32
- Request string
- WantReply bool
- Term string
- Columns uint32
- Rows uint32
- Width uint32
- Height uint32
- Modelist string
-}
-
-// RequestPty requests the association of a pty with the session on the remote host.
-func (s *Session) RequestPty(term string, h, w int) error {
- req := ptyRequestMsg{
- PeersId: s.peersId,
- Request: "pty-req",
- WantReply: true,
- Term: term,
- Columns: uint32(w),
- Rows: uint32(h),
- Width: uint32(w * 8),
- Height: uint32(h * 8),
- Modelist: emptyModelist,
- }
- if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil {
- return err
- }
- return s.waitForResponse()
-}
-
-// RFC 4254 Section 6.9.
-type signalMsg struct {
- PeersId uint32
- Request string
- WantReply bool
- Signal string
-}
-
-// Signal sends the given signal to the remote process.
-// sig is one of the SIG* constants.
-func (s *Session) Signal(sig Signal) error {
- req := signalMsg{
- PeersId: s.peersId,
- Request: "signal",
- WantReply: false,
- Signal: string(sig),
- }
- return s.writePacket(marshal(msgChannelRequest, req))
-}
-
-// RFC 4254 Section 6.5.
-type execMsg struct {
- PeersId uint32
- Request string
- WantReply bool
- Command string
-}
-
-// Start runs cmd on the remote host. Typically, the remote
-// server passes cmd to the shell for interpretation.
-// A Session only accepts one call to Run, Start or Shell.
-func (s *Session) Start(cmd string) error {
- if s.started {
- return errors.New("ssh: session already started")
- }
- req := execMsg{
- PeersId: s.peersId,
- Request: "exec",
- WantReply: true,
- Command: cmd,
- }
- if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil {
- return err
- }
- if err := s.waitForResponse(); err != nil {
- return fmt.Errorf("ssh: could not execute command %s: %v", cmd, err)
- }
- return s.start()
-}
-
-// Run runs cmd on the remote host. Typically, the remote
-// server passes cmd to the shell for interpretation.
-// A Session only accepts one call to Run, Start or Shell.
-//
-// The returned error is nil if the command runs, has no problems
-// copying stdin, stdout, and stderr, and exits with a zero exit
-// status.
-//
-// If the command fails to run or doesn't complete successfully, the
-// error is of type *ExitError. Other error types may be
-// returned for I/O problems.
-func (s *Session) Run(cmd string) error {
- err := s.Start(cmd)
- if err != nil {
- return err
- }
- return s.Wait()
-}
-
-// Shell starts a login shell on the remote host. A Session only
-// accepts one call to Run, Start or Shell.
-func (s *Session) Shell() error {
- if s.started {
- return errors.New("ssh: session already started")
- }
- req := channelRequestMsg{
- PeersId: s.peersId,
- Request: "shell",
- WantReply: true,
- }
- if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil {
- return err
- }
- if err := s.waitForResponse(); err != nil {
- return fmt.Errorf("ssh: cound not execute shell: %v", err)
- }
- return s.start()
-}
-
-func (s *Session) waitForResponse() error {
- msg := <-s.msg
- switch msg.(type) {
- case *channelRequestSuccessMsg:
- return nil
- case *channelRequestFailureMsg:
- return errors.New("request failed")
- }
- return fmt.Errorf("unknown packet %T received: %v", msg, msg)
-}
-
-func (s *Session) start() error {
- s.started = true
-
- type F func(*Session)
- for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
- setupFd(s)
- }
-
- s.errors = make(chan error, len(s.copyFuncs))
- for _, fn := range s.copyFuncs {
- go func(fn func() error) {
- s.errors <- fn()
- }(fn)
- }
- return nil
-}
-
-// Wait waits for the remote command to exit.
-//
-// The returned error is nil if the command runs, has no problems
-// copying stdin, stdout, and stderr, and exits with a zero exit
-// status.
-//
-// If the command fails to run or doesn't complete successfully, the
-// error is of type *ExitError. Other error types may be
-// returned for I/O problems.
-func (s *Session) Wait() error {
- if !s.started {
- return errors.New("ssh: session not started")
- }
- waitErr := s.wait()
-
- var copyError error
- for _ = range s.copyFuncs {
- if err := <-s.errors; err != nil && copyError == nil {
- copyError = err
- }
- }
- if waitErr != nil {
- return waitErr
- }
- return copyError
-}
-
-func (s *Session) wait() error {
- wm := Waitmsg{status: -1}
-
- // Wait for msg channel to be closed before returning.
- for msg := range s.msg {
- switch msg := msg.(type) {
- case *channelRequestMsg:
- switch msg.Request {
- case "exit-status":
- d := msg.RequestSpecificData
- wm.status = int(d[0])<<24 | int(d[1])<<16 | int(d[2])<<8 | int(d[3])
- case "exit-signal":
- signal, rest, ok := parseString(msg.RequestSpecificData)
- if !ok {
- return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData)
- }
- wm.signal = safeString(string(signal))
-
- // skip coreDumped bool
- if len(rest) == 0 {
- return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData)
- }
- rest = rest[1:]
-
- errmsg, rest, ok := parseString(rest)
- if !ok {
- return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData)
- }
- wm.msg = safeString(string(errmsg))
-
- lang, _, ok := parseString(rest)
- if !ok {
- return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData)
- }
- wm.lang = safeString(string(lang))
- default:
- return fmt.Errorf("wait: unexpected channel request: %v", msg)
- }
- default:
- return fmt.Errorf("wait: unexpected packet %T received: %v", msg, msg)
- }
- }
- if wm.status == 0 {
- return nil
- }
- if wm.status == -1 {
- // exit-status was never sent from server
- if wm.signal == "" {
- return errors.New("wait: remote command exited without exit status or exit signal")
- }
- wm.status = 128
- if _, ok := signals[Signal(wm.signal)]; ok {
- wm.status += signals[Signal(wm.signal)]
- }
- }
- return &ExitError{wm}
-}
-
-func (s *Session) stdin() {
- if s.stdinpipe {
- return
- }
- if s.Stdin == nil {
- s.Stdin = new(bytes.Buffer)
- }
- s.copyFuncs = append(s.copyFuncs, func() error {
- _, err := io.Copy(s.clientChan.stdin, s.Stdin)
- if err1 := s.clientChan.stdin.Close(); err == nil {
- err = err1
- }
- return err
- })
-}
-
-func (s *Session) stdout() {
- if s.stdoutpipe {
- return
- }
- if s.Stdout == nil {
- s.Stdout = ioutil.Discard
- }
- s.copyFuncs = append(s.copyFuncs, func() error {
- _, err := io.Copy(s.Stdout, s.clientChan.stdout)
- return err
- })
-}
-
-func (s *Session) stderr() {
- if s.stderrpipe {
- return
- }
- if s.Stderr == nil {
- s.Stderr = ioutil.Discard
- }
- s.copyFuncs = append(s.copyFuncs, func() error {
- _, err := io.Copy(s.Stderr, s.clientChan.stderr)
- return err
- })
-}
-
-// StdinPipe returns a pipe that will be connected to the
-// remote command's standard input when the command starts.
-func (s *Session) StdinPipe() (io.WriteCloser, error) {
- if s.Stdin != nil {
- return nil, errors.New("ssh: Stdin already set")
- }
- if s.started {
- return nil, errors.New("ssh: StdinPipe after process started")
- }
- s.stdinpipe = true
- return s.clientChan.stdin, nil
-}
-
-// StdoutPipe returns a pipe that will be connected to the
-// remote command's standard output when the command starts.
-// There is a fixed amount of buffering that is shared between
-// stdout and stderr streams. If the StdoutPipe reader is
-// not serviced fast enought it may eventually cause the
-// remote command to block.
-func (s *Session) StdoutPipe() (io.Reader, error) {
- if s.Stdout != nil {
- return nil, errors.New("ssh: Stdout already set")
- }
- if s.started {
- return nil, errors.New("ssh: StdoutPipe after process started")
- }
- s.stdoutpipe = true
- return s.clientChan.stdout, nil
-}
-
-// StderrPipe returns a pipe that will be connected to the
-// remote command's standard error when the command starts.
-// There is a fixed amount of buffering that is shared between
-// stdout and stderr streams. If the StderrPipe reader is
-// not serviced fast enought it may eventually cause the
-// remote command to block.
-func (s *Session) StderrPipe() (io.Reader, error) {
- if s.Stderr != nil {
- return nil, errors.New("ssh: Stderr already set")
- }
- if s.started {
- return nil, errors.New("ssh: StderrPipe after process started")
- }
- s.stderrpipe = true
- return s.clientChan.stderr, nil
-}
-
-// TODO(dfc) add Output and CombinedOutput helpers
-
-// NewSession returns a new interactive session on the remote host.
-func (c *ClientConn) NewSession() (*Session, error) {
- ch := c.newChan(c.transport)
- if err := c.writePacket(marshal(msgChannelOpen, channelOpenMsg{
- ChanType: "session",
- PeersId: ch.id,
- PeersWindow: 1 << 14,
- MaxPacketSize: 1 << 15, // RFC 4253 6.1
- })); err != nil {
- c.chanlist.remove(ch.id)
- return nil, err
- }
- if err := ch.waitForChannelOpenResponse(); err != nil {
- c.chanlist.remove(ch.id)
- return nil, fmt.Errorf("ssh: unable to open session: %v", err)
- }
- return &Session{
- clientChan: ch,
- }, nil
-}
-
-// An ExitError reports unsuccessful completion of a remote command.
-type ExitError struct {
- Waitmsg
-}
-
-func (e *ExitError) Error() string {
- return e.Waitmsg.String()
-}
-
-// Waitmsg stores the information about an exited remote command
-// as reported by Wait.
-type Waitmsg struct {
- status int
- signal string
- msg string
- lang string
-}
-
-// ExitStatus returns the exit status of the remote command.
-func (w Waitmsg) ExitStatus() int {
- return w.status
-}
-
-// Signal returns the exit signal of the remote command if
-// it was terminated violently.
-func (w Waitmsg) Signal() string {
- return w.signal
-}
-
-// Msg returns the exit message given by the remote command
-func (w Waitmsg) Msg() string {
- return w.msg
-}
-
-// Lang returns the language tag. See RFC 3066
-func (w Waitmsg) Lang() string {
- return w.lang
-}
-
-func (w Waitmsg) String() string {
- return fmt.Sprintf("Process exited with: %v. Reason was: %v (%v)", w.status, w.msg, w.signal)
-}
diff --git a/libgo/go/exp/ssh/session_test.go b/libgo/go/exp/ssh/session_test.go
deleted file mode 100644
index 4a3d22bee04..00000000000
--- a/libgo/go/exp/ssh/session_test.go
+++ /dev/null
@@ -1,374 +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
-
-// Session tests.
-
-import (
- "bytes"
- "exp/terminal"
- "io"
- "testing"
-)
-
-type serverType func(*channel)
-
-// dial constructs a new test server and returns a *ClientConn.
-func dial(handler serverType, t *testing.T) *ClientConn {
- pw := password("tiger")
- serverConfig.PasswordCallback = func(user, pass string) bool {
- return user == "testuser" && pass == string(pw)
- }
- serverConfig.PublicKeyCallback = nil
-
- l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
- if err != nil {
- t.Fatalf("unable to listen: %s", err)
- }
- go func() {
- defer l.Close()
- conn, err := l.Accept()
- if err != nil {
- t.Errorf("Unable to accept: %v", err)
- return
- }
- defer conn.Close()
- if err := conn.Handshake(); err != nil {
- t.Errorf("Unable to handshake: %v", err)
- return
- }
- for {
- ch, err := conn.Accept()
- if err == io.EOF {
- return
- }
- if err != nil {
- t.Errorf("Unable to accept incoming channel request: %v", err)
- return
- }
- if ch.ChannelType() != "session" {
- ch.Reject(UnknownChannelType, "unknown channel type")
- continue
- }
- ch.Accept()
- go handler(ch.(*channel))
- }
- t.Log("done")
- }()
-
- config := &ClientConfig{
- User: "testuser",
- Auth: []ClientAuth{
- ClientAuthPassword(pw),
- },
- }
-
- c, err := Dial("tcp", l.Addr().String(), config)
- if err != nil {
- t.Fatalf("unable to dial remote side: %s", err)
- }
- return c
-}
-
-// Test a simple string is returned to session.Stdout.
-func TestSessionShell(t *testing.T) {
- conn := dial(shellHandler, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
- stdout := new(bytes.Buffer)
- session.Stdout = stdout
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- if err := session.Wait(); err != nil {
- t.Fatalf("Remote command did not exit cleanly: %s", err)
- }
- actual := stdout.String()
- if actual != "golang" {
- t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
- }
-}
-
-// TODO(dfc) add support for Std{in,err}Pipe when the Server supports it.
-
-// Test a simple string is returned via StdoutPipe.
-func TestSessionStdoutPipe(t *testing.T) {
- conn := dial(shellHandler, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
- stdout, err := session.StdoutPipe()
- if err != nil {
- t.Fatalf("Unable to request StdoutPipe(): %v", err)
- }
- var buf bytes.Buffer
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- done := make(chan bool, 1)
- go func() {
- if _, err := io.Copy(&buf, stdout); err != nil {
- t.Errorf("Copy of stdout failed: %v", err)
- }
- done <- true
- }()
- if err := session.Wait(); err != nil {
- t.Fatalf("Remote command did not exit cleanly: %s", err)
- }
- <-done
- actual := buf.String()
- if actual != "golang" {
- t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
- }
-}
-
-// Test non-0 exit status is returned correctly.
-func TestExitStatusNonZero(t *testing.T) {
- conn := dial(exitStatusNonZeroHandler, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- err = session.Wait()
- if err == nil {
- t.Fatalf("expected command to fail but it didn't")
- }
- e, ok := err.(*ExitError)
- if !ok {
- t.Fatalf("expected *ExitError but got %T", err)
- }
- if e.ExitStatus() != 15 {
- t.Fatalf("expected command to exit with 15 but got %s", e.ExitStatus())
- }
-}
-
-// Test 0 exit status is returned correctly.
-func TestExitStatusZero(t *testing.T) {
- conn := dial(exitStatusZeroHandler, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
-
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- err = session.Wait()
- if err != nil {
- t.Fatalf("expected nil but got %s", err)
- }
-}
-
-// Test exit signal and status are both returned correctly.
-func TestExitSignalAndStatus(t *testing.T) {
- conn := dial(exitSignalAndStatusHandler, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- err = session.Wait()
- if err == nil {
- t.Fatalf("expected command to fail but it didn't")
- }
- e, ok := err.(*ExitError)
- if !ok {
- t.Fatalf("expected *ExitError but got %T", err)
- }
- if e.Signal() != "TERM" || e.ExitStatus() != 15 {
- t.Fatalf("expected command to exit with signal TERM and status 15 but got signal %s and status %v", e.Signal(), e.ExitStatus())
- }
-}
-
-// Test exit signal and status are both returned correctly.
-func TestKnownExitSignalOnly(t *testing.T) {
- conn := dial(exitSignalHandler, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- err = session.Wait()
- if err == nil {
- t.Fatalf("expected command to fail but it didn't")
- }
- e, ok := err.(*ExitError)
- if !ok {
- t.Fatalf("expected *ExitError but got %T", err)
- }
- if e.Signal() != "TERM" || e.ExitStatus() != 143 {
- t.Fatalf("expected command to exit with signal TERM and status 143 but got signal %s and status %v", e.Signal(), e.ExitStatus())
- }
-}
-
-// Test exit signal and status are both returned correctly.
-func TestUnknownExitSignal(t *testing.T) {
- conn := dial(exitSignalUnknownHandler, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- err = session.Wait()
- if err == nil {
- t.Fatalf("expected command to fail but it didn't")
- }
- e, ok := err.(*ExitError)
- if !ok {
- t.Fatalf("expected *ExitError but got %T", err)
- }
- if e.Signal() != "SYS" || e.ExitStatus() != 128 {
- t.Fatalf("expected command to exit with signal SYS and status 128 but got signal %s and status %v", e.Signal(), e.ExitStatus())
- }
-}
-
-// Test WaitMsg is not returned if the channel closes abruptly.
-func TestExitWithoutStatusOrSignal(t *testing.T) {
- conn := dial(exitWithoutSignalOrStatus, t)
- defer conn.Close()
- session, err := conn.NewSession()
- if err != nil {
- t.Fatalf("Unable to request new session: %s", err)
- }
- defer session.Close()
- if err := session.Shell(); err != nil {
- t.Fatalf("Unable to execute command: %s", err)
- }
- err = session.Wait()
- if err == nil {
- t.Fatalf("expected command to fail but it didn't")
- }
- _, ok := err.(*ExitError)
- if ok {
- // you can't actually test for errors.errorString
- // because it's not exported.
- t.Fatalf("expected *errorString but got %T", err)
- }
-}
-
-type exitStatusMsg struct {
- PeersId uint32
- Request string
- WantReply bool
- Status uint32
-}
-
-type exitSignalMsg struct {
- PeersId uint32
- Request string
- WantReply bool
- Signal string
- CoreDumped bool
- Errmsg string
- Lang string
-}
-
-func newServerShell(ch *channel, prompt string) *ServerTerminal {
- term := terminal.NewTerminal(ch, prompt)
- return &ServerTerminal{
- Term: term,
- Channel: ch,
- }
-}
-
-func exitStatusZeroHandler(ch *channel) {
- defer ch.Close()
- // this string is returned to stdout
- shell := newServerShell(ch, "> ")
- shell.ReadLine()
- sendStatus(0, ch)
-}
-
-func exitStatusNonZeroHandler(ch *channel) {
- defer ch.Close()
- shell := newServerShell(ch, "> ")
- shell.ReadLine()
- sendStatus(15, ch)
-}
-
-func exitSignalAndStatusHandler(ch *channel) {
- defer ch.Close()
- shell := newServerShell(ch, "> ")
- shell.ReadLine()
- sendStatus(15, ch)
- sendSignal("TERM", ch)
-}
-
-func exitSignalHandler(ch *channel) {
- defer ch.Close()
- shell := newServerShell(ch, "> ")
- shell.ReadLine()
- sendSignal("TERM", ch)
-}
-
-func exitSignalUnknownHandler(ch *channel) {
- defer ch.Close()
- shell := newServerShell(ch, "> ")
- shell.ReadLine()
- sendSignal("SYS", ch)
-}
-
-func exitWithoutSignalOrStatus(ch *channel) {
- defer ch.Close()
- shell := newServerShell(ch, "> ")
- shell.ReadLine()
-}
-
-func shellHandler(ch *channel) {
- defer ch.Close()
- // this string is returned to stdout
- shell := newServerShell(ch, "golang")
- shell.ReadLine()
- sendStatus(0, ch)
-}
-
-func sendStatus(status uint32, ch *channel) {
- msg := exitStatusMsg{
- PeersId: ch.theirId,
- Request: "exit-status",
- WantReply: false,
- Status: status,
- }
- ch.serverConn.writePacket(marshal(msgChannelRequest, msg))
-}
-
-func sendSignal(signal string, ch *channel) {
- sig := exitSignalMsg{
- PeersId: ch.theirId,
- Request: "exit-signal",
- WantReply: false,
- Signal: signal,
- CoreDumped: false,
- Errmsg: "Process terminated",
- Lang: "en-GB-oed",
- }
- ch.serverConn.writePacket(marshal(msgChannelRequest, sig))
-}
diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go
deleted file mode 100644
index e0c47bca1fc..00000000000
--- a/libgo/go/exp/ssh/tcpip.go
+++ /dev/null
@@ -1,132 +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 (
- "errors"
- "fmt"
- "io"
- "net"
- "time"
-)
-
-// Dial initiates a connection to the addr from the remote host.
-// addr is resolved using net.ResolveTCPAddr before connection.
-// This could allow an observer to observe the DNS name of the
-// remote host. Consider using ssh.DialTCP to avoid this.
-func (c *ClientConn) Dial(n, addr string) (net.Conn, error) {
- raddr, err := net.ResolveTCPAddr(n, addr)
- if err != nil {
- return nil, err
- }
- return c.DialTCP(n, nil, raddr)
-}
-
-// DialTCP connects to the remote address raddr on the network net,
-// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
-// as the local address for the connection.
-func (c *ClientConn) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) {
- if laddr == nil {
- laddr = &net.TCPAddr{
- IP: net.IPv4zero,
- Port: 0,
- }
- }
- ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port)
- if err != nil {
- return nil, err
- }
- return &tcpchanconn{
- tcpchan: ch,
- laddr: laddr,
- raddr: raddr,
- }, nil
-}
-
-// RFC 4254 7.2
-type channelOpenDirectMsg struct {
- ChanType string
- PeersId uint32
- PeersWindow uint32
- MaxPacketSize uint32
- raddr string
- rport uint32
- laddr string
- lport uint32
-}
-
-// dial opens a direct-tcpip connection to the remote server. laddr and raddr are passed as
-// strings and are expected to be resolveable at the remote end.
-func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*tcpchan, error) {
- ch := c.newChan(c.transport)
- if err := c.writePacket(marshal(msgChannelOpen, channelOpenDirectMsg{
- ChanType: "direct-tcpip",
- PeersId: ch.id,
- PeersWindow: 1 << 14,
- MaxPacketSize: 1 << 15, // RFC 4253 6.1
- raddr: raddr,
- rport: uint32(rport),
- laddr: laddr,
- lport: uint32(lport),
- })); err != nil {
- c.chanlist.remove(ch.id)
- return nil, err
- }
- if err := ch.waitForChannelOpenResponse(); err != nil {
- c.chanlist.remove(ch.id)
- return nil, fmt.Errorf("ssh: unable to open direct tcpip connection: %v", err)
- }
- return &tcpchan{
- clientChan: ch,
- Reader: ch.stdout,
- Writer: ch.stdin,
- }, nil
-}
-
-type tcpchan struct {
- *clientChan // the backing channel
- io.Reader
- io.Writer
-}
-
-// tcpchanconn fulfills the net.Conn interface without
-// the tcpchan having to hold laddr or raddr directly.
-type tcpchanconn struct {
- *tcpchan
- laddr, raddr net.Addr
-}
-
-// LocalAddr returns the local network address.
-func (t *tcpchanconn) LocalAddr() net.Addr {
- return t.laddr
-}
-
-// RemoteAddr returns the remote network address.
-func (t *tcpchanconn) RemoteAddr() net.Addr {
- return t.raddr
-}
-
-// SetDeadline sets the read and write deadlines associated
-// with the connection.
-func (t *tcpchanconn) SetDeadline(deadline time.Time) error {
- if err := t.SetReadDeadline(deadline); err != nil {
- return err
- }
- return t.SetWriteDeadline(deadline)
-}
-
-// SetReadDeadline sets the read deadline.
-// A zero value for t means Read will not time out.
-// After the deadline, the error from Read will implement net.Error
-// with Timeout() == true.
-func (t *tcpchanconn) SetReadDeadline(deadline time.Time) error {
- return errors.New("ssh: tcpchan: deadline not supported")
-}
-
-// SetWriteDeadline exists to satisfy the net.Conn interface
-// but is not implemented by this type. It always returns an error.
-func (t *tcpchanconn) SetWriteDeadline(deadline time.Time) error {
- return errors.New("ssh: tcpchan: deadline not supported")
-}
diff --git a/libgo/go/exp/ssh/tcpip_func_test.go b/libgo/go/exp/ssh/tcpip_func_test.go
deleted file mode 100644
index 261297241e9..00000000000
--- a/libgo/go/exp/ssh/tcpip_func_test.go
+++ /dev/null
@@ -1,59 +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
-
-// direct-tcpip functional tests
-
-import (
- "net"
- "net/http"
- "testing"
-)
-
-func TestTCPIPHTTP(t *testing.T) {
- if *sshuser == "" {
- t.Log("ssh.user not defined, skipping test")
- return
- }
- // google.com will generate at least one redirect, possibly three
- // depending on your location.
- doTest(t, "http://google.com")
-}
-
-func TestTCPIPHTTPS(t *testing.T) {
- if *sshuser == "" {
- t.Log("ssh.user not defined, skipping test")
- return
- }
- doTest(t, "https://encrypted.google.com/")
-}
-
-func doTest(t *testing.T, url string) {
- config := &ClientConfig{
- User: *sshuser,
- Auth: []ClientAuth{
- ClientAuthPassword(password(*sshpass)),
- },
- }
- conn, err := Dial("tcp", "localhost:22", config)
- if err != nil {
- t.Fatalf("Unable to connect: %s", err)
- }
- defer conn.Close()
- tr := &http.Transport{
- Dial: func(n, addr string) (net.Conn, error) {
- return conn.Dial(n, addr)
- },
- }
- client := &http.Client{
- Transport: tr,
- }
- resp, err := client.Get(url)
- if err != nil {
- t.Fatalf("unable to proxy: %s", err)
- }
- // got a body without error
- t.Log(resp)
-}
diff --git a/libgo/go/exp/ssh/transport.go b/libgo/go/exp/ssh/transport.go
deleted file mode 100644
index e21bc4ba202..00000000000
--- a/libgo/go/exp/ssh/transport.go
+++ /dev/null
@@ -1,369 +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 (
- "bufio"
- "crypto"
- "crypto/cipher"
- "crypto/hmac"
- "crypto/sha1"
- "crypto/subtle"
- "errors"
- "hash"
- "io"
- "net"
- "sync"
-)
-
-const (
- packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
- minPacketSize = 16
- maxPacketSize = 36000
- minPaddingSize = 4 // TODO(huin) should this be configurable?
-)
-
-// filteredConn reduces the set of methods exposed when embeddeding
-// a net.Conn inside ssh.transport.
-// TODO(dfc) suggestions for a better name will be warmly received.
-type filteredConn interface {
- // Close closes the connection.
- Close() error
-
- // LocalAddr returns the local network address.
- LocalAddr() net.Addr
-
- // RemoteAddr returns the remote network address.
- RemoteAddr() net.Addr
-}
-
-// Types implementing packetWriter provide the ability to send packets to
-// an SSH peer.
-type packetWriter interface {
- // Encrypt and send a packet of data to the remote peer.
- writePacket(packet []byte) error
-}
-
-// transport represents the SSH connection to the remote peer.
-type transport struct {
- reader
- writer
-
- filteredConn
-}
-
-// reader represents the incoming connection state.
-type reader struct {
- io.Reader
- common
-}
-
-// writer represnts the outgoing connection state.
-type writer struct {
- *sync.Mutex // protects writer.Writer from concurrent writes
- *bufio.Writer
- rand io.Reader
- common
-}
-
-// common represents the cipher state needed to process messages in a single
-// direction.
-type common struct {
- seqNum uint32
- mac hash.Hash
- cipher cipher.Stream
-
- cipherAlgo string
- macAlgo string
- compressionAlgo string
-}
-
-// Read and decrypt a single packet from the remote peer.
-func (r *reader) readOnePacket() ([]byte, error) {
- var lengthBytes = make([]byte, 5)
- var macSize uint32
- if _, err := io.ReadFull(r, lengthBytes); err != nil {
- return nil, err
- }
-
- r.cipher.XORKeyStream(lengthBytes, lengthBytes)
-
- if r.mac != nil {
- r.mac.Reset()
- seqNumBytes := []byte{
- byte(r.seqNum >> 24),
- byte(r.seqNum >> 16),
- byte(r.seqNum >> 8),
- byte(r.seqNum),
- }
- r.mac.Write(seqNumBytes)
- r.mac.Write(lengthBytes)
- macSize = uint32(r.mac.Size())
- }
-
- length := uint32(lengthBytes[0])<<24 | uint32(lengthBytes[1])<<16 | uint32(lengthBytes[2])<<8 | uint32(lengthBytes[3])
- paddingLength := uint32(lengthBytes[4])
-
- if length <= paddingLength+1 {
- return nil, errors.New("invalid packet length")
- }
- if length > maxPacketSize {
- return nil, errors.New("packet too large")
- }
-
- packet := make([]byte, length-1+macSize)
- if _, err := io.ReadFull(r, packet); err != nil {
- return nil, err
- }
- mac := packet[length-1:]
- r.cipher.XORKeyStream(packet, packet[:length-1])
-
- if r.mac != nil {
- r.mac.Write(packet[:length-1])
- if subtle.ConstantTimeCompare(r.mac.Sum(nil), mac) != 1 {
- return nil, errors.New("ssh: MAC failure")
- }
- }
-
- r.seqNum++
- return packet[:length-paddingLength-1], nil
-}
-
-// Read and decrypt next packet discarding debug and noop messages.
-func (t *transport) readPacket() ([]byte, error) {
- for {
- packet, err := t.readOnePacket()
- if err != nil {
- return nil, err
- }
- if packet[0] != msgIgnore && packet[0] != msgDebug {
- return packet, nil
- }
- }
- panic("unreachable")
-}
-
-// Encrypt and send a packet of data to the remote peer.
-func (w *writer) writePacket(packet []byte) error {
- w.Mutex.Lock()
- defer w.Mutex.Unlock()
-
- paddingLength := packetSizeMultiple - (5+len(packet))%packetSizeMultiple
- if paddingLength < 4 {
- paddingLength += packetSizeMultiple
- }
-
- length := len(packet) + 1 + paddingLength
- lengthBytes := []byte{
- byte(length >> 24),
- byte(length >> 16),
- byte(length >> 8),
- byte(length),
- byte(paddingLength),
- }
- padding := make([]byte, paddingLength)
- _, err := io.ReadFull(w.rand, padding)
- if err != nil {
- return err
- }
-
- if w.mac != nil {
- w.mac.Reset()
- seqNumBytes := []byte{
- byte(w.seqNum >> 24),
- byte(w.seqNum >> 16),
- byte(w.seqNum >> 8),
- byte(w.seqNum),
- }
- w.mac.Write(seqNumBytes)
- w.mac.Write(lengthBytes)
- w.mac.Write(packet)
- w.mac.Write(padding)
- }
-
- // TODO(dfc) lengthBytes, packet and padding should be
- // subslices of a single buffer
- w.cipher.XORKeyStream(lengthBytes, lengthBytes)
- w.cipher.XORKeyStream(packet, packet)
- w.cipher.XORKeyStream(padding, padding)
-
- if _, err := w.Write(lengthBytes); err != nil {
- return err
- }
- if _, err := w.Write(packet); err != nil {
- return err
- }
- if _, err := w.Write(padding); err != nil {
- return err
- }
-
- if w.mac != nil {
- if _, err := w.Write(w.mac.Sum(nil)); err != nil {
- return err
- }
- }
-
- if err := w.Flush(); err != nil {
- return err
- }
- w.seqNum++
- return err
-}
-
-// Send a message to the remote peer
-func (t *transport) sendMessage(typ uint8, msg interface{}) error {
- packet := marshal(typ, msg)
- return t.writePacket(packet)
-}
-
-func newTransport(conn net.Conn, rand io.Reader) *transport {
- return &transport{
- reader: reader{
- Reader: bufio.NewReader(conn),
- common: common{
- cipher: noneCipher{},
- },
- },
- writer: writer{
- Writer: bufio.NewWriter(conn),
- rand: rand,
- Mutex: new(sync.Mutex),
- common: common{
- cipher: noneCipher{},
- },
- },
- filteredConn: conn,
- }
-}
-
-type direction struct {
- ivTag []byte
- keyTag []byte
- macKeyTag []byte
-}
-
-// TODO(dfc) can this be made a constant ?
-var (
- serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
- clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
-)
-
-// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
-// described in RFC 4253, section 6.4. direction should either be serverKeys
-// (to setup server->client keys) or clientKeys (for client->server keys).
-func (c *common) setupKeys(d direction, K, H, sessionId []byte, hashFunc crypto.Hash) error {
- cipherMode := cipherModes[c.cipherAlgo]
-
- macKeySize := 20
-
- iv := make([]byte, cipherMode.ivSize)
- key := make([]byte, cipherMode.keySize)
- macKey := make([]byte, macKeySize)
-
- h := hashFunc.New()
- generateKeyMaterial(iv, d.ivTag, K, H, sessionId, h)
- generateKeyMaterial(key, d.keyTag, K, H, sessionId, h)
- generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h)
-
- c.mac = truncatingMAC{12, hmac.New(sha1.New, macKey)}
-
- cipher, err := cipherMode.createCipher(key, iv)
- if err != nil {
- return err
- }
-
- c.cipher = cipher
-
- return nil
-}
-
-// generateKeyMaterial fills out with key material generated from tag, K, H
-// and sessionId, as specified in RFC 4253, section 7.2.
-func generateKeyMaterial(out, tag []byte, K, H, sessionId []byte, h hash.Hash) {
- var digestsSoFar []byte
-
- for len(out) > 0 {
- h.Reset()
- h.Write(K)
- h.Write(H)
-
- if len(digestsSoFar) == 0 {
- h.Write(tag)
- h.Write(sessionId)
- } else {
- h.Write(digestsSoFar)
- }
-
- digest := h.Sum(nil)
- n := copy(out, digest)
- out = out[n:]
- if len(out) > 0 {
- digestsSoFar = append(digestsSoFar, digest...)
- }
- }
-}
-
-// truncatingMAC wraps around a hash.Hash and truncates the output digest to
-// a given size.
-type truncatingMAC struct {
- length int
- hmac hash.Hash
-}
-
-func (t truncatingMAC) Write(data []byte) (int, error) {
- return t.hmac.Write(data)
-}
-
-func (t truncatingMAC) Sum(in []byte) []byte {
- out := t.hmac.Sum(in)
- return out[:len(in)+t.length]
-}
-
-func (t truncatingMAC) Reset() {
- t.hmac.Reset()
-}
-
-func (t truncatingMAC) Size() int {
- return t.length
-}
-
-func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
-
-// maxVersionStringBytes is the maximum number of bytes that we'll accept as a
-// version string. In the event that the client is talking a different protocol
-// we need to set a limit otherwise we will keep using more and more memory
-// while searching for the end of the version handshake.
-const maxVersionStringBytes = 1024
-
-// Read version string as specified by RFC 4253, section 4.2.
-func readVersion(r io.Reader) ([]byte, error) {
- versionString := make([]byte, 0, 64)
- var ok bool
- var buf [1]byte
-forEachByte:
- for len(versionString) < maxVersionStringBytes {
- _, err := io.ReadFull(r, buf[:])
- if err != nil {
- return nil, err
- }
- // The RFC says that the version should be terminated with \r\n
- // but several SSH servers actually only send a \n.
- if buf[0] == '\n' {
- ok = true
- break forEachByte
- }
- versionString = append(versionString, buf[0])
- }
-
- if !ok {
- return nil, errors.New("ssh: failed to read version string")
- }
-
- // There might be a '\r' on the end which we should remove.
- if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
- versionString = versionString[:len(versionString)-1]
- }
- return versionString, nil
-}
diff --git a/libgo/go/exp/ssh/transport_test.go b/libgo/go/exp/ssh/transport_test.go
deleted file mode 100644
index ab9177f0d11..00000000000
--- a/libgo/go/exp/ssh/transport_test.go
+++ /dev/null
@@ -1,51 +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 (
- "bufio"
- "bytes"
- "testing"
-)
-
-func TestReadVersion(t *testing.T) {
- buf := serverVersion
- result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf)))
- if err != nil {
- t.Errorf("readVersion didn't read version correctly: %s", err)
- }
- if !bytes.Equal(buf[:len(buf)-2], result) {
- t.Error("version read did not match expected")
- }
-}
-
-func TestReadVersionWithJustLF(t *testing.T) {
- var buf []byte
- buf = append(buf, serverVersion...)
- buf = buf[:len(buf)-1]
- buf[len(buf)-1] = '\n'
- result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf)))
- if err != nil {
- t.Error("readVersion failed to handle just a \n")
- }
- if !bytes.Equal(buf[:len(buf)-1], result) {
- t.Errorf("version read did not match expected: got %x, want %x", result, buf[:len(buf)-1])
- }
-}
-
-func TestReadVersionTooLong(t *testing.T) {
- buf := make([]byte, maxVersionStringBytes+1)
- if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil {
- t.Errorf("readVersion consumed %d bytes without error", len(buf))
- }
-}
-
-func TestReadVersionWithoutCRLF(t *testing.T) {
- buf := serverVersion
- buf = buf[:len(buf)-1]
- if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil {
- t.Error("readVersion did not notice \\n was missing")
- }
-}
OpenPOWER on IntegriCloud