ssh: send ext-info-c only once

In accordance to RFC8308, send ext-info-c only during the first key
exchange. Some server implementations such as OpenSSH 7 will send an
extInfoMsg message each time when ext-info-c is received. This results
in a closed connection, as our client does not expect this message while
handling the mux.

See https://bugzilla.mindrot.org/show_bug.cgi?id=2929 regarding the
behaviour of OpenSSH if it sees ext-info-c in later key exchanges.

Fixes golang/go#51808

Change-Id: Id94f1ef73cec6147136246b0b6048b57db92660d
GitHub-Last-Rev: fcfe5ed37306136219854031abc809e0dc9b3124
GitHub-Pull-Request: golang/crypto#208
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/394134
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
diff --git a/ssh/handshake.go b/ssh/handshake.go
index f815cdb..653dc4d 100644
--- a/ssh/handshake.go
+++ b/ssh/handshake.go
@@ -479,10 +479,12 @@
 
 		// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
 		// algorithms the server supports for public key authentication. See RFC
-		// 8303, Section 2.1.
-		msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1)
-		msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
-		msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
+		// 8308, Section 2.1.
+		if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
+			msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1)
+			msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
+			msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
+		}
 	}
 
 	packet := Marshal(msg)