Browse Source

set version to 2.4.2

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
Nicola Murino 2 years ago
parent
commit
b989cdabe5

+ 3 - 0
Dockerfile

@@ -28,6 +28,8 @@ ARG DOWNLOAD_PLUGINS=false
 
 RUN if [ "${DOWNLOAD_PLUGINS}" = "true" ]; then apt-get update && apt-get install --no-install-recommends -y curl && ./docker/scripts/download-plugins.sh; fi
 
+RUN apt-get update && apt-get install --no-install-recommends -y openssh-server && rm -rf /var/lib/apt/lists/*
+
 FROM debian:bullseye-slim
 
 # Set to "true" to install jq and the optional git and rsync dependencies
@@ -45,6 +47,7 @@ RUN groupadd --system -g 1000 sftpgo && \
     --comment "SFTPGo user" --uid 1000 sftpgo
 
 COPY --from=builder /workspace/sftpgo.json /etc/sftpgo/sftpgo.json
+COPY --from=builder /etc/ssh/moduli /etc/sftpgo/moduli
 COPY --from=builder /workspace/templates /usr/share/sftpgo/templates
 COPY --from=builder /workspace/static /usr/share/sftpgo/static
 COPY --from=builder /workspace/openapi /usr/share/sftpgo/openapi

+ 2 - 0
Dockerfile.alpine

@@ -25,6 +25,7 @@ RUN set -xe && \
     export COMMIT_SHA=${COMMIT_SHA:-$(git describe --always --abbrev=8 --dirty)} && \
     go build $(if [ -n "${FEATURES}" ]; then echo "-tags ${FEATURES}"; fi) -trimpath -ldflags "-s -w -X github.com/drakkan/sftpgo/v2/internal/version.commit=${COMMIT_SHA} -X github.com/drakkan/sftpgo/v2/internal/version.date=`date -u +%FT%TZ`" -v -o sftpgo
 
+RUN apk add --update --no-cache openssh-client-common
 
 FROM alpine:3.16
 
@@ -41,6 +42,7 @@ RUN addgroup -g 1000 -S sftpgo && \
     adduser -u 1000 -h /var/lib/sftpgo -s /sbin/nologin -G sftpgo -S -D -H -g "SFTPGo user" sftpgo
 
 COPY --from=builder /workspace/sftpgo.json /etc/sftpgo/sftpgo.json
+COPY --from=builder /etc/ssh/moduli /etc/sftpgo/moduli
 COPY --from=builder /workspace/templates /usr/share/sftpgo/templates
 COPY --from=builder /workspace/static /usr/share/sftpgo/static
 COPY --from=builder /workspace/openapi /usr/share/sftpgo/openapi

+ 2 - 1
Dockerfile.distroless

@@ -28,7 +28,7 @@ RUN sed -i 's|"users_base_dir": "",|"users_base_dir": "/srv/sftpgo/data",|' sftp
     sed -i 's|"backups"|"/srv/sftpgo/backups"|' sftpgo.json && \
     sed -i 's|"sqlite"|"bolt"|' sftpgo.json
 
-RUN apt-get update && apt-get install --no-install-recommends -y media-types && rm -rf /var/lib/apt/lists/*
+RUN apt-get update && apt-get install --no-install-recommends -y media-types openssh-server && rm -rf /var/lib/apt/lists/*
 
 RUN mkdir /etc/sftpgo /var/lib/sftpgo /srv/sftpgo
 
@@ -38,6 +38,7 @@ COPY --from=builder --chown=1000:1000 /etc/sftpgo /etc/sftpgo
 COPY --from=builder --chown=1000:1000 /srv/sftpgo /srv/sftpgo
 COPY --from=builder --chown=1000:1000 /var/lib/sftpgo /var/lib/sftpgo
 COPY --from=builder --chown=1000:1000 /workspace/sftpgo.json /etc/sftpgo/sftpgo.json
+COPY --from=builder --chown=1000:1000 /etc/ssh/moduli /etc/sftpgo/moduli
 COPY --from=builder /workspace/templates /usr/share/sftpgo/templates
 COPY --from=builder /workspace/static /usr/share/sftpgo/static
 COPY --from=builder /workspace/openapi /usr/share/sftpgo/openapi

+ 6 - 6
docker/README.md

@@ -4,12 +4,12 @@ SFTPGo provides an official Docker image, it is available on both [Docker Hub](h
 
 ## Supported tags and respective Dockerfile links
 
-- [v2.4.1, v2.4, v2, latest](https://github.com/drakkan/sftpgo/blob/v2.4.1/Dockerfile)
-- [v2.4.1-plugins, v2.4-plugins, v2-plugins, plugins](https://github.com/drakkan/sftpgo/blob/v2.4.1/Dockerfile)
-- [v2.4.1-alpine, v2.4-alpine, v2-alpine, alpine](https://github.com/drakkan/sftpgo/blob/v2.4.1/Dockerfile.alpine)
-- [v2.4.1-slim, v2.4-slim, v2-slim, slim](https://github.com/drakkan/sftpgo/blob/v2.4.1/Dockerfile)
-- [v2.4.1-alpine-slim, v2.4-alpine-slim, v2-alpine-slim, alpine-slim](https://github.com/drakkan/sftpgo/blob/v2.4.1/Dockerfile.alpine)
-- [v2.4.1-distroless-slim, v2.4-distroless-slim, v2-distroless-slim, distroless-slim](https://github.com/drakkan/sftpgo/blob/v2.4.1/Dockerfile.distroless)
+- [v2.4.2, v2.4, v2, latest](https://github.com/drakkan/sftpgo/blob/v2.4.2/Dockerfile)
+- [v2.4.2-plugins, v2.4-plugins, v2-plugins, plugins](https://github.com/drakkan/sftpgo/blob/v2.4.2/Dockerfile)
+- [v2.4.2-alpine, v2.4-alpine, v2-alpine, alpine](https://github.com/drakkan/sftpgo/blob/v2.4.2/Dockerfile.alpine)
+- [v2.4.2-slim, v2.4-slim, v2-slim, slim](https://github.com/drakkan/sftpgo/blob/v2.4.2/Dockerfile)
+- [v2.4.2-alpine-slim, v2.4-alpine-slim, v2-alpine-slim, alpine-slim](https://github.com/drakkan/sftpgo/blob/v2.4.2/Dockerfile.alpine)
+- [v2.4.2-distroless-slim, v2.4-distroless-slim, v2-distroless-slim, distroless-slim](https://github.com/drakkan/sftpgo/blob/v2.4.2/Dockerfile.distroless)
 - [edge](../Dockerfile)
 - [edge-plugins](../Dockerfile)
 - [edge-alpine](../Dockerfile.alpine)

+ 2 - 1
docs/full-configuration.md

@@ -129,7 +129,8 @@ The configuration file contains the following sections:
   - `host_keys`, list of strings. It contains the daemon's private host keys. Each host key can be defined as a path relative to the configuration directory or an absolute one. If empty, the daemon will search or try to generate `id_rsa`, `id_ecdsa` and `id_ed25519` keys inside the configuration directory. If you configure absolute paths to files named `id_rsa`, `id_ecdsa` and/or `id_ed25519` then SFTPGo will try to generate these keys using the default settings.
   - `host_certificates`, list of strings. Public host certificates. Each certificate can be defined as a path relative to the configuration directory or an absolute one. Certificate's public key must match a private host key otherwise it will be silently ignored. Default: empty.
   - `host_key_algorithms`, list of strings. Public key algorithms that the server will accept for host key authentication. The supported values are: `rsa-sha2-512-cert-v01@openssh.com`, `rsa-sha2-256-cert-v01@openssh.com`, `ssh-rsa-cert-v01@openssh.com`, `ssh-dss-cert-v01@openssh.com`, `ecdsa-sha2-nistp256-cert-v01@openssh.com`, `ecdsa-sha2-nistp384-cert-v01@openssh.com`, `ecdsa-sha2-nistp521-cert-v01@openssh.com`, `ssh-ed25519-cert-v01@openssh.com`, `ecdsa-sha2-nistp256`, `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521`, `rsa-sha2-512`, `rsa-sha2-256`, `ssh-rsa`, `ssh-dss`, `ssh-ed25519`. Default values: `rsa-sha2-512-cert-v01@openssh.com`, `rsa-sha2-256-cert-v01@openssh.com`, `ecdsa-sha2-nistp256-cert-v01@openssh.com`, `ecdsa-sha2-nistp384-cert-v01@openssh.com`, `ecdsa-sha2-nistp521-cert-v01@openssh.com`, `ssh-ed25519-cert-v01@openssh.com`, `ecdsa-sha2-nistp256`, `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521`, `rsa-sha2-512`, `rsa-sha2-256`, `ssh-ed25519`.
-  - `kex_algorithms`, list of strings. Available KEX (Key Exchange) algorithms in preference order. Leave empty to use default values. The supported values are: `curve25519-sha256`, `curve25519-sha256@libssh.org`, `ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521`, `diffie-hellman-group14-sha256`, `diffie-hellman-group16-sha512`, `diffie-hellman-group18-sha512`, `diffie-hellman-group14-sha1`, `diffie-hellman-group1-sha1`. Default values: `curve25519-sha256`, `curve25519-sha256@libssh.org`, `ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521`, `diffie-hellman-group14-sha256`. SHA512 based KEXs are disabled by default because they are slow.
+  - `moduli`, list of strings. Diffie-Hellman moduli files. Each moduli file can be defined as a path relative to the configuration directory or an absolute one. If set, `diffie-hellman-group-exchange-sha256` and `diffie-hellman-group-exchange-sha1` KEX algorithms will be available, `diffie-hellman-group-exchange-sha256` will be enabled by default if you don't explicitly set KEXs. Default: empty.
+  - `kex_algorithms`, list of strings. Available KEX (Key Exchange) algorithms in preference order. Leave empty to use default values. The supported values are: `curve25519-sha256`, `curve25519-sha256@libssh.org`, `ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521`, `diffie-hellman-group14-sha256`, `diffie-hellman-group16-sha512`, `diffie-hellman-group18-sha512`, `diffie-hellman-group14-sha1`, `diffie-hellman-group1-sha1`. Default values: `curve25519-sha256`, `curve25519-sha256@libssh.org`, `ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521`, `diffie-hellman-group14-sha256`. SHA512 based KEXs are disabled by default because they are slow. If you set one or more moduli files,  `diffie-hellman-group-exchange-sha256` and `diffie-hellman-group-exchange-sha1` will be available.
   - `ciphers`, list of strings. Allowed ciphers in preference order. Leave empty to use default values. The supported values are: `aes128-gcm@openssh.com`, `aes256-gcm@openssh.com`, `chacha20-poly1305@openssh.com`, `aes128-ctr`, `aes192-ctr`, `aes256-ctr`, `aes128-cbc`, `aes192-cbc`, `aes256-cbc`, `3des-cbc`, `arcfour256`, `arcfour128`, `arcfour`. Default values: `aes128-gcm@openssh.com`, `aes256-gcm@openssh.com`, `chacha20-poly1305@openssh.com`, `aes128-ctr`, `aes192-ctr`, `aes256-ctr`. Please note that the ciphers disabled by default are insecure, you should expect that an active attacker can recover plaintext if you enable them.
   - `macs`, list of strings. Available MAC (message authentication code) algorithms in preference order. Leave empty to use default values. The supported values are: `hmac-sha2-256-etm@openssh.com`, `hmac-sha2-256`, `hmac-sha2-512-etm@openssh.com`, `hmac-sha2-512`, `hmac-sha1`, `hmac-sha1-96`. Default values: `hmac-sha2-256-etm@openssh.com`, `hmac-sha2-256`.
   - `trusted_user_ca_keys`, list of public keys paths of certificate authorities that are trusted to sign user certificates for authentication. The paths can be absolute or relative to the configuration directory.

+ 3 - 3
go.mod

@@ -38,7 +38,7 @@ require (
 	github.com/jackc/pgx/v5 v5.1.1
 	github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
 	github.com/klauspost/compress v1.15.12
-	github.com/lestrrat-go/jwx/v2 v2.0.7
+	github.com/lestrrat-go/jwx/v2 v2.0.8
 	github.com/lithammer/shortuuid/v3 v3.0.7
 	github.com/mattn/go-sqlite3 v1.14.16
 	github.com/mhale/smtpd v0.8.0
@@ -67,7 +67,7 @@ require (
 	go.etcd.io/bbolt v1.3.6
 	go.uber.org/automaxprocs v1.5.1
 	gocloud.dev v0.27.0
-	golang.org/x/crypto v0.2.0
+	golang.org/x/crypto v0.3.0
 	golang.org/x/net v0.2.0
 	golang.org/x/oauth2 v0.2.0
 	golang.org/x/sys v0.2.0
@@ -171,5 +171,5 @@ require (
 
 replace (
 	github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
-	golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20221112084010-a38283b153a8
+	golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20221117111000-a0321143587c
 )

+ 4 - 5
go.sum

@@ -538,8 +538,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
 github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
 github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/drakkan/crypto v0.0.0-20221112084010-a38283b153a8 h1:rekJXGgV8dSNaa4KjmT13kVU0GzBiyY11OATlGdiv3w=
-github.com/drakkan/crypto v0.0.0-20221112084010-a38283b153a8/go.mod h1:2ZkovGk6CT8C9CeXH8XzRpGVYQ+H5+/upg2lTOkgblk=
+github.com/drakkan/crypto v0.0.0-20221117111000-a0321143587c h1:3lJRXQcGw8fnheQ9ORGYE17JLuYzu6FkDuK8MZwqeRQ=
+github.com/drakkan/crypto v0.0.0-20221117111000-a0321143587c/go.mod h1:z/3TjBrBT/Dch7NfsgFg7f07WiGYZVYQgnxGHacCvRc=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
 github.com/drakkan/webdav v0.0.0-20221101181759-17ed21f9337b h1:B9z7XyDoVxLO4yEvnXgdvZ+0Uw9NA1qdD4KTSGmKcoQ=
@@ -1063,7 +1063,6 @@ github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
 github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
 github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 github.com/klauspost/cpuid/v2 v2.2.1 h1:U33DW0aiEj633gHYw3LoDNfkDiYnE5Q8M/TKJn2f2jI=
 github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
@@ -1096,8 +1095,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG
 github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
 github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
 github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
-github.com/lestrrat-go/jwx/v2 v2.0.7 h1:vNh7cA5pKS/1muWYpM1GeUHBCf/r1UFxYN60iv7LFRA=
-github.com/lestrrat-go/jwx/v2 v2.0.7/go.mod h1:zLxnyv9rTlEvOUHbc48FAfIL8iYu2hHvIRaTFGc8mT0=
+github.com/lestrrat-go/jwx/v2 v2.0.8 h1:jCFT8oc0hEDVjgUgsBy1F9cbjsjAVZSXNi7JaU9HR/Q=
+github.com/lestrrat-go/jwx/v2 v2.0.8/go.mod h1:zLxnyv9rTlEvOUHbc48FAfIL8iYu2hHvIRaTFGc8mT0=
 github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=

+ 2 - 0
internal/config/config.go

@@ -253,6 +253,7 @@ func Init() {
 			HostKeys:                          []string{},
 			HostCertificates:                  []string{},
 			HostKeyAlgorithms:                 []string{},
+			Moduli:                            []string{},
 			KexAlgorithms:                     []string{},
 			Ciphers:                           []string{},
 			MACs:                              []string{},
@@ -1961,6 +1962,7 @@ func setViperDefaults() {
 	viper.SetDefault("sftpd.host_keys", globalConf.SFTPD.HostKeys)
 	viper.SetDefault("sftpd.host_certificates", globalConf.SFTPD.HostCertificates)
 	viper.SetDefault("sftpd.host_key_algorithms", globalConf.SFTPD.HostKeyAlgorithms)
+	viper.SetDefault("sftpd.moduli", globalConf.SFTPD.Moduli)
 	viper.SetDefault("sftpd.kex_algorithms", globalConf.SFTPD.KexAlgorithms)
 	viper.SetDefault("sftpd.ciphers", globalConf.SFTPD.Ciphers)
 	viper.SetDefault("sftpd.macs", globalConf.SFTPD.MACs)

+ 24 - 0
internal/sftpd/internal_test.go

@@ -1926,6 +1926,30 @@ func TestSupportedSecurityOptions(t *testing.T) {
 	assert.Equal(t, supportedKexAlgos, serverConfig.KeyExchanges)
 }
 
+func TestLoadModuli(t *testing.T) {
+	dhGEXSha1 := "diffie-hellman-group-exchange-sha1"
+	dhGEXSha256 := "diffie-hellman-group-exchange-sha256"
+	c := Configuration{}
+	c.Moduli = []string{".", "missing file"}
+	err := c.loadModuli(configDir)
+	assert.Error(t, err)
+	assert.NotContains(t, supportedKexAlgos, dhGEXSha1)
+	assert.NotContains(t, supportedKexAlgos, dhGEXSha256)
+	assert.Len(t, supportedKexAlgos, 10)
+	moduli := []byte("20220414072358 2 6 100 2047 5 F19C2D09AD49978F8A0C1B84168A4011A26F9CD516815934764A319FDC5975FA514AAF11B747D8CA6B3919532BEFB68FA118079473895674F3770F71FBB742F176883841EB3DE679BEF53C6AFE437A662F228B03C1E34B5A0D3909F608CEAA16C1F8131DE11E67878EFD918A89205E5E4DE323054010CA4711F25D466BB7727A016DD3F9F53BDBCE093055A4F2497ADEFB5A2500F9C5C3B0BCD88C6489F4C1CBC7CFB67BA6EABA0195794E4188CE9060F431041AD52FB9BAC4DF7FA536F585FBE67746CD57BFAD67567E9706C24D95C49BE95B759657C6BB5151E2AEA32F4CD557C40298A5C402101520EE8AAB8DFEED6FFC11AAF8036D6345923CFB5D1B922F")
+	moduliFile := filepath.Join(os.TempDir(), "moduli")
+	err = os.WriteFile(moduliFile, moduli, 0600)
+	assert.NoError(t, err)
+	c.Moduli = []string{moduliFile}
+	err = c.loadModuli(configDir)
+	assert.NoError(t, err)
+	assert.Contains(t, supportedKexAlgos, dhGEXSha1)
+	assert.Contains(t, supportedKexAlgos, dhGEXSha256)
+	assert.Len(t, supportedKexAlgos, 12)
+	err = os.Remove(moduliFile)
+	assert.NoError(t, err)
+}
+
 func TestLoadHostKeys(t *testing.T) {
 	serverConfig := &ssh.ServerConfig{}
 	c := Configuration{}

+ 33 - 0
internal/sftpd/server.go

@@ -141,6 +141,12 @@ type Configuration struct {
 	// HostKeyAlgorithms lists the public key algorithms that the server will accept for host
 	// key authentication.
 	HostKeyAlgorithms []string `json:"host_key_algorithms" mapstructure:"host_key_algorithms"`
+	// Diffie-Hellman moduli files.
+	// Each moduli file can be defined as a path relative to the configuration directory or an absolute one.
+	// If set, "diffie-hellman-group-exchange-sha256" and "diffie-hellman-group-exchange-sha1" KEX algorithms
+	// will be available, `diffie-hellman-group-exchange-sha256` will be enabled by default if you
+	// don't explicitly set KEXs
+	Moduli []string `json:"moduli" mapstructure:"moduli"`
 	// KexAlgorithms specifies the available KEX (Key Exchange) algorithms in
 	// preference order.
 	KexAlgorithms []string `json:"kex_algorithms" mapstructure:"kex_algorithms"`
@@ -294,6 +300,10 @@ func (c *Configuration) Initialize(configDir string) error {
 		return err
 	}
 
+	if err := c.loadModuli(configDir); err != nil {
+		return err
+	}
+
 	sftp.SetSFTPExtensions(sftpExtensions...) //nolint:errcheck // we configure valid SFTP Extensions so we cannot get an error
 
 	if err := c.configureSecurityOptions(serverConfig); err != nil {
@@ -840,6 +850,29 @@ func (c *Configuration) checkHostKeyAutoGeneration(configDir string) error {
 	return nil
 }
 
+func (c *Configuration) loadModuli(configDir string) error {
+	supportedKexAlgos = util.Remove(supportedKexAlgos, "diffie-hellman-group-exchange-sha1")
+	supportedKexAlgos = util.Remove(supportedKexAlgos, "diffie-hellman-group-exchange-sha256")
+	for _, m := range c.Moduli {
+		m = strings.TrimSpace(m)
+		if !util.IsFileInputValid(m) {
+			logger.Warn(logSender, "", "unable to load invalid moduli file %q", m)
+			logger.WarnToConsole("unable to load invalid host moduli file %q", m)
+			continue
+		}
+		if !filepath.IsAbs(m) {
+			m = filepath.Join(configDir, m)
+		}
+		logger.Info(logSender, "", "loading moduli file %q", m)
+		if err := ssh.ParseModuli(m); err != nil {
+			return err
+		}
+		supportedKexAlgos = append(supportedKexAlgos, "diffie-hellman-group-exchange-sha1",
+			"diffie-hellman-group-exchange-sha256")
+	}
+	return nil
+}
+
 // If no host keys are defined we try to use or generate the default ones.
 func (c *Configuration) checkAndLoadHostKeys(configDir string, serverConfig *ssh.ServerConfig) error {
 	if err := c.checkHostKeyAutoGeneration(configDir); err != nil {

+ 7 - 1
internal/sftpd/sftpd_test.go

@@ -182,7 +182,7 @@ func TestMain(m *testing.M) {
 	logFilePath = filepath.Join(configDir, "sftpgo_sftpd_test.log")
 	loginBannerFileName := "login_banner"
 	loginBannerFile := filepath.Join(configDir, loginBannerFileName)
-	logger.InitLogger(logFilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
+	logger.InitLogger(logFilePath, 10, 1, 28, false, false, zerolog.DebugLevel)
 	err := os.WriteFile(loginBannerFile, []byte("simple login banner\n"), os.ModePerm)
 	if err != nil {
 		logger.ErrorToConsole("error creating login banner: %v", err)
@@ -401,6 +401,12 @@ func TestInitialization(t *testing.T) {
 	assert.True(t, sftpdConf.Bindings[0].HasProxy())
 	err = sftpdConf.Initialize(configDir)
 	assert.Error(t, err)
+	sftpdConf.Moduli = []string{"missing moduli file"}
+	err = sftpdConf.Initialize(configDir)
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "unable to open moduli file")
+	}
+	sftpdConf.Moduli = nil
 	sftpdConf.HostKeys = []string{"missing key"}
 	err = sftpdConf.Initialize(configDir)
 	assert.Error(t, err)

+ 12 - 0
internal/util/util.go

@@ -125,6 +125,18 @@ func Contains[T comparable](elems []T, v T) bool {
 	return false
 }
 
+// Remove removes an element from a string slice and
+// returns the modified slice
+func Remove(elems []string, val string) []string {
+	for idx, v := range elems {
+		if v == val {
+			elems[idx] = elems[len(elems)-1]
+			return elems[:len(elems)-1]
+		}
+	}
+	return elems
+}
+
 // IsStringPrefixInSlice searches a string prefix in a slice and returns true
 // if a matching prefix is found
 func IsStringPrefixInSlice(obj string, list []string) bool {

+ 1 - 1
internal/version/version.go

@@ -17,7 +17,7 @@ package version
 
 import "strings"
 
-const version = "2.4.1-dev"
+const version = "2.4.2"
 
 var (
 	commit = ""

+ 1 - 1
openapi/openapi.yaml

@@ -27,7 +27,7 @@ info:
     SFTPGo supports groups to simplify the administration of multiple accounts by letting you assign settings once to a group, instead of multiple times to each individual user.
     The SFTPGo WebClient allows end users to change their credentials, browse and manage their files in the browser and setup two-factor authentication which works with Authy, Google Authenticator and other compatible apps.
     From the WebClient each authorized user can also create HTTP/S links to externally share files and folders securely, by setting limits to the number of downloads/uploads, protecting the share with a password, limiting access by source IP address, setting an automatic expiration date.
-  version: 2.4.1-dev
+  version: 2.4.2
   contact:
     name: API support
     url: 'https://github.com/drakkan/sftpgo'

+ 1 - 0
sftpgo.json

@@ -84,6 +84,7 @@
     "host_keys": [],
     "host_certificates": [],
     "host_key_algorithms": [],
+    "moduli": [],
     "kex_algorithms": [],
     "ciphers": [],
     "macs": [],