ProFTPD: FTP and SSL/TLS

## FTP and SSL/TLS

RFC 4217 defines FTP over SSL/TLS:

      http://www.faqs.org/rfcs/rfc4217.html

The `mod_tls` module for `proftpd` is an implementation of RFC 4217.

RFC 2228 defines FTP Security Extensions, of which `mod_tls` is one implementation. Another such RFC 2228 implementation is the `mod_gss` module, available from SourceForge.

Example `mod_tls` configuration:

      <IfModule mod_dso.c>
        # If mod_tls was built as a shared/DSO module, load it
        LoadModule mod_tls.c
      </IfModule>

      <IfModule mod_tls.c>
        TLSEngine on
        TLSLog /var/ftpd/tls.log

        # Support TLSv1, TLSv1.1, and TLSv1.2
        TLSProtocol TLSv1 TLSv1.1 TLSv1.2

        # Are clients required to use FTP over TLS when talking to this server?
        TLSRequired off

        # Server's RSA certificate
        TLSRSACertificateFile /etc/ftpd/server-rsa.cert.pem
        TLSRSACertificateKeyFile /etc/ftpd/server-rsa.key.pem

        # Server's EC certificate
        TLSECCertificateFile /etc/ftpd/server-ec.cert.pem
        TLSECCertificateKeyFile /etc/ftpd/server-ec.key.pem

        # CA the server trusts
        TLSCACertificateFile /etc/ftpd/root.cert.pem

        # Authenticate clients that want to use FTP over TLS?
        TLSVerifyClient off

        # Allow SSL/TLS renegotiations when the client requests them, but
        # do not force the renegotiations.  Some clients do not support
        # SSL/TLS renegotiations; when mod_tls forces a renegotiation, these
        # clients will close the data connection, or there will be a timeout
        # on an idle data connection.
        TLSRenegotiate none

      </IfModule>

Managing Certificates
Here are some widely used tools for generating and managing TLS certificates:

- Certbot
- Let's Encrypt

Debugging
There are a couple of tools available for debugging and analysing FTPS traffic. One of the easiest to use is the `s_client` application, part of OpenSSL.

