Chapter 5. Authentication and Encryption

In this chapter, we cover two ways to protect your email server and the mail it handles:[82]

  • SMTP AUTH prevents untrusted machines from using your mail server to send undesirable mail. It also enables client sendmail machines to authenticate themselves to a server for outbound relaying.

  • Public/Private Key Cryptography provides the underpinnings used by STARTTLS. STARTTLS encrypts email content to prevent it from being snooped.

Support SMTP AUTH

Support for the SMTP extension AUTH, as defined by RFC2554, was first included in sendmail beginning with V8.10. In this section, we show how to include AUTH support inside sendmail, how to verify that it works, and finally, how to use it with a server and with a client. First, you will likely need to:

  • Download, compile, install, and configure the Cyrus SASL library.

  • Build and install sendmail with SASL support included.

Depending on whether you manage a server or a client you may also need to:

  • Configure your server sendmail machine to require AUTH.

  • Configure your client sendmail machine to use AUTH.

Before we begin, however, let’s consider why you might want AUTH support and why you might not need it.

SMTP AUTH is intended to prevent untrusted machines from using mail server machines to send undesirable mail, such as spam. If yours is just a lone Linux box used to send and receive personal email (and you don’t travel), SMTP AUTH will probably not be of use to you on your server, but it might still be of use to you for a client.

For SMTP AUTH to have value to a server, that server must be on a network that supports laptops or other portable machines that can be removed and installed without system administration oversight, and where those machines all need to trust each other. The larger your site, the more likely it is that you will need to use SMTP AUTH as one more layer of email protection for your server. A mail gateway machine that is a frontend for many PC and laptop machines is one situation where such trust is desirable, and we will use it as an example later in this section.

In AUTH Running As a Client on page 195, we show you how to set up sendmail as a client that connects to a server that requires AUTH.[83]

Get and Install the SASL Library

As of this writing, the Cyrus SASL library is available from ftp://ftp.andrew.cmu.edu/pub/cyrus-mail. But be sure you download and install the latest version. As of this writing, version 2.1.22 is the latest, and is the one officially supported by V8.14 and later sendmail. This is the version we document here and refer to as V2. The old Cyrus SASL versions 1.y.z are referred to, collectively, as V1.

Note that you need to download and install Cyrus SASL whether you are using your machine as a server or a client. The same library support is required for both roles.

After you have downloaded and extracted the source, first examine the file INSTALL. It tells you how to build and install the library. The first step is to configure the package for your machine:

# ./configure --help | more

This command shows all the ./configure command-line switches that you may choose from. Each determines how this library will be built and where it will be installed. For example, the following command line causes support for LOGIN authentication to be included in the resulting library:

# ./configure --enable-login -q

Note that here the -q tells ./configure to print only errors and warnings. Without the -q any errors might scroll off the screen, thereby causing you to miss them.

Be patient. This ./configure step can be quite slow on some machines, but pay attention to any warnings. For example:

configure: warning: No DES library found for Kerberos V4 support

A warning such as this indicates that you will not be able to perform DES encryption unless you download and install the DES library.[84] The second step is to compile (build) the library. Just enter the following command:

# make

If your compile fails, first look through the documentation that was supplied with the source. If you don’t find your answer there, visit this web site for additional help: http://asg.web.cmu.edu/sasl/.

The last step is to install the package, like this:

# make install

By default, the package installs its plug-ins in /usr/local/lib/sasl2 (/usr/local/lib/sasl for V1). But the library looks for them in /usr/lib/sasl2 (/usr/lib/sasl for V1).[85] Although the install process won’t make a link[86] for you, we recommend you create the required link using commands such as the following:

# cd /usr/lib
# ln -s ../local/lib/saslV1
# ln -s ../local/lib/sasl2V2

Be aware that these directories need to be secure. That is, they need to live in paths, all components of which are writable only by root and owned by root. On our system, the following command showed that permissions were correct:

% ls -ld / /usr /usr/lib /usr/lib/sasl* /usr/local /usr/local/lib /usr/local/
lib/sasl*
drwxr-xr-x  18 root  wheel   512 Mar 15 20:08 /
drwxr-xr-x  22 root  wheel   512 Sep 29  2000 /usr/
drwxr-xr-x   4 root  wheel  7168 Jan  3 11:34 /usr/lib/
lrwxr-xr-x   1 root  wheel    19 Jan  3 11:34 /usr/lib/sasl@ ->
    /usr/local/lib/sasl    ← V1
lrwxr-xr-x   1 root  wheel    19 Jan  3 11:34 /usr/lib/sasl2@ ->
    /usr/local/lib/sasl2   ← V2
drwxr-xr-x  18 root  wheel   512 Oct 11  2000 /usr/local/
drwxr-xr-x   9 root  wheel  2560 Jan  3 11:29 /usr/local/lib/
drwxr-xr-x   2 root  wheel   512 Jan  3 11:29
    /usr/local/lib/sasl/   ← V1
drwxr-xr-x   2 root  wheel   512 Jan  3 11:29
    /usr/local/lib/sasl2/  ← V2

If you install openssl in directories different from those shown earlier, you will later need to specify those new locations when you build sendmail, as shown in Add SASL Support to sendmail on page 187.

In addition, because sendmail does not trust shared libraries that are not in trusted locations, be aware that you may also need to link or copy the sasl shared libraries into the /usr/lib directory:

# cd /usr/lib
# ln -s ../local/lib/libsasl*                                 ← V1 link
# cp ../local/lib/libsasl* .                                  ← V1 copy
# ln -s ../local/lib/libsasl2* .                              ← V2 link
# cp ../local/lib/libsasl2* .                                 ← V2 copy

To tune the SASL library for your site, you need to decide how you want passwords validated. We cover this next, but first we need to discuss the sasldb database.

Note that the sasldb database provides the means to set up accounts for email that are separate from the user accounts that normally exist on your machine. If you wish to use only existing accounts, we have finished tuning your SASL library and you may skip to Install Sendmail.conf on page 186.

The saslpasswd2 program (or for V1, the saslpasswd program) is located in the util subdirectory of the SASL source tree and is installed in the /usr/local/sbin directory. It is used to set up user accounts that exist only for email:

# /usr/local/sbin/saslpasswd userV1
# /usr/local/sbin/saslpasswd2 userV2

Here, user is the login name of the user for whom you wish to set up an SASL authentication password.[87] These user accounts and passwords are stored in the sasldb database.

Install Sendmail.conf

The last step when tuning SASL is to create a file called Sendmail.conf in the /usr/lib/sasl2/ directory (or for V1, the /usr/lib/sasl/ directory). At a minimum, one line should appear in that file and that line should indicate your preferred password verification method:

pwcheck_method: method

Here, method is selected from the methods listed in Table 5-1.

Table 5-1. Valid pwcheck_method methods for Sendmail.conf

Method

Description

saslauthd

Connect to the saslauthd(8) program for all authentication. That program is usually installed in /usr/local/sbin and must be started as a daemon automatically if you use it.

sasldb

The user is looked up in sasldb (see above). For CRAM-MD5 and PLAIN, an @host.domain for the local host is appended to the user as the default realm for the lookup, if a realm is not otherwise specified.[a]

passwd

The user is looked up by sendmail via the sasl library using the getpwnam(3) C-Language library routine.

shadow

The user is looked up by sendmail via the sasl library using the getpwnam(3) C-Language library routine.

PAM

The user is looked up by sendmail via the sasl library using the PAM mechanism.

kerberos_v4

The user is looked up by sendmail via the sasl library using the KERBEROS V4 mechanism.

pwcheck

Synonym for saslauthd

[a] a This behavior has been an integral part of sasl since V1.5.20.

If you chose a method that is unsupported, sendmail will log the following warning and disallow the authentication:

Dec 14 09:49:31 your.host.domain sendmail[6985]: unknown password verifier

In the next section, we show how to run sendmail in a manner that allows you to determine whether it supports the method you’ve chosen.

Add SASL Support to sendmail

To add support for the SASL libraries to sendmail, just add one of the following pairs of lines to your Build m4 file:

