blob: dab10d5b3911de47683041898a04b0bc356da6f1 [file] [log] [blame]
Russ Cox470549d2012-01-25 15:31:12 -05001// 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
5package ssh
6
7import (
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -04008 "crypto"
Russ Cox470549d2012-01-25 15:31:12 -05009 "crypto/dsa"
Jonathan Pittman94c9f922012-12-14 05:52:19 +110010 "crypto/ecdsa"
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040011 "crypto/elliptic"
Russ Cox470549d2012-01-25 15:31:12 -050012 "crypto/rsa"
Adam Langley63f855d2012-04-20 15:17:42 -040013 "errors"
Dave Cheney1582bf02012-10-30 18:13:59 +110014 "fmt"
Russ Cox470549d2012-01-25 15:31:12 -050015 "math/big"
Russ Cox470549d2012-01-25 15:31:12 -050016 "sync"
Jonathan Pittman6a743c52013-09-09 13:06:04 -040017
18 _ "crypto/sha1"
19 _ "crypto/sha256"
20 _ "crypto/sha512"
Russ Cox470549d2012-01-25 15:31:12 -050021)
22
23// These are string constants in the SSH protocol.
24const (
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040025 kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
Russ Cox470549d2012-01-25 15:31:12 -050026 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040027 kexAlgoECDH256 = "ecdh-sha2-nistp256"
28 kexAlgoECDH384 = "ecdh-sha2-nistp384"
29 kexAlgoECDH521 = "ecdh-sha2-nistp521"
Russ Cox470549d2012-01-25 15:31:12 -050030 hostAlgoRSA = "ssh-rsa"
Jonathan Pittman9b05c272012-02-24 12:52:06 -050031 hostAlgoDSA = "ssh-dss"
Russ Cox470549d2012-01-25 15:31:12 -050032 compressionNone = "none"
33 serviceUserAuth = "ssh-userauth"
34 serviceSSH = "ssh-connection"
35)
36
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040037var supportedKexAlgos = []string{
38 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
39 kexAlgoDH14SHA1, kexAlgoDH1SHA1,
40}
41
Russ Cox470549d2012-01-25 15:31:12 -050042var supportedHostKeyAlgos = []string{hostAlgoRSA}
Russ Cox470549d2012-01-25 15:31:12 -050043var supportedCompressions = []string{compressionNone}
44
Jonathan Pittman6a743c52013-09-09 13:06:04 -040045// hashFuncs keeps the mapping of supported algorithms to their respective
46// hashes needed for signature verification.
47var hashFuncs = map[string]crypto.Hash{
48 KeyAlgoRSA: crypto.SHA1,
49 KeyAlgoDSA: crypto.SHA1,
50 KeyAlgoECDSA256: crypto.SHA256,
51 KeyAlgoECDSA384: crypto.SHA384,
52 KeyAlgoECDSA521: crypto.SHA512,
53 CertAlgoRSAv01: crypto.SHA1,
54 CertAlgoDSAv01: crypto.SHA1,
55 CertAlgoECDSA256v01: crypto.SHA256,
56 CertAlgoECDSA384v01: crypto.SHA384,
57 CertAlgoECDSA521v01: crypto.SHA512,
58}
59
Russ Cox470549d2012-01-25 15:31:12 -050060// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
61type dhGroup struct {
62 g, p *big.Int
63}
64
Adam Langley63f855d2012-04-20 15:17:42 -040065func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
66 if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
67 return nil, errors.New("ssh: DH parameter out of bounds")
68 }
69 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
70}
71
Daniel Theophanes36a967d2012-03-06 11:25:32 -050072// dhGroup1 is the group called diffie-hellman-group1-sha1 in RFC 4253 and
73// Oakley Group 2 in RFC 2409.
74var dhGroup1 *dhGroup
75
76var dhGroup1Once sync.Once
77
78func initDHGroup1() {
79 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
80
81 dhGroup1 = &dhGroup{
82 g: new(big.Int).SetInt64(2),
83 p: p,
84 }
85}
86
Russ Cox470549d2012-01-25 15:31:12 -050087// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
88// Oakley Group 14 in RFC 3526.
89var dhGroup14 *dhGroup
90
91var dhGroup14Once sync.Once
92
93func initDHGroup14() {
94 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
95
96 dhGroup14 = &dhGroup{
97 g: new(big.Int).SetInt64(2),
98 p: p,
99 }
100}
101
102// UnexpectedMessageError results when the SSH message that we received didn't
103// match what we wanted.
104type UnexpectedMessageError struct {
105 expected, got uint8
106}
107
108func (u UnexpectedMessageError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +1100109 return fmt.Sprintf("ssh: unexpected message type %d (expected %d)", u.got, u.expected)
Russ Cox470549d2012-01-25 15:31:12 -0500110}
111
112// ParseError results from a malformed SSH message.
113type ParseError struct {
114 msgType uint8
115}
116
117func (p ParseError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +1100118 return fmt.Sprintf("ssh: parse error in message type %d", p.msgType)
Russ Cox470549d2012-01-25 15:31:12 -0500119}
120
121type handshakeMagics struct {
122 clientVersion, serverVersion []byte
123 clientKexInit, serverKexInit []byte
124}
125
126func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
127 for _, clientAlgo := range clientAlgos {
128 for _, serverAlgo := range serverAlgos {
129 if clientAlgo == serverAlgo {
130 return clientAlgo, true
131 }
132 }
133 }
Dave Cheney1582bf02012-10-30 18:13:59 +1100134 return
135}
Russ Cox470549d2012-01-25 15:31:12 -0500136
Dave Cheney1582bf02012-10-30 18:13:59 +1100137func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCipher string, ok bool) {
138 for _, clientCipher := range clientCiphers {
139 for _, serverCipher := range serverCiphers {
140 // reject the cipher if we have no cipherModes definition
141 if clientCipher == serverCipher && cipherModes[clientCipher] != nil {
142 return clientCipher, true
143 }
144 }
145 }
Russ Cox470549d2012-01-25 15:31:12 -0500146 return
147}
148
149func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) {
150 kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
151 if !ok {
152 return
153 }
154
155 hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
156 if !ok {
157 return
158 }
159
Dave Cheney1582bf02012-10-30 18:13:59 +1100160 transport.writer.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
Russ Cox470549d2012-01-25 15:31:12 -0500161 if !ok {
162 return
163 }
164
Dave Cheney1582bf02012-10-30 18:13:59 +1100165 transport.reader.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
Russ Cox470549d2012-01-25 15:31:12 -0500166 if !ok {
167 return
168 }
169
170 transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
171 if !ok {
172 return
173 }
174
175 transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
176 if !ok {
177 return
178 }
179
180 transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
181 if !ok {
182 return
183 }
184
185 transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
186 if !ok {
187 return
188 }
189
190 ok = true
191 return
192}
193
194// Cryptographic configuration common to both ServerConfig and ClientConfig.
195type CryptoConfig struct {
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400196 // The allowed key exchanges algorithms. If unspecified then a
197 // default set of algorithms is used.
198 KeyExchanges []string
199
Russ Cox470549d2012-01-25 15:31:12 -0500200 // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
201 // used.
202 Ciphers []string
Dave Cheney6de97b52012-02-27 19:40:52 -0500203
204 // The allowed MAC algorithms. If unspecified then DefaultMACOrder is used.
205 MACs []string
Russ Cox470549d2012-01-25 15:31:12 -0500206}
207
208func (c *CryptoConfig) ciphers() []string {
209 if c.Ciphers == nil {
210 return DefaultCipherOrder
211 }
212 return c.Ciphers
213}
214
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400215func (c *CryptoConfig) kexes() []string {
216 if c.KeyExchanges == nil {
217 return defaultKeyExchangeOrder
218 }
219 return c.KeyExchanges
220}
221
Dave Cheney6de97b52012-02-27 19:40:52 -0500222func (c *CryptoConfig) macs() []string {
223 if c.MACs == nil {
224 return DefaultMACOrder
225 }
226 return c.MACs
227}
228
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400229// ecHash returns the hash to match the given elliptic curve, see RFC
230// 5656, section 6.2.1
231func ecHash(curve elliptic.Curve) crypto.Hash {
232 bitSize := curve.Params().BitSize
233 switch {
234 case bitSize <= 256:
235 return crypto.SHA256
236 case bitSize <= 384:
237 return crypto.SHA384
238 }
239 return crypto.SHA512
240}
241
Russ Cox470549d2012-01-25 15:31:12 -0500242// serialize a signed slice according to RFC 4254 6.6.
243func serializeSignature(algoname string, sig []byte) []byte {
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500244 // The corresponding private key to a public certificate is always a normal
245 // private key. For signature serialization purposes, ensure we use the
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100246 // proper key algorithm name in case the public cert algorithm name is passed.
Jonathan Pittman6a743c52013-09-09 13:06:04 -0400247 algoname = pubAlgoToPrivAlgo(algoname)
248
Adam Langley63f855d2012-04-20 15:17:42 -0400249 length := stringLength(len(algoname))
250 length += stringLength(len(sig))
Russ Cox470549d2012-01-25 15:31:12 -0500251
252 ret := make([]byte, length)
253 r := marshalString(ret, []byte(algoname))
254 r = marshalString(r, sig)
255
256 return ret
257}
258
Jonathan Pittman6a743c52013-09-09 13:06:04 -0400259func verifySignature(hash []byte, sig *signature, key interface{}) error {
260 switch pubKey := key.(type) {
261 case *rsa.PublicKey:
262 return verifyRSASignature(hash, sig, pubKey)
263 case *dsa.PublicKey:
264 return verifyDSASignature(hash, sig, pubKey)
265 case *ecdsa.PublicKey:
266 return verifyECDSASignature(hash, sig, pubKey)
267 case *OpenSSHCertV01:
268 return verifySignature(hash, sig, pubKey.Key)
269 }
270 return fmt.Errorf("ssh: unknown key type %T", key)
271}
272
273func verifyRSASignature(hash []byte, sig *signature, key *rsa.PublicKey) error {
274 return rsa.VerifyPKCS1v15(key, crypto.SHA1, hash, sig.Blob)
275}
276
277func verifyDSASignature(hash []byte, sig *signature, key *dsa.PublicKey) error {
278 // Per RFC 4253, section 6.6,
279 // The value for 'dss_signature_blob' is encoded as a string containing
280 // r, followed by s (which are 160-bit integers, without lengths or
281 // padding, unsigned, and in network byte order).
282 // For DSS purposes, sig.Blob should be exactly 40 bytes in length.
283 if len(sig.Blob) != 40 {
284 return fmt.Errorf("ssh: improper dss signature length of %d", len(sig.Blob))
285 }
286 r := new(big.Int).SetBytes(sig.Blob[:20])
287 s := new(big.Int).SetBytes(sig.Blob[20:])
288 if !dsa.Verify(key, hash, r, s) {
289 return errors.New("ssh: unable to verify dsa signature")
290 }
291 return nil
292}
293
294func verifyECDSASignature(hash []byte, sig *signature, key *ecdsa.PublicKey) error {
295 // Per RFC 5656, section 3.1.2,
296 // The ecdsa_signature_blob value has the following specific encoding:
297 // mpint r
298 // mpint s
299 r, rest, ok := parseInt(sig.Blob)
300 if !ok {
301 return errors.New("ssh: ecdsa signature blob parse failed")
302 }
303 s, rest, ok := parseInt(rest)
304 if !ok || len(rest) > 0 {
305 return errors.New("ssh: ecdsa signature blob parse failed")
306 }
307 if !ecdsa.Verify(key, hash, r, s) {
308 return errors.New("ssh: unable to verify ecdsa signature")
309 }
310 return nil
311}
312
Adam Langleyd33bbf22012-02-23 10:42:21 -0500313// serialize a *rsa.PublicKey or *dsa.PublicKey according to RFC 4253 6.6.
Han-Wen Nienhuysf17d1302013-09-05 11:36:51 -0400314func serializePublicKey(key interface{}) []byte {
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500315 var pubKeyBytes []byte
Russ Cox470549d2012-01-25 15:31:12 -0500316 algoname := algoName(key)
317 switch key := key.(type) {
Adam Langleyd33bbf22012-02-23 10:42:21 -0500318 case *rsa.PublicKey:
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500319 pubKeyBytes = marshalPubRSA(key)
Adam Langleyd33bbf22012-02-23 10:42:21 -0500320 case *dsa.PublicKey:
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500321 pubKeyBytes = marshalPubDSA(key)
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100322 case *ecdsa.PublicKey:
323 pubKeyBytes = marshalPubECDSA(key)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500324 case *OpenSSHCertV01:
325 pubKeyBytes = marshalOpenSSHCertV01(key)
326 default:
327 panic("unexpected key type")
Russ Cox470549d2012-01-25 15:31:12 -0500328 }
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500329
Adam Langley63f855d2012-04-20 15:17:42 -0400330 length := stringLength(len(algoname))
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500331 length += len(pubKeyBytes)
332 ret := make([]byte, length)
333 r := marshalString(ret, []byte(algoname))
334 copy(r, pubKeyBytes)
335 return ret
Russ Cox470549d2012-01-25 15:31:12 -0500336}
337
338func algoName(key interface{}) string {
339 switch key.(type) {
Adam Langleyd33bbf22012-02-23 10:42:21 -0500340 case *rsa.PublicKey:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500341 return KeyAlgoRSA
Adam Langleyd33bbf22012-02-23 10:42:21 -0500342 case *dsa.PublicKey:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500343 return KeyAlgoDSA
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100344 case *ecdsa.PublicKey:
345 switch key.(*ecdsa.PublicKey).Params().BitSize {
346 case 256:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500347 return KeyAlgoECDSA256
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100348 case 384:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500349 return KeyAlgoECDSA384
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100350 case 521:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500351 return KeyAlgoECDSA521
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100352 }
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500353 case *OpenSSHCertV01:
Jonathan Pittmand95b2832012-12-16 10:47:10 -0500354 switch key.(*OpenSSHCertV01).Key.(type) {
355 case *rsa.PublicKey:
356 return CertAlgoRSAv01
357 case *dsa.PublicKey:
358 return CertAlgoDSAv01
359 case *ecdsa.PublicKey:
360 switch key.(*OpenSSHCertV01).Key.(*ecdsa.PublicKey).Params().BitSize {
361 case 256:
362 return CertAlgoECDSA256v01
363 case 384:
364 return CertAlgoECDSA384v01
365 case 521:
366 return CertAlgoECDSA521v01
367 }
368 }
Russ Cox470549d2012-01-25 15:31:12 -0500369 }
Han-Wen Nienhuysf17d1302013-09-05 11:36:51 -0400370 panic(fmt.Sprintf("unexpected key type %T", key))
Russ Cox470549d2012-01-25 15:31:12 -0500371}
372
Jonathan Pittman6a743c52013-09-09 13:06:04 -0400373// pubAlgoToPrivAlgo returns the private key algorithm format name that
374// corresponds to a given public key algorithm format name. For most
375// public keys, the private key algorithm name is the same. For some
376// situations, such as openssh certificates, the private key algorithm and
377// public key algorithm names differ. This accounts for those situations.
378func pubAlgoToPrivAlgo(pubAlgo string) string {
379 switch pubAlgo {
380 case CertAlgoRSAv01:
381 return KeyAlgoRSA
382 case CertAlgoDSAv01:
383 return KeyAlgoDSA
384 case CertAlgoECDSA256v01:
385 return KeyAlgoECDSA256
386 case CertAlgoECDSA384v01:
387 return KeyAlgoECDSA384
388 case CertAlgoECDSA521v01:
389 return KeyAlgoECDSA521
390 }
391 return pubAlgo
392}
393
Russ Cox470549d2012-01-25 15:31:12 -0500394// buildDataSignedForAuth returns the data that is signed in order to prove
395// posession of a private key. See RFC 4252, section 7.
396func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
397 user := []byte(req.User)
398 service := []byte(req.Service)
399 method := []byte(req.Method)
400
Adam Langley63f855d2012-04-20 15:17:42 -0400401 length := stringLength(len(sessionId))
Russ Cox470549d2012-01-25 15:31:12 -0500402 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400403 length += stringLength(len(user))
404 length += stringLength(len(service))
405 length += stringLength(len(method))
Russ Cox470549d2012-01-25 15:31:12 -0500406 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400407 length += stringLength(len(algo))
408 length += stringLength(len(pubKey))
Russ Cox470549d2012-01-25 15:31:12 -0500409
410 ret := make([]byte, length)
411 r := marshalString(ret, sessionId)
412 r[0] = msgUserAuthRequest
413 r = r[1:]
414 r = marshalString(r, user)
415 r = marshalString(r, service)
416 r = marshalString(r, method)
417 r[0] = 1
418 r = r[1:]
419 r = marshalString(r, algo)
420 r = marshalString(r, pubKey)
421 return ret
422}
423
Adam Langley4002be22012-12-10 18:12:36 -0500424// safeString sanitises s according to RFC 4251, section 9.2.
Russ Cox470549d2012-01-25 15:31:12 -0500425// All control characters except tab, carriage return and newline are
426// replaced by 0x20.
427func safeString(s string) string {
428 out := []byte(s)
429 for i, c := range out {
430 if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
431 out[i] = 0x20
432 }
433 }
434 return string(out)
435}
Dave Cheney79d53bd2012-03-04 14:34:24 -0800436
437func appendU16(buf []byte, n uint16) []byte {
438 return append(buf, byte(n>>8), byte(n))
439}
440
441func appendU32(buf []byte, n uint32) []byte {
442 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
443}
444
445func appendInt(buf []byte, n int) []byte {
446 return appendU32(buf, uint32(n))
447}
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000448
Han-Wen Nienhuysc7df5652013-06-06 10:44:12 -0400449func appendString(buf []byte, s string) []byte {
450 buf = appendU32(buf, uint32(len(s)))
451 buf = append(buf, s...)
452 return buf
453}
454
455func appendBool(buf []byte, b bool) []byte {
456 if b {
457 buf = append(buf, 1)
458 } else {
459 buf = append(buf, 0)
460 }
461 return buf
462}
463
Adam Langley4002be22012-12-10 18:12:36 -0500464// newCond is a helper to hide the fact that there is no usable zero
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000465// value for sync.Cond.
466func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
467
Adam Langley4002be22012-12-10 18:12:36 -0500468// window represents the buffer available to clients
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000469// wishing to write to a channel.
470type window struct {
471 *sync.Cond
472 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
473}
474
475// add adds win to the amount of window available
476// for consumers.
477func (w *window) add(win uint32) bool {
Dave Cheney55aa0812012-05-22 12:04:51 +1000478 // a zero sized window adjust is a noop.
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000479 if win == 0 {
Dave Cheney55aa0812012-05-22 12:04:51 +1000480 return true
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000481 }
482 w.L.Lock()
483 if w.win+win < win {
484 w.L.Unlock()
485 return false
486 }
487 w.win += win
488 // It is unusual that multiple goroutines would be attempting to reserve
Adam Langley4002be22012-12-10 18:12:36 -0500489 // window space, but not guaranteed. Use broadcast to notify all waiters
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000490 // that additional window is available.
491 w.Broadcast()
492 w.L.Unlock()
493 return true
494}
495
496// reserve reserves win from the available window capacity.
497// If no capacity remains, reserve will block. reserve may
498// return less than requested.
499func (w *window) reserve(win uint32) uint32 {
500 w.L.Lock()
501 for w.win == 0 {
502 w.Wait()
503 }
504 if w.win < win {
505 win = w.win
506 }
507 w.win -= win
508 w.L.Unlock()
509 return win
510}