ssh: remove custom contains, use slices.Contains

Change-Id: If4784469e7285675bdd51399a76bdc16f0036a2e
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/703635
Reviewed-by: Mark Freeman <markfreeman@google.com>
Reviewed-by: Sean Liao <sean@liao.dev>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/ssh/client_auth.go b/ssh/client_auth.go
index c12818f..3127e49 100644
--- a/ssh/client_auth.go
+++ b/ssh/client_auth.go
@@ -9,6 +9,7 @@
 	"errors"
 	"fmt"
 	"io"
+	"slices"
 	"strings"
 )
 
@@ -83,7 +84,7 @@
 			// success
 			return nil
 		} else if ok == authFailure {
-			if m := auth.method(); !contains(tried, m) {
+			if m := auth.method(); !slices.Contains(tried, m) {
 				tried = append(tried, m)
 			}
 		}
@@ -97,7 +98,7 @@
 	findNext:
 		for _, a := range config.Auth {
 			candidateMethod := a.method()
-			if contains(tried, candidateMethod) {
+			if slices.Contains(tried, candidateMethod) {
 				continue
 			}
 			for _, meth := range methods {
@@ -117,15 +118,6 @@
 	return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
 }
 
-func contains(list []string, e string) bool {
-	for _, s := range list {
-		if s == e {
-			return true
-		}
-	}
-	return false
-}
-
 // An AuthMethod represents an instance of an RFC 4252 authentication method.
 type AuthMethod interface {
 	// auth authenticates user over transport t.
@@ -255,7 +247,7 @@
 		// Fallback to use if there is no "server-sig-algs" extension or a
 		// common algorithm cannot be found. We use the public key format if the
 		// MultiAlgorithmSigner supports it, otherwise we return an error.
-		if !contains(as.Algorithms(), underlyingAlgo(keyFormat)) {
+		if !slices.Contains(as.Algorithms(), underlyingAlgo(keyFormat)) {
 			return "", fmt.Errorf("ssh: no common public key signature algorithm, server only supports %q for key type %q, signer only supports %v",
 				underlyingAlgo(keyFormat), keyFormat, as.Algorithms())
 		}
@@ -284,7 +276,7 @@
 	// Filter algorithms based on those supported by MultiAlgorithmSigner.
 	var keyAlgos []string
 	for _, algo := range algorithmsForKeyFormat(keyFormat) {
-		if contains(as.Algorithms(), underlyingAlgo(algo)) {
+		if slices.Contains(as.Algorithms(), underlyingAlgo(algo)) {
 			keyAlgos = append(keyAlgos, algo)
 		}
 	}
@@ -334,7 +326,7 @@
 		// the key try to use the obtained algorithm as if "server-sig-algs" had
 		// not been implemented if supported from the algorithm signer.
 		if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 {
-			if contains(as.Algorithms(), KeyAlgoRSA) {
+			if slices.Contains(as.Algorithms(), KeyAlgoRSA) {
 				// We retry using the compat algorithm after all signers have
 				// been tried normally.
 				signers = append(signers, &multiAlgorithmSigner{
@@ -385,7 +377,7 @@
 		// contain the "publickey" method, do not attempt to authenticate with any
 		// other keys.  According to RFC 4252 Section 7, the latter can occur when
 		// additional authentication methods are required.
-		if success == authSuccess || !contains(methods, cb.method()) {
+		if success == authSuccess || !slices.Contains(methods, cb.method()) {
 			return success, methods, err
 		}
 	}
@@ -434,7 +426,7 @@
 			// 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) {
+			if !slices.Contains(algorithmsForKeyFormat(key.Type()), msg.Algo) {
 				return false, nil
 			}
 			if !bytes.Equal(msg.PubKey, pubKey) {
diff --git a/ssh/client_auth_test.go b/ssh/client_auth_test.go
index 8d1767c..e398c40 100644
--- a/ssh/client_auth_test.go
+++ b/ssh/client_auth_test.go
@@ -14,6 +14,7 @@
 	"net"
 	"os"
 	"runtime"
+	"slices"
 	"strings"
 	"testing"
 )
@@ -1214,7 +1215,7 @@
 	if err != nil {
 		return authFailure, nil, err
 	}
-	if success == authSuccess || !contains(methods, cb.method()) {
+	if success == authSuccess || !slices.Contains(methods, cb.method()) {
 		return success, methods, err
 	}
 
diff --git a/ssh/common.go b/ssh/common.go
index 36c82a7..b1884c2 100644
--- a/ssh/common.go
+++ b/ssh/common.go
@@ -345,7 +345,7 @@
 // algorithms.
 func isRSA(algo string) bool {
 	algos := algorithmsForKeyFormat(KeyAlgoRSA)
-	return contains(algos, underlyingAlgo(algo))
+	return slices.Contains(algos, underlyingAlgo(algo))
 }
 
 func isRSACert(algo string) bool {
@@ -544,7 +544,7 @@
 		if kexAlgoMap[k] != nil {
 			// Ignore the KEX if we have no kexAlgoMap definition.
 			kexs = append(kexs, k)
-			if k == KeyExchangeCurve25519 && !contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) {
+			if k == KeyExchangeCurve25519 && !slices.Contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) {
 				kexs = append(kexs, keyExchangeCurve25519LibSSH)
 			}
 		}
diff --git a/ssh/handshake.go b/ssh/handshake.go
index a90bfe3..4be3cbb 100644
--- a/ssh/handshake.go
+++ b/ssh/handshake.go
@@ -10,6 +10,7 @@
 	"io"
 	"log"
 	"net"
+	"slices"
 	"strings"
 	"sync"
 )
@@ -527,7 +528,7 @@
 			switch s := k.(type) {
 			case MultiAlgorithmSigner:
 				for _, algo := range algorithmsForKeyFormat(keyFormat) {
-					if contains(s.Algorithms(), underlyingAlgo(algo)) {
+					if slices.Contains(s.Algorithms(), underlyingAlgo(algo)) {
 						msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo)
 					}
 				}
@@ -679,7 +680,7 @@
 		return err
 	}
 
-	if t.sessionID == nil && ((isClient && contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && contains(clientInit.KexAlgos, kexStrictClient))) {
+	if t.sessionID == nil && ((isClient && slices.Contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && slices.Contains(clientInit.KexAlgos, kexStrictClient))) {
 		t.strictMode = true
 		if err := t.conn.setStrictMode(); err != nil {
 			return err
@@ -736,7 +737,7 @@
 	// On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO
 	// message with the server-sig-algs extension if the client supports it. See
 	// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
-	if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") {
+	if !isClient && firstKeyExchange && slices.Contains(clientInit.KexAlgos, "ext-info-c") {
 		supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",")
 		extInfo := &extInfoMsg{
 			NumExtensions: 2,
@@ -790,7 +791,7 @@
 func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
 	for _, k := range hostKeys {
 		if s, ok := k.(MultiAlgorithmSigner); ok {
-			if !contains(s.Algorithms(), underlyingAlgo(algo)) {
+			if !slices.Contains(s.Algorithms(), underlyingAlgo(algo)) {
 				continue
 			}
 		}
diff --git a/ssh/keys.go b/ssh/keys.go
index 8327260..c972169 100644
--- a/ssh/keys.go
+++ b/ssh/keys.go
@@ -27,6 +27,7 @@
 	"fmt"
 	"io"
 	"math/big"
+	"slices"
 	"strings"
 
 	"golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
@@ -409,11 +410,11 @@
 	}
 
 	for _, algo := range algorithms {
-		if !contains(supportedAlgos, algo) {
+		if !slices.Contains(supportedAlgos, algo) {
 			return nil, fmt.Errorf("ssh: algorithm %q is not supported for key type %q",
 				algo, signer.PublicKey().Type())
 		}
-		if !contains(signerAlgos, algo) {
+		if !slices.Contains(signerAlgos, algo) {
 			return nil, fmt.Errorf("ssh: algorithm %q is restricted for the provided signer", algo)
 		}
 	}
@@ -500,7 +501,7 @@
 
 func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
 	supportedAlgos := algorithmsForKeyFormat(r.Type())
-	if !contains(supportedAlgos, sig.Format) {
+	if !slices.Contains(supportedAlgos, sig.Format) {
 		return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
 	}
 	hash := hashFuncs[sig.Format]
@@ -1126,7 +1127,7 @@
 		algorithm = s.pubKey.Type()
 	}
 
-	if !contains(s.Algorithms(), algorithm) {
+	if !slices.Contains(s.Algorithms(), algorithm) {
 		return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
 	}
 
diff --git a/ssh/server.go b/ssh/server.go
index 98679ba..f06c08c 100644
--- a/ssh/server.go
+++ b/ssh/server.go
@@ -10,6 +10,7 @@
 	"fmt"
 	"io"
 	"net"
+	"slices"
 	"strings"
 )
 
@@ -246,7 +247,7 @@
 		fullConf.PublicKeyAuthAlgorithms = defaultPubKeyAuthAlgos
 	} else {
 		for _, algo := range fullConf.PublicKeyAuthAlgorithms {
-			if !contains(SupportedAlgorithms().PublicKeyAuths, algo) && !contains(InsecureAlgorithms().PublicKeyAuths, algo) {
+			if !slices.Contains(SupportedAlgorithms().PublicKeyAuths, algo) && !slices.Contains(InsecureAlgorithms().PublicKeyAuths, algo) {
 				c.Close()
 				return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
 			}
@@ -631,7 +632,7 @@
 				return nil, parseError(msgUserAuthRequest)
 			}
 			algo := string(algoBytes)
-			if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
+			if !slices.Contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
 				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
 				break
 			}
@@ -695,7 +696,7 @@
 				// ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public
 				// key type. The algorithm and public key type must be
 				// consistent: both must be certificate algorithms, or neither.
-				if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
+				if !slices.Contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
 					authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
 						pubKey.Type(), algo)
 					break
@@ -705,7 +706,7 @@
 				// algorithm name that corresponds to algo with
 				// sig.Format.  This is usually the same, but
 				// for certs, the names differ.
-				if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
+				if !slices.Contains(config.PublicKeyAuthAlgorithms, sig.Format) {
 					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
 					break
 				}