The following examples assume that `proftpd+mod_tls` is listening on 127.0.0.1, port 21:

      # openssl s_client -connect 127.0.0.1:21 -starttls ftp
      CONNECTED(00000003)
      depth=1 /CN=castaglia3-serverCA/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
      verify error:num=20:unable to get local issuer certificate
      verify return:0
      ---
      Certificate chain
       0 s:/CN=castaglia3-server/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
         i:/CN=castaglia3-serverCA/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
       1 s:/CN=castaglia3-serverCA/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
         i:/CN=castaglia3/C=US/ST=Washington/L=Seattle/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/emailAddress=tj@castaglia.org
      ---
      Server certificate
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
      subject=/CN=castaglia3-server/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
      issuer=/CN=castaglia3-serverCA/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
      ---
      Acceptable client certificate CA names
      /CN=castaglia3-clientCA/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
      /CN=castaglia3/C=US/ST=Washington/L=Seattle/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/emailAddress=tj@castaglia.org
      /CN=castaglia3-clientCA/C=US/emailAddress=tj@castaglia.org/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/ST=Washington
      /CN=castaglia3/C=US/ST=Washington/L=Seattle/O=Castaglia/OU=Castaglia Research and Development/OU=TJ Saunders/emailAddress=tj@castaglia.org
      ---
      SSL handshake has read 3731 bytes and written 344 bytes
      ---
      New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
      Server public key is 1024 bit
      Compression: NONE
      Expansion: NONE
      SSL-Session:
          Protocol  : TLSv1
          Cipher    : DHE-RSA-AES256-SHA
          Session-ID: D1F2E7C001BCFE57D797F34BD1518BDCC6160106D56A238CC0F957337C093435
          Session-ID-ctx:
          Master-Key: F8EE2812270E8FCD87D1B26F20546EF9BABAE40F36BC6F8DF45B0E2F089571E731EAFAEA5E61BCA7D9D204BE06F28B21
          Key-Arg   : None
          Start Time: 1232997620
          Timeout   : 300 (sec)
          Verify return code: 20 (unable to get local issuer certificate)
      ---
      220 ProFTPD 1.3.2rc4 Server (TJ's FTPS Server) [127.0.0.1]
      quit
      221 Goodbye.
      read:errno=0

Note that the "verify error" message is not of particular concern for us, since we are not using `s_client` to verify the server's certificate in this example.

The parts of the `s_client` output which are of particular interest are the highlighted "Certificate chain" and "Acceptable client certificate CA names" sections.

The "Certificate chain" section shows the certificate chain/trust path, from the server's certificate up through the root CA for that certificate. Note that this assumes the certificates in the trust path are available on the server. By default, OpenSSL constructs this certificate chain using the server's certificate (configured using `TLSRSACertificateFile` or `TLSDSACertificateFile`) and the trusted CA certificates configured using `TLSCACertificateFile` and/or `TLSCACertificatePath`. See the `TLSCertificateChainFile` FAQ for more details on how to influence the constructed certificate chain.

The "Acceptable client certificate CA names" section contains the list of CAs that can issue certificates that `mod_tls` is willing to trust. These CAs always come from the configured `TLSCACertificateFile` and/or `TLSCACertificatePath`. This list of acceptable client CAs is presented to the client whenever the server is requesting the client's certificate (which is what `mod_tls` does by default). If you use:

      TLSOptions NoCertRequest

then the server will not send this list of acceptable client CAs; using `s_client` in that case, you would see:

      ---
      No client certificate CA names sent
      ---

In case you're wondering, a list of CAs is sent to the client, rather than just a single CA, because this allows clients the ability to determine which certificate (as a client can have many) to use when talking to this particular server.

Another tool, slightly older, is `ssldump`. This tool is more like `ethereal` or `tcpdump` for any SSL/TLS traffic; it is deliberately modeled after `tcpdump`.

To use `ssldump` for watching your FTPS traffic, you will need the server key file (for decrypting), and possibly root privileges (for listening on the network interface). Here is an example where `ssldump` is used to listen on the loopback interface (`lo0`), port 21:

      # sudo ssldump -d -k server.pem -i lo0 port 21
      New TCP connection #1: localhost(64148) <-> localhost(21)
      0.0423 (0.0423)  S>C
      ---------------------------------------------------------------
      220 ProFTPD 1.3.2rc4 Server (TJ's FTPS Server) [127.0.0.1]
      ---------------------------------------------------------------

      0.0427 (0.0004)  C>S
      ---------------------------------------------------------------
      AUTH TLS
      ---------------------------------------------------------------

      0.0430 (0.0002)  S>C
      ---------------------------------------------------------------
      234 AUTH TLS successful
      ---------------------------------------------------------------

      1 1  0.0433 (0.0003)  C>S SSLv2 compatible client hello
        Version 3.1
        cipher suites
        Unknown value 0x39
        Unknown value 0x38
        Unknown value 0x35
        TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
        TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
        TLS_RSA_WITH_3DES_EDE_CBC_SHA
        SSL2_CK_3DES
        Unknown value 0x33
        Unknown value 0x32
        Unknown value 0x2f
        TLS_RSA_WITH_IDEA_CBC_SHA
        SSL2_CK_IDEA
        SSL2_CK_RC2
        TLS_RSA_WITH_RC4_128_SHA
        TLS_RSA_WITH_RC4_128_MD5
        SSL2_CK_RC4
        TLS_DHE_RSA_WITH_DES_CBC_SHA
        TLS_DHE_DSS_WITH_DES_CBC_SHA
        TLS_RSA_WITH_DES_CBC_SHA
        SSL2_CK_DES
        TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
        TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
        TLS_RSA_EXPORT_WITH_DES40_CBC_SHA
        TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
        SSL2_CK_RC2_EXPORT40
        TLS_RSA_EXPORT_WITH_RC4_40_MD5
        SSL2_CK_RC4_EXPORT40
      1 2  0.0658 (0.0225)  S>C  Handshake
            ServerHello
              Version 3.1
              session_id[32]=
                09 25 df 7a a8 e8 71 a2 9f 56 a6 7b dd 95 ac 67
                7d 2e 81 b2 1c ca b4 5f 1e 95 13 47 01 28 20 19
              cipherSuite         Unknown value 0x39
              compressionMethod                   NULL
      1 3  0.0658 (0.0000)  S>C  Handshake
            Certificate
      1 4  0.0658 (0.0000)  S>C  Handshake
            ServerKeyExchange
      1 5  0.0658 (0.0000)  S>C  Handshake
            CertificateRequest
              certificate_types                   rsa_fixed_dh
              certificate_types                   dss_fixed_dh
              certificate_types                   rsa_sign
              certificate_types                   dss_sign
              certificate_authority
                30 81 b8 31 1c 30 1a 06 03 55 04 03 13 13 63 61
                73 74 61 67 6c 69 61 33 2d 63 6c 69 65 6e 74 43
                41 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 1f
                30 1d 06 09 2a 86 48 86 f7 0d 01 09 01 16 10 74
                6a 40 63 61 73 74 61 67 6c 69 61 2e 6f 72 67 31
                12 30 10 06 03 55 04 0a 13 09 43 61 73 74 61 67
                6c 69 61 31 2b 30 29 06 03 55 04 0b 13 22 43 61
                73 74 61 67 6c 69 61 20 52 65 73 65 61 72 63 68
                20 61 6e 64 20 44 65 76 65 6c 6f 70 6d 65 6e 74
                31 14 30 12 06 03 55 04 0b 13 0b 54 4a 20 53 61
                75 6e 64 65 72 73 31 13 30 11 06 03 55 04 08 13
                0a 57 61 73 68 69 6e 67 74 6f 6e
              certificate_authority
                30 81 c1 31 13 30 11 06 03 55 04 03 13 0a 63 61
                73 74 61 67 6c 69 61 33 31 0b 30 09 06 03 55 04
                06 13 02 55 53 31 13 30 11 06 03 55 04 08 13 0a
                57 61 73 68 69 6e 67 74 6f 6e 31 10 30 0e 06 03
                55 04 07 13 07 53 65 61 74 74 6c 65 31 12 30 10
                06 03 55 04 0a 13 09 43 61 73 74 61 67 6c 69 61
                31 2b 30 29 06 03 55 04 0b 13 22 43 61 73 74 61
                67 6c 69 61 20 52 65 73 65 61 72 63 68 20 61 6e
                64 20 44 65 76 65 6c 6f 70 6d 65 6e 74 31 14 30
                12 06 03 55 04 0b 13 0b 54 4a 20 53 61 75 6e 64
                65 72 73 31 1f 30 1d 06 09 2a 86 48 86 f7 0d 01
                09 01 16 10 74 6a 40 63 61 73 74 61 67 6c 69 61
                2e 6f 72 67
              certificate_authority
                30 81 b8 31 1c 30 1a 06 03 55 04 03 13 13 63 61
                73 74 61 67 6c 69 61 33 2d 63 6c 69 65 6e 74 43
                41 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 1f
                30 1d 06 09 2a 86 48 86 f7 0d 01 09 01 16 10 74
                6a 40 63 61 73 74 61 67 6c 69 61 2e 6f 72 67 31
                12 30 10 06 03 55 04 0a 13 09 43 61 73 74 61 67
                6c 69 61 31 2b 30 29 06 03 55 04 0b 13 22 43 61
                73 74 61 67 6c 69 61 20 52 65 73 65 61 72 63 68
                20 61 6e 64 20 44 65 76 65 6c 6f 70 6d 65 6e 74
                31 14 30 12 06 03 55 04 0b 13 0b 54 4a 20 53 61
                75 6e 64 65 72 73 31 13 30 11 06 03 55 04 08 13
                0a 57 61 73 68 69 6e 67 74 6f 6e
              certificate_authority
                30 81 c1 31 13 30 11 06 03 55 04 03 13 0a 63 61
                73 74 61 67 6c 69 61 33 31 0b 30 09 06 03 55 04
                06 13 02 55 53 31 13 30 11 06 03 55 04 08 13 0a
                57 61 73 68 69 6e 67 74 6f 6e 31 10 30 0e 06 03
                55 04 07 13 07 53 65 61 74 74 6c 65 31 12 30 10
                06 03 55 04 0a 13 09 43 61 73 74 61 67 6c 69 61
                31 2b 30 29 06 03 55 04 0b 13 22 43 61 73 74 61
                67 6c 69 61 20 52 65 73 65 61 72 63 68 20 61 6e
                64 20 44 65 76 65 6c 6f 70 6d 65 6e 74 31 14 30
                12 06 03 55 04 0b 13 0b 54 4a 20 53 61 75 6e 64
                65 72 73 31 1f 30 1d 06 09 2a 86 48 86 f7 0d 01
                09 01 16 10 74 6a 40 63 61 73 74 61 67 6c 69 61
                2e 6f 72 67
            ServerHelloDone
      1 6  0.1005 (0.0346)  C>S  Handshake
            Certificate
      1 7  0.1005 (0.0000)  C>S  Handshake
            ClientKeyExchange
      1 8  0.1005 (0.0000)  C>S  ChangeCipherSpec
      1 9  0.1005 (0.0000)  C>S  Handshake
      1 10 0.1164 (0.0159)  S>C  ChangeCipherSpec
      1 11 0.1164 (0.0000)  S>C  Handshake
      1 12 1.7856 (1.6692)  C>S  application_data
      1 13 1.7856 (0.0000)  C>S  application_data
      1 14 1.7861 (0.0004)  S>C  application_data
      1    1.7866 (0.0004)  S>C  TCP FIN
      1 15 1.7868 (0.0002)  C>S  Alert

As you can see, the level of granularity used by `ssldump` is on the level of each SSL/TLS packet; while useful in some cases, I suspect that using `openssl s_client` will provide most of the information you will want in figuring out your certificate and verification issues.

TLS Client Auth/Mutual Auth
Like most web servers, when `mod_tls` is used, it does not require that the connecting client present a certificate for verification by default. That is, `mod_tls` does not require "client auth" or "mutual auth" by default. To require that clients present a valid certificate, you would use the `TLSVerifyClient` directive like so:

      <IfModule mod_tls.c>
        TLSEngine on
        ...
        # Verify clients that want to use FTP over TLS
        TLSVerifyClient on
      </IfModule>

With this directive enabled in your configuration, if a client connects and performs the SSL/TLS handshake but does not present a valid certificate, then the TLSLog would contain error messages like this:

      mod_tls/2.4.3[12065]: TLS/TLS-C requested, starting TLS handshake
      mod_tls/2.4.3[12065]: unable to accept TLS connection: protocol error:
        (1) error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate
      mod_tls/2.4.3[12065]: TLS/TLS-C negotiation failed on control channel

The client failed to provide a valid certificate, and so the connection was rejected.

Frequently Asked Questions

Question: When I enable `mod_tls`, I can't upload or download files, or list directories. I see the following error in my client:

      425 Unable to build data connection: Operation not permitted.

Why?
Answer: By default, `mod_tls` requires that the same SSL session be used data transfers (see `TLSOptions`), which includes uploads, downloads, and directory listings. If your data transfers are failing, you might look in your `TLSLog`, and see a log message like this:

      client did not reuse SSL session, rejecting data connection (see the NoSessionReuseRequired TLSOptions parameter)

The workaround, then, is to add the TLSOption mentioned in the log message to your configuration, i.e.:

      # Relax the requirement that the SSL session be reused for data transfers
      TLSOptions NoSessionReuseRequired

Then restart `proftpd`, and your data transfers should work.

Question: How do I generate the certificate files used by `mod_tls`?
Answer: The `mod_tls` module uses the same certificate files as Apache's `mod_ssl`. The `mod_ssl` documentation explains what the files are, how they are used, and how to generate your own:

      http://www.modssl.org/docs/2.7/ssl_faq.html

Question: Does FTPS protect both the control connection and the data connections?
Question: Short answer: yes.

The long answer is, of course, that it depends. In the case of `mod_tls`, it depends on your `TLSRequired` setting. If you use:

      TLSRequired on

then you are configuring `mod_tls` to require SSL/TLS protection for both control connections (e.g. protecting the username and password used to log in) and data connections. If you have:

      TLSRequired off

then it is up to the FTPS client whether both control and data connections will be protected via SSL/TLS. Other `TLSRequired` settings can be used to specify specific combinations: data connections only, control connections only, authentication plus data data connections only, etc. The `TLSRequired` documentation has the details.

Question: Where can I find a list of clients that support FTPS?
Answer: This page is a good FTPS resource:

      http://www.ford-hutchinson.com/~fh-1-pfh/ftps-ext.html

including the list of FTPS clients. On a related note, there have been some reports that Debian's `ftp-ssl` client has a few bugs; using Peter Runestig's `ftp-tls` is known to work.

Note, though, that there are known issues with some older versions of FTPS clients, most notably SmartFTP and CuteFTP Pro. These clients had the following behavior: RFC 2246 states that, if a client receives a `CertificateRequest`, and the client has no certificate, it "should send a certificate message containing no certificates" (Section 7.4.6). Instead, after negotiating to use TLS version 1, these clients choke and break the connection (which is actually SSL version 2 behavior). The `NoCertRequest` `TLSOption` is designed for use for such clients.

Question: How come `mod_tls` does not support "implicit" FTPS (i.e. automatically encrypting sessions on port 990)?
Answer: The short answer is because the Draft no longer specifies support for such a mode. Here is a description of why the alternatives to the current mode (client-requested encryption using standard control channel) are "bad".

The long answer is covered in Eric Rescorla's excellent book, "SSL and TLS". There tend to be two different strategies used when adding new features to a protocol: separate ports for protocol variants, or upward negotiation. Port 443 for HTTPS is an example of the separate ports strategy. The drawback to the separate ports approach is that there is a finite number of ports available, and so this approach does not scale well. The benefit is that use of separate ports tends to require smaller changes to client and server code. Upward negotiation is more flexible, but requires that the protocol support some sort of feature negotiation or extension discovery, allowing clients and servers to easily agree to negotiate "upward" into a secure channel. The authors of the FTPS Draft felt that upward negotiation was the more appropriate of these two approaches for encrypting FTP channels.

All that said, in ProFTPD 1.3.3rc2, the `mod_tls` module was enhanced to support implicit FTPS via the `UseImplicitSSL` `TLSOption`.

Question: How can I require that only TLSv1.2 be allowed/used?
Answer: Assuming your OpenSSL library is new enough, you should only need to use the following in your `mod_tls` configuration section:

      TLSProtocol TLSv1.2

Note that if you have multiple `<VirtualHost>` sections in your `proftpd.conf` and you want this to apply to all of those vhosts, then you should place the `TLSProtocol` directive in a `<Global>` section, e.g.:

      <Global>
        # Only allow TLSv1.2 for any of our FTPS vhosts
        TLSProtocol TLSv1.2
      </Global>

Question: Can I require TLS on a per-user basis?
Answer: Prior to ProFTPD 1.2.10rc2, no. The IETF Draft specifying FTP over TLS requires that the TLS handshake occur before the client sends the `USER` command. This means that the server does not know the name of the user that the client will be using when the TLS session is established. It is possible that the client's certificate, if one is even presented, may contain information the server may use to map that certificate to a user, but such mapping is not currently supported by `mod_tls`. Note that this is also the reason the `TLSRequired` directive cannot appear in the `<Anonymous>` context: anonymous logins are based on the `USER` command.

However, in 1.2.10rc2, the `mod_tls` module was modified to allow such per-user TLS requirements. To do this, the `AllowPerUser` parameter of the `TLSOptions` directive is used. For example, the following example `mod_tls` configuration allows non-SSL anonymous sessions, but requires SSL/TLS for all other sessions:

      <IfModule mod_tls.c>
        TLSEngine on
        TLSRSACertificateFile ...
        TLSCACertificateFile ...
        TLSOptions AllowPerUser
        TLSRequired on

        <Anonymous ~ftp>
          User ftp
          Group ftp
          UserAlias anonymous ftp

          RequireValidShell off

          # Note how TLSRequired is set to off here in the <Anonymous> context
          TLSRequired off
        </Anonymous>
      </IfModule>

The modification also allows `mod_ifsession`-based conditions, so that one can have settings like:

      <IfGroup trusted>
        TLSRequired off
      </IfGroup>

However, there is a risk involved in using the `AllowPerUser` option: it causes `mod_tls` not to enforce `TLSRequired` until after the potentially sensitive USER and PASS commands have been sent by the client. This allows clients, even when `TLSRequired on` or `TLSRequired ctrl` are in effect, to send the USER and PASS commands unencrypted. Depending on your site's security needs, the ability to require SSL/TLS on a per-user basis may or may not be worth the ability to require SSL/TLS for the USER and PASS commands.

Question: When I use the following in my `proftpd.conf`:

      TLSRequired on # or "TLSRequired auth", or "TLSRequired auth+data"
      TLSOptions AllowPerUser

I get the following error when I try to start `proftpd`:

      cannot enforce both 'TLSRequired auth' and 'TLSOptions AllowPerUser' at the same time

Answer: The reason this error occurs is because you have a configuration which is impossible to support. The `TLSRequired` setting (e.g. "on", "auth", or "auth+data") requires that SSL/TLS be in use during authentication. But in order to support the `TLSOption AllowPerUser` setting, the `mod_tls` cannot require that SSL/TLS be in use during authentication, since it does not know the user until after authentication has completed. The requested configuration cannot be supported, and thus the server will refuse to start.

Question: Why does `mod_tls` break FXP transfers?
Answer: The Draft specifying FTP over SSL explicitly omits site-to-site transfers. A TLS session is established between the client and the server on the control channel and, to save on the expensive overhead of TLS handshake, that session is reused for encrypting traffic on the data channel. In a site-to-site (FXP) transfer, the client opens two control channels, one with each server, and then arranges for those servers to open a data channel between themselves. However, since the servers have not established a TLS session between themselves, that opening of the data channel fails.

Note that the above happens only if the server requires that TLS be used on data connections (e.g. `TLSRequired` is either on or data), of if the client tells the server that the client will be using TLS on the data connections (e.g. when it sends the `AUTH` command with an argument of `TLS-P`). Without these conditions, site-to-site (FXP) transfers can occur normally, albeit unencrypted.

Note that as of `proftpd-1.3.5rc4`, encrypted site-to-site (FXP) transfers are supported via the `SSCN` FTP command. The `TLSVerifyServer` directive is also needed for secure FXP transfers.

Question: How come `mod_tls` does not support SSLv2?
Answer: Various defects have been found in the SSLv2 protocol. Some legacy sites need to support SSLv2 for their HTTP traffic, in spite of its flaws. Use of FTP over TLS is fairly new, however, and there is not much "legacy" in that regard; it was felt that, as `mod_tls` aims to provide strong cryptographic security, supporting a known bad protocol is a Bad Idea.

Question: Using `mod_tls`, FTP sessions through my firewall now no longer work. What's going on?
Answer: The short answer is that FTPS and firewalls (and devices performing NAT) do not interact well. The control connection happens on a well-known port, and has no issues; it is the data connection that poses problems for FTP-aware firewalls. In a non-FTPS session, the firewall can inspect the FTP server's responses on the control connection to a client's `PASV` or `PORT` command, and thus know which on which ports/addresses the data connection will be established. In an FTPS session, though, those control connection messages are encrypted (that is the point of using FTPS, right?), and so the FTP-aware firewall cannot peek. Hence, it cannot know which on which ports the data connection will be established. For firewalls that are configured to always allow a certain range of ports (such as might be configured using the `PassivePorts` directive), FTPS should function without issue.

Unfortunately, this is a rather intractable--and known--issue. Earlier versions of the Draft defining FTPS used to allow something known as "implicit" FTPS, by which a client could contact a well-known port (akin to port 443 for HTTPS; FTPS used port 990) and the server, simply because the client contacted that certain port, would automatically encrypt the session. This approach has several drawbacks (the reason why it was removed from later versions of the Draft), but it did allow for simple TCP proxying.

To attempt to deal with the above issue, the RFC for FTP over SSL/TLS suggests using the `CCC` FTP command (Clear Command Channel). The `CCC` command makes an encrypted control channel revert back to an unencrypted channel. This helps to solve data connection problems in situations where network equipment (such as firewalls, routers, NAT) peek at the control channel in order to open ports. By sending the `CCC` command and unecrypting the control channel, the network equipment can once again peek at the commands (i.e. `PORT` and `EPRT`) in the control channel. Since the CCC command must come after the client has logged in, the `USER` and `PASS` commands on the control channel will still be protected by SSL/TLS.

Note that in order to configure the `mod_tls` module to allow use of the `CCC` command by clients, the following must appear in your `proftpd.conf`:

      TLSRequired auth+data

See the `TLSRequired` description for more details.

Question: I can login using FTPS, but I cannot see any directories. Why not?
Answer: You have most likely configured `mod_tls` to require SSL/TLS protection for data transfers as well as control commands, by using:

      TLSRequired on

However, if your FTPS client does not expect to handle encrypted data transfers (and directory listings count as data transfers, as they are sent over a data channel), you may see your client appear to hang, waiting for data it can read. Make sure your client is prepared to handle the security requirements you have configured on the server.

The following may also appear in the `TLS` for any data transfers (which include directory listings):

      client did not reuse SSL session, rejecting data connection (see the NoSessionReuseRequired TLSOptions parameter

This message appears because an additional security restriction that was added in ProFTPD 1.3.3rc1. The `TLSOptions` documentation for this "NoSessionReuseRequired" option describes the situation in more detail.

You may also see the following appear in the `TLSLog` on occasion:

      PROT: unwilling to accept security parameter (C), declining

The `PROT` FTP command is used to set the protection level to be used for data transfers. Some clients send a `PROT` command with a security parameter of `C`, meaning "Clear", which effectively tells the server not to protect data transfers. The `mod_tls` module will refuse the `C` security parameter if, like above, there is "TLSRequired on" in your `proftpd.conf`. This case also indicates a disagreement between the client's security expectations and the security policy you have configured on the server.

In order to accept a "PROT C" FTP command, your `mod_tls` configuration would need to use a `TLSRequired` value other than required, e.g. something like:

      # We only require SSL/TLS protection during authentication
      TLSRequired auth

      # We will accept SSL/TLS protection for the control channel if the
      # client wants to use it, but NOT for data transfers
      TLSRequired !data

Question: Using FTPS, after uploading a very large file, my next directory listing fails:

      425 Unable to build data connection: Operation not permitted

The `TLSLog` contains:

      client did not reuse SSL session, rejecting data connection (see the NoSessionReuseRequired TLSOptions parameter)

but I do not want to use that option, and would like to rely on the additional security protection provided by requring SSL session reuse. And my FTPS client is correctly reusing SSL session IDs (as earlier data transfers were working properly). So why is my data transfer failing after the upload of a very large file?
Answer: The answer involves SSL session caching on the server side (i.e. `mod_tls`), cache timeouts, and session renegotiations.

By default, `mod_tls` uses OpenSSL's "internal" session cache, which is an in-memory caching of SSL session IDs. And by default, OpenSSL's internal session cache has a cache timeout of 5 minutes; after that amount of time in the internal session cache, a cached SSL session ID is considered stale and is available for reuse.

This means that 5 minutes or more into an FTPS session, even if your FTPS client reused an SSL session ID, the OpenSSL internal session cache will time out that SSL session ID. The next time your FTPS client goes to reuse that session ID for a data transfer, `mod_tls` won't find it in the OpenSSL internal session cache, and will think that your FTPS client is not reusing the SSL session ID as is required, and fail the transfer.

Fixing this situation requires two parts: a) the ability to change the cache timeout used for the OpenSSL internal session cache, and b) renegotiating the SSL session ID with the FTPS client periodically, to keep the SSL session ID up-to-date in the session cache.

The first part, configuring the session cache timeout for the OpenSSL internal session cache, is only possible in ProFTPD 1.3.4rc2 and later (see Bug#3580). The `TLSSessionCache` directive was modified to allow a configuration such as:

      TLSSessionCache internal: 1800

(Unfortunately, the ':' after "internal" is necessary.) This configures `mod_tls` such that the OpenSSL internal session cache uses a cache timeout of 1800 seconds (30 minutes), rather than the default of 300 seconds (5 minutes).

No matter how long you configure the cache timeout, eventually you will have a session which lasts longer than that timeout. Which brings us to the second part of the solution: renegotiating a new SSL session ID periodically, which keeps it fresh in the session cache. The `TLSRenegotiate` directive is needed for this. For example, the following configuration should address the issue of failed data transfers after very large uploads:

      TLSRenegotiate ctrl 1500 timeout 300
      TLSSessionCache internal: 1800

This tells `mod_tls` to request a renegotiation of the SSL session on the control channel every 1500 seconds (25 minutes), and to allow 300 seconds (5 minutes) for the client to perform the renegotiation. It also tells `mod_tls` to cache the SSL session data for 1800 seconds (30 minutes), i.e. longer than the renegotiation time of 1500 seconds.

This way, as long as your client supports renegotiations and is updating the SSL session ID properly for data transfers, when a data transfer is requested, the SSL session ID presented by the client should always be fresh and in the session cache.

Question: My FTPS client is failing to connect to `proftpd` with `mod_tls`. The `TLSLog` shows the following log messages, each time the FTPS client tries to connect:

      2016-01-15 07:32:37,275 mod_tls/2.7[5072]: TLS/TLS-C requested, starting TLS handshake
      2016-01-15 07:32:37,303 mod_tls/2.7[5072]: unable to accept TLS connection: protocol error:
        (1) error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol
      2016-01-15 07:32:37,303 mod_tls/2.7[5072]: TLS/TLS-C negotiation failed on control channel

Why does this happen?
Answer: This can happen when `mod_tls` is configured (e.g. using `TLSProtocol`) to support specific TLS versions, and the FTPS client is trying to use one of the unsupported protocol versions. For example, if you use:

      # Only support TLSv1.1 and TLSv1.2
      TLSProtocol TLSv1.1 TLSv1.2

And then connect with an FTPS client using TLSv1, like so:

      $ openssl s_client -connect address:port -starttls ftp -tls1

Then you would see the above error. Note that this same protocol mismatch issue can also manifest as the error message "wrong version number".

Question: Why would I see the following errors while attempting to build `proftpd` with `mod_tls`?

      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0x35): In function `dlfcn_load': : undefined reference to `dlopen'
      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0x95): In function `dlfcn_load': : undefined reference to `dlclose'
      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0xbc): In function `dlfcn_load': : undefined reference to `dlerror'
      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0x147): In function `dlfcn_bind_var': : undefined reference to `dlsym'
      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0x172): In function `dlfcn_bind_var': : undefined reference to `dlerror'
      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0x237): In function `dlfcn_bind_func': : undefined reference to `dlsym'
      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0x262): In function `dlfcn_bind_func': : undefined reference to `dlerror'
      /usr/local/ssl/lib/libcrypto.a(dso_dlfcn.o)(.text+0x50b): In function `dlfcn_unload': : undefined reference to `dlclose'
      collect2: ld returned 1 exit status
      make: *** [proftpd] Error 1

