ssh: validate key type in SSH_MSG_USERAUTH_PK_OK response

According to RFC 4252 Section 7 the algorithm in SSH_MSG_USERAUTH_PK_OK
should match that of the request but some servers send the key type instead.
OpenSSH checks for the key type, so we do the same.

Fixes golang/go#66438
Fixes golang/go#64785
Fixes golang/go#56342
Fixes golang/go#54027

Change-Id: I2f733f0faece097e44ba7a97c868d30a53e21d79
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/573360
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Joedian Reid <joedian@google.com>
diff --git a/ssh/client_auth.go b/ssh/client_auth.go
index 34bf089..9486c59 100644
--- a/ssh/client_auth.go
+++ b/ssh/client_auth.go
@@ -404,10 +404,10 @@
 		return false, err
 	}
 
-	return confirmKeyAck(key, algo, c)
+	return confirmKeyAck(key, c)
 }
 
-func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) {
+func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
 	pubKey := key.Marshal()
 
 	for {
@@ -425,7 +425,15 @@
 			if err := Unmarshal(packet, &msg); err != nil {
 				return false, err
 			}
-			if msg.Algo != algo || !bytes.Equal(msg.PubKey, pubKey) {
+			// According to RFC 4252 Section 7 the algorithm in
+			// SSH_MSG_USERAUTH_PK_OK should match that of the request but some
+			// servers send the key type instead. OpenSSH allows any algorithm
+			// that matches the public key, so we do the same.
+			// https://github.com/openssh/openssh-portable/blob/86bdd385/sshconnect2.c#L709
+			if !contains(algorithmsForKeyFormat(key.Type()), msg.Algo) {
+				return false, nil
+			}
+			if !bytes.Equal(msg.PubKey, pubKey) {
 				return false, nil
 			}
 			return true, nil