...

Source file src/golang.org/x/crypto/ssh/common.go

Documentation: golang.org/x/crypto/ssh

     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  	"math"
    13  	"sync"
    14  
    15  	_ "crypto/sha1"
    16  	_ "crypto/sha256"
    17  	_ "crypto/sha512"
    18  )
    19  
    20  // These are string constants in the SSH protocol.
    21  const (
    22  	compressionNone = "none"
    23  	serviceUserAuth = "ssh-userauth"
    24  	serviceSSH      = "ssh-connection"
    25  )
    26  
    27  // supportedCiphers lists ciphers we support but might not recommend.
    28  var supportedCiphers = []string{
    29  	"aes128-ctr", "aes192-ctr", "aes256-ctr",
    30  	"aes128-gcm@openssh.com", gcm256CipherID,
    31  	chacha20Poly1305ID,
    32  	"arcfour256", "arcfour128", "arcfour",
    33  	aes128cbcID,
    34  	tripledescbcID,
    35  }
    36  
    37  // preferredCiphers specifies the default preference for ciphers.
    38  var preferredCiphers = []string{
    39  	"aes128-gcm@openssh.com", gcm256CipherID,
    40  	chacha20Poly1305ID,
    41  	"aes128-ctr", "aes192-ctr", "aes256-ctr",
    42  }
    43  
    44  // supportedKexAlgos specifies the supported key-exchange algorithms in
    45  // preference order.
    46  var supportedKexAlgos = []string{
    47  	kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
    48  	// P384 and P521 are not constant-time yet, but since we don't
    49  	// reuse ephemeral keys, using them for ECDH should be OK.
    50  	kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
    51  	kexAlgoDH14SHA256, kexAlgoDH16SHA512, kexAlgoDH14SHA1,
    52  	kexAlgoDH1SHA1,
    53  }
    54  
    55  // serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden
    56  // for the server half.
    57  var serverForbiddenKexAlgos = map[string]struct{}{
    58  	kexAlgoDHGEXSHA1:   {}, // server half implementation is only minimal to satisfy the automated tests
    59  	kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
    60  }
    61  
    62  // preferredKexAlgos specifies the default preference for key-exchange
    63  // algorithms in preference order. The diffie-hellman-group16-sha512 algorithm
    64  // is disabled by default because it is a bit slower than the others.
    65  var preferredKexAlgos = []string{
    66  	kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
    67  	kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
    68  	kexAlgoDH14SHA256, kexAlgoDH14SHA1,
    69  }
    70  
    71  // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
    72  // of authenticating servers) in preference order.
    73  var supportedHostKeyAlgos = []string{
    74  	CertAlgoRSASHA256v01, CertAlgoRSASHA512v01,
    75  	CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
    76  	CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01,
    77  
    78  	KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
    79  	KeyAlgoRSASHA256, KeyAlgoRSASHA512,
    80  	KeyAlgoRSA, KeyAlgoDSA,
    81  
    82  	KeyAlgoED25519,
    83  }
    84  
    85  // supportedMACs specifies a default set of MAC algorithms in preference order.
    86  // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
    87  // because they have reached the end of their useful life.
    88  var supportedMACs = []string{
    89  	"hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", "hmac-sha1-96",
    90  }
    91  
    92  var supportedCompressions = []string{compressionNone}
    93  
    94  // hashFuncs keeps the mapping of supported signature algorithms to their
    95  // respective hashes needed for signing and verification.
    96  var hashFuncs = map[string]crypto.Hash{
    97  	KeyAlgoRSA:       crypto.SHA1,
    98  	KeyAlgoRSASHA256: crypto.SHA256,
    99  	KeyAlgoRSASHA512: crypto.SHA512,
   100  	KeyAlgoDSA:       crypto.SHA1,
   101  	KeyAlgoECDSA256:  crypto.SHA256,
   102  	KeyAlgoECDSA384:  crypto.SHA384,
   103  	KeyAlgoECDSA521:  crypto.SHA512,
   104  	// KeyAlgoED25519 doesn't pre-hash.
   105  	KeyAlgoSKECDSA256: crypto.SHA256,
   106  	KeyAlgoSKED25519:  crypto.SHA256,
   107  }
   108  
   109  // algorithmsForKeyFormat returns the supported signature algorithms for a given
   110  // public key format (PublicKey.Type), in order of preference. See RFC 8332,
   111  // Section 2. See also the note in sendKexInit on backwards compatibility.
   112  func algorithmsForKeyFormat(keyFormat string) []string {
   113  	switch keyFormat {
   114  	case KeyAlgoRSA:
   115  		return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA}
   116  	case CertAlgoRSAv01:
   117  		return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01}
   118  	default:
   119  		return []string{keyFormat}
   120  	}
   121  }
   122  
   123  // isRSA returns whether algo is a supported RSA algorithm, including certificate
   124  // algorithms.
   125  func isRSA(algo string) bool {
   126  	algos := algorithmsForKeyFormat(KeyAlgoRSA)
   127  	return contains(algos, underlyingAlgo(algo))
   128  }
   129  
   130  func isRSACert(algo string) bool {
   131  	_, ok := certKeyAlgoNames[algo]
   132  	if !ok {
   133  		return false
   134  	}
   135  	return isRSA(algo)
   136  }
   137  
   138  // supportedPubKeyAuthAlgos specifies the supported client public key
   139  // authentication algorithms. Note that this doesn't include certificate types
   140  // since those use the underlying algorithm. This list is sent to the client if
   141  // it supports the server-sig-algs extension. Order is irrelevant.
   142  var supportedPubKeyAuthAlgos = []string{
   143  	KeyAlgoED25519,
   144  	KeyAlgoSKED25519, KeyAlgoSKECDSA256,
   145  	KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
   146  	KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA,
   147  	KeyAlgoDSA,
   148  }
   149  
   150  // unexpectedMessageError results when the SSH message that we received didn't
   151  // match what we wanted.
   152  func unexpectedMessageError(expected, got uint8) error {
   153  	return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
   154  }
   155  
   156  // parseError results from a malformed SSH message.
   157  func parseError(tag uint8) error {
   158  	return fmt.Errorf("ssh: parse error in message type %d", tag)
   159  }
   160  
   161  func findCommon(what string, client []string, server []string) (common string, err error) {
   162  	for _, c := range client {
   163  		for _, s := range server {
   164  			if c == s {
   165  				return c, nil
   166  			}
   167  		}
   168  	}
   169  	return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server)
   170  }
   171  
   172  // directionAlgorithms records algorithm choices in one direction (either read or write)
   173  type directionAlgorithms struct {
   174  	Cipher      string
   175  	MAC         string
   176  	Compression string
   177  }
   178  
   179  // rekeyBytes returns a rekeying intervals in bytes.
   180  func (a *directionAlgorithms) rekeyBytes() int64 {
   181  	// According to RFC 4344 block ciphers should rekey after
   182  	// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
   183  	// 128.
   184  	switch a.Cipher {
   185  	case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcm128CipherID, gcm256CipherID, aes128cbcID:
   186  		return 16 * (1 << 32)
   187  
   188  	}
   189  
   190  	// For others, stick with RFC 4253 recommendation to rekey after 1 Gb of data.
   191  	return 1 << 30
   192  }
   193  
   194  var aeadCiphers = map[string]bool{
   195  	gcm128CipherID:     true,
   196  	gcm256CipherID:     true,
   197  	chacha20Poly1305ID: true,
   198  }
   199  
   200  type algorithms struct {
   201  	kex     string
   202  	hostKey string
   203  	w       directionAlgorithms
   204  	r       directionAlgorithms
   205  }
   206  
   207  func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
   208  	result := &algorithms{}
   209  
   210  	result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos)
   211  	if err != nil {
   212  		return
   213  	}
   214  
   215  	result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
   216  	if err != nil {
   217  		return
   218  	}
   219  
   220  	stoc, ctos := &result.w, &result.r
   221  	if isClient {
   222  		ctos, stoc = stoc, ctos
   223  	}
   224  
   225  	ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
   226  	if err != nil {
   227  		return
   228  	}
   229  
   230  	stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
   231  	if err != nil {
   232  		return
   233  	}
   234  
   235  	if !aeadCiphers[ctos.Cipher] {
   236  		ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
   237  		if err != nil {
   238  			return
   239  		}
   240  	}
   241  
   242  	if !aeadCiphers[stoc.Cipher] {
   243  		stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
   244  		if err != nil {
   245  			return
   246  		}
   247  	}
   248  
   249  	ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
   250  	if err != nil {
   251  		return
   252  	}
   253  
   254  	stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
   255  	if err != nil {
   256  		return
   257  	}
   258  
   259  	return result, nil
   260  }
   261  
   262  // If rekeythreshold is too small, we can't make any progress sending
   263  // stuff.
   264  const minRekeyThreshold uint64 = 256
   265  
   266  // Config contains configuration data common to both ServerConfig and
   267  // ClientConfig.
   268  type Config struct {
   269  	// Rand provides the source of entropy for cryptographic
   270  	// primitives. If Rand is nil, the cryptographic random reader
   271  	// in package crypto/rand will be used.
   272  	Rand io.Reader
   273  
   274  	// The maximum number of bytes sent or received after which a
   275  	// new key is negotiated. It must be at least 256. If
   276  	// unspecified, a size suitable for the chosen cipher is used.
   277  	RekeyThreshold uint64
   278  
   279  	// The allowed key exchanges algorithms. If unspecified then a default set
   280  	// of algorithms is used. Unsupported values are silently ignored.
   281  	KeyExchanges []string
   282  
   283  	// The allowed cipher algorithms. If unspecified then a sensible default is
   284  	// used. Unsupported values are silently ignored.
   285  	Ciphers []string
   286  
   287  	// The allowed MAC algorithms. If unspecified then a sensible default is
   288  	// used. Unsupported values are silently ignored.
   289  	MACs []string
   290  }
   291  
   292  // SetDefaults sets sensible values for unset fields in config. This is
   293  // exported for testing: Configs passed to SSH functions are copied and have
   294  // default values set automatically.
   295  func (c *Config) SetDefaults() {
   296  	if c.Rand == nil {
   297  		c.Rand = rand.Reader
   298  	}
   299  	if c.Ciphers == nil {
   300  		c.Ciphers = preferredCiphers
   301  	}
   302  	var ciphers []string
   303  	for _, c := range c.Ciphers {
   304  		if cipherModes[c] != nil {
   305  			// Ignore the cipher if we have no cipherModes definition.
   306  			ciphers = append(ciphers, c)
   307  		}
   308  	}
   309  	c.Ciphers = ciphers
   310  
   311  	if c.KeyExchanges == nil {
   312  		c.KeyExchanges = preferredKexAlgos
   313  	}
   314  	var kexs []string
   315  	for _, k := range c.KeyExchanges {
   316  		if kexAlgoMap[k] != nil {
   317  			// Ignore the KEX if we have no kexAlgoMap definition.
   318  			kexs = append(kexs, k)
   319  		}
   320  	}
   321  	c.KeyExchanges = kexs
   322  
   323  	if c.MACs == nil {
   324  		c.MACs = supportedMACs
   325  	}
   326  	var macs []string
   327  	for _, m := range c.MACs {
   328  		if macModes[m] != nil {
   329  			// Ignore the MAC if we have no macModes definition.
   330  			macs = append(macs, m)
   331  		}
   332  	}
   333  	c.MACs = macs
   334  
   335  	if c.RekeyThreshold == 0 {
   336  		// cipher specific default
   337  	} else if c.RekeyThreshold < minRekeyThreshold {
   338  		c.RekeyThreshold = minRekeyThreshold
   339  	} else if c.RekeyThreshold >= math.MaxInt64 {
   340  		// Avoid weirdness if somebody uses -1 as a threshold.
   341  		c.RekeyThreshold = math.MaxInt64
   342  	}
   343  }
   344  
   345  // buildDataSignedForAuth returns the data that is signed in order to prove
   346  // possession of a private key. See RFC 4252, section 7. algo is the advertised
   347  // algorithm, and may be a certificate type.
   348  func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte {
   349  	data := struct {
   350  		Session []byte
   351  		Type    byte
   352  		User    string
   353  		Service string
   354  		Method  string
   355  		Sign    bool
   356  		Algo    string
   357  		PubKey  []byte
   358  	}{
   359  		sessionID,
   360  		msgUserAuthRequest,
   361  		req.User,
   362  		req.Service,
   363  		req.Method,
   364  		true,
   365  		algo,
   366  		pubKey,
   367  	}
   368  	return Marshal(data)
   369  }
   370  
   371  func appendU16(buf []byte, n uint16) []byte {
   372  	return append(buf, byte(n>>8), byte(n))
   373  }
   374  
   375  func appendU32(buf []byte, n uint32) []byte {
   376  	return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
   377  }
   378  
   379  func appendU64(buf []byte, n uint64) []byte {
   380  	return append(buf,
   381  		byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
   382  		byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
   383  }
   384  
   385  func appendInt(buf []byte, n int) []byte {
   386  	return appendU32(buf, uint32(n))
   387  }
   388  
   389  func appendString(buf []byte, s string) []byte {
   390  	buf = appendU32(buf, uint32(len(s)))
   391  	buf = append(buf, s...)
   392  	return buf
   393  }
   394  
   395  func appendBool(buf []byte, b bool) []byte {
   396  	if b {
   397  		return append(buf, 1)
   398  	}
   399  	return append(buf, 0)
   400  }
   401  
   402  // newCond is a helper to hide the fact that there is no usable zero
   403  // value for sync.Cond.
   404  func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
   405  
   406  // window represents the buffer available to clients
   407  // wishing to write to a channel.
   408  type window struct {
   409  	*sync.Cond
   410  	win          uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
   411  	writeWaiters int
   412  	closed       bool
   413  }
   414  
   415  // add adds win to the amount of window available
   416  // for consumers.
   417  func (w *window) add(win uint32) bool {
   418  	// a zero sized window adjust is a noop.
   419  	if win == 0 {
   420  		return true
   421  	}
   422  	w.L.Lock()
   423  	if w.win+win < win {
   424  		w.L.Unlock()
   425  		return false
   426  	}
   427  	w.win += win
   428  	// It is unusual that multiple goroutines would be attempting to reserve
   429  	// window space, but not guaranteed. Use broadcast to notify all waiters
   430  	// that additional window is available.
   431  	w.Broadcast()
   432  	w.L.Unlock()
   433  	return true
   434  }
   435  
   436  // close sets the window to closed, so all reservations fail
   437  // immediately.
   438  func (w *window) close() {
   439  	w.L.Lock()
   440  	w.closed = true
   441  	w.Broadcast()
   442  	w.L.Unlock()
   443  }
   444  
   445  // reserve reserves win from the available window capacity.
   446  // If no capacity remains, reserve will block. reserve may
   447  // return less than requested.
   448  func (w *window) reserve(win uint32) (uint32, error) {
   449  	var err error
   450  	w.L.Lock()
   451  	w.writeWaiters++
   452  	w.Broadcast()
   453  	for w.win == 0 && !w.closed {
   454  		w.Wait()
   455  	}
   456  	w.writeWaiters--
   457  	if w.win < win {
   458  		win = w.win
   459  	}
   460  	w.win -= win
   461  	if w.closed {
   462  		err = io.EOF
   463  	}
   464  	w.L.Unlock()
   465  	return win, err
   466  }
   467  
   468  // waitWriterBlocked waits until some goroutine is blocked for further
   469  // writes. It is used in tests only.
   470  func (w *window) waitWriterBlocked() {
   471  	w.Cond.L.Lock()
   472  	for w.writeWaiters == 0 {
   473  		w.Cond.Wait()
   474  	}
   475  	w.Cond.L.Unlock()
   476  }
   477  

View as plain text