-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x/crypto/ssh/knownhosts: Should "*" match ports other than 22? #52056
Comments
Thanks for the issue. The code above currently using internal functions like testDB. Could you explain what exported functions this is affecting? Could you add an example using exported functions? Thanks. |
That code is a unit test for you in the |
Sorry, I'm not sure I understand. Is there anything unexpected that can be observed from exported API? Or this is just an implementation detail that users of this package cannot observe? Thanks. |
Yes -- A user trying to use the host key returned by
For example (and codified in the unit test I've provided), if the known-hosts file contains an entry like I clarified the test case a bit and tried to rename it more precisely (original version didn't have the actual func TestWildcardHostAuthorityNon22Port(t *testing.T) {
str := fmt.Sprintf("@cert-authority * %s", edKeyStr)
db := testDB(t, str)
want := &KeyError{
Want: []KnownKey{{
Filename: "testdb",
Line: 1,
Key: edKey,
}},
}
got := db.check("server.domain:2222", &net.TCPAddr{}, ecKey)
if !reflect.DeepEqual(got, want) {
t.Errorf("got %s, want %s", got, want)
}
} |
Thanks. |
We're encountering the same problem in skeema/knownhosts#9 ... it appears that wildcards are only applied to the hostname portion, and not the port portion, due to the logic at https://cs.opensource.google/go/x/crypto/+/refs/tags/v0.24.0:ssh/knownhosts/knownhosts.go;l=110 func (p *hostPattern) match(a addr) bool {
return wildcardMatch([]byte(p.addr.host), []byte(a.host)) && p.addr.port == a.port
} The OpenSSH doc doesn't specify whether wildcards should apply to ports, but indeed the actual behavior of OpenSSH differs from that of x/crypto/ssh/knownhosts here. In order to match a non-standard port with x/crypto/ssh/knownhosts, currently the known_hosts line needs to specify the exact port, e.g. |
In OpenSSH, wildcard host pattern entries in a known_hosts file can match hosts regardless of their port number. However, x/crypto/ssh/knownhosts does not follow this behavior, instead requiring strict port equality; see bug golang/go#52056 for background. This commit implements a workaround in skeema/knownhosts, which is enabled when using the NewDB constructor. Conceptually, the workaround works like this: * At constructor time, when re-reading the known_hosts file (originally to look for @cert-authority lines), also look for lines that have wildcards in the host pattern and no port number specified. Track these lines in a new field of the HostKeyDB struct for later use. * When a host key callback returns no matches (KeyError with empty Want slice) and the host had a nonstandard (non-22) port number, try the callback again, this time manipulating the host arg to be on port 22. * If this second call returned nil error, that means the host key now matched a known_hosts entry on port 22, so consider the host as known. * If this second call returned a KeyError with non-empty Want slice, filter down the resulting keys to only correspond to lines with known wildcards, using the preprocessed information from the first step. This ensures we aren't incorrectly returning non-wildcard entries among the Want slice. The implementation for the latter 3 bullets gets embedded directly in the host key callback returned by HostKeyDB.HostKeyCallback, by way of some nested callback wrapping. This only happens if the first bullet actually found at least one wildcard in the file.
In OpenSSH, wildcard host pattern entries in a known_hosts file can match hosts regardless of their port number. However, x/crypto/ssh/knownhosts does not follow this behavior, instead requiring strict port equality; see bug golang/go#52056 for background. This commit implements a workaround in skeema/knownhosts, which is enabled when using the NewDB constructor. Conceptually, the workaround works like this: * At constructor time, when re-reading the known_hosts file (originally to look for @cert-authority lines), also look for lines that have wildcards in the host pattern and no port number specified. Track these lines in a new field of the HostKeyDB struct for later use. * When a host key callback returns no matches (KeyError with empty Want slice) and the host had a nonstandard (non-22) port number, try the callback again, this time manipulating the host arg to be on port 22. * If this second call returned nil error, that means the host key now matched a known_hosts entry on port 22, so consider the host as known. * If this second call returned a KeyError with non-empty Want slice, filter down the resulting keys to only correspond to lines with known wildcards, using the preprocessed information from the first step. This ensures we aren't incorrectly returning non-wildcard entries among the Want slice. The implementation for the latter 3 bullets gets embedded directly in the host key callback returned by HostKeyDB.HostKeyCallback, by way of some nested callback wrapping. This only happens if the first bullet actually found at least one wildcard in the file.
In OpenSSH, wildcard host pattern entries in a known_hosts file can match hosts regardless of their port number. However, x/crypto/ssh/knownhosts does not follow this behavior, instead requiring strict port equality; see bug golang/go#52056 for background. This commit implements a workaround in skeema/knownhosts, which is enabled when using the NewDB constructor. Conceptually, the workaround works like this: * At constructor time, when re-reading the known_hosts file (originally to look for @cert-authority lines), also look for lines that have wildcards in the host pattern and no port number specified. Track these lines in a new field of the HostKeyDB struct for later use. * When a host key callback returns no matches (KeyError with empty Want slice) and the host had a nonstandard (non-22) port number, try the callback again, this time manipulating the host arg to be on port 22. * If this second call returned nil error, that means the host key now matched a known_hosts entry on port 22, so consider the host as known. * If this second call returned a KeyError with non-empty Want slice, filter down the resulting keys to only correspond to lines with known wildcards, using the preprocessed information from the first step. This ensures we aren't incorrectly returning non-wildcard entries among the Want slice. The implementation for the latter 3 bullets gets embedded directly in the host key callback returned by HostKeyDB.HostKeyCallback, by way of some nested callback wrapping. This only happens if the first bullet actually found at least one wildcard in the file.
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I tried to use
knownhosts.New
along with a file using@cert-authority
wildcards that are intended to match a server listening on a port other than 22. In short, I believe the following unit test should pass (it does not in current version):What did you expect to see?
I was expecting this to pass. It appears that the formulation is allowed by OpenSSH at least (I tried to find that in the BSD source code but don't read C well enough to navigate that codebase).
What did you see instead?
Host key matching in
ssh/knownhosts/knownhosts.go
currently fails for such a wildcard. I believe this is becausenewHostnameMatcher
, when provided the input pattern*
, gets an error (as expected) in the call toSplitHostPort
, which leads it to supply an explicit expectation of port 22 in the generated matcher. That subsequently will fail the port check in thep.addr.port == a.port
expression used to test matches.I'm happy to propose changes, but wonder if perhaps I'm misunderstanding OpenSSH (it being the reference implementation, IIUC).
The text was updated successfully, but these errors were encountered: