From b989cdabe5bfbbdfe422ce94056a2c97865a7955 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Fri, 25 Nov 2022 15:06:12 +0100 Subject: [PATCH] set version to 2.4.2 Signed-off-by: Nicola Murino --- Dockerfile | 3 +++ Dockerfile.alpine | 2 ++ Dockerfile.distroless | 3 ++- docker/README.md | 12 ++++++------ docs/full-configuration.md | 3 ++- go.mod | 6 +++--- go.sum | 9 ++++----- internal/config/config.go | 2 ++ internal/sftpd/internal_test.go | 24 ++++++++++++++++++++++++ internal/sftpd/server.go | 33 +++++++++++++++++++++++++++++++++ internal/sftpd/sftpd_test.go | 8 +++++++- internal/util/util.go | 12 ++++++++++++ internal/version/version.go | 2 +- openapi/openapi.yaml | 2 +- sftpgo.json | 1 + 15 files changed, 103 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84ef0822..6128d65b 100644 --- a/Dockerfile +++ b/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 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index a40b9dc4..6ab104b2 100644 --- a/Dockerfile.alpine +++ b/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 diff --git a/Dockerfile.distroless b/Dockerfile.distroless index 50d8baf9..92def6d8 100644 --- a/Dockerfile.distroless +++ b/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 diff --git a/docker/README.md b/docker/README.md index 08222e24..f271f6b4 100644 --- a/docker/README.md +++ b/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) diff --git a/docs/full-configuration.md b/docs/full-configuration.md index 645d8012..9a289da5 100644 --- a/docs/full-configuration.md +++ b/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. diff --git a/go.mod b/go.mod index 20b56b13..71809131 100644 --- a/go.mod +++ b/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 ) diff --git a/go.sum b/go.sum index b1ad55c1..2640cad7 100644 --- a/go.sum +++ b/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= diff --git a/internal/config/config.go b/internal/config/config.go index c3c45dd7..2b40895f 100644 --- a/internal/config/config.go +++ b/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) diff --git a/internal/sftpd/internal_test.go b/internal/sftpd/internal_test.go index 820a7a0d..6147b3f0 100644 --- a/internal/sftpd/internal_test.go +++ b/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{} diff --git a/internal/sftpd/server.go b/internal/sftpd/server.go index e4a65c10..430518db 100644 --- a/internal/sftpd/server.go +++ b/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 { diff --git a/internal/sftpd/sftpd_test.go b/internal/sftpd/sftpd_test.go index 7d41ae97..41695a8c 100644 --- a/internal/sftpd/sftpd_test.go +++ b/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) diff --git a/internal/util/util.go b/internal/util/util.go index 7f08be2e..5162e254 100644 --- a/internal/util/util.go +++ b/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 { diff --git a/internal/version/version.go b/internal/version/version.go index 6847f27b..75ee72b9 100644 --- a/internal/version/version.go +++ b/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 = "" diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 75c420d9..42529acb 100644 --- a/openapi/openapi.yaml +++ b/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' diff --git a/sftpgo.json b/sftpgo.json index 898d2598..ff16472e 100644 --- a/sftpgo.json +++ b/sftpgo.json @@ -84,6 +84,7 @@ "host_keys": [], "host_certificates": [], "host_key_algorithms": [], + "moduli": [], "kex_algorithms": [], "ciphers": [], "macs": [],