Answer: Add `-ldl` to your configure command, for example:

      make clean
      ./configure LDFLAGS=-ldl ...
      make

This tells the `proftpd` build system to add `libdl`, an OS-specific library for handling dynamically loaded code, to the list of libraries used when linking `proftpd`. On some systems, the functions in the `libdl` library are part of `libc`, and are not in a separate library.

I suspect that the reason this build option may be necessary is that OpenSSL 0.9.8 contained changes regarding how OpenSSL loads "engines", software modules that talk to hardware devices that can do specialized cryptographic operations. These changes involve being able to dynamically load the "engine" software modules.

Question: Why would I see a "no shared cipher" error in the TLSLog when attempting to connect with my FTPS client?

      Jan 10 17:15:18 mod_tls/2.1.1[2212]: TLS/TLS-C requested, starting TLS handshake
      Jan 10 17:15:18 mod_tls/2.1.1[2212]: unable to accept TLS connection:
        (1) error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher
      Jan 10 17:15:18 mod_tls/2.1.1[2212]: TLS/TLS-C negotiation failed on control channel

Answer: There are two reasons this might happen.

The first is that there is indeed no ciphersuite in common between `mod_tls` and your FTPS client. The SSL/TLS ciphersuites used by `mod_tls` are configured using the `TLSCipherSuite` directive. If you have a complex or restrictive `TLSCipherSuite` configured, that could be the culprit. Try relaxing (or removing outright) your `TLSCipherSuite`, or try to configure your FTPS client to use the same SSL/TLS ciphersuites.

