github.com/deis/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/Godeps/_workspace/src/golang.org/x/crypto/ssh/common.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  	"crypto"
     9  	"crypto/rand"
    10  	"fmt"
    11  	"io"
    12  	"sync"
    13  
    14  	_ "crypto/sha1"
    15  	_ "crypto/sha256"
    16  	_ "crypto/sha512"
    17  )
    18  
    19  // These are string constants in the SSH protocol.
    20  const (
    21  	compressionNone = "none"
    22  	serviceUserAuth = "ssh-userauth"
    23  	serviceSSH      = "ssh-connection"
    24  )
    25  
    26  // supportedCiphers specifies the supported ciphers in preference order.
    27  var supportedCiphers = []string{
    28  	"aes128-ctr", "aes192-ctr", "aes256-ctr",
    29  	"aes128-gcm@openssh.com",
    30  	"arcfour256", "arcfour128",
    31  }
    32  
    33  // supportedKexAlgos specifies the supported key-exchange algorithms in
    34  // preference order.
    35  var supportedKexAlgos = []string{
    36  	// P384 and P521 are not constant-time yet, but since we don't
    37  	// reuse ephemeral keys, using them for ECDH should be OK.
    38  	kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
    39  	kexAlgoDH14SHA1, kexAlgoDH1SHA1,
    40  }
    41  
    42  // supportedKexAlgos specifies the supported host-key algorithms (i.e. methods
    43  // of authenticating servers) in preference order.
    44  var supportedHostKeyAlgos = []string{
    45  	CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
    46  	CertAlgoECDSA384v01, CertAlgoECDSA521v01,
    47  
    48  	KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
    49  	KeyAlgoRSA, KeyAlgoDSA,
    50  }
    51  
    52  // supportedMACs specifies a default set of MAC algorithms in preference order.
    53  // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
    54  // because they have reached the end of their useful life.
    55  var supportedMACs = []string{
    56  	"hmac-sha1", "hmac-sha1-96",
    57  }
    58  
    59  var supportedCompressions = []string{compressionNone}
    60  
    61  // hashFuncs keeps the mapping of supported algorithms to their respective
    62  // hashes needed for signature verification.
    63  var hashFuncs = map[string]crypto.Hash{
    64  	KeyAlgoRSA:          crypto.SHA1,
    65  	KeyAlgoDSA:          crypto.SHA1,
    66  	KeyAlgoECDSA256:     crypto.SHA256,
    67  	KeyAlgoECDSA384:     crypto.SHA384,
    68  	KeyAlgoECDSA521:     crypto.SHA512,
    69  	CertAlgoRSAv01:      crypto.SHA1,
    70  	CertAlgoDSAv01:      crypto.SHA1,
    71  	CertAlgoECDSA256v01: crypto.SHA256,
    72  	CertAlgoECDSA384v01: crypto.SHA384,
    73  	CertAlgoECDSA521v01: crypto.SHA512,
    74  }
    75  
    76  // unexpectedMessageError results when the SSH message that we received didn't
    77  // match what we wanted.
    78  func unexpectedMessageError(expected, got uint8) error {
    79  	return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
    80  }
    81  
    82  // parseError results from a malformed SSH message.
    83  func parseError(tag uint8) error {
    84  	return fmt.Errorf("ssh: parse error in message type %d", tag)
    85  }
    86  
    87  func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
    88  	for _, clientAlgo := range clientAlgos {
    89  		for _, serverAlgo := range serverAlgos {
    90  			if clientAlgo == serverAlgo {
    91  				return clientAlgo, true
    92  			}
    93  		}
    94  	}
    95  	return
    96  }
    97  
    98  func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCipher string, ok bool) {
    99  	for _, clientCipher := range clientCiphers {
   100  		for _, serverCipher := range serverCiphers {
   101  			// reject the cipher if we have no cipherModes definition
   102  			if clientCipher == serverCipher && cipherModes[clientCipher] != nil {
   103  				return clientCipher, true
   104  			}
   105  		}
   106  	}
   107  	return
   108  }
   109  
   110  type directionAlgorithms struct {
   111  	Cipher      string
   112  	MAC         string
   113  	Compression string
   114  }
   115  
   116  type algorithms struct {
   117  	kex     string
   118  	hostKey string
   119  	w       directionAlgorithms
   120  	r       directionAlgorithms
   121  }
   122  
   123  func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms) {
   124  	var ok bool
   125  	result := &algorithms{}
   126  	result.kex, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
   127  	if !ok {
   128  		return
   129  	}
   130  
   131  	result.hostKey, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
   132  	if !ok {
   133  		return
   134  	}
   135  
   136  	result.w.Cipher, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
   137  	if !ok {
   138  		return
   139  	}
   140  
   141  	result.r.Cipher, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
   142  	if !ok {
   143  		return
   144  	}
   145  
   146  	result.w.MAC, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
   147  	if !ok {
   148  		return
   149  	}
   150  
   151  	result.r.MAC, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
   152  	if !ok {
   153  		return
   154  	}
   155  
   156  	result.w.Compression, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
   157  	if !ok {
   158  		return
   159  	}
   160  
   161  	result.r.Compression, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
   162  	if !ok {
   163  		return
   164  	}
   165  
   166  	return result
   167  }
   168  
   169  // If rekeythreshold is too small, we can't make any progress sending
   170  // stuff.
   171  const minRekeyThreshold uint64 = 256
   172  
   173  // Config contains configuration data common to both ServerConfig and
   174  // ClientConfig.
   175  type Config struct {
   176  	// Rand provides the source of entropy for cryptographic
   177  	// primitives. If Rand is nil, the cryptographic random reader
   178  	// in package crypto/rand will be used.
   179  	Rand io.Reader
   180  
   181  	// The maximum number of bytes sent or received after which a
   182  	// new key is negotiated. It must be at least 256. If
   183  	// unspecified, 1 gigabyte is used.
   184  	RekeyThreshold uint64
   185  
   186  	// The allowed key exchanges algorithms. If unspecified then a
   187  	// default set of algorithms is used.
   188  	KeyExchanges []string
   189  
   190  	// The allowed cipher algorithms. If unspecified then a sensible
   191  	// default is used.
   192  	Ciphers []string
   193  
   194  	// The allowed MAC algorithms. If unspecified then a sensible default
   195  	// is used.
   196  	MACs []string
   197  }
   198  
   199  // SetDefaults sets sensible values for unset fields in config. This is
   200  // exported for testing: Configs passed to SSH functions are copied and have
   201  // default values set automatically.
   202  func (c *Config) SetDefaults() {
   203  	if c.Rand == nil {
   204  		c.Rand = rand.Reader
   205  	}
   206  	if c.Ciphers == nil {
   207  		c.Ciphers = supportedCiphers
   208  	}
   209  
   210  	if c.KeyExchanges == nil {
   211  		c.KeyExchanges = supportedKexAlgos
   212  	}
   213  
   214  	if c.MACs == nil {
   215  		c.MACs = supportedMACs
   216  	}
   217  
   218  	if c.RekeyThreshold == 0 {
   219  		// RFC 4253, section 9 suggests rekeying after 1G.
   220  		c.RekeyThreshold = 1 << 30
   221  	}
   222  	if c.RekeyThreshold < minRekeyThreshold {
   223  		c.RekeyThreshold = minRekeyThreshold
   224  	}
   225  }
   226  
   227  // buildDataSignedForAuth returns the data that is signed in order to prove
   228  // possession of a private key. See RFC 4252, section 7.
   229  func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
   230  	data := struct {
   231  		Session []byte
   232  		Type    byte
   233  		User    string
   234  		Service string
   235  		Method  string
   236  		Sign    bool
   237  		Algo    []byte
   238  		PubKey  []byte
   239  	}{
   240  		sessionId,
   241  		msgUserAuthRequest,
   242  		req.User,
   243  		req.Service,
   244  		req.Method,
   245  		true,
   246  		algo,
   247  		pubKey,
   248  	}
   249  	return Marshal(data)
   250  }
   251  
   252  func appendU16(buf []byte, n uint16) []byte {
   253  	return append(buf, byte(n>>8), byte(n))
   254  }
   255  
   256  func appendU32(buf []byte, n uint32) []byte {
   257  	return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
   258  }
   259  
   260  func appendU64(buf []byte, n uint64) []byte {
   261  	return append(buf,
   262  		byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
   263  		byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
   264  }
   265  
   266  func appendInt(buf []byte, n int) []byte {
   267  	return appendU32(buf, uint32(n))
   268  }
   269  
   270  func appendString(buf []byte, s string) []byte {
   271  	buf = appendU32(buf, uint32(len(s)))
   272  	buf = append(buf, s...)
   273  	return buf
   274  }
   275  
   276  func appendBool(buf []byte, b bool) []byte {
   277  	if b {
   278  		return append(buf, 1)
   279  	}
   280  	return append(buf, 0)
   281  }
   282  
   283  // newCond is a helper to hide the fact that there is no usable zero
   284  // value for sync.Cond.
   285  func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
   286  
   287  // window represents the buffer available to clients
   288  // wishing to write to a channel.
   289  type window struct {
   290  	*sync.Cond
   291  	win          uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
   292  	writeWaiters int
   293  	closed       bool
   294  }
   295  
   296  // add adds win to the amount of window available
   297  // for consumers.
   298  func (w *window) add(win uint32) bool {
   299  	// a zero sized window adjust is a noop.
   300  	if win == 0 {
   301  		return true
   302  	}
   303  	w.L.Lock()
   304  	if w.win+win < win {
   305  		w.L.Unlock()
   306  		return false
   307  	}
   308  	w.win += win
   309  	// It is unusual that multiple goroutines would be attempting to reserve
   310  	// window space, but not guaranteed. Use broadcast to notify all waiters
   311  	// that additional window is available.
   312  	w.Broadcast()
   313  	w.L.Unlock()
   314  	return true
   315  }
   316  
   317  // close sets the window to closed, so all reservations fail
   318  // immediately.
   319  func (w *window) close() {
   320  	w.L.Lock()
   321  	w.closed = true
   322  	w.Broadcast()
   323  	w.L.Unlock()
   324  }
   325  
   326  // reserve reserves win from the available window capacity.
   327  // If no capacity remains, reserve will block. reserve may
   328  // return less than requested.
   329  func (w *window) reserve(win uint32) (uint32, error) {
   330  	var err error
   331  	w.L.Lock()
   332  	w.writeWaiters++
   333  	w.Broadcast()
   334  	for w.win == 0 && !w.closed {
   335  		w.Wait()
   336  	}
   337  	w.writeWaiters--
   338  	if w.win < win {
   339  		win = w.win
   340  	}
   341  	w.win -= win
   342  	if w.closed {
   343  		err = io.EOF
   344  	}
   345  	w.L.Unlock()
   346  	return win, err
   347  }
   348  
   349  // waitWriterBlocked waits until some goroutine is blocked for further
   350  // writes. It is used in tests only.
   351  func (w *window) waitWriterBlocked() {
   352  	w.Cond.L.Lock()
   353  	for w.writeWaiters == 0 {
   354  		w.Cond.Wait()
   355  	}
   356  	w.Cond.L.Unlock()
   357  }