github.com/timstclair/heapster@v0.20.0-alpha1/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  	var ciphers []string
   210  	for _, c := range c.Ciphers {
   211  		if cipherModes[c] != nil {
   212  			// reject the cipher if we have no cipherModes definition
   213  			ciphers = append(ciphers, c)
   214  		}
   215  	}
   216  	c.Ciphers = ciphers
   217  
   218  	if c.KeyExchanges == nil {
   219  		c.KeyExchanges = supportedKexAlgos
   220  	}
   221  
   222  	if c.MACs == nil {
   223  		c.MACs = supportedMACs
   224  	}
   225  
   226  	if c.RekeyThreshold == 0 {
   227  		// RFC 4253, section 9 suggests rekeying after 1G.
   228  		c.RekeyThreshold = 1 << 30
   229  	}
   230  	if c.RekeyThreshold < minRekeyThreshold {
   231  		c.RekeyThreshold = minRekeyThreshold
   232  	}
   233  }
   234  
   235  // buildDataSignedForAuth returns the data that is signed in order to prove
   236  // possession of a private key. See RFC 4252, section 7.
   237  func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
   238  	data := struct {
   239  		Session []byte
   240  		Type    byte
   241  		User    string
   242  		Service string
   243  		Method  string
   244  		Sign    bool
   245  		Algo    []byte
   246  		PubKey  []byte
   247  	}{
   248  		sessionId,
   249  		msgUserAuthRequest,
   250  		req.User,
   251  		req.Service,
   252  		req.Method,
   253  		true,
   254  		algo,
   255  		pubKey,
   256  	}
   257  	return Marshal(data)
   258  }
   259  
   260  func appendU16(buf []byte, n uint16) []byte {
   261  	return append(buf, byte(n>>8), byte(n))
   262  }
   263  
   264  func appendU32(buf []byte, n uint32) []byte {
   265  	return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
   266  }
   267  
   268  func appendU64(buf []byte, n uint64) []byte {
   269  	return append(buf,
   270  		byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
   271  		byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
   272  }
   273  
   274  func appendInt(buf []byte, n int) []byte {
   275  	return appendU32(buf, uint32(n))
   276  }
   277  
   278  func appendString(buf []byte, s string) []byte {
   279  	buf = appendU32(buf, uint32(len(s)))
   280  	buf = append(buf, s...)
   281  	return buf
   282  }
   283  
   284  func appendBool(buf []byte, b bool) []byte {
   285  	if b {
   286  		return append(buf, 1)
   287  	}
   288  	return append(buf, 0)
   289  }
   290  
   291  // newCond is a helper to hide the fact that there is no usable zero
   292  // value for sync.Cond.
   293  func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
   294  
   295  // window represents the buffer available to clients
   296  // wishing to write to a channel.
   297  type window struct {
   298  	*sync.Cond
   299  	win          uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
   300  	writeWaiters int
   301  	closed       bool
   302  }
   303  
   304  // add adds win to the amount of window available
   305  // for consumers.
   306  func (w *window) add(win uint32) bool {
   307  	// a zero sized window adjust is a noop.
   308  	if win == 0 {
   309  		return true
   310  	}
   311  	w.L.Lock()
   312  	if w.win+win < win {
   313  		w.L.Unlock()
   314  		return false
   315  	}
   316  	w.win += win
   317  	// It is unusual that multiple goroutines would be attempting to reserve
   318  	// window space, but not guaranteed. Use broadcast to notify all waiters
   319  	// that additional window is available.
   320  	w.Broadcast()
   321  	w.L.Unlock()
   322  	return true
   323  }
   324  
   325  // close sets the window to closed, so all reservations fail
   326  // immediately.
   327  func (w *window) close() {
   328  	w.L.Lock()
   329  	w.closed = true
   330  	w.Broadcast()
   331  	w.L.Unlock()
   332  }
   333  
   334  // reserve reserves win from the available window capacity.
   335  // If no capacity remains, reserve will block. reserve may
   336  // return less than requested.
   337  func (w *window) reserve(win uint32) (uint32, error) {
   338  	var err error
   339  	w.L.Lock()
   340  	w.writeWaiters++
   341  	w.Broadcast()
   342  	for w.win == 0 && !w.closed {
   343  		w.Wait()
   344  	}
   345  	w.writeWaiters--
   346  	if w.win < win {
   347  		win = w.win
   348  	}
   349  	w.win -= win
   350  	if w.closed {
   351  		err = io.EOF
   352  	}
   353  	w.L.Unlock()
   354  	return win, err
   355  }
   356  
   357  // waitWriterBlocked waits until some goroutine is blocked for further
   358  // writes. It is used in tests only.
   359  func (w *window) waitWriterBlocked() {
   360  	w.Cond.L.Lock()
   361  	for w.writeWaiters == 0 {
   362  		w.Cond.Wait()
   363  	}
   364  	w.Cond.L.Unlock()
   365  }