APPENDDEF(`confENVDEF', `-DSASL=1')                       ← V1
APPENDDEF(`conf_sendmail_LIBS', `-lsasl')                 ← V1
APPENDDEF(`confENVDEF', `-DSASL=2')                       ← V2
APPENDDEF(`conf_sendmail_LIBS', `-lsasl2')                ← V2

The first line causes SASL support to be included in the sendmail program.[88] The second line tells sendmail to use the V1 or V2 SASL library, respectively. If you installed the SASL library in the standard location as described in the previous section, these two additional Build lines might be all you need.

Now build sendmail as usual. If you get the following error (or something similar):

sendmail.h:127: sasl.h: No such file or directory

you will have to add a line that looks something like the following to your Build m4 file:

APPENDDEF(`confINCDIRS', `-I/disk/3/packages/sasl/include')
                             ↑
        the path to where the SASL include files are located

Another possible problem might be that the SASL library cannot be found. In that instance, an error message such as the following might appear:

ld: cannot open -lsasl: No such file or directory

To correct this problem, simply add the following line to your Build m4 file:[89]

APPENDDEF(`confLIBDIRS', `-L/disk/3/packages/sasl/lib')
                             ↑
           the path to where the SASL library is located

But be careful about where you locate this library. The SASL library is a shared library and as such is subject to security restrictions. When sendmail runs, it ignores LD_LIBRARY_PATH and so cannot find shared libraries that are not in your operating system’s default locations. Typically, that trusted location is /usr/lib, and sometimes /usr/local/lib. If sendmail appears to build correctly, but doesn’t produce the AUTH keyword as shown next, the problem might be that your location for the SASL library is bad.

Test SASL support in sendmail

Before you install sendmail, test it to be sure the added SASL support has worked. You can do this by running sendmail from the directory in which it was built. Note that you must do this as root:

# obj.*/sendmail/sendmail -bs -Am

Here, we run the newly built sendmail relative to the source directory. The -bs tells sendmail to speak SMTP on its standard input. The -Am tells sendmail to use its server configuration file (not submit.cf), even though it is running in mail-submission mode. Such a test session might look like this:

220 your.host.domain ESMTP Sendmail 8.14.1/8.14.1; Fri, 14 Dec 2007 11:43:02 −0700
(PST)
ehlo your.host.domain
250-your.host.domain Hello root@localhost, pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH DIGEST-MD5 CRAM-MD5                  ← note this line
250-DELIVERBY
250 HELP
quit
221 2.0.0 your.host.domain closing connection

Here, the AUTH SMTP keyword appears, indicating that this site supports SASL authentication and two modes of authentication as shown earlier.

If the AUTH keyword does not appear, you have a problem. First, be sure you ran the test as root. If you ran as root and the test still failed, examine your syslog file. Look for a line that contains the word SASL. One such error might look, in part, like this:

SASL error: listmech=0, num=0

Here, zero authentication mechanisms were found (the num=0). One possible reason might be that you did not install the SASL library in a path that was acceptable for shared libraries. Another possible reason for this error might be that you have not set up any mechanisms yet. Consider running the saslpasswd2(8) or saslpasswd(8) program as described in Get and Install the SASL Library on page 184.

If no SASL lines appear in your syslog file, look for errors relating to permissions. One possible error might be that the /etc directory is unsafe.[90] Another might be that the directory pointed to by the symbolic link /usr/lib/sasl2, or /usr/lib/sasl, is unsafe. Revise any offending permissions and rerun the test until it succeeds.

If no problems appear in your syslog file, and AUTH still fails to appear, consider increasing the LogLevel setting in sendmail to 13, while running the test again:

# obj.*/sendmail/sendmail -OLogLevel=13 -bs -Am

Then recheck your logfile for additional error information.

Watch authentication in action

To debug authentication before using it to send and receive real email, we recommend you first set up an authenticating sendmail test daemon that listens on a non-standard port and is bound to the loopback interface. That way, you can test without interfering with real email on your system. To begin, set up the following minimal mc configuration file in the cf/cf directory under the sendmail source and call it test.mc:

OSTYPE(linux)
FEATURE(no_default_msa)
DAEMON_OPTIONS(``A=localhost, P=26, N=authsmtp, M=a'')
MAILER(smtp)

Here, you should replace linux with the type of your operating system (Relays on page 602). The second line (the no_default_msa feature; FEATURE(no_default_msa) on page 635) disables all listening daemons. The second from last line (the DAEMON_OPTIONS; DaemonPortOptions on page 993) declares a single daemon with the name authsmtp that will bind to localhost (the loopback interface) and will listen on the nonstandard port numbered 26.[91] The M=a tells this server to always require connection authentication. The last line (the MAILER; MAILER( ) m4 macro on page 590) allows mail to be relayed using smtp over the Internet.

Save this text to a file named test.mc, and then run the following command in the cf/cf directory to create a cf file from that mc file:

# make test.cf
rm -f test.cf
m4 ../m4/cf.m4 test.mc > test.cf || ( rm -f test.cf && exit 1 )
echo "### test.mc ###" >>test.cf
sed -e 's/^/# /' test.mc >>test.cf
chmod 444 test.cf

You may then perform your tests by running the following command in one window while sending email in another:

# ../../obj.*/sendmail/sendmail -Ctest.cf -X/tmp/auth.log -bD

Here, the -X command-line switch (Log Transactions with -X on page 512) causes a copy of any SMTP transactions to be saved in the file /tmp/auth.log. The -bD runs sendmail as a daemon but leaves it connected to your keyboard so that you can easily stop and restart it.

After running these tests, you should test with an email client that can use AUTH for sender authentication. If you use Thunderbird, for example, select Preferences, and then select Outgoing Server. Change the port to the port you specified earlier (the P=26 for port 26). Also put a check in the box that says “Use name and password.” Then enter the appropriate username for testing. If a realm is required, this may have to be in form.

Now, send an email message. After it is sent or fails, exit sendmail and look at the /tmp/auth.log file you created. If the test has failed, the contents of that file may look, in part, like this:

13885 >>> 250-AUTH GSSAPI DIGEST-MD5 CRAM-MD5
13885 >>> 250-DELIVERBY
13885 >>> 250 HELP
13885 <<< AUTH CRAM-MD5
13885 >>> 334 PW4gPDIyMDg3MzU4ODAuMTI1NTgxMzFAeW91ci5ob3N0LmRvbWFpbj4K
13885 <<< dGVzdGVyQGxvY2FsaG9zdCAzMDRhNDAwMTBmYWE5MjhiOWYzZTllZmIyOTJkODYxMQ==
13885 >>> 535 5.7.0 authentication failed
13885 <<< [EOF]
13885 >>> 421 4.4.1 your.host.domain Lost input channel from localhost [127.0.0.1]

Here, CRAM-MD5 was the only authentication mechanism offered by sendmail and so was the only mechanism used by Thunderbird, and the test failed. To fix this, we will try to add the PLAIN authentication mechanism to the test.mc file (we cover confAUTH_MECHANISMS in the next section), by adding the following line to the test.mc file and rebuilding the cf file:

define(`confAUTH_MECHANISMS', `CRAM-MD5 PLAIN')

After you build a new test.cf file, run the same test again. This time, authentication succeeds and the /tmp/auth.log file contains, in part, lines like the following:

14062 >>> 250-AUTH CRAM-MD5 PLAIN
14062 >>> 250-DELIVERBY
14062 >>> 250 HELP
14062 <<< AUTH CRAM-MD5
14062 >>> 334 PW4gPDIyMDg3MzU4ODAuMTI1NTgxMzFAeW91ci5ob3N0LmRvbWFpbj4K
14062 <<< dGVzdGVyQGxvY2FsaG9zdCAzMDRhNDAwMTBmYWE5MjhiOWYzZTllZmIyOTJkODYxMQ==
14062 >>> 535 5.7.0 authentication failed
14062 <<< AUTH PLAIN dGVzdHVzZXJcMFRlc3RQYXNzd2QK
14062 >>> 235 2.0.0 OK Authenticated

Here, CRAM-MD5 fails as before, but now Thunderbird tries the PLAIN authentication mechanism and that mechanism succeeds with “235 2.0.0 OK Authenticated”.

Note that you should probably not use PLAIN if you are expecting authentication over the Internet, because it allows usernames and passwords to pass in the clear.[92] To see for yourself, use mimencode(1) or a similar program to decode the expression following AUTH PLAIN earlier. You will see the following, when you decode it:

testuser\0TestPasswd

If the -X file does not give you enough information to solve your problem, try increasing the log level to 13 as we described earlier, and examine your logs for additional information:

# ../../obj.*/sendmail/sendmail -Ctest.cf -X/tmp/auth.log -bD -OLogLevel=13

SASL and Your mc File

V8.10 sendmail and later offer macros for your mc configuration file that help with your SASL settings. We will cover them soon, but first we must describe two concepts central to SASL and its use: authorization and authentication.

Authorization refers to a user’s permission to perform certain actions. One form of authorization, for example, might be to allow a user to relay mail through your mail hub machine. In general, authorization is associated with a user’s identifier (userid), which may be the username or something more complex.

Authentication refers to the validation of a user or machine’s identity. One form of authentication, for example, might be the recognition that a laptop is a company-owned machine. Authentication is communicated inside credentials (more on this soon) and is associated with a client’s identifier (authid).

Your server requires AUTH

Your server can require AUTH for all connections only if it is not connected to the Internet for inbound email. For example, if your server functions as an outbound-only relay for machines behind a firewall, it might be appropriate to require AUTH for all connections.

For a normal server, one which functions as both an outbound relay and an inbound mail server, AUTH should be required only to enable relaying.

In general, the outbound role is handled by requiring AUTH upon connection, and the inbound role is based on the envelope sender. The two can, however, be combined, as when an AUTH mechanism (like CRAM-MD5) must be valid before the envelope sender may be checked.

The AuthMechanisms option (AuthMechanisms on page 975) is used to define a list of mechanisms that can be used to authenticate a connection. If, for example, you wish to limit your authentication mechanisms to just CRAM-MD5, you can define confAUTH_MECHANISMS in your mc file like this:

define(`confAUTH_MECHANISMS', `CRAM-MD5')

This only defines the mechanisms that will be required if AUTH is required for inbound connections. Whether or not connections must be authenticated is determined by the setting of the DaemonOptions option (discussed shortly).

The class $={TrustAuthMech} contains a list of authentication mechanisms that allow relaying. It must contain a subset, or a matching set,[93] of the list of all authentication mechanisms defined with the AuthMechanisms option, described earlier. For example:

TRUST_AUTH_MECH(`CRAM-MD5')

Here, sendmail will authenticate using that mechanism, and that authentication (if successful) will provide an authorization to relay.

AUTH realm

Prior to V8.13 sendmail, if authentication required a realm, the value of the $j macro (the canonical name of the local host) was used as the realm. Beginning with V8.13, the AuthRealm option (AuthRealm on page 978) can be invoked to define a realm to use in place of the value of the $j macro:

define(`confAUTH_REALM', `our.domain')

You may wish to define a different realm if your server has multiple network interfaces, and sendmail chooses as the value of $j the canonical name associated with the wrong interface. Or you may wish to define a different realm if you want to use your own domain name, rather than the host’s canonical name. Whatever your need, this confAUTH_REALM m4 macro allows you to define a realm of your choice.

The AuthOptions option

The AuthOptions option (AuthOptions on page 977) is used to specify how authentication should be handled by your server (or client; see AUTH Running As a Client on page 195). For example, if you wish to disallow any mechanism that permits anonymous logins, you would specify the y setting for this option:

define(`confAUTH_OPTIONS', `y')

The complete list of characters that determine AUTH usage and policy are listed in Table 5-2. Each character sets a single tuning parameter. If more than one character is listed, each character must be separated from the next by either a comma or a space:

define(`confAUTH_OPTIONS', `A y')
define(`confAUTH_OPTIONS', ``A,y'')

Note that if you use a comma, the entire expression must be doubly quoted.

Table 5-2. AuthOptions character settings

Character

Meaning

A

Use the AUTH= parameter from the MAIL From: command only when authentication succeeds. This character can be specified as a workaround for broken mail transfer agents (MTAs) that do not correctly implement RFC2554. (Client only)

a

Provide protection from active (nondictionary) attacks during the authentication exchange. (Server only)

c

Allow only selected mechanisms (those that can pass client credentials) to be used with client credentials. (Server only)

d

Don’t permit use of mechanisms that are susceptible to passive dictionary attacks. (Server only)

f

Require forward secrecy between sessions (where breaking one won’t help to break the next). (Server only)

m

Require the use of mechanisms that support mutual authentication. (Server only) (V8.13 and later)

p

Don’t permit mechanisms to be used if they are susceptible to simple passive attack (that is, disallow use of PLAIN and LOGIN), unless a security layer is already active (as, for example, provided by STARTTLS). (Server only)

T

The opposite of A (pre-V8.12 only, client only)

y

Don’t permit the use of any mechanism that allows anonymous login. (Server only)

If you are also using STARTTLS (STARTTLS on page 202), you may want to also define the AuthMaxBits option (AuthMaxBits on page 975) to suppress encryption within encryption when the CRAM-MD5 mechanism is used.

The M=a for the DaemonPortOptions option (DaemonPortOptions=Modify= on page 996) determines whether the connection must be authenticated for all connections, or whether only a sender that tries to relay must be authenticated. You saw examples of M=a (earlier) that require connection authentication for all inbound connections to the server. To turn that off and only require the sender to authenticate, use M=A. For example:

DAEMON_OPTIONS(``..., M=A'')

With this M=A setting, you can screen individual users for relaying permission using rule sets, as we demonstrate next. If your server receives mail from the Internet, you must use M=A instead of M=a.

SASL and Rule Sets

The SMTP AUTH extension, enabled by SASL, allows client machines to relay mail through the authentication-checking server. This mechanism is especially useful for roaming users whose laptops seldom have a constant IP number or hostname assigned.[94] A special rule set called trust_auth, found inside the sendmail configuration file, does the actual checking. This rule set decides whether the client’s authentication identifier (authid) is trusted to act as (proxy for) the requested authorization identity (userid). It allows authid to act for userid if both are recognized, and disallows that action if the authentication fails.

Another rule set, called Local_trust_auth, is available if you wish to supplement the basic test provided by trust_auth. The Local_trust_auth rule set can return the #error delivery agent to disallow proxying, or it can return OK to allow proxying.

Within the Local_trust_auth rule set you can use three new sendmail macros (in addition to the other normal sendmail macros). They are:

{auth_authen}

The client’s authentication credentials as determined by the authentication process (see ${auth_authen} on page 804).

{auth_author}

The authorization identity as set by issuance of the SMTP AUTH= parameter (see ${auth_author} on page 805). This could be either a username or a user@host.domain address.

{auth_type}

The mechanism used for authentication (see ${auth_type} on page 806), such as CRAM-MD5 and PLAIN.

These three macros can also be used in any of the relay-testing rule sets to determine whether a particular user may relay. To illustrate, consider a rule set designed to allow senders with local accounts on the local machine to relay only if authenticated:

LOCAL_RULESETS
SLocal_check_rcpt
R$*                     $: $&{auth_type} $| $&{auth_authen}
RDIGEST-MD5 $| $+@$=w   $# OK
RCRAM-MD5 $| $+@$=w      $# OK

Here, the Local_check_rcpt rule set (Local_check_rcpt and check_rcpt on page 257) is called to validate the envelope recipient. The first rule (R line) replaces the workspace (the $* on the left) with three values: the current value of the ${auth_type} macro (${auth_type} on page 806); a $| literal; and the current value of the ${auth_authen} macro (${auth_authen} on page 804). If the authentication type is either DIGEST-MD5 or CRAM-MD5 and if the domain is in the class $=w (is a local hostname or address), the envelope sender is allowed to relay. But if the ${auth_type} macro’s value is empty (nothing was authenticated), or if the authentication was by an untrusted mechanism, such as PLAIN, the envelope sender is not allowed to relay.

AUTH Running As a Client

For V8.10 and V8.11, the default authorization information for the local machine acting as a client is contained in the file /etc/mail/default-auth-info. Beginning with V8.12, that information is contained in the access database, unless you tell sendmail otherwise by declaring the authinfo feature (FEATURE(authinfo) on page 616):

FEATURE(`authinfo')  ← V8.12 and later

The file or database, if present, must live in a safe directory and must be given secure permissions. It contains the information needed to authenticate a client (outbound) connection, and its contents are described in detail in DefaultAuthInfo on page 999. Note that the DefaultAuthInfo option is deprecated as of V8.12, and the information in that file is instead looked up by default in the access database.

If you wish to force all connections to be authenticated, you can do so by specifying the a key letter to the DaemonPortOptions option (DaemonPortOptions on page 993). But note that you must not do this on a publicly accessible MTA that serves the Internet. You should do it only on client machines on your internal network, where those client machines connect only to your Internet mail server:

define(`confDAEMON_OPTIONS',`a')     ← V8.9 only
DAEMON_OPTIONS(`M=a')                ← V8.10 and later

Authinfo and the access database (V8.12 and later)

Under V8.12, default client authentication information was moved out of the default-auth-info text file and into the access database. If you prefer a more secure database than the access database, you can declare an alternative with the authinfo feature (FEATURE(authinfo) on page 616). For example:

FEATURE(`authinfo')

Here, instead of looking up client authentication information in the access database, sendmail will look in the /etc/mail/authinfo database.

Whether you store default client authentication information in the access database or in the authinfo database, the syntax of entries is the same.

The database entries are created from a text file that has keys down the left column and matching values down the right. The two columns are separated by one or more tab or space characters.[95] One line in such a source text file might look like this:

AuthInfo:address      "U:user"  "P=password"    ← V8.12 and later

The left column of the database is composed of two parts. The first part is mandatory, the literal expression AuthInfo:. The second, configurable part is an IPv4 address, an IPv6 address, or a canonical host or domain name. For example:

AuthInfo:123.45.67.89                       ← an IPv4 address
Authinfo:IPv6:2002:c0a8:51d2::23f4          ← an IPv6 address
AuthInfo:host.domain.com                    ← a hostname
AuthInfo:domain.com                         ← a domain name

When sendmail connects to another host, and that other host offers to authenticate, that connected-to host’s IP address, hostname, and domain are looked up in the database.

If the IP address, host, or domain is not found, the connection is allowed, but sendmail will not attempt to authenticate it. Otherwise, the information in the matching right column is returned for sendmail to use.

The right column is composed of letter and value pairs, each pair quoted and separated from the others by space characters:

AuthInfo:address      "U:user"  "P=password"

Letters are separated from their value with a colon or an equal-sign. A colon means that the value is literal text. An equal-sign means that the value is Base64-encoded.

These letters and their meanings are shown in Table 5-3.

Table 5-3. Right-column key letters for the default authinfo file

Letter

Description

U

The user (authorization) identifier

I

The authentication identifier

P

The password

R

The realm

M

The list of mechanisms (separated by spaces)

Either the U or the I, or both, must exist or authentication will fail. The P must always be present. The R and M are optional. All the letters are case-insensitive—that is, U and u are the same.

The U lists the name of the user that sendmail will use to check allowable permissions. Generally, this could be U:authuser (but it should never be root).

The I lists the name of the user allowed to set up the connection. Generally, this could be I:authuser (but it should never be root).

The P value is the password. If the P is followed by a colon (as P:), the password is in plain text. If the P is followed by an equal-sign (P=), the password is Base64-encoded. Generally, this should never be root’s plain-text password.

The R lists the administrative realm for authentication. In general, this should be your DNS domain. If no realm is specified (this item is missing), sendmail will substitute the value of the $j macro ($j on page 830) unless the AuthRealm option (AuthRealm on page 978) is used to define a realm to use in place of the value of the $j macro.

The M lists the preferred mechanism for connection authentication. Multiple mechanisms can be listed, one separated from another with a space:

"M:DIGEST-MD5 CRAM-MD5"

If the M item is missing, sendmail uses the mechanisms listed in the AuthMechanisms option (AuthMechanisms on page 975).

Missing required letters, unsupported letters, and letters that are missing values have warnings logged at a LogLevel of 9, or above, like this:

AUTH=client, relay=server_name [server_addr], authinfo failed

Here, the server_name is the value of the ${server_name} sendmail macro (${server_name} on page 845). The server_addr is the value of the ${server_addr} sendmail macro ${server_addr} on page 845). Both identify the connected-to host for which the connection failed.

All of this is implemented when you use the authinfo rule set. As of V8.14, there is no way to add your own rules to this rule set.

The default-auth-info file (V8.10 and V8.11)

For V8.10 and V8.11, the default-auth-info file is a plain-text file. Beginning with V8.12, that same information is in the access or authinfo database (see the previous section).

The default-auth-info file contains a list of values, one value per line, in the following order:

First

The username that sendmail uses to check allowable permissions, such as authuser (should never be root).

Second

The username of the user allowed to set up the connection, such as authuser (should never be root).

Third

The clear-text password used to authorize the mail connection. This should be a password dedicated to this use, not a plain-text copy of any user’s (especially root’s) password.

Fourth

The administrative zone for authentication. In general, this should be your DNS domain. If no realm is specified (this item is missing), sendmail will substitute the value of the $j macro ($j on page 830).

Fifth

With V8.11 only, the preferred mechanism for connection authentication. This should match one of the mechanisms listed in the AuthMechanisms option (AuthMechanisms on page 975).

For example, one such default-auth-info file’s contents might look like this:

user
user
foobar
our.official.domain
CRAM-MD5                   ← V8.11 only

This file must live in a directory, all components of which are writable only by root. The file itself must be readable or writable only by root, and optionally readable by the user defined by the TrustedUser option (TrustedUser on page 1112).

The location or name of this file can be changed using the confDEF_AUTH_INFO mc macro, which declares the DefaultAuthInfo option (DefaultAuthInfo on page 999):

define(`confDEF_AUTH_INFO', `/etc/security/default-auth-info')

Here, the location, but not the name, has been changed into what the administrator has set up as a more secure directory.

Additional SASL Help

Setting up SASL can be simpler than we have shown here, or more difficult. The ultimate level of complexity depends on the degree of sophistication you wish to employ using this method of authentication. Sources for additional information that might be of help are:

cf/README

The file cf/README in the source distribution contains a section called SMTP AUTHENTICATION that describes how to use authentication in rule sets.

http://www.sendmail.org/tips/

This web site deals with items ranging from what we have discussed here, to compliant MUAs, problems with realms, and how to use SASL AUTH in support of roaming users.

http://asg.web.cmu.edu/sasl/

This web site, in addition to distributing the source for SASL, contains links to a number of documents that will help you install and configure the SASL library.

http://test.smtp.org/

As of this writing, mail sent to will be accepted, discarded, and logged (with the logs visible via HTTP). Visit that site for details about how to use that address to test and validate your client-side AUTH setup. But note the warning on that site: “Do not use this machine to monitor your SMTP connectivity. It is for SMTP interpretability testing only!”

Public Key Cryptography

Public-key algorithms are asymmetric algorithms based on the use of two different keys. The two keys are called the private key and the public key:

  • The private key is known only by its owner.

  • The public key is known to everyone (it is public).

What one key encrypts, the other one decrypts, and vice versa. That means that if someone else encrypts something with your public key (which he knows because it’s public), you can use your private key to decrypt the message.

With public key cryptography, the same algorithm is used to decrypt as was used to encrypt. This simplifies code.

As long as the owner keeps the private key secret, no one but the owner will be able to decrypt the messages encrypted with the corresponding public key. In public-key systems, it is relatively easy to compute the public key from the private key, but very difficult to compute the private key from the public key. In fact, in some cases it could require several months of computation to obtain the private key from a public key. In general, the greater the number of bits used to encrypt, the stronger the private key.

Digital Signatures

Integrity is guaranteed in public-key systems by using digital signatures. A digital signature is a piece of data which is attached to a message and which can be used to determine whether the message was tampered with during transmission.

The digital signature for a message is generated in two steps.

First, a message digest is generated. A message digest is a “summary” of the message to be transmitted. It has two important properties: (1) it is always smaller than the message itself and (2) even the slightest change in the message produces a different digest. The message digest is generated using a set of hashing algorithms. For example:

% digest -a sha1 /var/log/syslog
61fafd21dcd3911998f561915f7ce8f10998fcdb

Here we use the digest(1) program to compute a sha1-style digest of the file /var/log/syslog. The resulting digest is the alphanumeric string shown.

Second, the computed message digest is encrypted using the sender’s private key. The resulting encrypted message digest is the digital signature.

The digital signature is attached (more on this soon) to the message that will be sent to the receiver. The receiver then performs the following three steps to verify that the message was not changed during transmission.

First, using the sender’s public key, the recipient decrypts the digital signature to obtain the message digest originally generated by the sender.

Second, using the same message digest algorithm originally used by the sender, the recipient generates another message digest of the received message.

Third, the recipient compares both message digests (the one sent by the sender, and the one generated by the recipient). If the two digests are not identical (exactly the same), it means the message was modified during transmission and cannot be trusted.

The recipient can be sure that the digital signature was sent by the sender (and not by a malicious user) because only the sender’s public key can decrypt the digital signature (which was encrypted by the sender’s private key). If the recipient decrypts using the wrong public key, that decrypting renders a faulty message digest, which means that either the message or the message digest is not exactly what the sender sent.

Using public key cryptography in this manner ensures integrity, because the recipient possesses the means to tell whether the message received was exactly what was sent. However, digital signatures guarantee only integrity. Digital signing is not intended to keep the data private.[96] It simply ensures that the data is not tampered with during transit.

Locate the Public Key

Public keys may be distributed in many ways, but for email only four methods are available:

  1. Public keys may be given to a recipient out-of-band, as, for example, by delivery of a floppy disk containing the public keys. Using an out-of-band method, the public keys may be stored long before the email is sent.

  2. Public keys may be embedded in a message. Typically, they are located in the header part of a message as part of a special header. For example:

    X-Public-Key: c3NoLWRzcyBBQUFBQjNOemFDMWtjM01BQUFDQkFKOTh2MXloQVp
        VWjBYM3ZMUVhiemVwY1hienkvdnh6T1NEN3E0a25Ed3loSWFoYm
        dLclMzK2RIV3hzOUErSTRrV2YrODlBLzMzU3VGOCtBOFdwUTc2W
        ld2K2JHMUZiUzg0WW5XeWtNUlY3Z3NzY2VlQUs4OXM2ZDcvSlR3
        VDhiZi9OVTFlT2hvWUdjamJONFBHVHhHajB1bW9nWlBaRiswdEZ
        SMm45b3hVcFpBQUFBRlFDdGpUUVBCS016cXM1Y0QxZVAydXJEZX
        NXSERRQUFBSUFwMEg5dG9YZ21yekJJdjN0aUtVWWcrN0JvSndsW
        HdWTnNiR1lPcVlzdWpxUlZKUWQ0SXRlcVo1WVo2VG5Rbk5DZUho
        V2tjVFNPa3NFcVhsemlIemtudS9pRUp4MTloQnlYaXFzYmlQQ2V
        ZRU1pZUp2Z2crWWZVQTlXb0QwWk00bEs2VHhKUTB2U09PV3E0Yn
        ZFYzNCMzI3ZGh6dS9QaGNqenNNLzMzQ05pVHdBQUFJQXNMWVduU
        HFMNnVkNFR0RTRFYXIyVXBaQ282WEg1ZDk2cVRHNHhUdlpLMnpl
        NTVyRi9Rc1pXNVdod2ZvYkhRWmM5WlRRZzdMeFRtSFhDZmVHT1U
        3eGhrTGpPUTJqMVB0ZXlYd2FTUVpiek1ITU8zaW10ejNwdVB4Vn
        J5a0owTVc0NHdPd1VzbWRvSElqOE5Za094QmNzU1FLUzN6NTdXb
        0VOSnZKbFZuSjBjdz09IGJjeEBsYWR5Cg==
  3. Public keys may be downloaded. DKIM, for example, specifies that public keys be downloaded using DNS:

    % dig txt mypub._domainkey.example.com
  4. A special header may specify a web URL:

    X-Public-Key-Location: https://www.example.com/keys/email/A459b.pub

No matter where a public key is stored, the public key that corresponds to the private key that created the digital signature must be possessed (downloaded and installed for use) by the receiver before a digital signature can be verified.

Authentication in Public-Key Systems

Digital signatures do, to a limited extent, guarantee the authenticity of the sender. After all, only the sender’s public key can decrypt the digital signature encrypted using the sender’s private key. Strictly speaking, however, the only thing this actually guarantees is that whoever sent the message possessed the private key corresponding to the public key used to decrypt the digital signature. Thus, although this public key might have been advertised as belonging to the sender, the recipient can never be absolutely certain.

Certainty is created through the use of digital certificates. A digital certificate certifies that a given public key is owned by a particular sender.

A digital certificate is nothing more than a public key that has been digitally signed by a third party. That third party is known as a certificate authority (CA) and is the person or business that certifies that the public key belongs to the sender.

Now, instead of providing the sender’s public key to the recipient, the sender provides a CA-signed public key (a digital certificate) to the recipient. The certificate proves to the recipient that the sender’s public key actually belongs to the sender.

First, the recipient decrypts the certificate using the CA’s public key and computes a digest of the sender’s public key contained in the result. The recipient compares the two digests (the one created by the CA and the one created by the recipient), and if they are the same, the recipient knows that the sender’s public key is good and was actually signed by the CA.

Second, the recipient uses the validated (authenticated) sender’s public key to validate the digital signature of the message.

To trust a certificate the recipient must trust the CA that signed it. Unfortunately, there is no automatic means for collecting trusted CA certificates. Instead, it is up to the recipient (and the recipient’s software) to collect only trusted CA certificates.

Some CAs are well known and are thus included in many public key systems (such as web browsers). VeriSign and GlobalSign are two well-known CA businesses that provide certificates to authenticate themselves to web browsers. But there are many others. It is up to the recipient to collect only CA certificates from CAs which it trusts.

Now the logical question of who signs the CA certificates arises. The answer is simple: another CA signs it. The fact that CA certificates can be signed by higher CAs gives the system an interesting property. Although the recipient might not explicitly trust a CA (because it is not in the recipient’s CA list), the recipient might trust the higher-level CA that signed the untrusted certificate. If any CA is trusted, all CA signatures under it can be trusted too.

However, the highest-level CA must always sign its own certificate. This is called a self-signed certificate and is a common practice. A CA with a self-signed certificate is called a root CA, because there’s no CA above it. To trust a certificate signed by a root CA, it must necessarily be in the recipient’s trusted CA list.

X.509 Certificate Format

All digital certificates are currently encoded in X.509 certificate format. An X.509 certificate is no more than a plain text file that is arranged in a very specific syntax. We will gloss over the full syntax here and focus, instead, on the items of interest in an X.509 certificate:

  • Subject is the name of the user encoded as a distinguished name (the format for distinguished names is explained shortly).

  • Subject’s public key includes not only the key itself, but also information such as the algorithm used to generate the public key.

  • Issuer’s Subject is the CA’s distinguished name.

  • Digital signature is a digital signature of all the information in the certificate. This digital signature is generated using the CA’s private key. To verify the digital signature, the recipient needs the CA’s public key (which can be found in the CA’s certificate).

Subjects in X.509 certificates are not encoded as common names (such as “Bob”), but are instead encoded as distinguished names. A distinguished name is a single line of text comprising a comma-separated list of name-value pairs. For example:

O=Whatsamatta U, OU=Dept of Woodsmanship, CN=B. Moose

Here, the O= specifies the organization, the OU= specifies the Organizational Unit, and the CN= specifies the Common Name (generally a person’s common name).

STARTTLS

Encryption can improve the security of sendmail. Ordinarily, mail is sent between two machines in the clear. That is, if you were to watch the transmission of bytes over the network,[97] you would see what is actually being sent or received. This includes passwords, which are also sent in the clear.

To reduce the likelihood that someone watching the network will find something that can harm you, you can encrypt the stream of data. Three forms of encryption are available as of this writing:

SSL

SSL is a method for encrypting a single connection over which network traffic can flow. One implementation of SSL is available from http://www.openssl.org/.

TLS

Transport Layer Security, defined by RFC2246, is the successor to SSL that provides further means of connection encryption. It, too, is available from http://www.openssl.org.

SMTP AUTH=

The DIGEST-MD5 and GSSAPI mechanisms, among others, for the AUTH= extension to SMTP, also provide stream encryption.

In this section, we show you:

  • How to select a random number generator

  • How to create a CA signed certificate for use with sendmail

  • How to include support for STARTTLS in sendmail

  • How to set up the configuration file for use with STARTTLS

  • Which sendmail macros are relevant to STARTTLS

  • How to use the access database for finer control

Select a Random Number Generator

If your system lacks the device /dev/urandom, you will need to perform additional steps before you can use TLS. If your system supports /dev/urandom, you can skip this section.

For TLS (and thus STARTTLS) to work in a reliable and secure manner, you need to set up a way for sendmail to acquire high-quality pseudorandom numbers. There are a few alternatives to /dev/urandom that you can use, some more suitable than others. They are, in order of preference:

  • SUNWski, which is a package from Sun Microsystems that emulates /dev/urandom, and which works only with SunOS 5.5.

  • EGD, which stands for Entropy Gathering Daemon.

  • PRNGD, which stands for PseudoRandom Number Generator Daemon.

  • You can also roll your own random number source in a file.

SUNWski

Sun Microsystems provides an equivalent to /dev/urandom, called /dev/random, as part of its SUNWski package for Solaris. If it is not already installed on your system, you can install it from a variety of sources. Look for it on your Solaris Server Intranet Extension CD.

For Solaris 2.6, look for patch number 106754, 106755, or 106756, which contains the SUNWski package.

EGD

EGD is a persistent daemon that provides excellent pseudorandom numbers via a Unix domain socket. It is available as perl(1) source from http://egd.sourceforge.net/.

If you choose to download and install this daemon, you can advise sendmail of that fact by defining the RandFile option (RandFile on page 1076) in your mc configuration file:

define(`confRAND_FILE', `egd:/etc/entropy')

Here, a decision was made to run the EGD daemon at the system level, and to have it create its socket as /etc/entropy.[98] If you place that socket in a different location, you should replace /etc/entropy in the confRAND_FILE line (as discussed earlier) with the new location. The egd: prefix is required and constant.

Note that to include support inside sendmail for use with this daemon, you must build sendmail with the EGD compile-time macro defined (EGD on page 111):

APPENDDEF(`confENVDEF', `-DEGD')   ← in your Build m4 file

PRNGD

PRNGD is an EGD-compatible daemon available from http://prngd.sourceforge.net/.

You download and install it, and then use it in the same manner described in the preceding section for EGD.

Roll your own

It is possible to use a file created by you that contains random numbers. To do this, first define the location of that file with sendmail’s RandFile option (RandFile on page 1076). Such a declaration might look like this:

define(`confRAND_FILE', `file:/var/run/randfile')

Note that the file: prefix is literal and must be present. The file, here named /var/run/randfile, contains at least 128 bytes of random data.

For such a file to work, you need to update its contents more often than once every 10 minutes. If you update it less often, sendmail might refuse to use it upon startup (as a daemon or simply to send an email message). That is, the modification time of the file must always be within 10 minutes of any envocation of sendmail.

Digital Certificate Acronyms

The sendmail program uses a number of acronyms and abbreviations to refer to the various components of digital certificates. They are listed in Table 5-4.

Table 5-4. Acronyms, abbreviations, and terms for digital certificates

Term

Description

CA

Certificate authority (authority that issues a digital certificate)

Cert

A digital certificate, but often means just the public part of the whole certificate

Cipher

The type of encryption used for a connection

Client Certificate

Identifies connecting client to the mail server

CN

Common Name (the username or site name)

Key

The private key, but often means just the private part of the whole certificate

Private Key

The private-key part of a certificate

Public Key

The public-key part of a certificate

Server Certificate

Identifies mail server to connecting client

Revocation List

A file which lists certificates that have been revoked and should no longer be considered valid

For example, you might see a reference to “install a CA cert” in this book or in the sendmail documentation. This phrase means to install a digital certificate issued by a certificate authority. When you install the certs of the issuing CA, you are generally installing only the public parts.

You are encouraged to refer to Table 5-4 while reading the next few sections, where these acronyms, abbreviations, and terms are frequently used.

Enable TLS with Build

To enable TLS in sendmail you need to add two new lines to your Build m4 file:

APPENDDEF(`conf_sendmail_ENVDEF', `-DSTARTTLS')
APPENDDEF(`conf_sendmail_LIBS', `-lssl -lcrypto')

With these two lines in place, build a new sendmail. If you get an error such as the following:

tls.c:16: openssl/err.h: No such file or directory

you will need to let Build know where you installed the ssl components:

APPENDDEF(`confINCDIRS', `-I/opt/packages/openssl/include')
APPENDDEF(`confLIBDIRS', `-L/opt/packages/openssl/lib')

Here, we installed OpenSSL in the nonstandard path /opt/packages/openssl.

Set Up Your Certificates

There are two ways to set up your site’s certificates: create your own and sign them yourself; or create your own and have a commercial site sign them. Commercial signatures generally require payment of an annual fee.

Table 5-5 shows a few of the commercial sites that sign certificates. There are many more than we show here. Use your favorite search engine to find more.

Table 5-5. Digital-certificate-issuing sites

Site

Description

http://www.verisign.com

The original certificate authority

http://www.thawte.com

Claims to be the largest

http://www.valicert.com

A business-oriented site

http://www.cacert.org/

Is free but rarely recognized

Before you can have your certificate signed, you need to create one. This is required because of security. You should never (and we mean never) send (or in any manner expose) your private key over the Internet. Remember, your private key is private and must remain so in order to be safe and effective.

This means that you cannot buy a certificate over the Internet and have it delivered via email or downloaded to your machine.[99] Instead, you must create your own certificate, and then send the public key to the certificate authority to be signed. Doing so is OK because the public key is world-visible and because the signature needs to be attached to the public part that is sent to others.

Create a certificate

The first step to create your own certificates is to decide where on the filesystem they may safely be stored. For email purposes, we suggest /etc/mail/CA or a similar path that is writable only by root, and where the private subdirectory under it is readable only by root. We use /etc/mail/CA in the examples to follow:

# cd /etc/mail
# mkdir CA CA/certs CA/crl CA/newcerts CA/private
# chmod -R 700 CA/private
# cd CA

For the rest of this discussion, we presume you will be working inside the CA directory; hence the cd CA in the preceding code. We also presume that the openssl(1) program is in your path. If it isn’t, you may need to prefix openssl in the examples that follow with its full path. For example:

# /usr/local/ssl/bin/openssl .....

Alternatively, you can temporarily modify root’s path:

# PATH=/usr/local/ssl/bin:$PATH; export PATH

Next, you generate your certificate authority (your CA). You need to do this only once. We use the req function for OpenSSL (http://www.openssl.org/docs/apps/req.html) to manage and create certificates:

# echo `01' > serial
# cp /dev/null index.txt
# openssl req -nodes -new -x509 -keyout private/cakey.pem -out cacert.pem

The -nodes prevents the resulting certificate from being encrypted. This is necessary for use with sendmail because sendmail must be able to start unattended without the need for an operator to type in a password each time.

The last command is a two-step process combined into one. The -keyout private/cakey.pem command creates an encryption key that will be used to sign the certificate:

Generating a 1024 bit RSA private key
.........++++++
.........................++++++
writing new private key to `private/cakey.pem'

This step can be slow on older systems, especially those that lack a good random number generator (one without sufficient entropy). You may, for example, be required to rapidly type characters to help generate random events.

This key must be protected, so we place it in the private subdirectory. If anyone were to access it, that person would be able to decrypt anything encrypted with it.

The second step creates the actual certificate. Because this is a standard X.509 certificate, you will be prompted to fill in some X.509 information.[100] We suggest the following answers for illustrative purposes only. Naturally, you need to enter information specific to your situation and your site:

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]:California
Locality Name (eg, city) []:Emeryville
Organization Name (eg, company) [Internet Widgits Pty Ltd]:your domain
Organizational Unit Name (eg, section) []:.
Common Name (eg, YOUR name) []:mail.your.domain
Email Address []:you@your.domain

Note that the “Common Name” must exactly match the hostname of the system on which the certificate will be used. If it differs, some clients may complain about a certificate-to-hostname mismatch.

The next step is to create a certificate for use with sendmail. You will have to perform this step whenever a new cert is required. The umask(1) in the following code ensures that every file created for the rest of this session will be writable only by root.

# umask 0066
# openssl req -nodes -new -x509 -keyout key.pem -out newcert.pem

The preceding command creates a certificate for use with sendmail. It is unsigned and still needs to be signed by the CA, which we will do next. Like the previous step, this creates a key (which may be a long process) and then prompts you for X.509 information. Fill in that information as you did earlier.

The last step is to sign the new sendmail certificate (called newcert.pem), which requires two commands. The first command generates a certificate request:

# openssl x509 -x509toreq -in newcert.pem -signkey key.pem -out csr.pem
Getting request Private Key
Generating certificate request

The second command uses the CA cert key in private/cakey.pem to sign the newcert.pem certificate. The request for the signature is in the csr.pem file we created earlier (where csr stands for Certificate Signing Request):

# openssl ca -policy policy_anything -out cert.pem -infiles csr.pem
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Feb  2 18:05:01 2007 GMT
            Not After : Feb  2 18:05:01 2008 GMT
        Subject:
            countryName               = US
            stateOrProvinceName       = California
            localityName              = Emeryville
            organizationName          = your domain
            commonName                = mail.your.domain
            emailAddress              = you@your.domain
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                44:76:FB:B4:54:F2:2E:FC:F6:35:3B:11:CD:FB:16:12:90:71:7B:B3
            X509v3 Authority Key Identifier:
                keyid:B7:A1:33:10:67:6E:15:E0:4D:BA:C4:B4:77:93:BA:5E:55:44:15:6C
Certificate is to be certified until Dec 15 18:05:01 2008 GMT (365 days)
Sign the certificate? [y/n]:

Here you are prompted to say yes or no to signing the certificate. This gives you the opportunity to review the information displayed. Certificates are sensitive to all sorts of minor errors and need to be handled carefully. You should select y only if all looks correct:

Sign the certificate? [y/n]:y

Committing means adding this particular certificate to your collection of certificates. The next question is whether you wish to commit the certificate:

1 out of 1 certificate requests certified, commit? [y/n]

We recommend yes. It will be added to your index.txt file.

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

If the above command fails, you may see the following error:

Error opening CA certificate ./demoCA/cacert.pem
2561:error:02001002:system library:fopen:No such file or directory:bss_file.c:352:
fopen('.demoCA/cacert.pem','r')
2561:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:354:
unable to load certificate

This just means that you have not yet set up your openssl(8) configuration defaults. If so, you can create the following symbolic link as a shortcut just to verify that the prior command will actually work:

# ln -s ../CA demoCA

If all went well, you “clean up.” The csr.pem file may be removed because it was only a scratch file needed for signing. The newcert.pem may be removed because it is the unsigned cert. The file cert.pem contains the CA signed cert.

To view the certificate you created (or any certificate, for that matter) simply use a command like the following:

# openssl x509 -noout -fingerprint -text -in cert.pem

We don’t show the output of this command because it can run to multiple pages. You can redirect this output into a file, if you wish, and share that file on a web site. Its output is your CA signed public key in text format.

Lastly, recall that sendmail can run as either a client or a server. Whether you use the same certificate for both roles is a matter of policy. But if you wish to offer TLS for both roles using separate certs for each, you should now rename the cert.pem and key.pem files for the server’s use and create (using the procedure we just outlined) another CA signed certificate for use with the client:

# mv cert.pem server.cert.pem
# mv key.pem server.key.pem
... create another CA signed cert here
# mv cert.pem client.cert.pem
# mv key.pem client.key.pem

Note that the preceding code generates separate certs for client and server. Note also that we will use the preceding filenames in the discussions to follow.

Revocation lists

Beginning with V8.12 sendmail, OpenSSL version 0.9.7 and later support the ability to screen certificates against a revocation list. In the preceding section, you created certificates that possessed a default life of one year. But what happens if you want to cancel a certificate and replace it with another? For housekeeping purposes, you can add the canceled certificate to a list of canceled certificates called a “revocation list.”

For use with sendmail, you may create an empty revocation file with the following commands:

# echo "01" > crlnumber
# openssl ca -gencrl -out crl/crl.pem

Later, when you need to add certificates to this file, you may. But in the meantime, an empty file works just fine for sendmail’s needs. Visit http://www.openssl.org/docs/apps/crl.html for additional guidance.

To view your empty revocation list, you may use the following command:

# openssl crl -in crl/crl.pem -noout -text

Sources of additional help

There can be much more to the creation and signing of certificates than we show here. The following lists a few resources that provide additional guidance to certificate creation and management:

http://www.sendmail.org/~gshapiro/security.pdf

A brief tutorial that describes sendmail security in general, and provides examples of certificate creation.

http://www.openssl.org/docs/

Online documentation for openssl(8) and its various applications and commands.

Network Security with OpenSSL

By John Viega, Matt Messier, and Pravir Chandra (O’Reilly). Provides a full description of OpenSSL, including how to create certificates and how to sign them.

SSL and TLS: Designing and Building Secure Systems

By Eric Rescorla (Addison Wesley Professional). A higher-level book that covers the protocols of SSL and TLS Internet security.

Add STARTTLS Support to Your mc File

After you have built sendmail with STARTTLS support (Enable TLS with Build on page 205), and after you have created certificates for use with sendmail, you must set up your configuration file to use STARTTLS. There are eight mc configuration file macros that you can use to do this. Based on what we have shown in the previous sections, one way to define them might look like this:

define(`CERT_DIR', `/etc/mail/CA')
define(`confCACERT_PATH',  CERT_DIR)
define(`confCACERT',  CERT_DIR`/cacert.pem')
define(`confSERVER_CERT',  CERT_DIR`/server.cert.pem')
define(`confSERVER_KEY',  CERT_DIR`/server.key.pem')
define(`confCLIENT_CERT',  CERT_DIR`/client.cert.pem')
define(`confCLIENT_KEY',  CERT_DIR`/client.key.pem')
define(`confCRL', CERT_DIR`/crl/crl.pem')                        ← V8.12 and later

Here, we set values for server and client, certificate, and key files. Rebuild your cf file and test the result as we show in the next section.

Test STARTTLS

Once you have built sendmail with STARTTLS support, and before you install it, you should test to see whether STARTTLS is working. One way to perform such a test is like this:

# obj.*/sendmail/sendmail -bs -Am

Here, we run the newly built sendmail relative to the source directory. The -bs tells sendmail to speak SMTP on its standard input. The -Am tells sendmail to use its server configuration file (not submit.cf), even though it is running in mail-submission mode. Such a test session might look like this:

220 your.host.domain ESMTP Sendmail 8.14.1/8.14.1; Fri, 14 Dec 2007 11:43:02 −0700
(PST)
ehlo your.host.domain
250-your.host.domain Hello root@localhost, pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-STARTTLS                  ← note this line
250-DELIVERBY
250 HELP
quit
221 2.0.0 your.host.domain closing connection

Here, the STARTTLS SMTP keyword appears, revealing that this site supports TLS encryptions of connections.

If STARTTLS doesn’t appear, rerun the command with extra debugging, like this:

# obj.*/sendmail/sendmail -O LogLevel=14 -bs -Am

Look in your syslog logfiles for sendmail messages. Look for messages such as warnings about unsafe files, or warnings about the validity of X.509 certificates. If this fails, and you need additional help, you can connect to http://www.sendmail.org/tips/.

If STARTTLS does appear, run sendmail as usual. Then examine Received: header lines for mail you received from other sites that support STARTTLS, and look for indications that TLS encryption worked:

Received: from other.host.domain (other.host.domain [123.45.67.89])
        by your.host.domain (8.12.5/8.12.3) with ESMTP id g75FlHR4038187
        (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO)
   ← note
        for <you@your.host.domain>; Fri, 13 Dec 2002 08:47:36 −0700 (PDT)

Note that even though the Received: header shows verify=NO, the message was still encrypted because the cipher= and bits= are present with values.

Macros for Use with STARTTLS

If you decide to use STARTTLS with sendmail, be aware that a number of related sendmail macros are useful in rule sets and database maps. These are shown in Table 5-6, and described in detail in Chapter 21.

Table 5-6. Macros for use with STARTTLS

Macro

§

Description

${cert_issuer}

${cert_issuer} on page 809

Distinguished name of CA that signed the presented cert

${cert_md5}

${cert_md5} on page 809

MD5 of certificate

${cert_subject}

${cert_subject} on page 809

Distinguished name of certificate

${cipher}

${cipher} on page 809

Cipher suite used for connection

${cipher_bits}

${cipher_bits} on page 810

TLS encryption key length

${tls_version}

${tls_version} on page 847

TLS/SSL version

${verify}

${verify} on page 849

Result of cert verification

To illustrate, consider a simple rule set that allows relaying by anyone who presents a cert that can be verified:

LOCAL_RULESETS
SLocal_check_rcpt
R$*        $: $&{verify}
ROK        $# OK

Here, the Local_check_rcpt rule set is used to check the envelope recipient. If the result of authentication stored in the ${verify} macro is OK, the sender is allowed to relay. Anything other than OK denies relaying.

More ambitious use of these sendmail macros involves the access database and is covered in the next section.

STARTTLS and the access Database

Beginning with V8.11, four new prefixes in the access database are available for use with STARTTLS connection encryption (STARTTLS on page 202). CERTISSUER: and CERTSUBJECT: are for use with the Local_Relay_Auth rule set. TLS_Srv: and TLS_Clt: are for use with the tls_server and tls_client rule sets.

The access database and Local_Relay_Auth

In the rule set Local_Relay_Auth, the STARTTLS-related sendmail macro ${verify} (which contains the result of connection verification) is compared to the literal value OK. If it is not OK, the other relaying checks are performed.

If ${verify} is OK, the value in the sendmail macro ${cert_issuer} (${cert_issuer} on page 809) is prefixed with CERTISSUER:, and the result is looked up in the access database. That macro contains as its value the distinguished name of the authority that signed the presented certificate. The value undergoes special translation before the lookup. Specifically, all nonprinting characters, the space and tab characters, and the special characters:

< > ( ) " +

are replaced with the hexadecimal value of the character prefixed with a plus sign. For example, Sendmail CA becomes Sendmail+20CA.

Therefore, if the issuer has the following distinguished name:

/C=US/ST=California/L=Berkeley/O=Sendmail.org/CN=Sendmail CA/

that value undergoes special translation, and is prefixed with the special prefix CERTISSUER: just before the lookup. So the following is looked up:

CERTISSUER:/C=US/ST=California/L=Berkeley/O=Sendmail.org/CN=Sendmail+20CA/

If that prefix and distinguished name are found in the database, and if the value returned is the keyword RELAY, relaying is allowed. If the value returned is the keyword SUBJECT instead of RELAY, the value of the sendmail macro ${cert_subject} (${cert_subject} on page 809) is looked up in the access database. That macro contains as its value the distinguished name of the connecting site. That value also undergoes translation, and is prefixed with the special prefix CERTSUBJECT: just before the lookup. For example, if the distinguished name of the certificate for the connecting site is:

/C=US/ST=California/L=Berkeley/O=Sendmail.org/CN=Eric Allman/

the following is looked up:

CERTSUBJECT:/C=US/ST=California/L=Berkeley/O=Sendmail.org/CN=Eric+20Allman/

If the prefixed macro’s value is found, and if the value returned is the keyword RELAY, relaying is allowed.

The access database with tls_server and tls_client

The tls_server rule set is called after the local sendmail issued (or should have issued) the STARTTLS SMTP command. This rule set handles outbound connections.

The tls_client rule set is called at two possible points: just after the connecting host’s STARTTLS SMTP command is offered; and from the check_mail rule set (which is called just after the connecting host issues the MAIL From: command). This tls_client rule set handles inbound connections.

Both rule sets are given the value of the ${verify} sendmail macro in their workspaces. The tls_client rule set is given that value, followed by a $| operator, and a literal string that is MAIL when tls_client is called from the check_mail rule set, or STARTTLS otherwise.

If the access database is not used, the connection is allowed in all cases, both inbound and outbound, unless the value in ${verify} is SOFTWARE, in which case the connection is not allowed.

If the access database is used, the tls_server rule set looks up the hostname of the destination host in the access database using the TLS_Srv: prefix. For example, if the local sendmail connected to the server insecure.host.domain, and if the negotiation for the TLS connection was good, the following lookup is performed:

TLS_Srv:insecure.host.domain

The tls_client rule set looks up the hostname of the inbound connecting host in the access database using the TLS_Clt: prefix. For example, if the local sendmail accepts a connection from ssl.host.domain, and if the negotiation for TLS connection was good, the following lookup is performed:

TLS_Clt:ssl.host.domain

For both rule sets, if the host or domain is not found, the host.domain and then the domain are looked up, and if neither is found, a bare prefix is looked up to determine the default behavior:

TLS_Clt:                           VERIFY
TLS_Srv:                           VERIFY

Here, the default for inbound and outbound connections is to require that they all be verified.

The access database righthand-side string VERIFY means that the value in the ${verify} macro must be OK.

In addition to the VERIFY value keyword, a number of bits (key length) can also be specified as:

VERIFY:bits

In addition to requiring that the certificate be verified, the number of bits in the ${cipher_bits} sendmail macro must be at least as wide as the number of bits specified in bits.

If the number of bits is the only item of concern, and if certificate verification is not of concern, the VERIFY in VERIFY:bits can be changed into ENCR:

ENCR:bits

Here, no certificate verification is required, but the number of bits in the ${cipher_bits} sendmail macro must be at least as wide as the number of bits specified in bits.

If the certificate is verified, and/or the number of bits is sufficient, the connection is allowed. Otherwise, it is rejected. When rejected, the rejection is temporary by default. You can prefix the VERIFY or ENCR with a TEMP+ to make a particular failure temporary, or with a PERM+ to make it permanent:

TEMP+VERIFY      ← temporary failure
PERM+ENCR:bitspermanent failure

You can also define the TLS_PERM_ERR macro in your mc configuration file to redefine the default to be a permanent failure:

define(`TLS_PERM_ERR')

If you wish to add your own rule to the tls_client or tls_server rule set, you can do so with an appropriate mc configuration command:

LOCAL_TLS_CLIENT ← additional rules for
tls_client here
LOCAL_TLS_SERVER ← additional rules for
tls_server here

Your rules, if any, will be called first. That is, for example, if you add rules to tls_client, those rules will be called before those that were already in the tls_client rule set. You do not need to restore the workspace at the end of your rules, however, because that restoration is taken care of for you.

The tls_rcpt rule set

In the preceding section, you learned that the tls_server rule set could be used to require that all mail to a particular site always be encrypted. For example, an access database entry such as the following does just that for the hostA.domain site:

TLS_Srv:hostA.domain   ENCR:128

However, because of MX records, mail might not always be sent to the hostA.domain’s mail server. Consider these two MX records:

hostA.domain.  IN MX 10        mail.hostA.domain.
hostA.domain.  IN MX 50        mail.someother.domain.

When the server mail.hostA.domain is down or heavily loaded, your local sendmail will likely connect to the backup MX site mail.someother.domain. When this happens, the requirement that all mail be encrypted (as set in the access database) will not be honored. Because you have no way of knowing ahead of time what host will serve as an MX backup, you probably won’t have that backup host listed in your access database:

TLS_Srv:hostA.domain   ENCR:128       ← mail.someother.domain not listed

When sendmail connects to mail.someother.domain (and when mail.someother.domain does not support STARTTLS) the message will be transmitted in plain text (unencrypted).

The tls_rcpt rule set was created specifically to deal with this problem. It is called just before a RCPT To: command is sent to the other site.

The workspace supplied to tls_rcpt is the current recipient (the one that will be given in the RCPT To: command when it is issued). This rule set is allowed to require encryption or verification of the recipient’s MTA, even if the message was redirected with MX records to another site.

The tls_rcpt rule set looks up the recipient in four different ways, where the format of the recipient address is user@host.domain. Each lookup is prefixed with a literal TLS_Rcpt:. The lookups are:

TLS_Rcpt:user@host.domain
TLS_Rcpt:user@
TLS_Rcpt:host.domain
TLS_Rcpt:domain
TLS_Rcpt:

The tls_rcpt rule set accepts the righthand-side value from the first matched lookup. If there is no match, the recipient address is considered good and the RCPT To: command is allowed to be issued.

The allowable righthand-side values are the same as those described for the tls_server rule set in the preceding section. The requirements in the righthand side are compared to the ${verify} and ${cipher_bits} macros, as appropriate, and the connection is either allowed to continue, or not, based on the result.

To illustrate, consider the MX example given earlier. If the access database contains the following entry:

TLS_Rcpt:hostA.domain   ENCR:128

encryption is required for any recipient at hostA.domain, even if delivery is redirected with an MX record to another site, such as mail.someother.domain.

In addition to the righthand-side values described earlier, the tls_rcpt rule set allows four righthand-side suffixes. Each starts with a plus sign, and when two or more are listed, each is separated from the others with two plus signs:

TLS_Rcpt:hostA.domain   ENCR:128+CN:smtp.hostA.domain++CI:hostB.domain

The suffixes allow further checks to be applied to the connection in addition to those required by the existing righthand-side value. The suffixes and their meanings are:

CN:name

The name specified. It must match the value in the ${cn_subject} macro (${cn_subject} on page 816).

CN

The value in the ${cn_subject} macro (${cn_subject} on page 816). It must match the value in the ${server_name} macro (${server_name} on page 845).

CS:name

The name specified. It must match the value in the ${cert_subject} macro (${cert_subject} on page 809).

CI:name

The name specified. It must match the value in the ${cert_issuer} macro (${cert_issuer} on page 809).

If you wish to add your own rules to the tls_rcpt rule set, you can do so with the following mc configuration command:

LOCAL_TLS_RCPT
 ← additional rules for tls_rcpt here

If your rules return a #error or #discard delivery agent, the connection is rejected. If they return a $#OK,[101] the connection is accepted and subsequent tls_rcpt rule set rules are skipped (the access database lookups are not performed):

R $*              $# OK      skip subsequent tls_rcpt rule set rules

But if they return a $@OK, further tls_rcpt rule set rules are allowed, and the access database lookups are performed, which might subsequently reject the connection:

R $*              $@ OK      allow subsequent tls_rcpt rule set rules

Your rules, if any, will be called first. That is, for example, if you add rules to tls_rcpt, those rules will be called before those that were already in the tls_rcpt rule set. You need not restore the workspace at the end of your rules, however, because that restoration is taken care of for you.

Disable STARTTLS with the try_tls rule set

By default, STARTTLS is used whenever possible. Unfortunately, some hosts on the Internet do not properly implement STARTTLS, so even though they offer STARTTLS, they don’t use it properly and the connection fails. If you know ahead of time which hosts have this problem, you can list them in the access database and cause STARTTLS to be skipped for them.

The try_tls rule set allows you to exempt specific connecting hosts and domains from STARTTLS support. This rule set simply looks up the connecting host’s hostname and address in the access database. Each lookup is prefixed with a literal Try_TLS:. If the lookup finds the host or address (if either is in the access database), the use of STARTTLS is suppressed:

Try_TLS:broken.server                NO      ← a domain
Try_TLS:host.broken.server           NO      ← a host
Try_TLS:123.45.67.89                 NO      ← an IPv4 address
Try_TLS:IPv6:2002:c0a8:51d2::23f4    NO      ← an IPv6 address

The righthand-side value for this lookup can be anything. All the try_tls rule set cares about is whether the lookup succeeds.

If you wish to add your own rule to the try_tls rule set, you can do so with the following mc configuration command:

LOCAL_TRY_TLS
 ← additional rules for try_tls here

If your rules return a #error or #discard delivery agent, STARTTLS is suppressed. If they return a $#OK,[102] STARTTLS is offered and subsequent try_tls rule set rules are skipped (the access database lookups are not performed):

R $*              $# OK      skip subsequent try_tls rule set rules

But if they return a $@OK, STARTTLS might be offered. We say “might” because further try_tls rule set rules are allowed, and access database lookups are performed, which, in turn, can subsequently disallow STARTTLS:

R $*              $@ OK      allow subsequent try_tls rule set rules

Your rules, if any, will be called first. That is, for example, if you add rules to try_tls, those rules will be called before those that were already in the try_tls rule set. You need not restore the workspace at the end of your rules, however, because that restoration is taken care of for you.

Additional TLS Help

Getting TLS to work at your site can be a daunting task. In addition to this book you may wish to investigate the following resource as well:

http://test.smtp.org/

As of this writing, mail sent to will be accepted, discarded, and logged (with the logs visible via HTTP). Visit that site for details about how to use that address to test and validate your TLS setup. But note the warning on that site: “Do not use this machine to monitor your SMTP connectivity. It is for SMTP interpretability testing only!”

Pitfalls

  • For security, beginning with V8.14 sendmail, authentication credentials (such as passwords) are no longer logged on failure. This can make debugging AUTH difficult. Try using the -X command-line switch to save SMTP transactions to a disk file. That raw SMTP transcript contains all credentials, albeit most are Base64-encoded.

  • If you run sslauthd(8) to authenticate, be sure to arrange for that program to be automatically restarted at boot time. Overlooking this step can lead to surprising rejections of valid relaying requests following a power, or some other, outage.

  • Prior to V8.13, AUTH information was included in bounced email when sendmail was configured to use SMTP AUTH. Beginning with V8.13, that sensitive information is excluded from bounced email.



[82] * Note, however, that neither may be necessary if your environment has already been set up with Virtual Private Network (VPN) support.

[83] * This setup could be useful, for example, if your laptop runs Linux and you need to relay mail through your server while roaming.

[84] * We don’t cover Kerberos in this book. You can find information about Kerberos at http://web.mit.edu/kerberos/.

[85] On some operating systems, such as Linux, OpenSSL is preinstalled in the correct directories, so you do not need to do anything special in order to use it.

[86] We describe links here, but you may prefer copies or even configuring OpenSSL to install in the correct system locations.

[87] * See the documents in the SASL source tree’s doc subdirectory, and the manual page for saslpasswd2(8) or saslpasswd(8) for more information.

[88] * If you have an SASL library version earlier than 1.5.10, you should upgrade to the latest version. If you cannot upgrade, or choose not to, you must define the value for SASL to be the version number of the SASL library you currently use. Your current version has the form a.b.c (as 1.5.9). You create a single number where b and c are each two digits; thus, 1.5.9 becomes 10509. You then define SASL with that number:

APPENDDEF('confENVDEF', '-DSASL=10509')

[89] * On your system, the -L might have to be -R instead, or you might have to use both.

[90] * Every component of a safe directory path must be owned and writable only by root.

[91] If you wish to test as a user other than root, use a nonprivileged port number higher than 1028.

[92] * If you use STARTTLS (STARTTLS on page 202) to first encrypt the SMTP session, PLAIN may be secure.

[93] * But will never provide a superset—more mechanisms—than the AuthMechanisms option specified.

[94] * This mechanism requires that the laptop be running a mail reading/sending program that can use SMTP AUTH. Recent versions of Thunderbird, Netscape, and Microsoft’s Outlook have this support, as do many other such programs. On laptops that run Unix (such as Linux and FreeBSD), you can, of course, run sendmail.

[95] * Or another character defined by makemap(18) when the database was built.

[96] * To ensure privacy, the message or channel carrying the message would need to be encrypted.

[97] * Examples of Unix utilities that watch the network are snoop(8) and tcpdump. For others, see your online documentation.

[98] * The EGD source installs in /etc by default. We recommend that you configure EGD to install in /var/run instead, and that you indicate the new path to sendmail with this confRAND_FILE mc macro.

[99] * Some certificate authorities provide signed certificates via secure transport, such as surface delivery of a CD or floppy disk, with physical signature and identification required.

[100] * If you have already edited your /etc/ssl/openssl.conf or /usr/local/ssl/openssl.conf file, you will have answered these questions already and won’t need to answer them here.

[101] * Actually, $#anything will have the same effect, but you should use $#OK only to remain compatible with future releases of sendmail.

[102] * Actually, $#anything will have the same effect, but you should use $#OK only to remain compatible with future releases of sendmail.