common.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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. package ssh
  5. import (
  6. "crypto"
  7. "crypto/rand"
  8. "fmt"
  9. "io"
  10. "math"
  11. "slices"
  12. "sync"
  13. _ "crypto/sha1"
  14. _ "crypto/sha256"
  15. _ "crypto/sha512"
  16. )
  17. // These are string constants in the SSH protocol.
  18. const (
  19. compressionNone = "none"
  20. serviceUserAuth = "ssh-userauth"
  21. serviceSSH = "ssh-connection"
  22. )
  23. // The ciphers currently or previously implemented by this library, to use in
  24. // [Config.Ciphers]. For a list, see the [Algorithms.Ciphers] returned by
  25. // [SupportedAlgorithms] or [InsecureAlgorithms].
  26. const (
  27. CipherAES128GCM = "aes128-gcm@openssh.com"
  28. CipherAES256GCM = "aes256-gcm@openssh.com"
  29. CipherChaCha20Poly1305 = "chacha20-poly1305@openssh.com"
  30. CipherAES128CTR = "aes128-ctr"
  31. CipherAES192CTR = "aes192-ctr"
  32. CipherAES256CTR = "aes256-ctr"
  33. InsecureCipherAES128CBC = "aes128-cbc"
  34. InsecureCipherTripleDESCBC = "3des-cbc"
  35. InsecureCipherRC4 = "arcfour"
  36. InsecureCipherRC4128 = "arcfour128"
  37. InsecureCipherRC4256 = "arcfour256"
  38. )
  39. // The key exchanges currently or previously implemented by this library, to use
  40. // in [Config.KeyExchanges]. For a list, see the
  41. // [Algorithms.KeyExchanges] returned by [SupportedAlgorithms] or
  42. // [InsecureAlgorithms].
  43. const (
  44. InsecureKeyExchangeDH1SHA1 = "diffie-hellman-group1-sha1"
  45. InsecureKeyExchangeDH14SHA1 = "diffie-hellman-group14-sha1"
  46. KeyExchangeDH14SHA256 = "diffie-hellman-group14-sha256"
  47. KeyExchangeDH16SHA512 = "diffie-hellman-group16-sha512"
  48. KeyExchangeECDHP256 = "ecdh-sha2-nistp256"
  49. KeyExchangeECDHP384 = "ecdh-sha2-nistp384"
  50. KeyExchangeECDHP521 = "ecdh-sha2-nistp521"
  51. KeyExchangeCurve25519 = "curve25519-sha256"
  52. InsecureKeyExchangeDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
  53. KeyExchangeDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
  54. // KeyExchangeMLKEM768X25519 is supported from Go 1.24.
  55. KeyExchangeMLKEM768X25519 = "mlkem768x25519-sha256"
  56. // An alias for KeyExchangeCurve25519SHA256. This kex ID will be added if
  57. // KeyExchangeCurve25519SHA256 is requested for backward compatibility with
  58. // OpenSSH versions up to 7.2.
  59. keyExchangeCurve25519LibSSH = "curve25519-sha256@libssh.org"
  60. )
  61. // The message authentication code (MAC) currently or previously implemented by
  62. // this library, to use in [Config.MACs]. For a list, see the
  63. // [Algorithms.MACs] returned by [SupportedAlgorithms] or
  64. // [InsecureAlgorithms].
  65. const (
  66. HMACSHA256ETM = "hmac-sha2-256-etm@openssh.com"
  67. HMACSHA512ETM = "hmac-sha2-512-etm@openssh.com"
  68. HMACSHA256 = "hmac-sha2-256"
  69. HMACSHA512 = "hmac-sha2-512"
  70. HMACSHA1 = "hmac-sha1"
  71. InsecureHMACSHA196 = "hmac-sha1-96"
  72. )
  73. var (
  74. // supportedKexAlgos specifies key-exchange algorithms implemented by this
  75. // package in preference order, excluding those with security issues.
  76. supportedKexAlgos = []string{
  77. KeyExchangeCurve25519,
  78. KeyExchangeECDHP256,
  79. KeyExchangeECDHP384,
  80. KeyExchangeECDHP521,
  81. KeyExchangeDH14SHA256,
  82. KeyExchangeDH16SHA512,
  83. KeyExchangeDHGEXSHA256,
  84. }
  85. // defaultKexAlgos specifies the default preference for key-exchange
  86. // algorithms in preference order.
  87. defaultKexAlgos = []string{
  88. KeyExchangeCurve25519,
  89. KeyExchangeECDHP256,
  90. KeyExchangeECDHP384,
  91. KeyExchangeECDHP521,
  92. KeyExchangeDH14SHA256,
  93. InsecureKeyExchangeDH14SHA1,
  94. }
  95. // insecureKexAlgos specifies key-exchange algorithms implemented by this
  96. // package and which have security issues.
  97. insecureKexAlgos = []string{
  98. InsecureKeyExchangeDH14SHA1,
  99. InsecureKeyExchangeDH1SHA1,
  100. InsecureKeyExchangeDHGEXSHA1,
  101. }
  102. // supportedCiphers specifies cipher algorithms implemented by this package
  103. // in preference order, excluding those with security issues.
  104. supportedCiphers = []string{
  105. CipherAES128GCM,
  106. CipherAES256GCM,
  107. CipherChaCha20Poly1305,
  108. CipherAES128CTR,
  109. CipherAES192CTR,
  110. CipherAES256CTR,
  111. }
  112. // defaultCiphers specifies the default preference for ciphers algorithms
  113. // in preference order.
  114. defaultCiphers = supportedCiphers
  115. // insecureCiphers specifies cipher algorithms implemented by this
  116. // package and which have security issues.
  117. insecureCiphers = []string{
  118. InsecureCipherAES128CBC,
  119. InsecureCipherTripleDESCBC,
  120. InsecureCipherRC4256,
  121. InsecureCipherRC4128,
  122. InsecureCipherRC4,
  123. }
  124. // supportedMACs specifies MAC algorithms implemented by this package in
  125. // preference order, excluding those with security issues.
  126. supportedMACs = []string{
  127. HMACSHA256ETM,
  128. HMACSHA512ETM,
  129. HMACSHA256,
  130. HMACSHA512,
  131. HMACSHA1,
  132. }
  133. // defaultMACs specifies the default preference for MAC algorithms in
  134. // preference order.
  135. defaultMACs = []string{
  136. HMACSHA256ETM,
  137. HMACSHA512ETM,
  138. HMACSHA256,
  139. HMACSHA512,
  140. HMACSHA1,
  141. InsecureHMACSHA196,
  142. }
  143. // insecureMACs specifies MAC algorithms implemented by this
  144. // package and which have security issues.
  145. insecureMACs = []string{
  146. InsecureHMACSHA196,
  147. }
  148. // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e.
  149. // methods of authenticating servers) implemented by this package in
  150. // preference order, excluding those with security issues.
  151. supportedHostKeyAlgos = []string{
  152. CertAlgoRSASHA256v01,
  153. CertAlgoRSASHA512v01,
  154. CertAlgoECDSA256v01,
  155. CertAlgoECDSA384v01,
  156. CertAlgoECDSA521v01,
  157. CertAlgoED25519v01,
  158. KeyAlgoRSASHA256,
  159. KeyAlgoRSASHA512,
  160. KeyAlgoECDSA256,
  161. KeyAlgoECDSA384,
  162. KeyAlgoECDSA521,
  163. KeyAlgoED25519,
  164. }
  165. // defaultHostKeyAlgos specifies the default preference for host-key
  166. // algorithms in preference order.
  167. defaultHostKeyAlgos = []string{
  168. CertAlgoRSASHA256v01,
  169. CertAlgoRSASHA512v01,
  170. CertAlgoRSAv01,
  171. InsecureCertAlgoDSAv01,
  172. CertAlgoECDSA256v01,
  173. CertAlgoECDSA384v01,
  174. CertAlgoECDSA521v01,
  175. CertAlgoED25519v01,
  176. KeyAlgoECDSA256,
  177. KeyAlgoECDSA384,
  178. KeyAlgoECDSA521,
  179. KeyAlgoRSASHA256,
  180. KeyAlgoRSASHA512,
  181. KeyAlgoRSA,
  182. InsecureKeyAlgoDSA,
  183. KeyAlgoED25519,
  184. }
  185. // insecureHostKeyAlgos specifies host-key algorithms implemented by this
  186. // package and which have security issues.
  187. insecureHostKeyAlgos = []string{
  188. KeyAlgoRSA,
  189. InsecureKeyAlgoDSA,
  190. CertAlgoRSAv01,
  191. InsecureCertAlgoDSAv01,
  192. }
  193. // supportedPubKeyAuthAlgos specifies the supported client public key
  194. // authentication algorithms. Note that this doesn't include certificate
  195. // types since those use the underlying algorithm. Order is irrelevant.
  196. supportedPubKeyAuthAlgos = []string{
  197. KeyAlgoED25519,
  198. KeyAlgoSKED25519,
  199. KeyAlgoSKECDSA256,
  200. KeyAlgoECDSA256,
  201. KeyAlgoECDSA384,
  202. KeyAlgoECDSA521,
  203. KeyAlgoRSASHA256,
  204. KeyAlgoRSASHA512,
  205. }
  206. // defaultPubKeyAuthAlgos specifies the preferred client public key
  207. // authentication algorithms. This list is sent to the client if it supports
  208. // the server-sig-algs extension. Order is irrelevant.
  209. defaultPubKeyAuthAlgos = []string{
  210. KeyAlgoED25519,
  211. KeyAlgoSKED25519,
  212. KeyAlgoSKECDSA256,
  213. KeyAlgoECDSA256,
  214. KeyAlgoECDSA384,
  215. KeyAlgoECDSA521,
  216. KeyAlgoRSASHA256,
  217. KeyAlgoRSASHA512,
  218. KeyAlgoRSA,
  219. InsecureKeyAlgoDSA,
  220. }
  221. // insecurePubKeyAuthAlgos specifies client public key authentication
  222. // algorithms implemented by this package and which have security issues.
  223. insecurePubKeyAuthAlgos = []string{
  224. KeyAlgoRSA,
  225. InsecureKeyAlgoDSA,
  226. }
  227. )
  228. // NegotiatedAlgorithms defines algorithms negotiated between client and server.
  229. type NegotiatedAlgorithms struct {
  230. KeyExchange string
  231. HostKey string
  232. Read DirectionAlgorithms
  233. Write DirectionAlgorithms
  234. }
  235. // Algorithms defines a set of algorithms that can be configured in the client
  236. // or server config for negotiation during a handshake.
  237. type Algorithms struct {
  238. KeyExchanges []string
  239. Ciphers []string
  240. MACs []string
  241. HostKeys []string
  242. PublicKeyAuths []string
  243. }
  244. // SupportedAlgorithms returns algorithms currently implemented by this package,
  245. // excluding those with security issues, which are returned by
  246. // InsecureAlgorithms. The algorithms listed here are in preference order.
  247. func SupportedAlgorithms() Algorithms {
  248. return Algorithms{
  249. Ciphers: slices.Clone(supportedCiphers),
  250. MACs: slices.Clone(supportedMACs),
  251. KeyExchanges: slices.Clone(supportedKexAlgos),
  252. HostKeys: slices.Clone(supportedHostKeyAlgos),
  253. PublicKeyAuths: slices.Clone(supportedPubKeyAuthAlgos),
  254. }
  255. }
  256. // InsecureAlgorithms returns algorithms currently implemented by this package
  257. // and which have security issues.
  258. func InsecureAlgorithms() Algorithms {
  259. return Algorithms{
  260. KeyExchanges: slices.Clone(insecureKexAlgos),
  261. Ciphers: slices.Clone(insecureCiphers),
  262. MACs: slices.Clone(insecureMACs),
  263. HostKeys: slices.Clone(insecureHostKeyAlgos),
  264. PublicKeyAuths: slices.Clone(insecurePubKeyAuthAlgos),
  265. }
  266. }
  267. var supportedCompressions = []string{compressionNone}
  268. // hashFuncs keeps the mapping of supported signature algorithms to their
  269. // respective hashes needed for signing and verification.
  270. var hashFuncs = map[string]crypto.Hash{
  271. KeyAlgoRSA: crypto.SHA1,
  272. KeyAlgoRSASHA256: crypto.SHA256,
  273. KeyAlgoRSASHA512: crypto.SHA512,
  274. InsecureKeyAlgoDSA: crypto.SHA1,
  275. KeyAlgoECDSA256: crypto.SHA256,
  276. KeyAlgoECDSA384: crypto.SHA384,
  277. KeyAlgoECDSA521: crypto.SHA512,
  278. // KeyAlgoED25519 doesn't pre-hash.
  279. KeyAlgoSKECDSA256: crypto.SHA256,
  280. KeyAlgoSKED25519: crypto.SHA256,
  281. }
  282. // algorithmsForKeyFormat returns the supported signature algorithms for a given
  283. // public key format (PublicKey.Type), in order of preference. See RFC 8332,
  284. // Section 2. See also the note in sendKexInit on backwards compatibility.
  285. func algorithmsForKeyFormat(keyFormat string) []string {
  286. switch keyFormat {
  287. case KeyAlgoRSA:
  288. return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA}
  289. case CertAlgoRSAv01:
  290. return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01}
  291. default:
  292. return []string{keyFormat}
  293. }
  294. }
  295. // isRSA returns whether algo is a supported RSA algorithm, including certificate
  296. // algorithms.
  297. func isRSA(algo string) bool {
  298. algos := algorithmsForKeyFormat(KeyAlgoRSA)
  299. return contains(algos, underlyingAlgo(algo))
  300. }
  301. func isRSACert(algo string) bool {
  302. _, ok := certKeyAlgoNames[algo]
  303. if !ok {
  304. return false
  305. }
  306. return isRSA(algo)
  307. }
  308. // unexpectedMessageError results when the SSH message that we received didn't
  309. // match what we wanted.
  310. func unexpectedMessageError(expected, got uint8) error {
  311. return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
  312. }
  313. // parseError results from a malformed SSH message.
  314. func parseError(tag uint8) error {
  315. return fmt.Errorf("ssh: parse error in message type %d", tag)
  316. }
  317. func findCommon(what string, client []string, server []string, isClient bool) (string, error) {
  318. for _, c := range client {
  319. for _, s := range server {
  320. if c == s {
  321. return c, nil
  322. }
  323. }
  324. }
  325. err := &AlgorithmNegotiationError{
  326. What: what,
  327. }
  328. if isClient {
  329. err.SupportedAlgorithms = client
  330. err.RequestedAlgorithms = server
  331. } else {
  332. err.SupportedAlgorithms = server
  333. err.RequestedAlgorithms = client
  334. }
  335. return "", err
  336. }
  337. // AlgorithmNegotiationError defines the error returned if the client and the
  338. // server cannot agree on an algorithm for key exchange, host key, cipher, MAC.
  339. type AlgorithmNegotiationError struct {
  340. What string
  341. // RequestedAlgorithms lists the algorithms supported by the peer.
  342. RequestedAlgorithms []string
  343. // SupportedAlgorithms lists the algorithms supported on our side.
  344. SupportedAlgorithms []string
  345. }
  346. func (a *AlgorithmNegotiationError) Error() string {
  347. return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %v, peer offered: %v",
  348. a.What, a.SupportedAlgorithms, a.RequestedAlgorithms)
  349. }
  350. // DirectionAlgorithms defines the algorithms negotiated in one direction
  351. // (either read or write).
  352. type DirectionAlgorithms struct {
  353. Cipher string
  354. MAC string
  355. compression string
  356. }
  357. // rekeyBytes returns a rekeying intervals in bytes.
  358. func (a *DirectionAlgorithms) rekeyBytes() int64 {
  359. // According to RFC 4344 block ciphers should rekey after
  360. // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
  361. // 128.
  362. switch a.Cipher {
  363. case CipherAES128CTR, CipherAES192CTR, CipherAES256CTR, CipherAES128GCM, CipherAES256GCM, InsecureCipherAES128CBC:
  364. return 16 * (1 << 32)
  365. }
  366. // For others, stick with RFC 4253 recommendation to rekey after 1 Gb of data.
  367. return 1 << 30
  368. }
  369. var aeadCiphers = map[string]bool{
  370. CipherAES128GCM: true,
  371. CipherAES256GCM: true,
  372. CipherChaCha20Poly1305: true,
  373. }
  374. func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *NegotiatedAlgorithms, err error) {
  375. result := &NegotiatedAlgorithms{}
  376. result.KeyExchange, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos, isClient)
  377. if err != nil {
  378. return
  379. }
  380. result.HostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos, isClient)
  381. if err != nil {
  382. return
  383. }
  384. stoc, ctos := &result.Write, &result.Read
  385. if isClient {
  386. ctos, stoc = stoc, ctos
  387. }
  388. ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer, isClient)
  389. if err != nil {
  390. return
  391. }
  392. stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient, isClient)
  393. if err != nil {
  394. return
  395. }
  396. if !aeadCiphers[ctos.Cipher] {
  397. ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer, isClient)
  398. if err != nil {
  399. return
  400. }
  401. }
  402. if !aeadCiphers[stoc.Cipher] {
  403. stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient, isClient)
  404. if err != nil {
  405. return
  406. }
  407. }
  408. ctos.compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer, isClient)
  409. if err != nil {
  410. return
  411. }
  412. stoc.compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient, isClient)
  413. if err != nil {
  414. return
  415. }
  416. return result, nil
  417. }
  418. // If rekeythreshold is too small, we can't make any progress sending
  419. // stuff.
  420. const minRekeyThreshold uint64 = 256
  421. // Config contains configuration data common to both ServerConfig and
  422. // ClientConfig.
  423. type Config struct {
  424. // Rand provides the source of entropy for cryptographic
  425. // primitives. If Rand is nil, the cryptographic random reader
  426. // in package crypto/rand will be used.
  427. Rand io.Reader
  428. // The maximum number of bytes sent or received after which a
  429. // new key is negotiated. It must be at least 256. If
  430. // unspecified, a size suitable for the chosen cipher is used.
  431. RekeyThreshold uint64
  432. // The allowed key exchanges algorithms. If unspecified then a default set
  433. // of algorithms is used. Unsupported values are silently ignored.
  434. KeyExchanges []string
  435. // The allowed cipher algorithms. If unspecified then a sensible default is
  436. // used. Unsupported values are silently ignored.
  437. Ciphers []string
  438. // The allowed MAC algorithms. If unspecified then a sensible default is
  439. // used. Unsupported values are silently ignored.
  440. MACs []string
  441. }
  442. // SetDefaults sets sensible values for unset fields in config. This is
  443. // exported for testing: Configs passed to SSH functions are copied and have
  444. // default values set automatically.
  445. func (c *Config) SetDefaults() {
  446. if c.Rand == nil {
  447. c.Rand = rand.Reader
  448. }
  449. if c.Ciphers == nil {
  450. c.Ciphers = defaultCiphers
  451. }
  452. var ciphers []string
  453. for _, c := range c.Ciphers {
  454. if cipherModes[c] != nil {
  455. // Ignore the cipher if we have no cipherModes definition.
  456. ciphers = append(ciphers, c)
  457. }
  458. }
  459. c.Ciphers = ciphers
  460. if c.KeyExchanges == nil {
  461. c.KeyExchanges = defaultKexAlgos
  462. }
  463. var kexs []string
  464. for _, k := range c.KeyExchanges {
  465. if kexAlgoMap[k] != nil {
  466. // Ignore the KEX if we have no kexAlgoMap definition.
  467. kexs = append(kexs, k)
  468. if k == KeyExchangeCurve25519 && !contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) {
  469. kexs = append(kexs, keyExchangeCurve25519LibSSH)
  470. }
  471. }
  472. }
  473. c.KeyExchanges = kexs
  474. if c.MACs == nil {
  475. c.MACs = defaultMACs
  476. }
  477. var macs []string
  478. for _, m := range c.MACs {
  479. if macModes[m] != nil {
  480. // Ignore the MAC if we have no macModes definition.
  481. macs = append(macs, m)
  482. }
  483. }
  484. c.MACs = macs
  485. if c.RekeyThreshold == 0 {
  486. // cipher specific default
  487. } else if c.RekeyThreshold < minRekeyThreshold {
  488. c.RekeyThreshold = minRekeyThreshold
  489. } else if c.RekeyThreshold >= math.MaxInt64 {
  490. // Avoid weirdness if somebody uses -1 as a threshold.
  491. c.RekeyThreshold = math.MaxInt64
  492. }
  493. }
  494. // buildDataSignedForAuth returns the data that is signed in order to prove
  495. // possession of a private key. See RFC 4252, section 7. algo is the advertised
  496. // algorithm, and may be a certificate type.
  497. func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte {
  498. data := struct {
  499. Session []byte
  500. Type byte
  501. User string
  502. Service string
  503. Method string
  504. Sign bool
  505. Algo string
  506. PubKey []byte
  507. }{
  508. sessionID,
  509. msgUserAuthRequest,
  510. req.User,
  511. req.Service,
  512. req.Method,
  513. true,
  514. algo,
  515. pubKey,
  516. }
  517. return Marshal(data)
  518. }
  519. func appendU16(buf []byte, n uint16) []byte {
  520. return append(buf, byte(n>>8), byte(n))
  521. }
  522. func appendU32(buf []byte, n uint32) []byte {
  523. return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
  524. }
  525. func appendU64(buf []byte, n uint64) []byte {
  526. return append(buf,
  527. byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
  528. byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
  529. }
  530. func appendInt(buf []byte, n int) []byte {
  531. return appendU32(buf, uint32(n))
  532. }
  533. func appendString(buf []byte, s string) []byte {
  534. buf = appendU32(buf, uint32(len(s)))
  535. buf = append(buf, s...)
  536. return buf
  537. }
  538. func appendBool(buf []byte, b bool) []byte {
  539. if b {
  540. return append(buf, 1)
  541. }
  542. return append(buf, 0)
  543. }
  544. // newCond is a helper to hide the fact that there is no usable zero
  545. // value for sync.Cond.
  546. func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
  547. // window represents the buffer available to clients
  548. // wishing to write to a channel.
  549. type window struct {
  550. *sync.Cond
  551. win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
  552. writeWaiters int
  553. closed bool
  554. }
  555. // add adds win to the amount of window available
  556. // for consumers.
  557. func (w *window) add(win uint32) bool {
  558. // a zero sized window adjust is a noop.
  559. if win == 0 {
  560. return true
  561. }
  562. w.L.Lock()
  563. if w.win+win < win {
  564. w.L.Unlock()
  565. return false
  566. }
  567. w.win += win
  568. // It is unusual that multiple goroutines would be attempting to reserve
  569. // window space, but not guaranteed. Use broadcast to notify all waiters
  570. // that additional window is available.
  571. w.Broadcast()
  572. w.L.Unlock()
  573. return true
  574. }
  575. // close sets the window to closed, so all reservations fail
  576. // immediately.
  577. func (w *window) close() {
  578. w.L.Lock()
  579. w.closed = true
  580. w.Broadcast()
  581. w.L.Unlock()
  582. }
  583. // reserve reserves win from the available window capacity.
  584. // If no capacity remains, reserve will block. reserve may
  585. // return less than requested.
  586. func (w *window) reserve(win uint32) (uint32, error) {
  587. var err error
  588. w.L.Lock()
  589. w.writeWaiters++
  590. w.Broadcast()
  591. for w.win == 0 && !w.closed {
  592. w.Wait()
  593. }
  594. w.writeWaiters--
  595. if w.win < win {
  596. win = w.win
  597. }
  598. w.win -= win
  599. if w.closed {
  600. err = io.EOF
  601. }
  602. w.L.Unlock()
  603. return win, err
  604. }
  605. // waitWriterBlocked waits until some goroutine is blocked for further
  606. // writes. It is used in tests only.
  607. func (w *window) waitWriterBlocked() {
  608. w.Cond.L.Lock()
  609. for w.writeWaiters == 0 {
  610. w.Cond.Wait()
  611. }
  612. w.Cond.L.Unlock()
  613. }