Another possibility is a misconfiguration. If your `TLSCACertificateFile` and `TLSRSACertificateFile` directives are in the "server config" context of the `proftpd.conf` file, and you have `<VirtualHost>` sections in your `proftpd.conf`, then you might see the "no shared cipher" error. The easiest thing is to move those `TLSCACertificateFile` and `TLSRSACertificateFile` directives into a `<Global>` section in your `proftpd.conf`, so that they apply to all vhosts configured. The virtual hosting howto describes this in more detail.

Question: When my FTPS client connects to my `mod_tls`-enabled server, the TLS handshake fails. I see these messages in my `TLSLog`:

      mod_tls/2.4.3[28786]: error: unable to verify certificate at depth 1
      mod_tls/2.4.3[28786]: client certificate failed verification: certificate chain too long

What causes this?
Answer: This can happen if you have your `mod_tls` configured with a very small `TLSVerifyDepth` value, e.g.:

      TLSVerifyDepth 0

Using small values, especially a value of 0, is a bad idea; most client certificate chains have a "depth" (or length) of 2-3, or perhaps longer. The default `TLSVerifyDepth` value of 10 is sufficient for most cases; it allows for long certificate chains, but still guards against chains which might be absurdly long.

Question: My FTPS client sometimes times out after uploading/downloading more than 1 GB of data. When I turn off SSL/TLS, the upload/download works. Why?
Answer: The culprit behind this is most likely SSL/TLS renegotiations. By default, `mod_tls` uses SSL/TLS renegotiations to periodically update the session key which protects the data being transferred; see the `TLSRenegotiate` documentation for more details, particularly the time-based and bytes-based limits at which renegotiations are forced.

