ssh/knownhosts: add IsHostAuthority.

This is a breaking change.

This adds a new hostkey callback which takes the hostname field
restrictions into account when validating host certificates.

Prior to this, a known_hosts file with the following entry

  @cert-authority *.example.com ssh-rsa <example.com public key>

would, when passed to knownhosts.New() generate an ssh.HostKeyCallback
that would accept all host certificates signed by the example.com public
key, no matter what host the client was connecting to.

After this change, that known_hosts entry can only be used to validate
host certificates presented when connecting to hosts under *.example.com

This also renames IsAuthority to IsUserAuthority to make its intended
purpose more clear.

Change-Id: I7188a53fdd40a8c0bc21983105317b3498f567bb
Reviewed-on: https://go-review.googlesource.com/41751
Reviewed-by: Han-Wen Nienhuys <hanwen@google.com>
Run-TryBot: Han-Wen Nienhuys <hanwen@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Peter Moody
2017-05-02 11:58:17 +00:00
committed by Han-Wen Nienhuys
parent c7af5bf263
commit 527d12e535
4 changed files with 37 additions and 24 deletions
+11 -12
View File
@@ -144,11 +144,16 @@ func keyEq(a, b ssh.PublicKey) bool {
return bytes.Equal(a.Marshal(), b.Marshal())
}
// IsAuthority can be used as a callback in ssh.CertChecker
func (db *hostKeyDB) IsAuthority(remote ssh.PublicKey) bool {
// IsAuthorityForHost can be used as a callback in ssh.CertChecker
func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool {
h, p, err := net.SplitHostPort(address)
if err != nil {
return false
}
a := addr{host: h, port: p}
for _, l := range db.lines {
// TODO(hanwen): should we check the hostname against host pattern?
if l.cert && keyEq(l.knownKey.Key, remote) {
if l.cert && keyEq(l.knownKey.Key, remote) && l.match([]addr{a}) {
return true
}
}
@@ -409,9 +414,7 @@ func (db *hostKeyDB) Read(r io.Reader, filename string) error {
// New creates a host key callback from the given OpenSSH host key
// files. The returned callback is for use in
// ssh.ClientConfig.HostKeyCallback. Hostnames are ignored for
// certificates, ie. any certificate authority is assumed to be valid
// for all remote hosts. Hashed hostnames are not supported.
// ssh.ClientConfig.HostKeyCallback. Hashed hostnames are not supported.
func New(files ...string) (ssh.HostKeyCallback, error) {
db := newHostKeyDB()
for _, fn := range files {
@@ -425,12 +428,8 @@ func New(files ...string) (ssh.HostKeyCallback, error) {
}
}
// TODO(hanwen): properly supporting certificates requires an
// API change in the SSH library: IsAuthority should provide
// the address too?
var certChecker ssh.CertChecker
certChecker.IsAuthority = db.IsAuthority
certChecker.IsHostAuthority = db.IsHostAuthority
certChecker.IsRevoked = db.IsRevoked
certChecker.HostKeyFallback = db.check