Repository: go
Issue: x/crypto/ssh/knownhosts: incorrect parsing of known_hosts for ipv6
Labels: NeedsInvestigation

<!--
Please answer these questions before submitting your issue. Thanks!
-->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.18 linux/amd64
</pre>

### Does this issue reproduce with the latest release?
Yes

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GOARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOVERSION="go1.18"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"


$ ssh -V
OpenSSH_9.0p1 Debian-1, OpenSSL 1.1.1o  3 May 2022
</pre>
</details>

### What did you do?

<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on go.dev/play is best.
-->

<pre>
package main

import (
	"fmt"
	"net"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/knownhosts"
)

func main() {
	hostKeyCallback, err := knownhosts.New("/home/samir/.ssh/known_hosts")
	if err != nil {
		fmt.Println(err)
		return
	}

	config := &ssh.ClientConfig{
		User: "test",
		Auth: []ssh.AuthMethod{ssh.Password("test")},
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			addr := []string{hostname}
			line := knownhosts.Line(addr, key)
			fmt.Println(line)

			return hostKeyCallback(hostname, remote, key)
		},
	}
	_, err = ssh.Dial("tcp", "[2001:3984:3989::10]:22", config)

	if err != nil {
		fmt.Println(err)
		return
	}
}

</pre>

When running the above script, the line `line := knownhosts.Line(addr, key)` prints the following:

(The xyz is a just a placeholder)
```
[2001:3984:3989::10] ecdsa-sha2-nistp256 xyz
```

which I add to `/home/samir/.ssh/known_hosts`. I get the message `ssh: handshake failed: knownhosts: key is unknown` as well, which is expected.

### What did you expect to see?

On the second re-run (with my hostkey added to known_hosts), I expect the connection to be established.

### What did you see instead?

I see:

```
knownhosts: /home/samir/.ssh/known_hosts:1: address [2001:3984:3989::10]: missing port in address
```

If I add the `:22` port to the IP, it works (this shouldn't work though, since it's the default port, should only work when port != 22):

```
[2001:3984:3989::10]:22 ecdsa-sha2-nistp256 xyz
```

And it works if I remove the brackets (this is the correct way and how ssh works):

```
2001:3984:3989::10 ecdsa-sha2-nistp256 xyz
```

The method `Line` says `Line returns a line to add append to the known_hosts files.`, but the method `New` doesn't support parsing the `known_hosts` file without a port number when brackets `[]` are used.

So it should be:

1. If IPv6 and `port == 22` return `abcd:abcd:abcd:abcd`
2. if IPv6 and `port != 22` return `[abcd:abcd:abcd:abcd]:33`
3. If IPv4 and `port == 22` return `127.0.0.1`
4. If IPv4 and `port != 22` return `[127.0.0.1]:33`

I think the Normalize function is the culprit in some of the errors:

https://cs.opensource.google/go/x/crypto/+/bc19a97f:ssh/knownhosts/knownhosts_test.go;l=329

The test cases are:
```
		"[abcd:abcd:abcd:abcd]":    "[abcd:abcd:abcd:abcd]",
		"[abcd:abcd:abcd:abcd]:22": "[abcd:abcd:abcd:abcd]",
```

They should be (removal of brackets on the right side):

```
		"[abcd:abcd:abcd:abcd]":    "abcd:abcd:abcd:abcd",
		"[abcd:abcd:abcd:abcd]:22": "abcd:abcd:abcd:abcd",
```


Also, a small note, the method `Line` has a grammar error:

It says `Line returns a line to add append to the known_hosts files.`, but it should say:
1. `Line returns a line to add to the known_hosts files.`, or
3. `Line returns a line to append to the known_hosts files.`