Repository: C2FO/vfs
Pull request #81 (2021-07-20 11:29:40)

Add support of key exchange algorithm as an option
fixes #81


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3dc1d0b..636cf08 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 ## [Unreleased]
+### Added
+- Add support of keyexchanges algorithm as a sftp option
+
 ## [5.6.0] - 2021-07-19
 ### Fixed
 - fixed #71 Listing a Google Cloud Storage bucket does not return things in the root of the bucket
diff --git a/backend/sftp/options.go b/backend/sftp/options.go
index 7015358..5937943 100644
--- a/backend/sftp/options.go
+++ b/backend/sftp/options.go
@@ -26,6 +26,7 @@ type Options struct {
 	KeyPassphrase      string              `json:"keyPassphrase,omitempty"`  // env var VFS_SFTP_KEYFILE_PASSPHRASE
 	KnownHostsFile     string              `json:"knownHostsFile,omitempty"` // env var VFS_SFTP_KNOWN_HOSTS_FILE
 	KnownHostsString   string              `json:"knownHostsString,omitempty"`
+	KeyExchanges       string              `json:"keyExchanges,omitempty"`
 	KnownHostsCallback ssh.HostKeyCallback // env var VFS_SFTP_INSECURE_KNOWN_HOSTS
 	Retry              vfs.Retry
 	MaxRetries         int
@@ -48,14 +49,23 @@ func getClient(authority utils.Authority, opts Options) (*_sftp.Client, error) {
 	if err != nil {
 		return nil, err
 	}
-
+	// To avoid ssh: handshake failed: ssh: no common algorithm for key exchange;
+	// client offered: [curve25519-sha256@libssh.org ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-	nistp521 diffie-hellman-group14-sha1],
+	// server offered: [diffie-hellman-group-exchange-sha256 ]
+	// Now receive KeyExchange algorithm as an option
+	sshConfig := ssh.Config{}
+	if opts.KeyExchanges != "" {
+		sshConfig = ssh.Config{
+			KeyExchanges: []string{opts.KeyExchanges},
+		}
+	}
 	// Define the Client Config
 	config := &ssh.ClientConfig{
 		User:            authority.User,
 		Auth:            authMethods,
 		HostKeyCallback: hostKeyCallback,
+		Config:          sshConfig,
 	}
-
 	// default to port 22
 	host := authority.Host
 	if !strings.Contains(host, ":") {
diff --git a/docs/sftp.md b/docs/sftp.md
index c01ef37..a6bf736 100644
--- a/docs/sftp.md
+++ b/docs/sftp.md
@@ -520,6 +520,7 @@ type Options struct {
 	KeyPassphrase      string              `json:"keyPassphrase,omitempty"`  // env var VFS_SFTP_KEYFILE_PASSPHRASE
 	KnownHostsFile     string              `json:"knownHostsFile,omitempty"` // env var VFS_SFTP_KNOWN_HOSTS_FILE
 	KnownHostsString   string              `json:"knownHostsString,omitempty"`
+	KeyExchanges       string              `json:"keyExchanges,omitempty"`
 	KnownHostsCallback ssh.HostKeyCallback //env var VFS_SFTP_INSECURE_KNOWN_HOSTS
 	Retry              vfs.Retry
 	MaxRetries         int


Test patch:
diff --git a/backend/sftp/options_test.go b/backend/sftp/options_test.go
index c37196e..0f03967 100644
--- a/backend/sftp/options_test.go
+++ b/backend/sftp/options_test.go
@@ -338,6 +338,7 @@ func (o *optionsSuite) TestGetAuthMethods() {
 				KeyFilePath:   o.keyFiles.SSHPrivateKey,
 				KeyPassphrase: o.keyFiles.passphrase,
 				Password:      "somepassword",
+				KeyExchanges:  "diffie-hellman-group-exchange-sha256",
 			},
 			returnCount: 2,
 			hasError:    false,