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