Some FTPS clients, however, do not support server-initiated SSL/TLS renegotiations. When the server does try to force a renegotiation, the client fails that new handshake, cannot upload/download any more data over the protected channel, and the transfer will eventually time out. Alternatively, the transfer could terminate strangely in the middle of the upload/download. Note, however, that not all transfer issues will be caused by SSL/TLS renegotiations. Bugs in firewalls and routers can also cause these symptoms.

Should you suspect that you are having issues with your FTPS client because of SSL/TLS renegotiations, you can configure `mod_tls` to accept renegotiations if the client requests one, but not to otherwise force them:

      TLSRenegotiate required off

Question: My FTPS client has trouble connecting to `proftpd` using SSL/TLS, with the following error appearing in the `TLSLog`:

      mod_tls/2.1.2[9628]: TLS/TLS-C requested, starting TLS handshake
      mod_tls/2.1.2[9628]: unable to accept TLS connection: received EOF that violates protocol
      mod_tls/2.1.2[9628]: TLS/TLS-C negotiation failed on control channel

Is this a bug in `mod_tls`, in the client, or something else?
Answer: There might be several different causes for this error. It could be a bug in the OpenSSL library, in `mod_tls`, in the FTPS client, or it could be a transient network issue.

The usual culprit for the above error is an FTP-aware network device such as a NAT, router, or firewall between the client and the server. Such network devices "peek" into the FTP control connection in order to dynamically open the necessary ports for data transfers. However, this "peeking" fails once an SSL/TLS handshake starts on that same control connection, and when that happens, these network devices usually terminate the control connection, resulting in the EOF ("end of file") error reported.

