mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-21 23:20:24 +00:00
ftpd: add support for TLS session reuse
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
de35eb77cb
commit
62b87083bb
10 changed files with 247 additions and 80 deletions
|
@ -164,6 +164,7 @@ The configuration file contains the following sections:
|
||||||
- `address`, string. Leave blank to listen on all available network interfaces. Default: "".
|
- `address`, string. Leave blank to listen on all available network interfaces. Default: "".
|
||||||
- `apply_proxy_config`, boolean. If enabled the common proxy configuration, if any, will be applied. Please note that we expect the proxy header on control and data connections. Default `true`.
|
- `apply_proxy_config`, boolean. If enabled the common proxy configuration, if any, will be applied. Please note that we expect the proxy header on control and data connections. Default `true`.
|
||||||
- `tls_mode`, integer. 0 means accept both cleartext and encrypted sessions. 1 means TLS is required for both control and data connection. 2 means implicit TLS. Do not enable this blindly, please check that a proper TLS config is in place if you set `tls_mode` is different from 0.
|
- `tls_mode`, integer. 0 means accept both cleartext and encrypted sessions. 1 means TLS is required for both control and data connection. 2 means implicit TLS. Do not enable this blindly, please check that a proper TLS config is in place if you set `tls_mode` is different from 0.
|
||||||
|
- `tls_session_reuse`, integer. 0 means session reuse is not checked, clients may or may not resume TLS sessions. 1 means TLS session reuse is required for explicit FTPS. Not supported for implicit TLS. Default: `0`.
|
||||||
- `certificate_file`, string. Binding specific TLS certificate. This can be an absolute path or a path relative to the config dir.
|
- `certificate_file`, string. Binding specific TLS certificate. This can be an absolute path or a path relative to the config dir.
|
||||||
- `certificate_key_file`, string. Binding specific private key matching the above certificate. This can be an absolute path or a path relative to the config dir. If not set the global ones will be used, if any.
|
- `certificate_key_file`, string. Binding specific private key matching the above certificate. This can be an absolute path or a path relative to the config dir. If not set the global ones will be used, if any.
|
||||||
- `min_tls_version`, integer. Defines the minimum version of TLS to be enabled. `12` means TLS 1.2 (and therefore TLS 1.2 and TLS 1.3 will be enabled),`13` means TLS 1.3. Default: `12`.
|
- `min_tls_version`, integer. Defines the minimum version of TLS to be enabled. `12` means TLS 1.2 (and therefore TLS 1.2 and TLS 1.3 will be enabled),`13` means TLS 1.3. Default: `12`.
|
||||||
|
|
44
go.mod
44
go.mod
|
@ -9,15 +9,15 @@ require (
|
||||||
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5
|
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5
|
||||||
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
|
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
|
||||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964
|
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964
|
||||||
github.com/aws/aws-sdk-go-v2 v1.20.2
|
github.com/aws/aws-sdk-go-v2 v1.20.3
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.34
|
github.com/aws/aws-sdk-go-v2/config v1.18.35
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.33
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.34
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.9
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.10
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.78
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.79
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.3
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.4
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.3
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.4
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.1
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.2
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.3
|
github.com/aws/aws-sdk-go-v2/service/sts v1.21.4
|
||||||
github.com/bmatcuk/doublestar/v4 v4.6.0
|
github.com/bmatcuk/doublestar/v4 v4.6.0
|
||||||
github.com/cockroachdb/cockroach-go/v2 v2.3.5
|
github.com/cockroachdb/cockroach-go/v2 v2.3.5
|
||||||
github.com/coreos/go-oidc/v3 v3.6.0
|
github.com/coreos/go-oidc/v3 v3.6.0
|
||||||
|
@ -85,18 +85,18 @@ require (
|
||||||
cloud.google.com/go/iam v1.1.2 // indirect
|
cloud.google.com/go/iam v1.1.2 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
|
||||||
github.com/ajg/form v1.5.1 // indirect
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.39 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.40 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.33 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.40 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.41 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.2 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.34 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.35 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.33 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.13.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.13.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.4 // indirect
|
||||||
github.com/aws/smithy-go v1.14.1 // indirect
|
github.com/aws/smithy-go v1.14.2 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1 // indirect
|
github.com/boombuler/barcode v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||||
|
@ -172,7 +172,7 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20230818123055-c8426c7a1b8d
|
github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20230820134433-b2a9de7897b3
|
||||||
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
|
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
|
||||||
github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0
|
github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0
|
||||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8
|
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8
|
||||||
|
|
88
go.sum
88
go.sum
|
@ -72,48 +72,48 @@ github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736/go.mod h1:mTe
|
||||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 h1:I9YN9WMo3SUh7p/4wKeNvD/IQla3U3SUa61U7ul+xM4=
|
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 h1:I9YN9WMo3SUh7p/4wKeNvD/IQla3U3SUa61U7ul+xM4=
|
||||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k=
|
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.20.2 h1:0Aok9u/HVTk7RtY6M1KDcthbaMKGhhS0eLPxIdSIzRI=
|
github.com/aws/aws-sdk-go-v2 v1.20.3 h1:lgeKmAZhlj1JqN43bogrM75spIvYnRxqTAh1iupu1yE=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.20.2/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac=
|
github.com/aws/aws-sdk-go-v2 v1.20.3/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 h1:lN6L3LrYHeZ6xCxaIYtoWCx4GMLk4nRknsh29OMSqHY=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12/go.mod h1:TDCkEAkMTXxTs0oLBGBKpBZbk3NLh8EvAfF0Q3x8/0c=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13/go.mod h1:gpAbvyDGQFozTEmlTFO8XcQKHzubdq0LzRyJpG6MiXM=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.34 h1:bFf7CtSgwz/vE4tl0cNbWbf6EDQ2TZR5VrsrO9ardoY=
|
github.com/aws/aws-sdk-go-v2/config v1.18.35 h1:uU9rgCzrW/pVRUUlRULiwKQe8RoEDst1NQu4Qo8kOtk=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.34/go.mod h1:uJ/keVhwR8vsSaErMu2Vb3dArUZZKLVTcOsKXIFfvjs=
|
github.com/aws/aws-sdk-go-v2/config v1.18.35/go.mod h1:7xF1yr9GBMfYRQI4PLHO8iceqKLM6DpGVEvXI38HB/A=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.33 h1:esA1X5Eti1xSGCF0W0LYpHH/r6p+MqT0DiKXsfDEPxs=
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.34 h1:/EYG4lzayDd5PY6HQQ2Qyj/cD6CR3kz96BjTZAO5tNo=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.33/go.mod h1:jNC10ZEYuLlt9IOowix60yNiO6vGA14RVK3oUfX5KgI=
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.34/go.mod h1:+wgdxCGNulHme6kTMZuDL9KOagLPloemoYkfjpQkSEU=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.9 h1:DnNHcClgyFV5suHJ4axqhmG3YeRGgIu6yv29IEWR9aE=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.10 h1:mgOrtwYfJZ4e3QJe1TrliC/xIkauafGMdLLuCExOqcs=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.9/go.mod h1:kz0hzQXlc/5Y5mkbwTKX8A+aTRA45t8Aavly60bQzAQ=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.10/go.mod h1:wMsSLVM2hRpDVhd+3dtLUzqwm7/fjuhNN+b1aOLDt6g=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.78 h1:yKlVjl84XK9IshIDplZCUaqwK6jvpQ/h1dQwrzMwZj0=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.79 h1:Lc2K7rBQlWnY+HB3cNrz/zpEF+ncyn//iJ6gpi5vfR4=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.78/go.mod h1:IIZC114y2/TZCDCczXrq2bL2nLDUtLqjEFT7zurX8kA=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.79/go.mod h1:NpiOzmnVgrRfF/ZbqShAsisq5/6DWYEG2QqHnsdUnbE=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.39 h1:OBokd2jreL7ItwqRRcN5QiSt24/i2r742aRsd2qMyeg=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.40 h1:CXceCS9BrDInRc74GDCQ8Qyk/Gp9VLdK+Rlve+zELSE=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.39/go.mod h1:OLmjwglQh90dCcFJDGD+T44G0ToLH+696kRwRhS1KOU=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.40/go.mod h1:5kKmFhLeOVy6pwPDpDNA6/hK/d6URC98pqDDqHgdBx4=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.33 h1:gcRN6PXAo8w3HYFp2wFyr+WYEP4n/a25/IOhzJl36Yw=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.34 h1:B+nZtd22cbko5+793hg7LEaTeLMiZwlgCLUrN5Y0uzg=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.33/go.mod h1:S/zgOphghZAIvrbtvsVycoOncfqh1Hc4uGDIHqDLwTU=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.34/go.mod h1:RZP0scceAyhMIQ9JvFp7HvkpcgqjL4l/4C+7RAeGbuM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.40 h1:glWaI8WyeYqQN4zh4zqogzSpNPj8rf11Nj+oE3ghQPw=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.41 h1:EcSFdpLdkF3FWizimox0qYLuorn9e4PNMR27mvshGLs=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.40/go.mod h1:OCnFHzgaBY2PuGiHSzLlfqV4j5rJrky7YMfBXcx2Uk0=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.41/go.mod h1:mKxUXW+TuwpCKKHVlmHGVVuBi9y9LKW8AiQodg23M5E=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.2 h1:9Np6KOCKYnjMwJd1/17ReLdN21gnloI80LNP3uCKk44=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.3 h1:uHhWcrNBgpm9gi3o8NSQcsAqha/U9OFYzi2k4+0UVz8=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.2/go.mod h1:0YZJZKZCSSbQYQrXpqv0DpIaOMcZ27+OHFaSJTmN+8o=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.3/go.mod h1:jYLMm3Dh0wbeV3lxth5ryks/O2M/omVXWyYm3YcEVqQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 h1:iV/W5OMBys+66OeXJi/7xIRrKZNsu0ylsLGu+6nbmQE=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 h1:m0QTSI6pZYJTk5WSKx3fm5cNW/DCicVzULBgU/6IyD0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13/go.mod h1:ReJb6xYmtGyu9KoFtRreWegbN9dZqvZIIv4vWnhcsyI=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14/go.mod h1:dDilntgHy9WnHXsh7dDtUPgHKEfTJIBUTHM8OWm0f/0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.34 h1:gQE3p36iC+wwf/hDaCw+tNVXmNxDUehqv5nAvnoG+yc=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.35 h1:oCUrlTzh9GwhlYdyDGNAS6UgqJRzJp5rKoYCJWqLyZI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.34/go.mod h1:swEfojiNWdgJaOTNT65+XsMclEx4k/tyzBAVEi0Y6vM=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.35/go.mod h1:YVHrksq36j0sbXCT6rSuQafpfYkMYqy0QTk7JTCTBIU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.33 h1:cr70Hw6Lq9cqRst1y4YOHLiaVWaWtBPiqdloinNkfis=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.34 h1:JwvXk+1ePAD9xkFHprhHYqwsxLDcbNFsPI1IAT2sPS0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.33/go.mod h1:kcNtzCcEoflp+6e2CDTmm2h3xQGZOBZqYA/8DhYx/S8=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.34/go.mod h1:ytsF+t+FApY2lFnN51fJKPhH6ICKOPXKEcwwgmJEdWI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.2 h1:M5vGdcDO+jUGWu7d4BXwcLRXp3UikWXAiCfQI20rqFQ=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.3 h1:rPDAISw3FjEhrJoaxmQjuD+GgBfv2p3AVhmAcnyqq3k=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.2/go.mod h1:bC2B9AS4ygwMNrefck3XeD6YwXeplWhY6Z2UtlGjv1s=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.3/go.mod h1:TXBww3ANB+QRj+/dUoYDvI8d/u4F4WzTxD4mxtDoxrg=
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.3 h1:NnDCBIRlYtreJIuK0PfqpvgPc3aYHpp2dFnxWxAfzUE=
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.4 h1:/AyMci1EGQIRzUPgXHkLmxUTDEmyBV+kSk/RWi94UKk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.3/go.mod h1:h2345n5Sc82zNIm7XItORbqv44cBx+di6gS7gpZG9OU=
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.4/go.mod h1:qQqwZdFSIOyDh/4I16LMDA/c5N4xBxQnynpIU6qzxpE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.3 h1:yWclTL4cyiqLBWSjxDJ1tjiIzP4x4Kp85aAUtKSbtwA=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.4 h1:P4p346B+YMTTCH9D4I/FWYl+E7BjSLQxqk1e2KYDI5w=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.3/go.mod h1:yER+u7+gwH6dXy5xRTC2OfoHpYY1BFRiS0SF5iamO6M=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.4/go.mod h1:uDxTlJiuPhbtRRPMHrPYRkn1Ck7Mtk3BEJiDut+gR5Y=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.1 h1:JBrOoTb1gfm4EhlwbMigvLRgOHgouSyQFRbOVQWn3wU=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.2 h1:6N4VK/eLcMYonOqGgihkYlgjE2URxEMqjjS/1zErTKA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.1/go.mod h1:fYrcZAwlCzBXN7+5RiJlokZbdIbEsEjwonLyPZQGVGg=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.21.2/go.mod h1:aYWGu8cQcyRdfDi/V4agl6VDmDz2N42VhiHj0xMf77o=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.13.3 h1:nceOkYE0jmaG9CoyXHJJm00FAQ8JE+/LCKJJ06hH/Nc=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.13.4 h1:WZPZ7Zf6Yo13lsfTetFrLU/7hZ9CXESDpdIHvmLxQFQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.13.3/go.mod h1:DApEBnZzexe+LDLaNrGOJA8xtRMCpikLW1gX7jZhHxc=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.13.4/go.mod h1:FP05hDXTLouXwAMQ1swqybHy7tHySblMkBMKSumaKg0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.3 h1:90qW9puxI7LgmiYKSPhx6wz4XqgVauTxCyS3185+JpA=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.4 h1:pYFM2U/3/4RLrlMSYXwL1XPBCWvaePk2p+0+i/BgHOs=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.3/go.mod h1:kKpyLjToIS7E3z0672lBhxIPD+uoQ9V0MYRYCVGIkO0=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.4/go.mod h1:4pdlNASc29u0j9bq2jIQcBghG5Lx2oQAIj91vo1u1t8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.3 h1:s3wBkMxfA/u2EJJl6KRsPcWv858lDHkhinqXyN6fkZI=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.21.4 h1:zj4jxK3L54tGyqKleKDMK4vHolENxlq11dF0v1oBkJo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.3/go.mod h1:b+y9zL57mwCRy6ftp9Nc7CONGHX3sZ50ZCLTrI5xpCc=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.21.4/go.mod h1:CQRMCzYvl5eeAQW3AWkRLS+zGGXCucBnsiQlrs+tCeo=
|
||||||
github.com/aws/smithy-go v1.14.1 h1:EFKMUmH/iHMqLiwoEDx2rRjRQpI1YCn5jTysoaDujFs=
|
github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ=
|
||||||
github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
|
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
|
||||||
|
@ -160,8 +160,8 @@ github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8 h1:TUieQf6mz4xlWJav
|
||||||
github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8/go.mod h1:jjOR8ZXZPvxgpYUhVmAtGUCuD1OFc5Hq984QRL686so=
|
github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8/go.mod h1:jjOR8ZXZPvxgpYUhVmAtGUCuD1OFc5Hq984QRL686so=
|
||||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
|
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/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||||
github.com/drakkan/ftpserverlib v0.0.0-20230818123055-c8426c7a1b8d h1:WcXXDwXoVS85iFI6nCugkkMZqvU9Hb4GAa6MErVlaxY=
|
github.com/drakkan/ftpserverlib v0.0.0-20230820134433-b2a9de7897b3 h1:z1XhTv2fAIkd0/T6NtYwW78iZWxwZclBPXcqiQnUELw=
|
||||||
github.com/drakkan/ftpserverlib v0.0.0-20230818123055-c8426c7a1b8d/go.mod h1:dI9/yw/KfJ0g4wmRK8ZukUfqakLr6ZTf9VDydKoLy90=
|
github.com/drakkan/ftpserverlib v0.0.0-20230820134433-b2a9de7897b3/go.mod h1:dI9/yw/KfJ0g4wmRK8ZukUfqakLr6ZTf9VDydKoLy90=
|
||||||
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8 h1:tdkLkSKtYd3WSDsZXGJDKsakiNstLQJPN5HjnqCkf2c=
|
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8 h1:tdkLkSKtYd3WSDsZXGJDKsakiNstLQJPN5HjnqCkf2c=
|
||||||
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8/go.mod h1:zOVb1QDhwwqWn2L2qZ0U3swMSO4GTSNyIwXCGO/UGWE=
|
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8/go.mod h1:zOVb1QDhwwqWn2L2qZ0U3swMSO4GTSNyIwXCGO/UGWE=
|
||||||
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 h1:/ZshrfQzayqRSBDodmp3rhNCHJCff+utvgBuWRbiqu4=
|
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 h1:/ZshrfQzayqRSBDodmp3rhNCHJCff+utvgBuWRbiqu4=
|
||||||
|
|
|
@ -1163,6 +1163,12 @@ func getFTPDBindingSecurityFromEnv(idx int, binding *ftpd.Binding) bool {
|
||||||
isSet = true
|
isSet = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tlsSessionReuse, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%v__TLS_SESSION_REUSE", idx), 0)
|
||||||
|
if ok {
|
||||||
|
binding.TLSSessionReuse = int(tlsSessionReuse)
|
||||||
|
isSet = true
|
||||||
|
}
|
||||||
|
|
||||||
tlsVer, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%v__MIN_TLS_VERSION", idx), 0)
|
tlsVer, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%v__MIN_TLS_VERSION", idx), 0)
|
||||||
if ok {
|
if ok {
|
||||||
binding.MinTLSVersion = int(tlsVer)
|
binding.MinTLSVersion = int(tlsVer)
|
||||||
|
|
|
@ -962,6 +962,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
|
||||||
os.Setenv("SFTPGO_FTPD__BINDINGS__0__PORT", "2200")
|
os.Setenv("SFTPGO_FTPD__BINDINGS__0__PORT", "2200")
|
||||||
os.Setenv("SFTPGO_FTPD__BINDINGS__0__APPLY_PROXY_CONFIG", "f")
|
os.Setenv("SFTPGO_FTPD__BINDINGS__0__APPLY_PROXY_CONFIG", "f")
|
||||||
os.Setenv("SFTPGO_FTPD__BINDINGS__0__TLS_MODE", "2")
|
os.Setenv("SFTPGO_FTPD__BINDINGS__0__TLS_MODE", "2")
|
||||||
|
os.Setenv("SFTPGO_FTPD__BINDINGS__0__TLS_SESSION_REUSE", "1")
|
||||||
os.Setenv("SFTPGO_FTPD__BINDINGS__0__FORCE_PASSIVE_IP", "127.0.1.2")
|
os.Setenv("SFTPGO_FTPD__BINDINGS__0__FORCE_PASSIVE_IP", "127.0.1.2")
|
||||||
os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__IP", "172.16.1.1")
|
os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__IP", "172.16.1.1")
|
||||||
os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_HOST", "127.0.1.3")
|
os.Setenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_HOST", "127.0.1.3")
|
||||||
|
@ -985,6 +986,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
|
||||||
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PORT")
|
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PORT")
|
||||||
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__APPLY_PROXY_CONFIG")
|
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__APPLY_PROXY_CONFIG")
|
||||||
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__TLS_MODE")
|
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__TLS_MODE")
|
||||||
|
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__TLS_SESSION_REUSE")
|
||||||
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__FORCE_PASSIVE_IP")
|
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__FORCE_PASSIVE_IP")
|
||||||
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__IP")
|
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_IP_OVERRIDES__0__IP")
|
||||||
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_HOST")
|
os.Unsetenv("SFTPGO_FTPD__BINDINGS__0__PASSIVE_HOST")
|
||||||
|
@ -1012,6 +1014,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
|
||||||
require.Equal(t, "127.0.0.1", bindings[0].Address)
|
require.Equal(t, "127.0.0.1", bindings[0].Address)
|
||||||
require.False(t, bindings[0].ApplyProxyConfig)
|
require.False(t, bindings[0].ApplyProxyConfig)
|
||||||
require.Equal(t, 2, bindings[0].TLSMode)
|
require.Equal(t, 2, bindings[0].TLSMode)
|
||||||
|
require.Equal(t, 1, bindings[0].TLSSessionReuse)
|
||||||
require.Equal(t, 12, bindings[0].MinTLSVersion)
|
require.Equal(t, 12, bindings[0].MinTLSVersion)
|
||||||
require.Equal(t, "127.0.1.2", bindings[0].ForcePassiveIP)
|
require.Equal(t, "127.0.1.2", bindings[0].ForcePassiveIP)
|
||||||
require.Len(t, bindings[0].PassiveIPOverrides, 0)
|
require.Len(t, bindings[0].PassiveIPOverrides, 0)
|
||||||
|
@ -1027,6 +1030,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) {
|
||||||
require.Equal(t, "127.0.1.1", bindings[1].Address)
|
require.Equal(t, "127.0.1.1", bindings[1].Address)
|
||||||
require.True(t, bindings[1].ApplyProxyConfig) // default value
|
require.True(t, bindings[1].ApplyProxyConfig) // default value
|
||||||
require.Equal(t, 1, bindings[1].TLSMode)
|
require.Equal(t, 1, bindings[1].TLSMode)
|
||||||
|
require.Equal(t, 0, bindings[1].TLSSessionReuse)
|
||||||
require.Equal(t, 13, bindings[1].MinTLSVersion)
|
require.Equal(t, 13, bindings[1].MinTLSVersion)
|
||||||
require.Equal(t, "127.0.1.1", bindings[1].ForcePassiveIP)
|
require.Equal(t, "127.0.1.1", bindings[1].ForcePassiveIP)
|
||||||
require.Empty(t, bindings[1].PassiveHost)
|
require.Empty(t, bindings[1].PassiveHost)
|
||||||
|
|
|
@ -66,6 +66,8 @@ type Binding struct {
|
||||||
// Set to 1 to require TLS for both data and control connection.
|
// Set to 1 to require TLS for both data and control connection.
|
||||||
// Set to 2 to enable implicit TLS
|
// Set to 2 to enable implicit TLS
|
||||||
TLSMode int `json:"tls_mode" mapstructure:"tls_mode"`
|
TLSMode int `json:"tls_mode" mapstructure:"tls_mode"`
|
||||||
|
// 0 disabled, 1 required
|
||||||
|
TLSSessionReuse int `json:"tls_session_reuse" mapstructure:"tls_session_reuse"`
|
||||||
// Certificate and matching private key for this specific binding, if empty the global
|
// Certificate and matching private key for this specific binding, if empty the global
|
||||||
// ones will be used, if any
|
// ones will be used, if any
|
||||||
CertificateFile string `json:"certificate_file" mapstructure:"certificate_file"`
|
CertificateFile string `json:"certificate_file" mapstructure:"certificate_file"`
|
||||||
|
@ -133,6 +135,14 @@ func (b *Binding) IsValid() bool {
|
||||||
return b.Port > 0
|
return b.Port > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Binding) isTLSModeValid() bool {
|
||||||
|
return b.TLSMode >= 0 && b.TLSMode <= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Binding) isTLSSessionReuseValid() bool {
|
||||||
|
return b.TLSSessionReuse >= 0 && b.TLSSessionReuse <= 1
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Binding) checkSecuritySettings() error {
|
func (b *Binding) checkSecuritySettings() error {
|
||||||
if b.PassiveConnectionsSecurity < 0 || b.PassiveConnectionsSecurity > 1 {
|
if b.PassiveConnectionsSecurity < 0 || b.PassiveConnectionsSecurity > 1 {
|
||||||
return fmt.Errorf("invalid passive_connections_security: %v", b.PassiveConnectionsSecurity)
|
return fmt.Errorf("invalid passive_connections_security: %v", b.PassiveConnectionsSecurity)
|
||||||
|
|
|
@ -58,14 +58,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
logSender = "ftpdTesting"
|
logSender = "ftpdTesting"
|
||||||
ftpServerAddr = "127.0.0.1:2121"
|
ftpServerAddr = "127.0.0.1:2121"
|
||||||
sftpServerAddr = "127.0.0.1:2122"
|
sftpServerAddr = "127.0.0.1:2122"
|
||||||
ftpSrvAddrTLS = "127.0.0.1:2124" // ftp server with implicit tls
|
ftpSrvAddrTLS = "127.0.0.1:2124" // ftp server with implicit tls
|
||||||
defaultUsername = "test_user_ftp"
|
ftpSrvAddrTLSResumption = "127.0.0.1:2126" // ftp server with implicit tls
|
||||||
defaultPassword = "test_password"
|
defaultUsername = "test_user_ftp"
|
||||||
osWindows = "windows"
|
defaultPassword = "test_password"
|
||||||
ftpsCert = `-----BEGIN CERTIFICATE-----
|
osWindows = "windows"
|
||||||
|
ftpsCert = `-----BEGIN CERTIFICATE-----
|
||||||
MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
|
MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
|
||||||
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
|
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
|
||||||
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
|
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
|
||||||
|
@ -263,7 +264,7 @@ var (
|
||||||
caCRLPath string
|
caCRLPath string
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) { //nolint:gocyclo
|
||||||
logFilePath = filepath.Join(configDir, "sftpgo_ftpd_test.log")
|
logFilePath = filepath.Join(configDir, "sftpgo_ftpd_test.log")
|
||||||
bannerFileName := "banner_file"
|
bannerFileName := "banner_file"
|
||||||
bannerFile := filepath.Join(configDir, bannerFileName)
|
bannerFile := filepath.Join(configDir, bannerFileName)
|
||||||
|
@ -271,6 +272,7 @@ func TestMain(m *testing.M) {
|
||||||
err := os.WriteFile(bannerFile, []byte("SFTPGo test ready\nsimple banner line\n"), os.ModePerm)
|
err := os.WriteFile(bannerFile, []byte("SFTPGo test ready\nsimple banner line\n"), os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.ErrorToConsole("error creating banner file: %v", err)
|
logger.ErrorToConsole("error creating banner file: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
// we run the test cases with UploadMode atomic and resume support. The non atomic code path
|
// we run the test cases with UploadMode atomic and resume support. The non atomic code path
|
||||||
// simply does not execute some code so if it works in atomic mode will
|
// simply does not execute some code so if it works in atomic mode will
|
||||||
|
@ -431,6 +433,31 @@ func TestMain(m *testing.M) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
waitTCPListening(ftpdConf.Bindings[0].GetAddress())
|
waitTCPListening(ftpdConf.Bindings[0].GetAddress())
|
||||||
|
|
||||||
|
ftpdConf = config.GetFTPDConfig()
|
||||||
|
ftpdConf.Bindings = []ftpd.Binding{
|
||||||
|
{
|
||||||
|
Port: 2126,
|
||||||
|
CertificateFile: certPath,
|
||||||
|
CertificateKeyFile: keyPath,
|
||||||
|
TLSMode: 1,
|
||||||
|
TLSSessionReuse: 1,
|
||||||
|
ClientAuthType: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ftpdConf.CACertificates = []string{caCrtPath}
|
||||||
|
ftpdConf.CARevocationLists = []string{caCRLPath}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
logger.Debug(logSender, "", "initializing FTP server with config %+v", ftpdConf)
|
||||||
|
if err := ftpdConf.Initialize(configDir); err != nil {
|
||||||
|
logger.ErrorToConsole("could not start FTP server: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
waitTCPListening(ftpdConf.Bindings[0].GetAddress())
|
||||||
|
|
||||||
waitNoConnections()
|
waitNoConnections()
|
||||||
startHTTPFs()
|
startHTTPFs()
|
||||||
|
|
||||||
|
@ -501,6 +528,16 @@ func TestInitializationFailure(t *testing.T) {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Contains(t, err.Error(), "the provided passive IP \"127001\" is not valid")
|
require.Contains(t, err.Error(), "the provided passive IP \"127001\" is not valid")
|
||||||
ftpdConf.Bindings[1].ForcePassiveIP = ""
|
ftpdConf.Bindings[1].ForcePassiveIP = ""
|
||||||
|
ftpdConf.Bindings[1].TLSMode = 2
|
||||||
|
ftpdConf.Bindings[1].TLSSessionReuse = 1
|
||||||
|
err = ftpdConf.Initialize(configDir)
|
||||||
|
require.Error(t, err, "TLS session resumption should not be supported with implicit FTPS")
|
||||||
|
ftpdConf.Bindings[1].TLSMode = 0
|
||||||
|
ftpdConf.Bindings[1].TLSSessionReuse = 100
|
||||||
|
err = ftpdConf.Initialize(configDir)
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "unsupported TLS reuse mode")
|
||||||
|
ftpdConf.Bindings[1].TLSSessionReuse = 0
|
||||||
err = ftpdConf.Initialize(configDir)
|
err = ftpdConf.Initialize(configDir)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
|
@ -3359,6 +3396,61 @@ func TestCombine(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTLSSessionReuse(t *testing.T) {
|
||||||
|
u := getTestUser()
|
||||||
|
user, _, err := httpdtest.AddUser(u, http.StatusCreated)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
client, err := getFTPClientWithSessionReuse(user, nil)
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
err = checkBasicFTP(client)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testFilePath := filepath.Join(homeBasePath, testFileName)
|
||||||
|
testFileSize := int64(65535)
|
||||||
|
err = createTestFile(testFilePath, testFileSize)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
|
||||||
|
err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
entries, err := client.List("/")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, entries, 1)
|
||||||
|
|
||||||
|
err = client.Quit()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.Remove(testFilePath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.Remove(localDownloadPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this TLS config does not support session resumption
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
ServerName: "localhost",
|
||||||
|
InsecureSkipVerify: true, // use this for tests only
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
client, err = getFTPClientWithSessionReuse(user, tlsConfig)
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
err = checkBasicFTP(client)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
err = client.Quit()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.RemoveAll(user.GetHomeDir())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestClientCertificateAuthRevokedCert(t *testing.T) {
|
func TestClientCertificateAuthRevokedCert(t *testing.T) {
|
||||||
u := getTestUser()
|
u := getTestUser()
|
||||||
u.Username = tlsClient2Username
|
u.Username = tlsClient2Username
|
||||||
|
@ -3369,11 +3461,12 @@ func TestClientCertificateAuthRevokedCert(t *testing.T) {
|
||||||
ServerName: "localhost",
|
ServerName: "localhost",
|
||||||
InsecureSkipVerify: true, // use this for tests only
|
InsecureSkipVerify: true, // use this for tests only
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
|
ClientSessionCache: tls.NewLRUClientSessionCache(0),
|
||||||
}
|
}
|
||||||
tlsCert, err := tls.X509KeyPair([]byte(client2Crt), []byte(client2Key))
|
tlsCert, err := tls.X509KeyPair([]byte(client2Crt), []byte(client2Key))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
|
tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
|
||||||
_, err = getFTPClient(user, true, tlsConfig)
|
_, err = getFTPClientWithSessionReuse(user, tlsConfig)
|
||||||
if assert.Error(t, err) {
|
if assert.Error(t, err) {
|
||||||
assert.Contains(t, err.Error(), "bad certificate")
|
assert.Contains(t, err.Error(), "bad certificate")
|
||||||
}
|
}
|
||||||
|
@ -3869,6 +3962,38 @@ func getFTPClientImplicitTLS(user dataprovider.User) (*ftp.ServerConn, error) {
|
||||||
return client, err
|
return client, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getFTPClientWithSessionReuse(user dataprovider.User, tlsConfig *tls.Config, dialOptions ...ftp.DialOption,
|
||||||
|
) (*ftp.ServerConn, error) {
|
||||||
|
ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
|
||||||
|
ftpOptions = append(ftpOptions, dialOptions...)
|
||||||
|
if tlsConfig == nil {
|
||||||
|
tlsConfig = &tls.Config{
|
||||||
|
ServerName: "localhost",
|
||||||
|
InsecureSkipVerify: true, // use this for tests only
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
ClientSessionCache: tls.NewLRUClientSessionCache(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ftpOptions = append(ftpOptions, ftp.DialWithExplicitTLS(tlsConfig))
|
||||||
|
client, err := ftp.Dial(ftpSrvAddrTLSResumption, ftpOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pwd := defaultPassword
|
||||||
|
if user.Password != "" {
|
||||||
|
if user.Password == emptyPwdPlaceholder {
|
||||||
|
pwd = ""
|
||||||
|
} else {
|
||||||
|
pwd = user.Password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = client.Login(user.Username, pwd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return client, err
|
||||||
|
}
|
||||||
|
|
||||||
func getFTPClient(user dataprovider.User, useTLS bool, tlsConfig *tls.Config, dialOptions ...ftp.DialOption,
|
func getFTPClient(user dataprovider.User, useTLS bool, tlsConfig *tls.Config, dialOptions ...ftp.DialOption,
|
||||||
) (*ftp.ServerConn, error) {
|
) (*ftp.ServerConn, error) {
|
||||||
ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
|
ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
|
||||||
|
|
|
@ -945,6 +945,11 @@ func TestVerifyTLSConnection(t *testing.T) {
|
||||||
|
|
||||||
err = server.verifyTLSConnection(state)
|
err = server.verifyTLSConnection(state)
|
||||||
assert.Error(t, err) // no verified certification chain
|
assert.Error(t, err) // no verified certification chain
|
||||||
|
err = server.VerifyTLSConnectionState(nil, state)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
server.binding.ClientAuthType = 1
|
||||||
|
err = server.VerifyTLSConnectionState(nil, state)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
crt, err = tls.X509KeyPair([]byte(caCRT), []byte(caKey))
|
crt, err = tls.X509KeyPair([]byte(caCRT), []byte(caKey))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -104,11 +104,15 @@ func (s *Server) GetSettings() (*ftpserver.Settings, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.binding.TLSMode < 0 || s.binding.TLSMode > 2 {
|
if !s.binding.isTLSModeValid() {
|
||||||
return nil, errors.New("unsupported TLS mode")
|
return nil, fmt.Errorf("unsupported TLS mode: %d", s.binding.TLSMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.binding.TLSMode > 0 && certMgr == nil {
|
if !s.binding.isTLSSessionReuseValid() {
|
||||||
|
return nil, fmt.Errorf("unsupported TLS reuse mode %d", s.binding.TLSSessionReuse)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.binding.TLSMode > 0 || s.binding.TLSSessionReuse > 0) && certMgr == nil {
|
||||||
return nil, errors.New("to enable TLS you need to provide a certificate")
|
return nil, errors.New("to enable TLS you need to provide a certificate")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +126,7 @@ func (s *Server) GetSettings() (*ftpserver.Settings, error) {
|
||||||
ConnectionTimeout: 20,
|
ConnectionTimeout: 20,
|
||||||
Banner: s.statusBanner,
|
Banner: s.statusBanner,
|
||||||
TLSRequired: ftpserver.TLSRequirement(s.binding.TLSMode),
|
TLSRequired: ftpserver.TLSRequirement(s.binding.TLSMode),
|
||||||
|
TLSSessionReuse: ftpserver.TLSSessionReuse(s.binding.TLSSessionReuse),
|
||||||
DisableSite: !s.config.EnableSite,
|
DisableSite: !s.config.EnableSite,
|
||||||
DisableActiveMode: s.config.DisableActiveMode,
|
DisableActiveMode: s.config.DisableActiveMode,
|
||||||
EnableHASH: s.config.HASHSupport > 0,
|
EnableHASH: s.config.HASHSupport > 0,
|
||||||
|
@ -284,7 +289,9 @@ func (s *Server) buildTLSConfig() {
|
||||||
s.binding.GetAddress(), s.binding.ciphers, certID)
|
s.binding.GetAddress(), s.binding.ciphers, certID)
|
||||||
if s.binding.isMutualTLSEnabled() {
|
if s.binding.isMutualTLSEnabled() {
|
||||||
s.tlsConfig.ClientCAs = certMgr.GetRootCAs()
|
s.tlsConfig.ClientCAs = certMgr.GetRootCAs()
|
||||||
s.tlsConfig.VerifyConnection = s.verifyTLSConnection
|
if s.binding.TLSSessionReuse != int(ftpserver.TLSSessionReuseRequired) {
|
||||||
|
s.tlsConfig.VerifyConnection = s.verifyTLSConnection
|
||||||
|
}
|
||||||
switch s.binding.ClientAuthType {
|
switch s.binding.ClientAuthType {
|
||||||
case 1:
|
case 1:
|
||||||
s.tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
s.tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
|
@ -303,6 +310,14 @@ func (s *Server) GetTLSConfig() (*tls.Config, error) {
|
||||||
return nil, errors.New("no TLS certificate configured")
|
return nil, errors.New("no TLS certificate configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyTLSConnectionState implements the MainDriverExtensionTLSConnectionStateVerifier extension
|
||||||
|
func (s *Server) VerifyTLSConnectionState(_ ftpserver.ClientContext, cs tls.ConnectionState) error {
|
||||||
|
if !s.binding.isMutualTLSEnabled() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.verifyTLSConnection(cs)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) verifyTLSConnection(state tls.ConnectionState) error {
|
func (s *Server) verifyTLSConnection(state tls.ConnectionState) error {
|
||||||
if certMgr != nil {
|
if certMgr != nil {
|
||||||
var clientCrt *x509.Certificate
|
var clientCrt *x509.Certificate
|
||||||
|
|
|
@ -113,6 +113,7 @@
|
||||||
"address": "",
|
"address": "",
|
||||||
"apply_proxy_config": true,
|
"apply_proxy_config": true,
|
||||||
"tls_mode": 0,
|
"tls_mode": 0,
|
||||||
|
"tls_session_reuse": 0,
|
||||||
"certificate_file": "",
|
"certificate_file": "",
|
||||||
"certificate_key_file": "",
|
"certificate_key_file": "",
|
||||||
"min_tls_version": 12,
|
"min_tls_version": 12,
|
||||||
|
|
Loading…
Reference in a new issue