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 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]
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 -qNote 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:
# makeIf 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 installBy 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/sasl← V1 #ln -s ../local/lib/sasl2← V2
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/saslpasswduser← V1# /usr/local/sbin/saslpasswd2user← V2
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.
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: methodHere, method is
selected from the methods listed in Table 5-1.
|
Description | |
|
|
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. |
|
|
The |
|
|
The |
|
|
The |
|
|
The |
|
|
The |
|
|
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.
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 locatedAnother 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 locatedBut 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.
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 -AmHere, 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.domain250-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 HELPquit221 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 -AmThen recheck your logfile for additional error information.
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.cfYou 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 user@your.domain 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
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 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.
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 (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.
|
Character |
Meaning |
|
|
Use the |
|
|
Provide protection from active (nondictionary) attacks during the authentication exchange. (Server only) |
|
|
Allow only selected mechanisms (those that can pass client credentials) to be used with client credentials. (Server only) |
|
|
Don’t permit use of mechanisms that are susceptible to passive dictionary attacks. (Server only) |
|
|
Require forward secrecy between sessions (where breaking one won’t help to break the next). (Server only) |
|
|
Require the use of mechanisms that support mutual authentication. (Server only) (V8.13 and later) |
|
|
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) |
|
|
The opposite of |
|
|
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.
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 $# OKHere, 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.
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 laterThe 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
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.
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.
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:
The username that sendmail uses to check allowable permissions, such as authuser (should never be root).
The username of the user allowed to set up the connection, such as authuser (should never be root).
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.
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).
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 onlyThis 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.
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:
The file cf/README in the source distribution contains a section called SMTP AUTHENTICATION that describes how to use authentication in rule sets.
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.
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.
As of this writing, mail sent to
bit-bucket@test.smtp.org 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 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.
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.
Public keys may be distributed in many ways, but for email only four methods are available:
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.
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==Public keys may be downloaded. DKIM, for example, specifies that public keys be downloaded using DNS:
% dig txt mypub._domainkey.example.com
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.
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.
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).
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 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/.
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.
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
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:
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 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 filePRNGD 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.
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.
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.
|
Term |
Description |
|
CA |
Certificate authority (authority that issues a digital certificate) |
|
A digital certificate, but often means just the public part of the whole certificate | |
|
The type of encryption used for a connection | |
|
Identifies connecting client to the mail server | |
|
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.
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.
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.
|
Site |
Description |
|
The original certificate authority | |
|
Claims to be the largest | |
|
A business-oriented site | |
|
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.
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]:USState or Province Name (full name) [Some-State]:CaliforniaLocality Name (eg, city) []:EmeryvilleOrganization Name (eg, company) [Internet Widgits Pty Ltd]:your domainOrganizational Unit Name (eg, section) []:.Common Name (eg, YOUR name) []:mail.your.domainEmail 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]:yCommitting 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 UpdatedIf 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 certificateThis 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.
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
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:
A brief tutorial that describes sendmail security in general, and provides examples of certificate creation.
Online documentation for openssl(8) and its various applications and commands.
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.
By Eric Rescorla (Addison Wesley Professional). A higher-level book that covers the protocols of SSL and TLS Internet security.
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 laterHere, 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.
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 -AmHere, 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.domain250-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 HELPquit221 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 -AmLook 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.
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.
|
Macro |
§ |
Description |
|
|
${cert_issuer} on page 809 |
Distinguished name of CA that signed the presented cert |
|
|
${cert_md5} on page 809 |
MD5 of certificate |
|
|
${cert_subject} on page 809 |
Distinguished name of certificate |
|
|
${cipher} on page 809 |
Cipher suite used for connection |
|
|
${cipher_bits} on page 810 |
TLS encryption key length |
|
|
${tls_version} on page 847 |
TLS/SSL version |
|
|
${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 $# OKHere, 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.
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.
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 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:bitsIn 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:bitsHere, 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:bits ← permanent 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.
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 listedWhen 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:nameThe name
specified. It must match the value in the ${cn_subject} macro
(${cn_subject} on page 816).
CNThe 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:nameThe name
specified. It must match the value in the ${cert_subject} macro
(${cert_subject} on page 809).
CI:nameThe 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.
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.
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:
As of this writing, mail sent to bit-bucket@test.smtp.org 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!”
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.