Question: When `proftpd` starts up, I am prompted to enter the passphrases for my certificates. How can I get the daemon to start without having to enter passphrases?
Answer: You can either remove the passphrase from the certificate key file (as mentioned in the Apache `mod_ssl` FAQ), or you can use the `TLSPassPhraseProvider` directive to configure a program will which provide the passphrases to `proftpd` automatically.

Question: How can I configure `mod_tls` to use OpenSSL in FIPS mode?
Answer: Using OpenSSL in FIPS mode requires quite a few steps. First, you would configure `proftpd` to use the `mod_tls` module as normal, assuming your OpenSSL installation has been compiled with FIPS support:

      ./configure --with-modules=mod_tls ...

Compiling `proftpd` requires the following, for FIPS support to work properly:

      make CC=/path/to/openssl/bin/fipsld FIPSLD_CC=gcc

The `FIPSLD_CC` variable should point to your normal C compiler, e.g. `gcc`. The use of this `fipsld` program is mandatory. The FIPS standard requires that the linking process happen a very specific way, involving verification of calculated and expected checksums of compiled code, etc. The OpenSSL packages with FIPS support supply this `fipsld` program which will link the compiled code according to the FIPS specifications. If you do not use `fipsld`, then attempts to use OpenSSL in FIPS mode will fail. For example, you would see the following if starting a `proftpd` daemon which has not been linked using `fipsld` while requesting use of FIPS:

      - mod_tls/2.1.2: unable to use FIPS mode: (unknown)
      - Fatal: unable to load module 'mod_tls.c': Operation not permitted

