github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/go.crypto/ssh/transport.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ssh
     6  
     7  import (
     8  	"bufio"
     9  	"crypto"
    10  	"crypto/cipher"
    11  	"crypto/hmac"
    12  	"crypto/sha1"
    13  	"crypto/subtle"
    14  	"errors"
    15  	"hash"
    16  	"io"
    17  	"net"
    18  	"sync"
    19  )
    20  
    21  const (
    22  	packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
    23  	minPacketSize      = 16
    24  	maxPacketSize      = 36000
    25  	minPaddingSize     = 4 // TODO(huin) should this be configurable?
    26  )
    27  
    28  // filteredConn reduces the set of methods exposed when embeddeding
    29  // a net.Conn inside ssh.transport.
    30  // TODO(dfc) suggestions for a better name will be warmly received.
    31  type filteredConn interface {
    32  	// Close closes the connection.
    33  	Close() error
    34  
    35  	// LocalAddr returns the local network address.
    36  	LocalAddr() net.Addr
    37  
    38  	// RemoteAddr returns the remote network address.
    39  	RemoteAddr() net.Addr
    40  }
    41  
    42  // Types implementing packetWriter provide the ability to send packets to
    43  // an SSH peer.
    44  type packetWriter interface {
    45  	// Encrypt and send a packet of data to the remote peer.
    46  	writePacket(packet []byte) error
    47  }
    48  
    49  // transport represents the SSH connection to the remote peer.
    50  type transport struct {
    51  	reader
    52  	writer
    53  
    54  	filteredConn
    55  }
    56  
    57  // reader represents the incoming connection state.
    58  type reader struct {
    59  	io.Reader
    60  	common
    61  }
    62  
    63  // writer represnts the outgoing connection state.
    64  type writer struct {
    65  	*sync.Mutex // protects writer.Writer from concurrent writes
    66  	*bufio.Writer
    67  	rand io.Reader
    68  	common
    69  }
    70  
    71  // common represents the cipher state needed to process messages in a single
    72  // direction.
    73  type common struct {
    74  	seqNum uint32
    75  	mac    hash.Hash
    76  	cipher cipher.Stream
    77  
    78  	cipherAlgo      string
    79  	macAlgo         string
    80  	compressionAlgo string
    81  }
    82  
    83  // Read and decrypt a single packet from the remote peer.
    84  func (r *reader) readOnePacket() ([]byte, error) {
    85  	var lengthBytes = make([]byte, 5)
    86  	var macSize uint32
    87  	if _, err := io.ReadFull(r, lengthBytes); err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	r.cipher.XORKeyStream(lengthBytes, lengthBytes)
    92  
    93  	if r.mac != nil {
    94  		r.mac.Reset()
    95  		seqNumBytes := []byte{
    96  			byte(r.seqNum >> 24),
    97  			byte(r.seqNum >> 16),
    98  			byte(r.seqNum >> 8),
    99  			byte(r.seqNum),
   100  		}
   101  		r.mac.Write(seqNumBytes)
   102  		r.mac.Write(lengthBytes)
   103  		macSize = uint32(r.mac.Size())
   104  	}
   105  
   106  	length := uint32(lengthBytes[0])<<24 | uint32(lengthBytes[1])<<16 | uint32(lengthBytes[2])<<8 | uint32(lengthBytes[3])
   107  	paddingLength := uint32(lengthBytes[4])
   108  
   109  	if length <= paddingLength+1 {
   110  		return nil, errors.New("invalid packet length")
   111  	}
   112  	if length > maxPacketSize {
   113  		return nil, errors.New("packet too large")
   114  	}
   115  
   116  	packet := make([]byte, length-1+macSize)
   117  	if _, err := io.ReadFull(r, packet); err != nil {
   118  		return nil, err
   119  	}
   120  	mac := packet[length-1:]
   121  	r.cipher.XORKeyStream(packet, packet[:length-1])
   122  
   123  	if r.mac != nil {
   124  		r.mac.Write(packet[:length-1])
   125  		if subtle.ConstantTimeCompare(r.mac.Sum(nil), mac) != 1 {
   126  			return nil, errors.New("ssh: MAC failure")
   127  		}
   128  	}
   129  
   130  	r.seqNum++
   131  	return packet[:length-paddingLength-1], nil
   132  }
   133  
   134  // Read and decrypt next packet discarding debug and noop messages.
   135  func (t *transport) readPacket() ([]byte, error) {
   136  	for {
   137  		packet, err := t.readOnePacket()
   138  		if err != nil {
   139  			return nil, err
   140  		}
   141  		if packet[0] != msgIgnore && packet[0] != msgDebug {
   142  			return packet, nil
   143  		}
   144  	}
   145  	panic("unreachable")
   146  }
   147  
   148  // Encrypt and send a packet of data to the remote peer.
   149  func (w *writer) writePacket(packet []byte) error {
   150  	w.Mutex.Lock()
   151  	defer w.Mutex.Unlock()
   152  
   153  	paddingLength := packetSizeMultiple - (5+len(packet))%packetSizeMultiple
   154  	if paddingLength < 4 {
   155  		paddingLength += packetSizeMultiple
   156  	}
   157  
   158  	length := len(packet) + 1 + paddingLength
   159  	lengthBytes := []byte{
   160  		byte(length >> 24),
   161  		byte(length >> 16),
   162  		byte(length >> 8),
   163  		byte(length),
   164  		byte(paddingLength),
   165  	}
   166  	padding := make([]byte, paddingLength)
   167  	_, err := io.ReadFull(w.rand, padding)
   168  	if err != nil {
   169  		return err
   170  	}
   171  
   172  	if w.mac != nil {
   173  		w.mac.Reset()
   174  		seqNumBytes := []byte{
   175  			byte(w.seqNum >> 24),
   176  			byte(w.seqNum >> 16),
   177  			byte(w.seqNum >> 8),
   178  			byte(w.seqNum),
   179  		}
   180  		w.mac.Write(seqNumBytes)
   181  		w.mac.Write(lengthBytes)
   182  		w.mac.Write(packet)
   183  		w.mac.Write(padding)
   184  	}
   185  
   186  	// TODO(dfc) lengthBytes, packet and padding should be
   187  	// subslices of a single buffer
   188  	w.cipher.XORKeyStream(lengthBytes, lengthBytes)
   189  	w.cipher.XORKeyStream(packet, packet)
   190  	w.cipher.XORKeyStream(padding, padding)
   191  
   192  	if _, err := w.Write(lengthBytes); err != nil {
   193  		return err
   194  	}
   195  	if _, err := w.Write(packet); err != nil {
   196  		return err
   197  	}
   198  	if _, err := w.Write(padding); err != nil {
   199  		return err
   200  	}
   201  
   202  	if w.mac != nil {
   203  		if _, err := w.Write(w.mac.Sum(nil)); err != nil {
   204  			return err
   205  		}
   206  	}
   207  
   208  	if err := w.Flush(); err != nil {
   209  		return err
   210  	}
   211  	w.seqNum++
   212  	return err
   213  }
   214  
   215  // Send a message to the remote peer
   216  func (t *transport) sendMessage(typ uint8, msg interface{}) error {
   217  	packet := marshal(typ, msg)
   218  	return t.writePacket(packet)
   219  }
   220  
   221  func newTransport(conn net.Conn, rand io.Reader) *transport {
   222  	return &transport{
   223  		reader: reader{
   224  			Reader: bufio.NewReader(conn),
   225  			common: common{
   226  				cipher: noneCipher{},
   227  			},
   228  		},
   229  		writer: writer{
   230  			Writer: bufio.NewWriter(conn),
   231  			rand:   rand,
   232  			Mutex:  new(sync.Mutex),
   233  			common: common{
   234  				cipher: noneCipher{},
   235  			},
   236  		},
   237  		filteredConn: conn,
   238  	}
   239  }
   240  
   241  type direction struct {
   242  	ivTag     []byte
   243  	keyTag    []byte
   244  	macKeyTag []byte
   245  }
   246  
   247  // TODO(dfc) can this be made a constant ?
   248  var (
   249  	serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
   250  	clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
   251  )
   252  
   253  // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
   254  // described in RFC 4253, section 6.4. direction should either be serverKeys
   255  // (to setup server->client keys) or clientKeys (for client->server keys).
   256  func (c *common) setupKeys(d direction, K, H, sessionId []byte, hashFunc crypto.Hash) error {
   257  	cipherMode := cipherModes[c.cipherAlgo]
   258  
   259  	macKeySize := 20
   260  
   261  	iv := make([]byte, cipherMode.ivSize)
   262  	key := make([]byte, cipherMode.keySize)
   263  	macKey := make([]byte, macKeySize)
   264  
   265  	h := hashFunc.New()
   266  	generateKeyMaterial(iv, d.ivTag, K, H, sessionId, h)
   267  	generateKeyMaterial(key, d.keyTag, K, H, sessionId, h)
   268  	generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h)
   269  
   270  	c.mac = truncatingMAC{12, hmac.New(sha1.New, macKey)}
   271  
   272  	cipher, err := cipherMode.createCipher(key, iv)
   273  	if err != nil {
   274  		return err
   275  	}
   276  
   277  	c.cipher = cipher
   278  
   279  	return nil
   280  }
   281  
   282  // generateKeyMaterial fills out with key material generated from tag, K, H
   283  // and sessionId, as specified in RFC 4253, section 7.2.
   284  func generateKeyMaterial(out, tag []byte, K, H, sessionId []byte, h hash.Hash) {
   285  	var digestsSoFar []byte
   286  
   287  	for len(out) > 0 {
   288  		h.Reset()
   289  		h.Write(K)
   290  		h.Write(H)
   291  
   292  		if len(digestsSoFar) == 0 {
   293  			h.Write(tag)
   294  			h.Write(sessionId)
   295  		} else {
   296  			h.Write(digestsSoFar)
   297  		}
   298  
   299  		digest := h.Sum(nil)
   300  		n := copy(out, digest)
   301  		out = out[n:]
   302  		if len(out) > 0 {
   303  			digestsSoFar = append(digestsSoFar, digest...)
   304  		}
   305  	}
   306  }
   307  
   308  // truncatingMAC wraps around a hash.Hash and truncates the output digest to
   309  // a given size.
   310  type truncatingMAC struct {
   311  	length int
   312  	hmac   hash.Hash
   313  }
   314  
   315  func (t truncatingMAC) Write(data []byte) (int, error) {
   316  	return t.hmac.Write(data)
   317  }
   318  
   319  func (t truncatingMAC) Sum(in []byte) []byte {
   320  	out := t.hmac.Sum(in)
   321  	return out[:len(in)+t.length]
   322  }
   323  
   324  func (t truncatingMAC) Reset() {
   325  	t.hmac.Reset()
   326  }
   327  
   328  func (t truncatingMAC) Size() int {
   329  	return t.length
   330  }
   331  
   332  func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
   333  
   334  // maxVersionStringBytes is the maximum number of bytes that we'll accept as a
   335  // version string. In the event that the client is talking a different protocol
   336  // we need to set a limit otherwise we will keep using more and more memory
   337  // while searching for the end of the version handshake.
   338  const maxVersionStringBytes = 1024
   339  
   340  // Read version string as specified by RFC 4253, section 4.2.
   341  func readVersion(r io.Reader) ([]byte, error) {
   342  	versionString := make([]byte, 0, 64)
   343  	var ok bool
   344  	var buf [1]byte
   345  forEachByte:
   346  	for len(versionString) < maxVersionStringBytes {
   347  		_, err := io.ReadFull(r, buf[:])
   348  		if err != nil {
   349  			return nil, err
   350  		}
   351  		// The RFC says that the version should be terminated with \r\n
   352  		// but several SSH servers actually only send a \n.
   353  		if buf[0] == '\n' {
   354  			ok = true
   355  			break forEachByte
   356  		}
   357  		versionString = append(versionString, buf[0])
   358  	}
   359  
   360  	if !ok {
   361  		return nil, errors.New("ssh: failed to read version string")
   362  	}
   363  
   364  	// There might be a '\r' on the end which we should remove.
   365  	if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
   366  		versionString = versionString[:len(versionString)-1]
   367  	}
   368  	return versionString, nil
   369  }