ssl_and_tls_gftpd.HOWTO Version 0.1g - July 23th 2002 How To use TLS (and SSL) in gftpd ================================= Contents ======== 1) Installing and Command Line options 2) The TLS configuration file 3) Debugging and Problem Determination 4) X.509 certificates 5) Server Testing 6) Client Testing 7) Client Certificate Mapping APPENDIX A) How to put together a 'cipher list string' APPENDIX B) Resources Please note, the whole TLS vs SSL deal. TLS is SSL v3.1. There is no intended distinction within this HOWTO between SSL and TLS. 1) Installing and Command Line Options ====================================== Assuming that ftpd is running as the ftp service via inetd, edit /etc/inetd.conf and add the TLS parameter to the ftp service call. The TLS parameters are indicted with the '-z' tag and are placed on the command line or in the configuration file. "-z config=FILE" - there is no default value for the config file This parameter specifies the TLS config file that can be used. The config file conists of the TLS parameters (without the "-z" prefix). The file can have comments (lines starting with '#'). This file is useful when the inetd running has a limited length for parameters on the ftpd server command line. See the section on The TLS configuration file later. "-z rsacert=FILE" or "-z cert=FILE" - default value is "ftpd-rsa.pem" This parameter specifies where OpenSSL should get the RSA certificate from. The RSA certificate should be in PEM format (see x.509 discussions below). "-z rsakey=FILE" or "-z key=FILE" - default value is "ftpd-rsa-key.pem" This parameter specifies where OpenSSL should get the RSA Private key from. The RSA Private key should be in PEM format (see x.509 discussions below). "-z dsacert=FILE" - default value is "ftpd-dsa.pem" This parameter specifies where OpenSSL should get the DSA certificate from. "-z dsakey=FILE" - default value is "ftpd-dsa-key.pem" This parameter specifies where OpenSSL should get the DSA Private key from. "-z dhparam=FILE" - default value is "ftpd-dhparam.pem" This parameter specifies where OpenSSL should get the Diffie-Hellman parameters from. "-z crlfile=FILE" - default value is "ftpd-crl.pem" This parameter specifies where OpenSSL should get the Certificate Revocation List file from. "-z crldir=FILE" - there is no default value I really don't know what this does. Perhaps I should ask Pete Runestig "-z cipher=LIST" - default value is "ALL:!EXP" This tells the OpenSSL librraies which Cipher Suites to advertise. (See APPENDIX A) "-z randfile=FILE" - default value is "/usr/local/ssl/.rnd" This tells the OpenSSL code where to get and store random data. A relative path for this file is a BAD idea as it puts a file in the current directory whenever a session is finished. "-z systemcertdir=DIR" - default value is "/usr/local/ftpsd/usercerts" This tells the ftp server where to look for system-wide Certificate mapping files. See the Client Certificate Mapping section later. "-z authmode=OPTION" - default option is "client_can" This tells the OpenSSL libraries what to do about authentication. There are three options. - 'server' The TLS session will not request or use client certificates at all. Only the server will be authenticated. - 'client_can' The TLS session will request a client certificate but will continue if one is not presented. - 'client_must' The TLS session will request a client certificate and will stop if one is not presented. "-z certsok" This flag tells the ftp server not to check the CA, CRL etc... of any presented Client cert. Useful for testing - of dubious value in real life. "-z allow_auth_ssl" This flag tells the ftp server to allow the now deprecated "AUTH SSL" command to trigger the TLS negotiation. This is not recommended, as the bahaviour exhibited by the Server is not in line with RFC2228. Only set this flag if you have awkward clients that insist on using the bad old ways. "-z tlsonly" - This will be set on if --disable-insecure or FORCE_TLS were used at compile time. This flag tells the ftp server to refuse USER commands until the control connection has been succesfully protected. In effect this means that all sessions must be protected by TLS. "-z clientcert" - This will be set on if --disable-insecure or FORCE_TLS were used at compile time. This flag tells the ftp server to refuse to accept PASS as an authentication mechanism. The effect of this is to force the client to authenticate via an X.509 Client certificate. "-z tlsdata" - This will be set on if --disable-insecure or FORCE_TLS were used at compile time. This flag tells the ftp server to refuse to transmit data on data connections that are not protected by TLS. A typical entry in /etc/inetd.conf might look like ftp stream tcp nowait root /usr/sbin/in.gftpd -t5000 -z config=/etc/ftpsd.conf OR ftp stream tcp nowait root /usr/sbin/in.gftpd -t5000 -z tlsonly -z tlsdata 2) The TLS configuration file ============================= The TLS configuration file (specified by "-z config=FILE" on the command line) can contain any of the above TLS parameters (without the "-z " prefix). Parameters on the comand line will override parameters in the configuration file. A sample configuration file might look like # # ftpsd configuration file # # where are our certs/keys # cert=/etc/security/ftpd_cert.pem key=/etc/security/ftpd_key.pem # # we only want weak encryption # cipher=EXP # # let's ensure that the client uses TLS and authenticates via X.509 certs # tlsonly tlsdata clientcert # 3) Debugging and Problem Determination ====================================== Assuming that you have a correctly working ftpd and have now installed the TLS capable one... Try connecting with a normal ftp client. - if the server's TLS configuration is broken then you'll get back a message "530 TLS subsystem failed." Have a look at the syslog ("/var/log/messages" on linux) and see if that has anything useful in it. Unless you are using the "-z tlsonly" option (or if the binary was made with --disable-insecure or FORCE_TLS) then you should be able to use the ftp server as a normal, unprotected server. 4) X.509 certificates ===================== For a basic end-to-end test you'll need 3 certificates. Firstly you'll need a self-signed certificate that will be used to sign the other two (this is the CA certificate). Secondly you'll need a certificate for the server. Finally, you'll need a certificate for the client. The client and server certificates need to be signed by the CA. There are many ways of getting these certificates - this HOWTO will assume you want to do it yourself using the OpenSSL toolkit that you have already got on the box. The sample certificates and keys provided (in the TLS_samp subdirectory) were created from these exact instructions. Feel free to use them as a basic connectivity test; but please do not use them in anger. They afford no security as all the private keys are provided and so anyone can do anything with them. Setting up ftpd to use a self signed CA signed certificate using openssl ------------------------------------------------------------------------ You probably want to be root to do most of this. - create a file containing the CA key's passphrase $ echo CHOOSE_A_GOOD_CA_PASSPHRASE >ca_passphrase - create a file full of random data $ cat /dev/random >.rnd (wait a bit and Ctrl-C) - create a key pair - protected by the passphrase for the CA $ openssl genrsa -des3 -passout file:ca_passphrase -rand .rnd 2048 >cakey.pem - create a CA self signed cert $ openssl req -x509 -new -days 1000 -key cakey.pem \ -passin file:ca_passphrase -out cacert.pem -config cacert.cfg cacert.cfg looks like this ... ----------------------------- [req] distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] C=UK ST=Insecure L=Warwick O=wu_ftpd_HOWTO_sample_CA OU=my_ca_orgunit CN=Do not trust me emailAddress=my_ca@localhost ------------------------------ - create a file full of random data $ cat /dev/random >.rnd (wait a bit and Ctrl-C) - create a server key pair (unprotected) $ openssl genrsa -rand .rnd 1024 >ftpd-rsa-key.pem - create a server certificate signing request $ openssl req -new -key ftpd-rsa-key.pem -out ftpd.csr -config ftpdcert.cfg - create the server cert $ openssl x509 -req -days 999 -in ftpd.csr -out ftpd-rsa.pem \ -CA cacert.pem -CAcreateserial -CAkey cakey.pem -passin file:ca_passphrase ftpdcert.cfg looks like this ... ----------------------------- [req] distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] C=UK ST=my_ftpd_state L=my_ftpd_town O=my_ftpd_org OU=my_ftpd_orgunit CN=localhost emailAddress=my_ftpd@localhost ------------------------------ Now - make sure cakey.pem and ca_passphrase are very secure put ftpd-rsa-key.pem into /usr/local/ssl/private put ftpd-rsa.pem and cacert.pem into /usr/local/ssl/certs create the hashed symlink for the cacert... $ cd /usr/local/ssl/certs $ ln -s cacert.pem `openssl x509 -hash -noout -in cacert.pem`.0 The hashed symlink allows the OpenSSL libraries to look for the CA's certificate in any client or server that it is trying to verify. You'll need this symlink (and the cacert.pem file) on any box that uses OpenSSL for this purpose. This sorts out the server's certificate. (time to hack inetd.conf and refresh inetd) You can test this works by ftp-ing to the sever and checking you get the 220 welcome reply. Using a client cert with ftp-tls and ftpd-tls --------------------------------------------- This assumes that you have set up the CA and ftpd certs as described above. Create a certificate using openssl ---------------------------------- - create a file full of random data $ cat /dev/random >.rnd (wait a bit and Ctrl-C) - create a client key pair $ openssl genrsa -passout pass:password -rand .rnd 1024 >client-key-pass-is-password.pem - create a client certificate signing request $ openssl req -new -key client-key-clear.pem -out client.csr \ -config clientcert.cfg - create the client cert $ openssl x509 -req -days 999 -in client.csr -out client-cert.pem \ -CA cacert.pem -CAcreateserial -CAkey cakey.pem -passin file:ca_passphrase clientcert.cfg looks like this ... ----------------------------- [req] distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] C=UK ST=my_client_state L=my_client_town O=my_client_org OU=my_client_orgunit CN=my_client emailAddress=my_client@localhost ------------------------------ - if your application needs a PKCS#12 file (.p12) instead of the various PEM encoded files, use this command to create it. $ openssl pkcs12 -in client-cert.pem -inkey client-key-pass-is-password.pem \ -export -des3 -passout pass:password -passin pass:password -CAfile \ cacert.pem -chain -out client-key-and-cert.p12 5) Server Testing ================= This is pretty much covered elsewhere. 6) Client Testing ================= GFTPD does NOT support incorrectly coded clients that require "334" instaed of "234" as a reply. GFTPD SSL/TSL has been tested OK against: 1. tslwrapper http://tlswrap.sunsite.dk/ (wrapper: unix & cygwin windows) 2. winsslwrap http://pftp.suxx.sk/winsslwrap/HOW-TO/ (wrapper: windows) 3. Pete Runestig's BSD based ftp client (client: unix) 4. ws_ftp 6.60+ (client: windows) Implementation follows http://www.ietf.org/internet-drafts/draft-murray-auth-ftp-ssl-09.txt, so it should work on all valid SSL/TSL clients or normal ftp clients using wrappers in passive mode. If you want to autologin using the ftpd-tls default mechanism see the section about Client Certificate Mapping. For Pete Runestig's BSD based ftp client ... ---------------------------------------- $ ftp -z key=client-key-pass-is-password.pem -z cert=client-cert.pem \ -z certsok localhost We use the "-z certsok" flag to stop warnings about the CA and the hostname. Once your basic testing is complete, you should remove this flag and address any issues that are then caused. For IPSwitch's ws_ftp (6.60+) ... ----------------------------- You need the server to have the "-z allow_auth_ssl" flag set. You need cacert.pem, client-key-pass-is-password.pem and client-cert.pem; but you need to copy or rename the 'cacert.pem' file to 'cacert.crt'; the 'client-cert.pem' file to 'client-cert.crt' and the 'client-key-pass-is-password.pem' file to 'client-key-pass-is-password.key'. Go to 'View' -> 'Configure SSL...' In the 'Certificate Selection' tab, enter 'client-key-pass-is-password.pem' into the 'Private Key' field; 'client-cert.pem' into the 'Certificate' field and 'password' into the two 'Pass phrase' fields. In the 'Trusted Authorities' tab, click on the 'Import' button and select the 'cacert.crt' file. Now, on the connection pop-up - check the 'Secure (SSL)' box and try to connect. 7) Client Certificate Mapping ============================= The first thing to understand is that, although Client Certificates can identify the user to the server, the FTP 'USER' command still needs to be issued and the parameter to that command is treated as the user that is trying to authenticate. Out of the box, there are two mechanisms to map certificates to users. If you want to get your hands dirty then the x509_to_user.c file can be hecked to your needs. Administrator-centric Mapping ----------------------------- The directory pointed at by the "-z systemcertsdir=DIR" parameter contains a collection of files. The name of a file is the name of the system user and corresponds to the parameter that the client passes on the "USER" command. When a TLS authenticated user issues the "USER xxx" command, the ftp server will check the systemcertsdir for a file called 'xxx' and verify that the certificate used for the TLS authentication is contained in the file. If the certificate is present in the file then the '232' reply will be sent to the client, indicating that the authentication phase is complete (no PASS command is requested). If the file exists but does not contain the certificate presented on the TLS session then the '331' reply is sent to the client, which demands a password. If the file does not exist then the User-centric Mapping process is invoked. User-centric Mapping -------------------- If the systemcertsdir does not exist, or there is no file with the name of the user in it, then the ftp server will look into the user's home directory for a file called ".tlslogin" If this file exists and contains the certificate that the TLS session is protected with, then the user is logged straight in (with the '232' reply). Otherwise a password is requested (by the '331' reply). APPENDIX A) How to put together a 'cipher list string': ======================================================== This discusses the parameter to the "-z cipher=" option Key Exchange Algorithms: "kRSA" RSA key exchange "kDHr" Diffie-Hellman key exchange (key from RSA cert) "kDHd" Diffie-Hellman key exchange (key from DSA cert) "kEDH' Ephemeral Diffie-Hellman key exchange (temporary key) Authentication Algorithm: "aNULL" No authentication "aRSA" RSA authentication "aDSS" DSS authentication "aDH" Diffie-Hellman authentication Cipher Encoding Algorithm: "eNULL" No encodiing "DES" DES encoding "3DES" Triple DES encoding "RC4" RC4 encoding "RC2" RC2 encoding "IDEA" IDEA encoding MAC Digest Algorithm: "MD5" MD5 hash function "SHA1" SHA1 hash function "SHA" SHA hash function (should not be used) Aliases: "ALL" all ciphers "SSLv2" all SSL version 2.0 ciphers (should not be used) "SSLv3" all SSL version 3.0 ciphers "EXP" all export ciphers (40-bit) "EXPORT56" all export ciphers (56-bit) "LOW" all low strength ciphers (no export) "MEDIUM" all ciphers with 128-bit encryption "HIGH" all ciphers using greater than 128-bit encryption "RSA" all ciphers using RSA key exchange "DH" all ciphers using Diffie-Hellman key exchange "EDH" all ciphers using Ephemeral Diffie-Hellman key exchange "ADH" all ciphers using Anonymous Diffie-Hellman key exchange "DSS" all ciphers using DSS authentication "NULL" all ciphers using no encryption Each item in the list may include a prefix modifier: "+" move cipher(s) to the current location in the list "-" remove cipher(s) from the list (may be added again by a subsequent list entry) "!" kill cipher from the list (it may not be added again by a subsequent list entry) If no modifier is specified the entry is added to the list at the current position. "+" may also be used to combine tags to specify entries such as "RSA+RC4" describes all ciphers that use both RSA and RC4. For example, all available ciphers not including ADH key exchange: ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP All algorithms including ADH and export but excluding patented algorithms: HIGH:MEDIUM:LOW:EXPORT56:EXP:ADH:!kRSA:!aRSA:!RC4:!RC2:!IDEA The OpenSSL command openssl ciphers -v may be used to list all of the ciphers and the order described by a specific . APPENDIX B) RESOURCES ===================== Pete Runestig's ProFTPd, OpenBSD ftpd and ftp ftp://ftp.runestig.com IPSwicth ws_ftp client for windows http://www.ipswitch.com Kermit kftp http://www.kermit-project.org/security.html State of the Union for ftp and ssl http://ww.ford-hutchinson.com/~fh-1-pfh/ftps-ext.html OpenSSL http://www.openssl.org wu-ftpd http://wu-ftpd.org gftpd http://www.gftpd.org