Now, assuming you have compiled and installed your `proftpd` properly, e.g.:

      make CC=/path/to/openssl/bin/fipsld FIPSLD_CC=gcc
      make CC=/path/to/openssl/bin/fipsld FIPSLD_CC=gcc install

you will now be ready to start `proftpd`.

In order for FIPS mode to be effective, OpenSSL must be told to run in FIPS mode from the very beginning. The `mod_tls` module initializes the OpenSSL library when the `mod_tls` module is loaded, before the `proftpd.conf` file is parsed. Thus the requesting of FIPS mode cannot be done via a setting in `proftpd.conf`. (Annoying, I know.)

Instead, you must use the -D command-line parameter when starting `proftpd` (see the docs for the `<IfDefine>` and `Define` directives) to define a specific variable, which the `mod_tls` module will look for. Specifically, you will need to start `proftpd` like thus:

      /path/to/proftpd -DTLS_USE_FIPS ...

This will define the `TLS_USE_FIPS` variable; this tells `mod_tls` to initialize OpenSSL using FIPS mode. When this works, you will see the following when `proftpd` starts up:

      - mod_tls/2.1.2: FIPS mode enabled

For additional reading on OpenSSL and FIPS, see:

      http://www.openssl.org/docs/fips/fipsnotes.html

Question: Why do I see the following in my logs when I start `proftpd` using `mod_tls`?

     - mod_tls/2.2: compiled using OpenSSL version 'OpenSSL 0.9.7i 14 Oct 2005'
    headers, but linked to OpenSSL version 'OpenSSL 0.9.7l 28 Sep 2006' library

What does this mean?
Answer: That is an informational/warning message.

Some systems are badly maintained by their admins (and/or by the packages installed on the systems), such that the OpenSSL headers can become quite badly out of sync with the OpenSSL libraries. If this discrepancy becomes bad enough, you can see strange behavior from OpenSSL, ranging from random behavior to segfaults. So `mod_tls` tries to let the admin know about the system's mismatched OpenSSL header/library versions.

Usually a minor OpenSSL version difference like the example above is OK, but it really depends on exactly what changed in OpenSSL, and how.

If you see the above message, it is not a requirement that you recompile `proftpd` against the OpenSSL headers of the same version as the OpenSSL libraries. However, the version discrepancy is a possible source of trouble.

This header/library version check was added recently, hence why older `proftpd` releases do not log the warning.

Question: When should the `TLSCertificateChainFile` directive be used?
Answer: Short answer: only in very specific arrangements of CA hierarchies. Most of the time, you probably do not need it.

The long explanation requires an illustration. Let's say we have a CA hierarchy that looks something like this:

           MyRootCA                      TheirRootCA
               |                             |
          MyServerCA                    TheirClientCA
               |                             |
        +------+------+               +------+------+
        |      |      |               |      |      |
      certA  certB  certC           cert1  cert2  cert3

Another way of asking the question thus is: "How to I send MyServerCA and MyRootCA to the client without having them in my trusted CA locations"?

We might configure `mod_tls` to have "certA" as the server's certificate, via `TLSRSACertificateFile`. The "certA" certificate is issued by MyServerCA. And let's assume that we do not want to verify any client certificates issued by MyServerCA.

We do want to be able to verify client certs issued by a different CA, say, TheirClientCA. We configure TheirClientCA in `mod_tls` using `TLSCACertificateFile` or `TLSCACertificatePath`.

The client connects to `mod_tls`, and starts the SSL/TLS handshake. `mod_tls` sends its "certA" certificate, along with any certs that may be needed on the client for verifying the server's certificate. (This is what appears in the "Certificate chain" output from `s_client`; see SSL/TLS debugging above.) Perhaps the client does not have MyServerCA present in the client certificate store. So we need to tell `mod_tls` to send the MyServerCA and MyRootCA certs, along with "certA". We could place the MyServerCA and MyRootCA certs in `TLSCACertificatePath`, but then any client certs issued by MyServerCA would be trusted as well (and that's not what we want for this example).

