Refactor code use updated interfaces for golang.org/x/crypto/ssh.

This commit is contained in:
Russell Jones 2018-04-05 01:14:14 +00:00
parent 8331645a75
commit bfb4c41891
7 changed files with 48 additions and 14 deletions

View file

@ -154,8 +154,8 @@ func NewTunnel(addr utils.NetAddr,
if err != nil {
return nil, err
}
tunnel.userCertChecker = ssh.CertChecker{IsAuthority: tunnel.isUserAuthority}
tunnel.hostCertChecker = ssh.CertChecker{IsAuthority: tunnel.isHostAuthority}
tunnel.userCertChecker = ssh.CertChecker{IsUserAuthority: tunnel.isUserAuthority}
tunnel.hostCertChecker = ssh.CertChecker{IsHostAuthority: tunnel.isHostAuthority}
return tunnel, nil
}
@ -246,7 +246,7 @@ func (s *AuthTunnel) HandleNewChan(_ net.Conn, sconn *ssh.ServerConn, nch ssh.Ne
// isHostAuthority is called during checking the client key, to see if the signing
// key is the real host CA authority key.
func (s *AuthTunnel) isHostAuthority(auth ssh.PublicKey) bool {
func (s *AuthTunnel) isHostAuthority(auth ssh.PublicKey, address string) bool {
domainName, err := s.authServer.GetDomainName()
if err != nil {
return false

View file

@ -163,7 +163,7 @@ type Config struct {
// HostKeyCallback will be called to check host keys of the remote
// node, if not specified will be using CheckHostSignature function
// that uses local cache to validate hosts
HostKeyCallback HostKeyCallback
HostKeyCallback ssh.HostKeyCallback
// KeyDir defines where temporary session keys will be stored.
// if empty, they'll go to ~/.tsh

View file

@ -51,7 +51,7 @@ type ProxyClient struct {
hostLogin string
proxyAddress string
proxyPrincipal string
hostKeyCallback utils.HostKeyCallback
hostKeyCallback ssh.HostKeyCallback
authMethod ssh.AuthMethod
siteName string
clientAddr string

View file

@ -126,7 +126,7 @@ type Agent struct {
AgentConfig
ctx context.Context
cancel context.CancelFunc
hostKeyCallback utils.HostKeyCallback
hostKeyCallback ssh.HostKeyCallback
authMethods []ssh.AuthMethod
// state is the state of this agent
state string

View file

@ -23,6 +23,7 @@ import (
"fmt"
"net"
"net/http"
"strconv"
"strings"
"sync"
"sync/atomic"
@ -228,8 +229,8 @@ func NewServer(cfg Config) (Server, error) {
if err != nil {
return nil, err
}
srv.hostCertChecker = ssh.CertChecker{IsAuthority: srv.isHostAuthority}
srv.userCertChecker = ssh.CertChecker{IsAuthority: srv.isUserAuthority}
srv.userCertChecker = ssh.CertChecker{IsUserAuthority: srv.isUserAuthority}
srv.hostCertChecker = ssh.CertChecker{IsHostAuthority: srv.isHostAuthority}
srv.srv = s
go srv.periodicFunctions()
return srv, nil
@ -473,7 +474,7 @@ func (s *server) HandleNewChan(conn net.Conn, sconn *ssh.ServerConn, nch ssh.New
// isHostAuthority is called during checking the client key, to see if the signing
// key is the real host CA authority key.
func (s *server) isHostAuthority(auth ssh.PublicKey) bool {
func (s *server) isHostAuthority(auth ssh.PublicKey, address string) bool {
keys, err := s.getTrustedCAKeys(services.HostCA)
if err != nil {
s.Errorf("failed to retrieve trusted keys, err: %v", err)
@ -561,7 +562,17 @@ func (s *server) keyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permiss
logger.Warningf("Failed to authenticate host, err: %v.", err)
return nil, err
}
err := s.hostCertChecker.CheckHostKey(conn.User(), conn.RemoteAddr(), key)
// CheckHostKey expects the addr that is passed in to be in the format
// host:port. This is because this function is usually used by a client to
// check if the host it attempted to connect to presented a certificate for
// the host requested (this prevents man-in-the-middle attacks).
//
// In this situation however, it's a server essentially performing user
// authentication, but since it's machine-to-machine communication, the
// "user" is presenting a host certificate. To make CheckHostKey behave
// like Authenticate we pass in a addr in the host:port format it expects.
addr := formatAddr(conn.User())
err := s.hostCertChecker.CheckHostKey(addr, conn.RemoteAddr(), key)
if err != nil {
logger.Warningf("Failed to authenticate host, err: %v.", err)
return nil, trace.Wrap(err)
@ -850,6 +861,29 @@ func newRemoteSite(srv *server, domainName string) (*remoteSite, error) {
return remoteSite, nil
}
// formatAddr adds :port to the passed in string if it's not in
// host:port format.
func formatAddr(s string) string {
i := strings.Index(s, ":")
if i == -1 {
return s + ":0"
}
if i == len(s)-1 {
return s[:len(s)-1] + ":0"
}
port, err := strconv.Atoi(s[i+1:])
if err != nil {
return s[:i] + ":0"
}
if port < 0 || port > 65535 {
return s[:i] + ":0"
}
return s
}
const (
extHost = "host@teleport"
extCertType = "certtype@teleport"

View file

@ -167,7 +167,7 @@ func (h *AuthHandlers) UserKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*s
h.AuditLog.EmitAuditEvent(events.AuthAttemptEvent, fields)
}
certChecker := ssh.CertChecker{IsAuthority: h.IsUserAuthority}
certChecker := ssh.CertChecker{IsUserAuthority: h.IsUserAuthority}
permissions, err := certChecker.Authenticate(conn, key)
if err != nil {
recordFailedLogin(err)

View file

@ -572,7 +572,7 @@ func makeClient(cf *CLIConf, useProfileLogin bool) (tc *client.TeleportClient, e
key *client.Key
identityAuth ssh.AuthMethod
expiryDate time.Time
hostAuthFunc client.HostKeyCallback
hostAuthFunc ssh.HostKeyCallback
)
// read the ID file and create an "auth method" from it:
key, hostAuthFunc, err = loadIdentity(cf.IdentityFileIn)
@ -692,7 +692,7 @@ func refuseArgs(command string, args []string) {
//
// If the "host auth callback" is not returned, user will be prompted to
// trust the proxy server.
func loadIdentity(idFn string) (*client.Key, client.HostKeyCallback, error) {
func loadIdentity(idFn string) (*client.Key, ssh.HostKeyCallback, error) {
logrus.Infof("Reading identity file: ", idFn)
f, err := os.Open(idFn)
@ -754,7 +754,7 @@ func loadIdentity(idFn string) (*client.Key, client.HostKeyCallback, error) {
if err != nil {
return nil, nil, trace.Wrap(err)
}
var hostAuthFunc client.HostKeyCallback = nil
var hostAuthFunc ssh.HostKeyCallback = nil
// validate CA (cluster) cert
if len(caCert) > 0 {
_, _, pkey, _, _, err := ssh.ParseKnownHosts(caCert)