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