diff --git a/plumbing/transport/ssh/auth_method.go b/plumbing/transport/ssh/auth_method.go index 351466954..5adbaf52d 100644 --- a/plumbing/transport/ssh/auth_method.go +++ b/plumbing/transport/ssh/auth_method.go @@ -56,12 +56,10 @@ func (a *KeyboardInteractive) String() string { } func (a *KeyboardInteractive) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ - a.Challenge, - }, - }) + clientConfig := DefaultSSHClientConfig + clientConfig.User = a.User + clientConfig.Auth = []ssh.AuthMethod{a.Challenge} + return a.SetHostKeyCallback(clientConfig) } // Password implements AuthMethod by using the given password. @@ -80,10 +78,10 @@ func (a *Password) String() string { } func (a *Password) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.Password(a.Password)}, - }) + clientConfig := DefaultSSHClientConfig + clientConfig.User = a.User + clientConfig.Auth = []ssh.AuthMethod{ssh.Password(a.Password)} + return a.SetHostKeyCallback(clientConfig) } // PasswordCallback implements AuthMethod by using a callback @@ -103,10 +101,10 @@ func (a *PasswordCallback) String() string { } func (a *PasswordCallback) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)}, - }) + clientConfig := DefaultSSHClientConfig + clientConfig.User = a.User + clientConfig.Auth = []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)} + return a.SetHostKeyCallback(clientConfig) } // PublicKeys implements AuthMethod by using the given key pairs. @@ -152,10 +150,10 @@ func (a *PublicKeys) String() string { } func (a *PublicKeys) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.PublicKeys(a.Signer)}, - }) + clientConfig := DefaultSSHClientConfig + clientConfig.User = a.User + clientConfig.Auth = []ssh.AuthMethod{ssh.PublicKeys(a.Signer)} + return a.SetHostKeyCallback(clientConfig) } func username() (string, error) { @@ -213,10 +211,10 @@ func (a *PublicKeysCallback) String() string { } func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)}, - }) + clientConfig := DefaultSSHClientConfig + clientConfig.User = a.User + clientConfig.Auth = []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)} + return a.SetHostKeyCallback(clientConfig) } // NewKnownHostsCallback returns ssh.HostKeyCallback based on a file based on a diff --git a/plumbing/transport/ssh/common.go b/plumbing/transport/ssh/common.go index 46e79134c..bf9a24ec6 100644 --- a/plumbing/transport/ssh/common.go +++ b/plumbing/transport/ssh/common.go @@ -4,6 +4,7 @@ package ssh import ( "context" "fmt" + "os" "reflect" "strconv" "strings" @@ -27,6 +28,89 @@ type sshConfig interface { Get(alias, key string) string } +// ENV_SSH_HOSTKEY_ALGORITHMS +// +// ssh.ClientConfig.HostKeyAlgorithms +// +// Use comma as separator if multiple values. +// +// Example: +// export GO_GIT_SSH_HOSTKEY_ALGORITHMS="ssh-ed25519,ecdsa-sha2-nistp256" +// +// See golang.org/x/crypto/ssh for valid values. +// +// +// +const ENV_SSH_HOSTKEY_ALGORITHMS = "GO_GIT_SSH_HOSTKEY_ALGORITHMS" + +// ENV_SSH_CONFIG_KEY_EXCHANGES +// +// ssh.ClientConfig.Config.KeyExchanges +// +// Use comma as separator if multiple values. +// +// Example: +// export GO_GIT_SSH_CONFIG_KEY_EXCHANGES="diffie-hellman-group14-sha1,ecdh-sha2-nistp256" +// +// See golang.org/x/crypto/ssh for valid values. +const ENV_SSH_CONFIG_KEY_EXCHANGES = "GO_GIT_SSH_CONFIG_KEY_EXCHANGES" + +// ENV_SSH_CONFIG_CIPHERS +// +// ssh.ClientConfig.Config.Ciphers +// +// Use comma as separator if multiple values. +// +// Example: +// export GO_GIT_SSH_CONFIG_CIPHERS="aes128-ctr,aes192-ctr" +// +// See golang.org/x/crypto/ssh for valid values. +const ENV_SSH_CONFIG_CIPHERS = "GO_GIT_SSH_CONFIG_CIPHERS" + +// ENV_SSH_CONFIG_MACS +// +// ssh.ClientConfig.Config.MACs +// +// Use comma as separator if multiple values. +// +// Example: +// export GO_GIT_SSH_CONFIG_MACS="hmac-sha2-256,hmac-sha1" +// +// See golang.org/x/crypto/ssh for valid values. +const ENV_SSH_CONFIG_MACS = "GO_GIT_SSH_CONFIG_MACS" + +// DefaultSSHClientConfig +// +// The following environment variables will be used if defined +// +// GO_GIT_SSH_HOSTKEY_ALGORITHMS +// GO_GIT_SSH_CONFIG_KEY_EXCHANGES +// GO_GIT_SSH_CONFIG_CIPHERS +// GO_GIT_SSH_CONFIG_MACS +// +var DefaultSSHClientConfig *ssh.ClientConfig = func() *ssh.ClientConfig { + sshClientConfig := &ssh.ClientConfig{} + + if hostKeyAlgorithms, isSet := os.LookupEnv(ENV_SSH_HOSTKEY_ALGORITHMS); isSet { + // TODO validation + sshClientConfig.HostKeyAlgorithms = strings.Split(hostKeyAlgorithms, ",") + } + if keyExchanges, isSet := os.LookupEnv(ENV_SSH_CONFIG_KEY_EXCHANGES); isSet { + // TODO validation + sshClientConfig.Config.KeyExchanges = strings.Split(keyExchanges, ",") + } + if ciphers, isSet := os.LookupEnv(ENV_SSH_CONFIG_CIPHERS); isSet { + // TODO validation + sshClientConfig.Config.Ciphers = strings.Split(ciphers, ",") + } + if MACs, isSet := os.LookupEnv(ENV_SSH_CONFIG_MACS); isSet { + // TODO validation + sshClientConfig.Config.MACs = strings.Split(MACs, ",") + } + + return sshClientConfig +}() + // NewClient creates a new SSH client with an optional *ssh.ClientConfig. func NewClient(config *ssh.ClientConfig) transport.Transport { return common.NewClient(&runner{config: config})