By Weldon Whipple <weldon@whipple.org>
This document tells how I currently implement STARTTLS on my sendmail servers. Hopefully it will give you ideas of things you can do (and maybe shouldn't do). Feel free to send comments, suggestions and corrections--and to set me straight if you think I don't understand something.
After investigation, thought and some trial and error, I have arrived at the following goals for my STARTTLS setup:
I use Cyrus SASL version 2 (from Carnegie Mellon University) to control relaying with AUTH.
My setup doesn't accomplish the following:
I have had only limited success getting e-mail clients and other servers to verify the one commercial SSL certificate I purchased last year. Investigation seems to indicate that the purchased certificate's "purpose" is specifically for https transactions. In conversations between two sendmail servers, I have never seen TLS verification succeed with the commercial cert.Many (user) e-mail clients don't recognize commercial certs. (Those clients that do recognize commercial certificates are generally closely associated with a web browser that also recognizes the certificate.) Even with commercial certificates, it is likely--when the client sends TLS-encrypted e-mail to the STARTTLS-enabled sendmail server for the first time--that the client software will display a dialog that reports an unknown TLS certificate.
If you decide to use commercial certificates, you can skip sections 3 and 4 of this document.
This is a limitation of the SMTP protocol when used on the Internet at large. In fact, since only a miniscule number of public mail servers implement STARTTLS, it is highly unlikely that any given e-mail will remain encrypted during its journey from sender to recipient. (Configured appropriately, private networks can be configured to enforce encryption at every "hop" from sender to recipient.)
This document focuses on basic STARTTLS configuration. It does not (for example) discuss the role of the access database in STARTTLS negotiations, DH parameter tweaks, and other STARTTLS sendmail topics.
These instructions assume that
All of my sendmail servers are running sendmail 8.12.11 or 8.13.0, on FreeBSD 4.x or 5.2.1.
At the time of this writing, I use OpenSSL 0.9.7d.
On FreeBSD, you can install from ports with the following command sequence:# cd /usr/ports/security/cyrus-sasl2 # make # make install # cd /usr/ports/security/cyrus-sasl2-saslauthd # make # make install
To verify that your sendmail supports SASLv2 and STARTTLS, issue the command:"sendmail -d0.1 < /dev/null" from the command line. The "Compiled with" section of the output should include both "SASLv2" and "STARTTLS". Note 2018-11-09: The version of sendmail running on RaspBSD (FreeBSD 11.2 on my old Raspberry PI B 2.1) lacked SASLv2. I had to rebuild sendmail using the instructions in the FreeBSD Handbook section 28.9 (https://www.freebsd.org/doc/handbook/SMTP-Auth.html). I had previously successfully downloaded /usr/ports, which enabled me to install security/cyrus-sasl2 and security/cyrus-sasl2-saslauthd from ports). However, my /tmp directory kept filling up when I tried to download /usr/src. I enlarged the /tmp directory to 2G by editing /etc/fstab and changing the tmpfs line's size value from 50m to 2048m and rebooting. Then I download /usr/src from freebsd.org by using the command:# svn checkout https://svn.freebsd.org/base/releng/11.2 /usr/srcThen I was able to continue with the instructions in the FreeBSD Handbook to rebuild sendmail and verify that it defined both STARTTLS and SASLv2.
Before creating certificates for your sendmail servers, you need to become a certificate authority (CA). Becoming a certificate authority means creating a special certificate authority certificate, which asserts that you have the authority to issue certificates for others (your e-mail server(s) in this case.)
As root, issue the following commands. (Many thanks to Gregory Neil Shapiro, whose instructions are the basis of the following steps.)
If you are generating certs for multiple servers and/or e-mail clients, you should do it on a computer that is fairly secure--some go so far as to say that the computer shouldn't be connected to a network at all. After generating the certs for each computer, I use the scp (secure copy) command to encrypt and copy the certificates and keys to each mail server. (When I am finished creating and distributing certificates to the sendmail servers, I write the certificates, keys, and other working files to a CD-R, then delete all but the files needed for daily operation.)
This command changes to root's home directory, beneath which the generated certificates and keys will be created.
We will be working in the CA ("certificate authority") directory, beneath root's home directory.
The above create some working directories and initialize some files that we will use in generating certs. The "serial" file contains the serial number of the next certificate to be generated. (The openssl command to sign a cert reads the serial number, then uses that number to create an "archive" of certs signed by the certificate authority, stored in the newcerts directory.)
This copies the sample OpenSSL configuration file (shipped with the OpenSSL distribution) to the current directory. If OpenSSL is installed somewhere else on your server, change the first argument of the cp command appropriately. Note 2018-11-09:Although openssl executable is installed on my FreeBSD 11.2 on my Raspberry PI, there is no /usr/local/openssl directory. I see an openssl.cnf in the directory /etc/ssl. Uncertain of what to do, I started to install security/openssl from ports. However, it was taking a long time, so I just issued the command "pkg install openssl111-1.1.1_2" and now see a /usr/local/openssl directory with identical files openssl.cnf and openssl.cnf.dist. I copied openssl.cnf to root's CA directory.
Edit the openssl configuration as indicated in the table below.
(Actually, I prefer to edit with emacs, but use the more ubiquitous vi editor for this example.)
Attribute | Original Value | Change to |
---|---|---|
dir | ./demoCA | . |
Under the [ policy_match ] section: | ||
stateOrProvinceName | match | optional |
organizationalUnitName | optional | match |
commonName | supplied | optional |
Under the [ req_distinguished_name ] section: | ||
commonName | Common Name (eg, YOUR name) | Common Name (eg, host/domain name) |
The above command is what makes you a certificate authority. The CA certificate will end up in the file cacert.pem; the CA's private key will be in private/cakey.pem. I chose to make the certificate good for about 5 years (1825 days).
Here is my interaction with the openssl req command (my input in bold italics):
# openssl req -new -x509 -keyout private/cakey.pem -out cacert.pem -days 1825 -config openssl.cnf Generating a 1024 bit RSA private key ..++++++ .............................................................++++++ writing new private key to 'private/cakey.pem' Enter PEM pass phrase:[Type pass phrase here] Verifying - Enter PEM pass phrase:[Type pass phrase here] ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:. [i.e., type a period] Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]:Whipple Certificate Authority Organizational Unit Name (eg, section) []: Common Name (eg, host/domain name) []: Email Address []: #
Note that I intentionally omitted the Common Name, as I have noticed that commercial CA's generally don't have common names. Some SSL/TLS verification routines object to CA certificates that have common names.If you want to see what your new CA cert looks like, issue this command:
openssl x509 -noout -text -in cacert.pem(If you want to see what it really looks like, I suppose you could try:less cacert.pem:-)
Now that you are a Certificate Authority, you are prepared to issue certificates for your sendmail servers.
Continuing as root (in the same directory as above), issue the following command sequence for each sendmail server:
Here is my interaction with the openssl req command for one of my own servers (my input in bold italics):
# openssl req -nodes -new -x509 -keyout gabriel.pem -out gabriel.pem -days 365 -config openssl.cnf Generating a 1024 bit RSA private key ..................++++++ .....++++++ writing new private key to 'gabriel.pem' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:. [i.e., type a period] Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]:Whipple Website Organizational Unit Name (eg, section) []: Common Name (eg, host/domain name) []:gabriel.whipple.org Email Address []:hostmaster@whipple.org #
The above generates a certificate request, storing the unsigned certificate and private key in the same file, named servername.pem (Substitute your server's name for servername in the command.)If you were purchasing a certificate from a commercial certificate authority, they would have you do something like the above to generate a certificate "request." They you would send them the certificate request. They would sign it and return it to you.
If you prefer, you can specify different files for the -keyout and -out options. (If you were generating the certificate request for a commercial CA, you would want to send them only the request--you wouldn't want them to get their hands on your private key!) In our case, it doesn't hurt to put both the request and the private key in the same file: OpenSSL "tags" the sections of the file, so that commands that use the file for input can find what they are looking for (e.g., the request or the key).
In the following commands, your certificate authority signs the above certificate (for free!).
The above command will prompt you for the CA's pass phrase (the one you entered twice when you created the CA certificate earlier--to make you a certificate authority). Then it will display the certificate that you are signing and ask you if you want to sign the certificate. Respond with 'y'. When it asks you if you want to commit the certified request, respond with 'y'.
The files that sendmail will need (later on in these instructions) are servername.pem (for the private key that it contains) and servername-cert.pem (the server's signed certificate).Notice that we specify "policy_anything" when we sign the certificate, so that it can be used for e-mail. (Commercial CAs generally use a more restrictive policy--which prevents sendmail and many e-mail clients from using them for identity verification.)
When you finish generating and signing certs for all your servers, remove the file tmp.pem:
rm -f tmp.pem
If you want to see what a server cert looks like, issue this command:openssl x509 -noout -text -in servername-cert.pem
Now that you have signed certificates and keys for your sendmail servers, place them on the mail servers, as follows.
The following commands will ensure that the above requirements are met:# cd /etc/mail/certs # chown root * # chmod 0400 *
# cd /etc/mail/certs # ln -s cacert.pem `openssl x509 -noout -hash < cacert.pem`.0
The above reads the cacert.pem file and creates an 8-character cryptographic hash of its contents, which is used as the filename (with '.0' appended) that links to the CA certificate. The "ls -l" command (in the /etc/mail/certs directory) will now show something like:# ls -l total 8 -r-------- 1 root wheel 1139 Mar 15 15:17 cacert.pem lrwxr-xr-x 1 root wheel 18 Mar 16 16:42 c567b670.0 -> cacert.pem -r-------- 1 root wheel 3462 Mar 15 15:13 gabriel-cert.pem -r-------- 1 root wheel 2018 Mar 15 15:13 gabriel-key.pem #During an SSL handshake's certificate exchange, sendmail will compute the the hash of the received CA cert's public key, append '.0' to it, then compare it to its own copy of the CA cert's public key. (This is probably an over simplification, but you get the idea.)
With certificates and keys in place, you are ready to modify the sendmail.cf file. Using your favorite editor, open the macro configuration (mc) file you use to generate your server's sendmail.cf. Add the following directives (in the area of the file that has other "define" statements):
define(`CERT_DIR', `/etc/mail/certs') define(`confCACERT_PATH', `CERT_DIR') define(`confCACERT', `CERT_DIR/cacert.pem') define(`confSERVER_CERT', `CERT_DIR/servername-cert.pem') define(`confSERVER_KEY', `CERT_DIR/servername-key.pem') define(`confCLIENT_CERT', `CERT_DIR/servername-cert.pem') define(`confCLIENT_KEY', `CERT_DIR/servername-key.pem')
The defined macros have the following significance:
When sendmail attempts to verify the host at the other end of an SMTP connection, it creates a hash of the CA information in the presented cert, then checks for a file matching that name in confCACERT_PATH to verify the authenticity of the host's certificate.
If your sendmail server relays e-mail for users who authenticate with SMTP AUTH, you can require that their user name and password be encrypted by including the following line in the mc file:
define(`confAUTH_OPTIONS',`A,p,y')dnl
If you support both encrypted and plaintext SMTP authentication mechanisms, the above will cause the server to offer only encrypted authentication mechanisms until after STARTTLS encryption is negotiated. After STARTTLS has been negotiated, the server will add PLAIN and LOGIN to the AUTH mechanisms it offers in response to EHLO.
By default, sendmail will ask e-mail clients for their SSL/TLS certificates. Since almost no clients have personal TLS certificates, you can tell sendmail to skip the request with the line:
define(`confTLS_SRV_OPTIONS', `V')
After editing your mc file, generate a sendmail.cf. With the new sendmail.cf in place, restart the sendmail daemons.
The sendmail distribution says to use "./Build <cfname>" to generate a cf file from an mc file. On FreeBSD, the command sequence"cd /etc/mail; make; make install; make restart" will generally suffice. The exact command used to build a sendmail.cf file is beyond the scope of this document.
After restarting the sendmail daemons with the new sendmail.cf file, be sure to check the mail log and look for error messages from sendmail, indicating that sendmail might not be working properly. You will also want to try sending some test e-mail and verify that it is delivered.
If you configured STARTTLS properly, you should see mention of STARTTLS in some of the sendmail log entries. It is probably a good idea to telnet to port 25 or 587 of the server just configured, and make sure that it offers STARTTLS in response to the EHLO command. Here is a sample telnet session (my input in bold italics):
weldon@zadkiel:~% telnet gabriel.whipple.org 587 Trying 166.70.98.35... Connected to gabriel.whipple.org. Escape character is '^]'. 220 gabriel.whipple.org ESMTP Sendmail 8.12.11/8.12.11; Thu, 18 Mar 2004 13:30:08 -0700 (MST) ehlo zadkiel.whipple.org 250-gabriel.whipple.org Hello zadkiel.whipple.org [166.70.98.36], pleased to meet you 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-8BITMIME 250-SIZE 250-DSN 250-STARTTLS 250-DELIVERBY 250 HELP quit 221 2.0.0 gabriel.whipple.org closing connection Connection closed by foreign host. weldon@zadkiel:~%
If you see the line 250-STARTTLS in response to the SMTP EHLO command, it indicates that STARTTLS is probably configured correctly.
With STARTTLS configured, you will probably see lines like the following in the mail log file:
Mar 18 00:24:55 gabriel sm-mta[19377]: STARTTLS=server, relay=[204.228.146.20], version=TLSv1/SSLv3, verify=NO, cipher=DHE-RSA-AES256-SHA, bits=256/256
If you see the cipher and bits equates, it indicates that encryption is occuring.
The verify equate caused some confusion the first time I saw it. Here are possibly values that you might see for the verify equate:
OK is quite common when two of my sendmail servers--each configured with certificates signed by my private certificate authority--are communicating with each other. (This happens when my secondary MX server relays mail to my primary MX server.)
This occurs when my client--which doesn't have a private certificate--submits e-mail to my sendmail server. It has no certificate to present, so it doesn't present one.
One reason for this to occur is the inclusion of a line define(`confTLS_SRV_OPTIONS', `V') in the sendmail macro configuration file (which prevents sendmail from asking for client certificates).
This value might be the most common value for the verify equate (?). As long as the cipher and bits equates have meaningful values, encryption is still occuring.
I don't recall ever seeing PROTOCOL or SOFTWARE values in the log file.
Don't overlook the "Sendmail Configuration Files" README (in the sendmail distribution at ./cf/README) or the Sendmail Installation and Operation Guide. The latter is in the sendmail distribution at ./doc/op.
If you can't read the Operation Guide, try issuing the command (with ./doc/op as your current directory):make op.pdf
to create a nicely formatted PDF file. If that doesn't work, then trymake op.txt
for a text version of the file.