The solution here is to use `TLSCertificateChainFile` to supply the MyServerCA and MyRootCA certs, as part of the server cert chain. The configured `TLSCertificateChainFile` would contain the PEM-formatted MyServerCA and MyRootCA public certs. And although the `TLSCertificateChainFile` states that the certs contained in the file should be in certificate chain order, this is not strictly necessary; the OpenSSL library will adjust the ordering as appropriate.

Question: I am having trouble connecting to my SSL/TLS-enabled `proftpd`; my FTPS client shows this error:

      error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure

What is wrong?
Answer: It depends; the first thing is to check your `TLSLog` to see what errors, if any, are logged by the `mod_tls` module. For example, you might see:

      Dec 14 10:47:58 mod_tls/2.4.1[13393]: unable to accept TLS connection: protocol error:
        (1) error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher

The most common causes of these problems are: a) overly restrictive `TLSCipherSuite` configuration, or b) missing server certificate (i.e. `TLSRSACertificateFile`, `TLSDSACertificateFile`, or `TLSPKCS12File`). The file configured for the server certificate might also be badly formatted, which would result in the same error.

Question: Is there a way to require TLS (FTPS) for remote clients only, and allow simple FTP (without TLS) for local clients (i.e. for clients in networks which we will be able to define as "local")?
Answer: Yes.

To do this, you would use a combination of `<Class>` sections and mod_ifsession's `<IfClass>`, e.g.:

      <Class local>
        From ...
      </Class>

      <IfModule mod_tls.c>
        # Normal mod_tls configuration here

        <IfClass local>
          # Don't require FTPS from local clients
          TLSRequired off
        </IfClass>

        <IfClass !local>
          # Require FTPS from remote/non-local clients
          TLSRequired on
        </IfClass>

      </IfModule>

Question: I have configured my `proftpd` server for FTPS. When I use FileZilla to try to connect to it, though, I see one of these errors in the FileZilla logs:

      GnuTLS error -8: A record packet with illegal version was received
      GnuTLS error -9: A TLS packet with unexpected length was received

Is there a ProFTPD directive to fix this error?
Answer: In most cases, the above client error indicates an error unrelated to SSL/TLS on your server. Check the proftpd debug logging, the `SQLLogFile` if you are using the `mod_sql` module, etc.

Question: When I use FileZilla to connect to my `proftpd` server, it fails, and I see this error:

      gnutls_handshake: An unexpected TLS packet was received.

How to can I connect to my FTPS server using FileZilla?
Answer: The most common cause of this is using a URL such as "ftps://..." in your FileZilla client; for FileZilla, you must use "ftpes://..." (note the e there) when connecting to `proftpd`. Why? Using "ftpes://..." tells FileZilla to use explicit TLS, which is what `proftpd` implements, as that is the RFC-mandated behavior. See:

      https://wiki.filezilla-project.org/SSL/TLS#Explicit_vs_Implicit_FTPS

Question: I'm trying to use `lftp` as my FTPS client for talking to `proftpd`, configured to use `mod_tls`, but it fails to connect. I am using:

      $ lftp ftps://pc -u myuser

What is going wrong?
Answer: You may need to tell `lftp` that using SSL/TLS is allowed when talking to an FTP server:

      $ lftp pc
      lftp> set ftp:ssl-allow yes
      lftp> user user
      ...

or put the above setting in your `~/.lftprc` file.

Note that if you always want `lftp` to use SSL/TLS for FTP sessions, then you would use this setting:

      set ftp:ssl-force yes

Question: What is the difference between the `mod_tls_shmcache` and `mod_tls_memcache` modules?
Answer: Both of these modules are used to support session caching/resumption in `mod_tls`. The difference between these modules is in where the SSL session data is cached/stored.

The `mod_tls_shmcache` module stores SSL session data in a SysV shared memory ("shm") segment, which can be accessed by the different proftpd processes on the same machine. The `mod_tls_memcache` module stores SSL session data in a memcached server (configured using the `mod_memcache` module); this allows different proftpd processes on different machines to access/reuse the cached session data; this can be quite useful when operating a pool of `proftpd` servers e.g. behind a load balancer.

Question: When I try to connect using FTPS to my `proftpd` server, the SSL/TLS connection fails, and I see the following errors in the TLSLog:

      Jul 23 01:15:46 mod_tls/2.4.3[10481]: using default OpenSSL verification locations (see $SSL_CERT_DIR environment variable)
      Jul 23 01:15:46 mod_tls/2.4.3[10481]: error checking key from
        TLSRSACertificateKeyFile '/usr/local/etc/proftpd/ssl/proftpd.key.pem':
        (1) error:140A80B1:SSL routines:SSL_CTX_check_private_key:no certificate assigned
      Jul 23 01:15:46 mod_tls/2.4.3[10481]: error initializing OpenSSL context for this session
      Jul 23 01:15:46 mod_tls/2.4.3[10481]: TLS/TLS-C requested, starting TLS handshake
      Jul 23 01:15:47 mod_tls/2.4.3[10481]: unable to accept TLS connection: protocol error:
        (1) error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher
      Jul 23 01:15:47 mod_tls/2.4.3[10481]: TLS/TLS-C negotiation failed on control channel

What does this mean?
Answer: This error means that, somehow, you have configured a key for a certificate, but do not have the matching certificate configured. For example, if you configured `mod_tls` like so:

      #TLSRSACertificateFile /usr/local/etc/proftpd/ssl/server.cert.pem
      TLSRSACertificateKeyFile /usr/local/etc/proftpd/ssl/proftpd.key.pem

then you would see the above error.

This could also happen if, for some reason, the certificate and key in the configured files were not properly matched up.

© Copyright 2017-2019 The ProFTPD Project
All Rights Reserved