]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.5-20080109
authorWietse Venema <wietse@porcupine.org>
Wed, 9 Jan 2008 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:33:49 +0000 (06:33 +0000)
127 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/STRESS_README
postfix/README_FILES/TLS_README
postfix/RELEASE_NOTES
postfix/TLS_TODO
postfix/WISHLIST
postfix/html/STRESS_README.html
postfix/html/TLS_README.html
postfix/html/lmtp.8.html
postfix/html/master.5.html
postfix/html/postconf.5.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/man/man5/master.5
postfix/man/man5/postconf.5
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/mantools/postconf2man
postfix/mantools/postlink
postfix/mantools/xpostconf
postfix/proto/Makefile.in
postfix/proto/STRESS_README.html
postfix/proto/TLS_README.html
postfix/proto/master
postfix/proto/postconf.proto
postfix/src/anvil/anvil.c
postfix/src/bounce/bounce.c
postfix/src/bounce/bounce_template.c
postfix/src/cleanup/cleanup_bounce.c
postfix/src/cleanup/cleanup_init.c
postfix/src/cleanup/cleanup_message.c
postfix/src/cleanup/cleanup_milter.c
postfix/src/flush/flush.c
postfix/src/global/cleanup_strerror.c
postfix/src/global/cleanup_user.h
postfix/src/global/data_redirect.c
postfix/src/global/delivered_hdr.c
postfix/src/global/dsn_mask.c
postfix/src/global/ehlo_mask.c
postfix/src/global/ext_prop.c
postfix/src/global/header_body_checks.c
postfix/src/global/header_body_checks.h
postfix/src/global/header_opts.c
postfix/src/global/header_opts.h
postfix/src/global/input_transp.c
postfix/src/global/int_filt.c
postfix/src/global/mail_conf.h
postfix/src/global/mail_conf_bool.c
postfix/src/global/mail_conf_int.c
postfix/src/global/mail_conf_long.c
postfix/src/global/mail_conf_raw.c
postfix/src/global/mail_conf_str.c
postfix/src/global/mail_conf_time.c
postfix/src/global/mail_dict.c
postfix/src/global/mail_error.c
postfix/src/global/mail_error.h
postfix/src/global/mail_params.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/mbox_conf.c
postfix/src/global/mime_state.c
postfix/src/global/mime_state.h
postfix/src/global/mkmap_open.c
postfix/src/global/mynetworks.c
postfix/src/global/pipe_command.c
postfix/src/global/sys_exits.c
postfix/src/global/sys_exits.h
postfix/src/local/local.c
postfix/src/master/master.h
postfix/src/master/master_listen.c
postfix/src/master/master_proto.h
postfix/src/master/master_vars.c
postfix/src/master/master_wakeup.c
postfix/src/milter/milter8.c
postfix/src/oqmgr/qmgr.c
postfix/src/oqmgr/qmgr_feedback.c
postfix/src/pickup/pickup.c
postfix/src/pipe/pipe.c
postfix/src/postconf/extract.awk
postfix/src/postconf/postconf.c
postfix/src/postdrop/postdrop.c
postfix/src/postfix/postfix.c
postfix/src/postqueue/postqueue.c
postfix/src/proxymap/proxymap.c
postfix/src/qmgr/qmgr.c
postfix/src/qmgr/qmgr_feedback.c
postfix/src/qmqpd/qmqpd.c
postfix/src/scache/scache.c
postfix/src/sendmail/sendmail.c
postfix/src/showq/showq.c
postfix/src/smtp/lmtp_params.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_params.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_sasl_proto.c
postfix/src/smtp/smtp_session.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_milter.c
postfix/src/smtpd/smtpd_proxy.c
postfix/src/spawn/spawn.c
postfix/src/tls/Makefile.in
postfix/src/tls/tls.h
postfix/src/tls/tls_bio_ops.c
postfix/src/tls/tls_client.c
postfix/src/tls/tls_level.c
postfix/src/tls/tls_misc.c
postfix/src/tls/tls_server.c
postfix/src/tls/tls_session.c
postfix/src/tls/tls_stream.c
postfix/src/tls/tls_verify.c
postfix/src/tlsmgr/tlsmgr.c
postfix/src/trivial-rewrite/trivial-rewrite.c
postfix/src/util/dict.c
postfix/src/util/dict_cdb.c
postfix/src/util/dict_open.c
postfix/src/util/inet_proto.c
postfix/src/verify/verify.c
postfix/src/virtual/virtual.c
postfix/src/xsasl/xsasl_client.c
postfix/src/xsasl/xsasl_cyrus_security.c
postfix/src/xsasl/xsasl_dovecot_server.c
postfix/src/xsasl/xsasl_server.c

index 3b8209c42fc553088f863e71734ace63898208f1..b54aff891d87ce2d07ab78afeaf86cd4568ba7a4 100644 (file)
 -TFILE
 -TFORWARD_INFO
 -THBC_ACTION_CALL_BACKS
+-THBC_CALL_BACKS
 -THBC_CHECKS
 -THBC_MAP_INFO
 -THBC_OUTPUT_CALL_BACKS
 -TSTRING_TABLE
 -TSYS_EXITS_DETAIL
 -TTLSMGR_SCACHE
+-TTLS_APPL_STATE
+-TTLS_CLIENT_INIT_PROPS
+-TTLS_CLIENT_START_PROPS
 -TTLS_PRNG_SEED_INFO
 -TTLS_PRNG_SRC
 -TTLS_SCACHE
 -TTLS_SCACHE_ENTRY
+-TTLS_SERVER_INIT_PROPS
+-TTLS_SERVER_START_PROPS
+-TTLS_SESS_STATE
 -TTLS_VINFO
 -TTLScontext_t
 -TTOK822
 -TXSASL_SERVER
 -TXSASL_SERVER_IMPL
 -TXSASL_SERVER_IMPL_INFO
--Tcipher_probe
+-Tcipher_probe_t
 -Toff_t
 -Tregex_t
 -Tregmatch_t
 -Tsfsistat
 -Tsize_t
 -Tssize_t
--Ttls_client_init_props
--Ttls_client_start_props
--Ttls_info_t
--Ttls_server_props
--Ttls_server_start_props
index b0787657c5175e7365bb5b1712fa54a7d3467125..b8302f2951f00fd9e41a782dc8b38ebbdd6de4f1 100644 (file)
@@ -14049,6 +14049,58 @@ Apologies for any names omitted.
        Cleanup: don't try sending HELO after a 421 EHLO reply.
        File: smtp/smtp_proto.c.
 
+20071221-nonprod
+
+       Using 20071221 as reference point.
+
+       Cleanup: Simplified TLS library cipher and protocol API to
+       just pass string-valued properties to tls_client_init() and
+       tls_client_start(). The client is now agnostic of the
+       mechanics of cipher management internal to the library. The
+       main.cf parameters used internally in the library are now
+       loaded by the library, not the caller. Files:
+       src/smtp/lmtp_params.c, src/smtp/smtp.c, src/smtp/smtp.h,
+       src/smtp/smtp_params.c, src/smtp/smtp_proto.c,
+       src/smtp/smtp_session.c, src/smtpd/smtpd.c, src/tls/tls.h,
+       src/tls/tls_client.c, src/tls/tls_level.c, src/tls/tls_misc.c,
+       src/tls/tls_server.c, src/tls/tls_session.c, src/tls/tls_verify.c
+       and src/tlsmgr/tlsmgr.c
+
+       Cleanup: Client session lookup key "salting" is now handled
+       internally in the tls library. Files: src/tls/tls_client.c
+
+       Cleanup: Cipher state is cached, and only updated when
+       necessary.  Files: src/tls/tls_misc.c
+
+       Feature: Extended the syntax of protocol selection to allow
+       exclusions as well as inclusions. Files: src/tls/tls_misc.c
+
+       Cleanup: Updated default verification depth to match reality:
+       default is 9 in OpenSSL and we don't yet override it.  When
+       we do (soon), the default will match previous behavior.
+       Files: src/global/mail_params.h
+
+       Bugfix: Reference to obsolete "pfixtls" code won't compile
+       inside #ifdef for OpenSSL <= 0.9.5a. Using an OpenSSL release
+       that old has not been tested for some time, but may now
+       work. Files: src/tls/tls_bio_ops.c.
+
+       Replaced "void *" TLS library application handles by explicit
+       pointer types, while hiding data structure implementation
+       details from the TLS library users. Files: tls/tls_client.c,
+       tls/tls_server.c, smtp/smtp.c, smtpd/smtpd.c.
+
+       The TLS library no longer modifies VSTRINGs passed in by
+       the caller. Where possible, information is passed as "const"
+       from application to library. Files: smtp/smtp_proto.c,
+       tls/tls_client.c.
+
+20071227-nonprod
+
+       Replaced explicit initialization of props structures by
+       emulating function calls with named parameter lists.  Files:
+       tls/tls.h, smtp/smtp.c, smtp/smtp_proto.c, smtpd/smtpd.c.
+
 20071222
 
        Further polishing of the Milter code and logging. File:
@@ -14088,18 +14140,94 @@ Apologies for any names omitted.
        generic "4.3.0 Sevice unavailable", but log the text for
        the actual error. File: cleanup/cleanup_milter.c.
 
+20080102-nonprod
+
+       SMTP client fingerprint security level support and configurable
+       fingerprint digest algorithm. Victor Duchovni. Files:
+       smtp/lmtp_params.c, smtp/smtp.c, smtp/smtp.h,
+       src/smtp/smtp_params.c, src/smtp/smtp_proto.c,
+       src/smtp/smtp_session.c, tls/tls_client.c, tls/tls_level.c,
+       tls/tls_verify.c.
+
+20080103-nonprod
+
+       Missed "invalid TLS configuration" patch for SMTP client.
+       Victor Duchovni. File: smtp/smtp_proto.c.
+
+       SMTP server configurable fingerprint digest algorithm.
+       Victor Duchovni. Files: smtpd/smtpd.c, tls/tls.h,
+       tls/tls_server.c, tls/tls_verify.c.
+
+20080104-nonprod
+
+       Cleanup: finally implemented certificate verification depth
+       limit parameters. Prior to Postfix 2.5 these were ignored.
+       For backwards compatibility, the default verification depth
+       limit is now 9, the OpenSSL default. Victor Duchovni. Files:
+       src/tls/tls_client.c, src/tls/tls_server.c, src/tls/tls_verify.c.
+
+       Robustness: Avoid possibility of NULL pointer issues in
+       application code that checks certificate names, by providing
+       "empty string" values when no data is available.  Victor
+       Duchovni.  Files: src/tls/tls_verify.c, src/tls/tls_client.c,
+       src/tls/tls_server.c, src/smtpd/smtpd_check.c, src/smtpd/smtpd.c.
+
+       Cleanup: separation of TLS handshake from security level
+       enforcement. The library shakes hands; the application
+       decides if the resulting security is acceptable. Victor
+       Duchovni.  Files: smtpd/smtpd.c, smtpd/smtpd_proto.c,
+       tls/tls_server.c, tls/tls_client.c, tls/tls_verify.c.
+
+       Robustness: more robust processing of ASN.1 string attributes
+       in x509v3 certificates, plus additional sanity checks (e.g.
+       embedded null characters). Victor Duchovni. File:
+       src/tls/tls_verify.c.
+
 20080104
 
        Workaround: minor change to the Dovecot AUTH request to
        prevent dovecot-auth memory wastage. Timo Sirainen.  File:
        xsasl/xsasl_dovecot_server.c.
 
-20070807
+20080105-nonprod
+
+       Cleanup: renamed TLS-related symbols for consistency (always
+       include the init, start, stop prefix in the TLS library
+       function and data structure names; consistently distinguish
+       between per-application TLS state and per-session TLS state;
+       consistently use the fpt prefix for fingerprint related
+       variables and structure members; consistent use of monocase
+       typedef-ed names).
+
+20080106-nonprod
+
+       Cleanup: consistent use of <pre> and <blockquote> in examples;
+       instead of emphasizing new Postfix 2.5 behavior in reference
+       documentation, describe the new behavior as "current", with
+       historical behavior as a supplemental note.
+
+20080107
+
+       Feature: new "pass" service type (in addition to "inet",
+       "unix" and "fifo").  The "pass" service type supports
+       front-end daemons that accept all inbound connections and
+       that permit only well-behaved clients to talk to the MTA.
+       This service type had been sitting in the master daemon for
+       years but was disabled by default.  Actual applications for
+       this will have to be developed later.  Files: util/upass_connect.c,
+       util/upass_trigger.c.
+
+20080108
+
+       Cleanup: where possible, store data structures in read-only
+       memory. Besides the security advantage of no write access,
+       this also gives slightly better memory utilization when
+       many processes execute the same file. Files: pretty much
+       everything that has a static table, except for a few tables
+       in the benchmark tools with flags that are controlled by
+       command-line information.
+
+20080109
 
-       Feature (experimental release only): new "pass" service
-       type (in addition to "inet", "unix" and "fifo").  The "pass"
-       service type supports front-end daemons that accept all
-       inbound connections and that permit only well-behaved clients
-       to talk to the MTA. This service type had been sitting in
-       the master daemon for years but was disabled by default.
-       Files: util/upass_connect.c, util/upass_trigger.c.
+       Cleanup: more read-only data. Files: everything that passes
+       around a HEADER_OPTS pointer.
index bcd5ffc83672451388eef7f26974d75140c1f94c..dbdd3171f0b346fc9653a85c6070421a8fcdf45f 100644 (file)
@@ -8,8 +8,8 @@ This document describes the symptoms of Postfix SMTP server overload, and how
 to avoid the condition under normal conditions. When the condition is caused by
 botnets or other malware, the document suggests configuration settings that
 help to minimize the impact on legitimate mail. Finally, the document
-introduces Postfix stress-adaptive behavior, and how it can be used to
-automatically switch configuration settings under overload.
+introduces stress-adaptive behavior, introduced with Postfix 2.5, and how it
+can be used to automatically switch configuration settings under overload.
 
 Topics covered in this document:
 
@@ -26,27 +26,17 @@ Topics covered in this document:
 S\bSy\bym\bmp\bpt\bto\bom\bms\bs o\bof\bf P\bPo\bos\bst\btf\bfi\bix\bx S\bSM\bMT\bTP\bP s\bse\ber\brv\bve\ber\br o\bov\bve\ber\brl\blo\boa\bad\bd
 
 Under normal conditions, Postfix responds immediately when a remote SMTP client
-connects. The time needed to deliver mail to Postfix may depend on how busy the
-CPU or disk are, but that should be noticeable only with very large messages.
-Performance degrades more dramatically when the number of remote SMTP clients
-exceeds the number of Postfix SMTP server processes. When a client connects
-while all server processes are busy, the client must wait until a server
-process becomes available.
+connects. The time needed to deliver mail should be noticeable only with very
+large messages. Performance degrades more dramatically when the number of
+remote SMTP clients exceeds the number of Postfix SMTP server processes. When a
+client connects while all server processes are busy, the client must wait until
+a server process becomes available.
 
 Overload may be caused by a legitimate mail (example: a DNS registrar opens a
 new zone for registrations), by mistake (mail explosion caused by a forwarding
 loop) or by illegitimate mail (worm outbreak, botnet, or other malware
 activity). Symptoms of Postfix SMTP mail server overload are:
 
-  * Postfix logs a warning that all server ports are busy:
-
-    Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
-     (25) has reached its process limit "30": new clients may experience
-     noticeable delays
-    Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
-     condition, increase the process count in master.cf or reduce the
-     service time per client
-
   * Remote SMTP clients experience a long delay before Postfix sends the "220
     hostname.example.com ESMTP Postfix" greeting. If this affects end-user mail
     clients, enable the "submission" service entry in master.cf (present since
@@ -57,7 +47,16 @@ activity). Symptoms of Postfix SMTP mail server overload are:
     CONNECT" events. This happens because remote SMTP clients disconnect before
     Postfix answers the connection.
 
-NOTE: The last two symptoms also happen without overload.
+  * Postfix 2.3 and later logs a warning that all server ports are busy:
+
+    Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
+     (25) has reached its process limit "30": new clients may experience
+     noticeable delays
+    Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
+     condition, increase the process count in master.cf or reduce the
+     service time per client
+
+NOTE: The first two symptoms may also happen without overload, for example:
 
   * Broken DNS also causes lengthy delays before "220 hostname.example.com ..."
     while the Postfix SMTP server tries to look up the client's hostname.
index 7c5011927f9fd24350b85452b04e0a24a451b4c1..e11a09668e73438432a72ab5d22691fbaa10017e 100644 (file)
@@ -5,10 +5,10 @@ P\bPo\bos\bst\btf\bfi\bix\bx T\bTL\bLS\bS S\bSu\bup\bpp\bpo\bor\brt\bt
 W\bWA\bAR\bRN\bNI\bIN\bNG\bG
 
 By turning on TLS support in Postfix, you not only get the ability to encrypt
-mail and to authenticate clients or servers. You also turn on thousands and
-thousands of lines of OpenSSL library code. Assuming that OpenSSL is written as
-carefully as Wietse's own code, every 1000 lines introduce one additional bug
-into Postfix.
+mail and to authenticate remote SMTP clients or servers. You also turn on
+thousands and thousands of lines of OpenSSL library code. Assuming that OpenSSL
+is written as carefully as Wietse's own code, every 1000 lines introduce one
+additional bug into Postfix.
 
 W\bWh\bha\bat\bt P\bPo\bos\bst\btf\bfi\bix\bx T\bTL\bLS\bS s\bsu\bup\bpp\bpo\bor\brt\bt d\bdo\boe\bes\bs f\bfo\bor\br y\byo\bou\bu
 
@@ -126,7 +126,7 @@ S\bSe\ber\brv\bve\ber\br-\b-s\bsi\bid\bde\be c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be a\ban\bnd\bd p\b
 
 In order to use TLS, the Postfix SMTP server generally needs a certificate and
 a private key. Both must be in "PEM" format. The private key must not be
-encrypted, meaning: the key must be accessible without password. Both
+encrypted, meaning: the key must be accessible without a password. The
 certificate and private key may be in the same file, in which case the
 certificate file should be owned by "root" and not be readable by any other
 user. If the key is stored separately, this applies to the key file only, and
@@ -134,19 +134,20 @@ the certificate file may be "world-readable".
 
 Public Internet MX hosts without certificates signed by a "reputable" CA must
 generate, and be prepared to present to most clients, a self-signed or private-
-CA signed certificate. The client will not be able to authenticate the server,
-but unless it is running Postfix 2.3 or similar software, it will still insist
-on a server certificate.
+CA signed certificate. The remote SMTP client will generally not be able to
+authenticate the self-signed certificate, but unless the client is running
+Postfix 2.3 or similar software, it will still insist on a server certificate.
 
-For servers that are n\bno\bot\bt public Internet MX hosts, Postfix 2.3 supports
+For servers that are n\bno\bot\bt public Internet MX hosts, Postfix supports
 configurations with no certificates. This entails the use of just the anonymous
 TLS ciphers, which are not supported by typical SMTP clients. Since such
 clients will not, as a rule, fall back to plain text after a TLS handshake
-failure, the server will be unable to receive email from most TLS enabled
-clients. To avoid accidental configurations with no certificates, Postfix 2.3
-enables certificate-less operation only when the administrator explicitly sets
-"smtpd_tls_cert_file = none". This ensures that new Postfix configurations will
-not accidentally run with no certificates.
+failure, a certificate-less Postfix SMTP server will be unable to receive email
+from most TLS enabled clients. To avoid accidental configurations with no
+certificates, Postfix enables certificate-less operation only when the
+administrator explicitly sets "smtpd_tls_cert_file = none". This ensures that
+new Postfix SMTP server configurations will not accidentally run with no
+certificates.
 
 Both RSA and DSA certificates are supported. Typically you will only have RSA
 certificates issued by a commercial CA. In addition, the tools supplied with
@@ -160,9 +161,9 @@ the CA certificate (in case of a certificate chain, all CA certificates) must
 be available. You should add any intermediate CA certificates to the server
 certificate: the server certificate first, then the intermediate CA(s).
 
-Example: the certificate for "server.dom.ain" was issued by "intermediate CA"
-which itself has a certificate issued by "root CA". Create the server.pem file
-with:
+Example: the certificate for "server.example.com" was issued by "intermediate
+CA" which itself has a certificate issued by "root CA". Create the server.pem
+file with:
 
     % c\bca\bat\bt s\bse\ber\brv\bve\ber\br_\b_c\bce\ber\brt\bt.\b.p\bpe\bem\bm i\bin\bnt\bte\ber\brm\bme\bed\bdi\bia\bat\bte\be_\b_C\bCA\bA.\b.p\bpe\bem\bm >\b> s\bse\ber\brv\bve\ber\br.\b.p\bpe\bem\bm
 
@@ -175,14 +176,7 @@ of the "server.pem" file reduces the overhead of the TLS exchange.
 
 If you want the Postfix SMTP server to accept remote SMTP client certificates
 issued by these CAs, append the root certificate to $smtpd_tls_CAfile or
-install it in the $smtpd_tls_CApath directory. When you configure trust in a
-root CA, it is not necessary to explicitly trust intermediary CAs signed by the
-root CA, unless $smtpd_tls_ccert_verifydepth is less than the number of CAs in
-the certificate chain for the clients of interest. With a verify depth of 1 you
-can only verify certificates directly signed by a trusted CA, and all trusted
-intermediary CAs need to be configured explicitly. With a verify depth of 2 you
-can verify clients signed by a root CA or a direct intermediary CA (so long as
-the client is correctly configured to supply its intermediate CA certificate).
+install it in the $smtpd_tls_CApath directory.
 
 RSA key and certificate examples:
 
@@ -220,14 +214,14 @@ files in the directory when the information is needed. Thus, the
 $smtpd_tls_CApath directory needs to be accessible inside the optional chroot
 jail.
 
-When you configure Postfix to request client certificates, any CA certificates
-in $smtpd_tls_CAfile are sent to the client, in order to allow it to choose an
-identity signed by a CA you trust. If no $smtpd_tls_CAfile is specified, no
-preferred CA list is sent, and the client is free to choose an identity signed
-by any CA. Many clients use a fixed identity regardless of the preferred CA
-list and you may be able to reduce TLS negotiation overhead by installing
-client CA certificates mostly or only in $smtpd_tls_CApath. In the latter case
-you need not specify a $smtpd_tls_CAfile.
+When you configure the Postfix SMTP server to request client certificates, any
+CA certificates in $smtpd_tls_CAfile are sent to the client, in order to allow
+it to choose an identity signed by a CA you trust. If no $smtpd_tls_CAfile is
+specified, no preferred CA list is sent, and the client is free to choose an
+identity signed by any CA. Many clients use a fixed identity regardless of the
+preferred CA list and you may be able to reduce TLS negotiation overhead by
+installing client CA certificates mostly or only in $smtpd_tls_CApath. In the
+latter case you need not specify a $smtpd_tls_CAfile.
 
 Note, that unless client certificates are used to allow greater access to TLS
 authenticated clients, it is best to not ask for client certificates at all, as
@@ -292,12 +286,12 @@ Example:
         # Obsolete, but still supported
         smtpd_use_tls = yes
 
-With this, Postfix SMTP server announces STARTTLS support to SMTP clients, but
-does not require that clients use TLS encryption.
+With this, the Postfix SMTP server announces STARTTLS support to remote SMTP
+clients, but does not require that clients use TLS encryption.
 
 Note: when an unprivileged user invokes "sendmail -bs", STARTTLS is never
-offered due to insufficient privileges to access the server private key. This
-is intended behavior.
+offered due to insufficient privileges to access the Postfix SMTP server
+private key. This is intended behavior.
 
 You can ENFORCE the use of TLS, so that the Postfix SMTP server announces
 STARTTLS and accepts no mail without TLS encryption, by setting
@@ -315,10 +309,10 @@ Example:
         smtpd_enforce_tls = yes
 
 TLS is sometimes used in the non-standard "wrapper" mode where a server always
-uses TLS, instead of announcing STARTTLS support and waiting for clients to
-request TLS service. Some clients, namely Outlook [Express] prefer the
-"wrapper" mode. This is true for OE (Win32 < 5.0 and Win32 >=5.0 when run on a
-port<>25 and OE (5.01 Mac on all ports).
+uses TLS, instead of announcing STARTTLS support and waiting for remote SMTP
+clients to request TLS service. Some clients, namely Outlook [Express] prefer
+the "wrapper" mode. This is true for OE (Win32 < 5.0 and Win32 >=5.0 when run
+on a port<>25 and OE (5.01 Mac on all ports).
 
 It is strictly discouraged to use this mode from main.cf. If you want to
 support this service, enable a special port in master.cf and specify "-
@@ -344,8 +338,8 @@ session. So this option is "off" by default. You will however need the
 certificate if you want to use certificate based relaying with, for example,
 the permit_tls_clientcerts feature. A server that wants client certificates
 must first present its own certificate. While Postfix 2.3 by default offers
-anonymous ciphers to clients, these are automatically suppressed when the
-server is configured to ask for client certificates.
+anonymous ciphers to remote SMTP clients, these are automatically suppressed
+when the Postfix SMTP server is configured to ask for client certificates.
 
 Example:
 
@@ -370,15 +364,22 @@ Example:
         # Obsolete, but still supported
         smtpd_enforce_tls = yes
 
-A client certificate verification depth of 1 is sufficient if the certificate
-is directly issued by a CA listed in the CA file. The default value (5) should
-also suffice for longer chains (root CA issues special CA which then issues the
-actual certificate...)
+The client certificate verification depth is specified with the main.cf
+smtpd_tls_ccert_verifydepth parameter. The default verification depth is 9 (the
+OpenSSL default), for compatibility with Postfix versions before 2.5 where
+smtpd_tls_ccert_verifydepth was ignored. When you configure trust in a root CA,
+it is not necessary to explicitly trust intermediary CAs signed by the root CA,
+unless $smtpd_tls_ccert_verifydepth is less than the number of CAs in the
+certificate chain for the clients of interest. With a verify depth of 1 you can
+only verify certificates directly signed by a trusted CA, and all trusted
+intermediary CAs need to be configured explicitly. With a verify depth of 2 you
+can verify clients signed by a root CA or a direct intermediary CA (so long as
+the client is correctly configured to supply its intermediate CA certificate).
 
 Example:
 
     /etc/postfix/main.cf:
-        smtpd_tls_ccert_verifydepth = 5
+        smtpd_tls_ccert_verifydepth = 2
 
 S\bSu\bup\bpp\bpo\bor\brt\bti\bin\bng\bg A\bAU\bUT\bTH\bH o\bov\bve\ber\br T\bTL\bLS\bS o\bon\bnl\bly\by
 
@@ -448,17 +449,22 @@ Postfix TLS support introduces three additional features for Postfix SMTP
 server access control:
 
     permit_tls_clientcerts
-        Allow the remote SMTP client SMTP request if the client certificate
-        passes verification, and if its fingerprint is listed in the list of
-        client certificates (see relay_clientcerts discussion below).
+        Allow the remote SMTP client request if the client certificate
+        fingerprint is listed in the client certificate table (see
+        relay_clientcerts discussion below).
 
     permit_tls_all_clientcerts
-        Allow the remote client SMTP request if the client certificate passes
-        verification.
+        Allow the remote SMTP client request if the client certificate passes
+        trust chain verification. Useful with private-label CAs that only issue
+        certificates to trusted clients (and not otherwise).
 
     check_ccert_access type:table
-        If the client certificate passes verification, use its fingerprint as a
-        key for the specified access(5) table.
+        Use the remote SMTP client certificate fingerprint as the lookup key
+        for the specified access(5) table.
+
+The digest algorithm used to construct the client certificate fingerprints is
+specified with the main.cf smtpd_tls_fingerprint_digest parameter. The default
+is "md5", for compatibility with Postfix versions < 2.5.
 
 The permit_tls_all_clientcerts feature must be used with caution, because it
 can result in too many access permissions. Use this feature only if a special
@@ -481,14 +487,9 @@ Example:
             reject_unauth_destination
             ...
 
-The Postfix list manipulation routines give special treatment to whitespace and
-some other characters, making the use of certificate names impractical. Instead
-we use the certificate fingerprints as they are difficult to fake but easy to
-use for lookup. Postfix lookup tables are in the form of (key, value) pairs.
-Since we only need the key, the value can be chosen freely, e.g. the name of
-the user or host.
-
-Example:
+Example: Postfix lookup tables are in the form of (key, value) pairs. Since we
+only need the key, the value can be chosen freely, e.g. the name of the user or
+host:
 
     /etc/postfix/main.cf:
         relay_clientcerts = hash:/etc/postfix/relay_clientcerts
@@ -532,23 +533,24 @@ Example: (MSA that requires TLS with high grade ciphers)
         smtpd_tls_key_file = /etc/postfix/key.pem
         smtpd_tls_mandatory_ciphers = high
         smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5
-        # Postfix 2.3 and later
         smtpd_tls_security_level = encrypt
-        # Obsolete, but still supported
-        smtpd_enforce_tls = yes
-
-If you want to take advantage of ciphers with EDH, DH parameters are needed.
-Instead of using the built-in DH parameters for both 1024bit and 512bit, it is
-better to generate your own parameters, since otherwise it would "pay" for a
-possible attacker to start a brute force attack against parameters that are
-used by everybody. For this reason, the default parameters chosen by OpenSSL
-are already different from those distributed with other TLS packages.
+        smtpd_tls_mandatory_protocols = TLSv1
+        # Also available with Postfix >= 2.5:
+        smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
+
+If you want to take advantage of ciphers with ephemeral Diffie-Hellman (EDH)
+key exchange (this offers "forward-secrecy"), DH parameters are needed. Instead
+of using the built-in DH parameters for both 1024-bit (non-export ciphers) and
+512-bit (export ciphers), it is better to generate your own parameters, since
+otherwise it would "pay" for a possible attacker to start a brute force attack
+against parameters that are used by everybody. Postfix defaults to compiled-in
+parameters that are shared by all Postfix users who don't generate their own
+settings.
 
 To generate your own set of DH parameters, use:
 
-    % o\bop\bpe\ben\bns\bss\bsl\bl g\bge\ben\bnd\bdh\bh -\b-o\bou\but\bt /\b/e\bet\btc\bc/\b/p\bpo\bos\bst\btf\bfi\bix\bx/\b/d\bdh\bh_\b_1\b10\b02\b24\b4.\b.p\bpe\bem\bm -\b-2\b2 -\b-r\bra\ban\bnd\bd /\b/v\bva\bar\br/\b/r\bru\bun\bn/\b/e\beg\bgd\bd-\b-p\bpo\boo\bol\bl
-    1\b10\b02\b24\b4
-    % o\bop\bpe\ben\bns\bss\bsl\bl g\bge\ben\bnd\bdh\bh -\b-o\bou\but\bt /\b/e\bet\btc\bc/\b/p\bpo\bos\bst\btf\bfi\bix\bx/\b/d\bdh\bh_\b_5\b51\b12\b2.\b.p\bpe\bem\bm -\b-2\b2 -\b-r\bra\ban\bnd\bd /\b/v\bva\bar\br/\b/r\bru\bun\bn/\b/e\beg\bgd\bd-\b-p\bpo\boo\bol\bl 5\b51\b12\b2
+    % o\bop\bpe\ben\bns\bss\bsl\bl g\bge\ben\bnd\bdh\bh -\b-o\bou\but\bt /\b/e\bet\btc\bc/\b/p\bpo\bos\bst\btf\bfi\bix\bx/\b/d\bdh\bh_\b_5\b51\b12\b2.\b.p\bpe\bem\bm -\b-2\b2 5\b51\b12\b2
+    % o\bop\bpe\ben\bns\bss\bsl\bl g\bge\ben\bnd\bdh\bh -\b-o\bou\but\bt /\b/e\bet\btc\bc/\b/p\bpo\bos\bst\btf\bfi\bix\bx/\b/d\bdh\bh_\b_1\b10\b02\b24\b4.\b.p\bpe\bem\bm -\b-2\b2 1\b10\b02\b24\b4
 
 Examples:
 
@@ -579,6 +581,7 @@ Topics covered in this section:
   * Disabling TLS in the SMTP/LMTP client
   * Enabling TLS in the SMTP/LMTP client
   * Mandating TLS encryption
+  * Certificate fingerprint verification
   * Mandating server certificate verification
   * Secure server certificate verification
   * Per-destination TLS policy
@@ -592,29 +595,27 @@ Topics covered in this section:
 
 T\bTL\bLS\bS s\bsu\bup\bpp\bpo\bor\brt\bt i\bin\bn t\bth\bhe\be L\bLM\bMT\bTP\bP d\bde\bel\bli\biv\bve\ber\bry\by a\bag\bge\ben\bnt\bt
 
-In Postfix 2.3, the smtp(8) and lmtp(8) delivery agents have been merged into a
-single dual-purpose program. As a result the lmtp(8) delivery agent is no
-longer the poor cousin of the more extensively used smtp(8). Specifically, as
-of Postfix 2.3, all the TLS features described below apply equally to SMTP and
-LMTP, after replacing the "smtp_" prefix of the each parameter name with
-"lmtp_".
-
-The LMTP delivery agent can communicate with LMTP servers listening on UNIX-
-domain sockets. When server certificate verification is enabled and the server
-is listening on a UNIX-domain socket, the $myhostname parameter is used to set
-the TLS verification nexthop and hostname. Note, opportunistic encryption of
-LMTP traffic over UNIX-domain sockets is futile. TLS is only useful in this
-context when it is mandatory, typically to allow at least one of the server or
-the client to authenticate the other. The "null" cipher grade may be
-appropriate in this context, when available on both client and server. The
+The smtp(8) and lmtp(8) delivery agents are implemented by a single dual-
+purpose program. Specifically, all the TLS features described below apply
+equally to SMTP and LMTP, after replacing the "smtp_" prefix of the each
+parameter name with "lmtp_".
+
+The Postfix LMTP delivery agent can communicate with LMTP servers listening on
+UNIX-domain sockets. When server certificate verification is enabled and the
+server is listening on a UNIX-domain socket, the $myhostname parameter is used
+to set the TLS verification nexthop and hostname. Note, opportunistic
+encryption of LMTP traffic over UNIX-domain sockets is futile. TLS is only
+useful in this context when it is mandatory, typically to allow at least one of
+the server or the client to authenticate the other. The "null" cipher grade may
+be appropriate in this context, when available on both client and server. The
 "null" ciphers provide authentication without encryption.
 
 C\bCl\bli\bie\ben\bnt\bt-\b-s\bsi\bid\bde\be c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be a\ban\bnd\bd p\bpr\bri\biv\bva\bat\bte\be k\bke\bey\by c\bco\bon\bnf\bfi\big\bgu\bur\bra\bat\bti\bio\bon\bn
 
-Do not configure client certificates unless you m\bmu\bus\bst\bt present client TLS
-certificates to one or more servers. Client certificates are not usually
-needed, and can cause problems in configurations that work well without them.
-The recommended setting is to let the defaults stand:
+Do not configure Postfix SMTP client certificates unless you m\bmu\bus\bst\bt present
+client TLS certificates to one or more servers. Client certificates are not
+usually needed, and can cause problems in configurations that work well without
+them. The recommended setting is to let the defaults stand:
 
         smtp_tls_cert_file =
         smtp_tls_dcert_file =
@@ -661,14 +662,7 @@ of the "client.pem" file reduces the overhead of the TLS exchange.
 
 If you want the Postfix SMTP client to accept remote SMTP server certificates
 issued by these CAs, append the root certificate to $smtp_tls_CAfile or install
-it in the $smtp_tls_CApath directory. When you configure trust in a root CA, it
-is not necessary to explicitly trust intermediary CAs signed by the root CA,
-unless $smtp_tls_scert_verifydepth is less than the number of CAs in the
-certificate chain for the servers of interest. With a verify depth of 1 you can
-only verify certificates directly signed by a trusted CA, and all trusted
-intermediary CAs need to be configured explicitly. With a verify depth of 2 you
-can verify servers signed by a root CA or a direct intermediary CA (so long as
-the server is correctly configured to supply its intermediate CA certificate).
+it in the $smtp_tls_CApath directory.
 
 RSA key and certificate examples:
 
@@ -860,6 +854,8 @@ m\bma\bay\by
     Opportunistic TLS.
 e\ben\bnc\bcr\bry\byp\bpt\bt
     Mandatory TLS encryption.
+f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt
+    Certificate fingerprint verification.
 v\bve\ber\bri\bif\bfy\by
     Mandatory server certificate verification.
 s\bse\bec\bcu\bur\bre\be
@@ -941,11 +937,11 @@ M\bMa\ban\bnd\bda\bat\bto\bor\bry\by T\bTL\bLS\bS e\ben\bnc\bcr\bry\byp\bpt\bti\bio\bon\bn
 
 At the "encrypt" TLS security level, messages are sent only over TLS encrypted
 sessions. The SMTP transaction is aborted unless the STARTTLS ESMTP feature is
-supported by the server. If no suitable servers are found, the message will be
-deferred. With Postfix 2.3 and later, mandatory TLS encryption can be
-configured by setting "smtp_tls_security_level = encrypt". Even though TLS
-encryption is always used, mail delivery continues if the server certificate is
-untrusted or bears the wrong name.
+supported by the remote SMTP server. If no suitable servers are found, the
+message will be deferred. With Postfix 2.3 and later, mandatory TLS encryption
+can be configured by setting "smtp_tls_security_level = encrypt". Even though
+TLS encryption is always used, mail delivery continues even if the server
+certificate is untrusted or bears the wrong name.
 
 At this security level and higher, the smtp_tls_mandatory_protocols and
 smtp_tls_mandatory_ciphers configuration parameters determine the list of
@@ -1039,16 +1035,68 @@ table; use the new policy table instead.
     /etc/postfix/tls_per_site:
         [example.net]:587   MUST_NOPEERMATCH
 
+C\bCe\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt v\bve\ber\bri\bif\bfi\bic\bca\bat\bti\bio\bon\bn
+
+Certificate fingerprint verification is available with Postfix 2.5 and later.
+At this security level ("smtp_tls_security_level = fingerprint"), no trusted
+certificate authorities are used or required. The certificate trust chain,
+expiration date, ... are not checked. Instead, the
+smtp_tls_fingerprint_cert_match parameter or the "match" attribute in the
+policy table lists the valid "fingerprints" of the remote SMTP server
+certificate.
+
+If certificate fingerprints are exchanged securely, this is the strongest, and
+least scalable security level. The administrator needs to securely collect the
+fingerprints of the X.509 certificates of each peer server, store them into a
+local file, and update this local file whenever the peer server's public
+certificate changes. This may be feasible for an SMTP "VPN" connecting a small
+number of branch offices over the Internet, or for secure connections to a
+central mail hub. It works poorly if the remote SMTP server is managed by a
+third party, and its public certificate changes periodically without prior
+coordination with the verifying site.
+
+The digest algorithm used to calculate the fingerprint is selected by the
+s\bsm\bmt\btp\bp_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_d\bdi\big\bge\bes\bst\bt parameter. In the policy table multiple
+fingerprints can be combined with a "|" delimiter in a single match attribute,
+or multiple match attributes can be employed. The ":" character is not used as
+a delimiter as it occurs between each pair of fingerprint (hexadecimal) digits.
+
+Example: fingerprint TLS security with an internal mailhub. Two matching
+fingerprints are listed. The relayhost may be multiple physical hosts behind a
+load-balancer, each with its own private/public key and self-signed
+certificate. Alternatively, a single relayhost may be in the process of
+switching from one set of private/public keys to another, and both keys are
+trusted just prior to the transition.
+
+        relayhost = [mailhub.example.com]
+        smtp_tls_security_level = fingerprint
+        smtp_tls_fingerprint_digest = md5
+        smtp_tls_fingerprint_cert_match =
+            3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+            EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+
+Example: Certificate fingerprint verification with selected destinations. As in
+the example above, we show two matching fingerprints:
+
+    /etc/postfix/main.cf:
+        smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+        smtp_tls_fingerprint_digest = md5
+
+    /etc/postfix/tls_policy:
+        example.com    fingerprint
+            match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+            match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+
 M\bMa\ban\bnd\bda\bat\bto\bor\bry\by s\bse\ber\brv\bve\ber\br c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be v\bve\ber\bri\bif\bfi\bic\bca\bat\bti\bio\bon\bn
 
 At the "verify" TLS security level, messages are sent only over TLS encrypted
-sessions if the server certificate is valid (not expired or revoked, and signed
-by a trusted certificate authority) and if the server certificate name matches
-a known pattern. Mandatory server certificate verification can be configured by
-setting "smtp_tls_security_level = verify". The smtp_tls_verify_cert_match
-parameter can override the default "hostname" certificate name matching
-strategy. Fine-tuning the matching strategy is generally only appropriate for
-secure-channel destinations.
+sessions if the remote SMTP server certificate is valid (not expired or
+revoked, and signed by a trusted certificate authority) and where the server
+certificate name matches a known pattern. Mandatory server certificate
+verification can be configured by setting "smtp_tls_security_level = verify".
+The smtp_tls_verify_cert_match parameter can override the default "hostname"
+certificate name matching strategy. Fine-tuning the matching strategy is
+generally only appropriate for secure-channel destinations.
 
 With Postfix 2.2 and earlier, or when smtp_tls_security_level is set to its
 default (backwards compatible) empty value, the appropriate configuration
@@ -1057,9 +1105,9 @@ For LMTP use the corresponding "lmtp_" parameters.
 
 If the server certificate chain is trusted (see smtp_tls_CAfile and
 smtp_tls_CApath), any DNS names in the SubjectAlternativeName certificate
-extension are used to verify the server name. If no DNS names are specified,
-the certificate CommonName is checked. If you want mandatory encryption without
-server certificate verification, see above.
+extension are used to verify the remote SMTP server name. If no DNS names are
+specified, the certificate CommonName is checked. If you want mandatory
+encryption without server certificate verification, see above.
 
 Despite the potential for eliminating "man-in-the-middle" and other attacks,
 mandatory certificate trust chain and subject name verification is not viable
@@ -1085,9 +1133,10 @@ policy settings.
 
 Example:
 
-In this example, the client encrypts all traffic to the example.com domain. The
-peer hostname is verified, but verification is vulnerable to DNS response
-forgery. Mail transmission to example.com recipients uses "high" grade ciphers.
+In this example, the Postfix SMTP client encrypts all traffic to the
+example.com domain. The peer hostname is verified, but verification is
+vulnerable to DNS response forgery. Mail transmission to example.com recipients
+uses "high" grade ciphers.
 
     /etc/postfix/main.cf:
         indexed = ${default_database_type}:${config_directory}/
@@ -1124,9 +1173,9 @@ DNS data. For LMTP, use the corresponding "lmtp_" parameters.
 
 If the server certificate chain is trusted (see smtp_tls_CAfile and
 smtp_tls_CApath), any DNS names in the SubjectAlternativeName certificate
-extension are used to verify the server name. If no DNS names are specified,
-the CommonName is checked. If you want mandatory encryption without server
-certificate verification, see above.
+extension are used to verify the remote SMTP server name. If no DNS names are
+specified, the CommonName is checked. If you want mandatory encryption without
+server certificate verification, see above.
 
 Despite the potential for eliminating "man-in-the-middle" and other attacks,
 mandatory secure server certificate verification is not viable as a default
@@ -1153,12 +1202,13 @@ Examples:
 
 Secure-channel TLS without transport(5) table overrides:
 
-The client will encrypt all traffic and verify the destination name immune from
-forged DNS responses. MX lookups are still used to find the SMTP servers for
-example.com, but these are not used when checking the names in the server
-certificate(s). Rather, the requirement is that the MX hosts for example.com
-have trusted certificates with a subject name of example.com or a sub-domain,
-see the documentation for the smtp_tls_secure_cert_match parameter.
+The Postfix SMTP client will encrypt all traffic and verify the destination
+name immune from forged DNS responses. MX lookups are still used to find the
+hostnames of the SMTP servers for example.com, but these hostnames are not used
+when checking the names in the server certificate(s). Rather, the requirement
+is that the MX hosts for example.com have trusted certificates with a subject
+name of example.com or a sub-domain, see the documentation for the
+smtp_tls_secure_cert_match parameter.
 
 The related domains example.co.uk and example.co.jp are hosted on the same MX
 hosts as the primary example.com domain, and traffic to these is secured by
@@ -1279,25 +1329,37 @@ n\bno\bon\bne\be
 m\bma\bay\by
     Opportunistic TLS. No additional attributes are supported at this level.
 e\ben\bnc\bcr\bry\byp\bpt\bt
-    Mandatory TLS encryption. Mail is delivered only if remote SMTP server
+    Mandatory encryption. Mail is delivered only if the remote SMTP server
     offers STARTTLS and the TLS handshake succeeds. At this level and higher
     the optional "ciphers" attribute overrides the main.cf
-    smtp_tls_mandatory_ciphers parameter and the optional "protocols" keyword
-    overrides the main.cf smtp_tls_mandatory_protocols parameter.
+    smtp_tls_mandatory_ciphers parameter, and the optional "protocols"
+    attribute overrides the main.cf smtp_tls_mandatory_protocols parameter.
+f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt
+    Certificate fingerprint verification. Available with Postfix 2.5 and later.
+    At this security level, there are no trusted certificate authorities. The
+    certificate trust chain, expiration date, ... are not checked. Instead, the
+    optional m\bma\bat\btc\bch\bh attribute, or else the main.cf
+    s\bsm\bmt\btp\bp_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_c\bce\ber\brt\bt_\b_m\bma\bat\btc\bch\bh parameter, lists the valid fingerprints of
+    the server certificate. The digest algorithm used to calculate fingerprints
+    is selected by the s\bsm\bmt\btp\bp_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_d\bdi\big\bge\bes\bst\bt parameter. Multiple
+    fingerprints can be combined with a "|" delimiter in a single match
+    attribute, or multiple match attributes can be employed. The ":" character
+    is not used as a delimiter as it occurs between each pair of fingerprint
+    (hexadecimal) digits.
 v\bve\ber\bri\bif\bfy\by
     Mandatory server certificate verification. Mail is delivered only if the
-    TLS handshake succeeds, if the server certificate can be validated (not
-    expired or revoked, and signed by a trusted certificate authority), and if
-    the server certificate name matches the optional "match" attribute (or the
-    main.cf smtp_tls_verify_cert_match parameter value when no optional "match"
-    attribute is specified).
+    TLS handshake succeeds, if the remote SMTP server certificate can be
+    validated (not expired or revoked, and signed by a trusted certificate
+    authority), and if the server certificate name matches the optional "match"
+    attribute (or the main.cf smtp_tls_verify_cert_match parameter value when
+    no optional "match" attribute is specified).
 s\bse\bec\bcu\bur\bre\be
-    Secure-channel TLS. Mail is delivered only if the TLS handshake succeeds,
-    if the server certificate can be validated (not expired or revoked, and
-    signed by a trusted certificate authority), and if the server certificate
-    name matches the optional "match" attribute (or the main.cf
-    smtp_tls_secure_cert_match parameter value when no optional "match"
-    attribute is specified).
+    Secure certificate verification. Mail is delivered only if the TLS
+    handshake succeeds, if the remote SMTP server certificate can be validated
+    (not expired or revoked, and signed by a trusted certificate authority),
+    and if the server certificate name matches the optional "match" attribute
+    (or the main.cf smtp_tls_secure_cert_match parameter value when no optional
+    "match" attribute is specified).
 Notes:
 
   * The "match" attribute is especially useful to verify TLS certificates for
@@ -1316,6 +1378,8 @@ Example:
 
     /etc/postfix/main.cf:
         smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+        # Postfix 2.5 and later
+        smtp_tls_fingerprint_digest = md5
     /etc/postfix/tls_policy:
         example.edu             none
         example.mil             may
@@ -1325,6 +1389,10 @@ Example:
         example.net             secure
         .example.net            secure match=.example.net:example.net
         [mail.example.org]:587  secure match=nexthop
+        # Postfix 2.5 and later
+        [thumb.example.org]         fingerprint
+               match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+       match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
 
 N\bNo\bot\bte\be:\b: The "hostname" strategy if listed in a non-default setting of
 smtp_tls_secure_cert_match or in the "match" attribute in the policy table can
@@ -1509,16 +1577,22 @@ Example:
 
 S\bSe\ber\brv\bve\ber\br c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be v\bve\ber\bri\bif\bfi\bic\bca\bat\bti\bio\bon\bn d\bde\bep\bpt\bth\bh
 
-When verifying a remote SMTP server certificate, a verification depth of 1 is
-sufficient if the certificate is directly issued by a CA specified with
-smtp_tls_CAfile or smtp_tls_CApath. The default value of 5 should also suffice
-for longer chains (where the root CA issues a special CA certificate which then
-issues the actual certificate).
+The server certificate verification depth is specified with the main.cf
+smtp_tls_scert_verifydepth parameter. The default verification depth is 9 (the
+OpenSSL default), for compatibility with Postfix versions before 2.5 where
+smtp_tls_scert_verifydepth was ignored. When you configure trust in a root CA,
+it is not necessary to explicitly trust intermediary CAs signed by the root CA,
+unless $smtp_tls_scert_verifydepth is less than the number of CAs in the
+certificate chain for the servers of interest. With a verify depth of 1 you can
+only verify certificates directly signed by a trusted CA, and all trusted
+intermediary CAs need to be configured explicitly. With a verify depth of 2 you
+can verify servers signed by a root CA or a direct intermediary CA (so long as
+the server is correctly configured to supply its intermediate CA certificate).
 
 Example:
 
     /etc/postfix/main.cf:
-        smtp_tls_scert_verifydepth = 5
+        smtp_tls_scert_verifydepth = 2
 
 C\bCl\bli\bie\ben\bnt\bt-\b-s\bsi\bid\bde\be c\bci\bip\bph\bhe\ber\br c\bco\bon\bnt\btr\bro\bol\bls\bs
 
@@ -1531,12 +1605,13 @@ today's crypt-analytic methods. See smtp_tls_policy_maps for information on how
 to configure ciphers on a per-destination basis.
 
 By default anonymous ciphers are allowed, and automatically disabled when
-server certificates are verified. If you want to disable anonymous ciphers even
-at the "encrypt" security level, set "smtp_tls_mandatory_exclude_ciphers =
-aNULL"; and to disable anonymous ciphers even with opportunistic TLS, set
-"smtp_tls_exclude_ciphers = aNULL". There is generally no need to take these
-measures. Anonymous ciphers save bandwidth and TLS session cache space, if
-certificates are ignored, there is little point in requesting them.
+remote SMTP server certificates are verified. If you want to disable anonymous
+ciphers even at the "encrypt" security level, set
+"smtp_tls_mandatory_exclude_ciphers = aNULL"; and to disable anonymous ciphers
+even with opportunistic TLS, set "smtp_tls_exclude_ciphers = aNULL". There is
+generally no need to take these measures. Anonymous ciphers save bandwidth and
+TLS session cache space, if certificates are ignored, there is little point in
+requesting them.
 
 Example:
 
@@ -1544,6 +1619,9 @@ Example:
         smtp_tls_mandatory_ciphers = medium
         smtp_tls_mandatory_exclude_ciphers = RC4, MD5
         smtp_tls_exclude_ciphers = aNULL
+        smtp_tls_mandatory_protocols = SSLv3, TLSv1
+        # Also available with Postfix >= 2.5:
+        smtp_tls_mandatory_protocols = !SSLv2
 
 C\bCl\bli\bie\ben\bnt\bt-\b-s\bsi\bid\bde\be S\bSM\bMT\bTP\bPS\bS s\bsu\bup\bpp\bpo\bor\brt\bt
 
@@ -1793,7 +1871,7 @@ indicates a super-user shell.
             smtp_tls_CAfile = /etc/postfix/cacert.pem
             smtp_tls_session_cache_database =
                btree:/var/lib/postfix/smtp_tls_session_cache
-            smtp_use_tls = yes
+            smtp_tls_security_level = may
             smtpd_tls_CAfile = /etc/postfix/cacert.pem
             smtpd_tls_cert_file = /etc/postfix/FOO-cert.pem
             smtpd_tls_key_file = /etc/postfix/FOO-key.pem
@@ -1822,4 +1900,8 @@ C\bCr\bre\bed\bdi\bit\bts\bs
   * Victor Duchovni was instrumental with the re-implementation of the
     smtp_tls_per_site code in terms of enforcement levels, which simplified the
     implementation greatly.
+  * Victor Duchovni implemented the fingerprint security level, added more
+    sanity checks, and separated TLS connection management from security policy
+    enforcement. The latter change simplified the code that verifies
+    certificate signatures, certificate names, and certificate fingerprints.
 
index cc1d9e95dac126d422817b4e26a1bed033fcf078..a1b9ec37417b6835640134c6bce9b704c9d9db89 100644 (file)
@@ -11,15 +11,75 @@ instead, a new snapshot is released.
 The mail_release_date configuration parameter (format: yyyymmdd)
 specifies the release date of a stable release or snapshot release.
 
+Incompatibility with Postfix snapshot 20080109
+==============================================
+
+TLS logging output has changed to make it more useful. Existing
+logfile parser regular expressions may need adjustment.
+
+- More log entries include the "hostnamename[ipaddress]" of the
+  remote SMTP peer.
+
+- Certificate trust chain error reports show only the first
+  error certificate (closest to the trust chain root), and the
+  reporting is more human-readable for the most likely errors.
+
+- After the completion of the TLS handshake, the session is logged
+  with TLS loglevel >= 1 as either "Untrusted", "Trusted" or
+  "Verified" (SMTP client only).
+  - "Untrusted" means that the certificate trust chain is invalid,
+    or that the root CA is not trusted.
+  - "Trusted" means that the certificate trust chain is valid, and
+    that the root CA is trusted.
+  - "Verified" means that the certificate meets the SMTP client's
+    matching criteria for the destination:
+    - In the case of a destination name match, "Verified" also
+      implies "Trusted".
+    - In the case of a fingerprint match, CA trust is not applicable.
+
+- The logging of protocol states with TLS loglevel >= 2 no longer
+  reports bogus error conditions when OpenSSL asks Postfix to refill
+  (or flush) network I/O buffers.  This loglevel is for debugging
+  only; use 0 or 1 in production configurations.
+
+Major changes with Postfix snapshot 20080109
+============================================
+
+The Postfix SMTP client has a new "fingerprint" security level.
+This avoids dependencies on CAs, and relies entirely on bi-lateral
+exchange of public keys (really self-signed or private CA signed
+X.509 public key certificates). Scalability is clearly limited. For
+details, see the fingerprint discussion in TLS_README.
+
+The Postfix SMTP server can now use SHA1 instead of MD5 to compute
+remote SMTP client certificate fingerprints. For backwards
+compatibility, the default algorithm is MD5.  For details, see the
+"smtpd_tls_fingerprint_digest" parameter in the postconf(5) manual.
+
+The maximum certificate trust chain depth (verifydepth) is finally
+implemented in the Postfix TLS library. Previously, the parameter
+had no effect. The default depth was changed to 9 (the OpenSSL
+default) for backwards compatibility.
+
+If you have explicity limited the verification depth in main.cf,
+check that the configured limit meets your needs. See the
+"lmtp_tls_scert_verifydepth", "smtp_tls_scert_verifydepth" and
+"smtpd_tls_ccert_verifydepth" parameters in the postconf(5) manual.
+
+The selection of SSL/TLS protocols for mandatory TLS can now use
+exclusion rather than inclusion. Either form is acceptable; see the
+"lmtp_tls_mandatory_protocols", "smtp_tls_mandatory_protocols" and
+"smtpd_tls_mandatory_protocols" parameters in the postconf(5) manual.
+
 Major changes with Postfix snapshot 20080107
 ============================================
 
 New "pass" service type in master.cf.  Written years ago, this
-allows a front-end daemon to accept all connections from the network,
-and forward only those from well-behaved clients to Postfix. Since
-this uses file descriptor passing, it imposes no overhead once a
-connection is handed over to Postfix. This is available in the
-experimental release only. See master(5) for a few details.
+allows a future front-end daemon to accept all connections from the
+network, and forward only those from well-behaved clients to Postfix.
+Since this uses file descriptor passing, it imposes no overhead
+once a connection is handed over to Postfix. See master(5) for a
+few details.
 
 Incompatibility with Postfix snapshot 20071224
 ==============================================
index 575c25ff352829d7e2ace21e6d55e9cd3df4d4c6..05590100ca6d4b6b7de4ae46ca6e326ed1a496c3 100644 (file)
@@ -1,5 +1,19 @@
 This list does not really follow priority.
 
+* Code cleanup: split smtp_session.c into generic SMTP, legacy TLS,
+  and current TLS.  The amount of TLS code now dominates the file.
+  Do this after all other code revisions stabilize, to avoid
+  complicating code reviews.
+
+* Code cleanup: TLS_LEV_NOTFOUND no longer belongs in the TLS
+  library. It is an SMTP-client only feature. To fix, change the
+  policy lookup API and use a different method to indicate if a
+  policy was found. At the same time, fix policy lookup to initialize
+  session->tls_level.
+
+* Code cleanup: see if multiple consecutive switches can be aggregated
+  (set_cipher_grade() and session_tls_init()).
+
 * Implement support of CRL checking. OpenSSL 0.9.7 finally supports CRLs,
   so Postfix/TLS should support loading CRLs.
 
index 179fbcba1cf0aeb3cebc067273058817e9b2dc22..de66e9fe9e00c45fc6f854009b160a3b47634a28 100644 (file)
@@ -1,5 +1,7 @@
 Wish list:
 
+       Consolidate duplicated code *_server_accept_{pass,inet}().
+
        Consolidate duplicated code in {inet,unix,upass}_trigger.c.
 
        In the SMTP client, handle 421 replies in smtp_loop() by
index 61a0e7032dd141e4a2879899e5c89e520fcc9dcf..1ea44d77b3562456ab2defc5582e84ac4b244135 100644 (file)
@@ -24,9 +24,10 @@ Stress-Dependent Configuration</h1>
 overload, and how to avoid the condition under normal conditions.
 When the condition is caused by botnets or other malware, the
 document suggests configuration settings that help to minimize the
-impact on legitimate mail.  Finally, the document introduces Postfix
-stress-adaptive behavior, and how it can be used to automatically
-switch configuration settings under overload.  </p>
+impact on legitimate mail.  Finally, the document introduces
+stress-adaptive behavior, introduced with Postfix 2.5, and how it
+can be used to automatically switch configuration settings under
+overload.  </p>
 
 <p> Topics covered in this document: </p>
 
@@ -55,8 +56,7 @@ switch configuration settings under overload.  </p>
 <h2><a name="overload"> Symptoms of Postfix SMTP server overload </a></h2>
 
 <p> Under normal conditions, Postfix responds immediately when a
-remote SMTP client connects. The time needed to deliver mail to
-Postfix may depend on how busy the CPU or disk are, but that should
+remote SMTP client connects. The time needed to deliver mail should
 be noticeable only with very large messages.  Performance degrades
 more dramatically when the number of remote SMTP clients exceeds
 the number of Postfix SMTP server processes.  When a client connects
@@ -71,17 +71,6 @@ SMTP mail server overload are: </p>
 
 <ul>
 
-<li> <p> Postfix logs a warning that all server ports are busy: </p>
-
-<pre>
-Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
- (25) has reached its process limit "30": new clients may experience
- noticeable delays
-Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
- condition, increase the process count in <a href="master.5.html">master.cf</a> or reduce the
- service time per client
-</pre>
-
 <li> <p> Remote SMTP clients experience a long delay before Postfix
 sends the "220 hostname.example.com ESMTP Postfix" greeting.  If
 this affects end-user mail clients, enable the "submission" service
@@ -92,9 +81,22 @@ connect to this instead of the public SMTP service. </p>
 connection after CONNECT" events. This happens because remote SMTP
 clients disconnect before Postfix answers the connection. </p>
 
+<li> <p> Postfix 2.3 and later logs a warning that all server ports
+are busy: </p>
+
+<pre>
+Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
+ (25) has reached its process limit "30": new clients may experience
+ noticeable delays
+Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
+ condition, increase the process count in <a href="master.5.html">master.cf</a> or reduce the
+ service time per client
+</pre>
+
 </ul>
 
-<p> NOTE: The last two symptoms also happen without overload. </p>
+<p> NOTE: The first two symptoms may also happen without overload,
+for example: </p>
 
 <ul>
 
index 81965f443a9090708800bba65cc9e41df5030c7f..9d6157aec8ab9da6837ce6fdfe49b5e1bb403e98 100644 (file)
@@ -21,7 +21,7 @@
 <h2> WARNING </h2>
 
 <p> By turning on TLS support in Postfix, you not only get the
-ability to encrypt mail and to authenticate clients or servers.
+ability to encrypt mail and to authenticate remote SMTP clients or servers.
 You also turn on thousands and thousands of lines of OpenSSL library
 code.  Assuming that OpenSSL is written as carefully as Wietse's
 own code, every 1000 lines introduce one additional bug into
@@ -225,7 +225,7 @@ key configuration </a> </h3>
 <p> In order to use TLS, the Postfix SMTP server generally needs
 a certificate and a private key. Both must be in "PEM" format. The
 private key must not be encrypted, meaning:  the key must be accessible
-without password.  Both certificate and private key may be in the same
+without a password.  The certificate and private key may be in the same
 file, in which case the certificate file should be owned by "root" and
 not be readable by any other user. If the key is stored separately,
 this applies to the key file only, and the certificate file may be
@@ -233,20 +233,24 @@ this applies to the key file only, and the certificate file may be
 
 <p> Public Internet MX hosts without certificates signed by a "reputable"
 CA must generate, and be prepared to present to most clients, a
-self-signed or private-CA signed certificate. The client will not be
-able to authenticate the server, but unless it is running Postfix 2.3 or
+self-signed or private-CA signed certificate. The remote SMTP client
+will generally not be
+able to authenticate the self-signed certificate, but unless the
+client is running Postfix 2.3 or
 similar software, it will still insist on a server certificate. </p>
 
 <p> For servers that are <b>not</b> public Internet MX hosts, Postfix
-2.3 supports configurations with no certificates. This entails the
+supports configurations with no certificates. This entails the
 use of just the anonymous TLS ciphers, which are not supported by
 typical SMTP clients. Since such clients will not, as a rule, fall
-back to plain text after a TLS handshake failure, the server will
+back to plain text after a TLS handshake failure, a certificate-less
+Postfix SMTP server will
 be unable to receive email from most TLS enabled clients. To avoid
-accidental configurations with no certificates, Postfix 2.3 enables
+accidental configurations with no certificates, Postfix enables
 certificate-less operation only when the administrator explicitly sets
 "<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a> = none". This ensures that new Postfix
-configurations will not accidentally run with no certificates. </p>
+SMTP server configurations will not accidentally run with no
+certificates. </p>
 
 <p> Both RSA and DSA certificates are supported. Typically you will
 only have RSA certificates issued by a commercial CA. In addition,
@@ -262,7 +266,7 @@ chain, all CA certificates) must be available.  You should add any
 intermediate CA certificates to the server certificate: the server
 certificate first, then the intermediate CA(s).  </p>
 
-<p> Example: the certificate for "server.dom.ain" was issued by
+<p> Example: the certificate for "server.example.com" was issued by
 "intermediate CA" which itself has a certificate issued by "root
 CA".  Create the server.pem file with: </p>
 
@@ -283,15 +287,7 @@ the overhead of the TLS exchange. </p>
 
 <p> If you want the Postfix SMTP server to accept remote SMTP client
 certificates issued by these CAs, append the root certificate to
-$<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> or install it in the $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> directory.  When
-you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a>
-is less than the number of CAs in the certificate chain for the clients
-of interest. With a verify depth of 1 you can only verify certificates
-directly signed by a trusted CA, and all trusted intermediary CAs need to
-be configured explicitly. With a verify depth of 2 you can verify clients
-signed by a root CA or a direct intermediary CA (so long as the client
-is correctly configured to supply its intermediate CA certificate). </p>
+$<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> or install it in the $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> directory. </p>
 
 <p> RSA key and certificate examples: </p>
 
@@ -347,7 +343,7 @@ privileges) from the files in the directory when the information
 is needed. Thus, the $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> directory needs to be
 accessible inside the optional chroot jail. </p>
 
-<p> When you configure Postfix to request <a
+<p> When you configure the Postfix SMTP server to request <a
 href="#server_vrfy_client">client certificates</a>, any CA certificates
 in $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> are sent to the client, in order to allow it to
 choose an identity signed by a CA you trust. If no $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a>
@@ -450,12 +446,13 @@ supported). </p>
 </pre>
 </blockquote>
 
-<p> With this, Postfix SMTP server announces STARTTLS support to
-SMTP clients, but does not require that clients use TLS encryption.
+<p> With this, the Postfix SMTP server announces STARTTLS support to
+remote SMTP clients, but does not require that clients use TLS encryption.
 </p>
 
 <p> Note: when an unprivileged user invokes "sendmail -bs", STARTTLS
-is never offered due to insufficient privileges to access the server
+is never offered due to insufficient privileges to access the Postfix
+SMTP server
 private key. This is intended behavior. </p>
 
 <p> <a name="server_enforce">You can ENFORCE the use of TLS</a>,
@@ -481,7 +478,8 @@ by default and should only seldom be used. </p>
 
 <p> TLS is sometimes used in the non-standard "wrapper" mode where
 a server always uses TLS, instead of announcing STARTTLS support
-and waiting for clients to request TLS service. Some clients, namely
+and waiting for remote SMTP clients to request TLS service. Some
+clients, namely
 Outlook [Express] prefer the "wrapper" mode.  This is true for OE
 (Win32 &lt; 5.0 and Win32 &gt;=5.0 when run on a port&lt;&gt;25
 and OE (5.01 Mac on all ports). </p>
@@ -517,8 +515,10 @@ this option is "off" by default. You will however need the certificate
 if you want to use certificate based relaying with, for example, the
 <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a> feature. A server that wants client certificates
 must first present its own certificate. While Postfix 2.3 by default
-offers anonymous ciphers to clients, these are automatically suppressed
-when the server is configured to ask for client certificates. </p>
+offers anonymous ciphers to remote SMTP clients, these are automatically
+suppressed
+when the Postfix SMTP server is configured to ask for client
+certificates. </p>
 
 <p> Example: </p>
  
@@ -553,18 +553,26 @@ logged. </p>
 </pre>
 </blockquote>
 
-<p> A client certificate verification depth of 1 is sufficient if
-the certificate is directly issued by a CA listed in the CA file.
-The default value (5) should also suffice for longer chains (root
-CA issues special CA which then issues the actual certificate...)
-</p>
+<p> The client certificate verification depth is specified with the
+<a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> parameter. The default verification
+depth is 9 (the OpenSSL default), for compatibility with Postfix
+versions before 2.5 where <a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> was ignored.
+When you configure trust in a
+root CA, it is not necessary to explicitly trust intermediary CAs signed
+by the root CA, unless $<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> is less than the
+number of CAs in the certificate chain for the clients of interest. With
+a verify depth of 1 you can only verify certificates directly signed
+by a trusted CA, and all trusted intermediary CAs need to be configured
+explicitly. With a verify depth of 2 you can verify clients signed by a
+root CA or a direct intermediary CA (so long as the client is correctly
+configured to supply its intermediate CA certificate). </p>
 
 <p> Example: </p>
  
 <blockquote>
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> = 5
+    <a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> = 2
 </pre>
 </blockquote>
 
@@ -661,23 +669,30 @@ Postfix SMTP server access control:  </p>
 
 <dl>
 
-<dt> <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a> </dt> <dd> <p> Allow the remote SMTP
-client SMTP request if the client certificate passes verification,
-and if its fingerprint is listed in the list of client certificates
-(see <a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a> discussion below). </p> </dd>
+<dt> <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a> </dt> <dd> <p> Allow the remote SMTP client
+request if the client certificate fingerprint is listed in the
+client certificate table (see <a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a> discussion below). </p>
+</dd>
 
-<dt> <a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> </dt> <dd> <p> Allow the remote
-client SMTP request if the client certificate passes verification.
-</p> </dd>
+<dt> <a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> </dt> <dd> <p> Allow the remote SMTP
+client request if the client certificate passes trust chain verification.
+Useful with private-label CAs that only issue certificates to trusted
+clients (and not otherwise). </p> </dd>
 
-<dt> <a href="postconf.5.html#check_ccert_access">check_ccert_access</a> <a href="DATABASE_README.html">type:table</a></dt> <dd>
-<p> If the client certificate passes verification, use its fingerprint
-as a key for the specified <a href="access.5.html">access(5)</a> table. </p> </dd>
+<dt> <a href="postconf.5.html#check_ccert_access">check_ccert_access</a> <a href="DATABASE_README.html">type:table</a></dt> <dd> <p> Use the remote SMTP
+client
+certificate fingerprint as the lookup key for the specified <a href="access.5.html">access(5)</a>
+table. </p> </dd>
 
 </dl>
 
 </blockquote>
 
+<p> The digest algorithm used to construct the client certificate
+fingerprints is specified with the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a>
+parameter.  The default is "md5", for compatibility with Postfix
+versions &lt; 2.5. </p>
+
 <p> The <a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> feature must be used with caution,
 because it can result in too many access permissions.  Use this
 feature only if a special CA issues the client certificates, and
@@ -704,16 +719,10 @@ certificate must no longer be used (e.g. an employee leaving). </p>
 </pre>
 </blockquote>
 
-<p> The Postfix list manipulation routines give special treatment
-to whitespace and some other characters, making the use of certificate
-names impractical.  Instead we use the certificate fingerprints as
-they are difficult to fake but easy to use for lookup.  Postfix
-lookup tables are in the form of (key, value) pairs.  Since we only
-need the key, the value can be chosen freely, e.g.  the name of
-the user or host.</p>
+<p> Example: Postfix lookup tables are in the form of (key, value)
+pairs. Since we only need the key, the value can be chosen freely, e.g.
+the name of the user or host:</p>
 
-<p> Example: </p>
 <blockquote>
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
@@ -766,27 +775,29 @@ and not specifying an <a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_d
     <a href="postconf.5.html#smtpd_tls_key_file">smtpd_tls_key_file</a> = /etc/postfix/key.pem
     <a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a> = high
     <a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">smtpd_tls_mandatory_exclude_ciphers</a> = aNULL, MD5
-    # Postfix 2.3 and later
     <a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a> = encrypt
-    # Obsolete, but still supported
-    <a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a> = yes
+    <a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = TLSv1
+    # Also available with Postfix &ge; 2.5:
+    <a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = !SSLv2, !SSLv3
 </pre>
 </blockquote>
 
-<p> If you want to take advantage of ciphers with EDH, DH parameters
-are needed.  Instead of using the built-in DH parameters for both
-1024bit and 512bit, it is better to generate your own parameters,
-since otherwise it would "pay" for a possible attacker to start a
-brute force attack against parameters that are used by everybody.
-For this reason, the default parameters chosen by OpenSSL are already
-different from those distributed with other TLS packages. </p>
+<p> If you want to take advantage of ciphers with ephemeral Diffie-Hellman
+(EDH) key exchange (this offers "forward-secrecy"), DH parameters are
+needed.  Instead of using the built-in DH parameters for both 1024-bit
+(non-export ciphers) and 512-bit (export ciphers), it is better to
+generate your own parameters, since otherwise it would "pay" for a
+possible attacker to start a brute force attack against parameters that
+are used by everybody.  Postfix defaults to compiled-in parameters
+that are shared by all Postfix users who don't generate their own
+settings. </p>
 
 <p> To generate your own set of DH parameters, use: </p>
 
 <blockquote>
 <pre>
-% <b>openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024</b>
-% <b>openssl gendh -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512</b>
+% <b>openssl gendh -out /etc/postfix/dh_512.pem -2 512</b>
+% <b>openssl gendh -out /etc/postfix/dh_1024.pem -2 1024</b>
 </pre>
 </blockquote>
 
@@ -841,6 +852,8 @@ key configuration </a>
 
 <li><a href="#client_tls_encrypt"> Mandating TLS encryption </a>
 
+<li><a href="#client_tls_fprint"> Certificate fingerprint verification </a>
+
 <li><a href="#client_tls_verify"> Mandating server certificate verification </a>
 
 <li><a href="#client_tls_secure"> Secure server certificate verification </a>
@@ -866,14 +879,14 @@ key configuration </a>
 <h3><a name="client_lmtp_tls"> TLS support in the LMTP delivery agent </a>
 </h3>
 
-<p> In Postfix 2.3, the <a href="smtp.8.html">smtp(8)</a> and <a href="lmtp.8.html">lmtp(8)</a> delivery agents have been
-merged into a single dual-purpose program. As a result the <a href="lmtp.8.html">lmtp(8)</a>
-delivery agent is no longer the poor cousin of the more extensively used
-<a href="smtp.8.html">smtp(8)</a>. Specifically, as of Postfix 2.3, all the TLS features described
-below apply equally to SMTP and LMTP, after replacing the "smtp_"
-prefix of the each parameter name with "lmtp_".
+<p> The <a href="smtp.8.html">smtp(8)</a> and <a href="lmtp.8.html">lmtp(8)</a> delivery agents are implemented by a
+single dual-purpose program.  Specifically, all the TLS features
+described below apply
+equally to SMTP and LMTP, after replacing the "smtp_" prefix of the each
+parameter name with "lmtp_".
 
-<p> The LMTP delivery agent can communicate with LMTP servers listening
+<p> The Postfix LMTP delivery agent can communicate with LMTP servers
+listening
 on UNIX-domain sockets. When server certificate verification is enabled
 and the server is listening on a UNIX-domain socket, the $<a href="postconf.5.html#myhostname">myhostname</a>
 parameter is used to set the TLS verification <i>nexthop</i> and
@@ -887,7 +900,8 @@ The "null" ciphers provide authentication without encryption. </p>
 <h3><a name="client_cert_key">Client-side certificate and private
 key configuration </a> </h3>
 
-<p> Do not configure client certificates unless you <b>must</b> present
+<p> Do not configure Postfix SMTP client certificates unless you <b>must</b>
+present
 client TLS certificates to one or more servers. Client certificates are
 not usually needed, and can cause problems in configurations that work
 well without them. The recommended setting is to let the defaults stand: </p>
@@ -951,15 +965,7 @@ the overhead of the TLS exchange. </p>
 
 <p> If you want the Postfix SMTP client to accept remote SMTP server
 certificates issued by these CAs, append the root certificate to
-$<a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> or install it in the $<a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a> directory.  When
-you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $<a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a>
-is less than the number of CAs in the certificate chain for the servers
-of interest. With a verify depth of 1 you can only verify certificates
-directly signed by a trusted CA, and all trusted intermediary CAs need to
-be configured explicitly. With a verify depth of 2 you can verify servers
-signed by a root CA or a direct intermediary CA (so long as the server
-is correctly configured to supply its intermediate CA certificate). </p>
+$<a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> or install it in the $<a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a> directory. </p>
 
 <p> RSA key and certificate examples: </p>
  
@@ -1212,6 +1218,8 @@ in the sections that follow.</p>
 <dd><a href="#client_tls_may">Opportunistic TLS.</a></dd>
 <dt><b>encrypt</b></dt>
 <dd><a href="#client_tls_encrypt">Mandatory TLS encryption.</a>
+<dt><b>fingerprint</b></dt>
+<dd><a href="#client_tls_fprint">Certificate fingerprint verification.</a>
 <dt><b>verify</b></dt>
 <dd><a href="#client_tls_verify">Mandatory server certificate verification.</a>
 <dt><b>secure</b></dt>
@@ -1314,11 +1322,12 @@ on TLS <a href="#client_tls_limits">limitations</a> above. </p>
 
 <p> At the "encrypt" TLS security level, messages are sent only
 over TLS encrypted sessions. The SMTP transaction is aborted unless
-the STARTTLS ESMTP feature is supported by the server. If no suitable
+the STARTTLS ESMTP feature is supported by the remote SMTP server.
+If no suitable
 servers are found, the message will be deferred. With Postfix 2.3
 and later, mandatory TLS encryption can be configured by setting
 "<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = encrypt". Even though TLS
-encryption is always used, mail delivery continues if the server
+encryption is always used, mail delivery continues even if the server
 certificate is untrusted or bears the wrong name. </p>
 
 <p> At this security level and higher, the <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>
@@ -1437,13 +1446,82 @@ use the new <a href="#client_tls_policy">policy table</a> instead. </p>
 </pre>
 </blockquote>
 
+<h3><a name="client_tls_fprint"> Certificate fingerprint verification </a>
+</h3>
+
+<p> Certificate fingerprint verification is available with Postfix 2.5 and
+later. At this security level ("<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = fingerprint"),
+no trusted certificate authorities are used or required.  The certificate
+trust chain, expiration date, ... are not checked. Instead, the
+<a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> parameter or the "match" attribute
+in the <a href="#client_tls_policy">policy</a> table lists the valid
+"fingerprints" of the remote SMTP server certificate. </p>
+
+<p> If certificate fingerprints are exchanged securely, this is the
+strongest, and least scalable security level. The administrator needs to
+securely collect the fingerprints of the X.509 certificates of each peer
+server, store them into a local file, and update this local file
+whenever the peer server's public certificate
+changes. This may be feasible for an SMTP "VPN" connecting a small
+number of branch offices over the Internet, or for secure connections
+to a central mail hub. It works poorly if the remote SMTP server is
+managed by a
+third party, and its public certificate changes periodically without
+prior coordination with the verifying site. </p>
+
+<p> The digest algorithm used to calculate the fingerprint is
+selected by the <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b> parameter. In the <a
+href="#client_tls_policy">policy</a> table multiple fingerprints can be
+combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </p>
+
+<p> Example: fingerprint TLS security with an internal mailhub.
+Two matching fingerprints are listed. The <a href="postconf.5.html#relayhost">relayhost</a> may be multiple
+physical hosts behind a load-balancer, each with its own private/public
+key and self-signed certificate. Alternatively, a single <a href="postconf.5.html#relayhost">relayhost</a> may
+be in the process of switching from one set of private/public keys to
+another, and both keys are trusted just prior to the transition. </p>
+
+<blockquote>
+<pre>
+    <a href="postconf.5.html#relayhost">relayhost</a> = [mailhub.example.com]
+    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = fingerprint
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+    <a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> =
+        3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+        EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
+<p> Example: Certificate fingerprint verification with selected destinations.
+As in the example above, we show two matching fingerprints: </p>
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = hash:/etc/postfix/tls_policy
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+</pre>
+</blockquote>
+<blockquote>
+<pre>
+/etc/postfix/tls_policy:
+    example.com        fingerprint
+        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
 <h3><a name="client_tls_verify"> Mandatory server certificate verification </a>
 </h3>
 
 <p> At the "verify" TLS security level, messages are sent only over
-TLS encrypted sessions if the server certificate is valid (not
+TLS encrypted sessions if the remote SMTP server certificate is
+valid (not
 expired or revoked, and signed by a trusted certificate authority)
-and if the server certificate name matches a known pattern.  Mandatory
+and where the server certificate name matches a known pattern.
+Mandatory
 server certificate verification can be configured by setting
 "<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = verify".  The
 <a href="postconf.5.html#smtp_tls_verify_cert_match">smtp_tls_verify_cert_match</a> parameter can override the default
@@ -1459,7 +1537,8 @@ appropriate configuration settings are "<a href="postconf.5.html#smtp_enforce_tl
 
 <p> If the server certificate chain is trusted (see <a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a>
 and <a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a>), any DNS names in the SubjectAlternativeName
-certificate extension are used to verify the server name.  If no
+certificate extension are used to verify the remote SMTP server name.
+If no
 DNS names are specified, the certificate CommonName is checked.
 If you want mandatory encryption without server certificate
 verification, see <a href="#client_tls_encrypt">above</a>. </p>
@@ -1492,7 +1571,7 @@ Postfix 2.3 and later should use the new TLS policy settings. </p>
 
 <p> Example: </p>
 
-<p> In this example, the client encrypts all traffic to the
+<p> In this example, the Postfix SMTP client encrypts all traffic to the
 <i>example.com</i> domain. The peer hostname is verified, but
 verification is vulnerable to DNS response forgery. Mail transmission
 to <i>example.com</i> recipients uses "high" grade ciphers. </p>
@@ -1543,7 +1622,8 @@ parameters. </p>
 
 <p> If the server certificate chain is trusted (see <a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> and
 <a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a>), any DNS names in the SubjectAlternativeName certificate
-extension are used to verify the server name. If no DNS names are
+extension are used to verify the remote SMTP server name. If no DNS names
+are
 specified, the CommonName is checked. If you want mandatory encryption
 without server certificate verification, see <a
 href="#client_tls_encrypt">above</a>. </p>
@@ -1578,9 +1658,11 @@ should use the new TLS policy settings. </p>
 
 <p> Secure-channel TLS without <a href="transport.5.html">transport(5)</a> table overrides: </p>
 
-<p> The client will encrypt all traffic and verify the destination name
+<p> The Postfix SMTP client will encrypt all traffic and verify the
+destination name
 immune from forged DNS responses. MX lookups are still used to find
-the SMTP servers for <i>example.com</i>, but these are not used when
+the hostnames of the SMTP servers for <i>example.com</i>, but these
+hostnames are not used when
 checking the names in the server certificate(s). Rather, the requirement
 is that the MX hosts for <i>example.com</i> have trusted certificates
 with a subject name of <i>example.com</i> or a sub-domain, see the
@@ -1729,35 +1811,50 @@ describe the corresponding table syntax: </p>
 
 <dl>
 
-<dt><b>none</b></dt>         
-<dd>No TLS. No additional attributes are supported at this level. </dd>
-
-<dt><b>may</b></dt>
-<dd>Opportunistic TLS. No additional attributes are supported at this
-level. </dd>
-
-<dt><b>encrypt</b></dt> <dd>Mandatory TLS encryption. Mail is
-delivered only if remote SMTP server offers STARTTLS and the TLS
-handshake succeeds.  At this level and higher the optional "ciphers"
-attribute overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> parameter
-and the optional "protocols" keyword overrides the <a href="postconf.5.html">main.cf</a>
-<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> parameter. </dd>
-
-<dt><b>verify</b></dt> <dd>Mandatory server certificate verification.
-Mail is delivered only if the TLS handshake succeeds, if the server
-certificate can be validated (not expired or revoked, and signed
-by a trusted certificate authority), and if the server certificate
-name matches the optional "match" attribute (or the <a href="postconf.5.html">main.cf</a>
-<a href="postconf.5.html#smtp_tls_verify_cert_match">smtp_tls_verify_cert_match</a> parameter value when no optional "match"
-attribute is specified).  </dd>
-
-<dt><b>secure</b></dt> <dd>Secure-channel TLS. Mail is delivered
-only if the TLS handshake succeeds, if the server certificate can
-be validated (not expired or revoked, and signed by a trusted
-certificate authority), and if the server certificate name matches
-the optional "match" attribute (or the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_secure_cert_match">smtp_tls_secure_cert_match</a>
-parameter value when no optional "match" attribute is specified).
-</dd>
+<dt><b>none</b></dt> <dd><a href="#client_tls_none">No TLS</a>. No
+additional attributes are supported at this level. </dd>
+
+<dt><b>may</b></dt> <dd><a href="#client_tls_may">Opportunistic TLS</a>.
+No additional attributes are supported at this level. </dd>
+
+<dt><b>encrypt</b></dt> <dd><a href="#client_tls_encrypt">Mandatory
+encryption</a>. Mail is delivered only if the remote SMTP
+server offers STARTTLS and the TLS handshake succeeds. At this
+level and higher the optional "ciphers" attribute overrides the
+<a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> parameter, and the optional
+"protocols" attribute
+overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> parameter. </dd>
+
+<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
+fingerprint verification.</a> Available with Postfix 2.5 and
+later. At this security level, there are no trusted certificate
+authorities. The certificate trust chain, expiration date, ... are
+not checked. Instead, the optional <b>match</b> attribute, or else
+the <a href="postconf.5.html">main.cf</a> <b><a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a></b> parameter,
+lists the valid fingerprints of the server certificate. The
+digest algorithm used to calculate fingerprints is selected by the
+<b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b> parameter. Multiple fingerprints can
+be combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </dd>
+
+<dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory
+server certificate verification</a>.  Mail is delivered only if the
+TLS handshake
+succeeds, if the remote SMTP server certificate can be validated (not
+expired or revoked, and signed by a trusted certificate authority), and
+if the server certificate name matches the optional "match" attribute (or
+the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_verify_cert_match">smtp_tls_verify_cert_match</a> parameter value when no optional
+"match" attribute is specified).  </dd>
+
+<dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate
+verification.</a> Mail is delivered only if the TLS handshake succeeds,
+if the remote SMTP server certificate can be validated (not expired
+or revoked, and signed by a trusted certificate authority), and if the
+server certificate name matches the optional "match" attribute (or the
+<a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_secure_cert_match">smtp_tls_secure_cert_match</a> parameter value when no optional
+"match" attribute is specified).  </dd>
 
 </dl>
 
@@ -1789,6 +1886,8 @@ Example:
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = hash:/etc/postfix/tls_policy
+    # Postfix 2.5 and later
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
 /etc/postfix/tls_policy:
     example.edu             none
     example.mil             may
@@ -1798,6 +1897,10 @@ Example:
     example.net             secure
     .example.net            secure match=.example.net:example.net
     [mail.example.org]:587  secure match=nexthop
+    # Postfix 2.5 and later
+    [thumb.example.org]         fingerprint
+       match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+       match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
 </pre>
 </blockquote>
 
@@ -2040,18 +2143,26 @@ postfix/smtp[pid]: Host offered STARTTLS: [hostname.example.com]
 
 <h3><a name="client_vrfy_server">Server certificate verification depth</a> </h3>
 
-<p> When verifying a remote SMTP server certificate, a verification
-depth of 1 is sufficient if the certificate is directly issued by
-a CA specified with <a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> or <a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a>.  The default
-value of 5 should also suffice for longer chains (where the root CA issues
-a special CA certificate which then issues the actual certificate). </p>
-
-<p> Example: </p>
+<p> The server certificate verification depth is specified with the
+<a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> parameter. The default verification
+depth is 9 (the OpenSSL default), for compatibility with Postfix
+versions before 2.5 where <a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> was ignored.
+When you configure trust
+in a root CA, it is not necessary to explicitly trust intermediary CAs
+signed by the root CA, unless $<a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> is less than the
+number of CAs in the certificate chain for the servers of interest. With
+a verify depth of 1 you can only verify certificates directly signed
+by a trusted CA, and all trusted intermediary CAs need to be configured
+explicitly. With a verify depth of 2 you can verify servers signed by a
+root CA or a direct intermediary CA (so long as the server is correctly
+configured to supply its intermediate CA certificate). </p>
  
+<p> Example: </p>
+
 <blockquote>
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> = 5
+    <a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> = 2
 </pre>
 </blockquote>
 
@@ -2067,7 +2178,8 @@ methods. See <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps
 ciphers on a per-destination basis. </p>
 
 <p> By default anonymous ciphers are allowed, and automatically
-disabled when server certificates are verified. If you want to
+disabled when remote SMTP server certificates are verified. If you
+want to
 disable anonymous ciphers even at the "encrypt" security level, set
 "<a href="postconf.5.html#smtp_tls_mandatory_exclude_ciphers">smtp_tls_mandatory_exclude_ciphers</a> = aNULL"; and to
 disable anonymous ciphers even with opportunistic TLS, set
@@ -2084,6 +2196,9 @@ little point in requesting them. </p>
     <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = medium
     <a href="postconf.5.html#smtp_tls_mandatory_exclude_ciphers">smtp_tls_mandatory_exclude_ciphers</a> = RC4, MD5
     <a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a> = aNULL
+    <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = SSLv3, TLSv1
+    # Also available with Postfix &ge; 2.5:
+    <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = !SSLv2
 </pre>
 </blockquote>
 
@@ -2405,7 +2520,7 @@ but don't require them from all clients. </p>
     <a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> = /etc/postfix/cacert.pem
     <a href="postconf.5.html#smtp_tls_session_cache_database">smtp_tls_session_cache_database</a> =
        btree:/var/lib/postfix/smtp_tls_session_cache
-    <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> = yes
+    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may
     <a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> = /etc/postfix/cacert.pem
     <a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a> = /etc/postfix/FOO-cert.pem
     <a href="postconf.5.html#smtpd_tls_key_file">smtpd_tls_key_file</a> = /etc/postfix/FOO-key.pem
@@ -2444,6 +2559,12 @@ compiled this part of the documentation from Lutz's documents.
 of the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> code in terms of enforcement levels, which
 simplified the implementation greatly.
 
+<li> Victor Duchovni implemented the fingerprint security level,
+added more sanity checks, and separated TLS connection management
+from security policy enforcement.  The latter change simplified the
+code that verifies certificate signatures, certificate names, and
+certificate fingerprints.
+
 </ul>
 
 </body>
index 9e1659cde673c16378c4987f1c22bf018712867c..949e74009429d113273283e2c49e5a71449cd797 100644 (file)
@@ -424,10 +424,10 @@ SMTP(8)                                                                SMTP(8)
               obsolete <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> parameter.
 
        <b><a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> (SSLv3, TLSv1)</b>
-              List  of TLS protocols that the Postfix SMTP client
-              will use with mandatory TLS encryption.
+              List  of  SSL/TLS  protocols  that the Postfix SMTP
+              client will use with mandatory TLS encryption.
 
-       <b><a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> (5)</b>
+       <b><a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> (9)</b>
               The verification depth for remote SMTP server  cer-
               tificates.
 
@@ -481,29 +481,40 @@ SMTP(8)                                                                SMTP(8)
               Postfix  SMTP  client  uses  for TLS encrypted SMTP
               sessions with a verified server certificate.
 
+       Available in Postfix version 2.5 and later:
+
+       <b><a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> (empty)</b>
+              List of acceptable remote SMTP  server  certificate
+              fingerprints  for  the  "fingerprint"  TLS security
+              level (<b><a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a></b> = fingerprint).
+
+       <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> (md5)</b>
+              The message  digest  algorithm  used  to  construct
+              remote SMTP server certificate fingerprints.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The following configuration parameters exist for  compati-
+       The  following configuration parameters exist for compati-
        bility with Postfix versions before 2.3. Support for these
        will be removed in a future release.
 
        <b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
-              Opportunistic mode: use  TLS  when  a  remote  SMTP
-              server  announces  STARTTLS support, otherwise send
+              Opportunistic  mode:  use  TLS  when  a remote SMTP
+              server announces STARTTLS support,  otherwise  send
               the mail in the clear.
 
        <b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
-              Enforcement mode: require that remote SMTP  servers
-              use  TLS  encryption,  and  never  send mail in the
+              Enforcement  mode: require that remote SMTP servers
+              use TLS encryption, and  never  send  mail  in  the
               clear.
 
        <b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
-              With mandatory TLS  encryption,  require  that  the
+              With  mandatory  TLS  encryption,  require that the
               remote SMTP server hostname matches the information
               in the remote SMTP server certificate.
 
        <b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
               Optional lookup tables with the Postfix SMTP client
-              TLS  usage  policy  by  next-hop destination and by
+              TLS usage policy by  next-hop  destination  and  by
               remote SMTP server hostname.
 
        <b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
@@ -513,27 +524,27 @@ SMTP(8)                                                                SMTP(8)
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#smtp_destination_concurrency_limit">smtp_destination_concurrency_limit</a>      ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
-              The  maximal  number  of parallel deliveries to the
-              same destination  via  the  smtp  message  delivery
+              The maximal number of parallel  deliveries  to  the
+              same  destination  via  the  smtp  message delivery
               transport.
 
        <b><a href="postconf.5.html#smtp_destination_recipient_limit">smtp_destination_recipient_limit</a>        ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
-              The  maximal  number of recipients per delivery via
+              The maximal number of recipients per  delivery  via
               the smtp message delivery transport.
 
        <b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
-              The SMTP client time limit  for  completing  a  TCP
+              The  SMTP  client  time  limit for completing a TCP
               connection,  or  zero  (use  the  operating  system
               built-in time limit).
 
        <b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
-              The SMTP client time limit for sending the HELO  or
-              EHLO  command, and for receiving the initial server
+              The  SMTP client time limit for sending the HELO or
+              EHLO command, and for receiving the initial  server
               response.
 
        <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
-              The LMTP client time limit  for  sending  the  LHLO
+              The  LMTP  client  time  limit for sending the LHLO
               command,  and  for  receiving  the  initial  server
               response.
 
@@ -542,30 +553,30 @@ SMTP(8)                                                                SMTP(8)
               command, and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
-              The  SMTP  client  time  limit for sending the MAIL
-              FROM  command,  and  for   receiving   the   server
+              The SMTP client time limit  for  sending  the  MAIL
+              FROM   command,   and   for  receiving  the  server
               response.
 
        <b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
-              RCPT TO  command,  and  for  receiving  the  server
+              The SMTP client time limit  for  sending  the  SMTP
+              RCPT  TO  command,  and  for  receiving  the server
               response.
 
        <b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
-              DATA  command,  and  for   receiving   the   server
+              The SMTP client time limit  for  sending  the  SMTP
+              DATA   command,   and   for  receiving  the  server
               response.
 
        <b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
+              The SMTP client time limit  for  sending  the  SMTP
               message content.
 
        <b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
+              The  SMTP  client  time  limit for sending the SMTP
               ".", and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_quit_timeout">smtp_quit_timeout</a> (300s)</b>
-              The  SMTP  client  time  limit for sending the QUIT
+              The SMTP client time limit  for  sending  the  QUIT
               command, and for receiving the server response.
 
        Available in Postfix version 2.1 and later:
@@ -576,12 +587,12 @@ SMTP(8)                                                                SMTP(8)
               lookups, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
-              The maximal number of SMTP  sessions  per  delivery
-              request  before  giving up or delivering to a fall-
+              The  maximal  number  of SMTP sessions per delivery
+              request before giving up or delivering to  a  fall-
               back <a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
-              The SMTP client time limit  for  sending  the  RSET
+              The  SMTP  client  time  limit for sending the RSET
               command, and for receiving the server response.
 
        Available in Postfix version 2.2 and earlier:
@@ -593,11 +604,11 @@ SMTP(8)                                                                SMTP(8)
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
-              Permanently enable SMTP connection caching for  the
+              Permanently  enable SMTP connection caching for the
               specified destinations.
 
        <b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
-              Temporarily  enable SMTP connection caching while a
+              Temporarily enable SMTP connection caching while  a
               destination has a high volume of mail in the active
               queue.
 
@@ -607,62 +618,62 @@ SMTP(8)                                                                SMTP(8)
 
        <b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
               When SMTP connection caching is enabled, the amount
-              of  time  that an unused SMTP client socket is kept
+              of time that an unused SMTP client socket  is  kept
               open before it is closed.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
-              Time limit for connection cache  connect,  send  or
+              Time  limit  for  connection cache connect, send or
               receive operations.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in  verbose  logging  level  when a
-              remote client or server matches a  pattern  in  the
+              The increment  in  verbose  logging  level  when  a
+              remote  client  or  server matches a pattern in the
               <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional  list  of remote client or server hostname
-              or network address patterns that cause the  verbose
-              logging  level  to increase by the amount specified
+              Optional list of remote client or  server  hostname
+              or  network address patterns that cause the verbose
+              logging level to increase by the  amount  specified
               in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The recipient  of  postmaster  notifications  about
-              mail  delivery  problems that are caused by policy,
+              The  recipient  of  postmaster  notifications about
+              mail delivery problems that are caused  by  policy,
               resource, software or protocol errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What categories of Postfix-generated mail are  sub-
-              ject   to   before-queue   content   inspection  by
+              What  categories of Postfix-generated mail are sub-
+              ject  to   before-queue   content   inspection   by
               <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The list of error classes that are reported to  the
+              The  list of error classes that are reported to the
               postmaster.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
-              Where  the  Postfix SMTP client should deliver mail
+              Where the Postfix SMTP client should  deliver  mail
               when it detects a "mail loops back to myself" error
               condition.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The maximal number  of  digits  after  the  decimal
+              The  maximal  number  of  digits  after the decimal
               point when logging sub-second delay values.
 
        <b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
-              Disable  DNS  lookups  in the Postfix SMTP and LMTP
+              Disable DNS lookups in the Postfix  SMTP  and  LMTP
               clients.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
@@ -670,7 +681,7 @@ SMTP(8)                                                                SMTP(8)
               tem receives mail on.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
-              The  Internet protocols Postfix will attempt to use
+              The Internet protocols Postfix will attempt to  use
               when making or accepting connections.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -678,75 +689,75 @@ SMTP(8)                                                                SMTP(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
-              The  default  TCP port that the Postfix LMTP client
+              The default TCP port that the Postfix  LMTP  client
               connects to.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time  that  an  idle  Postfix
-              daemon  process  waits  for  an incoming connection
+              The  maximum  amount  of  time that an idle Postfix
+              daemon process waits  for  an  incoming  connection
               before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The maximal number of incoming connections  that  a
-              Postfix  daemon  process will service before termi-
+              The  maximal  number of incoming connections that a
+              Postfix daemon process will service  before  termi-
               nating voluntarily.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The process ID  of  a  Postfix  command  or  daemon
+              The  process  ID  of  a  Postfix  command or daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The  process  name  of  a Postfix command or daemon
+              The process name of a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
               The network interface addresses that this mail sys-
-              tem  receives  mail on by way of a proxy or network
+              tem receives mail on by way of a proxy  or  network
               address translation unit.
 
        <b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
-              An optional  numerical  network  address  that  the
-              Postfix  SMTP  client should bind to when making an
+              An  optional  numerical  network  address  that the
+              Postfix SMTP client should bind to when  making  an
               IPv4 connection.
 
        <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
-              An optional  numerical  network  address  that  the
-              Postfix  SMTP  client should bind to when making an
+              An  optional  numerical  network  address  that the
+              Postfix SMTP client should bind to when  making  an
               IPv6 connection.
 
        <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The hostname to send in the SMTP EHLO or HELO  com-
+              The  hostname to send in the SMTP EHLO or HELO com-
               mand.
 
        <b><a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
               The hostname to send in the LMTP LHLO command.
 
        <b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
-              What  mechanisms  when the Postfix SMTP client uses
+              What mechanisms when the Postfix SMTP  client  uses
               to look up a host's IP address.
 
        <b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
-              Randomize the order  of  equal-preference  MX  host
+              Randomize  the  order  of  equal-preference MX host
               addresses.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The  mail  system  name  that  is  prepended to the
-              process name in syslog  records,  so  that  "smtpd"
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
               becomes, for example, "postfix/smtpd".
 
        Available with Postfix 2.2 and earlier:
 
        <b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
-              Optional  list of relay hosts for SMTP destinations
+              Optional list of relay hosts for SMTP  destinations
               that can't be found or that are unreachable.
 
        Available with Postfix 2.3 and later:
 
        <b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
-              Optional list of relay hosts for SMTP  destinations
+              Optional  list of relay hosts for SMTP destinations
               that can't be found or that are unreachable.
 
 <b>SEE ALSO</b>
@@ -767,7 +778,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
@@ -789,10 +800,6 @@ SMTP(8)                                                                SMTP(8)
        SuSE Rhein/Main AG
        65760 Eschborn, Germany
 
-       Connection caching in cooperation with:
-       Victor Duchovni
-       Morgan Stanley
-
        TLS support originally by:
        Lutz Jaenicke
        BTU Cottbus
@@ -800,5 +807,9 @@ SMTP(8)                                                                SMTP(8)
        Universitaetsplatz 3-4
        D-03044 Cottbus, Germany
 
+       Revised TLS and SMTP connection cache support by:
+       Victor Duchovni
+       Morgan Stanley
+
                                                                        SMTP(8)
 </pre> </body> </html>
index 68fe8dc191acadc0f6d8bb79e7f5e24db6c32393..e28361305850b0179a0440cd7c13281fec0a7799 100644 (file)
@@ -114,14 +114,14 @@ MASTER(5)                                                            MASTER(5)
                      tor  passing) per connection request, and is
                      accessible to local clients only.
 
-                     This feature is not part of the stable Post-
-                     fix release.
-
-                     The  service  name is a pathname relative to
-                     the Postfix queue directory  (pathname  con-
-                     trolled  with the <b><a href="postconf.5.html#queue_directory">queue_directory</a></b> configura-
+                     The service name is a pathname  relative  to
+                     the  Postfix  queue directory (pathname con-
+                     trolled with the <b><a href="postconf.5.html#queue_directory">queue_directory</a></b>  configura-
                      tion parameter in <a href="postconf.5.html">main.cf</a>).
 
+                     This feature is available as of Postfix ver-
+                     sion 2.5.
+
        <b>Private (default: y)</b>
               Whether or not access is  restricted  to  the  mail
               system.   Internet  (type  <b>inet</b>)  services can't be
index 0ea951e41726ef2998330c5f6a708971b955c4b6..180c320b93480ead8d3955f5d3b776187b051843 100644 (file)
@@ -83,19 +83,6 @@ the sender.  This feature is enabled with the <a href="postconf.5.html#notify_cl
 parameter.  </p>
 
 
-</DD>
-
-<DT><b><a name="<i>transport</i>_destination_concurrency_failed_cohort_limit"><i>transport</i>_destination_concurrency_failed_cohort_limit</a>
-(default: $<a href="postconf.5.html#default_destination_concurrency_failed_cohort_limit">default_destination_concurrency_failed_cohort_limit</a>)</b></DT><DD>
-
-<p> A transport-specific override for the
-<a href="postconf.5.html#default_destination_concurrency_failed_cohort_limit">default_destination_concurrency_failed_cohort_limit</a> parameter value,
-where <i>transport</i> is the <a href="master.5.html">master.cf</a> name of the message delivery
-transport. </p>
-
-<p> This feature is available in Postfix 2.5 and later. </p>
-
-
 </DD>
 
 <DT><b><a name="access_map_reject_code">access_map_reject_code</a>
@@ -2515,7 +2502,7 @@ created locally as the result of configuration or software error.
 </DD>
 
 <DT><b><a name="empty_address_relayhost_maps_lookup_key">empty_address_relayhost_maps_lookup_key</a>
-(default: <>)</b></DT><DD>
+(default: &lt;&gt;)</b></DT><DD>
 
 <p> The <a href="postconf.5.html#sender_dependent_relayhost_maps">sender_dependent_relayhost_maps</a> search string that will be
 used instead of the null sender address. </p>
@@ -3727,10 +3714,12 @@ clients, or it can be specified in the <a href="master.5.html">master.cf</a> fil
 client, for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/<a href="master.5.html">master.cf</a>:
-        mylmtp ... lmtp -o <a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a>=foo.bar.com
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    mylmtp ... lmtp -o <a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a>=foo.bar.com
 </pre>
+</blockquote>
 
 <p>
 This feature is available in Postfix 2.3 and later.
@@ -4187,6 +4176,28 @@ configuration parameter.  See there for details. </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="lmtp_tls_fingerprint_cert_match">lmtp_tls_fingerprint_cert_match</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a>
+configuration parameter.  See there for details. </p>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_tls_fingerprint_digest">lmtp_tls_fingerprint_digest</a>
+(default: md5)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a>
+configuration parameter.  See there for details. </p>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="lmtp_tls_key_file">lmtp_tls_key_file</a>
@@ -4278,7 +4289,7 @@ configuration parameter. See there for details. </p>
 </DD>
 
 <DT><b><a name="lmtp_tls_scert_verifydepth">lmtp_tls_scert_verifydepth</a>
-(default: 5)</b></DT><DD>
+(default: 9)</b></DT><DD>
 
 <p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a>
 configuration parameter.  See there for details. </p>
@@ -4297,6 +4308,17 @@ configuration parameter. See there for details. </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="lmtp_tls_security_level">lmtp_tls_security_level</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> configuration
+parameter.  See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="lmtp_tls_session_cache_database">lmtp_tls_session_cache_database</a>
@@ -4471,8 +4493,10 @@ protocol. </dd>
 <dt><b><a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a> </b></dt>
 
 <dd> Append the domain name in $<a href="postconf.5.html#myorigin">myorigin</a> or $<a href="postconf.5.html#mydomain">mydomain</a> when the
-client TLS certificate is successfully verified, and the client
-certificate fingerprint is listed in $<a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a>.  </dd>
+client TLS certificate fingerprint is listed in $<a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a>.
+The fingerprint digest algorithm is configurable via the
+<a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> parameter (hard-coded as md5 prior to
+Postfix version 2.5).  </dd>
 
 <dt><b><a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> </b></dt>
 
@@ -4498,16 +4522,20 @@ is suitable for, e.g., pop-before-smtp lookup tables. </dd>
 message headers, and always append my own domain to incomplete
 header addresses.  </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all
+<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all
 </pre>
+</blockquote>
 
 <p> The purist (and default) setting: rewrite headers only in mail
 from Postfix sendmail and in SMTP mail from this machine. </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = <a href="postconf.5.html#permit_inet_interfaces">permit_inet_interfaces</a>
+<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = <a href="postconf.5.html#permit_inet_interfaces">permit_inet_interfaces</a>
 </pre>
+</blockquote>
 
 <p> The intermediate setting: rewrite header addresses and append
 $<a href="postconf.5.html#myorigin">myorigin</a> or $<a href="postconf.5.html#mydomain">mydomain</a> information only with mail from Postfix
@@ -4517,11 +4545,13 @@ sendmail, from local clients, or from authorized SMTP clients. </p>
 rewriting when mail from a remote client is forwarded by a neighboring
 system.  </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,
-        <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a> <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a>
-        <a href="postconf.5.html#check_address_map">check_address_map</a> hash:/etc/postfix/pop-before-smtp
+<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,
+    <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a> <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a>
+    <a href="postconf.5.html#check_address_map">check_address_map</a> hash:/etc/postfix/pop-before-smtp
 </pre>
+</blockquote>
 
 
 </DD>
@@ -5095,9 +5125,11 @@ The list is processed left to right, and processing stops at the
 first match.  Thus,
 </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#masquerade_domains">masquerade_domains</a> = foo.example.com example.com
+<a href="postconf.5.html#masquerade_domains">masquerade_domains</a> = foo.example.com example.com
 </pre>
+</blockquote>
 
 <p>
 strips "user@any.thing.foo.example.com" to "user@foo.example.com",
@@ -5109,9 +5141,11 @@ A domain name prefixed with ! means do not masquerade this domain
 or its subdomains. Thus,
 </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#masquerade_domains">masquerade_domains</a> = !foo.example.com example.com
+<a href="postconf.5.html#masquerade_domains">masquerade_domains</a> = !foo.example.com example.com
 </pre>
+</blockquote>
 
 <p>
 does not change "user@any.thing.foo.example.com" or "user@foo.example.com",
@@ -6681,12 +6715,12 @@ Do not change this unless you have a complete understanding of <a href="http://t
 <DT><b><a name="relay_clientcerts">relay_clientcerts</a>
 (default: empty)</b></DT><DD>
 
-<p> The list of remote SMTP client certificates for which the
-Postfix SMTP server will allow access with the <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a>
-feature.  This feature does not use certificate names, because
-Postfix list manipulation routines treat whitespace and some other
-characters as special.  Instead we use certificate fingerprints as
-they are difficult to fake but easy to use for lookup. </p>
+<p> List of tables with remote SMTP client-certificate fingerprints
+for which the Postfix SMTP server will allow access with the
+<a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a> feature.
+The fingerprint digest algorithm is configurable via the
+<a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> parameter (hard-coded as md5 prior to
+Postfix version 2.5).  </p>
 
 <p> Postfix lookup tables are in the form of (key, value) pairs.
 Since we only need the key, the value can be chosen freely, e.g.
@@ -6938,16 +6972,20 @@ considers local. </p>
 addresses from remote SMTP clients, so that those addresses cannot
 be confused with local addresses. </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> = domain.invalid
+<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> = domain.invalid
 </pre>
+</blockquote>
 
 <p> The default, purist, setting: don't rewrite headers from remote
 clients at all. </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> =
+<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> =
 </pre>
+</blockquote>
 
 
 </DD>
@@ -7295,10 +7333,12 @@ it can be specified in the <a href="master.5.html">master.cf</a> file for a spec
 for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/<a href="master.5.html">master.cf</a>:
-        smtp ... smtp -o <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a>=11.22.33.44
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    smtp ... smtp -o <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a>=11.22.33.44
 </pre>
+</blockquote>
 
 <p> Note 1: when <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> specifies no more than one IPv4
 address, and that address is a non-loopback address, it is
@@ -7328,10 +7368,12 @@ it can be specified in the <a href="master.5.html">master.cf</a> file for a spec
 for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/<a href="master.5.html">master.cf</a>:
-        smtp ... smtp -o <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a>=1:2:3:4:5:6:7:8
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    smtp ... smtp -o <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a>=1:2:3:4:5:6:7:8
 </pre>
+</blockquote>
 
 <p> Note 1: when <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> specifies no more than one IPv6
 address, and that address is a non-loopback address, it is
@@ -7778,10 +7820,12 @@ clients, or it can be specified in the <a href="master.5.html">master.cf</a> fil
 client, for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/<a href="master.5.html">master.cf</a>:
-        mysmtp ... smtp -o <a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a>=foo.bar.com
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    mysmtp ... smtp -o <a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a>=foo.bar.com
 </pre>
+</blockquote>
 
 <p>
 This feature is available in Postfix 2.0 and later.
@@ -8052,10 +8096,12 @@ The default is to comply with <a href="http://tools.ietf.org/html/rfc821">RFC 82
 a broken SMTP server, configure a special SMTP client in <a href="master.5.html">master.cf</a>:
 </p>
 
+<blockquote>
 <pre>
-    /etc/postfix/<a href="master.5.html">master.cf</a>:
-        broken-smtp . . . smtp -o <a href="postconf.5.html#smtp_quote_rfc821_envelope">smtp_quote_rfc821_envelope</a>=no
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    broken-smtp . . . smtp -o <a href="postconf.5.html#smtp_quote_rfc821_envelope">smtp_quote_rfc821_envelope</a>=no
 </pre>
+</blockquote>
 
 <p>
 and route mail for the destination in question to the "broken-smtp"
@@ -8261,10 +8307,8 @@ client uses for TLS encrypted SMTP sessions. </p>
 
 <p> The SASL authentication security options that the Postfix SMTP
 client uses for TLS encrypted SMTP sessions with a verified server
-certificate. This feature is still under construction. It will not be
-included in the Postfix 2.3 release. </p>
-
-<p> This feature should be available in Postfix 2.4 and later. </p>
+certificate. This feature is under construction as of Postfix version
+2.3. </p>
 
 
 </DD>
@@ -8435,10 +8479,10 @@ well without them. The recommended setting is to let the defaults stand: </p>
 
 <blockquote>
 <pre>
-    <a href="postconf.5.html#smtp_tls_cert_file">smtp_tls_cert_file</a> =
-    <a href="postconf.5.html#smtp_tls_dcert_file">smtp_tls_dcert_file</a> =
-    <a href="postconf.5.html#smtp_tls_key_file">smtp_tls_key_file</a> =
-    <a href="postconf.5.html#smtp_tls_dkey_file">smtp_tls_dkey_file</a> =
+<a href="postconf.5.html#smtp_tls_cert_file">smtp_tls_cert_file</a> =
+<a href="postconf.5.html#smtp_tls_dcert_file">smtp_tls_dcert_file</a> =
+<a href="postconf.5.html#smtp_tls_key_file">smtp_tls_key_file</a> =
+<a href="postconf.5.html#smtp_tls_dkey_file">smtp_tls_dkey_file</a> =
 </pre>
 </blockquote>
 
@@ -8565,6 +8609,7 @@ case only ciphers matching <b>all</b> the properties are excluded. </p>
 
 <p> Examples (some of these will cause problems): </p>
 
+<blockquote>
 <pre>
 <a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a> = aNULL
 <a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a> = MD5, DES
@@ -8572,6 +8617,7 @@ case only ciphers matching <b>all</b> the properties are excluded. </p>
 <a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a> = AES256-SHA, DES-CBC3-MD5
 <a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a> = kEDH+aRSA
 </pre>
+</blockquote>
 
 <p> The first setting, disables anonymous ciphers. The next setting
 disables ciphers that use the MD5 digest algorithm or the (single) DES
@@ -8583,6 +8629,115 @@ key exchange with RSA authentication. </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a>
+(default: empty)</b></DT><DD>
+
+<p> List of acceptable remote SMTP server certificate fingerprints
+for the "fingerprint" TLS security level (<b><a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a></b> =
+fingerprint). At this security level, certificate authorities are
+not used, and certificate expiration times are ignored. Instead,
+server certificates are verified directly via their "fingerprint". The
+fingerprint is a message digest of the server certificate. The digest
+algorithm is selected via the <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b>
+parameter. </p>
+
+<p> When an <b><a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a></b> table entry specifies the
+"fingerprint" security level, any "match" attributes in that entry specify
+the list of valid fingerprints for the corresponding destination. Multiple
+fingerprints can be combined with a "|" delimiter in a single match
+attribute, or multiple match attributes can be employed. </p>
+
+<p> Example: Certificate fingerprint verification with internal mailhub.
+Two matching fingerprints are listed. The <a href="postconf.5.html#relayhost">relayhost</a> may be multiple
+physical hosts behind a load-balancer, each with its own private/public
+key and self-signed certificate. Alternatively, a single <a href="postconf.5.html#relayhost">relayhost</a> may
+be in the process of switching from one set of private/public keys to
+another, and both keys are trusted just prior to the transition. </p>
+
+<blockquote>
+<pre>
+<a href="postconf.5.html#relayhost">relayhost</a> = [mailhub.example.com]
+<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = fingerprint
+<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+<a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> =
+    3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+    EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
+<p> Example: Certificate fingerprint verification with selected destinations.
+As in the example above, we show two matching fingerprints: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = hash:/etc/postfix/tls_policy
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+</pre>
+<pre>
+/etc/postfix/tls_policy:
+    example.com        fingerprint
+        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a>
+(default: md5)</b></DT><DD>
+
+<p> The message digest algorithm used to construct remote SMTP server
+certificate fingerprints. At the "fingerprint" TLS security level
+(<b><a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a></b> = fingerprint), the server certificate is
+verified by directly matching its <i>fingerprint</i>. The fingerprint
+is the message digest of the server certificate using the selected
+algorithm. With a digest algorithm resistant to "second pre-image"
+attacks, it is not feasible to create a new public key and a matching
+certificate that has the same fingerprint. </p>
+
+<p> The default algorithm is <b>md5</b>; this is consistent with
+the backwards compatible setting of the digest used to verify client
+certificates in the SMTP server. </p>
+
+<p> The best practice algorithm is now <b>sha1</b>. Recent advances in hash
+function cryptanalysis have led to md5 being deprecated in favor of sha1.
+However, as long as there are no known "second pre-image" attacks
+against md5, its use in this context can still be considered safe.
+</p>
+
+<p> While additional digest algorithms are often available with OpenSSL's
+libcrypto, only those used by libssl in SSL cipher suites are available to
+Postfix. For now this means just md5 or sha1. </p>
+
+<p> To find the fingerprint of a specific certificate file, with a
+specific digest algorithm, run:
+</p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -<i>digest</i> -in <i>certfile</i>.pem
+</pre>
+</blockquote>
+
+<p> The text to the right of "=" sign is the desired fingerprint.
+For example: </p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
+SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtp_tls_key_file">smtp_tls_key_file</a>
@@ -8730,22 +8885,36 @@ works in addition to the exclusions listed with <a href="postconf.5.html#smtp_tl
 <DT><b><a name="smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>
 (default: SSLv3, TLSv1)</b></DT><DD>
 
-<p> List of TLS protocols that the Postfix SMTP client will use
-with mandatory TLS encryption.  In <a href="postconf.5.html">main.cf</a> the values
-are separated by whitespace, commas or colons. In the policy table
+<p> List of SSL/TLS protocols that the Postfix SMTP client will use with
+mandatory TLS encryption.  In <a href="postconf.5.html">main.cf</a> the values are separated by
+whitespace, commas or colons. In the policy table "protocols" attribute
 (see <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a>) the only valid separator is colon. An
-empty value means allow all protocols. The valid protocol names,
-(see <b>SSL_get_version(3)</b>), are "SSLv2", "SSLv3" and
-"TLSv1". </p>
+empty value means allow all protocols. The valid protocol names, (see
+<b>SSL_get_version(3)</b>), are "SSLv2", "SSLv3" and "TLSv1". </p>
 
-<p> Since SSL version 2 has known protocol weaknesses and
-is now deprecated, the default setting only lists "SSLv3" and
-"TLSv1". This means that by default, SSL version 2 will not be used
-at the "encrypt" security level and higher. </p>
+<p> With Postfix &ge; 2.5 the parameter syntax is expanded to support
+protocol exclusions. One can now explicitly exclude SSLv2 by setting
+"<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = !SSLv2". To exclude both SSLv2 and
+SSLv3 set "<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = !SSLv2, !SSLv3". Listing
+the protocols to include, rather than protocols to exclude, is still
+supported; use the form you find more intuitive. </p>
+
+<p> Since SSL version 2 has known protocol weaknesses and is now
+deprecated, the default setting excludes "SSLv2".  This means that by
+default, SSL version 2 will not be used at the "encrypt" security level
+and higher. </p>
 
 <p> See the documentation of the <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> parameter and
 <a href="TLS_README.html">TLS_README</a> for more information about security levels. </p>
 
+<p> Example: </p>
+
+<pre>
+<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = TLSv1
+# Alternative form with Postfix &ge; 2.5:
+<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = !SSLv2, !SSLv3
+</pre>
+
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
@@ -8903,6 +9072,20 @@ keyword overrides the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.
 In the policy table, multiple protocols must be separated by colons,
 as attribute values may not contain whitespace or commas. </dd>
 
+<dt><b>fingerprint</b></dt> <dd>Certificate fingerprint
+verification. Available with Postfix 2.5 and later. At this security
+level, there are no trusted certificate authorities. The certificate
+trust chain, expiration date, ... are not checked. Instead,
+the optional <b>match</b> attribute, or else the <a href="postconf.5.html">main.cf</a>
+<b><a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a></b> parameter, lists the
+valid "fingerprints" of the server certificate. The digest
+algorithm used to calculate the fingerprint is selected by the
+<b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b> parameter. Multiple fingerprints can
+be combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </dd>
+
 <dt><b>verify</b></dt> <dd>Mandatory TLS verification.  At this security
 level, DNS MX lookups are trusted to be secure enough, and the name
 verified in the server certificate is usually obtained indirectly via
@@ -8936,11 +9119,14 @@ Example:
 </p>
 
 <pre>
-<a href="postconf.5.html">main.cf</a>:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = hash:/etc/postfix/tls_policy
+    # Postfix 2.5 and later
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
 </pre>
+
 <pre>
-tls_policy:
+/etc/postfix/tls_policy:
     example.edu                 none
     example.mil                 may
     example.gov                 encrypt protocols=TLSv1
@@ -8948,6 +9134,10 @@ tls_policy:
     example.net                 secure
     .example.net                secure match=.example.net:example.net
     [mail.example.org]:587      secure match=nexthop
+    # Postfix 2.5 and later
+    [thumb.example.org]          fingerprint
+       match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+       match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
 </pre>
 
 <p> <b>Note:</b> The <b>hostname</b> strategy if listed in a non-default
@@ -8962,13 +9152,20 @@ configurations in environments where DNS security is not assured. </p>
 </DD>
 
 <DT><b><a name="smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a>
-(default: 5)</b></DT><DD>
+(default: 9)</b></DT><DD>
+
+<p> The verification depth for remote SMTP server certificates. A depth
+of 1 is sufficient if the issuing CA is listed in a local CA file. </p>
 
-<p> The verification depth for remote SMTP server certificates. A
-depth of 1 is sufficient, if the certificate is directly issued by
-a CA listed in the CA files.  The default value (5) should suffice
-for longer chains (the root CA issues special CA which then issues
-the actual certificate...). </p>
+<p> The default verification depth is 9 (the OpenSSL default) for
+compatibility with earlier Postfix behavior. Prior to Postfix 2.5,
+the default value was 5, but the limit was not actually enforced. If
+you have set this to a lower non-default value, certificates with longer
+trust chains may now fail to verify. Certificate chains with 1 or 2
+CAs are common, deeper chains are more rare and any number between 5
+and 9 should suffice in practice. You can choose a lower number if,
+for example, you trust certificates directly signed by an issuing CA
+but not any CAs it delegates to. </p>
 
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
@@ -8997,18 +9194,22 @@ the results of MX lookups in certificate verification is not immune to active
 Sample <a href="postconf.5.html">main.cf</a> setting:
 </p>
 
+<blockquote>
 <pre>
 <a href="postconf.5.html#smtp_tls_secure_cert_match">smtp_tls_secure_cert_match</a> = nexthop
 </pre>
+</blockquote>
 
 <p>
 Sample policy table override:
 </p>
 
+<blockquote>
 <pre>
 example.net     secure match=example.com:.example.com
 .example.net    secure match=example.com:.example.com
 </pre>
+</blockquote>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
@@ -9050,6 +9251,15 @@ cipher grade which the administrator considers secure enough for
 mandatory encrypted sessions. This security level is not an appropriate
 default for systems delivering mail to the Internet. </dd>
 
+<dt><b>fingerprint</b></dt> <dd>Certificate fingerprint
+verification. Available with Postfix 2.5 and later. At this security
+level, there are no trusted certificate authorities. The certificate
+trust chain, expiration date, ... are not checked. Instead,
+the <b><a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a></b> parameter lists
+the valid "fingerprints" of the server certificate. The digest
+algorithm used to calculate the fingerprint is selected by the
+<b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b> parameter. </dd>
+
 <dt><b>verify</b></dt> <dd>Mandatory TLS verification. At this security
 level, DNS MX lookups are trusted to be secure enough, and the name
 verified in the server certificate is usually obtained indirectly
@@ -9075,40 +9285,50 @@ an appropriate default for systems delivering mail to the Internet. </dd>
 Examples:
 </p>
 
-<p>No TLS, old-style: <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>=no and <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a>=no.</p>
 <pre>
-<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = none
+# No TLS. Formerly: <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>=no and <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a>=no.
+<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = none
 </pre>
 
-<p>Opportunistic TLS:</p>
 <pre>
-<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may
+# Opportunistic TLS.
+<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may
 </pre>
 
-<p>Mandatory (high-grade) TLS encryption:</p>
 <pre>
-<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = encrypt
-    <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = high
+# Mandatory (high-grade) TLS encryption.
+<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = encrypt
+<a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = high
 </pre>
 
-<p>Mandatory TLS verification, of hostname or nexthop domain:</p>
 <pre>
-<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = verify
-    <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = high
-    <a href="postconf.5.html#smtp_tls_verify_cert_match">smtp_tls_verify_cert_match</a> = hostname, nexthop, dot-nexthop
+# Mandatory TLS verification of hostname or nexthop domain.
+<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = verify
+<a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = high
+<a href="postconf.5.html#smtp_tls_verify_cert_match">smtp_tls_verify_cert_match</a> = hostname, nexthop, dot-nexthop
+</pre>
+
+<pre>
+# Secure channel TLS with exact nexthop name match.
+<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = secure
+<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = TLSv1
+<a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = high
+<a href="postconf.5.html#smtp_tls_secure_cert_match">smtp_tls_secure_cert_match</a> = nexthop
 </pre>
 
-<p>Secure channel TLS with exact nexthop name matching:</p>
 <pre>
-<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = secure
-    <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = TLSv1
-    <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = high
-    <a href="postconf.5.html#smtp_tls_secure_cert_match">smtp_tls_secure_cert_match</a> = nexthop
+# Certificate fingerprint verification (Postfix &ge; 2.5).
+# The CA-less "fingerprint" security level only scales to a limited
+# number of destinations. As a global default rather than a per-site
+# setting, this is practical when mail for all recipients is sent
+# to a central mail hub.
+<a href="postconf.5.html#relayhost">relayhost</a> = [mailhub.example.com]
+<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = fingerprint
+<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = !SSLv2, !SSLv3
+<a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> = high
+<a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> =
+    3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+    EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
 </pre>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
@@ -9673,9 +9893,12 @@ client network address information.
 <dt><b><a name="check_ccert_access">check_ccert_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
 
 <dd> Use the client certificate fingerprint as lookup key for the
-specified <a href="access.5.html">access(5)</a> database; with Postfix version 2.2, also require
-that the SMTP client certificate is verified successfully. This
-feature is available with Postfix version 2.2 and later.</dd>
+specified <a href="access.5.html">access(5)</a> database; with Postfix version 2.2, also require that
+the SMTP client certificate is verified successfully.
+The fingerprint digest algorithm is configurable via the
+<a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> parameter (hard-coded as md5 prior to
+Postfix version 2.5).  This feature is available with Postfix version
+2.2 and later. </dd>
 
 <dt><b><a name="check_client_access">check_client_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
 
@@ -9708,9 +9931,13 @@ allowed to relay. This feature is available with Postfix version 2.2.</dd>
 
 <dt><b><a name="permit_tls_clientcerts">permit_tls_clientcerts</a></b></dt>
 
-<dd>Permit the request when the remote SMTP client certificate is
-verified successfully, and the certificate fingerprint is listed
-in $<a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a>. This feature is available with Postfix version 2.2.</dd>
+<dd>Permit the request when the remote SMTP client certificate
+fingerprint is listed in $<a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a>.
+The fingerprint digest algorithm is configurable via the
+<a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> parameter (hard-coded as md5 prior to
+Postfix version 2.5).  This feature is available with Postfix version
+2.2. </dd>
+
 <dt><b><a name="reject_rbl_client">reject_rbl_client <i>rbl_domain=d.d.d.d</i></a></b></dt>
 
 <dd>Reject the request when the reversed client network address is
@@ -9853,7 +10080,6 @@ rejected requests (default: 554).</dd>
 <dd>Pause for the specified number of seconds and proceed with
 the next restriction in the list, if any. This may stop zombie
 mail when used as:
-
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> =
@@ -10555,9 +10781,11 @@ at least one of the following restrictions. Otherwise Postfix will
 refuse to receive mail:
 </p>
 
+<blockquote>
 <pre>
-    reject, defer, <a href="postconf.5.html#defer_if_permit">defer_if_permit</a>, <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>
+reject, defer, <a href="postconf.5.html#defer_if_permit">defer_if_permit</a>, <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>
 </pre>
+</blockquote>
 
 <p>
 Specify a list of restrictions, separated by commas and/or whitespace.
@@ -10851,18 +11079,22 @@ If a remote SMTP client is authenticated, the <a href="postconf.5.html#permit_sa
 access restriction can be used to permit relay access, like this:
 </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
-        <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>, <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a>, ...
+<a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
+    <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>, <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a>, ...
 </pre>
+</blockquote>
 
 <p> To reject all SMTP connections from unauthenticated clients,
 specify "<a href="postconf.5.html#smtpd_delay_reject">smtpd_delay_reject</a> = yes" (which is the default) and use:
 </p>
 
+<blockquote>
 <pre>
-    <a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> = <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a>, reject
+<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> = <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a>, reject
 </pre>
+</blockquote>
 
 <p>
 See the <a href="SASL_README.html">SASL_README</a> file for SASL configuration and operation details.
@@ -11380,11 +11612,9 @@ with other MTAs. </p>
 
 <p> Example: </p>
 
-<blockquote>
 <pre>
-    <a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_session_ids</a> = no
+<a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_session_ids</a> = no
 </pre>
-</blockquote>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
@@ -11421,13 +11651,21 @@ connections. </p>
 </DD>
 
 <DT><b><a name="smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a>
-(default: 5)</b></DT><DD>
+(default: 9)</b></DT><DD>
 
 <p> The verification depth for remote SMTP client certificates. A
 depth of 1 is sufficient if the issuing CA is listed in a local CA
-file.  The default value should also suffice for longer chains (the
-root CA issues special CA which then issues the actual certificate...).
-</p>
+file. </p>
+
+<p> The default verification depth is 9 (the OpenSSL default) for
+compatibility with earlier Postfix behavior. Prior to Postfix 2.5,
+the default value was 5, but the limit was not actually enforced. If
+you have set this to a lower non-default value, certificates with longer
+trust chains may now fail to verify. Certificate chains with 1 or 2
+CAs are common, deeper chains are more rare and any number between 5
+and 9 should suffice in practice. You can choose a lower number if,
+for example, you trust certificates directly signed by an issuing CA
+but not any CAs it delegates to. </p>
 
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
@@ -11516,7 +11754,7 @@ Postfix 2.3 and later; use <a href="postconf.5.html#smtpd_tls_mandatory_ciphers"
 (default: empty)</b></DT><DD>
 
 <p> File with the Postfix SMTP server DSA certificate in PEM format.
-This file may also contain the Postfix SMTP server private key. <p>
+This file may also contain the Postfix SMTP server private DSA key. </p>
 
 <p> See the discussion under <a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a> for more details.
 </p>
@@ -11542,9 +11780,11 @@ use with EDH ciphers. </p>
 with other TLS packages, it is more secure to generate your own
 set of parameters with something like the following command:  </p>
 
+<blockquote>
 <pre>
-openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024
+openssl gendh -out /etc/postfix/dh_1024.pem -2 1024
 </pre>
+</blockquote>
 
 <p> Your actual source for entropy may differ. Some systems have
 /dev/random; on other system you may consider using the "Entropy
@@ -11611,6 +11851,7 @@ only ciphers matching <b>all</b> the properties are excluded. </p>
 
 <p> Examples (some of these will cause problems): </p>
 
+<blockquote>
 <pre>
 <a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a> = aNULL
 <a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a> = MD5, DES
@@ -11618,6 +11859,7 @@ only ciphers matching <b>all</b> the properties are excluded. </p>
 <a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a> = AES256-SHA, DES-CBC3-MD5
 <a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a> = kEDH+aRSA
 </pre>
+</blockquote>
 
 <p> The first setting disables anonymous ciphers. The next setting
 disables ciphers that use the MD5 digest algorithm or the (single) DES
@@ -11629,15 +11871,77 @@ key exchange with RSA authentication. </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a>
+(default: md5)</b></DT><DD>
+
+<p> The message digest algorithm used to construct client-certificate
+fingerprints for <b><a href="postconf.5.html#check_ccert_access">check_ccert_access</a></b> and
+<b><a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a></b>. The default algorithm is <b>md5</b>,
+for backwards compatibility with Postfix releases prior to 2.5.
+</p>
+
+<p> The best practice algorithm is now <b>sha1</b>. Recent advances in hash
+function cryptanalysis have led to md5 being deprecated in favor of sha1.
+However, as long as there are no known "second pre-image" attacks
+against md5, its use in this context can still be considered safe.
+</p>
+
+<p> While additional digest algorithms are often available with OpenSSL's
+libcrypto, only those used by libssl in SSL cipher suites are available to
+Postfix. For now this means just md5 or sha1. </p>
+
+<p> To find the fingerprint of a specific certificate file, with a
+specific digest algorithm, run: </p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -<i>digest</i> -in <i>certfile</i>.pem
+</pre>
+</blockquote>
+
+<p> The text to the right of "=" sign is the desired fingerprint.
+For example: </p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
+SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+</pre>
+</blockquote>
+
+<p> Example: client-certificate access table, with sha1 fingerprints: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> = sha1
+    <a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> =
+        <a href="postconf.5.html#check_ccert_access">check_ccert_access</a> hash:/etc/postfix/access,
+        reject
+</pre>
+<pre>
+/etc/postfix/access:
+    # Action folded to next line...
+    AF:88:7C:AD:51:95:6F:36:96:F6:01:FB:2E:48:CD:AB:49:25:A2:3B
+        OK
+    85:16:78:FD:73:6E:CE:70:E0:31:5F:0D:3C:C8:6D:C4:2C:24:59:E1
+        <a href="postconf.5.html#permit_auth_destination">permit_auth_destination</a>
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtpd_tls_key_file">smtpd_tls_key_file</a>
 (default: $<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>)</b></DT><DD>
 
 <p> File with the Postfix SMTP server RSA private key in PEM format.
-This file may be combined with the Postfix SMTP server certificate
-file specified
-with $<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>. </p>
+This file may be combined with the Postfix SMTP server RSA certificate
+file specified with $<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>. </p>
 
 <p> The private key must be accessible without a pass-phrase, i.e. it
 must not be encrypted, but file permissions should grant read/write
@@ -11774,18 +12078,31 @@ works in addition to the exclusions listed with <a href="postconf.5.html#smtpd_t
 <DT><b><a name="smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a>
 (default: SSLv3, TLSv1)</b></DT><DD>
 
-<p> The TLS protocols accepted by the Postfix SMTP server with
-mandatory TLS encryption.  With opportunistic TLS encryption, all
-protocols are always accepted. If the list is empty, the server
-supports all available TLS protocol versions.  A non-empty value
-is a list of protocol names separated by whitespace, commas or
-colons. The supported protocol names are "SSLv2", "SSLv3" and
-"TLSv1", and are not case sensitive. </p>
+<p> The SSL/TLS protocols accepted by the Postfix SMTP server with
+mandatory TLS encryption. If the list is empty, the server supports all
+available SSL/TLS protocol versions.  A non-empty value is a list
+of protocol
+names separated by whitespace, commas or colons. The supported protocol
+names are "SSLv2", "SSLv3" and "TLSv1", and are not case sensitive. </p>
+
+<p> With Postfix &ge; 2.5 the parameter syntax is expanded to support
+protocol exclusions. One can now explicitly exclude SSLv2 by setting
+"<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = !SSLv2". To exclude both SSLv2 and
+SSLv3 set "<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = !SSLv2, !SSLv3". Listing
+the protocols to include, rather than protocols to exclude, is still
+supported, use the form you find more intuitive. </p>
+
+<p> Since SSL version 2 has known protocol weaknesses and is now
+deprecated, the default setting excludes "SSLv2".  This means that
+by default, SSL version 2 will not be used at the "encrypt" security
+level. </p>
 
 <p> Example: </p>
 
 <pre>
-<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = SSLv3, TLSv1
+<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = TLSv1
+# Alternative form with Postfix &ge; 2.5:
+<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = !SSLv2, !SSLv3
 </pre>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
@@ -11811,7 +12128,7 @@ that was recorded by the final destination can be trusted. </p>
 <DT><b><a name="smtpd_tls_req_ccert">smtpd_tls_req_ccert</a>
 (default: no)</b></DT><DD>
 
-<p> With mandatory TLS encryption, require a remote SMTP client
+<p> With mandatory TLS encryption, require a trusted remote SMTP client
 certificate in order to allow TLS connections to proceed.  This
 option implies "<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> = yes". </p>
 
@@ -11849,7 +12166,8 @@ be used only on dedicated servers. </dd>
 
 </dl>
 
-<p> Note 1: the "verify" and "secure" levels are not supported.
+<p> Note 1: the "fingerprint", "verify" and "secure" levels are not
+supported here.
 The Postfix SMTP server logs a warning and uses "encrypt" instead.
 To verify SMTP client certificates, see <a href="TLS_README.html">TLS_README</a> for a discussion
 of the <a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a>, <a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a>, and <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a>
@@ -12408,6 +12726,19 @@ parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf
 the message delivery transport. </p>
 
 
+</DD>
+
+<DT><b><a name="transport_destination_concurrency_failed_cohort_limit">transport_destination_concurrency_failed_cohort_limit</a>
+(default: $<a href="postconf.5.html#default_destination_concurrency_failed_cohort_limit">default_destination_concurrency_failed_cohort_limit</a>)</b></DT><DD>
+
+<p> A transport-specific override for the
+<a href="postconf.5.html#default_destination_concurrency_failed_cohort_limit">default_destination_concurrency_failed_cohort_limit</a> parameter value,
+where <i>transport</i> is the <a href="master.5.html">master.cf</a> name of the message delivery
+transport. </p>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="transport_destination_concurrency_limit">transport_destination_concurrency_limit</a>
index 9e1659cde673c16378c4987f1c22bf018712867c..949e74009429d113273283e2c49e5a71449cd797 100644 (file)
@@ -424,10 +424,10 @@ SMTP(8)                                                                SMTP(8)
               obsolete <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> parameter.
 
        <b><a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> (SSLv3, TLSv1)</b>
-              List  of TLS protocols that the Postfix SMTP client
-              will use with mandatory TLS encryption.
+              List  of  SSL/TLS  protocols  that the Postfix SMTP
+              client will use with mandatory TLS encryption.
 
-       <b><a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> (5)</b>
+       <b><a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> (9)</b>
               The verification depth for remote SMTP server  cer-
               tificates.
 
@@ -481,29 +481,40 @@ SMTP(8)                                                                SMTP(8)
               Postfix  SMTP  client  uses  for TLS encrypted SMTP
               sessions with a verified server certificate.
 
+       Available in Postfix version 2.5 and later:
+
+       <b><a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> (empty)</b>
+              List of acceptable remote SMTP  server  certificate
+              fingerprints  for  the  "fingerprint"  TLS security
+              level (<b><a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a></b> = fingerprint).
+
+       <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> (md5)</b>
+              The message  digest  algorithm  used  to  construct
+              remote SMTP server certificate fingerprints.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The following configuration parameters exist for  compati-
+       The  following configuration parameters exist for compati-
        bility with Postfix versions before 2.3. Support for these
        will be removed in a future release.
 
        <b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
-              Opportunistic mode: use  TLS  when  a  remote  SMTP
-              server  announces  STARTTLS support, otherwise send
+              Opportunistic  mode:  use  TLS  when  a remote SMTP
+              server announces STARTTLS support,  otherwise  send
               the mail in the clear.
 
        <b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
-              Enforcement mode: require that remote SMTP  servers
-              use  TLS  encryption,  and  never  send mail in the
+              Enforcement  mode: require that remote SMTP servers
+              use TLS encryption, and  never  send  mail  in  the
               clear.
 
        <b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
-              With mandatory TLS  encryption,  require  that  the
+              With  mandatory  TLS  encryption,  require that the
               remote SMTP server hostname matches the information
               in the remote SMTP server certificate.
 
        <b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
               Optional lookup tables with the Postfix SMTP client
-              TLS  usage  policy  by  next-hop destination and by
+              TLS usage policy by  next-hop  destination  and  by
               remote SMTP server hostname.
 
        <b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
@@ -513,27 +524,27 @@ SMTP(8)                                                                SMTP(8)
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#smtp_destination_concurrency_limit">smtp_destination_concurrency_limit</a>      ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
-              The  maximal  number  of parallel deliveries to the
-              same destination  via  the  smtp  message  delivery
+              The maximal number of parallel  deliveries  to  the
+              same  destination  via  the  smtp  message delivery
               transport.
 
        <b><a href="postconf.5.html#smtp_destination_recipient_limit">smtp_destination_recipient_limit</a>        ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
        <b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
-              The  maximal  number of recipients per delivery via
+              The maximal number of recipients per  delivery  via
               the smtp message delivery transport.
 
        <b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
-              The SMTP client time limit  for  completing  a  TCP
+              The  SMTP  client  time  limit for completing a TCP
               connection,  or  zero  (use  the  operating  system
               built-in time limit).
 
        <b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
-              The SMTP client time limit for sending the HELO  or
-              EHLO  command, and for receiving the initial server
+              The  SMTP client time limit for sending the HELO or
+              EHLO command, and for receiving the initial  server
               response.
 
        <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
-              The LMTP client time limit  for  sending  the  LHLO
+              The  LMTP  client  time  limit for sending the LHLO
               command,  and  for  receiving  the  initial  server
               response.
 
@@ -542,30 +553,30 @@ SMTP(8)                                                                SMTP(8)
               command, and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
-              The  SMTP  client  time  limit for sending the MAIL
-              FROM  command,  and  for   receiving   the   server
+              The SMTP client time limit  for  sending  the  MAIL
+              FROM   command,   and   for  receiving  the  server
               response.
 
        <b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
-              RCPT TO  command,  and  for  receiving  the  server
+              The SMTP client time limit  for  sending  the  SMTP
+              RCPT  TO  command,  and  for  receiving  the server
               response.
 
        <b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
-              DATA  command,  and  for   receiving   the   server
+              The SMTP client time limit  for  sending  the  SMTP
+              DATA   command,   and   for  receiving  the  server
               response.
 
        <b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
-              The  SMTP  client  time  limit for sending the SMTP
+              The SMTP client time limit  for  sending  the  SMTP
               message content.
 
        <b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
-              The SMTP client time limit  for  sending  the  SMTP
+              The  SMTP  client  time  limit for sending the SMTP
               ".", and for receiving the server response.
 
        <b><a href="postconf.5.html#smtp_quit_timeout">smtp_quit_timeout</a> (300s)</b>
-              The  SMTP  client  time  limit for sending the QUIT
+              The SMTP client time limit  for  sending  the  QUIT
               command, and for receiving the server response.
 
        Available in Postfix version 2.1 and later:
@@ -576,12 +587,12 @@ SMTP(8)                                                                SMTP(8)
               lookups, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
-              The maximal number of SMTP  sessions  per  delivery
-              request  before  giving up or delivering to a fall-
+              The  maximal  number  of SMTP sessions per delivery
+              request before giving up or delivering to  a  fall-
               back <a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
-              The SMTP client time limit  for  sending  the  RSET
+              The  SMTP  client  time  limit for sending the RSET
               command, and for receiving the server response.
 
        Available in Postfix version 2.2 and earlier:
@@ -593,11 +604,11 @@ SMTP(8)                                                                SMTP(8)
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
-              Permanently enable SMTP connection caching for  the
+              Permanently  enable SMTP connection caching for the
               specified destinations.
 
        <b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
-              Temporarily  enable SMTP connection caching while a
+              Temporarily enable SMTP connection caching while  a
               destination has a high volume of mail in the active
               queue.
 
@@ -607,62 +618,62 @@ SMTP(8)                                                                SMTP(8)
 
        <b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
               When SMTP connection caching is enabled, the amount
-              of  time  that an unused SMTP client socket is kept
+              of time that an unused SMTP client socket  is  kept
               open before it is closed.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
-              Time limit for connection cache  connect,  send  or
+              Time  limit  for  connection cache connect, send or
               receive operations.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in  verbose  logging  level  when a
-              remote client or server matches a  pattern  in  the
+              The increment  in  verbose  logging  level  when  a
+              remote  client  or  server matches a pattern in the
               <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional  list  of remote client or server hostname
-              or network address patterns that cause the  verbose
-              logging  level  to increase by the amount specified
+              Optional list of remote client or  server  hostname
+              or  network address patterns that cause the verbose
+              logging level to increase by the  amount  specified
               in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The recipient  of  postmaster  notifications  about
-              mail  delivery  problems that are caused by policy,
+              The  recipient  of  postmaster  notifications about
+              mail delivery problems that are caused  by  policy,
               resource, software or protocol errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What categories of Postfix-generated mail are  sub-
-              ject   to   before-queue   content   inspection  by
+              What  categories of Postfix-generated mail are sub-
+              ject  to   before-queue   content   inspection   by
               <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The list of error classes that are reported to  the
+              The  list of error classes that are reported to the
               postmaster.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
-              Where  the  Postfix SMTP client should deliver mail
+              Where the Postfix SMTP client should  deliver  mail
               when it detects a "mail loops back to myself" error
               condition.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The maximal number  of  digits  after  the  decimal
+              The  maximal  number  of  digits  after the decimal
               point when logging sub-second delay values.
 
        <b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
-              Disable  DNS  lookups  in the Postfix SMTP and LMTP
+              Disable DNS lookups in the Postfix  SMTP  and  LMTP
               clients.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
@@ -670,7 +681,7 @@ SMTP(8)                                                                SMTP(8)
               tem receives mail on.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
-              The  Internet protocols Postfix will attempt to use
+              The Internet protocols Postfix will attempt to  use
               when making or accepting connections.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -678,75 +689,75 @@ SMTP(8)                                                                SMTP(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
-              The  default  TCP port that the Postfix LMTP client
+              The default TCP port that the Postfix  LMTP  client
               connects to.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time  that  an  idle  Postfix
-              daemon  process  waits  for  an incoming connection
+              The  maximum  amount  of  time that an idle Postfix
+              daemon process waits  for  an  incoming  connection
               before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The maximal number of incoming connections  that  a
-              Postfix  daemon  process will service before termi-
+              The  maximal  number of incoming connections that a
+              Postfix daemon process will service  before  termi-
               nating voluntarily.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The process ID  of  a  Postfix  command  or  daemon
+              The  process  ID  of  a  Postfix  command or daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The  process  name  of  a Postfix command or daemon
+              The process name of a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
               The network interface addresses that this mail sys-
-              tem  receives  mail on by way of a proxy or network
+              tem receives mail on by way of a proxy  or  network
               address translation unit.
 
        <b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
-              An optional  numerical  network  address  that  the
-              Postfix  SMTP  client should bind to when making an
+              An  optional  numerical  network  address  that the
+              Postfix SMTP client should bind to when  making  an
               IPv4 connection.
 
        <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
-              An optional  numerical  network  address  that  the
-              Postfix  SMTP  client should bind to when making an
+              An  optional  numerical  network  address  that the
+              Postfix SMTP client should bind to when  making  an
               IPv6 connection.
 
        <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The hostname to send in the SMTP EHLO or HELO  com-
+              The  hostname to send in the SMTP EHLO or HELO com-
               mand.
 
        <b><a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
               The hostname to send in the LMTP LHLO command.
 
        <b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
-              What  mechanisms  when the Postfix SMTP client uses
+              What mechanisms when the Postfix SMTP  client  uses
               to look up a host's IP address.
 
        <b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
-              Randomize the order  of  equal-preference  MX  host
+              Randomize  the  order  of  equal-preference MX host
               addresses.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The  mail  system  name  that  is  prepended to the
-              process name in syslog  records,  so  that  "smtpd"
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
               becomes, for example, "postfix/smtpd".
 
        Available with Postfix 2.2 and earlier:
 
        <b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
-              Optional  list of relay hosts for SMTP destinations
+              Optional list of relay hosts for SMTP  destinations
               that can't be found or that are unreachable.
 
        Available with Postfix 2.3 and later:
 
        <b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
-              Optional list of relay hosts for SMTP  destinations
+              Optional  list of relay hosts for SMTP destinations
               that can't be found or that are unreachable.
 
 <b>SEE ALSO</b>
@@ -767,7 +778,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
@@ -789,10 +800,6 @@ SMTP(8)                                                                SMTP(8)
        SuSE Rhein/Main AG
        65760 Eschborn, Germany
 
-       Connection caching in cooperation with:
-       Victor Duchovni
-       Morgan Stanley
-
        TLS support originally by:
        Lutz Jaenicke
        BTU Cottbus
@@ -800,5 +807,9 @@ SMTP(8)                                                                SMTP(8)
        Universitaetsplatz 3-4
        D-03044 Cottbus, Germany
 
+       Revised TLS and SMTP connection cache support by:
+       Victor Duchovni
+       Morgan Stanley
+
                                                                        SMTP(8)
 </pre> </body> </html>
index 5c0872ada11455584c69729f59755424a2a0b251..555ff650c1284270c556e3ac71027cebce3a2406 100644 (file)
@@ -398,7 +398,7 @@ SMTPD(8)                                                              SMTPD(8)
               server,  do not announce or accept SASL authentica-
               tion over unencrypted connections.
 
-       <b><a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> (5)</b>
+       <b><a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> (9)</b>
               The verification depth for remote SMTP client  cer-
               tificates.
 
@@ -444,7 +444,7 @@ SMTPD(8)                                                              SMTPD(8)
               tory TLS security levels.
 
        <b><a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> (SSLv3, TLSv1)</b>
-              The  TLS  protocols  accepted  by  the Postfix SMTP
+              The  SSL/TLS protocols accepted by the Postfix SMTP
               server with mandatory TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_tls_received_header">smtpd_tls_received_header</a> (no)</b>
@@ -455,9 +455,9 @@ SMTPD(8)                                                              SMTPD(8)
               CommonName.
 
        <b><a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a> (no)</b>
-              With mandatory TLS  encryption,  require  a  remote
-              SMTP  client certificate in order to allow TLS con-
-              nections to proceed.
+              With mandatory TLS encryption,  require  a  trusted
+              remote  SMTP  client  certificate in order to allow
+              TLS connections to proceed.
 
        <b><a href="postconf.5.html#smtpd_tls_session_cache_database">smtpd_tls_session_cache_database</a> (empty)</b>
               Name of the file containing  the  optional  Postfix
@@ -498,6 +498,13 @@ SMTPD(8)                                                              SMTPD(8)
               The OpenSSL cipherlist  for  "NULL"  grade  ciphers
               that provide authentication without encryption.
 
+       Available in Postfix version 2.5 and later:
+
+       <b><a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> (md5)</b>
+              The  message  digest  algorithm  used  to construct
+              client-certificate         fingerprints         for
+              <b><a href="postconf.5.html#check_ccert_access">check_ccert_access</a></b> and <b><a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a></b>.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
        The  following configuration parameters exist for compati-
        bility with Postfix versions before 2.3. Support for these
@@ -1181,5 +1188,9 @@ SMTPD(8)                                                              SMTPD(8)
        Universitaetsplatz 3-4
        D-03044 Cottbus, Germany
 
+       Revised TLS support by:
+       Victor Duchovni
+       Morgan Stanley
+
                                                                       SMTPD(8)
 </pre> </body> </html>
index 2a787a23a4bab00c9b66b4c3f7ad6d58a44d3b1b..4148063534e776e9b1be866ffca2f68f084ad7dd 100644 (file)
@@ -106,11 +106,11 @@ The service listens on a UNIX-domain socket, receives one
 open connection (file descriptor passing) per connection
 request, and is accessible to local clients only.
 
-This feature is not part of the stable Postfix release.
-
 The service name is a pathname relative to the Postfix
 queue directory (pathname controlled with the \fBqueue_directory\fR
 configuration parameter in main.cf).
+
+This feature is available as of Postfix version 2.5.
 .RE
 .IP "\fBPrivate (default: y)\fR"
 Whether or not access is restricted to the mail system.
index 43469a2afe6f79e98739daa01e988a9c25a4bec9..b842e89a6a6b80f4cbc312587c388a997593cec4 100644 (file)
@@ -63,15 +63,6 @@ operation of the mail system.
 The recipient of undeliverable mail that cannot be returned to
 the sender.  This feature is enabled with the notify_classes
 parameter.
-<DT>\fB\fItransport\fR_destination_concurrency_failed_cohort_limit
-(default: $default_destination_concurrency_failed_cohort_limit)\fR</DT><DD>
-.PP
-A transport-specific override for the
-default_destination_concurrency_failed_cohort_limit parameter value,
-where \fItransport\fR is the master.cf name of the message delivery
-transport.
-.PP
-This feature is available in Postfix 2.5 and later.
 .SH access_map_reject_code (default: 554)
 The numerical Postfix SMTP server response code when a client
 is rejected by an \fBaccess\fR(5) map restriction.
@@ -550,7 +541,7 @@ and changed the default to none.
 Specify a list of network/netmask patterns, separated by commas
 and/or whitespace. The mask specifies the number of bits in the
 network part of a host address. You can also specify hostnames or
-\e&.domain names (the initial dot causes the domain to match any name
+\&.domain names (the initial dot causes the domain to match any name
 below it),  "/file/name" or "type:table" patterns.  A "/file/name"
 pattern is replaced by its contents; a "type:table" lookup table
 is matched when a table entry matches a lookup string (the lookup
@@ -2060,15 +2051,17 @@ The default value is the machine hostname.  Specify a hostname or
 This information can be specified in the main.cf file for all LMTP
 clients, or it can be specified in the master.cf file for a specific
 client, for example:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-  /etc/postfix/master.cf:
-        mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
+/etc/postfix/master.cf:
+    mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
 .fi
 .ad
 .ft R
+.in -4
 .PP
 This feature is available in Postfix 2.3 and later.
 .SH lmtp_lhlo_timeout (default: 300s)
@@ -2275,6 +2268,16 @@ The LMTP-specific version of the smtp_tls_exclude_ciphers
 configuration parameter.  See there for details.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_fingerprint_cert_match (default: empty)
+The LMTP-specific version of the smtp_tls_fingerprint_cert_match
+configuration parameter.  See there for details.
+.PP
+This feature is available in Postfix 2.5 and later.
+.SH lmtp_tls_fingerprint_digest (default: md5)
+The LMTP-specific version of the smtp_tls_fingerprint_digest
+configuration parameter.  See there for details.
+.PP
+This feature is available in Postfix 2.5 and later.
 .SH lmtp_tls_key_file (default: $lmtp_tls_cert_file)
 The LMTP-specific version of the smtp_tls_key_file
 configuration parameter.  See there for details.
@@ -2315,7 +2318,7 @@ The LMTP-specific version of the smtp_tls_policy_maps
 configuration parameter. See there for details.
 .PP
 This feature is available in Postfix 2.3 and later.
-.SH lmtp_tls_scert_verifydepth (default: 5)
+.SH lmtp_tls_scert_verifydepth (default: 9)
 The LMTP-specific version of the smtp_tls_scert_verifydepth
 configuration parameter.  See there for details.
 .PP
@@ -2325,6 +2328,11 @@ The LMTP-specific version of the smtp_tls_secure_cert_match
 configuration parameter. See there for details.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_security_level (default: empty)
+The LMTP-specific version of the smtp_tls_security_level configuration
+parameter.  See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
 .SH lmtp_tls_session_cache_database (default: empty)
 The LMTP-specific version of the smtp_tls_session_cache_database
 configuration parameter. See there for details.
@@ -2429,8 +2437,10 @@ client is successfully authenticated via the RFC 4954 (AUTH)
 protocol.
 .IP "\fBpermit_tls_clientcerts \fR"
 Append the domain name in $myorigin or $mydomain when the
-client TLS certificate is successfully verified, and the client
-certificate fingerprint is listed in $relay_clientcerts.
+client TLS certificate fingerprint is listed in $relay_clientcerts.
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).
 .IP "\fBpermit_tls_all_clientcerts \fR"
 Append the domain name in $myorigin or $mydomain when the
 client TLS certificate is successfully verified, regardless of
@@ -2448,25 +2458,29 @@ Examples:
 The Postfix < 2.2 backwards compatible setting: always rewrite
 message headers, and always append my own domain to incomplete
 header addresses.
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    local_header_rewrite_clients = static:all
+local_header_rewrite_clients = static:all
 .fi
 .ad
 .ft R
+.in -4
 .PP
 The purist (and default) setting: rewrite headers only in mail
 from Postfix sendmail and in SMTP mail from this machine.
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    local_header_rewrite_clients = permit_inet_interfaces
+local_header_rewrite_clients = permit_inet_interfaces
 .fi
 .ad
 .ft R
+.in -4
 .PP
 The intermediate setting: rewrite header addresses and append
 $myorigin or $mydomain information only with mail from Postfix
@@ -2475,16 +2489,18 @@ sendmail, from local clients, or from authorized SMTP clients.
 Note: this setting will not prevent remote mail header address
 rewriting when mail from a remote client is forwarded by a neighboring
 system.
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    local_header_rewrite_clients = permit_mynetworks,
-        permit_sasl_authenticated permit_tls_clientcerts
-        check_address_map hash:/etc/postfix/pop-before-smtp
+local_header_rewrite_clients = permit_mynetworks,
+    permit_sasl_authenticated permit_tls_clientcerts
+    check_address_map hash:/etc/postfix/pop-before-smtp
 .fi
 .ad
 .ft R
+.in -4
 .SH local_recipient_maps (default: proxy:unix:passwd.byname $alias_maps)
 Lookup tables with all names or addresses of local recipients:
 a recipient address is local when its domain matches $mydestination,
@@ -2793,28 +2809,32 @@ off in email addresses.
 .PP
 The list is processed left to right, and processing stops at the
 first match.  Thus,
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    masquerade_domains = foo.example.com example.com
+masquerade_domains = foo.example.com example.com
 .fi
 .ad
 .ft R
+.in -4
 .PP
 strips "user@any.thing.foo.example.com" to "user@foo.example.com",
 but strips "user@any.thing.else.example.com" to "user@example.com".
 .PP
 A domain name prefixed with ! means do not masquerade this domain
 or its subdomains. Thus,
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    masquerade_domains = !foo.example.com example.com
+masquerade_domains = !foo.example.com example.com
 .fi
 .ad
 .ft R
+.in -4
 .PP
 does not change "user@any.thing.foo.example.com" or "user@foo.example.com",
 but strips "user@any.thing.else.example.com" to "user@example.com".
@@ -3707,12 +3727,12 @@ client request is rejected by the "reject" restriction.
 .PP
 Do not change this unless you have a complete understanding of RFC 821.
 .SH relay_clientcerts (default: empty)
-The list of remote SMTP client certificates for which the
-Postfix SMTP server will allow access with the permit_tls_clientcerts
-feature.  This feature does not use certificate names, because
-Postfix list manipulation routines treat whitespace and some other
-characters as special.  Instead we use certificate fingerprints as
-they are difficult to fake but easy to use for lookup.
+List of tables with remote SMTP client-certificate fingerprints
+for which the Postfix SMTP server will allow access with the
+permit_tls_clientcerts feature.
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).
 .PP
 Postfix lookup tables are in the form of (key, value) pairs.
 Since we only need the key, the value can be chosen freely, e.g.
@@ -3888,25 +3908,29 @@ Examples:
 The safe setting: append "domain.invalid" to incomplete header
 addresses from remote SMTP clients, so that those addresses cannot
 be confused with local addresses.
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    remote_header_rewrite_domain = domain.invalid
+remote_header_rewrite_domain = domain.invalid
 .fi
 .ad
 .ft R
+.in -4
 .PP
 The default, purist, setting: don't rewrite headers from remote
 clients at all.
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    remote_header_rewrite_domain =
+remote_header_rewrite_domain =
 .fi
 .ad
 .ft R
+.in -4
 .SH require_home_directory (default: no)
 Whether or not a \fBlocal\fR(8) recipient's home directory must exist
 before mail delivery is attempted. By default this test is disabled.
@@ -4087,15 +4111,17 @@ should bind to when making an IPv4 connection.
 This can be specified in the main.cf file for all SMTP clients, or
 it can be specified in the master.cf file for a specific client,
 for example:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-  /etc/postfix/master.cf:
-        smtp ... smtp -o smtp_bind_address=11.22.33.44
+/etc/postfix/master.cf:
+    smtp ... smtp -o smtp_bind_address=11.22.33.44
 .fi
 .ad
 .ft R
+.in -4
 .PP
 Note 1: when inet_interfaces specifies no more than one IPv4
 address, and that address is a non-loopback address, it is
@@ -4114,15 +4140,17 @@ This feature is available in Postfix 2.2 and later.
 This can be specified in the main.cf file for all SMTP clients, or
 it can be specified in the master.cf file for a specific client,
 for example:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-  /etc/postfix/master.cf:
-        smtp ... smtp -o smtp_bind_address6=1:2:3:4:5:6:7:8
+/etc/postfix/master.cf:
+    smtp ... smtp -o smtp_bind_address6=1:2:3:4:5:6:7:8
 .fi
 .ad
 .ft R
+.in -4
 .PP
 Note 1: when inet_interfaces specifies no more than one IPv6
 address, and that address is a non-loopback address, it is
@@ -4392,15 +4420,17 @@ The default value is the machine hostname.  Specify a hostname or
 This information can be specified in the main.cf file for all SMTP
 clients, or it can be specified in the master.cf file for a specific
 client, for example:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-  /etc/postfix/master.cf:
-        mysmtp ... smtp -o smtp_helo_name=foo.bar.com
+/etc/postfix/master.cf:
+    mysmtp ... smtp -o smtp_helo_name=foo.bar.com
 .fi
 .ad
 .ft R
+.in -4
 .PP
 This feature is available in Postfix 2.0 and later.
 .SH smtp_helo_timeout (default: 300s)
@@ -4525,15 +4555,17 @@ that ends in ".".
 .PP
 The default is to comply with RFC 821. If you have to send mail to
 a broken SMTP server, configure a special SMTP client in master.cf:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    /etc/postfix/master.cf:
-        broken-smtp . . . smtp -o smtp_quote_rfc821_envelope=no
+/etc/postfix/master.cf:
+    broken-smtp . . . smtp -o smtp_quote_rfc821_envelope=no
 .fi
 .ad
 .ft R
+.in -4
 .PP
 and route mail for the destination in question to the "broken-smtp"
 message delivery with a \fBtransport\fR(5) table.
@@ -4651,10 +4683,8 @@ This feature is available in Postfix 2.2 and later.
 .SH smtp_sasl_tls_verified_security_options (default: $smtp_sasl_tls_security_options)
 The SASL authentication security options that the Postfix SMTP
 client uses for TLS encrypted SMTP sessions with a verified server
-certificate. This feature is still under construction. It will not be
-included in the Postfix 2.3 release.
-.PP
-This feature should be available in Postfix 2.4 and later.
+certificate. This feature is under construction as of Postfix version
+2.3.
 .SH smtp_sasl_type (default: cyrus)
 The SASL plug-in type that the Postfix SMTP client should use
 for authentication.  The available types are listed with the
@@ -4752,22 +4782,19 @@ Do not configure client certificates unless you \fBmust\fR present
 client TLS certificates to one or more servers. Client certificates are
 not usually needed, and can cause problems in configurations that work
 well without them. The recommended setting is to let the defaults stand:
-.na
-.nf
+.sp
 .in +4
 .nf
 .na
 .ft C
-    smtp_tls_cert_file =
-    smtp_tls_dcert_file =
-    smtp_tls_key_file =
-    smtp_tls_dkey_file =
+smtp_tls_cert_file =
+smtp_tls_dcert_file =
+smtp_tls_key_file =
+smtp_tls_dkey_file =
 .fi
 .ad
 .ft R
 .in -4
-.fi
-.ad
 .PP
 The best way to use the default settings is to comment out the above
 parameters in main.cf if present.
@@ -4868,7 +4895,8 @@ single cipher, or one or more "+" separated cipher properties, in which
 case only ciphers matching \fBall\fR the properties are excluded.
 .PP
 Examples (some of these will cause problems):
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
@@ -4880,6 +4908,7 @@ smtp_tls_exclude_ciphers = kEDH+aRSA
 .fi
 .ad
 .ft R
+.in -4
 .PP
 The first setting, disables anonymous ciphers. The next setting
 disables ciphers that use the MD5 digest algorithm or the (single) DES
@@ -4889,6 +4918,121 @@ and "DES-CBC3-MD5". The last setting disables ciphers that use "EDH"
 key exchange with RSA authentication.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH smtp_tls_fingerprint_cert_match (default: empty)
+List of acceptable remote SMTP server certificate fingerprints
+for the "fingerprint" TLS security level (\fBsmtp_tls_security_level\fR =
+fingerprint). At this security level, certificate authorities are
+not used, and certificate expiration times are ignored. Instead,
+server certificates are verified directly via their "fingerprint". The
+fingerprint is a message digest of the server certificate. The digest
+algorithm is selected via the \fBsmtp_tls_fingerprint_digest\fR
+parameter.
+.PP
+When an \fBsmtp_tls_policy_maps\fR table entry specifies the
+"fingerprint" security level, any "match" attributes in that entry specify
+the list of valid fingerprints for the corresponding destination. Multiple
+fingerprints can be combined with a "|" delimiter in a single match
+attribute, or multiple match attributes can be employed.
+.PP
+Example: Certificate fingerprint verification with internal mailhub.
+Two matching fingerprints are listed. The relayhost may be multiple
+physical hosts behind a load-balancer, each with its own private/public
+key and self-signed certificate. Alternatively, a single relayhost may
+be in the process of switching from one set of private/public keys to
+another, and both keys are trusted just prior to the transition.
+.sp
+.in +4
+.nf
+.na
+.ft C
+relayhost = [mailhub.example.com]
+smtp_tls_security_level = fingerprint
+smtp_tls_fingerprint_digest = md5
+smtp_tls_fingerprint_cert_match =
+    3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+    EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+.fi
+.ad
+.ft R
+.in -4
+.PP
+Example: Certificate fingerprint verification with selected destinations.
+As in the example above, we show two matching fingerprints:
+.sp
+.in +4
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+    smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+    smtp_tls_fingerprint_digest = md5
+.fi
+.ad
+.ft R
+.nf
+.na
+.ft C
+/etc/postfix/tls_policy:
+    example.com        fingerprint
+        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+.fi
+.ad
+.ft R
+.in -4
+.PP
+This feature is available in Postfix 2.5 and later.
+.SH smtp_tls_fingerprint_digest (default: md5)
+The message digest algorithm used to construct remote SMTP server
+certificate fingerprints. At the "fingerprint" TLS security level
+(\fBsmtp_tls_security_level\fR = fingerprint), the server certificate is
+verified by directly matching its \fIfingerprint\fR. The fingerprint
+is the message digest of the server certificate using the selected
+algorithm. With a digest algorithm resistant to "second pre-image"
+attacks, it is not feasible to create a new public key and a matching
+certificate that has the same fingerprint.
+.PP
+The default algorithm is \fBmd5\fR; this is consistent with
+the backwards compatible setting of the digest used to verify client
+certificates in the SMTP server.
+.PP
+The best practice algorithm is now \fBsha1\fR. Recent advances in hash
+function cryptanalysis have led to md5 being deprecated in favor of sha1.
+However, as long as there are no known "second pre-image" attacks
+against md5, its use in this context can still be considered safe.
+.PP
+While additional digest algorithms are often available with OpenSSL's
+libcrypto, only those used by libssl in SSL cipher suites are available to
+Postfix. For now this means just md5 or sha1.
+.PP
+To find the fingerprint of a specific certificate file, with a
+specific digest algorithm, run:
+.sp
+.in +4
+.nf
+.na
+.ft C
+$ openssl x509 -noout -fingerprint -\fIdigest\fR -in \fIcertfile\fR.pem
+.fi
+.ad
+.ft R
+.in -4
+.PP
+The text to the right of "=" sign is the desired fingerprint.
+For example:
+.sp
+.in +4
+.nf
+.na
+.ft C
+$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
+SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+.fi
+.ad
+.ft R
+.in -4
+.PP
+This feature is available in Postfix 2.5 and later.
 .SH smtp_tls_key_file (default: $smtp_tls_cert_file)
 File with the Postfix SMTP client RSA private key in PEM format.
 This file may be combined with the Postfix SMTP client RSA certificate
@@ -5000,22 +5144,40 @@ works in addition to the exclusions listed with smtp_tls_exclude_ciphers
 .PP
 This feature is available in Postfix 2.3 and later.
 .SH smtp_tls_mandatory_protocols (default: SSLv3, TLSv1)
-List of TLS protocols that the Postfix SMTP client will use
-with mandatory TLS encryption.  In main.cf the values
-are separated by whitespace, commas or colons. In the policy table
+List of SSL/TLS protocols that the Postfix SMTP client will use with
+mandatory TLS encryption.  In main.cf the values are separated by
+whitespace, commas or colons. In the policy table "protocols" attribute
 (see smtp_tls_policy_maps) the only valid separator is colon. An
-empty value means allow all protocols. The valid protocol names,
-(see \\fBfBSSL_get_version\fR(3)\fR), are "SSLv2", "SSLv3" and
-"TLSv1".
+empty value means allow all protocols. The valid protocol names, (see
+\\fBfBSSL_get_version\fR(3)\fR), are "SSLv2", "SSLv3" and "TLSv1".
+.PP
+With Postfix >= 2.5 the parameter syntax is expanded to support
+protocol exclusions. One can now explicitly exclude SSLv2 by setting
+"smtp_tls_mandatory_protocols = !SSLv2". To exclude both SSLv2 and
+SSLv3 set "smtp_tls_mandatory_protocols = !SSLv2, !SSLv3". Listing
+the protocols to include, rather than protocols to exclude, is still
+supported; use the form you find more intuitive.
 .PP
-Since SSL version 2 has known protocol weaknesses and
-is now deprecated, the default setting only lists "SSLv3" and
-"TLSv1". This means that by default, SSL version 2 will not be used
-at the "encrypt" security level and higher.
+Since SSL version 2 has known protocol weaknesses and is now
+deprecated, the default setting excludes "SSLv2".  This means that by
+default, SSL version 2 will not be used at the "encrypt" security level
+and higher.
 .PP
 See the documentation of the smtp_tls_policy_maps parameter and
 TLS_README for more information about security levels.
 .PP
+Example:
+.PP
+.nf
+.na
+.ft C
+smtp_tls_mandatory_protocols = TLSv1
+# Alternative form with Postfix >= 2.5:
+smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
+.fi
+.ad
+.ft R
+.PP
 This feature is available in Postfix 2.3 and later.
 .SH smtp_tls_note_starttls_offer (default: no)
 Log the hostname of a remote SMTP server that offers STARTTLS,
@@ -5149,6 +5311,20 @@ smtp_tls_mandatory_ciphers parameter and the optional "protocols"
 keyword overrides the main.cf smtp_tls_mandatory_protocols parameter.
 In the policy table, multiple protocols must be separated by colons,
 as attribute values may not contain whitespace or commas.
+.IP "\fBfingerprint\fR"
+Certificate fingerprint
+verification. Available with Postfix 2.5 and later. At this security
+level, there are no trusted certificate authorities. The certificate
+trust chain, expiration date, ... are not checked. Instead,
+the optional \fBmatch\fR attribute, or else the main.cf
+\fBsmtp_tls_fingerprint_cert_match\fR parameter, lists the
+valid "fingerprints" of the server certificate. The digest
+algorithm used to calculate the fingerprint is selected by the
+\fBsmtp_tls_fingerprint_digest\fR parameter. Multiple fingerprints can
+be combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits.
 .IP "\fBverify\fR"
 Mandatory TLS verification.  At this security
 level, DNS MX lookups are trusted to be secure enough, and the name
@@ -5181,15 +5357,18 @@ Example:
 .nf
 .na
 .ft C
-main.cf:
+/etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+    # Postfix 2.5 and later
+    smtp_tls_fingerprint_digest = md5
 .fi
 .ad
 .ft R
+.PP
 .nf
 .na
 .ft C
-tls_policy:
+/etc/postfix/tls_policy:
     example.edu                 none
     example.mil                 may
     example.gov                 encrypt protocols=TLSv1
@@ -5197,6 +5376,10 @@ tls_policy:
     example.net                 secure
     .example.net                secure match=.example.net:example.net
     [mail.example.org]:587      secure match=nexthop
+    # Postfix 2.5 and later
+    [thumb.example.org]          fingerprint
+       match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+       match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
 .fi
 .ad
 .ft R
@@ -5208,12 +5391,19 @@ DNS forgery. Do not use the \fBhostname\fR strategy for secure-channel
 configurations in environments where DNS security is not assured.
 .PP
 This feature is available in Postfix 2.3 and later.
-.SH smtp_tls_scert_verifydepth (default: 5)
-The verification depth for remote SMTP server certificates. A
-depth of 1 is sufficient, if the certificate is directly issued by
-a CA listed in the CA files.  The default value (5) should suffice
-for longer chains (the root CA issues special CA which then issues
-the actual certificate...).
+.SH smtp_tls_scert_verifydepth (default: 9)
+The verification depth for remote SMTP server certificates. A depth
+of 1 is sufficient if the issuing CA is listed in a local CA file.
+.PP
+The default verification depth is 9 (the OpenSSL default) for
+compatibility with earlier Postfix behavior. Prior to Postfix 2.5,
+the default value was 5, but the limit was not actually enforced. If
+you have set this to a lower non-default value, certificates with longer
+trust chains may now fail to verify. Certificate chains with 1 or 2
+CAs are common, deeper chains are more rare and any number between 5
+and 9 should suffice in practice. You can choose a lower number if,
+for example, you trust certificates directly signed by an issuing CA
+but not any CAs it delegates to.
 .PP
 This feature is available in Postfix 2.2 and later.
 .SH smtp_tls_secure_cert_match (default: nexthop, dot-nexthop)
@@ -5233,7 +5423,8 @@ the results of MX lookups in certificate verification is not immune to active
 (man-in-the-middle) attacks on DNS.
 .PP
 Sample main.cf setting:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
@@ -5241,17 +5432,20 @@ smtp_tls_secure_cert_match = nexthop
 .fi
 .ad
 .ft R
+.in -4
 .PP
 Sample policy table override:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
 example.net     secure match=example.com:.example.com
-\e&.example.net    secure match=example.com:.example.com
+\&.example.net    secure match=example.com:.example.com
 .fi
 .ad
 .ft R
+.in -4
 .PP
 This feature is available in Postfix 2.3 and later.
 .SH smtp_tls_security_level (default: empty)
@@ -5282,6 +5476,15 @@ smtp_tls_mandatory_ciphers specify the TLS protocols and minimum
 cipher grade which the administrator considers secure enough for
 mandatory encrypted sessions. This security level is not an appropriate
 default for systems delivering mail to the Internet.
+.IP "\fBfingerprint\fR"
+Certificate fingerprint
+verification. Available with Postfix 2.5 and later. At this security
+level, there are no trusted certificate authorities. The certificate
+trust chain, expiration date, ... are not checked. Instead,
+the \fBsmtp_tls_fingerprint_cert_match\fR parameter lists
+the valid "fingerprints" of the server certificate. The digest
+algorithm used to calculate the fingerprint is selected by the
+\fBsmtp_tls_fingerprint_digest\fR parameter.
 .IP "\fBverify\fR"
 Mandatory TLS verification. At this security
 level, DNS MX lookups are trusted to be secure enough, and the name
@@ -5304,58 +5507,72 @@ an appropriate default for systems delivering mail to the Internet.
 .PP
 Examples:
 .PP
-No TLS, old-style: smtp_use_tls=no and smtp_enforce_tls=no.
 .nf
 .na
 .ft C
-main.cf:
-    smtp_tls_security_level = none
+# No TLS. Formerly: smtp_use_tls=no and smtp_enforce_tls=no.
+smtp_tls_security_level = none
 .fi
 .ad
 .ft R
 .PP
-Opportunistic TLS:
 .nf
 .na
 .ft C
-main.cf:
-    smtp_tls_security_level = may
+# Opportunistic TLS.
+smtp_tls_security_level = may
 .fi
 .ad
 .ft R
 .PP
-Mandatory (high-grade) TLS encryption:
 .nf
 .na
 .ft C
-main.cf:
-    smtp_tls_security_level = encrypt
-    smtp_tls_mandatory_ciphers = high
+# Mandatory (high-grade) TLS encryption.
+smtp_tls_security_level = encrypt
+smtp_tls_mandatory_ciphers = high
 .fi
 .ad
 .ft R
 .PP
-Mandatory TLS verification, of hostname or nexthop domain:
 .nf
 .na
 .ft C
-main.cf:
-    smtp_tls_security_level = verify
-    smtp_tls_mandatory_ciphers = high
-    smtp_tls_verify_cert_match = hostname, nexthop, dot-nexthop
+# Mandatory TLS verification of hostname or nexthop domain.
+smtp_tls_security_level = verify
+smtp_tls_mandatory_ciphers = high
+smtp_tls_verify_cert_match = hostname, nexthop, dot-nexthop
 .fi
 .ad
 .ft R
 .PP
-Secure channel TLS with exact nexthop name matching:
 .nf
 .na
 .ft C
-main.cf:
-    smtp_tls_security_level = secure
-    smtp_tls_mandatory_protocols = TLSv1
-    smtp_tls_mandatory_ciphers = high
-    smtp_tls_secure_cert_match = nexthop
+# Secure channel TLS with exact nexthop name match.
+smtp_tls_security_level = secure
+smtp_tls_mandatory_protocols = TLSv1
+smtp_tls_mandatory_ciphers = high
+smtp_tls_secure_cert_match = nexthop
+.fi
+.ad
+.ft R
+.PP
+.nf
+.na
+.ft C
+# Certificate fingerprint verification (Postfix >= 2.5).
+# The CA-less "fingerprint" security level only scales to a limited
+# number of destinations. As a global default rather than a per-site
+# setting, this is practical when mail for all recipients is sent
+# to a central mail hub.
+relayhost = [mailhub.example.com]
+smtp_tls_security_level = fingerprint
+smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
+smtp_tls_mandatory_ciphers = high
+smtp_tls_fingerprint_cert_match =
+    3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+    EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
 .fi
 .ad
 .ft R
@@ -5465,7 +5682,7 @@ Sample policy table override:
 .na
 .ft C
 example.com     verify  match=hostname:nexthop
-\e&.example.com    verify  match=example.com:.example.com:hostname
+\&.example.com    verify  match=example.com:.example.com:hostname
 .fi
 .ad
 .ft R
@@ -5502,7 +5719,7 @@ is backwards compatible with Postfix version 2.0.
 Specify a list of network/netmask patterns, separated by commas
 and/or whitespace. The mask specifies the number of bits in the
 network part of a host address. You can also specify hostnames or
-\e&.domain names (the initial dot causes the domain to match any name
+\&.domain names (the initial dot causes the domain to match any name
 below it),  "/file/name" or "type:table" patterns.  A "/file/name"
 pattern is replaced by its contents; a "type:table" lookup table
 is matched when a table entry matches a lookup string (the lookup
@@ -5530,7 +5747,7 @@ By default, no clients are allowed to specify XCLIENT.
 Specify a list of network/netmask patterns, separated by commas
 and/or whitespace. The mask specifies the number of bits in the
 network part of a host address. You can also specify hostnames or
-\e&.domain names (the initial dot causes the domain to match any name
+\&.domain names (the initial dot causes the domain to match any name
 below it),  "/file/name" or "type:table" patterns.  A "/file/name"
 pattern is replaced by its contents; a "type:table" lookup table
 is matched when a table entry matches a lookup string (the lookup
@@ -5557,7 +5774,7 @@ By default, no clients are allowed to specify XFORWARD.
 Specify a list of network/netmask patterns, separated by commas
 and/or whitespace. The mask specifies the number of bits in the
 network part of a host address. You can also specify hostnames or
-\e&.domain names (the initial dot causes the domain to match any name
+\&.domain names (the initial dot causes the domain to match any name
 below it),  "/file/name" or "type:table" patterns.  A "/file/name"
 pattern is replaced by its contents; a "type:table" lookup table
 is matched when a table entry matches a lookup string (the lookup
@@ -5736,9 +5953,12 @@ The following restrictions are specific to client hostname or
 client network address information.
 .IP "\fBcheck_ccert_access \fItype:table\fR\fR"
 Use the client certificate fingerprint as lookup key for the
-specified \fBaccess\fR(5) database; with Postfix version 2.2, also require
-that the SMTP client certificate is verified successfully. This
-feature is available with Postfix version 2.2 and later.
+specified \fBaccess\fR(5) database; with Postfix version 2.2, also require that
+the SMTP client certificate is verified successfully.
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).  This feature is available with Postfix version
+2.2 and later.
 .IP "\fBcheck_client_access \fItype:table\fR\fR"
 Search the specified access database for the client hostname,
 parent domains, client IP address, or networks obtained by stripping
@@ -5759,9 +5979,12 @@ CA issues the certificates and only this CA is listed as trusted
 CA, otherwise all clients with a recognized certificate would be
 allowed to relay. This feature is available with Postfix version 2.2.
 .IP "\fBpermit_tls_clientcerts\fR"
-Permit the request when the remote SMTP client certificate is
-verified successfully, and the certificate fingerprint is listed
-in $relay_clientcerts. This feature is available with Postfix version 2.2.
+Permit the request when the remote SMTP client certificate
+fingerprint is listed in $relay_clientcerts.
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).  This feature is available with Postfix version
+2.2.
 .IP "\fBreject_rbl_client \fIrbl_domain=d.d.d.d\fR\fR"
 Reject the request when the reversed client network address is
 listed with the A record "\fId.d.d.d\fR" under \fIrbl_domain\fR
@@ -5886,7 +6109,6 @@ rejected requests (default: 554).
 Pause for the specified number of seconds and proceed with
 the next restriction in the list, if any. This may stop zombie
 mail when used as:
-.PP
 .nf
 .na
 .ft C
@@ -6287,14 +6509,16 @@ $virtual_mailbox_domains.
 IMPORTANT: If you change this parameter setting, you must specify
 at least one of the following restrictions. Otherwise Postfix will
 refuse to receive mail:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    reject, defer, defer_if_permit, reject_unauth_destination
+reject, defer, defer_if_permit, reject_unauth_destination
 .fi
 .ad
 .ft R
+.in -4
 .PP
 Specify a list of restrictions, separated by commas and/or whitespace.
 Continue long lines by starting the next line with whitespace.
@@ -6494,26 +6718,30 @@ the Postfix SMTP server does not use authentication.
 .PP
 If a remote SMTP client is authenticated, the permit_sasl_authenticated
 access restriction can be used to permit relay access, like this:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    smtpd_recipient_restrictions =
-        permit_mynetworks, permit_sasl_authenticated, ...
+smtpd_recipient_restrictions =
+    permit_mynetworks, permit_sasl_authenticated, ...
 .fi
 .ad
 .ft R
+.in -4
 .PP
 To reject all SMTP connections from unauthenticated clients,
 specify "smtpd_delay_reject = yes" (which is the default) and use:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-    smtpd_client_restrictions = permit_sasl_authenticated, reject
+smtpd_client_restrictions = permit_sasl_authenticated, reject
 .fi
 .ad
 .ft R
+.in -4
 .PP
 See the SASL_README file for SASL configuration and operation details.
 .SH smtpd_sasl_authenticated_header (default: no)
@@ -6859,19 +7087,14 @@ such as MS Outlook, and may also prevent interoperability issues
 with other MTAs.
 .PP
 Example:
-.na
-.nf
-.in +4
+.PP
 .nf
 .na
 .ft C
-    smtpd_tls_always_issue_session_ids = no
+smtpd_tls_always_issue_session_ids = no
 .fi
 .ad
 .ft R
-.in -4
-.fi
-.ad
 .PP
 This feature is available in Postfix 2.3 and later.
 .SH smtpd_tls_ask_ccert (default: no)
@@ -6891,11 +7114,20 @@ not announce or accept SASL authentication over unencrypted
 connections.
 .PP
 This feature is available in Postfix 2.2 and later.
-.SH smtpd_tls_ccert_verifydepth (default: 5)
+.SH smtpd_tls_ccert_verifydepth (default: 9)
 The verification depth for remote SMTP client certificates. A
 depth of 1 is sufficient if the issuing CA is listed in a local CA
-file.  The default value should also suffice for longer chains (the
-root CA issues special CA which then issues the actual certificate...).
+file.
+.PP
+The default verification depth is 9 (the OpenSSL default) for
+compatibility with earlier Postfix behavior. Prior to Postfix 2.5,
+the default value was 5, but the limit was not actually enforced. If
+you have set this to a lower non-default value, certificates with longer
+trust chains may now fail to verify. Certificate chains with 1 or 2
+CAs are common, deeper chains are more rare and any number between 5
+and 9 should suffice in practice. You can choose a lower number if,
+for example, you trust certificates directly signed by an issuing CA
+but not any CAs it delegates to.
 .PP
 This feature is available in Postfix 2.2 and later.
 .SH smtpd_tls_cert_file (default: empty)
@@ -6970,7 +7202,7 @@ This feature is available with Postfix version 2.2. It is not used with
 Postfix 2.3 and later; use smtpd_tls_mandatory_ciphers instead.
 .SH smtpd_tls_dcert_file (default: empty)
 File with the Postfix SMTP server DSA certificate in PEM format.
-This file may also contain the Postfix SMTP server private key.
+This file may also contain the Postfix SMTP server private DSA key.
 .PP
 See the discussion under smtpd_tls_cert_file for more details.
 .PP
@@ -6992,14 +7224,16 @@ use with EDH ciphers.
 Instead of using the exact same parameter sets as distributed
 with other TLS packages, it is more secure to generate your own
 set of parameters with something like the following command:
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
-openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024
+openssl gendh -out /etc/postfix/dh_1024.pem -2 1024
 .fi
 .ad
 .ft R
+.in -4
 .PP
 Your actual source for entropy may differ. Some systems have
 /dev/random; on other system you may consider using the "Entropy
@@ -7054,7 +7288,8 @@ cipher, or one or more "+" separated cipher properties, in which case
 only ciphers matching \fBall\fR the properties are excluded.
 .PP
 Examples (some of these will cause problems):
-.PP
+.sp
+.in +4
 .nf
 .na
 .ft C
@@ -7066,6 +7301,7 @@ smtpd_tls_exclude_ciphers = kEDH+aRSA
 .fi
 .ad
 .ft R
+.in -4
 .PP
 The first setting disables anonymous ciphers. The next setting
 disables ciphers that use the MD5 digest algorithm or the (single) DES
@@ -7075,11 +7311,81 @@ and "DES-CBC3-MD5". The last setting disables ciphers that use "EDH"
 key exchange with RSA authentication.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH smtpd_tls_fingerprint_digest (default: md5)
+The message digest algorithm used to construct client-certificate
+fingerprints for \fBcheck_ccert_access\fR and
+\fBpermit_tls_clientcerts\fR. The default algorithm is \fBmd5\fR,
+for backwards compatibility with Postfix releases prior to 2.5.
+.PP
+The best practice algorithm is now \fBsha1\fR. Recent advances in hash
+function cryptanalysis have led to md5 being deprecated in favor of sha1.
+However, as long as there are no known "second pre-image" attacks
+against md5, its use in this context can still be considered safe.
+.PP
+While additional digest algorithms are often available with OpenSSL's
+libcrypto, only those used by libssl in SSL cipher suites are available to
+Postfix. For now this means just md5 or sha1.
+.PP
+To find the fingerprint of a specific certificate file, with a
+specific digest algorithm, run:
+.sp
+.in +4
+.nf
+.na
+.ft C
+$ openssl x509 -noout -fingerprint -\fIdigest\fR -in \fIcertfile\fR.pem
+.fi
+.ad
+.ft R
+.in -4
+.PP
+The text to the right of "=" sign is the desired fingerprint.
+For example:
+.sp
+.in +4
+.nf
+.na
+.ft C
+$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
+SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+.fi
+.ad
+.ft R
+.in -4
+.PP
+Example: client-certificate access table, with sha1 fingerprints:
+.sp
+.in +4
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+    smtpd_tls_fingerprint_digest = sha1
+    smtpd_client_restrictions =
+        check_ccert_access hash:/etc/postfix/access,
+        reject
+.fi
+.ad
+.ft R
+.nf
+.na
+.ft C
+/etc/postfix/access:
+    # Action folded to next line...
+    AF:88:7C:AD:51:95:6F:36:96:F6:01:FB:2E:48:CD:AB:49:25:A2:3B
+        OK
+    85:16:78:FD:73:6E:CE:70:E0:31:5F:0D:3C:C8:6D:C4:2C:24:59:E1
+        permit_auth_destination
+.fi
+.ad
+.ft R
+.in -4
+.PP
+This feature is available in Postfix 2.5 and later.
 .SH smtpd_tls_key_file (default: $smtpd_tls_cert_file)
 File with the Postfix SMTP server RSA private key in PEM format.
-This file may be combined with the Postfix SMTP server certificate
-file specified
-with $smtpd_tls_cert_file.
+This file may be combined with the Postfix SMTP server RSA certificate
+file specified with $smtpd_tls_cert_file.
 .PP
 The private key must be accessible without a pass-phrase, i.e. it
 must not be encrypted, but file permissions should grant read/write
@@ -7180,20 +7486,33 @@ works in addition to the exclusions listed with smtpd_tls_exclude_ciphers
 .PP
 This feature is available in Postfix 2.3 and later.
 .SH smtpd_tls_mandatory_protocols (default: SSLv3, TLSv1)
-The TLS protocols accepted by the Postfix SMTP server with
-mandatory TLS encryption.  With opportunistic TLS encryption, all
-protocols are always accepted. If the list is empty, the server
-supports all available TLS protocol versions.  A non-empty value
-is a list of protocol names separated by whitespace, commas or
-colons. The supported protocol names are "SSLv2", "SSLv3" and
-"TLSv1", and are not case sensitive.
+The SSL/TLS protocols accepted by the Postfix SMTP server with
+mandatory TLS encryption. If the list is empty, the server supports all
+available SSL/TLS protocol versions.  A non-empty value is a list
+of protocol
+names separated by whitespace, commas or colons. The supported protocol
+names are "SSLv2", "SSLv3" and "TLSv1", and are not case sensitive.
+.PP
+With Postfix >= 2.5 the parameter syntax is expanded to support
+protocol exclusions. One can now explicitly exclude SSLv2 by setting
+"smtpd_tls_mandatory_protocols = !SSLv2". To exclude both SSLv2 and
+SSLv3 set "smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3". Listing
+the protocols to include, rather than protocols to exclude, is still
+supported, use the form you find more intuitive.
+.PP
+Since SSL version 2 has known protocol weaknesses and is now
+deprecated, the default setting excludes "SSLv2".  This means that
+by default, SSL version 2 will not be used at the "encrypt" security
+level.
 .PP
 Example:
 .PP
 .nf
 .na
 .ft C
-smtpd_tls_mandatory_protocols = SSLv3, TLSv1
+smtpd_tls_mandatory_protocols = TLSv1
+# Alternative form with Postfix >= 2.5:
+smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
 .fi
 .ad
 .ft R
@@ -7209,7 +7528,7 @@ that was recorded by the final destination can be trusted.
 .PP
 This feature is available in Postfix 2.2 and later.
 .SH smtpd_tls_req_ccert (default: no)
-With mandatory TLS encryption, require a remote SMTP client
+With mandatory TLS encryption, require a trusted remote SMTP client
 certificate in order to allow TLS connections to proceed.  This
 option implies "smtpd_tls_ask_ccert = yes".
 .PP
@@ -7236,7 +7555,8 @@ encryption. According to RFC 2487 this MUST NOT be applied in case
 of a publicly-referenced SMTP server. Instead, this option should
 be used only on dedicated servers.
 .PP
-Note 1: the "verify" and "secure" levels are not supported.
+Note 1: the "fingerprint", "verify" and "secure" levels are not
+supported here.
 The Postfix SMTP server logs a warning and uses "encrypt" instead.
 To verify SMTP client certificates, see TLS_README for a discussion
 of the smtpd_tls_ask_ccert, smtpd_tls_req_ccert, and permit_tls_clientcerts
@@ -7553,6 +7873,13 @@ the message delivery transport.
 A transport-specific override for the default_delivery_slot_loan
 parameter value, where \fItransport\fR is the master.cf name of
 the message delivery transport.
+.SH transport_destination_concurrency_failed_cohort_limit (default: $default_destination_concurrency_failed_cohort_limit)
+A transport-specific override for the
+default_destination_concurrency_failed_cohort_limit parameter value,
+where \fItransport\fR is the master.cf name of the message delivery
+transport.
+.PP
+This feature is available in Postfix 2.5 and later.
 .SH transport_destination_concurrency_limit (default: $default_destination_concurrency_limit)
 A transport-specific override for the
 default_destination_concurrency_limit parameter value, where
index 40532a4db677958059b975d8a744045e124f884d..873c5658cf75cda409040a1a9280af7561c467f4 100644 (file)
@@ -355,9 +355,9 @@ Optional lookup tables with the Postfix SMTP client TLS security
 policy by next-hop destination; when a non-empty value is specified,
 this overrides the obsolete smtp_tls_per_site parameter.
 .IP "\fBsmtp_tls_mandatory_protocols (SSLv3, TLSv1)\fR"
-List of TLS protocols that the Postfix SMTP client will use
-with mandatory TLS encryption.
-.IP "\fBsmtp_tls_scert_verifydepth (5)\fR"
+List of SSL/TLS protocols that the Postfix SMTP client will use with
+mandatory TLS encryption.
+.IP "\fBsmtp_tls_scert_verifydepth (9)\fR"
 The verification depth for remote SMTP server certificates.
 .IP "\fBsmtp_tls_secure_cert_match (nexthop, dot-nexthop)\fR"
 The server certificate peername verification method for the
@@ -392,6 +392,15 @@ Available in Postfix version 2.4 and later:
 The SASL authentication security options that the Postfix SMTP
 client uses for TLS encrypted SMTP sessions with a verified server
 certificate.
+.PP
+Available in Postfix version 2.5 and later:
+.IP "\fBsmtp_tls_fingerprint_cert_match (empty)\fR"
+List of acceptable remote SMTP server certificate fingerprints
+for the "fingerprint" TLS security level (\fBsmtp_tls_security_level\fR =
+fingerprint).
+.IP "\fBsmtp_tls_fingerprint_digest (md5)\fR"
+The message digest algorithm used to construct remote SMTP server
+certificate fingerprints.
 .SH "OBSOLETE STARTTLS CONTROLS"
 .na
 .nf
@@ -639,13 +648,13 @@ Till Franke
 SuSE Rhein/Main AG
 65760 Eschborn, Germany
 
-Connection caching in cooperation with:
-Victor Duchovni
-Morgan Stanley
-
 TLS support originally by:
 Lutz Jaenicke
 BTU Cottbus
 Allgemeine Elektrotechnik
 Universitaetsplatz 3-4
 D-03044 Cottbus, Germany
+
+Revised TLS and SMTP connection cache support by:
+Victor Duchovni
+Morgan Stanley
index 118ff8b95d2f91263c27986709faa8e3b522c362..b0014b5c69a495323b9ece407efdab78a22c3903 100644 (file)
@@ -348,7 +348,7 @@ Ask a remote SMTP client for a client certificate.
 When TLS encryption is optional in the Postfix SMTP server, do
 not announce or accept SASL authentication over unencrypted
 connections.
-.IP "\fBsmtpd_tls_ccert_verifydepth (5)\fR"
+.IP "\fBsmtpd_tls_ccert_verifydepth (9)\fR"
 The verification depth for remote SMTP client certificates.
 .IP "\fBsmtpd_tls_cert_file (empty)\fR"
 File with the Postfix SMTP server RSA certificate in PEM format.
@@ -377,7 +377,7 @@ TLS encryption.
 Additional list of ciphers or cipher types to exclude from the
 SMTP server cipher list at mandatory TLS security levels.
 .IP "\fBsmtpd_tls_mandatory_protocols (SSLv3, TLSv1)\fR"
-The TLS protocols accepted by the Postfix SMTP server with
+The SSL/TLS protocols accepted by the Postfix SMTP server with
 mandatory TLS encryption.
 .IP "\fBsmtpd_tls_received_header (no)\fR"
 Request that the Postfix SMTP server produces Received:  message
@@ -385,7 +385,7 @@ headers that include information about the protocol and cipher used,
 as well as the client CommonName and client certificate issuer
 CommonName.
 .IP "\fBsmtpd_tls_req_ccert (no)\fR"
-With mandatory TLS encryption, require a remote SMTP client
+With mandatory TLS encryption, require a trusted remote SMTP client
 certificate in order to allow TLS connections to proceed.
 .IP "\fBsmtpd_tls_session_cache_database (empty)\fR"
 Name of the file containing the optional Postfix SMTP server
@@ -411,6 +411,12 @@ The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
 .IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
 The OpenSSL cipherlist for "NULL" grade ciphers that provide
 authentication without encryption.
+.PP
+Available in Postfix version 2.5 and later:
+.IP "\fBsmtpd_tls_fingerprint_digest (md5)\fR"
+The message digest algorithm used to construct client-certificate
+fingerprints for \fBcheck_ccert_access\fR and
+\fBpermit_tls_clientcerts\fR.
 .SH "OBSOLETE STARTTLS CONTROLS"
 .na
 .nf
@@ -950,3 +956,7 @@ BTU Cottbus
 Allgemeine Elektrotechnik
 Universitaetsplatz 3-4
 D-03044 Cottbus, Germany
+
+Revised TLS support by:
+Victor Duchovni
+Morgan Stanley
index 360373d1fa95ce75fd5d1498fde4393a638d9f9b..234533f2544c750b72918e076bd3dce9d3f70c45 100755 (executable)
@@ -31,7 +31,10 @@ while(<>) {
        $block .= $_;
     } while(($_ = <>) && /\S/);
 
-    $block =~ s/\n\./\n\\\&./g;
+    # How the %!#$^@ do I get a backslash substituted into a string?
+    # Even \134 comes out as \e. What brain damage is this?
+    #$block =~ s/\n\./\n\\\&./g;
+    $block =~ s/\n\./\n\134\&./g;
     if ($block =~ /<H2>/) {
        $block =~ s/<H2><a[^>]+>([^<]+)<\/a><\/H2>/\n.SH \1\n/g;
        $block =~ tr/a-z/A-Z/;
@@ -66,11 +69,13 @@ while(<>) {
     $block =~ s/\s*<\/dt>/"/g;
     $block =~ s/<tt>\s*//g;
     $block =~ s/\s*<\/tt>//g;
-    $block =~ s/<blockquote>/\n.na\n.nf\n.in +4\n/g;
-    $block =~ s/<\/blockquote>/\n.in -4\n.fi\n.ad\n/g;
+    $block =~ s/<blockquote>/\n.sp\n.in +4\n/g;
+    $block =~ s/<\/blockquote>/\n.in -4\n/g;
     $block =~ s/\n<br>/\n.br\n/g;
     $block =~ s/<br>\s*/\n.br\n/g;
+    $block =~ s/&le;/<=/g;
     $block =~ s/&lt;/</g;
+    $block =~ s/&ge;/>=/g;
     $block =~ s/&gt;/>/g;
     $block =~ s/&amp;/\&/g;
     $block =~ s/\s+\n/\n/g;
index 289ffcb731a15d9da26564987590c9c90ebcf81e..be7948d38adc7f572802a4919c0c0fba9c09ea2d 100755 (executable)
@@ -216,6 +216,7 @@ while (<>) {
     s;\blmtp_tls_policy_maps\b;<a href="postconf.5.html#lmtp_tls_policy_maps">$&</a>;g;
     s;\blmtp_tls_secure_cert_match\b;<a href="postconf.5.html#lmtp_tls_secure_cert_match">$&</a>;g;
     s;\blmtp_tls_security_level\b;<a href="postconf.5.html#lmtp_tls_security_level">$&</a>;g;
+    s;\blmtp_tls_fingerprint_cert_match\b;<a href="postconf.5.html#lmtp_tls_fingerprint_cert_match">$&</a>;g;
     s;\blmtp_tls_verify_cert_match\b;<a href="postconf.5.html#lmtp_tls_verify_cert_match">$&</a>;g;
     s;\blmtp_tls_per_site\b;<a href="postconf.5.html#lmtp_tls_per_site">$&</a>;g;
     s;\blmtp_tls_cert_file\b;<a href="postconf.5.html#lmtp_tls_cert_file">$&</a>;g;
@@ -224,6 +225,7 @@ while (<>) {
     s;\blmtp_tls_dkey_file\b;<a href="postconf.5.html#lmtp_tls_dkey_file">$&</a>;g;
     s;\blmtp_tls_CAfile\b;<a href="postconf.5.html#lmtp_tls_CAfile">$&</a>;g;
     s;\blmtp_tls_CApath\b;<a href="postconf.5.html#lmtp_tls_CApath">$&</a>;g;
+    s;\blmtp_tls_fingerprint_digest\b;<a href="postconf.5.html#lmtp_tls_fingerprint_digest">$&</a>;g;
     s;\blmtp_tls_mandatory_ciphers\b;<a href="postconf.5.html#lmtp_tls_mandatory_ciphers">$&</a>;g;
     s;\blmtp_tls_exclude_ciphers\b;<a href="postconf.5.html#lmtp_tls_exclude_ciphers">$&</a>;g;
     s;\blmtp_tls_mandatory_exclude_ciphers\b;<a href="postconf.5.html#lmtp_tls_mandatory_exclude_ciphers">$&</a>;g;
@@ -553,6 +555,7 @@ while (<>) {
     s;\bsmtp_tls_CAfile\b;<a href="postconf.5.html#smtp_tls_CAfile">$&</a>;g;
     s;\bsmtp_tls_CApath\b;<a href="postconf.5.html#smtp_tls_CApath">$&</a>;g;
     s;\bsmtp_tls_cert_file\b;<a href="postconf.5.html#smtp_tls_cert_file">$&</a>;g;
+    s;\bsmtp_tls_fingerprint_digest\b;<a href="postconf.5.html#smtp_tls_fingerprint_digest">$&</a>;g;
     s;\bsmtp_tls_mandatory_ciphers\b;<a href="postconf.5.html#smtp_tls_mandatory_ciphers">$&</a>;g;
     s;\bsmtp_tls_cipherlist\b;<a href="postconf.5.html#smtp_tls_cipherlist">$&</a>;g;
     s;\bsmtp_tls_exclude_ciphers\b;<a href="postconf.5.html#smtp_tls_exclude_ciphers">$&</a>;g;
@@ -566,6 +569,7 @@ while (<>) {
     s;\bsmtp_tls_per_site\b;<a href="postconf.5.html#smtp_tls_per_site">$&</a>;g;
     s;\bsmtp_tls_policy_maps\b;<a href="postconf.5.html#smtp_tls_policy_maps">$&</a>;g;
     s;\bsmtp_tls_mandatory_protocols\b;<a href="postconf.5.html#smtp_tls_mandatory_protocols">$&</a>;g;
+    s;\bsmtp_tls_fingerprint_cert_match\b;<a href="postconf.5.html#smtp_tls_fingerprint_cert_match">$&</a>;g;
     s;\bsmtp_tls_verify_cert_match\b;<a href="postconf.5.html#smtp_tls_verify_cert_match">$&</a>;g;
     s;\bsmtp_tls_secure_cert_match\b;<a href="postconf.5.html#smtp_tls_secure_cert_match">$&</a>;g;
     s;\bsmtp_tls_scert_verifydepth\b;<a href="postconf.5.html#smtp_tls_scert_verifydepth">$&</a>;g;
@@ -589,6 +593,7 @@ while (<>) {
     s;\bsmtpd_tls_cert_file\b;<a href="postconf.5.html#smtpd_tls_cert_file">$&</a>;g;
     s;\bsmtpd_tls_cipherlist\b;<a href="postconf.5.html#smtpd_tls_cipherlist">$&</a>;g;
     s;\bsmtpd_tls_exclude_ciphers\b;<a href="postconf.5.html#smtpd_tls_exclude_ciphers">$&</a>;g;
+    s;\bsmtpd_tls_fingerprint_digest\b;<a href="postconf.5.html#smtpd_tls_fingerprint_digest">$&</a>;g;
     s;\bsmtpd_tls_mandatory_ciphers\b;<a href="postconf.5.html#smtpd_tls_mandatory_ciphers">$&</a>;g;
     s;\bsmtpd_tls_mandatory_exclude_ciphers\b;<a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">$&</a>;g;
     s;\bsmtpd_tls_dcert_file\b;<a href="postconf.5.html#smtpd_tls_dcert_file">$&</a>;g;
index e221cf42859d9e591f6530a8318a45c246c3599e..6721e0a38fabcf7c734cfa9dd0286663e9c26e86 100755 (executable)
@@ -58,7 +58,7 @@ open(POSTCONF, $protofile) || die " cannot open $protofile: $!\n";
 
 while(<POSTCONF>) {
 
-    next if /^#/;
+    next if /^#/ && $text eq "";
     next unless ($name || /\S/);
 
     if (/^%(PARAM|CLASS)/) {
index ec7e0d6ae0b413f6f4341cee27014f09b1a79311..d2ffd2416045724dc4bf4eb4eea3318e76dd3081 100644 (file)
@@ -417,8 +417,8 @@ clobber:
 ../man/man5/postconf.5: postconf.man.prolog postconf.proto postconf.man.epilog \
        ../mantools/xpostconf ../mantools/postconf2html ../mantools/postconf2man
        (cat postconf.man.prolog; ../mantools/xpostconf postconf.proto | \
-           ../mantools/postconf2html | ../mantools/postconf2man; \
-           cat postconf.man.epilog ) > $@
+           ../mantools/postconf2html | ../mantools/postconf2man | \
+               sed 's/\\e&/\\\&/'; cat postconf.man.epilog ) > $@
 
 ../html/postconf.5.html: postconf.html.prolog postconf.proto \
        postconf.html.epilog ../mantools/xpostconf ../mantools/postconf2html \
index 9d29979d410b8ceb06048e501aad6d9bd7e3d4eb..9f6e7a4c8756dcd8c96627c40418684517a686e9 100644 (file)
@@ -24,9 +24,10 @@ Stress-Dependent Configuration</h1>
 overload, and how to avoid the condition under normal conditions.
 When the condition is caused by botnets or other malware, the
 document suggests configuration settings that help to minimize the
-impact on legitimate mail.  Finally, the document introduces Postfix
-stress-adaptive behavior, and how it can be used to automatically
-switch configuration settings under overload.  </p>
+impact on legitimate mail.  Finally, the document introduces
+stress-adaptive behavior, introduced with Postfix 2.5, and how it
+can be used to automatically switch configuration settings under
+overload.  </p>
 
 <p> Topics covered in this document: </p>
 
@@ -55,8 +56,7 @@ switch configuration settings under overload.  </p>
 <h2><a name="overload"> Symptoms of Postfix SMTP server overload </a></h2>
 
 <p> Under normal conditions, Postfix responds immediately when a
-remote SMTP client connects. The time needed to deliver mail to
-Postfix may depend on how busy the CPU or disk are, but that should
+remote SMTP client connects. The time needed to deliver mail should
 be noticeable only with very large messages.  Performance degrades
 more dramatically when the number of remote SMTP clients exceeds
 the number of Postfix SMTP server processes.  When a client connects
@@ -71,17 +71,6 @@ SMTP mail server overload are: </p>
 
 <ul>
 
-<li> <p> Postfix logs a warning that all server ports are busy: </p>
-
-<pre>
-Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
- (25) has reached its process limit "30": new clients may experience
- noticeable delays
-Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
- condition, increase the process count in master.cf or reduce the
- service time per client
-</pre>
-
 <li> <p> Remote SMTP clients experience a long delay before Postfix
 sends the "220 hostname.example.com ESMTP Postfix" greeting.  If
 this affects end-user mail clients, enable the "submission" service
@@ -92,9 +81,22 @@ connect to this instead of the public SMTP service. </p>
 connection after CONNECT" events. This happens because remote SMTP
 clients disconnect before Postfix answers the connection. </p>
 
+<li> <p> Postfix 2.3 and later logs a warning that all server ports
+are busy: </p>
+
+<pre>
+Oct  3 20:39:27 spike postfix/master[28905]: warning: service "smtp"
+ (25) has reached its process limit "30": new clients may experience
+ noticeable delays
+Oct  3 20:39:27 spike postfix/master[28905]: warning: to avoid this
+ condition, increase the process count in master.cf or reduce the
+ service time per client
+</pre>
+
 </ul>
 
-<p> NOTE: The last two symptoms also happen without overload. </p>
+<p> NOTE: The first two symptoms may also happen without overload,
+for example: </p>
 
 <ul>
 
index 5ee992597b3065339c76885520ee6e87d62d302a..92889bc508bd6e5083ad0878002cabe9b86fc6c5 100644 (file)
@@ -21,7 +21,7 @@
 <h2> WARNING </h2>
 
 <p> By turning on TLS support in Postfix, you not only get the
-ability to encrypt mail and to authenticate clients or servers.
+ability to encrypt mail and to authenticate remote SMTP clients or servers.
 You also turn on thousands and thousands of lines of OpenSSL library
 code.  Assuming that OpenSSL is written as carefully as Wietse's
 own code, every 1000 lines introduce one additional bug into
@@ -225,7 +225,7 @@ key configuration </a> </h3>
 <p> In order to use TLS, the Postfix SMTP server generally needs
 a certificate and a private key. Both must be in "PEM" format. The
 private key must not be encrypted, meaning:  the key must be accessible
-without password.  Both certificate and private key may be in the same
+without a password.  The certificate and private key may be in the same
 file, in which case the certificate file should be owned by "root" and
 not be readable by any other user. If the key is stored separately,
 this applies to the key file only, and the certificate file may be
@@ -233,20 +233,24 @@ this applies to the key file only, and the certificate file may be
 
 <p> Public Internet MX hosts without certificates signed by a "reputable"
 CA must generate, and be prepared to present to most clients, a
-self-signed or private-CA signed certificate. The client will not be
-able to authenticate the server, but unless it is running Postfix 2.3 or
+self-signed or private-CA signed certificate. The remote SMTP client
+will generally not be
+able to authenticate the self-signed certificate, but unless the
+client is running Postfix 2.3 or
 similar software, it will still insist on a server certificate. </p>
 
 <p> For servers that are <b>not</b> public Internet MX hosts, Postfix
-2.3 supports configurations with no certificates. This entails the
+supports configurations with no certificates. This entails the
 use of just the anonymous TLS ciphers, which are not supported by
 typical SMTP clients. Since such clients will not, as a rule, fall
-back to plain text after a TLS handshake failure, the server will
+back to plain text after a TLS handshake failure, a certificate-less
+Postfix SMTP server will
 be unable to receive email from most TLS enabled clients. To avoid
-accidental configurations with no certificates, Postfix 2.3 enables
+accidental configurations with no certificates, Postfix enables
 certificate-less operation only when the administrator explicitly sets
 "smtpd_tls_cert_file = none". This ensures that new Postfix
-configurations will not accidentally run with no certificates. </p>
+SMTP server configurations will not accidentally run with no
+certificates. </p>
 
 <p> Both RSA and DSA certificates are supported. Typically you will
 only have RSA certificates issued by a commercial CA. In addition,
@@ -262,7 +266,7 @@ chain, all CA certificates) must be available.  You should add any
 intermediate CA certificates to the server certificate: the server
 certificate first, then the intermediate CA(s).  </p>
 
-<p> Example: the certificate for "server.dom.ain" was issued by
+<p> Example: the certificate for "server.example.com" was issued by
 "intermediate CA" which itself has a certificate issued by "root
 CA".  Create the server.pem file with: </p>
 
@@ -283,15 +287,7 @@ the overhead of the TLS exchange. </p>
 
 <p> If you want the Postfix SMTP server to accept remote SMTP client
 certificates issued by these CAs, append the root certificate to
-$smtpd_tls_CAfile or install it in the $smtpd_tls_CApath directory.  When
-you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtpd_tls_ccert_verifydepth
-is less than the number of CAs in the certificate chain for the clients
-of interest. With a verify depth of 1 you can only verify certificates
-directly signed by a trusted CA, and all trusted intermediary CAs need to
-be configured explicitly. With a verify depth of 2 you can verify clients
-signed by a root CA or a direct intermediary CA (so long as the client
-is correctly configured to supply its intermediate CA certificate). </p>
+$smtpd_tls_CAfile or install it in the $smtpd_tls_CApath directory. </p>
 
 <p> RSA key and certificate examples: </p>
 
@@ -347,7 +343,7 @@ privileges) from the files in the directory when the information
 is needed. Thus, the $smtpd_tls_CApath directory needs to be
 accessible inside the optional chroot jail. </p>
 
-<p> When you configure Postfix to request <a
+<p> When you configure the Postfix SMTP server to request <a
 href="#server_vrfy_client">client certificates</a>, any CA certificates
 in $smtpd_tls_CAfile are sent to the client, in order to allow it to
 choose an identity signed by a CA you trust. If no $smtpd_tls_CAfile
@@ -450,12 +446,13 @@ supported). </p>
 </pre>
 </blockquote>
 
-<p> With this, Postfix SMTP server announces STARTTLS support to
-SMTP clients, but does not require that clients use TLS encryption.
+<p> With this, the Postfix SMTP server announces STARTTLS support to
+remote SMTP clients, but does not require that clients use TLS encryption.
 </p>
 
 <p> Note: when an unprivileged user invokes "sendmail -bs", STARTTLS
-is never offered due to insufficient privileges to access the server
+is never offered due to insufficient privileges to access the Postfix
+SMTP server
 private key. This is intended behavior. </p>
 
 <p> <a name="server_enforce">You can ENFORCE the use of TLS</a>,
@@ -481,7 +478,8 @@ by default and should only seldom be used. </p>
 
 <p> TLS is sometimes used in the non-standard "wrapper" mode where
 a server always uses TLS, instead of announcing STARTTLS support
-and waiting for clients to request TLS service. Some clients, namely
+and waiting for remote SMTP clients to request TLS service. Some
+clients, namely
 Outlook [Express] prefer the "wrapper" mode.  This is true for OE
 (Win32 &lt; 5.0 and Win32 &gt;=5.0 when run on a port&lt;&gt;25
 and OE (5.01 Mac on all ports). </p>
@@ -517,8 +515,10 @@ this option is "off" by default. You will however need the certificate
 if you want to use certificate based relaying with, for example, the
 permit_tls_clientcerts feature. A server that wants client certificates
 must first present its own certificate. While Postfix 2.3 by default
-offers anonymous ciphers to clients, these are automatically suppressed
-when the server is configured to ask for client certificates. </p>
+offers anonymous ciphers to remote SMTP clients, these are automatically
+suppressed
+when the Postfix SMTP server is configured to ask for client
+certificates. </p>
 
 <p> Example: </p>
  
@@ -553,18 +553,26 @@ logged. </p>
 </pre>
 </blockquote>
 
-<p> A client certificate verification depth of 1 is sufficient if
-the certificate is directly issued by a CA listed in the CA file.
-The default value (5) should also suffice for longer chains (root
-CA issues special CA which then issues the actual certificate...)
-</p>
+<p> The client certificate verification depth is specified with the
+main.cf smtpd_tls_ccert_verifydepth parameter. The default verification
+depth is 9 (the OpenSSL default), for compatibility with Postfix
+versions before 2.5 where smtpd_tls_ccert_verifydepth was ignored.
+When you configure trust in a
+root CA, it is not necessary to explicitly trust intermediary CAs signed
+by the root CA, unless $smtpd_tls_ccert_verifydepth is less than the
+number of CAs in the certificate chain for the clients of interest. With
+a verify depth of 1 you can only verify certificates directly signed
+by a trusted CA, and all trusted intermediary CAs need to be configured
+explicitly. With a verify depth of 2 you can verify clients signed by a
+root CA or a direct intermediary CA (so long as the client is correctly
+configured to supply its intermediate CA certificate). </p>
 
 <p> Example: </p>
  
 <blockquote>
 <pre>
 /etc/postfix/main.cf:
-    smtpd_tls_ccert_verifydepth = 5
+    smtpd_tls_ccert_verifydepth = 2
 </pre>
 </blockquote>
 
@@ -661,23 +669,30 @@ Postfix SMTP server access control:  </p>
 
 <dl>
 
-<dt> permit_tls_clientcerts </dt> <dd> <p> Allow the remote SMTP
-client SMTP request if the client certificate passes verification,
-and if its fingerprint is listed in the list of client certificates
-(see relay_clientcerts discussion below). </p> </dd>
+<dt> permit_tls_clientcerts </dt> <dd> <p> Allow the remote SMTP client
+request if the client certificate fingerprint is listed in the
+client certificate table (see relay_clientcerts discussion below). </p>
+</dd>
 
-<dt> permit_tls_all_clientcerts </dt> <dd> <p> Allow the remote
-client SMTP request if the client certificate passes verification.
-</p> </dd>
+<dt> permit_tls_all_clientcerts </dt> <dd> <p> Allow the remote SMTP
+client request if the client certificate passes trust chain verification.
+Useful with private-label CAs that only issue certificates to trusted
+clients (and not otherwise). </p> </dd>
 
-<dt> check_ccert_access type:table</dt> <dd>
-<p> If the client certificate passes verification, use its fingerprint
-as a key for the specified access(5) table. </p> </dd>
+<dt> check_ccert_access type:table</dt> <dd> <p> Use the remote SMTP
+client
+certificate fingerprint as the lookup key for the specified access(5)
+table. </p> </dd>
 
 </dl>
 
 </blockquote>
 
+<p> The digest algorithm used to construct the client certificate
+fingerprints is specified with the main.cf smtpd_tls_fingerprint_digest
+parameter.  The default is "md5", for compatibility with Postfix
+versions &lt; 2.5. </p>
+
 <p> The permit_tls_all_clientcerts feature must be used with caution,
 because it can result in too many access permissions.  Use this
 feature only if a special CA issues the client certificates, and
@@ -704,16 +719,10 @@ certificate must no longer be used (e.g. an employee leaving). </p>
 </pre>
 </blockquote>
 
-<p> The Postfix list manipulation routines give special treatment
-to whitespace and some other characters, making the use of certificate
-names impractical.  Instead we use the certificate fingerprints as
-they are difficult to fake but easy to use for lookup.  Postfix
-lookup tables are in the form of (key, value) pairs.  Since we only
-need the key, the value can be chosen freely, e.g.  the name of
-the user or host.</p>
+<p> Example: Postfix lookup tables are in the form of (key, value)
+pairs. Since we only need the key, the value can be chosen freely, e.g.
+the name of the user or host:</p>
 
-<p> Example: </p>
 <blockquote>
 <pre>
 /etc/postfix/main.cf:
@@ -766,27 +775,29 @@ and not specifying an smtpd_tls_dcert_file. </p>
     smtpd_tls_key_file = /etc/postfix/key.pem
     smtpd_tls_mandatory_ciphers = high
     smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5
-    # Postfix 2.3 and later
     smtpd_tls_security_level = encrypt
-    # Obsolete, but still supported
-    smtpd_enforce_tls = yes
+    smtpd_tls_mandatory_protocols = TLSv1
+    # Also available with Postfix &ge; 2.5:
+    smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
 </pre>
 </blockquote>
 
-<p> If you want to take advantage of ciphers with EDH, DH parameters
-are needed.  Instead of using the built-in DH parameters for both
-1024bit and 512bit, it is better to generate your own parameters,
-since otherwise it would "pay" for a possible attacker to start a
-brute force attack against parameters that are used by everybody.
-For this reason, the default parameters chosen by OpenSSL are already
-different from those distributed with other TLS packages. </p>
+<p> If you want to take advantage of ciphers with ephemeral Diffie-Hellman
+(EDH) key exchange (this offers "forward-secrecy"), DH parameters are
+needed.  Instead of using the built-in DH parameters for both 1024-bit
+(non-export ciphers) and 512-bit (export ciphers), it is better to
+generate your own parameters, since otherwise it would "pay" for a
+possible attacker to start a brute force attack against parameters that
+are used by everybody.  Postfix defaults to compiled-in parameters
+that are shared by all Postfix users who don't generate their own
+settings. </p>
 
 <p> To generate your own set of DH parameters, use: </p>
 
 <blockquote>
 <pre>
-% <b>openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024</b>
-% <b>openssl gendh -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512</b>
+% <b>openssl gendh -out /etc/postfix/dh_512.pem -2 512</b>
+% <b>openssl gendh -out /etc/postfix/dh_1024.pem -2 1024</b>
 </pre>
 </blockquote>
 
@@ -841,6 +852,8 @@ key configuration </a>
 
 <li><a href="#client_tls_encrypt"> Mandating TLS encryption </a>
 
+<li><a href="#client_tls_fprint"> Certificate fingerprint verification </a>
+
 <li><a href="#client_tls_verify"> Mandating server certificate verification </a>
 
 <li><a href="#client_tls_secure"> Secure server certificate verification </a>
@@ -866,14 +879,14 @@ key configuration </a>
 <h3><a name="client_lmtp_tls"> TLS support in the LMTP delivery agent </a>
 </h3>
 
-<p> In Postfix 2.3, the smtp(8) and lmtp(8) delivery agents have been
-merged into a single dual-purpose program. As a result the lmtp(8)
-delivery agent is no longer the poor cousin of the more extensively used
-smtp(8). Specifically, as of Postfix 2.3, all the TLS features described
-below apply equally to SMTP and LMTP, after replacing the "smtp_"
-prefix of the each parameter name with "lmtp_".
+<p> The smtp(8) and lmtp(8) delivery agents are implemented by a
+single dual-purpose program.  Specifically, all the TLS features
+described below apply
+equally to SMTP and LMTP, after replacing the "smtp_" prefix of the each
+parameter name with "lmtp_".
 
-<p> The LMTP delivery agent can communicate with LMTP servers listening
+<p> The Postfix LMTP delivery agent can communicate with LMTP servers
+listening
 on UNIX-domain sockets. When server certificate verification is enabled
 and the server is listening on a UNIX-domain socket, the $myhostname
 parameter is used to set the TLS verification <i>nexthop</i> and
@@ -887,7 +900,8 @@ The "null" ciphers provide authentication without encryption. </p>
 <h3><a name="client_cert_key">Client-side certificate and private
 key configuration </a> </h3>
 
-<p> Do not configure client certificates unless you <b>must</b> present
+<p> Do not configure Postfix SMTP client certificates unless you <b>must</b>
+present
 client TLS certificates to one or more servers. Client certificates are
 not usually needed, and can cause problems in configurations that work
 well without them. The recommended setting is to let the defaults stand: </p>
@@ -951,15 +965,7 @@ the overhead of the TLS exchange. </p>
 
 <p> If you want the Postfix SMTP client to accept remote SMTP server
 certificates issued by these CAs, append the root certificate to
-$smtp_tls_CAfile or install it in the $smtp_tls_CApath directory.  When
-you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtp_tls_scert_verifydepth
-is less than the number of CAs in the certificate chain for the servers
-of interest. With a verify depth of 1 you can only verify certificates
-directly signed by a trusted CA, and all trusted intermediary CAs need to
-be configured explicitly. With a verify depth of 2 you can verify servers
-signed by a root CA or a direct intermediary CA (so long as the server
-is correctly configured to supply its intermediate CA certificate). </p>
+$smtp_tls_CAfile or install it in the $smtp_tls_CApath directory. </p>
 
 <p> RSA key and certificate examples: </p>
  
@@ -1212,6 +1218,8 @@ in the sections that follow.</p>
 <dd><a href="#client_tls_may">Opportunistic TLS.</a></dd>
 <dt><b>encrypt</b></dt>
 <dd><a href="#client_tls_encrypt">Mandatory TLS encryption.</a>
+<dt><b>fingerprint</b></dt>
+<dd><a href="#client_tls_fprint">Certificate fingerprint verification.</a>
 <dt><b>verify</b></dt>
 <dd><a href="#client_tls_verify">Mandatory server certificate verification.</a>
 <dt><b>secure</b></dt>
@@ -1314,11 +1322,12 @@ on TLS <a href="#client_tls_limits">limitations</a> above. </p>
 
 <p> At the "encrypt" TLS security level, messages are sent only
 over TLS encrypted sessions. The SMTP transaction is aborted unless
-the STARTTLS ESMTP feature is supported by the server. If no suitable
+the STARTTLS ESMTP feature is supported by the remote SMTP server.
+If no suitable
 servers are found, the message will be deferred. With Postfix 2.3
 and later, mandatory TLS encryption can be configured by setting
 "smtp_tls_security_level = encrypt". Even though TLS
-encryption is always used, mail delivery continues if the server
+encryption is always used, mail delivery continues even if the server
 certificate is untrusted or bears the wrong name. </p>
 
 <p> At this security level and higher, the smtp_tls_mandatory_protocols
@@ -1437,13 +1446,82 @@ use the new <a href="#client_tls_policy">policy table</a> instead. </p>
 </pre>
 </blockquote>
 
+<h3><a name="client_tls_fprint"> Certificate fingerprint verification </a>
+</h3>
+
+<p> Certificate fingerprint verification is available with Postfix 2.5 and
+later. At this security level ("smtp_tls_security_level = fingerprint"),
+no trusted certificate authorities are used or required.  The certificate
+trust chain, expiration date, ... are not checked. Instead, the
+smtp_tls_fingerprint_cert_match parameter or the "match" attribute
+in the <a href="#client_tls_policy">policy</a> table lists the valid
+"fingerprints" of the remote SMTP server certificate. </p>
+
+<p> If certificate fingerprints are exchanged securely, this is the
+strongest, and least scalable security level. The administrator needs to
+securely collect the fingerprints of the X.509 certificates of each peer
+server, store them into a local file, and update this local file
+whenever the peer server's public certificate
+changes. This may be feasible for an SMTP "VPN" connecting a small
+number of branch offices over the Internet, or for secure connections
+to a central mail hub. It works poorly if the remote SMTP server is
+managed by a
+third party, and its public certificate changes periodically without
+prior coordination with the verifying site. </p>
+
+<p> The digest algorithm used to calculate the fingerprint is
+selected by the <b>smtp_tls_fingerprint_digest</b> parameter. In the <a
+href="#client_tls_policy">policy</a> table multiple fingerprints can be
+combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </p>
+
+<p> Example: fingerprint TLS security with an internal mailhub.
+Two matching fingerprints are listed. The relayhost may be multiple
+physical hosts behind a load-balancer, each with its own private/public
+key and self-signed certificate. Alternatively, a single relayhost may
+be in the process of switching from one set of private/public keys to
+another, and both keys are trusted just prior to the transition. </p>
+
+<blockquote>
+<pre>
+    relayhost = [mailhub.example.com]
+    smtp_tls_security_level = fingerprint
+    smtp_tls_fingerprint_digest = md5
+    smtp_tls_fingerprint_cert_match =
+        3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+        EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
+<p> Example: Certificate fingerprint verification with selected destinations.
+As in the example above, we show two matching fingerprints: </p>
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+    smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+    smtp_tls_fingerprint_digest = md5
+</pre>
+</blockquote>
+<blockquote>
+<pre>
+/etc/postfix/tls_policy:
+    example.com        fingerprint
+        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
 <h3><a name="client_tls_verify"> Mandatory server certificate verification </a>
 </h3>
 
 <p> At the "verify" TLS security level, messages are sent only over
-TLS encrypted sessions if the server certificate is valid (not
+TLS encrypted sessions if the remote SMTP server certificate is
+valid (not
 expired or revoked, and signed by a trusted certificate authority)
-and if the server certificate name matches a known pattern.  Mandatory
+and where the server certificate name matches a known pattern.
+Mandatory
 server certificate verification can be configured by setting
 "smtp_tls_security_level = verify".  The
 smtp_tls_verify_cert_match parameter can override the default
@@ -1459,7 +1537,8 @@ appropriate configuration settings are "smtp_enforce_tls = yes" and
 
 <p> If the server certificate chain is trusted (see smtp_tls_CAfile
 and smtp_tls_CApath), any DNS names in the SubjectAlternativeName
-certificate extension are used to verify the server name.  If no
+certificate extension are used to verify the remote SMTP server name.
+If no
 DNS names are specified, the certificate CommonName is checked.
 If you want mandatory encryption without server certificate
 verification, see <a href="#client_tls_encrypt">above</a>. </p>
@@ -1492,7 +1571,7 @@ Postfix 2.3 and later should use the new TLS policy settings. </p>
 
 <p> Example: </p>
 
-<p> In this example, the client encrypts all traffic to the
+<p> In this example, the Postfix SMTP client encrypts all traffic to the
 <i>example.com</i> domain. The peer hostname is verified, but
 verification is vulnerable to DNS response forgery. Mail transmission
 to <i>example.com</i> recipients uses "high" grade ciphers. </p>
@@ -1543,7 +1622,8 @@ parameters. </p>
 
 <p> If the server certificate chain is trusted (see smtp_tls_CAfile and
 smtp_tls_CApath), any DNS names in the SubjectAlternativeName certificate
-extension are used to verify the server name. If no DNS names are
+extension are used to verify the remote SMTP server name. If no DNS names
+are
 specified, the CommonName is checked. If you want mandatory encryption
 without server certificate verification, see <a
 href="#client_tls_encrypt">above</a>. </p>
@@ -1578,9 +1658,11 @@ should use the new TLS policy settings. </p>
 
 <p> Secure-channel TLS without transport(5) table overrides: </p>
 
-<p> The client will encrypt all traffic and verify the destination name
+<p> The Postfix SMTP client will encrypt all traffic and verify the
+destination name
 immune from forged DNS responses. MX lookups are still used to find
-the SMTP servers for <i>example.com</i>, but these are not used when
+the hostnames of the SMTP servers for <i>example.com</i>, but these
+hostnames are not used when
 checking the names in the server certificate(s). Rather, the requirement
 is that the MX hosts for <i>example.com</i> have trusted certificates
 with a subject name of <i>example.com</i> or a sub-domain, see the
@@ -1729,35 +1811,50 @@ describe the corresponding table syntax: </p>
 
 <dl>
 
-<dt><b>none</b></dt>         
-<dd>No TLS. No additional attributes are supported at this level. </dd>
-
-<dt><b>may</b></dt>
-<dd>Opportunistic TLS. No additional attributes are supported at this
-level. </dd>
-
-<dt><b>encrypt</b></dt> <dd>Mandatory TLS encryption. Mail is
-delivered only if remote SMTP server offers STARTTLS and the TLS
-handshake succeeds.  At this level and higher the optional "ciphers"
-attribute overrides the main.cf smtp_tls_mandatory_ciphers parameter
-and the optional "protocols" keyword overrides the main.cf
-smtp_tls_mandatory_protocols parameter. </dd>
-
-<dt><b>verify</b></dt> <dd>Mandatory server certificate verification.
-Mail is delivered only if the TLS handshake succeeds, if the server
-certificate can be validated (not expired or revoked, and signed
-by a trusted certificate authority), and if the server certificate
-name matches the optional "match" attribute (or the main.cf
-smtp_tls_verify_cert_match parameter value when no optional "match"
-attribute is specified).  </dd>
-
-<dt><b>secure</b></dt> <dd>Secure-channel TLS. Mail is delivered
-only if the TLS handshake succeeds, if the server certificate can
-be validated (not expired or revoked, and signed by a trusted
-certificate authority), and if the server certificate name matches
-the optional "match" attribute (or the main.cf smtp_tls_secure_cert_match
-parameter value when no optional "match" attribute is specified).
-</dd>
+<dt><b>none</b></dt> <dd><a href="#client_tls_none">No TLS</a>. No
+additional attributes are supported at this level. </dd>
+
+<dt><b>may</b></dt> <dd><a href="#client_tls_may">Opportunistic TLS</a>.
+No additional attributes are supported at this level. </dd>
+
+<dt><b>encrypt</b></dt> <dd><a href="#client_tls_encrypt">Mandatory
+encryption</a>. Mail is delivered only if the remote SMTP
+server offers STARTTLS and the TLS handshake succeeds. At this
+level and higher the optional "ciphers" attribute overrides the
+main.cf smtp_tls_mandatory_ciphers parameter, and the optional
+"protocols" attribute
+overrides the main.cf smtp_tls_mandatory_protocols parameter. </dd>
+
+<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
+fingerprint verification.</a> Available with Postfix 2.5 and
+later. At this security level, there are no trusted certificate
+authorities. The certificate trust chain, expiration date, ... are
+not checked. Instead, the optional <b>match</b> attribute, or else
+the main.cf <b>smtp_tls_fingerprint_cert_match</b> parameter,
+lists the valid fingerprints of the server certificate. The
+digest algorithm used to calculate fingerprints is selected by the
+<b>smtp_tls_fingerprint_digest</b> parameter. Multiple fingerprints can
+be combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </dd>
+
+<dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory
+server certificate verification</a>.  Mail is delivered only if the
+TLS handshake
+succeeds, if the remote SMTP server certificate can be validated (not
+expired or revoked, and signed by a trusted certificate authority), and
+if the server certificate name matches the optional "match" attribute (or
+the main.cf smtp_tls_verify_cert_match parameter value when no optional
+"match" attribute is specified).  </dd>
+
+<dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate
+verification.</a> Mail is delivered only if the TLS handshake succeeds,
+if the remote SMTP server certificate can be validated (not expired
+or revoked, and signed by a trusted certificate authority), and if the
+server certificate name matches the optional "match" attribute (or the
+main.cf smtp_tls_secure_cert_match parameter value when no optional
+"match" attribute is specified).  </dd>
 
 </dl>
 
@@ -1789,6 +1886,8 @@ Example:
 <pre>
 /etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+    # Postfix 2.5 and later
+    smtp_tls_fingerprint_digest = md5
 /etc/postfix/tls_policy:
     example.edu             none
     example.mil             may
@@ -1798,6 +1897,10 @@ Example:
     example.net             secure
     .example.net            secure match=.example.net:example.net
     [mail.example.org]:587  secure match=nexthop
+    # Postfix 2.5 and later
+    [thumb.example.org]         fingerprint
+       match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+       match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
 </pre>
 </blockquote>
 
@@ -2040,18 +2143,26 @@ postfix/smtp[pid]: Host offered STARTTLS: [hostname.example.com]
 
 <h3><a name="client_vrfy_server">Server certificate verification depth</a> </h3>
 
-<p> When verifying a remote SMTP server certificate, a verification
-depth of 1 is sufficient if the certificate is directly issued by
-a CA specified with smtp_tls_CAfile or smtp_tls_CApath.  The default
-value of 5 should also suffice for longer chains (where the root CA issues
-a special CA certificate which then issues the actual certificate). </p>
-
-<p> Example: </p>
+<p> The server certificate verification depth is specified with the
+main.cf smtp_tls_scert_verifydepth parameter. The default verification
+depth is 9 (the OpenSSL default), for compatibility with Postfix
+versions before 2.5 where smtp_tls_scert_verifydepth was ignored.
+When you configure trust
+in a root CA, it is not necessary to explicitly trust intermediary CAs
+signed by the root CA, unless $smtp_tls_scert_verifydepth is less than the
+number of CAs in the certificate chain for the servers of interest. With
+a verify depth of 1 you can only verify certificates directly signed
+by a trusted CA, and all trusted intermediary CAs need to be configured
+explicitly. With a verify depth of 2 you can verify servers signed by a
+root CA or a direct intermediary CA (so long as the server is correctly
+configured to supply its intermediate CA certificate). </p>
  
+<p> Example: </p>
+
 <blockquote>
 <pre>
 /etc/postfix/main.cf:
-    smtp_tls_scert_verifydepth = 5
+    smtp_tls_scert_verifydepth = 2
 </pre>
 </blockquote>
 
@@ -2067,7 +2178,8 @@ methods. See smtp_tls_policy_maps for information on how to configure
 ciphers on a per-destination basis. </p>
 
 <p> By default anonymous ciphers are allowed, and automatically
-disabled when server certificates are verified. If you want to
+disabled when remote SMTP server certificates are verified. If you
+want to
 disable anonymous ciphers even at the "encrypt" security level, set
 "smtp_tls_mandatory_exclude_ciphers = aNULL"; and to
 disable anonymous ciphers even with opportunistic TLS, set
@@ -2084,6 +2196,9 @@ little point in requesting them. </p>
     smtp_tls_mandatory_ciphers = medium
     smtp_tls_mandatory_exclude_ciphers = RC4, MD5
     smtp_tls_exclude_ciphers = aNULL
+    smtp_tls_mandatory_protocols = SSLv3, TLSv1
+    # Also available with Postfix &ge; 2.5:
+    smtp_tls_mandatory_protocols = !SSLv2
 </pre>
 </blockquote>
 
@@ -2405,7 +2520,7 @@ but don't require them from all clients. </p>
     smtp_tls_CAfile = /etc/postfix/cacert.pem
     smtp_tls_session_cache_database =
        btree:/var/lib/postfix/smtp_tls_session_cache
-    smtp_use_tls = yes
+    smtp_tls_security_level = may
     smtpd_tls_CAfile = /etc/postfix/cacert.pem
     smtpd_tls_cert_file = /etc/postfix/FOO-cert.pem
     smtpd_tls_key_file = /etc/postfix/FOO-key.pem
@@ -2444,6 +2559,12 @@ compiled this part of the documentation from Lutz's documents.
 of the smtp_tls_per_site code in terms of enforcement levels, which
 simplified the implementation greatly.
 
+<li> Victor Duchovni implemented the fingerprint security level,
+added more sanity checks, and separated TLS connection management
+from security policy enforcement.  The latter change simplified the
+code that verifies certificate signatures, certificate names, and
+certificate fingerprints.
+
 </ul>
 
 </body>
index 11f407933b959b0fc13cdb06348ab23203d0365f..15b82f4e20d8e7b040d3feedb786cd31a6590356 100644 (file)
 #      open connection (file descriptor passing) per connection
 #      request, and is accessible to local clients only.
 #
-#      This feature is not part of the stable Postfix release.
-#
 #      The service name is a pathname relative to the Postfix
 #      queue directory (pathname controlled with the \fBqueue_directory\fR
 #      configuration parameter in main.cf).
+#
+#      This feature is available as of Postfix version 2.5.
 # .RE
 # .IP "\fBPrivate (default: y)\fR"
 #      Whether or not access is restricted to the mail system.
index b05f1e7f557f29351cfc065b83560ef1cdee4d85..038a7e84a7f27d65e3887d9ed8379e9c4e2478a7 100644 (file)
 #   * Text between <!-- and --> is stripped out. The <!-- and -->
 #     must appear on separate lines.
 #
+#   * Text after a blank line must start with an HTML element.
+#
 #   Also:
 #
 #   * All <dt> and <dd>text must be closed with </dt> and </dd>.
 #
+#   * Use <blockquote><pre>..</pre></blockquote> for examples
+#     between narrative text, instead of indenting examples by hand.
+#
+#   * Use <pre>..</pre> for the "Examples:" section at the end
+#     of a parameter description.
+#
 # The postlink tool automatically inserts hyperlinks for the following,
 # so you must not hyperlink that information yourself:
 #
@@ -2552,9 +2560,11 @@ The list is processed left to right, and processing stops at the
 first match.  Thus,
 </p>
 
+<blockquote>
 <pre>
-    masquerade_domains = foo.example.com example.com
+masquerade_domains = foo.example.com example.com
 </pre>
+</blockquote>
 
 <p>
 strips "user@any.thing.foo.example.com" to "user@foo.example.com",
@@ -2566,9 +2576,11 @@ A domain name prefixed with ! means do not masquerade this domain
 or its subdomains. Thus,
 </p>
 
+<blockquote>
 <pre>
-    masquerade_domains = !foo.example.com example.com
+masquerade_domains = !foo.example.com example.com
 </pre>
+</blockquote>
 
 <p>
 does not change "user@any.thing.foo.example.com" or "user@foo.example.com",
@@ -3625,10 +3637,12 @@ it can be specified in the master.cf file for a specific client,
 for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/master.cf:
-        smtp ... smtp -o smtp_bind_address=11.22.33.44
+/etc/postfix/master.cf:
+    smtp ... smtp -o smtp_bind_address=11.22.33.44
 </pre>
+</blockquote>
 
 <p> Note 1: when inet_interfaces specifies no more than one IPv4
 address, and that address is a non-loopback address, it is
@@ -3654,10 +3668,12 @@ it can be specified in the master.cf file for a specific client,
 for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/master.cf:
-        smtp ... smtp -o smtp_bind_address6=1:2:3:4:5:6:7:8
+/etc/postfix/master.cf:
+    smtp ... smtp -o smtp_bind_address6=1:2:3:4:5:6:7:8
 </pre>
+</blockquote>
 
 <p> Note 1: when inet_interfaces specifies no more than one IPv6
 address, and that address is a non-loopback address, it is
@@ -3958,10 +3974,12 @@ clients, or it can be specified in the master.cf file for a specific
 client, for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/master.cf:
-        mysmtp ... smtp -o smtp_helo_name=foo.bar.com
+/etc/postfix/master.cf:
+    mysmtp ... smtp -o smtp_helo_name=foo.bar.com
 </pre>
+</blockquote>
 
 <p>
 This feature is available in Postfix 2.0 and later.
@@ -4108,10 +4126,12 @@ The default is to comply with RFC 821. If you have to send mail to
 a broken SMTP server, configure a special SMTP client in master.cf:
 </p>
 
+<blockquote>
 <pre>
-    /etc/postfix/master.cf:
-        broken-smtp . . . smtp -o smtp_quote_rfc821_envelope=no
+/etc/postfix/master.cf:
+    broken-smtp . . . smtp -o smtp_quote_rfc821_envelope=no
 </pre>
+</blockquote>
 
 <p>
 and route mail for the destination in question to the "broken-smtp"
@@ -4678,9 +4698,12 @@ client network address information.
 <dt><b><a name="check_ccert_access">check_ccert_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
 
 <dd> Use the client certificate fingerprint as lookup key for the
-specified access(5) database; with Postfix version 2.2, also require
-that the SMTP client certificate is verified successfully. This
-feature is available with Postfix version 2.2 and later.</dd>
+specified access(5) database; with Postfix version 2.2, also require that
+the SMTP client certificate is verified successfully. 
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).  This feature is available with Postfix version
+2.2 and later. </dd>
 
 <dt><b><a name="check_client_access">check_client_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
 
@@ -4714,9 +4737,13 @@ allowed to relay. This feature is available with Postfix version 2.2.</dd>
 
 <dt><b><a name="permit_tls_clientcerts">permit_tls_clientcerts</a></b></dt>
 
-<dd>Permit the request when the remote SMTP client certificate is
-verified successfully, and the certificate fingerprint is listed
-in $relay_clientcerts. This feature is available with Postfix version 2.2.</dd>
+<dd>Permit the request when the remote SMTP client certificate
+fingerprint is listed in $relay_clientcerts.
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).  This feature is available with Postfix version
+2.2. </dd>
+
 <dt><b><a name="reject_rbl_client">reject_rbl_client <i>rbl_domain=d.d.d.d</i></a></b></dt>
 
 <dd>Reject the request when the reversed client network address is
@@ -4872,7 +4899,6 @@ rejected requests (default: 554).</dd>
 <dd>Pause for the specified number of seconds and proceed with
 the next restriction in the list, if any. This may stop zombie
 mail when used as:
-
 <pre>
 /etc/postfix/main.cf:
     smtpd_client_restrictions = 
@@ -5322,9 +5348,11 @@ at least one of the following restrictions. Otherwise Postfix will
 refuse to receive mail:
 </p>
 
+<blockquote>
 <pre>
-    reject, defer, defer_if_permit, reject_unauth_destination
+reject, defer, defer_if_permit, reject_unauth_destination
 </pre>
+</blockquote>
 
 <p>
 Specify a list of restrictions, separated by commas and/or whitespace.
@@ -5517,18 +5545,22 @@ If a remote SMTP client is authenticated, the permit_sasl_authenticated
 access restriction can be used to permit relay access, like this:
 </p>
 
+<blockquote>
 <pre>
-    smtpd_recipient_restrictions =
-        permit_mynetworks, permit_sasl_authenticated, ...
+smtpd_recipient_restrictions =
+    permit_mynetworks, permit_sasl_authenticated, ...
 </pre>
+</blockquote>
 
 <p> To reject all SMTP connections from unauthenticated clients,
 specify "smtpd_delay_reject = yes" (which is the default) and use:
 </p>
 
+<blockquote>
 <pre>
-    smtpd_client_restrictions = permit_sasl_authenticated, reject
+smtpd_client_restrictions = permit_sasl_authenticated, reject
 </pre>
+</blockquote>
 
 <p>
 See the SASL_README file for SASL configuration and operation details.
@@ -8135,16 +8167,20 @@ considers local. </p>
 addresses from remote SMTP clients, so that those addresses cannot
 be confused with local addresses. </p>
 
+<blockquote>
 <pre> 
-    remote_header_rewrite_domain = domain.invalid
+remote_header_rewrite_domain = domain.invalid
 </pre>
+</blockquote>
 
 <p> The default, purist, setting: don't rewrite headers from remote
 clients at all. </p>
 
+<blockquote>
 <pre>
-    remote_header_rewrite_domain =
+remote_header_rewrite_domain =
 </pre>
+</blockquote>
 
 %PARAM local_header_rewrite_clients permit_inet_interfaces
 
@@ -8186,8 +8222,10 @@ protocol. </dd>
 <dt><b>permit_tls_clientcerts </b></dt>
 
 <dd> Append the domain name in $myorigin or $mydomain when the
-client TLS certificate is successfully verified, and the client
-certificate fingerprint is listed in $relay_clientcerts.  </dd>
+client TLS certificate fingerprint is listed in $relay_clientcerts.
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).  </dd>
 
 <dt><b>permit_tls_all_clientcerts </b></dt>
 
@@ -8213,16 +8251,20 @@ is suitable for, e.g., pop-before-smtp lookup tables. </dd>
 message headers, and always append my own domain to incomplete
 header addresses.  </p>
 
+<blockquote>
 <pre> 
-    local_header_rewrite_clients = static:all
+local_header_rewrite_clients = static:all
 </pre>
+</blockquote>
 
 <p> The purist (and default) setting: rewrite headers only in mail
 from Postfix sendmail and in SMTP mail from this machine. </p>
 
+<blockquote>
 <pre>
-    local_header_rewrite_clients = permit_inet_interfaces
+local_header_rewrite_clients = permit_inet_interfaces
 </pre>
+</blockquote>
 
 <p> The intermediate setting: rewrite header addresses and append
 $myorigin or $mydomain information only with mail from Postfix
@@ -8232,11 +8274,13 @@ sendmail, from local clients, or from authorized SMTP clients. </p>
 rewriting when mail from a remote client is forwarded by a neighboring
 system.  </p>
 
+<blockquote>
 <pre>
-    local_header_rewrite_clients = permit_mynetworks, 
-        permit_sasl_authenticated permit_tls_clientcerts
-        check_address_map hash:/etc/postfix/pop-before-smtp 
+local_header_rewrite_clients = permit_mynetworks, 
+    permit_sasl_authenticated permit_tls_clientcerts
+    check_address_map hash:/etc/postfix/pop-before-smtp 
 </pre>
+</blockquote>
 
 %PARAM smtpd_tls_cert_file
 
@@ -8294,9 +8338,8 @@ smtpd_tls_cert_file = /etc/postfix/server.pem
 %PARAM smtpd_tls_key_file $smtpd_tls_cert_file
 
 <p> File with the Postfix SMTP server RSA private key in PEM format.
-This file may be combined with the Postfix SMTP server certificate
-file specified
-with $smtpd_tls_cert_file. </p>
+This file may be combined with the Postfix SMTP server RSA certificate
+file specified with $smtpd_tls_cert_file. </p>
 
 <p> The private key must be accessible without a pass-phrase, i.e. it
 must not be encrypted, but file permissions should grant read/write
@@ -8305,7 +8348,7 @@ access only to the system superuser account ("root"). </p>
 %PARAM smtpd_tls_dcert_file
 
 <p> File with the Postfix SMTP server DSA certificate in PEM format.
-This file may also contain the Postfix SMTP server private key. <p>
+This file may also contain the Postfix SMTP server private DSA key. </p>
 
 <p> See the discussion under smtpd_tls_cert_file for more details.
 </p>
@@ -8463,7 +8506,7 @@ may be annoying, so this option is "off" by default. </p>
 
 %PARAM smtpd_tls_req_ccert no
 
-<p> With mandatory TLS encryption, require a remote SMTP client
+<p> With mandatory TLS encryption, require a trusted remote SMTP client
 certificate in order to allow TLS connections to proceed.  This
 option implies "smtpd_tls_ask_ccert = yes". </p>
 
@@ -8472,13 +8515,21 @@ a warning written to the mail log. </p>
 
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
-%PARAM smtpd_tls_ccert_verifydepth 5
+%PARAM smtpd_tls_ccert_verifydepth 9
 
 <p> The verification depth for remote SMTP client certificates. A
 depth of 1 is sufficient if the issuing CA is listed in a local CA
-file.  The default value should also suffice for longer chains (the
-root CA issues special CA which then issues the actual certificate...).
-</p>
+file. </p>
+
+<p> The default verification depth is 9 (the OpenSSL default) for
+compatibility with earlier Postfix behavior. Prior to Postfix 2.5,
+the default value was 5, but the limit was not actually enforced. If
+you have set this to a lower non-default value, certificates with longer
+trust chains may now fail to verify. Certificate chains with 1 or 2
+CAs are common, deeper chains are more rare and any number between 5
+and 9 should suffice in practice. You can choose a lower number if,
+for example, you trust certificates directly signed by an issuing CA
+but not any CAs it delegates to. </p>
 
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
@@ -8535,12 +8586,12 @@ are not possible. </p>
 
 %PARAM relay_clientcerts
 
-<p> The list of remote SMTP client certificates for which the
-Postfix SMTP server will allow access with the permit_tls_clientcerts
-feature.  This feature does not use certificate names, because
-Postfix list manipulation routines treat whitespace and some other
-characters as special.  Instead we use certificate fingerprints as
-they are difficult to fake but easy to use for lookup. </p>
+<p> List of tables with remote SMTP client-certificate fingerprints
+for which the Postfix SMTP server will allow access with the
+permit_tls_clientcerts feature.  
+The fingerprint digest algorithm is configurable via the
+smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
+Postfix version 2.5).  </p>
 
 <p> Postfix lookup tables are in the form of (key, value) pairs.
 Since we only need the key, the value can be chosen freely, e.g.
@@ -8585,9 +8636,11 @@ use with EDH ciphers. </p>
 with other TLS packages, it is more secure to generate your own
 set of parameters with something like the following command:  </p>
 
+<blockquote>
 <pre>
-openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024
+openssl gendh -out /etc/postfix/dh_1024.pem -2 1024
 </pre>
+</blockquote>
 
 <p> Your actual source for entropy may differ. Some systems have
 /dev/random; on other system you may consider using the "Entropy
@@ -8639,10 +8692,10 @@ well without them. The recommended setting is to let the defaults stand: </p>
 
 <blockquote>
 <pre>
-    smtp_tls_cert_file =
-    smtp_tls_dcert_file =
-    smtp_tls_key_file =
-    smtp_tls_dkey_file =
+smtp_tls_cert_file =
+smtp_tls_dcert_file =
+smtp_tls_key_file =
+smtp_tls_dkey_file =
 </pre>
 </blockquote>
 
@@ -8925,13 +8978,20 @@ per-site TLS policies) for a possible work-around. </p>
 <p> This feature is available in Postfix 2.2 and later. With
 Postfix 2.3 and later use smtp_tls_policy_maps instead. </p>
 
-%PARAM smtp_tls_scert_verifydepth 5
+%PARAM smtp_tls_scert_verifydepth 9
+
+<p> The verification depth for remote SMTP server certificates. A depth
+of 1 is sufficient if the issuing CA is listed in a local CA file. </p>
 
-<p> The verification depth for remote SMTP server certificates. A
-depth of 1 is sufficient, if the certificate is directly issued by
-a CA listed in the CA files.  The default value (5) should suffice
-for longer chains (the root CA issues special CA which then issues
-the actual certificate...). </p>
+<p> The default verification depth is 9 (the OpenSSL default) for
+compatibility with earlier Postfix behavior. Prior to Postfix 2.5,
+the default value was 5, but the limit was not actually enforced. If
+you have set this to a lower non-default value, certificates with longer
+trust chains may now fail to verify. Certificate chains with 1 or 2
+CAs are common, deeper chains are more rare and any number between 5
+and 9 should suffice in practice. You can choose a lower number if,
+for example, you trust certificates directly signed by an issuing CA
+but not any CAs it delegates to. </p>
 
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
@@ -9203,7 +9263,7 @@ substitutions in regular expression maps. </p>
 This feature is available in Postfix 2.3 and later.
 </p>
 
-%PARAM empty_address_relayhost_maps_lookup_key <>
+%PARAM empty_address_relayhost_maps_lookup_key &lt;&gt;
 
 <p> The sender_dependent_relayhost_maps search string that will be
 used instead of the null sender address. </p>
@@ -9252,10 +9312,12 @@ clients, or it can be specified in the master.cf file for a specific
 client, for example:
 </p>
 
+<blockquote>
 <pre>
-  /etc/postfix/master.cf:
-        mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
+/etc/postfix/master.cf:
+    mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
 </pre>
+</blockquote>
 
 <p>
 This feature is available in Postfix 2.3 and later.
@@ -9405,7 +9467,7 @@ parameter.  See there for details. </p>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
-%PARAM lmtp_tls_scert_verifydepth 5
+%PARAM lmtp_tls_scert_verifydepth 9
 
 <p> The LMTP-specific version of the smtp_tls_scert_verifydepth
 configuration parameter.  See there for details. </p>
@@ -9461,6 +9523,13 @@ parameter.  See there for details. </p>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
+%PARAM lmtp_tls_security_level
+
+<p> The LMTP-specific version of the smtp_tls_security_level configuration
+parameter.  See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
 %PARAM lmtp_tls_enforce_peername yes
 
 <p> The LMTP-specific version of the smtp_tls_enforce_peername
@@ -9625,10 +9694,8 @@ configuration parameter.  See there for details. </p>
 
 <p> The SASL authentication security options that the Postfix SMTP
 client uses for TLS encrypted SMTP sessions with a verified server
-certificate. This feature is still under construction. It will not be
-included in the Postfix 2.3 release. </p>
-
-<p> This feature should be available in Postfix 2.4 and later. </p>
+certificate. This feature is under construction as of Postfix version
+2.3. </p>
 
 %PARAM lmtp_sasl_tls_verified_security_options $lmtp_sasl_tls_security_options
 
@@ -9780,6 +9847,20 @@ keyword overrides the main.cf smtp_tls_mandatory_protocols parameter.
 In the policy table, multiple protocols must be separated by colons,
 as attribute values may not contain whitespace or commas. </dd>
 
+<dt><b>fingerprint</b></dt> <dd>Certificate fingerprint
+verification. Available with Postfix 2.5 and later. At this security
+level, there are no trusted certificate authorities. The certificate
+trust chain, expiration date, ... are not checked. Instead,
+the optional <b>match</b> attribute, or else the main.cf
+<b>smtp_tls_fingerprint_cert_match</b> parameter, lists the
+valid "fingerprints" of the server certificate. The digest
+algorithm used to calculate the fingerprint is selected by the
+<b>smtp_tls_fingerprint_digest</b> parameter. Multiple fingerprints can
+be combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </dd>
+
 <dt><b>verify</b></dt> <dd>Mandatory TLS verification.  At this security
 level, DNS MX lookups are trusted to be secure enough, and the name
 verified in the server certificate is usually obtained indirectly via
@@ -9813,11 +9894,14 @@ Example:
 </p>
 
 <pre>
-main.cf:
+/etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+    # Postfix 2.5 and later
+    smtp_tls_fingerprint_digest = md5
 </pre>
+
 <pre>
-tls_policy:
+/etc/postfix/tls_policy:
     example.edu                 none
     example.mil                 may
     example.gov                 encrypt protocols=TLSv1
@@ -9825,6 +9909,10 @@ tls_policy:
     example.net                 secure
     .example.net                secure match=.example.net:example.net
     [mail.example.org]:587      secure match=nexthop
+    # Postfix 2.5 and later
+    [thumb.example.org]          fingerprint
+       match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+       match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
 </pre>
 
 <p> <b>Note:</b> The <b>hostname</b> strategy if listed in a non-default
@@ -9837,22 +9925,36 @@ configurations in environments where DNS security is not assured. </p>
 
 %PARAM smtp_tls_mandatory_protocols SSLv3, TLSv1
 
-<p> List of TLS protocols that the Postfix SMTP client will use
-with mandatory TLS encryption.  In main.cf the values
-are separated by whitespace, commas or colons. In the policy table
+<p> List of SSL/TLS protocols that the Postfix SMTP client will use with
+mandatory TLS encryption.  In main.cf the values are separated by
+whitespace, commas or colons. In the policy table "protocols" attribute
 (see smtp_tls_policy_maps) the only valid separator is colon. An
-empty value means allow all protocols. The valid protocol names,
-(see <b>SSL_get_version(3)</b>), are "SSLv2", "SSLv3" and
-"TLSv1". </p>
+empty value means allow all protocols. The valid protocol names, (see
+<b>SSL_get_version(3)</b>), are "SSLv2", "SSLv3" and "TLSv1". </p>
+
+<p> With Postfix &ge; 2.5 the parameter syntax is expanded to support
+protocol exclusions. One can now explicitly exclude SSLv2 by setting
+"smtp_tls_mandatory_protocols = !SSLv2". To exclude both SSLv2 and
+SSLv3 set "smtp_tls_mandatory_protocols = !SSLv2, !SSLv3". Listing
+the protocols to include, rather than protocols to exclude, is still
+supported; use the form you find more intuitive. </p>
 
-<p> Since SSL version 2 has known protocol weaknesses and
-is now deprecated, the default setting only lists "SSLv3" and
-"TLSv1". This means that by default, SSL version 2 will not be used
-at the "encrypt" security level and higher. </p>
+<p> Since SSL version 2 has known protocol weaknesses and is now
+deprecated, the default setting excludes "SSLv2".  This means that by
+default, SSL version 2 will not be used at the "encrypt" security level
+and higher. </p>
 
 <p> See the documentation of the smtp_tls_policy_maps parameter and
 TLS_README for more information about security levels. </p>
 
+<p> Example: </p>
+
+<pre>
+smtp_tls_mandatory_protocols = TLSv1
+# Alternative form with Postfix &ge; 2.5:
+smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
+</pre>
+
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 %PARAM smtp_tls_verify_cert_match hostname
@@ -9952,18 +10054,22 @@ the results of MX lookups in certificate verification is not immune to active
 Sample main.cf setting:
 </p>
 
+<blockquote>
 <pre>
 smtp_tls_secure_cert_match = nexthop
 </pre>
+</blockquote>
 
 <p>
 Sample policy table override:
 </p>
 
+<blockquote>
 <pre>
 example.net     secure match=example.com:.example.com
 .example.net    secure match=example.com:.example.com
 </pre>
+</blockquote>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
@@ -9997,18 +10103,31 @@ configuration parameter. See there for details. </p>
 
 %PARAM smtpd_tls_mandatory_protocols SSLv3, TLSv1
 
-<p> The TLS protocols accepted by the Postfix SMTP server with
-mandatory TLS encryption.  With opportunistic TLS encryption, all
-protocols are always accepted. If the list is empty, the server
-supports all available TLS protocol versions.  A non-empty value
-is a list of protocol names separated by whitespace, commas or
-colons. The supported protocol names are "SSLv2", "SSLv3" and
-"TLSv1", and are not case sensitive. </p>
+<p> The SSL/TLS protocols accepted by the Postfix SMTP server with
+mandatory TLS encryption. If the list is empty, the server supports all
+available SSL/TLS protocol versions.  A non-empty value is a list
+of protocol
+names separated by whitespace, commas or colons. The supported protocol
+names are "SSLv2", "SSLv3" and "TLSv1", and are not case sensitive. </p>
+
+<p> With Postfix &ge; 2.5 the parameter syntax is expanded to support
+protocol exclusions. One can now explicitly exclude SSLv2 by setting
+"smtpd_tls_mandatory_protocols = !SSLv2". To exclude both SSLv2 and
+SSLv3 set "smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3". Listing
+the protocols to include, rather than protocols to exclude, is still
+supported, use the form you find more intuitive. </p>
+
+<p> Since SSL version 2 has known protocol weaknesses and is now
+deprecated, the default setting excludes "SSLv2".  This means that
+by default, SSL version 2 will not be used at the "encrypt" security
+level. </p>
 
 <p> Example: </p>
 
 <pre>
-smtpd_tls_mandatory_protocols = SSLv3, TLSv1
+smtpd_tls_mandatory_protocols = TLSv1
+# Alternative form with Postfix &ge; 2.5:
+smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
 </pre>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
@@ -10047,6 +10166,15 @@ cipher grade which the administrator considers secure enough for
 mandatory encrypted sessions. This security level is not an appropriate
 default for systems delivering mail to the Internet. </dd>
 
+<dt><b>fingerprint</b></dt> <dd>Certificate fingerprint
+verification. Available with Postfix 2.5 and later. At this security
+level, there are no trusted certificate authorities. The certificate
+trust chain, expiration date, ... are not checked. Instead,
+the <b>smtp_tls_fingerprint_cert_match</b> parameter lists
+the valid "fingerprints" of the server certificate. The digest
+algorithm used to calculate the fingerprint is selected by the
+<b>smtp_tls_fingerprint_digest</b> parameter. </dd>
+
 <dt><b>verify</b></dt> <dd>Mandatory TLS verification. At this security
 level, DNS MX lookups are trusted to be secure enough, and the name
 verified in the server certificate is usually obtained indirectly
@@ -10072,40 +10200,50 @@ an appropriate default for systems delivering mail to the Internet. </dd>
 Examples:
 </p>
 
-<p>No TLS, old-style: smtp_use_tls=no and smtp_enforce_tls=no.</p>
 <pre>
-main.cf:
-    smtp_tls_security_level = none
+# No TLS. Formerly: smtp_use_tls=no and smtp_enforce_tls=no.
+smtp_tls_security_level = none
+</pre>
+
+<pre>
+# Opportunistic TLS.
+smtp_tls_security_level = may
 </pre>
 
-<p>Opportunistic TLS:</p>
 <pre>
-main.cf:
-    smtp_tls_security_level = may
+# Mandatory (high-grade) TLS encryption.
+smtp_tls_security_level = encrypt
+smtp_tls_mandatory_ciphers = high
 </pre>
 
-<p>Mandatory (high-grade) TLS encryption:</p>
 <pre>
-main.cf:
-    smtp_tls_security_level = encrypt
-    smtp_tls_mandatory_ciphers = high
+# Mandatory TLS verification of hostname or nexthop domain.
+smtp_tls_security_level = verify
+smtp_tls_mandatory_ciphers = high
+smtp_tls_verify_cert_match = hostname, nexthop, dot-nexthop
 </pre>
 
-<p>Mandatory TLS verification, of hostname or nexthop domain:</p>
 <pre>
-main.cf:
-    smtp_tls_security_level = verify
-    smtp_tls_mandatory_ciphers = high
-    smtp_tls_verify_cert_match = hostname, nexthop, dot-nexthop
+# Secure channel TLS with exact nexthop name match.
+smtp_tls_security_level = secure
+smtp_tls_mandatory_protocols = TLSv1
+smtp_tls_mandatory_ciphers = high
+smtp_tls_secure_cert_match = nexthop
 </pre>
 
-<p>Secure channel TLS with exact nexthop name matching:</p>
 <pre>
-main.cf:
-    smtp_tls_security_level = secure
-    smtp_tls_mandatory_protocols = TLSv1
-    smtp_tls_mandatory_ciphers = high
-    smtp_tls_secure_cert_match = nexthop
+# Certificate fingerprint verification (Postfix &ge; 2.5).
+# The CA-less "fingerprint" security level only scales to a limited
+# number of destinations. As a global default rather than a per-site
+# setting, this is practical when mail for all recipients is sent
+# to a central mail hub.
+relayhost = [mailhub.example.com]
+smtp_tls_security_level = fingerprint
+smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
+smtp_tls_mandatory_ciphers = high
+smtp_tls_fingerprint_cert_match = 
+    3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+    EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
 </pre>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
@@ -10393,6 +10531,7 @@ only ciphers matching <b>all</b> the properties are excluded. </p>
 
 <p> Examples (some of these will cause problems): </p>
 
+<blockquote>
 <pre>
 smtpd_tls_exclude_ciphers = aNULL
 smtpd_tls_exclude_ciphers = MD5, DES
@@ -10400,6 +10539,7 @@ smtpd_tls_exclude_ciphers = DES+MD5
 smtpd_tls_exclude_ciphers = AES256-SHA, DES-CBC3-MD5
 smtpd_tls_exclude_ciphers = kEDH+aRSA
 </pre>
+</blockquote>
 
 <p> The first setting disables anonymous ciphers. The next setting
 disables ciphers that use the MD5 digest algorithm or the (single) DES
@@ -10502,6 +10642,7 @@ case only ciphers matching <b>all</b> the properties are excluded. </p>
 
 <p> Examples (some of these will cause problems): </p>
 
+<blockquote>
 <pre>
 smtp_tls_exclude_ciphers = aNULL
 smtp_tls_exclude_ciphers = MD5, DES
@@ -10509,6 +10650,7 @@ smtp_tls_exclude_ciphers = DES+MD5
 smtp_tls_exclude_ciphers = AES256-SHA, DES-CBC3-MD5
 smtp_tls_exclude_ciphers = kEDH+aRSA
 </pre>
+</blockquote>
 
 <p> The first setting, disables anonymous ciphers. The next setting
 disables ciphers that use the MD5 digest algorithm or the (single) DES
@@ -10625,7 +10767,8 @@ be used only on dedicated servers. </dd>
 
 </dl>
 
-<p> Note 1: the "verify" and "secure" levels are not supported.
+<p> Note 1: the "fingerprint", "verify" and "secure" levels are not
+supported here.
 The Postfix SMTP server logs a warning and uses "encrypt" instead.
 To verify SMTP client certificates, see TLS_README for a discussion
 of the smtpd_tls_ask_ccert, smtpd_tls_req_ccert, and permit_tls_clientcerts
@@ -10680,11 +10823,9 @@ with other MTAs. </p>
 
 <p> Example: </p>
 
-<blockquote>
 <pre>
-    smtpd_tls_always_issue_session_ids = no
+smtpd_tls_always_issue_session_ids = no
 </pre>
-</blockquote>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
@@ -10728,6 +10869,180 @@ configuration parameter.  See there for details. </p>
 
 <p> This feature is available in Postfix 2.4 and later. </p>
 
+%PARAM smtp_tls_fingerprint_digest md5
+
+<p> The message digest algorithm used to construct remote SMTP server
+certificate fingerprints. At the "fingerprint" TLS security level
+(<b>smtp_tls_security_level</b> = fingerprint), the server certificate is
+verified by directly matching its <i>fingerprint</i>. The fingerprint
+is the message digest of the server certificate using the selected
+algorithm. With a digest algorithm resistant to "second pre-image"
+attacks, it is not feasible to create a new public key and a matching
+certificate that has the same fingerprint. </p>
+
+<p> The default algorithm is <b>md5</b>; this is consistent with
+the backwards compatible setting of the digest used to verify client
+certificates in the SMTP server. </p>
+
+<p> The best practice algorithm is now <b>sha1</b>. Recent advances in hash
+function cryptanalysis have led to md5 being deprecated in favor of sha1.
+However, as long as there are no known "second pre-image" attacks
+against md5, its use in this context can still be considered safe.
+</p>
+
+<p> While additional digest algorithms are often available with OpenSSL's
+libcrypto, only those used by libssl in SSL cipher suites are available to
+Postfix. For now this means just md5 or sha1. </p>
+
+<p> To find the fingerprint of a specific certificate file, with a
+specific digest algorithm, run:
+</p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -<i>digest</i> -in <i>certfile</i>.pem
+</pre>
+</blockquote>
+
+<p> The text to the right of "=" sign is the desired fingerprint.
+For example: </p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
+SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+%PARAM smtp_tls_fingerprint_cert_match
+
+<p> List of acceptable remote SMTP server certificate fingerprints
+for the "fingerprint" TLS security level (<b>smtp_tls_security_level</b> =
+fingerprint). At this security level, certificate authorities are
+not used, and certificate expiration times are ignored. Instead,
+server certificates are verified directly via their "fingerprint". The
+fingerprint is a message digest of the server certificate. The digest
+algorithm is selected via the <b>smtp_tls_fingerprint_digest</b>
+parameter. </p>
+
+<p> When an <b>smtp_tls_policy_maps</b> table entry specifies the
+"fingerprint" security level, any "match" attributes in that entry specify
+the list of valid fingerprints for the corresponding destination. Multiple
+fingerprints can be combined with a "|" delimiter in a single match
+attribute, or multiple match attributes can be employed. </p>
+
+<p> Example: Certificate fingerprint verification with internal mailhub.
+Two matching fingerprints are listed. The relayhost may be multiple
+physical hosts behind a load-balancer, each with its own private/public
+key and self-signed certificate. Alternatively, a single relayhost may
+be in the process of switching from one set of private/public keys to
+another, and both keys are trusted just prior to the transition. </p>
+
+<blockquote>
+<pre>
+relayhost = [mailhub.example.com]
+smtp_tls_security_level = fingerprint
+smtp_tls_fingerprint_digest = md5
+smtp_tls_fingerprint_cert_match =
+    3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+    EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
+<p> Example: Certificate fingerprint verification with selected destinations.
+As in the example above, we show two matching fingerprints: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+    smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
+    smtp_tls_fingerprint_digest = md5
+</pre>
+<pre>
+/etc/postfix/tls_policy:
+    example.com        fingerprint
+        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
+        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+%PARAM lmtp_tls_fingerprint_cert_match
+
+<p> The LMTP-specific version of the smtp_tls_fingerprint_cert_match
+configuration parameter.  See there for details. </p>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+%PARAM lmtp_tls_fingerprint_digest md5
+
+<p> The LMTP-specific version of the smtp_tls_fingerprint_digest
+configuration parameter.  See there for details. </p>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
+%PARAM smtpd_tls_fingerprint_digest md5
+
+<p> The message digest algorithm used to construct client-certificate
+fingerprints for <b>check_ccert_access</b> and
+<b>permit_tls_clientcerts</b>. The default algorithm is <b>md5</b>,
+for backwards compatibility with Postfix releases prior to 2.5.
+</p>
+
+<p> The best practice algorithm is now <b>sha1</b>. Recent advances in hash
+function cryptanalysis have led to md5 being deprecated in favor of sha1.
+However, as long as there are no known "second pre-image" attacks
+against md5, its use in this context can still be considered safe.
+</p>
+
+<p> While additional digest algorithms are often available with OpenSSL's
+libcrypto, only those used by libssl in SSL cipher suites are available to
+Postfix. For now this means just md5 or sha1. </p>
+
+<p> To find the fingerprint of a specific certificate file, with a
+specific digest algorithm, run: </p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -<i>digest</i> -in <i>certfile</i>.pem
+</pre>
+</blockquote>
+
+<p> The text to the right of "=" sign is the desired fingerprint.
+For example: </p>
+
+<blockquote>
+<pre>
+$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
+SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+</pre>
+</blockquote>
+
+<p> Example: client-certificate access table, with sha1 fingerprints: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+    smtpd_tls_fingerprint_digest = sha1
+    smtpd_client_restrictions =
+        check_ccert_access hash:/etc/postfix/access,
+        reject
+</pre>
+<pre>
+/etc/postfix/access:
+    # Action folded to next line...
+    AF:88:7C:AD:51:95:6F:36:96:F6:01:FB:2E:48:CD:AB:49:25:A2:3B
+        OK
+    85:16:78:FD:73:6E:CE:70:E0:31:5F:0D:3C:C8:6D:C4:2C:24:59:E1
+        permit_auth_destination
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.5 and later. </p>
+
 %PARAM lmtp_pix_workaround_maps
 
 <p> The LMTP-specific version of the smtp_pix_workaround_maps
@@ -10950,7 +11265,7 @@ is the master.cf name of the message delivery transport. </p>
 
 <p> This feature is available in Postfix 2.5 and later.  </p>
 
-%PARAM <i>transport</i>_destination_concurrency_failed_cohort_limit $default_destination_concurrency_failed_cohort_limit
+%PARAM transport_destination_concurrency_failed_cohort_limit $default_destination_concurrency_failed_cohort_limit
 
 <p> A transport-specific override for the
 default_destination_concurrency_failed_cohort_limit parameter value,
index 79377009030ee95fd201155d94477c91b11ab1d8..ac45cf30574affc62ac68abe7c6b603534400d4f 100644 (file)
@@ -847,7 +847,7 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
 {
     static VSTRING *request;
     static VSTRING *ident;
-    static ANVIL_REQ_TABLE request_table[] = {
+    static const ANVIL_REQ_TABLE request_table[] = {
        ANVIL_REQ_CONN, anvil_remote_connect,
        ANVIL_REQ_MAIL, anvil_remote_mail,
        ANVIL_REQ_RCPT, anvil_remote_rcpt,
@@ -857,7 +857,7 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
        ANVIL_REQ_LOOKUP, anvil_remote_lookup,
        0, 0,
     };
-    ANVIL_REQ_TABLE *rp;
+    const ANVIL_REQ_TABLE *rp;
 
     /*
      * Sanity check. This service takes no command-line arguments.
@@ -941,7 +941,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_ANVIL_TIME_UNIT, DEF_ANVIL_TIME_UNIT, &var_anvil_time_unit, 1, 0,
        VAR_ANVIL_STAT_TIME, DEF_ANVIL_STAT_TIME, &var_anvil_stat_time, 1, 0,
        0,
index 805144e956f9d27221f1dd19a6809f545769762e..ae62d21db1669d7e79cfa2056434eb9a0c46afc4 100644 (file)
@@ -612,16 +612,16 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0,
        0,
     };
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000,
        VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
        0,
     };
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
        VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0,
        VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0,
index 23f16b0a3d1474e897bd020d6836ce1233408435..352944b59e60d14d3833270e88b19a0af908b7c4 100644 (file)
@@ -173,7 +173,7 @@ typedef struct {
 
 #define STRING_AND_LEN(x) (x), (sizeof(x) - 1)
 
-static BOUNCE_TIME_DIVISOR time_divisors[] = {
+static const BOUNCE_TIME_DIVISOR time_divisors[] = {
     STRING_AND_LEN("seconds"), 1,
     STRING_AND_LEN("minutes"), 60,
     STRING_AND_LEN("hours"), 60 * 60,
@@ -192,7 +192,7 @@ typedef struct {
     int    *value;                     /* parameter value */
 } BOUNCE_TIME_PARAMETER;
 
-static BOUNCE_TIME_PARAMETER time_parameter[] = {
+static const BOUNCE_TIME_PARAMETER time_parameter[] = {
     STRING_AND_LEN(VAR_DELAY_WARN_TIME), &var_delay_warn_time,
     STRING_AND_LEN(VAR_MAX_QUEUE_TIME), &var_max_queue_time,
     0, 0,
@@ -381,8 +381,8 @@ static const char *bounce_template_lookup(const char *key, int unused_mode,
                                                  char *context)
 {
     BOUNCE_TEMPLATE *tp = (BOUNCE_TEMPLATE *) context;
-    BOUNCE_TIME_PARAMETER *bp;
-    BOUNCE_TIME_DIVISOR *bd;
+    const BOUNCE_TIME_PARAMETER *bp;
+    const BOUNCE_TIME_DIVISOR *bd;
     static VSTRING *buf;
     int     result;
 
index d0d4c4f3e9693608b08caf0eb65ab7ec02ed38aa..e5a9cf92190afe03aab79c938bf8bd70b601e553 100644 (file)
@@ -86,7 +86,7 @@ int     cleanup_bounce(CLEANUP_STATE *state)
 {
     const char *myname = "cleanup_bounce";
     VSTRING *buf = vstring_alloc(100);
-    CLEANUP_STAT_DETAIL *detail;
+    const CLEANUP_STAT_DETAIL *detail;
     DSN_SPLIT dp;
     const char *dsn_status;
     const char *dsn_text;
index c30c91e9cb7b9d3797cc0362944f396ea176efe5..bb3983c4df6c39aee76c590119e7cc4470a623e4 100644 (file)
@@ -301,17 +301,17 @@ void    cleanup_sig(int sig)
 
 void    cleanup_pre_jail(char *unused_name, char **unused_argv)
 {
-    static NAME_MASK send_canon_class_table[] = {
+    static const NAME_MASK send_canon_class_table[] = {
        CANON_CLASS_ENV_FROM, CLEANUP_CANON_FLAG_ENV_FROM,
        CANON_CLASS_HDR_FROM, CLEANUP_CANON_FLAG_HDR_FROM,
        0,
     };
-    static NAME_MASK rcpt_canon_class_table[] = {
+    static const NAME_MASK rcpt_canon_class_table[] = {
        CANON_CLASS_ENV_RCPT, CLEANUP_CANON_FLAG_ENV_RCPT,
        CANON_CLASS_HDR_RCPT, CLEANUP_CANON_FLAG_HDR_RCPT,
        0,
     };
-    static NAME_MASK canon_class_table[] = {
+    static const NAME_MASK canon_class_table[] = {
        CANON_CLASS_ENV_FROM, CLEANUP_CANON_FLAG_ENV_FROM,
        CANON_CLASS_ENV_RCPT, CLEANUP_CANON_FLAG_ENV_RCPT,
        CANON_CLASS_HDR_FROM, CLEANUP_CANON_FLAG_HDR_FROM,
@@ -319,7 +319,7 @@ void    cleanup_pre_jail(char *unused_name, char **unused_argv)
        0,
     };
 
-    static NAME_MASK masq_class_table[] = {
+    static const NAME_MASK masq_class_table[] = {
        MASQ_CLASS_ENV_FROM, CLEANUP_MASQ_FLAG_ENV_FROM,
        MASQ_CLASS_ENV_RCPT, CLEANUP_MASQ_FLAG_ENV_RCPT,
        MASQ_CLASS_HDR_FROM, CLEANUP_MASQ_FLAG_HDR_FROM,
index fee73bbe95d1da313b2316ba313e236f69593683..3abb2519a068ec4c9181e2e0a3f910315b1c5cca 100644 (file)
@@ -132,7 +132,8 @@ static char *cleanup_extract_internal(VSTRING *buffer, TOK822 *addr)
 
 /* cleanup_rewrite_sender - sender address rewriting */
 
-static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts,
+static void cleanup_rewrite_sender(CLEANUP_STATE *state,
+                                          const HEADER_OPTS *hdr_opts,
                                           VSTRING *header_buf)
 {
     TOK822 *tree;
@@ -188,7 +189,8 @@ static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts,
 
 /* cleanup_rewrite_recip - recipient address rewriting */
 
-static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts,
+static void cleanup_rewrite_recip(CLEANUP_STATE *state,
+                                         const HEADER_OPTS *hdr_opts,
                                          VSTRING *header_buf)
 {
     TOK822 *tree;
@@ -297,7 +299,7 @@ static const char *cleanup_act(CLEANUP_STATE *state, char *context,
      * queue record processing, and prevents bounces from being sent.
      */
     if (STREQUAL(value, "REJECT", command_len)) {
-       CLEANUP_STAT_DETAIL *detail;
+       const CLEANUP_STAT_DETAIL *detail;
 
        if (state->reason)
            myfree(state->reason);
@@ -437,7 +439,8 @@ static const char *cleanup_act(CLEANUP_STATE *state, char *context,
 /* cleanup_header_callback - process one complete header line */
 
 static void cleanup_header_callback(void *context, int header_class,
-                                HEADER_OPTS *hdr_opts, VSTRING *header_buf,
+                                           const HEADER_OPTS *hdr_opts,
+                                           VSTRING *header_buf,
                                            off_t unused_offset)
 {
     CLEANUP_STATE *state = (CLEANUP_STATE *) context;
@@ -762,7 +765,7 @@ static void cleanup_message_headerbody(CLEANUP_STATE *state, int type,
                                               const char *buf, ssize_t len)
 {
     const char *myname = "cleanup_message_headerbody";
-    MIME_STATE_DETAIL *detail;
+    const MIME_STATE_DETAIL *detail;
     const char *cp;
     char   *dst;
 
index ed1adb8ff785f3286f5a2c42eb134804819257b6..7a76c52efe8eb5d6e34b7457ba950ae573602a2f 100644 (file)
@@ -234,7 +234,7 @@ static void cleanup_milter_set_error(CLEANUP_STATE *state, int err)
 static const char *cleanup_milter_error(CLEANUP_STATE *state, int err)
 {
     const char *myname = "cleanup_milter_error";
-    CLEANUP_STAT_DETAIL *dp;
+    const CLEANUP_STAT_DETAIL *dp;
 
     /*
      * For consistency with error reporting within the milter infrastructure,
@@ -348,7 +348,7 @@ static off_t cleanup_find_header_start(CLEANUP_STATE *state, ssize_t index,
     off_t   curr_offset;               /* offset after found record */
     off_t   ptr_offset;                        /* pointer to found record */
     VSTRING *ptr_buf = 0;
-    int     rec_type;
+    int     rec_type = REC_TYPE_ERROR;
     int     last_type;
     ssize_t len;
     int     hdr_count = 0;
index 853769144174febf44fc2744071b59336a46a48c..2658819cdbadd735ee0e8306318624107c0784f3 100644 (file)
@@ -820,7 +820,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_FFLUSH_REFRESH, DEF_FFLUSH_REFRESH, &var_fflush_refresh, 1, 0,
        VAR_FFLUSH_PURGE, DEF_FFLUSH_PURGE, &var_fflush_purge, 1, 0,
        0,
index 3603f04c08f4afd2cfd67aed9077092b4aaaf57c..ce0bb40d05c180102c29d0c8885e0ccd25c885a8 100644 (file)
@@ -18,7 +18,7 @@
 /*     const char *cleanup_strerror(code)
 /*     int     code;
 /*
-/*     CLEANUP_STAT_DETAIL *cleanup_stat_detail(code)
+/*     const CLEANUP_STAT_DETAIL *cleanup_stat_detail(code)
 /*     int     code;
 /* DESCRIPTION
 /*     cleanup_strerror() maps a status code returned by the \fIcleanup\fR
@@ -58,7 +58,7 @@
   * multiple errors, to it is important to list the most severe errors first,
   * because cleanup_strerror() can report only one error.
   */
-static CLEANUP_STAT_DETAIL cleanup_stat_map[] = {
+static const CLEANUP_STAT_DETAIL cleanup_stat_map[] = {
     CLEANUP_STAT_DEFER, 451, "4.7.1", "service unavailable",
     CLEANUP_STAT_PROXY, 451, "4.3.0", "queue file write error",
     CLEANUP_STAT_BAD, 451, "4.3.0", "internal protocol error",
@@ -91,7 +91,7 @@ const char *cleanup_strerror(unsigned status)
 
 /* cleanup_stat_detail - map status code to table entry with assorted data */
 
-CLEANUP_STAT_DETAIL *cleanup_stat_detail(unsigned status)
+const CLEANUP_STAT_DETAIL *cleanup_stat_detail(unsigned status)
 {
     unsigned i;
 
index ede715d4147c5a1d1ee8ee088b52b438306b4446..9d399cde71e3585b3d437c04636e8c317dd83c46 100644 (file)
@@ -84,7 +84,7 @@ typedef struct {
 } CLEANUP_STAT_DETAIL;
 
 extern const char *cleanup_strerror(unsigned);
-extern CLEANUP_STAT_DETAIL *cleanup_stat_detail(unsigned);
+extern const CLEANUP_STAT_DETAIL *cleanup_stat_detail(unsigned);
 extern const char *cleanup_strflags(unsigned);
 
 /* LICENSE
index 95697075c63693ae9d825bc77e4775dd62ff63bf..77a28e209fe8253cb1728d9fefdc711d6ed1f5c9 100644 (file)
@@ -94,7 +94,7 @@
   * even know about, because map types may be added dynamically on some
   * platforms.
   */
-static NAME_CODE data_redirect_map_types[] = {
+static const NAME_CODE data_redirect_map_types[] = {
     DICT_TYPE_HASH, 1,
     DICT_TYPE_BTREE, 1,
     DICT_TYPE_DBM, 1,
index 746998a57dd62e103ecbf317ffcec40eaf548b8f..2bbd2f6d1e193663da6a05df36e156e471b7f973 100644 (file)
@@ -113,7 +113,7 @@ DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *fp, off_t offset, int flags)
 {
     char   *cp;
     DELIVERED_HDR_INFO *info;
-    HEADER_OPTS *hdr;
+    const HEADER_OPTS *hdr;
 
     /*
      * Sanity check.
index 251f6f6ac0b0b255beaa5b29b2248f4108c25407..3c183aa4af507fa297d494ac59451442bebd7cb8 100644 (file)
@@ -71,7 +71,7 @@
 
 /* Application-specific. */
 
-static NAME_MASK dsn_notify_table[] = {
+static const NAME_MASK dsn_notify_table[] = {
     "NEVER", DSN_NOTIFY_NEVER,
     "SUCCESS", DSN_NOTIFY_SUCCESS,
     "FAILURE", DSN_NOTIFY_FAILURE,
@@ -79,7 +79,7 @@ static NAME_MASK dsn_notify_table[] = {
     0, 0,
 };
 
-static NAME_CODE dsn_ret_table[] = {
+static const NAME_CODE dsn_ret_table[] = {
     "FULL", DSN_RET_FULL,
     "HDRS", DSN_RET_HDRS,
     0, 0,
index 811005487749c0696dafc3937ec9c7b626b7cf2b..d7501934b89216b2e9315be0cf2229b8e272d631 100644 (file)
@@ -62,7 +62,7 @@
  /*
   * The lookup table.
   */
-static NAME_MASK ehlo_mask_table[] = {
+static const NAME_MASK ehlo_mask_table[] = {
     "8BITMIME", EHLO_MASK_8BITMIME,
     "AUTH", EHLO_MASK_AUTH,
     "ETRN", EHLO_MASK_ETRN,
index 9ae7cc4931c369c989a397f0944605c69e736e4a..29bce7bddf9fa1bbeddf1c792e92208520b0305b 100644 (file)
@@ -64,7 +64,7 @@
 
 int     ext_prop_mask(const char *param_name, const char *pattern)
 {
-    static NAME_MASK table[] = {
+    static const NAME_MASK table[] = {
        "canonical", EXT_PROP_CANONICAL,
        "virtual", EXT_PROP_VIRTUAL,
        "alias", EXT_PROP_ALIAS,
index de8f58bc97bd6b68d248cc89bdcca2903992ae3a..b5f2aa12b8b15f8a1e6cbe5a709c0e1abe148e3a 100644 (file)
@@ -42,7 +42,7 @@
 /*     void    *context;
 /*     HBC_CHECKS *hbc;
 /*     int     header_class;
-/*     HEADER_OPTS *hdr_opts;
+/*     const HEADER_OPTS *hdr_opts;
 /*     VSTRING *header;
 /*
 /*     char    *hbc_body_checks(context, hbc, body_line, body_line_len)
@@ -292,7 +292,7 @@ static char *hbc_action(void *context, HBC_CALL_BACKS *cb,
 /* hbc_header_checks - process one complete header line */
 
 char   *hbc_header_checks(void *context, HBC_CHECKS *hbc, int header_class,
-                                 HEADER_OPTS *hdr_opts,
+                                 const HEADER_OPTS *hdr_opts,
                                  VSTRING *header, off_t offset)
 {
     const char *myname = "hbc_header_checks";
@@ -463,7 +463,8 @@ static void out_cb(void *context, int rec_type, const char *buf,
 
 /* head_out - MIME_STATE header call-back */
 
-static void head_out(void *context, int header_class, HEADER_OPTS *header_info,
+static void head_out(void *context, int header_class,
+                            const HEADER_OPTS *header_info,
                             VSTRING *buf, off_t offset)
 {
     HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
index 2fc37677b3edd7900dc6af298d6e1d1e49ed9641..f397ae2a75ef57c1a0ef50273a387239fde6402f 100644 (file)
@@ -53,7 +53,7 @@ extern HBC_CHECKS *hbc_header_checks_create(const char *, const char *,
                                                    HBC_CALL_BACKS *);
 extern HBC_CHECKS *hbc_body_checks_create(const char *, const char *,
                                                  HBC_CALL_BACKS *);
-extern char *hbc_header_checks(void *, HBC_CHECKS *, int, HEADER_OPTS *,
+extern char *hbc_header_checks(void *, HBC_CHECKS *, int, const HEADER_OPTS *,
                                       VSTRING *, off_t);
 extern char *hbc_body_checks(void *, HBC_CHECKS *, const char *, ssize_t, off_t);
 
index 4a88ccb283cd4f726195b9e1045449d8887bcaee..0461502ff9fd99a747b01187157aa90ae8eedebd 100644 (file)
@@ -6,7 +6,7 @@
 /* SYNOPSIS
 /*     #include <header_opts.h>
 /*
-/*     HEADER_OPTS *header_opts_find(string)
+/*     const HEADER_OPTS *header_opts_find(string)
 /*     const char *string;
 /* DESCRIPTION
 /*     header_opts_find() takes a message header line and looks up control
@@ -48,7 +48,7 @@
   * Header names are given in the preferred capitalization. The lookups are
   * case-insensitive.
   */
-static HEADER_OPTS header_opts[] = {
+static const HEADER_OPTS header_opts[] = {
     "Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP,
     "Bcc", HDR_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP,
     "Cc", HDR_CC, HDR_OPT_XRECIP,
@@ -91,7 +91,7 @@ static VSTRING *header_key;
 
 static void header_opts_init(void)
 {
-    HEADER_OPTS *hp;
+    const HEADER_OPTS *hp;
     const char *cp;
 
     /*
@@ -111,7 +111,7 @@ static void header_opts_init(void)
 
 /* header_opts_find - look up header options */
 
-HEADER_OPTS *header_opts_find(const char *string)
+const HEADER_OPTS *header_opts_find(const char *string)
 {
     const char *cp;
 
@@ -131,5 +131,5 @@ HEADER_OPTS *header_opts_find(const char *string)
                     trimblanks(vstring_str(header_key), cp - string)
                     - vstring_str(header_key));
     VSTRING_TERMINATE(header_key);
-    return ((HEADER_OPTS *) htable_find(header_hash, vstring_str(header_key)));
+    return ((const HEADER_OPTS *) htable_find(header_hash, vstring_str(header_key)));
 }
index cb6a48279bbac2c53fbff22a3868918e30be81b6..a0f26510ac66f6ea44a48809e2f1f8ec760d191d 100644 (file)
@@ -67,7 +67,7 @@ typedef struct {
 
 #define HDR_OPT_XRECIP (HDR_OPT_RECIP | HDR_OPT_EXTRACT)
 
-extern HEADER_OPTS *header_opts_find(const char *);
+extern const HEADER_OPTS *header_opts_find(const char *);
 
 /* LICENSE
 /* .ad
index 46b8812809c20f7cf18fdb81f90dafb68a4923de..ca3af340923727a1f0ea3573654b7a1ae610425e 100644 (file)
@@ -69,7 +69,7 @@
 
 int     input_transp_mask(const char *param_name, const char *pattern)
 {
-    static NAME_MASK table[] = {
+    static const NAME_MASK table[] = {
        "no_unknown_recipient_checks", INPUT_TRANSP_UNKNOWN_RCPT,
        "no_address_mappings", INPUT_TRANSP_ADDRESS_MAPPING,
        "no_header_body_checks", INPUT_TRANSP_HEADER_BODY,
index 1071b10d666a1716286f3b5ca07b05445e6b24a8..528824170a8d4f1c23d2736c0dee152edabeb347 100644 (file)
@@ -53,7 +53,7 @@
 
 int     int_filt_flags(int class)
 {
-    static NAME_MASK table[] = {
+    static const NAME_MASK table[] = {
        "notify", INT_FILT_NOTIFY,
        "bounce", INT_FILT_BOUNCE,
        0,
index a8bff1b57fb0ffcaef9a67fee26a83edbc5e5376..89cce98c180b3f26ca5f77cfcf324fdd3b7c77eb 100644 (file)
@@ -126,12 +126,12 @@ typedef struct {
     int     max;                       /* upper bound or zero */
 } CONFIG_TIME_TABLE;
 
-extern void get_mail_conf_str_table(CONFIG_STR_TABLE *);
-extern void get_mail_conf_int_table(CONFIG_INT_TABLE *);
-extern void get_mail_conf_long_table(CONFIG_LONG_TABLE *);
-extern void get_mail_conf_bool_table(CONFIG_BOOL_TABLE *);
-extern void get_mail_conf_time_table(CONFIG_TIME_TABLE *);
-extern void get_mail_conf_raw_table(CONFIG_RAW_TABLE *);
+extern void get_mail_conf_str_table(const CONFIG_STR_TABLE *);
+extern void get_mail_conf_int_table(const CONFIG_INT_TABLE *);
+extern void get_mail_conf_long_table(const CONFIG_LONG_TABLE *);
+extern void get_mail_conf_bool_table(const CONFIG_BOOL_TABLE *);
+extern void get_mail_conf_time_table(const CONFIG_TIME_TABLE *);
+extern void get_mail_conf_raw_table(const CONFIG_RAW_TABLE *);
 
  /*
   * Tables to initialize parameters from the global configuration file or
@@ -175,11 +175,11 @@ typedef struct {
     int    *target;                    /* pointer to global variable */
 } CONFIG_BOOL_FN_TABLE;
 
-extern void get_mail_conf_str_fn_table(CONFIG_STR_FN_TABLE *);
-extern void get_mail_conf_int_fn_table(CONFIG_INT_FN_TABLE *);
-extern void get_mail_conf_long_fn_table(CONFIG_LONG_FN_TABLE *);
-extern void get_mail_conf_bool_fn_table(CONFIG_BOOL_FN_TABLE *);
-extern void get_mail_conf_raw_fn_table(CONFIG_RAW_FN_TABLE *);
+extern void get_mail_conf_str_fn_table(const CONFIG_STR_FN_TABLE *);
+extern void get_mail_conf_int_fn_table(const CONFIG_INT_FN_TABLE *);
+extern void get_mail_conf_long_fn_table(const CONFIG_LONG_FN_TABLE *);
+extern void get_mail_conf_bool_fn_table(const CONFIG_BOOL_FN_TABLE *);
+extern void get_mail_conf_raw_fn_table(const CONFIG_RAW_FN_TABLE *);
 
 /* LICENSE
 /* .ad
index f6a11024bab14dca6c57bf731925d261521f3a53..30d4813ba4340b0c66d0e86d8b5f8f97c734a090 100644 (file)
 /*     int     value;
 /*
 /*     void    get_mail_conf_bool_table(table)
-/*     CONFIG_BOOL_TABLE *table;
+/*     const CONFIG_BOOL_TABLE *table;
 /*
 /*     void    get_mail_conf_bool_fn_table(table)
-/*     CONFIG_BOOL_TABLE *table;
+/*     const CONFIG_BOOL_TABLE *table;
 /* DESCRIPTION
 /*     This module implements configuration parameter support for
 /*     boolean values. The internal representation is zero (false)
@@ -134,7 +134,7 @@ void    set_mail_conf_bool(const char *name, int value)
 
 /* get_mail_conf_bool_table - look up table of booleans */
 
-void    get_mail_conf_bool_table(CONFIG_BOOL_TABLE *table)
+void    get_mail_conf_bool_table(const CONFIG_BOOL_TABLE *table)
 {
     while (table->name) {
        table->target[0] = get_mail_conf_bool(table->name, table->defval);
@@ -144,7 +144,7 @@ void    get_mail_conf_bool_table(CONFIG_BOOL_TABLE *table)
 
 /* get_mail_conf_bool_fn_table - look up booleans, defaults are functions */
 
-void    get_mail_conf_bool_fn_table(CONFIG_BOOL_FN_TABLE *table)
+void    get_mail_conf_bool_fn_table(const CONFIG_BOOL_FN_TABLE *table)
 {
     while (table->name) {
        table->target[0] = get_mail_conf_bool_fn(table->name, table->defval);
index e00e1de0af66589be9e64d183b88c04edc852cc2..1c2dcba43985a29abe8c0e4f99e758c4139b7cd5 100644 (file)
 /*     int     value;
 /*
 /*     void    get_mail_conf_int_table(table)
-/*     CONFIG_INT_TABLE *table;
+/*     const CONFIG_INT_TABLE *table;
 /*
 /*     void    get_mail_conf_int_fn_table(table)
-/*     CONFIG_INT_TABLE *table;
+/*     const CONFIG_INT_TABLE *table;
 /* AUXILIARY FUNCTIONS
 /*     int     get_mail_conf_int2(name1, name2, defval, min, max);
 /*     const char *name1;
@@ -172,7 +172,7 @@ void    set_mail_conf_int(const char *name, int value)
 
 /* get_mail_conf_int_table - look up table of integers */
 
-void    get_mail_conf_int_table(CONFIG_INT_TABLE *table)
+void    get_mail_conf_int_table(const CONFIG_INT_TABLE *table)
 {
     while (table->name) {
        table->target[0] = get_mail_conf_int(table->name, table->defval,
@@ -183,7 +183,7 @@ void    get_mail_conf_int_table(CONFIG_INT_TABLE *table)
 
 /* get_mail_conf_int_fn_table - look up integers, defaults are functions */
 
-void    get_mail_conf_int_fn_table(CONFIG_INT_FN_TABLE *table)
+void    get_mail_conf_int_fn_table(const CONFIG_INT_FN_TABLE *table)
 {
     while (table->name) {
        table->target[0] = get_mail_conf_int_fn(table->name, table->defval,
index 91e488a55ae821ff8c107dec23371c7a6dfb9bb7..e9feaa3ad927f598f5b06c84fc61ee66588366e7 100644 (file)
 /*     long    value;
 /*
 /*     void    get_mail_conf_long_table(table)
-/*     CONFIG_LONG_TABLE *table;
+/*     const CONFIG_LONG_TABLE *table;
 /*
 /*     void    get_mail_conf_long_fn_table(table)
-/*     CONFIG_LONG_TABLE *table;
+/*     const CONFIG_LONG_TABLE *table;
 /* AUXILIARY FUNCTIONS
 /*     int     get_mail_conf_long2(name1, name2, defval, min, max);
 /*     const char *name1;
@@ -172,7 +172,7 @@ void    set_mail_conf_long(const char *name, long value)
 
 /* get_mail_conf_long_table - look up table of integers */
 
-void    get_mail_conf_long_table(CONFIG_LONG_TABLE *table)
+void    get_mail_conf_long_table(const CONFIG_LONG_TABLE *table)
 {
     while (table->name) {
        table->target[0] = get_mail_conf_long(table->name, table->defval,
@@ -183,7 +183,7 @@ void    get_mail_conf_long_table(CONFIG_LONG_TABLE *table)
 
 /* get_mail_conf_long_fn_table - look up integers, defaults are functions */
 
-void    get_mail_conf_long_fn_table(CONFIG_LONG_FN_TABLE *table)
+void    get_mail_conf_long_fn_table(const CONFIG_LONG_FN_TABLE *table)
 {
     while (table->name) {
        table->target[0] = get_mail_conf_long_fn(table->name, table->defval,
index 2e4c9832ef153c7e7fa167b43878c04caf0450d9..4c9c5bde70c1cff02cf2f8bff3a7e14c36a288c7 100644 (file)
 /*     int     max;
 /*
 /*     void    get_mail_conf_raw_table(table)
-/*     CONFIG_RAW_TABLE *table;
+/*     const CONFIG_RAW_TABLE *table;
 /*
 /*     void    get_mail_conf_raw_fn_table(table)
-/*     CONFIG_RAW_TABLE *table;
+/*     const CONFIG_RAW_TABLE *table;
 /* DESCRIPTION
 /*     This module implements support for string-valued global
 /*     configuration parameters that are loaded without $name expansion.
@@ -120,7 +120,7 @@ char   *get_mail_conf_raw_fn(const char *name, stupid_indent_str defval,
 
 /* get_mail_conf_raw_table - look up table of strings */
 
-void    get_mail_conf_raw_table(CONFIG_RAW_TABLE *table)
+void    get_mail_conf_raw_table(const CONFIG_RAW_TABLE *table)
 {
     while (table->name) {
        if (table->target[0])
@@ -133,7 +133,7 @@ void    get_mail_conf_raw_table(CONFIG_RAW_TABLE *table)
 
 /* get_mail_conf_raw_fn_table - look up strings, defaults are functions */
 
-void    get_mail_conf_raw_fn_table(CONFIG_RAW_FN_TABLE *table)
+void    get_mail_conf_raw_fn_table(const CONFIG_RAW_FN_TABLE *table)
 {
     while (table->name) {
        if (table->target[0])
index 1f8af32e3e4cca71d2a8c5c44017974153c8a860..8d8288ce3a3b94ec86912d186beb65d812382476 100644 (file)
 /*     const char *value;
 /*
 /*     void    get_mail_conf_str_table(table)
-/*     CONFIG_STR_TABLE *table;
+/*     const CONFIG_STR_TABLE *table;
 /*
 /*     void    get_mail_conf_str_fn_table(table)
-/*     CONFIG_STR_TABLE *table;
+/*     const CONFIG_STR_TABLE *table;
 /* AUXILIARY FUNCTIONS
 /*     char    *get_mail_conf_str2(name, suffix, defval, min, max)
 /*     const char *name;
@@ -165,7 +165,7 @@ void    set_mail_conf_str(const char *name, const char *value)
 
 /* get_mail_conf_str_table - look up table of strings */
 
-void    get_mail_conf_str_table(CONFIG_STR_TABLE *table)
+void    get_mail_conf_str_table(const CONFIG_STR_TABLE *table)
 {
     while (table->name) {
        if (table->target[0])
@@ -178,7 +178,7 @@ void    get_mail_conf_str_table(CONFIG_STR_TABLE *table)
 
 /* get_mail_conf_str_fn_table - look up strings, defaults are functions */
 
-void    get_mail_conf_str_fn_table(CONFIG_STR_FN_TABLE *table)
+void    get_mail_conf_str_fn_table(const CONFIG_STR_FN_TABLE *table)
 {
     while (table->name) {
        if (table->target[0])
index 09926c76f0827e6bfe11bcf00d2f27be9e74ce0d..64523e9da04fc95522090b023610037df8130149 100644 (file)
@@ -21,7 +21,7 @@
 /*     int     value;
 /*
 /*     void    get_mail_conf_time_table(table)
-/*     CONFIG_TIME_TABLE *table;
+/*     const CONFIG_TIME_TABLE *table;
 /* AUXILIARY FUNCTIONS
 /*     int     get_mail_conf_time2(name1, name2, defval, def_unit, min, max);
 /*     const char *name1;
@@ -185,7 +185,7 @@ void    set_mail_conf_time_int(const char *name, int value)
 
 /* get_mail_conf_time_table - look up table of integers */
 
-void    get_mail_conf_time_table(CONFIG_TIME_TABLE *table)
+void    get_mail_conf_time_table(const CONFIG_TIME_TABLE *table)
 {
     while (table->name) {
        table->target[0] = get_mail_conf_time(table->name, table->defval,
@@ -208,7 +208,7 @@ int     main(int unused_argc, char **unused_argv)
     static int hours;
     static int days;
     static int weeks;
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        "seconds", "10s", &seconds, 0, 0,
        "minutes", "10m", &minutes, 0, 0,
        "hours", "10h", &hours, 0, 0,
index fab1db30436012b50cd63b7b98a2ebcd841128a5..35ecffb889f548862b475a3f75bde32ffa76e55d 100644 (file)
@@ -43,7 +43,7 @@ typedef struct {
     struct DICT *(*open) (const char *, int, int);
 } DICT_OPEN_INFO;
 
-static DICT_OPEN_INFO dict_open_info[] = {
+static const DICT_OPEN_INFO dict_open_info[] = {
     DICT_TYPE_PROXY, dict_proxy_open,
 #ifdef HAS_LDAP
     DICT_TYPE_LDAP, dict_ldap_open,
@@ -61,7 +61,7 @@ static DICT_OPEN_INFO dict_open_info[] = {
 
 void    mail_dict_init(void)
 {
-    DICT_OPEN_INFO *dp;
+    const DICT_OPEN_INFO *dp;
 
     for (dp = dict_open_info; dp->type; dp++)
        dict_open_register(dp->type, dp->open);
index 9355c051fe403001ddc6d9acdfa5dc059cafdd4d..8e9d40936a74baa4edf643f97ecbc2e3df89158e 100644 (file)
@@ -64,7 +64,7 @@
   * also contains a function that is being called explicitly. REF/DEF and all
   * that.
   */
-NAME_MASK mail_error_masks[] = {
+const NAME_MASK mail_error_masks[] = {
     "bounce", MAIL_ERROR_BOUNCE,
     "2bounce", MAIL_ERROR_2BOUNCE,
     "delay", MAIL_ERROR_DELAY,
index ffe7b3806cc5819af5b2c6e6982addb9de4e5f83..89aee07e43f3f9837dcb1cd95698415282100a7b 100644 (file)
@@ -27,7 +27,7 @@
 #define MAIL_ERROR_2BOUNCE     (1<<5)
 #define MAIL_ERROR_DELAY       (1<<6)
 
-extern NAME_MASK mail_error_masks[];
+extern const NAME_MASK mail_error_masks[];
 
 /* LICENSE
 /* .ad
index 54e48368f9b912aad7d4852857f85d194fe35485..2cb19631d619a6ddd51d63b58e37fd52bcb72b36 100644 (file)
@@ -487,17 +487,17 @@ static char *read_param_from_file(const char *path)
 
 void    mail_params_init()
 {
-    static CONFIG_STR_TABLE first_str_defaults[] = {
+    static const CONFIG_STR_TABLE first_str_defaults[] = {
        VAR_SYSLOG_FACILITY, DEF_SYSLOG_FACILITY, &var_syslog_facility, 1, 0,
        VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 1, 0,
        0,
     };
-    static CONFIG_STR_FN_TABLE function_str_defaults[] = {
+    static const CONFIG_STR_FN_TABLE function_str_defaults[] = {
        VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0,
        VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0,
        0,
     };
-    static CONFIG_STR_TABLE other_str_defaults[] = {
+    static const CONFIG_STR_TABLE other_str_defaults[] = {
        VAR_MAIL_NAME, DEF_MAIL_NAME, &var_mail_name, 1, 0,
        VAR_SYSLOG_NAME, DEF_SYSLOG_NAME, &var_syslog_name, 1, 0,
        VAR_MAIL_OWNER, DEF_MAIL_OWNER, &var_mail_owner, 1, 0,
@@ -544,11 +544,11 @@ void    mail_params_init()
        VAR_INT_FILT_CLASSES, DEF_INT_FILT_CLASSES, &var_int_filt_classes, 0, 0,
        0,
     };
-    static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
+    static const CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
        VAR_MYNETWORKS, mynetworks, &var_mynetworks, 0, 0,
        0,
     };
-    static CONFIG_INT_TABLE other_int_defaults[] = {
+    static const CONFIG_INT_TABLE other_int_defaults[] = {
        VAR_MAX_USE, DEF_MAX_USE, &var_use_limit, 1, 0,
        VAR_DONT_REMOVE, DEF_DONT_REMOVE, &var_dont_remove, 0, 0,
        VAR_LINE_LIMIT, DEF_LINE_LIMIT, &var_line_limit, 512, 0,
@@ -567,7 +567,7 @@ void    mail_params_init()
        VAR_DELAY_MAX_RES, DEF_DELAY_MAX_RES, &var_delay_max_res, MIN_DELAY_MAX_RES, MAX_DELAY_MAX_RES,
        0,
     };
-    static CONFIG_TIME_TABLE time_defaults[] = {
+    static const CONFIG_TIME_TABLE time_defaults[] = {
        VAR_EVENT_DRAIN, DEF_EVENT_DRAIN, &var_event_drain, 1, 0,
        VAR_MAX_IDLE, DEF_MAX_IDLE, &var_idle_limit, 1, 0,
        VAR_IPC_TIMEOUT, DEF_IPC_TIMEOUT, &var_ipc_timeout, 1, 0,
@@ -581,7 +581,7 @@ void    mail_params_init()
        VAR_IN_FLOW_DELAY, DEF_IN_FLOW_DELAY, &var_in_flow_delay, 0, 10,
        0,
     };
-    static CONFIG_BOOL_TABLE bool_defaults[] = {
+    static const CONFIG_BOOL_TABLE bool_defaults[] = {
        VAR_DISABLE_DNS, DEF_DISABLE_DNS, &var_disable_dns,
        VAR_SOFT_BOUNCE, DEF_SOFT_BOUNCE, &var_soft_bounce,
        VAR_OWNREQ_SPECIAL, DEF_OWNREQ_SPECIAL, &var_ownreq_special,
index 549ebc224e715121290013c2a682aba34680a80a..078d15b82c903dfdb67247ae5780a1f828cff013 100644 (file)
@@ -1162,7 +1162,7 @@ extern bool var_smtpd_tls_ask_ccert;
 extern bool var_smtpd_tls_req_ccert;
 
 #define VAR_SMTPD_TLS_CCERT_VD "smtpd_tls_ccert_verifydepth"
-#define DEF_SMTPD_TLS_CCERT_VD 5
+#define DEF_SMTPD_TLS_CCERT_VD 9
 extern int var_smtpd_tls_ccert_vd;
 
 #define VAR_SMTPD_TLS_CERT_FILE        "smtpd_tls_cert_file"
@@ -1205,6 +1205,10 @@ extern char *var_smtpd_tls_excl_ciph;
 #define DEF_SMTPD_TLS_MAND_EXCL  ""
 extern char *var_smtpd_tls_mand_excl;
 
+#define VAR_SMTPD_TLS_FPT_DGST "smtpd_tls_fingerprint_digest"
+#define DEF_SMTPD_TLS_FPT_DGST "md5"
+extern char *var_smtpd_tls_fpt_dgst;
+
 #define VAR_SMTPD_TLS_512_FILE "smtpd_tls_dh512_param_file"
 #define DEF_SMTPD_TLS_512_FILE ""
 extern char *var_smtpd_tls_dh512_param_file;
@@ -1268,9 +1272,9 @@ extern bool var_smtp_tls_enforce_peername;
 extern char *var_smtp_tls_level;
 
 #define VAR_SMTP_TLS_SCERT_VD  "smtp_tls_scert_verifydepth"
-#define DEF_SMTP_TLS_SCERT_VD  5
+#define DEF_SMTP_TLS_SCERT_VD  9
 #define VAR_LMTP_TLS_SCERT_VD  "lmtp_tls_scert_verifydepth"
-#define DEF_LMTP_TLS_SCERT_VD  5
+#define DEF_LMTP_TLS_SCERT_VD  9
 extern int var_smtp_tls_scert_vd;
 
 #define VAR_SMTP_TLS_CERT_FILE "smtp_tls_cert_file"
@@ -1327,6 +1331,12 @@ extern char *var_smtp_tls_excl_ciph;
 #define DEF_LMTP_TLS_MAND_EXCL  ""
 extern char *var_smtp_tls_mand_excl;
 
+#define VAR_SMTP_TLS_FPT_DGST  "smtp_tls_fingerprint_digest"
+#define DEF_SMTP_TLS_FPT_DGST  "md5"
+#define VAR_LMTP_TLS_FPT_DGST  "lmtp_tls_fingerprint_digest"
+#define DEF_LMTP_TLS_FPT_DGST  "md5"
+extern char *var_smtp_tls_fpt_dgst;
+
 #define VAR_SMTP_TLS_LOGLEVEL  "smtp_tls_loglevel"
 #define DEF_SMTP_TLS_LOGLEVEL  0
 #define VAR_LMTP_TLS_LOGLEVEL  "lmtp_tls_loglevel"
@@ -1382,6 +1392,12 @@ extern char *var_smtp_tls_vfy_cmatch;
 extern char *var_smtp_tls_sec_cmatch;
 
 
+#define VAR_SMTP_TLS_FPT_CMATCH "smtp_tls_fingerprint_cert_match"
+#define DEF_SMTP_TLS_FPT_CMATCH ""
+#define VAR_LMTP_TLS_FPT_CMATCH "lmtp_tls_fingerprint_cert_match"
+#define DEF_LMTP_TLS_FPT_CMATCH ""
+extern char *var_smtp_tls_fpt_cmatch;
+
  /*
   * SASL authentication support, SMTP server side.
   */
index 1d9229222faf63f1f301be311eff4fd885783f7c..d8e7ab37fbcc132ad80f6e3f6528b014b90ee0f1 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20080107"
+#define MAIL_RELEASE_DATE      "20080109"
 #define MAIL_VERSION_NUMBER    "2.5"
 
 #ifdef SNAPSHOT
index 1fc1276f8047e8397773ab1514b2d5d251b8a1a0..2856d86ab269293536346ef6f7b1ae037b03b50d 100644 (file)
@@ -67,7 +67,7 @@
   * though some systems do not use dotlock files by default (4.4BSD), such
   * locks can be necessary when accessing mailbox files over NFS.
   */
-static NAME_MASK mbox_mask[] = {
+static const NAME_MASK mbox_mask[] = {
 #ifdef HAS_FLOCK_LOCK
     "flock", MBOX_FLOCK_LOCK,
 #endif
@@ -89,7 +89,7 @@ int     mbox_lock_mask(const char *string)
 
 ARGV   *mbox_lock_names(void)
 {
-    NAME_MASK *np;
+    const NAME_MASK *np;
     ARGV   *argv;
 
     argv = argv_alloc(2);
index bea9e0ad4ec4f9b7b170632e7fa713f974716fd4..ac754c0a337e59ac095d52b79cd5502e5d2d42b0 100644 (file)
@@ -11,7 +11,7 @@
 /*                                      err_print, context)
 /*     int     flags;
 /*     void    (*head_out)(void *ptr, int header_class,
-/*                             HEADER_OPTS *header_info,
+/*                             const HEADER_OPTS *header_info,
 /*                             VSTRING *buf, off_t offset);
 /*     void    (*head_end)(void *ptr);
 /*     void    (*body_out)(void *ptr, int rec_type,
@@ -41,7 +41,7 @@
 /* .in -4
 /*     } MIME_STATE_DETAIL;
 /*
-/*     MIME_STATE_DETAIL *mime_state_detail(error_code)
+/*     const MIME_STATE_DETAIL *mime_state_detail(error_code)
 /*     int     error_code;
 /* DESCRIPTION
 /*     This module implements a one-pass MIME processor with optional
@@ -385,7 +385,7 @@ typedef struct MIME_ENCODING {
 #define MIME_ENC_BINARY                9       /* domain only */
 #endif
 
-static MIME_ENCODING mime_encoding_map[] = {   /* RFC 2045 */
+static const MIME_ENCODING mime_encoding_map[] = {     /* RFC 2045 */
     "7bit", MIME_ENC_7BIT, MIME_ENC_7BIT,      /* domain */
     "8bit", MIME_ENC_8BIT, MIME_ENC_8BIT,      /* domain */
     "binary", MIME_ENC_BINARY, MIME_ENC_BINARY,        /* domain */
@@ -539,7 +539,7 @@ MIME_STATE *mime_state_free(MIME_STATE *state)
 /* mime_state_content_type - process content-type header */
 
 static void mime_state_content_type(MIME_STATE *state,
-                                           HEADER_OPTS *header_info)
+                                           const HEADER_OPTS *header_info)
 {
     const char *cp;
     ssize_t tok_count;
@@ -650,10 +650,10 @@ static void mime_state_content_type(MIME_STATE *state,
 /* mime_state_content_encoding - process content-transfer-encoding header */
 
 static void mime_state_content_encoding(MIME_STATE *state,
-                                               HEADER_OPTS *header_info)
+                                            const HEADER_OPTS *header_info)
 {
     const char *cp;
-    MIME_ENCODING *cmp;
+    const MIME_ENCODING *cmp;
 
 #define PARSE_CONTENT_ENCODING_HEADER(state, ptr) \
     header_token(state->token, 1, state->token_buffer, ptr, (char *) 0, 0)
@@ -680,7 +680,7 @@ static void mime_state_content_encoding(MIME_STATE *state,
 
 static const char *mime_state_enc_name(int encoding)
 {
-    MIME_ENCODING *cmp;
+    const MIME_ENCODING *cmp;
 
     for (cmp = mime_encoding_map; cmp->name != 0; cmp++)
        if (encoding == cmp->encoding)
@@ -754,7 +754,7 @@ int     mime_state_update(MIME_STATE *state, int rec_type,
     int     input_is_text = (rec_type == REC_TYPE_NORM
                             || rec_type == REC_TYPE_CONT);
     MIME_STACK *sp;
-    HEADER_OPTS *header_info;
+    const HEADER_OPTS *header_info;
     const unsigned char *cp;
 
 #define SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type) do { \
@@ -1122,7 +1122,7 @@ int     mime_state_update(MIME_STATE *state, int rec_type,
   * must precede less serious errors, because the error-to-text conversion
   * can report only one error.
   */
-static MIME_STATE_DETAIL mime_err_detail[] = {
+static const MIME_STATE_DETAIL mime_err_detail[] = {
     MIME_ERR_NESTING, "5.6.0", "MIME nesting exceeds safety limit",
     MIME_ERR_TRUNC_HEADER, "5.6.0", "message header length exceeds safety limit",
     MIME_ERR_8BIT_IN_HEADER, "5.6.0", "improper use of 8-bit data in message header",
@@ -1135,7 +1135,7 @@ static MIME_STATE_DETAIL mime_err_detail[] = {
 
 const char *mime_state_error(int error_code)
 {
-    MIME_STATE_DETAIL *mp;
+    const MIME_STATE_DETAIL *mp;
 
     if (error_code == 0)
        msg_panic("mime_state_error: there is no error");
@@ -1147,9 +1147,9 @@ const char *mime_state_error(int error_code)
 
 /* mime_state_detail - error code to table entry with assorted data */
 
-MIME_STATE_DETAIL *mime_state_detail(int error_code)
+const MIME_STATE_DETAIL *mime_state_detail(int error_code)
 {
-    MIME_STATE_DETAIL *mp;
+    const MIME_STATE_DETAIL *mp;
 
     if (error_code == 0)
        msg_panic("mime_state_detail: there is no error");
@@ -1175,7 +1175,7 @@ MIME_STATE_DETAIL *mime_state_detail(int error_code)
 
 #define REC_LEN        1024
 
-static void head_out(void *context, int class, HEADER_OPTS *unused_info,
+static void head_out(void *context, int class, const HEADER_OPTS *unused_info,
                             VSTRING *buf, off_t offset)
 {
     VSTREAM *stream = (VSTREAM *) context;
index 35f5c827f0c2cf5301f4cb13f4a0db3fd5ac3d5b..88a4d7cf39ed68797aa9f6d35c62f926b8a1fe84 100644 (file)
@@ -25,7 +25,7 @@
   * External interface. All MIME_STATE structure members are private.
   */
 typedef struct MIME_STATE MIME_STATE;
-typedef void (*MIME_STATE_HEAD_OUT) (void *, int, HEADER_OPTS *, VSTRING *, off_t);
+typedef void (*MIME_STATE_HEAD_OUT) (void *, int, const HEADER_OPTS *, VSTRING *, off_t);
 typedef void (*MIME_STATE_BODY_OUT) (void *, int, const char *, ssize_t, off_t);
 typedef void (*MIME_STATE_ANY_END) (void *);
 typedef void (*MIME_STATE_ERR_PRINT) (void *, int, const char *, ssize_t);
@@ -69,7 +69,7 @@ typedef struct {
 #define MIME_ERR_8BIT_IN_7BIT_BODY     (1<<3)
 #define MIME_ERR_ENCODING_DOMAIN       (1<<4)
 
-extern MIME_STATE_DETAIL *mime_state_detail(int);
+extern const MIME_STATE_DETAIL *mime_state_detail(int);
 extern const char *mime_state_error(int);
 
  /*
index f96cd472efba7c1ccb3115e8df0ea39231194007..69a0d5727a987d9270de8bdef0135d0726a0e685 100644 (file)
 
  /*
   * Information about available database types. Here, we list only those map
-  * types that exist as files. Network-based maps are not of interest.
+  * types that support "create" operations.
+  * 
+  * We use a different table (in dict_open.c) when querying maps.
   */
 typedef struct {
     char   *type;
     MKMAP  *(*before_open) (const char *);
 } MKMAP_OPEN_INFO;
 
-MKMAP_OPEN_INFO mkmap_types[] = {
+static const MKMAP_OPEN_INFO mkmap_types[] = {
     DICT_TYPE_PROXY, mkmap_proxy_open,
 #ifdef HAS_CDB
     DICT_TYPE_CDB, mkmap_cdb_open,
@@ -147,7 +149,7 @@ MKMAP  *mkmap_open(const char *type, const char *path,
                           int open_flags, int dict_flags)
 {
     MKMAP  *mkmap;
-    MKMAP_OPEN_INFO *mp;
+    const MKMAP_OPEN_INFO *mp;
 
     /*
      * Find out what map type to use.
index 12192ca3b88b18b5ab676086758ca20dbecf1e3b..f2b9d5c228d3e3eb2c6d3969f5e6e2f821aa65f6 100644 (file)
@@ -73,7 +73,7 @@
 #define MASK_STYLE_SUBNET      (1 << 1)
 #define MASK_STYLE_HOST                (1 << 2)
 
-static NAME_MASK mask_styles[] = {
+static const NAME_MASK mask_styles[] = {
     MYNETWORKS_STYLE_CLASS, MASK_STYLE_CLASS,
     MYNETWORKS_STYLE_SUBNET, MASK_STYLE_SUBNET,
     MYNETWORKS_STYLE_HOST, MASK_STYLE_HOST,
index d305f79d0628c73871a2ec549a9fa2857e678525..ce3bad0a91ce613e000d519412fec3d6b0c425e3 100644 (file)
@@ -401,7 +401,7 @@ int     pipe_command(VSTREAM *src, DSN_BUF *why,...)
     char  **cpp;
     ARGV   *argv;
     DSN_SPLIT dp;
-    SYS_EXITS_DETAIL *sp;
+    const SYS_EXITS_DETAIL *sp;
 
     /*
      * Process the variadic argument list. This also does sanity checks on
index 09c1db22ef4a1701ebad4798bacbf75e9a43c1fd..bdd26b4403753a4fb5e68dfc759152e31fb63a82 100644 (file)
@@ -20,7 +20,7 @@
 /*     const char *sys_exits_strerror(code)
 /*     int     code;
 /*
-/*     SYS_EXITS_DETAIL *sys_exits_detail(code)
+/*     const SYS_EXITS_DETAIL *sys_exits_detail(code)
 /*     int     code;
 /*
 /*     int     sys_exits_softerror(code)
@@ -71,7 +71,7 @@
 
 /* Application-specific. */
 
-static SYS_EXITS_DETAIL sys_exits_table[] = {
+static const SYS_EXITS_DETAIL sys_exits_table[] = {
     EX_USAGE, "5.3.0", "command line usage error",
     EX_DATAERR, "5.6.0", "data format error",
     EX_NOINPUT, "5.3.0", "cannot open input",
@@ -120,7 +120,7 @@ const char *sys_exits_strerror(int code)
 
 /* sys_exits_detail - map exit status info table entry */
 
-SYS_EXITS_DETAIL *sys_exits_detail(int code)
+const SYS_EXITS_DETAIL *sys_exits_detail(int code)
 {
     if (!SYS_EXITS_CODE(code)) {
        return (sys_exits_fake(code));
index ee3b8ba32d8e6fe75643a4be32160a35f67ffc5a..bf4cce18e82966f109de56e0aaf8a3c328a03231 100644 (file)
@@ -21,7 +21,7 @@ typedef struct {
 } SYS_EXITS_DETAIL;
 
 extern const char *sys_exits_strerror(int);
-extern SYS_EXITS_DETAIL *sys_exits_detail(int);
+extern const SYS_EXITS_DETAIL *sys_exits_detail(int);
 extern int sys_exits_softerror(int);
 
 #define SYS_EXITS_CODE(n) ((n) >= EX__BASE && (n) <= EX__MAX)
index 6788fc80fa4edbadd99df01519636f77ed145e20..6300111afe92adff6b211947dc040162744b84f8 100644 (file)
@@ -757,19 +757,19 @@ static void local_service(VSTREAM *stream, char *service, char **argv)
 
 static void local_mask_init(void)
 {
-    static NAME_MASK file_mask[] = {
+    static const NAME_MASK file_mask[] = {
        "alias", EXPAND_TYPE_ALIAS,
        "forward", EXPAND_TYPE_FWD,
        "include", EXPAND_TYPE_INCL,
        0,
     };
-    static NAME_MASK command_mask[] = {
+    static const NAME_MASK command_mask[] = {
        "alias", EXPAND_TYPE_ALIAS,
        "forward", EXPAND_TYPE_FWD,
        "include", EXPAND_TYPE_INCL,
        0,
     };
-    static NAME_MASK deliver_mask[] = {
+    static const NAME_MASK deliver_mask[] = {
        "command", DELIVER_HDR_CMD,
        "file", DELIVER_HDR_FILE,
        "forward", DELIVER_HDR_FWD,
@@ -856,16 +856,16 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0,
        0,
     };
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
        VAR_MAILBOX_LIMIT, DEF_MAILBOX_LIMIT, &var_mailbox_limit, 0, 0,
        0,
     };
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0,
        VAR_HOME_MAILBOX, DEF_HOME_MAILBOX, &var_home_mailbox, 0, 0,
        VAR_ALLOW_COMMANDS, DEF_ALLOW_COMMANDS, &var_allow_commands, 0, 0,
@@ -885,7 +885,7 @@ int     main(int argc, char **argv)
        VAR_MAILBOX_CMD_MAPS, DEF_MAILBOX_CMD_MAPS, &var_mailbox_cmd_maps, 0, 0,
        0,
     };
-    static CONFIG_BOOL_TABLE bool_table[] = {
+    static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_BIFF, DEF_BIFF, &var_biff,
        VAR_EXP_OWN_ALIAS, DEF_EXP_OWN_ALIAS, &var_exp_own_alias,
        VAR_STAT_HOME_DIR, DEF_STAT_HOME_DIR, &var_stat_home_dir,
@@ -895,7 +895,7 @@ int     main(int argc, char **argv)
     };
 
     /* Suppress $name expansion upon loading. */
-    static CONFIG_RAW_TABLE raw_table[] = {
+    static const CONFIG_RAW_TABLE raw_table[] = {
        VAR_EXEC_DIRECTORY, DEF_EXEC_DIRECTORY, &var_exec_directory, 0, 0,
        VAR_FORWARD_PATH, DEF_FORWARD_PATH, &var_forward_path, 0, 0,
        VAR_MAILBOX_COMMAND, DEF_MAILBOX_COMMAND, &var_mailbox_command, 0, 0,
index f1dcdda4ff904c068aec0e9fc3d107717028c8ae..88dbb5622e5f236d49d0b90bf714efb762579b03 100644 (file)
@@ -75,9 +75,7 @@ typedef struct MASTER_SERV {
 #define MASTER_SERV_TYPE_UNIX  1       /* AF_UNIX domain socket */
 #define MASTER_SERV_TYPE_INET  2       /* AF_INET domain socket */
 #define MASTER_SERV_TYPE_FIFO  3       /* fifo (named pipe) */
-#ifdef SNAPSHOT                                /* see also master_proto.h */
 #define MASTER_SERV_TYPE_PASS  4       /* AF_UNIX domain socket */
-#endif
 
  /*
   * Default process management policy values. This is only the bare minimum.
index 50b9721775576a72caedd2b8532844d5720c7418..494d429f738675caab4b3c151e0388d9c365ed3c 100644 (file)
@@ -24,6 +24,7 @@
 /*     inet_listen(3), internet-domain listener
 /*     unix_listen(3), unix-domain listener
 /*     fifo_listen(3), named-pipe listener
+/*     upass_listen(3), file descriptor passing listener
 /*     set_eugid(3), set effective user/group attributes
 /* LICENSE
 /* .ad
index a017b5a2649e17dc1eeb9af3c40fe3b1733e91c5..bfa0e04c65df4eee0c92d30d574c83e447bd2896 100644 (file)
@@ -15,9 +15,7 @@
 #define MASTER_XPORT_NAME_UNIX "unix"  /* local IPC */
 #define MASTER_XPORT_NAME_FIFO "fifo"  /* local IPC */
 #define MASTER_XPORT_NAME_INET "inet"  /* non-local IPC */
-#ifdef SNAPSHOT                                /* see also master.h */
 #define MASTER_XPORT_NAME_PASS "pass"  /* local IPC */
-#endif
 
  /*
   * Format of a status message sent by a child process to the process
index 33869b8c8df690a1a8a77285ded15f18ce5e0c02..1457d6b4b4ac243dda74a3ac948d323a7b4fd11b 100644 (file)
@@ -55,15 +55,15 @@ int     var_throttle_time;
 void    master_vars_init(void)
 {
     char   *path;
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 1, 0,
        0,
     };
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
        0,
     };
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_THROTTLE_TIME, DEF_THROTTLE_TIME, &var_throttle_time, 1, 0,
        0,
     };
index 306514ede4c8ebb82bf0c7de7e82377d47a86dae..ee6062023a3782e16fd358396b019032fe1664da 100644 (file)
@@ -36,6 +36,7 @@
 /*     inet_trigger(3), internet-domain client
 /*     unix_trigger(3), unix-domain client
 /*     fifo_trigger(3), fifo client
+/*     upass_trigger(3), file descriptor passing client
 /* LICENSE
 /* .ad
 /* .fi
index 37ce0060b9a66257cb942e2810d445f8b56a684e..6247b601afb218de59a9c3eb24449112954ffa98 100644 (file)
@@ -2167,7 +2167,7 @@ typedef struct {
 /* milter8_header - milter8_message call-back for message header */
 
 static void milter8_header(void *ptr, int unused_header_class,
-                                  HEADER_OPTS *header_info,
+                                  const HEADER_OPTS *header_info,
                                   VSTRING *buf, off_t unused_offset)
 {
     const char *myname = "milter8_header";
@@ -2387,7 +2387,7 @@ static const char *milter8_message(MILTER *m, VSTREAM *qfile,
     MILTER8 *milter = (MILTER8 *) m;
     MIME_STATE *mime_state;
     int     rec_type;
-    MIME_STATE_DETAIL *detail;
+    const MIME_STATE_DETAIL *detail;
     int     mime_errs = 0;
     MILTER_MSG_CONTEXT msg_ctx;
     VSTRING *buf;
index 875ae625f871fd922e17bedd80248227f3c278d5..d895cc78de04e4ad05bac4fa805d96801c8cb94d 100644 (file)
@@ -597,13 +597,13 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_DEFER_XPORTS, DEF_DEFER_XPORTS, &var_defer_xports, 0, 0,
        VAR_CONC_POS_FDBACK, DEF_CONC_POS_FDBACK, &var_conc_pos_feedback, 1, 0,
        VAR_CONC_NEG_FDBACK, DEF_CONC_NEG_FDBACK, &var_conc_neg_feedback, 1, 0,
        0,
     };
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0,
        VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0,
        VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
@@ -614,7 +614,7 @@ int     main(int argc, char **argv)
        VAR_DEST_RATE_DELAY, DEF_DEST_RATE_DELAY, &var_dest_rate_delay, 0, 0,
        0,
     };
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_QMGR_ACT_LIMIT, DEF_QMGR_ACT_LIMIT, &var_qmgr_active_limit, 1, 0,
        VAR_QMGR_RCPT_LIMIT, DEF_QMGR_RCPT_LIMIT, &var_qmgr_rcpt_limit, 1, 0,
        VAR_INIT_DEST_CON, DEF_INIT_DEST_CON, &var_init_dest_concurrency, 1, 0,
@@ -627,7 +627,7 @@ int     main(int argc, char **argv)
        VAR_CONC_COHORT_LIM, DEF_CONC_COHORT_LIM, &var_conc_cohort_limit, 0, 0,
        0,
     };
-    static CONFIG_BOOL_TABLE bool_table[] = {
+    static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off,
        VAR_CONC_FDBACK_DEBUG, DEF_CONC_FDBACK_DEBUG, &var_conc_feedback_debug,
        0,
index 6d62a6ed2e99bf60cc4dc318b7448484c107865a..f341b9591d3b77d65472f4b669ac7feedd87638d 100644 (file)
@@ -90,7 +90,7 @@
  /*
   * Lookup tables for main.cf feedback method names.
   */
-NAME_CODE qmgr_feedback_map[] = {
+const NAME_CODE qmgr_feedback_map[] = {
     CONC_FDBACK_NAME_WIN, QMGR_FEEDBACK_IDX_WIN,
 #ifdef QMGR_FEEDBACK_IDX_SQRT_WIN
     CONC_FDBACK_NAME_SQRT_WIN, QMGR_FEEDBACK_IDX_SQRT_WIN,
index 153f36326fdac97cec5ed3c8abd87c6613be5a3a..5262818261a6683b7ad834f31b5fbdcc72a96963 100644 (file)
@@ -577,7 +577,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
        VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0,
        0,
index 1a699c126c56137ffc0152ef3ee56d6cfa26d9d1..13a0da53f0b4671bbe3e4385f2ea425fb117a567 100644 (file)
@@ -1311,7 +1311,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0,
        0,
     };
index 77cd7440fcfda02e8c0d7e7fbae65e3dd57f5d23..8619c3f038ca1def05a66c69df7d366db2531bc9 100644 (file)
@@ -13,7 +13,7 @@
 # or lower/upper bounds still result in "postconf -d" duplicates,
 # which are a sign of an error somewhere...
 
-/^(static| )*CONFIG_INT_TABLE .*\{/,/\};/ { 
+/^(static| )*(const +)?CONFIG_INT_TABLE .*\{/,/\};/ { 
     if ($1 ~ /VAR/) {
        print "int " substr($3,2,length($3)-2) ";" > "int_vars.h"
        if (++itab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
@@ -21,7 +21,7 @@
        }
     }
 }
-/^(static| )*CONFIG_STR_TABLE .*\{/,/\};/ { 
+/^(static| )*(const +)?CONFIG_STR_TABLE .*\{/,/\};/ { 
     if ($1 ~ /^VAR/) {
        print "char *" substr($3,2,length($3)-2) ";" > "str_vars.h"
        if (++stab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
@@ -29,7 +29,7 @@
        }
     }
 }
-/^(static| )*CONFIG_RAW_TABLE .*\{/,/\};/ { 
+/^(static| )*(const +)?CONFIG_RAW_TABLE .*\{/,/\};/ { 
     if ($1 ~ /^VAR/) {
        print "char *" substr($3,2,length($3)-2) ";" > "raw_vars.h"
        if (++rtab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
@@ -37,7 +37,7 @@
        }
     }
 }
-/^(static| )*CONFIG_BOOL_TABLE .*\{/,/\};/ { 
+/^(static| )*(const +)?CONFIG_BOOL_TABLE .*\{/,/\};/ { 
     if ($1 ~ /^VAR/) {
        print "int " substr($3,2,length($3)-2) ";" > "bool_vars.h"
        if (++btab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
@@ -45,7 +45,7 @@
        }
     }
 }
-/^(static| )*CONFIG_TIME_TABLE .*\{/,/\};/ { 
+/^(static| )*(const +)?CONFIG_TIME_TABLE .*\{/,/\};/ { 
     if ($1 ~ /^VAR/) {
        print "int " substr($3,2,length($3)-2) ";" > "time_vars.h"
        if (++ttab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
index bb88fcd646403f3e2bf13bfb02850110b3ff4edd..329a5ff1dce8112ceb73d66e284b753a99fb30ef 100644 (file)
@@ -311,29 +311,29 @@ DICT   *text_table;
  /*
   * Lookup tables generated by scanning actual C source files.
   */
-static CONFIG_TIME_TABLE time_table[] = {
+static const CONFIG_TIME_TABLE time_table[] = {
 #include "time_table.h"
     0,
 };
 
-static CONFIG_BOOL_TABLE bool_table[] = {
+static const CONFIG_BOOL_TABLE bool_table[] = {
 #include "bool_table.h"
     0,
 };
 
-static CONFIG_INT_TABLE int_table[] = {
+static const CONFIG_INT_TABLE int_table[] = {
 #include "int_table.h"
     0,
 };
 
-static CONFIG_STR_TABLE str_table[] = {
+static const CONFIG_STR_TABLE str_table[] = {
 #include "str_table.h"
 #include "auto_table.h"                        /* XXX */
 #include "install_table.h"
     0,
 };
 
-static CONFIG_RAW_TABLE raw_table[] = {
+static const CONFIG_RAW_TABLE raw_table[] = {
 #include "raw_table.h"
     0,
 };
@@ -349,12 +349,12 @@ static const char *check_myhostname(void);
 static const char *check_mydomainname(void);
 static const char *check_mynetworks(void);
 
-static CONFIG_STR_FN_TABLE str_fn_table[] = {
+static const CONFIG_STR_FN_TABLE str_fn_table[] = {
     VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0,
     VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0,
     0,
 };
-static CONFIG_STR_FN_TABLE str_fn_table_2[] = {
+static const CONFIG_STR_FN_TABLE str_fn_table_2[] = {
     VAR_MYNETWORKS, check_mynetworks, &var_mynetworks, 1, 0,
     0,
 };
@@ -634,12 +634,12 @@ static void set_parameters(void)
 
 static void hash_parameters(void)
 {
-    CONFIG_TIME_TABLE *ctt;
-    CONFIG_BOOL_TABLE *cbt;
-    CONFIG_INT_TABLE *cit;
-    CONFIG_STR_TABLE *cst;
-    CONFIG_STR_FN_TABLE *csft;
-    CONFIG_RAW_TABLE *rst;
+    const CONFIG_TIME_TABLE *ctt;
+    const CONFIG_BOOL_TABLE *cbt;
+    const CONFIG_INT_TABLE *cit;
+    const CONFIG_STR_TABLE *cst;
+    const CONFIG_STR_FN_TABLE *csft;
+    const CONFIG_RAW_TABLE *rst;
 
     param_table = htable_create(100);
 
index 92170708fe59f4442d32db923f99ec00872d6b76..630bdb300ce440ac987ba8faebc0a9fd9c90bd70 100644 (file)
   */
 char   *var_submit_acl;
 
-static CONFIG_STR_TABLE str_table[] = {
+static const CONFIG_STR_TABLE str_table[] = {
     VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0,
     0,
 };
index 132aedd6f462aef1fde0f0a290d8885856d6b704..13eb9a6817fe8ad08ba70d007e80dfe95790140b 100644 (file)
@@ -337,7 +337,7 @@ int     main(int argc, char **argv)
     int     fd;
     int     ch;
     ARGV   *import_env;
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_SENDMAIL_PATH, DEF_SENDMAIL_PATH, &var_sendmail_path, 1, 0,
        VAR_MAILQ_PATH, DEF_MAILQ_PATH, &var_mailq_path, 1, 0,
        VAR_NEWALIAS_PATH, DEF_NEWALIAS_PATH, &var_newalias_path, 1, 0,
index dad7b592be6827425c17c504e4569c7b694cf8f6..7ced31f05703e9441e4c2315d470613e9605a88b 100644 (file)
 char   *var_flush_acl;
 char   *var_showq_acl;
 
-static CONFIG_STR_TABLE str_table[] = {
+static const CONFIG_STR_TABLE str_table[] = {
     VAR_FLUSH_ACL, DEF_FLUSH_ACL, &var_flush_acl, 0, 0,
     VAR_SHOWQ_ACL, DEF_SHOWQ_ACL, &var_showq_acl, 0, 0,
     0,
index 481510a8da7179b46a63387e8995f1078efa72ec..937f370df70ab81d56f770e01a716e69663d65fd 100644 (file)
@@ -622,7 +622,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
        VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
        VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
index 99d0c6425941af66618e3263bac8bd9a529bebbb..b3da982b10e72343507cc2651500236168906874 100644 (file)
@@ -664,13 +664,13 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_DEFER_XPORTS, DEF_DEFER_XPORTS, &var_defer_xports, 0, 0,
        VAR_CONC_POS_FDBACK, DEF_CONC_POS_FDBACK, &var_conc_pos_feedback, 1, 0,
        VAR_CONC_NEG_FDBACK, DEF_CONC_NEG_FDBACK, &var_conc_neg_feedback, 1, 0,
        0,
     };
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0,
        VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0,
        VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
@@ -682,7 +682,7 @@ int     main(int argc, char **argv)
        VAR_DEST_RATE_DELAY, DEF_DEST_RATE_DELAY, &var_dest_rate_delay, 0, 0,
        0,
     };
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_QMGR_ACT_LIMIT, DEF_QMGR_ACT_LIMIT, &var_qmgr_active_limit, 1, 0,
        VAR_QMGR_RCPT_LIMIT, DEF_QMGR_RCPT_LIMIT, &var_qmgr_rcpt_limit, 1, 0,
        VAR_QMGR_MSG_RCPT_LIMIT, DEF_QMGR_MSG_RCPT_LIMIT, &var_qmgr_msg_rcpt_limit, 1, 0,
@@ -702,7 +702,7 @@ int     main(int argc, char **argv)
        VAR_CONC_COHORT_LIM, DEF_CONC_COHORT_LIM, &var_conc_cohort_limit, 0, 0,
        0,
     };
-    static CONFIG_BOOL_TABLE bool_table[] = {
+    static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off,
        VAR_CONC_FDBACK_DEBUG, DEF_CONC_FDBACK_DEBUG, &var_conc_feedback_debug,
        0,
index 6d62a6ed2e99bf60cc4dc318b7448484c107865a..f341b9591d3b77d65472f4b669ac7feedd87638d 100644 (file)
@@ -90,7 +90,7 @@
  /*
   * Lookup tables for main.cf feedback method names.
   */
-NAME_CODE qmgr_feedback_map[] = {
+const NAME_CODE qmgr_feedback_map[] = {
     CONC_FDBACK_NAME_WIN, QMGR_FEEDBACK_IDX_WIN,
 #ifdef QMGR_FEEDBACK_IDX_SQRT_WIN
     CONC_FDBACK_NAME_SQRT_WIN, QMGR_FEEDBACK_IDX_SQRT_WIN,
index dab3b09dcc1895a0f4342c2a9bf431076ee1c1be..a6b5e66f47d3c3a4a27f798ff0e8989412c85549 100644 (file)
@@ -775,18 +775,18 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_QMTPD_TMOUT, DEF_QMTPD_TMOUT, &var_qmqpd_timeout, 1, 0,
        VAR_QMTPD_ERR_SLEEP, DEF_QMTPD_ERR_SLEEP, &var_qmqpd_err_sleep, 0, 0,
        0,
     };
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
        VAR_QMQPD_CLIENTS, DEF_QMQPD_CLIENTS, &var_qmqpd_clients, 0, 0,
        VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0,
        0,
     };
-    static CONFIG_BOOL_TABLE bool_table[] = {
+    static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_QMQPD_CLIENT_PORT_LOG, DEF_QMQPD_CLIENT_PORT_LOG, &var_qmqpd_client_port_log,
        0,
     };
index f75ec306a374120140231016fae3c16fc8edb17d..6a4164ef6bd6c9e58b8970b5f9f95bc3d92bf1ff 100644 (file)
@@ -539,7 +539,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_SCACHE_TTL_LIM, DEF_SCACHE_TTL_LIM, &var_scache_ttl_lim, 1, 0,
        VAR_SCACHE_STAT_TIME, DEF_SCACHE_STAT_TIME, &var_scache_stat_time, 1, 0,
        0,
index e2da158ba9cbc62e6db7fb078ffa47c4e3101b52..7c1d6e805ca31914c4c17ce9d4634115012f450e 100644 (file)
@@ -483,7 +483,7 @@ typedef struct SM_STATE {
   */
 char   *var_submit_acl;
 
-static CONFIG_STR_TABLE str_table[] = {
+static const CONFIG_STR_TABLE str_table[] = {
     VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0,
     0,
 };
@@ -509,7 +509,7 @@ static void output_text(void *context, int rec_type, const char *buf, ssize_t le
 /* output_header - output one message header */
 
 static void output_header(void *context, int header_class,
-                                 HEADER_OPTS *header_info,
+                                 const HEADER_OPTS *header_info,
                                  VSTRING *buf, off_t offset)
 {
     SM_STATE *state = (SM_STATE *) context;
index 613f333e789ae2534045bdba13fed9bf9a63bfca..73517a60e7e60a03d76f95c6f0331617eb8d9ddc 100644 (file)
@@ -398,7 +398,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
        0,
     };
index 0ebb292b3300dce835ee731bd4a6e8fefe3e034f..7ab5241e9e9fb87a2e8745574bdcb4358fdee4cd 100644 (file)
@@ -1,4 +1,4 @@
-    static CONFIG_STR_TABLE lmtp_str_table[] = {
+    static const CONFIG_STR_TABLE lmtp_str_table[] = {
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
        VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0,
        VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
        VAR_LMTP_TLS_MAND_CIPH, DEF_LMTP_TLS_MAND_CIPH, &var_smtp_tls_mand_ciph, 1, 0,
        VAR_LMTP_TLS_EXCL_CIPH, DEF_LMTP_TLS_EXCL_CIPH, &var_smtp_tls_excl_ciph, 0, 0,
        VAR_LMTP_TLS_MAND_EXCL, DEF_LMTP_TLS_MAND_EXCL, &var_smtp_tls_mand_excl, 0, 0,
-       VAR_TLS_HIGH_CLIST, DEF_TLS_HIGH_CLIST, &var_tls_high_clist, 1, 0,
-       VAR_TLS_MEDIUM_CLIST, DEF_TLS_MEDIUM_CLIST, &var_tls_medium_clist, 1, 0,
-       VAR_TLS_LOW_CLIST, DEF_TLS_LOW_CLIST, &var_tls_low_clist, 1, 0,
-       VAR_TLS_EXPORT_CLIST, DEF_TLS_EXPORT_CLIST, &var_tls_export_clist, 1, 0,
-       VAR_TLS_NULL_CLIST, DEF_TLS_NULL_CLIST, &var_tls_null_clist, 1, 0,
        VAR_LMTP_TLS_MAND_PROTO, DEF_LMTP_TLS_MAND_PROTO, &var_smtp_tls_mand_proto, 0, 0,
        VAR_LMTP_TLS_VFY_CMATCH, DEF_LMTP_TLS_VFY_CMATCH, &var_smtp_tls_vfy_cmatch, 1, 0,
        VAR_LMTP_TLS_SEC_CMATCH, DEF_LMTP_TLS_SEC_CMATCH, &var_smtp_tls_sec_cmatch, 1, 0,
+       VAR_LMTP_TLS_FPT_CMATCH, DEF_LMTP_TLS_FPT_CMATCH, &var_smtp_tls_fpt_cmatch, 0, 0,
+       VAR_LMTP_TLS_FPT_DGST, DEF_LMTP_TLS_FPT_DGST, &var_smtp_tls_fpt_dgst, 1, 0,
 #endif
        VAR_LMTP_SASL_MECHS, DEF_LMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
        VAR_LMTP_SASL_TYPE, DEF_LMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
@@ -53,7 +50,7 @@
        VAR_LMTP_BODY_CHKS, DEF_LMTP_BODY_CHKS, &var_smtp_body_chks, 0, 0,
        0,
     };
-    static CONFIG_TIME_TABLE lmtp_time_table[] = {
+    static const CONFIG_TIME_TABLE lmtp_time_table[] = {
        VAR_LMTP_CONN_TMOUT, DEF_LMTP_CONN_TMOUT, &var_smtp_conn_tmout, 0, 0,
        VAR_LMTP_HELO_TMOUT, DEF_LMTP_HELO_TMOUT, &var_smtp_helo_tmout, 1, 0,
        VAR_LMTP_XFWD_TMOUT, DEF_LMTP_XFWD_TMOUT, &var_smtp_xfwd_tmout, 1, 0,
        VAR_SCACHE_PROTO_TMOUT, DEF_SCACHE_PROTO_TMOUT, &var_scache_proto_tmout, 1, 0,
        0,
     };
-    static CONFIG_INT_TABLE lmtp_int_table[] = {
+    static const CONFIG_INT_TABLE lmtp_int_table[] = {
        VAR_LMTP_LINE_LIMIT, DEF_LMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
        VAR_LMTP_MXADDR_LIMIT, DEF_LMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
        VAR_LMTP_MXSESS_LIMIT, DEF_LMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
 #ifdef USE_TLS
        VAR_LMTP_TLS_SCERT_VD, DEF_LMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
        VAR_LMTP_TLS_LOGLEVEL, DEF_LMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0,
-       VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 1, 0,
 #endif
        0,
     };
-    static CONFIG_BOOL_TABLE lmtp_bool_table[] = {
+    static const CONFIG_BOOL_TABLE lmtp_bool_table[] = {
        VAR_LMTP_SKIP_5XX, DEF_LMTP_SKIP_5XX, &var_smtp_skip_5xx_greeting,
        VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
        VAR_LMTP_SASL_ENABLE, DEF_LMTP_SASL_ENABLE, &var_smtp_sasl_enable,
index 356967c7ce0e88d39472092e5c279c0d8156c53d..963256c96950e6ce4458519049ed0fbd2a4a4189 100644 (file)
 /*     policy by next-hop destination; when a non-empty value is specified,
 /*     this overrides the obsolete smtp_tls_per_site parameter.
 /* .IP "\fBsmtp_tls_mandatory_protocols (SSLv3, TLSv1)\fR"
-/*     List of TLS protocols that the Postfix SMTP client will use
-/*     with mandatory TLS encryption.
-/* .IP "\fBsmtp_tls_scert_verifydepth (5)\fR"
+/*     List of SSL/TLS protocols that the Postfix SMTP client will use with
+/*     mandatory TLS encryption.
+/* .IP "\fBsmtp_tls_scert_verifydepth (9)\fR"
 /*     The verification depth for remote SMTP server certificates.
 /* .IP "\fBsmtp_tls_secure_cert_match (nexthop, dot-nexthop)\fR"
 /*     The server certificate peername verification method for the
 /*     The SASL authentication security options that the Postfix SMTP
 /*     client uses for TLS encrypted SMTP sessions with a verified server
 /*     certificate.
+/* .PP
+/*     Available in Postfix version 2.5 and later:
+/* .IP "\fBsmtp_tls_fingerprint_cert_match (empty)\fR"
+/*     List of acceptable remote SMTP server certificate fingerprints
+/*     for the "fingerprint" TLS security level (\fBsmtp_tls_security_level\fR =
+/*     fingerprint).
+/* .IP "\fBsmtp_tls_fingerprint_digest (md5)\fR"
+/*     The message digest algorithm used to construct remote SMTP server
+/*     certificate fingerprints.
 /* OBSOLETE STARTTLS CONTROLS
 /* .ad
 /* .fi
 /*     SuSE Rhein/Main AG
 /*     65760 Eschborn, Germany
 /*
-/*     Connection caching in cooperation with:
-/*     Victor Duchovni
-/*     Morgan Stanley
-/*
 /*     TLS support originally by:
 /*     Lutz Jaenicke
 /*     BTU Cottbus
 /*     Allgemeine Elektrotechnik
 /*     Universitaetsplatz 3-4
 /*     D-03044 Cottbus, Germany
+/*
+/*     Revised TLS and SMTP connection cache support by:
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
@@ -721,7 +730,8 @@ char   *var_smtp_tls_mand_proto;
 char   *var_smtp_tls_sec_cmatch;
 int     var_smtp_tls_scert_vd;
 char   *var_smtp_tls_vfy_cmatch;
-int     var_tls_daemon_rand_bytes;
+char   *var_smtp_tls_fpt_cmatch;
+char   *var_smtp_tls_fpt_dgst;
 
 #endif
 
@@ -755,9 +765,9 @@ HBC_CHECKS *smtp_body_checks;               /* limited body checks */
 #ifdef USE_TLS
 
  /*
-  * OpenSSL client state.
+  * OpenSSL client state (opaque handle)
   */
-SSL_CTX *smtp_tls_ctx;
+TLS_APPL_STATE *smtp_tls_ctx;
 
 #endif
 
@@ -839,7 +849,7 @@ static void smtp_service(VSTREAM *client_stream, char *service, char **argv)
 
 static void post_init(char *unused_name, char **unused_argv)
 {
-    static NAME_MASK lookup_masks[] = {
+    static const NAME_MASK lookup_masks[] = {
        SMTP_HOST_LOOKUP_DNS, SMTP_HOST_FLAG_DNS,
        SMTP_HOST_LOOKUP_NATIVE, SMTP_HOST_FLAG_NATIVE,
        0,
@@ -894,34 +904,55 @@ static void pre_init(char *unused_name, char **unused_argv)
                 VAR_SMTP_SASL_ENABLE);
 #endif
 
-    if (*var_smtp_tls_level)
-       use_tls = tls_level_lookup(var_smtp_tls_level) > TLS_LEV_NONE;
-    else
-       use_tls = var_smtp_enforce_tls || var_smtp_use_tls;
+    if (*var_smtp_tls_level != 0)
+       switch (tls_level_lookup(var_smtp_tls_level)) {
+       case TLS_LEV_SECURE:
+       case TLS_LEV_VERIFY:
+       case TLS_LEV_FPRINT:
+       case TLS_LEV_ENCRYPT:
+           var_smtp_use_tls = var_smtp_enforce_tls = 1;
+           break;
+       case TLS_LEV_MAY:
+           var_smtp_use_tls = 1;
+           var_smtp_enforce_tls = 0;
+           break;
+       case TLS_LEV_NONE:
+           var_smtp_use_tls = var_smtp_enforce_tls = 0;
+           break;
+       default:
+           /* tls_level_lookup() logs no warning. */
+           /* session_tls_init() assumes that var_smtp_tls_level is sane. */
+           msg_fatal("Invalid TLS level \"%s\"", var_smtp_tls_level);
+       }
+    use_tls = (var_smtp_use_tls || var_smtp_enforce_tls);
 
     /*
      * Initialize the TLS data before entering the chroot jail
      */
     if (use_tls || var_smtp_tls_per_site[0] || var_smtp_tls_policy[0]) {
 #ifdef USE_TLS
-       tls_client_init_props props;
+       TLS_CLIENT_INIT_PROPS props;
 
        /*
         * We get stronger type safety and a cleaner interface by combining
         * the various parameters into a single tls_client_props structure.
+        * 
+        * Large parameter lists are error-prone, so we emulate a language
+        * feature that C does not have natively: named parameter lists.
         */
-       props.log_level = var_smtp_tls_loglevel;
-       props.verifydepth = var_smtp_tls_scert_vd;
-       props.cache_type = strcmp(var_procname, "smtp") == 0 ?
-           TLS_MGR_SCACHE_SMTP : TLS_MGR_SCACHE_LMTP;
-       props.cert_file = var_smtp_tls_cert_file;
-       props.key_file = var_smtp_tls_key_file;
-       props.dcert_file = var_smtp_tls_dcert_file;
-       props.dkey_file = var_smtp_tls_dkey_file;
-       props.CAfile = var_smtp_tls_CAfile;
-       props.CApath = var_smtp_tls_CApath;
-
-       smtp_tls_ctx = tls_client_init(&props);
+       smtp_tls_ctx =
+           TLS_CLIENT_INIT(&props,
+                           log_level = var_smtp_tls_loglevel,
+                           verifydepth = var_smtp_tls_scert_vd,
+                           cache_type = strcmp(var_procname, "smtp") == 0 ?
+                           TLS_MGR_SCACHE_SMTP : TLS_MGR_SCACHE_LMTP,
+                           cert_file = var_smtp_tls_cert_file,
+                           key_file = var_smtp_tls_key_file,
+                           dcert_file = var_smtp_tls_dcert_file,
+                           dkey_file = var_smtp_tls_dkey_file,
+                           CAfile = var_smtp_tls_CAfile,
+                           CApath = var_smtp_tls_CApath,
+                           fpt_dgst = var_smtp_tls_fpt_dgst);
        smtp_tls_list_init();
 #else
        msg_warn("TLS has been selected, but TLS support is not compiled in");
index 259d32ea92ff84e24cd05f17ff21820a0f5470c4..da3f3034b565fb58f416762c8a90486f20bb484e 100644 (file)
@@ -177,7 +177,7 @@ extern int smtp_ext_prop_mask;              /* address externsion propagation */
 
 #ifdef USE_TLS
 
-extern SSL_CTX *smtp_tls_ctx;          /* client-side TLS engine */
+extern TLS_APPL_STATE *smtp_tls_ctx;   /* client-side TLS engine */
 
 #endif
 
@@ -227,13 +227,14 @@ typedef struct SMTP_SESSION {
      * TLS related state, don't forget to initialize in session_tls_init()!
      */
 #ifdef USE_TLS
-    TLScontext_t *tls_context;         /* TLS session state */
+    TLS_SESS_STATE *tls_context;       /* TLS session state */
     char   *tls_nexthop;               /* Nexthop domain for cert checks */
     int     tls_level;                 /* TLS enforcement level */
     int     tls_retry_plain;           /* Try plain when TLS handshake fails */
-    int     tls_protocols;             /* Acceptable SSL protocols (mask) */
-    char   *tls_cipherlist;            /* Acceptable SSL ciphers */
-    char   *tls_certmatch;             /* Certificate match patterns */
+    char   *tls_protocols;             /* Acceptable SSL protocols */
+    char   *tls_grade;                 /* Cipher grade: "export", ... */
+    VSTRING *tls_exclusions;           /* Excluded SSL ciphers */
+    ARGV   *tls_matchargv;             /* Cert match patterns */
 #endif
 
     SMTP_STATE *state;                 /* back link */
index 947f5299c824a78e52b7ae02abc1995e9d119cbf..e8e7887e9c37f354ff9a4f12e10b50515adf987e 100644 (file)
@@ -1,4 +1,4 @@
-    static CONFIG_STR_TABLE smtp_str_table[] = {
+    static const CONFIG_STR_TABLE smtp_str_table[] = {
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
        VAR_SMTP_FALLBACK, DEF_SMTP_FALLBACK, &var_fallback_relay, 0, 0,
        VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0,
        VAR_SMTP_TLS_MAND_CIPH, DEF_SMTP_TLS_MAND_CIPH, &var_smtp_tls_mand_ciph, 1, 0,
        VAR_SMTP_TLS_EXCL_CIPH, DEF_SMTP_TLS_EXCL_CIPH, &var_smtp_tls_excl_ciph, 0, 0,
        VAR_SMTP_TLS_MAND_EXCL, DEF_SMTP_TLS_MAND_EXCL, &var_smtp_tls_mand_excl, 0, 0,
-       VAR_TLS_HIGH_CLIST, DEF_TLS_HIGH_CLIST, &var_tls_high_clist, 1, 0,
-       VAR_TLS_MEDIUM_CLIST, DEF_TLS_MEDIUM_CLIST, &var_tls_medium_clist, 1, 0,
-       VAR_TLS_LOW_CLIST, DEF_TLS_LOW_CLIST, &var_tls_low_clist, 1, 0,
-       VAR_TLS_EXPORT_CLIST, DEF_TLS_EXPORT_CLIST, &var_tls_export_clist, 1, 0,
-       VAR_TLS_NULL_CLIST, DEF_TLS_NULL_CLIST, &var_tls_null_clist, 1, 0,
        VAR_SMTP_TLS_MAND_PROTO, DEF_SMTP_TLS_MAND_PROTO, &var_smtp_tls_mand_proto, 0, 0,
        VAR_SMTP_TLS_VFY_CMATCH, DEF_SMTP_TLS_VFY_CMATCH, &var_smtp_tls_vfy_cmatch, 1, 0,
        VAR_SMTP_TLS_SEC_CMATCH, DEF_SMTP_TLS_SEC_CMATCH, &var_smtp_tls_sec_cmatch, 1, 0,
+       VAR_SMTP_TLS_FPT_CMATCH, DEF_SMTP_TLS_FPT_CMATCH, &var_smtp_tls_fpt_cmatch, 0, 0,
+       VAR_SMTP_TLS_FPT_DGST, DEF_SMTP_TLS_FPT_DGST, &var_smtp_tls_fpt_dgst, 1, 0,
 #endif
        VAR_SMTP_SASL_MECHS, DEF_SMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
        VAR_SMTP_SASL_TYPE, DEF_SMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
@@ -54,7 +51,7 @@
        VAR_SMTP_BODY_CHKS, DEF_SMTP_BODY_CHKS, &var_smtp_body_chks, 0, 0,
        0,
     };
-    static CONFIG_TIME_TABLE smtp_time_table[] = {
+    static const CONFIG_TIME_TABLE smtp_time_table[] = {
        VAR_SMTP_CONN_TMOUT, DEF_SMTP_CONN_TMOUT, &var_smtp_conn_tmout, 0, 0,
        VAR_SMTP_HELO_TMOUT, DEF_SMTP_HELO_TMOUT, &var_smtp_helo_tmout, 1, 0,
        VAR_SMTP_XFWD_TMOUT, DEF_SMTP_XFWD_TMOUT, &var_smtp_xfwd_tmout, 1, 0,
        VAR_SCACHE_PROTO_TMOUT, DEF_SCACHE_PROTO_TMOUT, &var_scache_proto_tmout, 1, 0,
        0,
     };
-    static CONFIG_INT_TABLE smtp_int_table[] = {
+    static const CONFIG_INT_TABLE smtp_int_table[] = {
        VAR_SMTP_LINE_LIMIT, DEF_SMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
        VAR_SMTP_MXADDR_LIMIT, DEF_SMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
        VAR_SMTP_MXSESS_LIMIT, DEF_SMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
 #ifdef USE_TLS
        VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
        VAR_SMTP_TLS_LOGLEVEL, DEF_SMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0,
-       VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 1, 0,
 #endif
        0,
     };
-    static CONFIG_BOOL_TABLE smtp_bool_table[] = {
+    static const CONFIG_BOOL_TABLE smtp_bool_table[] = {
        VAR_SMTP_SKIP_5XX, DEF_SMTP_SKIP_5XX, &var_smtp_skip_5xx_greeting,
        VAR_IGN_MX_LOOKUP_ERR, DEF_IGN_MX_LOOKUP_ERR, &var_ign_mx_lookup_err,
        VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
index 48d2e3eba8f4dc0161802aaa92183afbfe25e6bb..ed40eff5b25863dec88f8217889ab0c8dc26c8a1 100644 (file)
@@ -264,7 +264,7 @@ int     smtp_helo(SMTP_STATE *state)
     char   *words;
     char   *word;
     int     n;
-    static NAME_CODE xforward_features[] = {
+    static const NAME_CODE xforward_features[] = {
        XFORWARD_NAME, SMTP_FEATURE_XFORWARD_NAME,
        XFORWARD_ADDR, SMTP_FEATURE_XFORWARD_ADDR,
        XFORWARD_PORT, SMTP_FEATURE_XFORWARD_PORT,
@@ -276,7 +276,7 @@ int     smtp_helo(SMTP_STATE *state)
     SOCKOPT_SIZE optlen;
     const char *ehlo_words;
     int     discard_mask;
-    static NAME_MASK pix_bug_table[] = {
+    static const NAME_MASK pix_bug_table[] = {
        PIX_BUG_DISABLE_ESMTP, SMTP_FEATURE_PIX_NO_ESMTP,
        PIX_BUG_DELAY_DOTCRLF, SMTP_FEATURE_PIX_DELAY_DOTCRLF,
        0,
@@ -323,6 +323,18 @@ int     smtp_helo(SMTP_STATE *state)
                                   translit(resp->str, "\n", " ")));
        }
 
+       /*
+        * If the policy table specifies a bogus TLS security level, fail
+        * now.
+        */
+#ifdef USE_TLS
+       if (session->tls_level == TLS_LEV_INVALID)
+           /* Warning is already logged. */
+           return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
+                                  SMTP_RESP_FAKE(&fake, "4.7.0"),
+                                  "client TLS configuration problem"));
+#endif
+
        /*
         * XXX Some PIX firewall versions require flush before ".<CR><LF>" so
         * it does not span a packet boundary. This hurts performance so it
@@ -676,7 +688,7 @@ int     smtp_helo(SMTP_STATE *state)
 static int smtp_start_tls(SMTP_STATE *state)
 {
     SMTP_SESSION *session = state->session;
-    tls_client_start_props tls_props;
+    TLS_CLIENT_START_PROPS tls_props;
     VSTRING *serverid;
     SMTP_RESP fake;
 
@@ -692,20 +704,15 @@ static int smtp_start_tls(SMTP_STATE *state)
     DONT_CACHE_THIS_SESSION;
 
     /*
-     * The actual TLS handshake may succeed, but tls_client_start() may fail
-     * anyway, for example because server certificate verification is
-     * required but failed, or because enforce_peername is required but the
-     * names listed in the server certificate don't match the peer hostname.
+     * As of Postfix 2.5, tls_client_start() tries hard to always complete
+     * the TLS handshake. It records the verification and match status in the
+     * resulting TLScontext. It is now up to the application to abort the TLS
+     * connection if it chooses.
      * 
      * XXX When tls_client_start() fails then we don't know what state the SMTP
      * connection is in, so we give up on this connection even if we are not
      * required to use TLS.
      * 
-     * XXX Other tests for specific combinations of required/failed behavior
-     * follow below AFTER the tls_client_start() call. These tests should be
-     * done inside tls_client_start() or its call-backs, to keep the SMTP
-     * client code clean (as it is in the SMTP server).
-     * 
      * The following assumes sites that use TLS in a perverse configuration:
      * multiple hosts per hostname, or even multiple hosts per IP address.
      * All this without a shared TLS session cache, and they still want to
@@ -719,76 +726,40 @@ static int smtp_start_tls(SMTP_STATE *state)
      * is valid for another. Therefore the client session id must include
      * either the transport name or the values of CAfile and CApath. We use
      * the transport name.
-     */
-    serverid = vstring_alloc(10);
-    vstring_sprintf(serverid, "%s:%s:%u:%s", state->service, session->addr,
-                 ntohs(session->port), session->helo ? session->helo : "");
-
-    /*
-     * XXX: We store only one session per lookup key. Ideally the the key
-     * maps 1-to-1 to a server TLS session cache. We use the IP address, port
-     * and ehlo response name to build a lookup key that works for split
-     * caches (that announce distinct names) behind a load balancer.
-     * 
-     * Starting with Postfix 2.3 we may have incompatible security requirements
-     * for different domains hosted on the same server (peer cache). This
-     * requires multiple sessions to be negotiated with the same peer. It
-     * would be bad to store just one session and repeatedly discard it when
-     * we encounter incompatible requirements.
      * 
-     * This drives us to separate lookup keys for each combination of cipher and
-     * protocol requirements. While at times a stronger session may not get
-     * re-used for a delivery with weaker requirements, a multi-session cache
-     * is prohibitively complex at this time.
+     * XXX: We store only one session per lookup key. Ideally the the key maps
+     * 1-to-1 to a server TLS session cache. We use the IP address, port and
+     * ehlo response name to build a lookup key that works for split caches
+     * (that announce distinct names) behind a load balancer.
      * 
-     * - Expiration code would need to selectively delete sessions from a list -
-     * Re-use code would need to decode many sessions and choose the best -
-     * Store code would need to choose between replace and append.
+     * XXX: The TLS library may salt the serverid with further details of the
+     * protocol and cipher requirements.
      * 
-     * Note: checking the compatibility of re-activated sessions against the
-     * cipher requirements of the session under construction requires us to
-     * store the cipher name in the session cache with the passivated session
-     * object. But the name is not available when the session is revived
-     * until the handshake is complete, which is too late.
-     * 
-     * XXX: When a cached session is reloaded, its cipher is not available via
-     * documented APIs until the handshake completes. We need to filter out
-     * sessions that use the wrong ciphers, but may not peek at the
-     * undocumented session->cipher_id and cipher->id structure members.
-     * 
-     * Since cipherlists are typically shared by many domains, we include the
-     * cipherlist in the session cache lookup key. This avoids false
-     * positives from the TLS session cache.
-     * 
-     * To support mutually incompatible protocol/cipher combinations, our
-     * session key must include both the protocol and the cipherlist.
-     * 
-     * XXX: the cipherlist is case sensitive, "aDH" != "ADH". So we don't
-     * lowercase() the serverid.
+     * Large parameter lists are error-prone, so we emulate a language feature
+     * that C does not have natively: named parameter lists.
      */
-    if (session->tls_level >= TLS_LEV_ENCRYPT
-       && session->tls_protocols != 0
-       && session->tls_protocols != TLS_ALL_PROTOCOLS)
-       vstring_sprintf_append(serverid, "&p=%s",
-                              tls_protocol_names(VAR_SMTP_TLS_MAND_PROTO,
-                                                 session->tls_protocols));
-    if (session->tls_level >= TLS_LEV_ENCRYPT)
-       vstring_sprintf_append(serverid, "&c=%s", session->tls_cipherlist);
-
-    tls_props.ctx = smtp_tls_ctx;
-    tls_props.stream = session->stream;
-    tls_props.log_level = var_smtp_tls_loglevel;
-    tls_props.timeout = var_smtp_starttls_tmout;
-    tls_props.tls_level = session->tls_level;
-    tls_props.nexthop = session->tls_nexthop;
-    tls_props.host = session->host;
-    tls_props.serverid = vstring_str(serverid);
-    tls_props.protocols = session->tls_protocols;
-    tls_props.cipherlist = session->tls_cipherlist;
-    tls_props.certmatch = session->tls_certmatch;
-
-    session->tls_context = tls_client_start(&tls_props);
+    serverid = vstring_alloc(10);
+    vstring_sprintf(serverid, "%s:%s:%u:%s", state->service, session->addr,
+                 ntohs(session->port), session->helo ? session->helo : "");
+    session->tls_context =
+       TLS_CLIENT_START(&tls_props,
+                        ctx = smtp_tls_ctx,
+                        stream = session->stream,
+                        log_level = var_smtp_tls_loglevel,
+                        timeout = var_smtp_starttls_tmout,
+                        tls_level = session->tls_level,
+                        nexthop = session->tls_nexthop,
+                        host = session->host,
+                        namaddr = session->namaddrport,
+                        serverid = vstring_str(serverid),
+                        protocols = session->tls_protocols,
+                        cipher_grade = session->tls_grade,
+                        cipher_exclusions
+                        = vstring_str(session->tls_exclusions),
+                        matchargv = session->tls_matchargv,
+                        fpt_dgst = var_smtp_tls_fpt_dgst);
     vstring_free(serverid);
+
     if (session->tls_context == 0) {
 
        /*
@@ -820,6 +791,26 @@ static int smtp_start_tls(SMTP_STATE *state)
                               "Cannot start TLS: handshake failure"));
     }
 
+    /*
+     * If we are verifying the server certificate and are not happy with the
+     * result, abort the delivery here. We have a usable TLS session with the
+     * server, so no need to disable I/O, ... we can even be polite and send
+     * "QUIT".
+     * 
+     * See src/tls/tls_level.c. Levels above encrypt require matching. Levels >=
+     * verify require CA trust.
+     */
+    if (session->tls_level >= TLS_LEV_VERIFY)
+       if (!TLS_CERT_IS_TRUSTED(session->tls_context))
+           return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
+                                  SMTP_RESP_FAKE(&fake, "4.7.5"),
+                                  "Server certificate not trusted"));
+    if (session->tls_level > TLS_LEV_ENCRYPT)
+       if (!TLS_CERT_IS_MATCHED(session->tls_context))
+           return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
+                                  SMTP_RESP_FAKE(&fake, "4.7.5"),
+                                  "Server certificate not verified"));
+
     /*
      * At this point we have to re-negotiate the "EHLO" to reget the
      * feature-list.
@@ -912,8 +903,8 @@ static void smtp_format_out(void *context, int rec_type, const char *fmt,...)
 /* smtp_header_out - output one message header */
 
 static void smtp_header_out(void *context, int unused_header_class,
-                                   HEADER_OPTS *unused_info, VSTRING *buf,
-                                   off_t offset)
+                                   const HEADER_OPTS *unused_info,
+                                   VSTRING *buf, off_t offset)
 {
     char   *start = vstring_str(buf);
     char   *line;
@@ -933,8 +924,8 @@ static void smtp_header_out(void *context, int unused_header_class,
 /* smtp_header_rewrite - rewrite message header before output */
 
 static void smtp_header_rewrite(void *context, int header_class,
-                                    HEADER_OPTS *header_info, VSTRING *buf,
-                                       off_t offset)
+                                       const HEADER_OPTS *header_info,
+                                       VSTRING *buf, off_t offset)
 {
     SMTP_STATE *state = (SMTP_STATE *) context;
     int     did_rewrite = 0;
@@ -1060,7 +1051,7 @@ static void smtp_body_rewrite(void *context, int type,
 
 static void smtp_mime_fail(SMTP_STATE *state, int mime_errs)
 {
-    MIME_STATE_DETAIL *detail;
+    const MIME_STATE_DETAIL *detail;
     SMTP_RESP fake;
 
     detail = mime_state_detail(mime_errs);
index ce0877a1d75ec7a8bb9e27e51cb5df07952a96bc..9e813b276c18036f9798bed1ff23260803558195 100644 (file)
@@ -184,7 +184,7 @@ int     smtp_sasl_helo_login(SMTP_STATE *state)
            smtp_sasl_start(session, VAR_SMTP_SASL_OPTS,
                            var_smtp_sasl_opts);
 #ifdef SNAPSHOT                                        /* XXX: Not yet */
-       else if (session->tls_context->peer_verified)
+       else if (TLS_CERT_IS_MATCHED(session->tls_context))
            smtp_sasl_start(session, VAR_SMTP_SASL_TLSV_OPTS,
                            var_smtp_sasl_tlsv_opts);
 #endif
index 97cc8ceb9a3ca36b9211caf0de2556e5fee32493..b67bc8524f1b9727f499de14449c952fc1044bf1 100644 (file)
@@ -201,8 +201,7 @@ static void tls_site_lookup(int *site_level, const char *site_name,
 
 /* tls_policy_lookup_one - look up destination TLS policy */
 
-static int tls_policy_lookup_one(SMTP_SESSION *session,
-                                        int *site_level, int *cipher_level,
+static int tls_policy_lookup_one(SMTP_SESSION *session, int *site_level,
                                         const char *site_name,
                                         const char *site_class)
 {
@@ -224,87 +223,117 @@ static int tls_policy_lookup_one(SMTP_SESSION *session,
     if (cbuf == 0)
        cbuf = vstring_alloc(10);
 
-#define set_context(cbuf,  site_class, site_name) \
-    vstring_sprintf(cbuf, "TLS policy table, %s '%s'", site_class, site_name)
-#define str_context(cbuf,  site_class, site_name) \
-    vstring_str(set_context(cbuf, site_class, site_name))
+#define WHERE \
+    vstring_str(vstring_sprintf(cbuf, "TLS policy table, %s \"%s\"", \
+               site_class, site_name))
 
     saved_policy = policy = mystrdup(lookup);
 
     if ((tok = mystrtok(&policy, "\t\n\r ,")) == 0) {
-       msg_warn("ignoring empty tls policy for %s", site_name);
+       msg_warn("%s: invalid empty policy", WHERE);
+       *site_level = TLS_LEV_INVALID;
        FREE_RETURN(1);                         /* No further lookups */
     }
     *site_level = tls_level_lookup(tok);
-    if (*site_level == TLS_LEV_NOTFOUND) {
-       msg_warn("%s: unknown security level '%s' ignored",
-                str_context(cbuf, site_class, site_name), tok);
+    if (*site_level == TLS_LEV_INVALID) {
+       /* tls_level_lookup() logs no warning. */
+       msg_warn("%s: invalid security level \"%s\"", WHERE, tok);
        FREE_RETURN(1);                         /* No further lookups */
     }
+
+    /*
+     * Warn about ignored attributes when TLS is disabled.
+     */
+    if (*site_level < TLS_LEV_MAY) {
+       while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0)
+           msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
+                    WHERE, tok);
+       FREE_RETURN(1);
+    }
+
+    /*
+     * Errors in attributes may have security consequences, don't ignore
+     * errors that can degrade security.
+     */
     while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0) {
        if ((err = split_nameval(tok, &name, &val)) != 0) {
-           msg_warn("%s: malformed attribute/value pair '%s' ignored: %s",
-                    str_context(cbuf, site_class, site_name), tok, err);
-           continue;
+           *site_level = TLS_LEV_INVALID;
+           msg_warn("%s: malformed attribute/value pair \"%s\": %s",
+                    WHERE, tok, err);
+           break;
        }
+       /* Only one instance per policy. */
        if (!strcasecmp(name, "ciphers")) {
            if (*site_level < TLS_LEV_ENCRYPT) {
-               msg_warn("%s: attribute '%s' ignored at security level '%s'",
-                        str_context(cbuf, site_class, site_name),
-                        name, policy_name(*site_level));
-               continue;
+               msg_warn("%s: attribute \"%s\" invalid at security level \"%s\"",
+                        WHERE, name, policy_name(*site_level));
+               *site_level = TLS_LEV_INVALID;
+               break;
+           }
+           if (*val == 0) {
+               msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
+               *site_level = TLS_LEV_INVALID;
+               break;
            }
-           *cipher_level = tls_cipher_level(val);
-           if (*cipher_level == TLS_CIPHER_NONE) {
-               msg_warn("%s: invalid %s value '%s' ignored",
-                        str_context(cbuf, site_class, site_name),
-                        name, val);
+           if (session->tls_grade) {
+               msg_warn("%s: attribute \"%s\" is specified multiple times",
+                        WHERE, name);
+               *site_level = TLS_LEV_INVALID;
+               break;
            }
+           /* set_cipher_grade() assumes this is NULL with level < encrypt */
+           session->tls_grade = mystrdup(val);
            continue;
        }
+       /* Only one instance per policy. */
        if (!strcasecmp(name, "protocols")) {
            if (*site_level < TLS_LEV_ENCRYPT) {
-               msg_warn("%s: attribute '%s' ignored at security level '%s'",
-                        str_context(cbuf, site_class, site_name),
-                        name, policy_name(*site_level));
-               continue;
+               msg_warn("%s: attribute \"%s\" invalid at security level \"%s\"",
+                        WHERE, name, policy_name(*site_level));
+               *site_level = TLS_LEV_INVALID;
+               break;
            }
-           if (*val == 0) {
-               msg_warn("%s: empty %s value ignored",
-                        str_context(cbuf, site_class, site_name), name);
-               continue;
+           if (session->tls_protocols) {
+               msg_warn("%s: attribute \"%s\" is specified multiple times",
+                        WHERE, name);
+               *site_level = TLS_LEV_INVALID;
+               break;
            }
-           vstring_sprintf(cbuf, "protocol in TLS policy table, %s '%s':",
-                           site_class, site_name);
-           session->tls_protocols = tls_protocol_mask(vstring_str(cbuf), val);
+           session->tls_protocols = mystrdup(val);
            continue;
        }
+       /* Multiple instance(s) per policy. */
        if (!strcasecmp(name, "match")) {
-           if (*site_level < TLS_LEV_VERIFY) {
-               msg_warn("%s: attribute '%s' ignored at security level '%s'",
-                        str_context(cbuf, site_class, site_name),
-                        name, policy_name(*site_level));
-               continue;
+           char   *delim = *site_level == TLS_LEV_FPRINT ? "|" : ":";
+
+           if (*site_level <= TLS_LEV_ENCRYPT) {
+               msg_warn("%s: attribute \"%s\" invalid at security level \"%s\"",
+                        WHERE, name, policy_name(*site_level));
+               *site_level = TLS_LEV_INVALID;
+               break;
            }
            if (*val == 0) {
-               msg_warn("%s: empty %s value ignored",
-                        str_context(cbuf, site_class, site_name), name);
-               continue;
+               msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
+               *site_level = TLS_LEV_INVALID;
+               break;
            }
-           session->tls_certmatch = mystrdup(val);
+           if (session->tls_matchargv == 0)
+               session->tls_matchargv = argv_split(val, delim);
+           else
+               argv_split_append(session->tls_matchargv, val, delim);
            continue;
+       } else {
+           msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
+           *site_level = TLS_LEV_INVALID;
+           break;
        }
-       msg_warn("%s: unknown attribute '%s' ignored",
-                str_context(cbuf, site_class, site_name), name);
     }
-
     FREE_RETURN(1);
 }
 
 /* tls_policy_lookup - look up destination TLS policy */
 
-static void tls_policy_lookup(SMTP_SESSION *session,
-                                     int *site_level, int *cipher_level,
+static void tls_policy_lookup(SMTP_SESSION *session, int *site_level,
                                      const char *site_name,
                                      const char *site_class)
 {
@@ -317,14 +346,17 @@ static void tls_policy_lookup(SMTP_SESSION *session,
      * sub-domains of the recipient domain.
      */
     if (!valid_hostname(site_name, DONT_GRIPE)) {
-       tls_policy_lookup_one(session, site_level, cipher_level,
-                             site_name, site_class);
+       tls_policy_lookup_one(session, site_level, site_name, site_class);
        return;
     }
+
+    /*
+     * XXX For clarity consider using ``do { .. } while'', instead of using
+     * ``while { .. }'' with loop control at the bottom.
+     */
     while (1) {
        /* Try the given domain */
-       if (tls_policy_lookup_one(session, site_level, cipher_level,
-                                 site_name, site_class))
+       if (tls_policy_lookup_one(session, site_level, site_name, site_class))
            return;
        /* Re-try with parent domain */
        if ((site_name = strchr(site_name + 1, '.')) == 0)
@@ -332,14 +364,12 @@ static void tls_policy_lookup(SMTP_SESSION *session,
     }
 }
 
-/* set_cipherlist - Choose cipherlist per security level and cipher suite */
+/* set_cipher_grade - Set cipher grade and exclusions */
 
-static void set_cipherlist(SMTP_SESSION *session, int cipher_level, int lmtp)
+static void set_cipher_grade(SMTP_SESSION *session)
 {
-    const char *cipherlist = 0;
-    const char *exclude = var_smtp_tls_excl_ciph;
-    const char *also_exclude = "";
     const char *mand_exclude = "";
+    const char *also_exclude = "";
 
     /*
      * Use main.cf cipher level if no per-destination value specified. With
@@ -347,42 +377,50 @@ static void set_cipherlist(SMTP_SESSION *session, int cipher_level, int lmtp)
      * at least authenticate!
      */
     switch (session->tls_level) {
+    case TLS_LEV_INVALID:
     case TLS_LEV_NONE:
-       session->tls_cipherlist = 0;
        return;
 
     case TLS_LEV_MAY:
-       cipher_level = TLS_CIPHER_EXPORT;       /* Interoperate! */
+       /* tls_policy_lookup_one() leaves this NULL with level < encrypt. */
+       session->tls_grade = mystrdup("export");/* XXX: For now */
        break;
 
     case TLS_LEV_ENCRYPT:
-       also_exclude = "eNULL";
-       if (cipher_level == TLS_CIPHER_NONE)
-           cipher_level = tls_cipher_level(var_smtp_tls_mand_ciph);
+       if (session->tls_grade == 0)
+           session->tls_grade = mystrdup(var_smtp_tls_mand_ciph);
        mand_exclude = var_smtp_tls_mand_excl;
+       also_exclude = "eNULL";
        break;
 
+    case TLS_LEV_FPRINT:
     case TLS_LEV_VERIFY:
     case TLS_LEV_SECURE:
-       also_exclude = "aNULL";
-       if (cipher_level == TLS_CIPHER_NONE)
-           cipher_level = tls_cipher_level(var_smtp_tls_mand_ciph);
+       if (session->tls_grade == 0)
+           session->tls_grade = mystrdup(var_smtp_tls_mand_ciph);
        mand_exclude = var_smtp_tls_mand_excl;
+       also_exclude = "aNULL";
        break;
     }
 
-    cipherlist = tls_cipher_list(cipher_level, exclude, mand_exclude,
-                                also_exclude, TLS_END_EXCLUDE);
-    if (cipherlist == 0) {
-       msg_warn("unknown '%s' value '%s' ignored, using 'medium'",
-                lmtp ? VAR_LMTP_TLS_MAND_CIPH : VAR_SMTP_TLS_MAND_CIPH,
-                var_smtp_tls_mand_ciph);
-       cipherlist = tls_cipher_list(TLS_CIPHER_MEDIUM, exclude, mand_exclude,
-                                    also_exclude, TLS_END_EXCLUDE);
-       if (cipherlist == 0)
-           msg_panic("NULL medium cipherlist");
+#define ADD_EXCLUDE(vstr, str) \
+    do { \
+       if (*(str)) \
+           vstring_sprintf_append((vstr), "%s%s", \
+                                  VSTRING_LEN(vstr) ? " " : "", (str)); \
+    } while (0)
+
+    /*
+     * Soon, the "exclude" policy table attribute will be able to override
+     * the main.cf mandatory exclusion list, and the latter may become
+     * obsolete.
+     */
+    if (session->tls_exclusions == 0) {
+       session->tls_exclusions = vstring_alloc(10);
+       ADD_EXCLUDE(session->tls_exclusions, var_smtp_tls_excl_ciph);
+       ADD_EXCLUDE(session->tls_exclusions, mand_exclude);
     }
-    session->tls_cipherlist = mystrdup(cipherlist);
+    ADD_EXCLUDE(session->tls_exclusions, also_exclude);
 }
 
 /* session_tls_init - session TLS parameters */
@@ -390,10 +428,9 @@ static void set_cipherlist(SMTP_SESSION *session, int cipher_level, int lmtp)
 static void session_tls_init(SMTP_SESSION *session, const char *dest,
                                     const char *host, int flags)
 {
+    const char *myname = "session_tls_init";
     int     global_level;
     int     site_level;
-    int     lmtp = flags & SMTP_MISC_FLAG_USE_LMTP;
-    int     cipher_level = TLS_CIPHER_NONE;
 
     /*
      * Initialize all TLS related session properties.
@@ -403,8 +440,9 @@ static void session_tls_init(SMTP_SESSION *session, const char *dest,
     session->tls_level = TLS_LEV_NONE;
     session->tls_retry_plain = 0;
     session->tls_protocols = 0;
-    session->tls_cipherlist = 0;
-    session->tls_certmatch = 0;
+    session->tls_grade = 0;
+    session->tls_exclusions = 0;
+    session->tls_matchargv = 0;
 
     /*
      * Compute the global TLS policy. This is the default policy level when
@@ -412,12 +450,11 @@ static void session_tls_init(SMTP_SESSION *session, const char *dest,
      * per-site policy.
      */
     if (*var_smtp_tls_level) {
+       /* Require that var_smtp_tls_level is sanitized upon startup. */
        global_level = tls_level_lookup(var_smtp_tls_level);
-       if (global_level == TLS_LEV_NOTFOUND) {
-           msg_fatal("%s: unknown TLS security level '%s'",
-                     lmtp ? VAR_LMTP_TLS_LEVEL : VAR_SMTP_TLS_LEVEL,
-                     var_smtp_tls_level);
-       }
+       if (global_level == TLS_LEV_INVALID)
+           msg_panic("%s: invalid TLS security level: \"%s\"",
+                     myname, var_smtp_tls_level);
     } else if (var_smtp_enforce_tls) {
        global_level = var_smtp_tls_enforce_peername ?
            TLS_LEV_VERIFY : TLS_LEV_ENCRYPT;
@@ -436,8 +473,7 @@ static void session_tls_init(SMTP_SESSION *session, const char *dest,
     site_level = TLS_LEV_NOTFOUND;
 
     if (tls_policy) {
-       tls_policy_lookup(session, &site_level, &cipher_level,
-                         dest, "next-hop destination");
+       tls_policy_lookup(session, &site_level, dest, "next-hop destination");
     } else if (tls_per_site) {
        tls_site_lookup(&site_level, dest, "next-hop destination");
        if (strcasecmp(dest, host) != 0)
@@ -470,37 +506,44 @@ static void session_tls_init(SMTP_SESSION *session, const char *dest,
        session->tls_level = site_level;
 
     /*
-     * Use main.cf protocols setting if not set in per-destination table
+     * Use main.cf protocols setting if not set in per-destination table.
      */
-    if (session->tls_level >= TLS_LEV_ENCRYPT
-       && session->tls_protocols == 0
-       && *var_smtp_tls_mand_proto)
+    if (session->tls_level > TLS_LEV_NONE && session->tls_protocols == 0)
        session->tls_protocols =
-           tls_protocol_mask(VAR_SMTP_TLS_MAND_PROTO, var_smtp_tls_mand_proto);
+           mystrdup((session->tls_level == TLS_LEV_MAY) ?
+                    "" : var_smtp_tls_mand_proto);
 
     /*
-     * Convert cipher level (if set in per-destination table, else
-     * set_cipherlist uses main.cf settings) to an OpenSSL cipherlist. The
-     * "lmtp" vs. "smtp" identity is used for error reporting.
+     * Compute cipher grade (if set in per-destination table, else
+     * set_cipher() uses main.cf settings) and security level dependent
+     * cipher exclusion list.
      */
-    set_cipherlist(session, cipher_level, lmtp);
+    set_cipher_grade(session);
 
     /*
-     * Use main.cf cert_match setting if not set in per-destination table
+     * Use main.cf cert_match setting if not set in per-destination table.
      */
-    if (session->tls_level >= TLS_LEV_ENCRYPT
-       && session->tls_certmatch == 0) {
+    if (session->tls_matchargv == 0) {
        switch (session->tls_level) {
+       case TLS_LEV_INVALID:
+       case TLS_LEV_NONE:
+       case TLS_LEV_MAY:
        case TLS_LEV_ENCRYPT:
            break;
+       case TLS_LEV_FPRINT:
+           session->tls_matchargv =
+               argv_split(var_smtp_tls_fpt_cmatch, "\t\n\r, |");
+           break;
        case TLS_LEV_VERIFY:
-           session->tls_certmatch = mystrdup(var_smtp_tls_vfy_cmatch);
+           session->tls_matchargv =
+               argv_split(var_smtp_tls_vfy_cmatch, "\t\n\r, :");
            break;
        case TLS_LEV_SECURE:
-           session->tls_certmatch = mystrdup(var_smtp_tls_sec_cmatch);
+           session->tls_matchargv =
+               argv_split(var_smtp_tls_sec_cmatch, "\t\n\r, :");
            break;
        default:
-           msg_panic("unexpected mandatory TLS security level: %d",
+           msg_panic("unexpected TLS security level: %d",
                      session->tls_level);
        }
     }
@@ -583,10 +626,14 @@ void    smtp_session_free(SMTP_SESSION *session)
            tls_client_stop(smtp_tls_ctx, session->stream,
                          var_smtp_starttls_tmout, 0, session->tls_context);
     }
-    if (session->tls_cipherlist)
-       myfree(session->tls_cipherlist);
-    if (session->tls_certmatch)
-       myfree(session->tls_certmatch);
+    if (session->tls_protocols)
+       myfree(session->tls_protocols);
+    if (session->tls_grade)
+       myfree(session->tls_grade);
+    if (session->tls_exclusions)
+       vstring_free(session->tls_exclusions);
+    if (session->tls_matchargv)
+       argv_free(session->tls_matchargv);
 #endif
     if (session->stream)
        vstream_fclose(session->stream);
index a7a3e9c5d2cd2d89bc3298e49b8d4f98a21b8ffb..807ec3fcb05b0da618a5d2351d86095f7ff82f97 100644 (file)
@@ -298,6 +298,7 @@ smtpd_dsn_fix.o: ../../include/sys_defs.h
 smtpd_dsn_fix.o: smtpd_dsn_fix.c
 smtpd_dsn_fix.o: smtpd_dsn_fix.h
 smtpd_milter.o: ../../include/argv.h
+smtpd_milter.o: ../../include/attr.h
 smtpd_milter.o: ../../include/mail_params.h
 smtpd_milter.o: ../../include/mail_stream.h
 smtpd_milter.o: ../../include/milter.h
@@ -365,6 +366,7 @@ smtpd_proxy.o: smtpd.h
 smtpd_proxy.o: smtpd_proxy.c
 smtpd_proxy.o: smtpd_proxy.h
 smtpd_sasl_glue.o: ../../include/argv.h
+smtpd_sasl_glue.o: ../../include/attr.h
 smtpd_sasl_glue.o: ../../include/mail_params.h
 smtpd_sasl_glue.o: ../../include/mail_stream.h
 smtpd_sasl_glue.o: ../../include/milter.h
index 231fe99f3c1a3c2b0be3df958f715f08f5f612b5..68775495a8bef76a274c716160658041f00d117a 100644 (file)
 /*     When TLS encryption is optional in the Postfix SMTP server, do
 /*     not announce or accept SASL authentication over unencrypted
 /*     connections.
-/* .IP "\fBsmtpd_tls_ccert_verifydepth (5)\fR"
+/* .IP "\fBsmtpd_tls_ccert_verifydepth (9)\fR"
 /*     The verification depth for remote SMTP client certificates.
 /* .IP "\fBsmtpd_tls_cert_file (empty)\fR"
 /*     File with the Postfix SMTP server RSA certificate in PEM format.
 /*     Additional list of ciphers or cipher types to exclude from the
 /*     SMTP server cipher list at mandatory TLS security levels.
 /* .IP "\fBsmtpd_tls_mandatory_protocols (SSLv3, TLSv1)\fR"
-/*     The TLS protocols accepted by the Postfix SMTP server with
+/*     The SSL/TLS protocols accepted by the Postfix SMTP server with
 /*     mandatory TLS encryption.
 /* .IP "\fBsmtpd_tls_received_header (no)\fR"
 /*     Request that the Postfix SMTP server produces Received:  message
 /*     as well as the client CommonName and client certificate issuer
 /*     CommonName.
 /* .IP "\fBsmtpd_tls_req_ccert (no)\fR"
-/*     With mandatory TLS encryption, require a remote SMTP client
+/*     With mandatory TLS encryption, require a trusted remote SMTP client
 /*     certificate in order to allow TLS connections to proceed.
 /* .IP "\fBsmtpd_tls_session_cache_database (empty)\fR"
 /*     Name of the file containing the optional Postfix SMTP server
 /* .IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
 /*     The OpenSSL cipherlist for "NULL" grade ciphers that provide
 /*     authentication without encryption.
+/* .PP
+/*     Available in Postfix version 2.5 and later:
+/* .IP "\fBsmtpd_tls_fingerprint_digest (md5)\fR"
+/*     The message digest algorithm used to construct client-certificate
+/*     fingerprints for \fBcheck_ccert_access\fR and
+/*     \fBpermit_tls_clientcerts\fR.
 /* OBSOLETE STARTTLS CONTROLS
 /* .ad
 /* .fi
 /*     Allgemeine Elektrotechnik
 /*     Universitaetsplatz 3-4
 /*     D-03044 Cottbus, Germany
+/*
+/*     Revised TLS support by:
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
@@ -1110,7 +1120,7 @@ bool    var_smtpd_tls_received_header;
 bool    var_smtpd_tls_req_ccert;
 int     var_smtpd_tls_scache_timeout;
 bool    var_smtpd_tls_set_sessid;
-int     var_tls_daemon_rand_bytes;
+char   *var_smtpd_tls_fpt_dgst;
 
 #endif
 
@@ -1210,10 +1220,13 @@ MILTERS *smtpd_milters;
  /*
   * TLS initialization status.
   */
-static SSL_CTX *smtpd_tls_ctx;
+static TLS_APPL_STATE *smtpd_tls_ctx;
+static int wantcert;
 
 #endif
 
+static int enforce_tls;
+
 #ifdef USE_SASL_AUTH
 
  /*
@@ -2511,7 +2524,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
     VSTREAM *out_stream;
     int     out_error;
     char  **cpp;
-    CLEANUP_STAT_DETAIL *detail;
+    const CLEANUP_STAT_DETAIL *detail;
     const char *rfc3848_sess;
     const char *rfc3848_auth;
 
@@ -2628,20 +2641,17 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
                        state->tls_context->cipher_name,
                        state->tls_context->cipher_usebits,
                        state->tls_context->cipher_algbits);
-           if (state->tls_context->peer_CN) {
+           if (TLS_CERT_IS_PRESENT(state->tls_context)) {
                peer_CN = VSTRING_STRDUP(state->tls_context->peer_CN);
                comment_sanitize(peer_CN);
                issuer_CN = VSTRING_STRDUP(state->tls_context->issuer_CN ?
                                        state->tls_context->issuer_CN : "");
                comment_sanitize(issuer_CN);
-               if (state->tls_context->peer_verified)
-                   out_fprintf(out_stream, REC_TYPE_NORM,
-                       "\t(Client CN \"%s\", Issuer \"%s\" (verified OK))",
-                               STR(peer_CN), STR(issuer_CN));
-               else
-                   out_fprintf(out_stream, REC_TYPE_NORM,
-                      "\t(Client CN \"%s\", Issuer \"%s\" (not verified))",
-                               STR(peer_CN), STR(issuer_CN));
+               out_fprintf(out_stream, REC_TYPE_NORM,
+                           "\t(Client CN \"%s\", Issuer \"%s\" (%s))",
+                           STR(peer_CN), STR(issuer_CN),
+                           TLS_CERT_IS_TRUSTED(state->tls_context) ?
+                           "verified OK" : "not verified");
                vstring_free(issuer_CN);
                vstring_free(peer_CN);
            } else if (var_smtpd_tls_ask_ccert)
@@ -3164,12 +3174,12 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     char   *attr_name;
     int     update_namaddr = 0;
     int     name_status;
-    static NAME_CODE peer_codes[] = {
+    static const NAME_CODE peer_codes[] = {
        XCLIENT_UNAVAILABLE, SMTPD_PEER_CODE_PERM,
        XCLIENT_TEMPORARY, SMTPD_PEER_CODE_TEMP,
        0, SMTPD_PEER_CODE_OK,
     };
-    static NAME_CODE proto_names[] = {
+    static const NAME_CODE proto_names[] = {
        MAIL_PROTO_SMTP, 1,
        MAIL_PROTO_ESMTP, 2,
        0, -1,
@@ -3439,7 +3449,7 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     const char *bare_value;
     char   *attr_name;
     int     updated = 0;
-    static NAME_CODE xforward_flags[] = {
+    static const NAME_CODE xforward_flags[] = {
        XFORWARD_NAME, SMTPD_STATE_XFORWARD_NAME,
        XFORWARD_ADDR, SMTPD_STATE_XFORWARD_ADDR,
        XFORWARD_PORT, SMTPD_STATE_XFORWARD_PORT,
@@ -3452,7 +3462,7 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        MAIL_ATTR_RWR_LOCAL,            /* Postfix internal form */
        MAIL_ATTR_RWR_REMOTE,           /* Postfix internal form */
     };
-    static NAME_CODE xforward_to_context[] = {
+    static const NAME_CODE xforward_to_context[] = {
        XFORWARD_DOM_LOCAL, 0,          /* XFORWARD representation */
        XFORWARD_DOM_REMOTE, 1,         /* XFORWARD representation */
        0, -1,
@@ -3689,7 +3699,10 @@ static void chat_reset(SMTPD_STATE *state, int threshold)
 static void smtpd_start_tls(SMTPD_STATE *state)
 {
     int     rate;
-    tls_server_start_props props;
+    TLS_SERVER_START_PROPS props;
+    static char *cipher_grade;
+    static VSTRING *cipher_exclusions;
+    int     cert_present;
 
     /*
      * Wrapper mode uses a dedicated port and always requires TLS.
@@ -3701,28 +3714,56 @@ static void smtpd_start_tls(SMTPD_STATE *state)
      * command. For this reason, Postfix does not require client certificate
      * verification unless TLS is required.
      * 
-     * XXX We append the service name to the session cache ID, so that there
-     * won't be collisions between multiple master.cf entries that use
-     * different roots of trust. This does not eliminate collisions between
-     * multiple inetd.conf entries that use different roots of trust. For a
-     * universal solution we would have to append the local IP address + port
-     * number information.
+     * The cipher grade and exclusions don't change between sessions. Compute
+     * just once and cache.
      */
-    memset((char *) &props, 0, sizeof(props));
-    props.ctx = smtpd_tls_ctx;
-    props.stream = state->client;
-    props.log_level = var_smtpd_tls_loglevel;
-    props.timeout = var_smtpd_starttls_tmout;
-    props.requirecert = (var_smtpd_tls_req_ccert && state->tls_enforce_tls);
-    props.serverid = state->service;
-    props.peername = state->name;
-    props.peeraddr = state->addr;
-    state->tls_context = tls_server_start(&props);
+#define ADD_EXCLUDE(vstr, str) \
+    do { \
+       if (*(str)) \
+           vstring_sprintf_append((vstr), "%s%s", \
+                                  VSTRING_LEN(vstr) ? " " : "", (str)); \
+    } while (0)
+
+    if (cipher_grade == 0) {
+       cipher_grade =
+           enforce_tls ? var_smtpd_tls_mand_ciph : "export";
+       cipher_exclusions = vstring_alloc(10);
+       ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_excl_ciph);
+       if (enforce_tls)
+           ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_mand_excl);
+       if (wantcert)
+           ADD_EXCLUDE(cipher_exclusions, "aNULL");
+    }
 
     /*
-     * XXX The client event count/rate control must be consistent in its use
-     * of client address information in connect and disconnect events. For
-     * now we exclude xclient authorized hosts from event count/rate control.
+     * Perform the TLS handshake now. Check the client certificate
+     * requirements later, if necessary.
+     */
+    state->tls_context =
+       TLS_SERVER_START(&props,
+                        ctx = smtpd_tls_ctx,
+                        stream = state->client,
+                        log_level = var_smtpd_tls_loglevel,
+                        timeout = var_smtpd_starttls_tmout,
+                        requirecert = (var_smtpd_tls_req_ccert
+                                       && state->tls_enforce_tls),
+                        serverid = state->service,
+                        namaddr = state->namaddr,
+                        cipher_grade = cipher_grade,
+                        cipher_exclusions = STR(cipher_exclusions),
+                        fpt_dgst = var_smtpd_tls_fpt_dgst);
+
+    /*
+     * For new (i.e. not re-used) TLS sessions, increment the client's new
+     * TLS session rate counter. We enforce the limit here only for human
+     * factors reasons (reduce the WTF factor), even though it is too late to
+     * save the CPU that was already burnt on PKI ops. The real safety
+     * mechanism applies with future STARTTLS commands (or wrappermode
+     * connections), prior to the SSL handshake.
+     * 
+     * XXX The client event count/rate control must be consistent in its use of
+     * client address information in connect and disconnect events. For now
+     * we exclude xclient authorized hosts from event count/rate control.
      */
     if (var_smtpd_cntls_limit > 0
        && state->tls_context
@@ -3751,6 +3792,31 @@ static void smtpd_start_tls(SMTPD_STATE *state)
     if (state->tls_context == 0)
        vstream_longjmp(state->client, SMTP_ERR_EOF);
 
+    /*
+     * If we are requiring verified client certs, enforce the constraint
+     * here. We have a usable TLS session with the client, so no need to
+     * disable I/O, ...  we can even be polite and send "421 ...".
+     */
+    if (props.requirecert && TLS_CERT_IS_TRUSTED(state->tls_context) == 0) {
+
+       /*
+        * Fetch and reject the next command (should be EHLO), then
+        * disconnect (side-effect of returning "421 ...".
+        */
+       cert_present = TLS_CERT_IS_PRESENT(state->tls_context);
+       msg_info("NOQUEUE: abort: TLS from %s: %s",
+                state->namaddr, cert_present ?
+                "Client certificate not trusted" :
+                "No client certificate presented");
+       smtpd_chat_query(state);
+       smtpd_chat_reply(state, "421 4.7.1 %s Error: %s",
+                        var_myhostname, cert_present ?
+                        "Client certificate not trusted" :
+                        "No client certificate presented");
+       state->error_mask |= MAIL_ERROR_POLICY;
+       return;
+    }
+
     /*
      * When TLS is turned on, we may offer AUTH methods that would not be
      * offered within a plain-text session.
@@ -3810,9 +3876,12 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
     }
 
     /*
-     * XXX The client event count/rate control must be consistent in its use
-     * of client address information in connect and disconnect events. For
-     * now we exclude xclient authorized hosts from event count/rate control.
+     * Enforce TLS handshake rate limit when this client negotiated too many
+     * new TLS sessions in the recent past.
+     * 
+     * XXX The client event count/rate control must be consistent in its use of
+     * client address information in connect and disconnect events. For now
+     * we exclude xclient authorized hosts from event count/rate control.
      */
     if (var_smtpd_cntls_limit > 0
        && SMTPD_STAND_ALONE(state) == 0
@@ -3974,10 +4043,11 @@ static void smtpd_proto(SMTPD_STATE *state)
         * the STARTTLS command. This code does not return when the handshake
         * fails.
         * 
-        * XXX We start TLS before we apply access control, concurrency or
-        * connection rate limits, so that we can inform the client why
-        * service is denied. This means we spend a lot of CPU just to tell
-        * the client that we don't provide service. TLS wrapper mode is
+        * Enforce TLS handshake rate limit when this client negotiated too many
+        * new TLS sessions in the recent past.
+        * 
+        * XXX This means we don't complete a TLS handshake just to tell the
+        * client that we don't provide service. TLS wrapper mode is
         * obsolete, so we don't have to provide perfect support.
         */
 #ifdef USE_TLS
@@ -4333,7 +4403,6 @@ static void pre_accept(char *unused_name, char **unused_argv)
 
 static void pre_jail_init(char *unused_name, char **unused_argv)
 {
-    int     enforce_tls;
     int     use_tls;
 
     /*
@@ -4379,15 +4448,18 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
      * security levels. We implement only a subset for now. If we implement
      * more levels, wrappermode should override only weaker TLS security
      * levels.
+     * 
+     * Note: tls_level_lookup() logs no warning.
      */
     if (!var_smtpd_tls_wrappermode && *var_smtpd_tls_level) {
        switch (tls_level_lookup(var_smtpd_tls_level)) {
        default:
-           msg_warn("%s: ignoring unknown TLS level \"%s\"",
-                    VAR_SMTPD_TLS_LEVEL, var_smtpd_tls_level);
+           msg_fatal("Invalid TLS level \"%s\"", var_smtpd_tls_level);
+           /* NOTREACHED */
            break;
        case TLS_LEV_SECURE:
        case TLS_LEV_VERIFY:
+       case TLS_LEV_FPRINT:
            msg_warn("%s: unsupported TLS level \"%s\", using \"encrypt\"",
                     VAR_SMTPD_TLS_LEVEL, var_smtpd_tls_level);
            /* FALLTHROUGH */
@@ -4414,33 +4486,10 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
     if (getuid() == 0 || getuid() == var_owner_uid) {
        if (use_tls) {
 #ifdef USE_TLS
-           tls_server_props props;
+           TLS_SERVER_INIT_PROPS props;
+           const char *cert_file;
            int     havecert;
            int     oknocert;
-           int     wantcert;
-
-           /*
-            * We get stronger type safety and a cleaner interface by
-            * combining the various parameters into a single
-            * tls_server_props structure.
-            */
-           props.log_level = var_smtpd_tls_loglevel;
-           props.verifydepth = var_smtpd_tls_ccert_vd;
-           props.cache_type = TLS_MGR_SCACHE_SMTPD;
-           props.scache_timeout = var_smtpd_tls_scache_timeout;
-           props.set_sessid = var_smtpd_tls_set_sessid;
-           props.cert_file = var_smtpd_tls_cert_file;
-           props.key_file = var_smtpd_tls_key_file;
-           props.dcert_file = var_smtpd_tls_dcert_file;
-           props.dkey_file = var_smtpd_tls_dkey_file;
-           props.CAfile = var_smtpd_tls_CAfile;
-           props.CApath = var_smtpd_tls_CApath;
-           props.dh1024_param_file = var_smtpd_tls_dh1024_param_file;
-           props.dh512_param_file = var_smtpd_tls_dh512_param_file;
-           props.protocols = enforce_tls && *var_smtpd_tls_mand_proto ?
-               tls_protocol_mask(VAR_SMTPD_TLS_MAND_PROTO,
-                                 var_smtpd_tls_mand_proto) : 0;
-           props.ask_ccert = var_smtpd_tls_ask_ccert;
 
            /*
             * Can't use anonymous ciphers if we want client certificates.
@@ -4448,47 +4497,53 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
             * 
             * XXX: Ugh! Too many booleans!
             */
-           wantcert = props.ask_ccert;
-           wantcert |= enforce_tls && var_smtpd_tls_req_ccert;
-           oknocert = strcasecmp(props.cert_file, "none") == 0;
-           if (oknocert)
-               props.cert_file = "";
-           havecert = *props.cert_file || *props.dcert_file;
+           wantcert = (var_smtpd_tls_ask_ccert
+                       || (enforce_tls && var_smtpd_tls_req_ccert));
+           if (strcasecmp(var_smtpd_tls_cert_file, "none") == 0) {
+               oknocert = 1;
+               cert_file = "";
+           } else {
+               oknocert = 0;
+               cert_file = var_smtpd_tls_cert_file;
+           }
+           havecert =
+               (*cert_file || *var_smtpd_tls_dcert_file);
 
+           /* Some TLS configuration errors are not show stoppers. */
            if (!havecert && wantcert)
                msg_warn("Need a server cert to request client certs");
            if (!enforce_tls && var_smtpd_tls_req_ccert)
                msg_warn("Can't require client certs unless TLS is required");
-
-           props.cipherlist =
-               tls_cipher_list(enforce_tls ?
-                               tls_cipher_level(var_smtpd_tls_mand_ciph) :
-                               TLS_CIPHER_EXPORT,
-                               var_smtpd_tls_excl_ciph,
-                               havecert ? "" : "aRSA aDSS",
-                               wantcert ? "aNULL" : "",
-                               enforce_tls ? var_smtpd_tls_mand_excl :
-                               TLS_END_EXCLUDE,
-                               TLS_END_EXCLUDE);
-
-           if (props.cipherlist == 0) {
-               msg_warn("unknown '%s' value '%s' ignored, using 'export'",
-                        VAR_SMTPD_TLS_MAND_CIPH, var_smtpd_tls_mand_ciph);
-               props.cipherlist =
-                   tls_cipher_list(TLS_CIPHER_EXPORT,
-                                   var_smtpd_tls_excl_ciph,
-                                   havecert ? "" : "aRSA aDSS",
-                                   wantcert ? "aNULL" : "",
-                                   enforce_tls ? var_smtpd_tls_mand_excl :
-                                   TLS_END_EXCLUDE,
-                                   TLS_END_EXCLUDE);
-               if (props.cipherlist == 0)
-                   msg_panic("NULL export cipherlist");
-           }
-           if (havecert || oknocert)
-               smtpd_tls_ctx = tls_server_init(&props);
-           else if (enforce_tls)
-               msg_fatal("No server certs available. TLS can't be enabled");
+           /* After a show-stopper error, reply with 454 to STARTTLS. */
+           if (havecert || (oknocert && !wantcert))
+
+               /*
+                * Large parameter lists are error-prone, so we emulate a
+                * language feature that C does not have natively: named
+                * parameter lists.
+                */
+               smtpd_tls_ctx =
+                   TLS_SERVER_INIT(&props,
+                                   log_level = var_smtpd_tls_loglevel,
+                                   verifydepth = var_smtpd_tls_ccert_vd,
+                                   cache_type = TLS_MGR_SCACHE_SMTPD,
+                                   scache_timeout
+                                   = var_smtpd_tls_scache_timeout,
+                                   set_sessid = var_smtpd_tls_set_sessid,
+                                   cert_file = cert_file,
+                                   key_file = var_smtpd_tls_key_file,
+                                   dcert_file = var_smtpd_tls_dcert_file,
+                                   dkey_file = var_smtpd_tls_dkey_file,
+                                   CAfile = var_smtpd_tls_CAfile,
+                                   CApath = var_smtpd_tls_CApath,
+                                   dh1024_param_file
+                                   = var_smtpd_tls_dh1024_param_file,
+                                   dh512_param_file
+                                   = var_smtpd_tls_dh512_param_file,
+                                   protocols = enforce_tls ?
+                                   var_smtpd_tls_mand_proto : "",
+                                   ask_ccert = var_smtpd_tls_ask_ccert,
+                                   fpt_dgst = var_smtpd_tls_fpt_dgst);
            else
                msg_warn("No server certs available. TLS won't be enabled");
 #else
@@ -4579,7 +4634,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_SMTPD_RCPT_LIMIT, DEF_SMTPD_RCPT_LIMIT, &var_smtpd_rcpt_limit, 1, 0,
        VAR_SMTPD_SOFT_ERLIM, DEF_SMTPD_SOFT_ERLIM, &var_smtpd_soft_erlim, 1, 0,
        VAR_SMTPD_HARD_ERLIM, DEF_SMTPD_HARD_ERLIM, &var_smtpd_hard_erlim, 1, 0,
@@ -4614,11 +4669,10 @@ int     main(int argc, char **argv)
 #ifdef USE_TLS
        VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
        VAR_SMTPD_TLS_LOGLEVEL, DEF_SMTPD_TLS_LOGLEVEL, &var_smtpd_tls_loglevel, 0, 0,
-       VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 1, 0,
 #endif
        0,
     };
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_SMTPD_TMOUT, DEF_SMTPD_TMOUT, &var_smtpd_tmout, 1, 0,
        VAR_SMTPD_ERR_SLEEP, DEF_SMTPD_ERR_SLEEP, &var_smtpd_err_sleep, 0, 0,
        VAR_SMTPD_PROXY_TMOUT, DEF_SMTPD_PROXY_TMOUT, &var_smtpd_proxy_tmout, 1, 0,
@@ -4635,7 +4689,7 @@ int     main(int argc, char **argv)
        VAR_MILT_MSG_TIME, DEF_MILT_MSG_TIME, &var_milt_msg_time, 1, 0,
        0,
     };
-    static CONFIG_BOOL_TABLE bool_table[] = {
+    static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_HELO_REQUIRED, DEF_HELO_REQUIRED, &var_helo_required,
        VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
        VAR_STRICT_RFC821_ENV, DEF_STRICT_RFC821_ENV, &var_strict_rfc821_env,
@@ -4662,7 +4716,7 @@ int     main(int argc, char **argv)
        VAR_SMTPD_CLIENT_PORT_LOG, DEF_SMTPD_CLIENT_PORT_LOG, &var_smtpd_client_port_log,
        0,
     };
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0,
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
        VAR_CLIENT_CHECKS, DEF_CLIENT_CHECKS, &var_client_checks, 0, 0,
@@ -4717,14 +4771,10 @@ int     main(int argc, char **argv)
        VAR_SMTPD_TLS_MAND_CIPH, DEF_SMTPD_TLS_MAND_CIPH, &var_smtpd_tls_mand_ciph, 1, 0,
        VAR_SMTPD_TLS_EXCL_CIPH, DEF_SMTPD_TLS_EXCL_CIPH, &var_smtpd_tls_excl_ciph, 0, 0,
        VAR_SMTPD_TLS_MAND_EXCL, DEF_SMTPD_TLS_MAND_EXCL, &var_smtpd_tls_mand_excl, 0, 0,
-       VAR_TLS_HIGH_CLIST, DEF_TLS_HIGH_CLIST, &var_tls_high_clist, 1, 0,
-       VAR_TLS_MEDIUM_CLIST, DEF_TLS_MEDIUM_CLIST, &var_tls_medium_clist, 1, 0,
-       VAR_TLS_LOW_CLIST, DEF_TLS_LOW_CLIST, &var_tls_low_clist, 1, 0,
-       VAR_TLS_EXPORT_CLIST, DEF_TLS_EXPORT_CLIST, &var_tls_export_clist, 1, 0,
-       VAR_TLS_NULL_CLIST, DEF_TLS_NULL_CLIST, &var_tls_null_clist, 1, 0,
        VAR_SMTPD_TLS_MAND_PROTO, DEF_SMTPD_TLS_MAND_PROTO, &var_smtpd_tls_mand_proto, 0, 0,
        VAR_SMTPD_TLS_512_FILE, DEF_SMTPD_TLS_512_FILE, &var_smtpd_tls_dh512_param_file, 0, 0,
        VAR_SMTPD_TLS_1024_FILE, DEF_SMTPD_TLS_1024_FILE, &var_smtpd_tls_dh1024_param_file, 0, 0,
+       VAR_SMTPD_TLS_FPT_DGST, DEF_SMTPD_TLS_FPT_DGST, &var_smtpd_tls_fpt_dgst, 1, 0,
 #endif
        VAR_SMTPD_TLS_LEVEL, DEF_SMTPD_TLS_LEVEL, &var_smtpd_tls_level, 0, 0,
        VAR_SMTPD_SASL_TYPE, DEF_SMTPD_SASL_TYPE, &var_smtpd_sasl_type, 1, 0,
@@ -4744,7 +4794,7 @@ int     main(int argc, char **argv)
        VAR_STRESS, DEF_STRESS, &var_stress, 0, 0,
        0,
     };
-    static CONFIG_RAW_TABLE raw_table[] = {
+    static const CONFIG_RAW_TABLE raw_table[] = {
        VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter, 1, 0,
        VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply, 1, 0,
        0,
index b4e1aeb8a8172ab0d57883eff72db41744e514fc..899bb70f4e7094f1c0f5393bbfc2545cfafef56f 100644 (file)
@@ -170,7 +170,7 @@ typedef struct SMTPD_STATE {
     int     tls_use_tls;               /* can use TLS */
     int     tls_enforce_tls;           /* must use TLS */
     int     tls_auth_only;             /* use SASL over TLS only */
-    TLScontext_t *tls_context;         /* TLS session state */
+    TLS_SESS_STATE *tls_context;       /* TLS session state */
 #endif
 
     /*
index 81839bd39bc5ed64cd4ab541d6625492b6878d18..f1c0366da96d7d4d0ea50d094a6ea419c39c36a0 100644 (file)
@@ -1228,7 +1228,7 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
     if (!state->tls_context)
        return SMTPD_CHECK_DUNNO;
 
-    if (state->tls_context->peer_verified && permit_all_certs) {
+    if (TLS_CERT_IS_TRUSTED(state->tls_context) && permit_all_certs) {
        if (msg_verbose)
            msg_info("Relaying allowed for all verified client certificates");
        return (SMTPD_CHECK_OK);
@@ -1238,7 +1238,7 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
      * When directly checking the fingerprint, it is OK if the issuing CA is
      * not trusted.
      */
-    if (state->tls_context->peer_fingerprint) {
+    if (TLS_CERT_IS_PRESENT(state->tls_context)) {
        found = maps_find(relay_ccerts, state->tls_context->peer_fingerprint,
                          DICT_FLAG_NONE);
        if (found) {
@@ -2618,14 +2618,11 @@ static int check_ccert_access(SMTPD_STATE *state, const char *table,
     const char *myname = "check_ccert_access";
     int     found;
 
-    if (!state->tls_context)
-       return SMTPD_CHECK_DUNNO;
-
     /*
      * When directly checking the fingerprint, it is OK if the issuing CA is
      * not trusted.
      */
-    if (state->tls_context->peer_fingerprint) {
+    if (TLS_CERT_IS_PRESENT(state->tls_context)) {
        if (msg_verbose)
            msg_info("%s: %s", myname, state->tls_context->peer_fingerprint);
 
@@ -3323,8 +3320,7 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
 
 #ifdef USE_TLS
 #define ENCODE_CN(coded_CN, coded_CN_buf, CN) do { \
-       if (state->tls_context == 0 \
-           || state->tls_context->peer_verified == 0 || (CN) == 0) { \
+       if (!TLS_CERT_IS_TRUSTED(state->tls_context) || *(CN) == 0) { \
            coded_CN_buf = 0; \
            coded_CN = ""; \
        } else { \
@@ -3379,14 +3375,9 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
                          state->sasl_sender : "",
 #endif
 #ifdef USE_TLS
-#define IF_VERIFIED(x) \
-    ((state->tls_context && \
-      state->tls_context->peer_verified && ((x) != 0)) ? (x) : "")
 #define IF_ENCRYPTED(x, y) ((state->tls_context && ((x) != 0)) ? (x) : (y))
-                         ATTR_TYPE_STR, MAIL_ATTR_CCERT_SUBJECT,
-                         IF_VERIFIED(subject),
-                         ATTR_TYPE_STR, MAIL_ATTR_CCERT_ISSUER,
-                         IF_VERIFIED(issuer),
+                         ATTR_TYPE_STR, MAIL_ATTR_CCERT_SUBJECT, subject,
+                         ATTR_TYPE_STR, MAIL_ATTR_CCERT_ISSUER, issuer,
 
     /*
      * When directly checking the fingerprint, it is OK if the issuing CA is
@@ -4718,7 +4709,7 @@ typedef struct {
 #undef DEF_LOCAL_RCPT_MAPS
 #define DEF_LOCAL_RCPT_MAPS    ""
 
-static STRING_TABLE string_table[] = {
+static const STRING_TABLE string_table[] = {
     VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains,
     VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin,
     VAR_MYDEST, DEF_MYDEST, &var_mydest,
@@ -4817,7 +4808,7 @@ int     var_smtpd_rej_unl_rcpt;
 int     var_plaintext_code;
 bool    var_smtpd_peername_lookup;
 
-static INT_TABLE int_table[] = {
+static const INT_TABLE int_table[] = {
     "msg_verbose", 0, &msg_verbose,
     VAR_UNK_CLIENT_CODE, DEF_UNK_CLIENT_CODE, &var_unk_client_code,
     VAR_BAD_NAME_CODE, DEF_BAD_NAME_CODE, &var_bad_name_code,
@@ -4882,7 +4873,7 @@ typedef struct {
     ARGV  **target;
 } REST_TABLE;
 
-static REST_TABLE rest_table[] = {
+static const REST_TABLE rest_table[] = {
     "client_restrictions", &client_restrctions,
     "helo_restrictions", &helo_restrctions,
     "sender_restrictions", &mail_restrctions,
index 356debed5d7211414257ff7a1d943c804671e403..28693b6f7473f45d4712df22fbfff6e6fdb96446 100644 (file)
@@ -114,8 +114,7 @@ const char *smtpd_milter_eval(const char *name, void *ptr)
      */
 #ifdef USE_TLS
 #define IF_ENCRYPTED(x) (state->tls_context ? (x) : 0)
-#define IF_VERIFIED(x) \
-    (state->tls_context && state->tls_context->peer_verified ? (x) : 0)
+#define IF_TRUSTED(x) (TLS_CERT_IS_TRUSTED(state->tls_context) ? (x) : 0)
 
     if (strcmp(name, S8_MAC_TLS_VERSION) == 0)
        return (IF_ENCRYPTED(state->tls_context->protocol));
@@ -131,9 +130,9 @@ const char *smtpd_milter_eval(const char *name, void *ptr)
        return (STR(state->expand_buf));
     }
     if (strcmp(name, S8_MAC_CERT_SUBJECT) == 0)
-       return (IF_VERIFIED(state->tls_context->peer_CN));
+       return (IF_TRUSTED(state->tls_context->peer_CN));
     if (strcmp(name, S8_MAC_CERT_ISSUER) == 0)
-       return (IF_VERIFIED(state->tls_context->issuer_CN));
+       return (IF_TRUSTED(state->tls_context->issuer_CN));
 #endif
 
     /*
index e4804de8f628ed5557dc9f7eb5492ab30db542eb..c2fa84102bde04b3563d82b95030685b41924182 100644 (file)
@@ -255,7 +255,7 @@ int     smtpd_proxy_open(SMTPD_STATE *state, const char *service,
     VSTRING *buf;
     int     bad;
     char   *word;
-    static NAME_CODE xforward_features[] = {
+    static const NAME_CODE xforward_features[] = {
        XFORWARD_NAME, SMTPD_PROXY_XFORWARD_NAME,
        XFORWARD_ADDR, SMTPD_PROXY_XFORWARD_ADDR,
        XFORWARD_PORT, SMTPD_PROXY_XFORWARD_PORT,
@@ -264,7 +264,7 @@ int     smtpd_proxy_open(SMTPD_STATE *state, const char *service,
        XFORWARD_DOMAIN, SMTPD_PROXY_XFORWARD_DOMAIN,
        0, 0,
     };
-    CLEANUP_STAT_DETAIL *detail;
+    const CLEANUP_STAT_DETAIL *detail;
     int     (*connect_fn) (const char *, int, int);
     const char *endpoint;
 
@@ -460,7 +460,7 @@ int     smtpd_proxy_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
     int     last_char;
     int     err = 0;
     static VSTRING *buffer = 0;
-    CLEANUP_STAT_DETAIL *detail;
+    const CLEANUP_STAT_DETAIL *detail;
 
     /*
      * Errors first. Be prepared for delayed errors from the DATA phase.
index 3e06138710f0ba56e34583b824fd5a8366e4259e..3ef6228f54e53b7a4f0357f71da7381dbc2f9441 100644 (file)
@@ -346,7 +346,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_COMMAND_MAXTIME, DEF_COMMAND_MAXTIME, &var_command_maxtime, 1, 0,
        0,
     };
index d3e21510a078dc1dde171d3b825f939a41eedbbe..9ebaae1e427ac52581169f66637a67b1870d29c5 100644 (file)
@@ -89,6 +89,7 @@ depend: $(MAKES)
        @$(EXPORT) make -f Makefile.in Makefile 1>&2
 
 # do not edit below this line - it is generated by 'make depend'
+tls_bio_ops.o: ../../include/argv.h
 tls_bio_ops.o: ../../include/iostuff.h
 tls_bio_ops.o: ../../include/msg.h
 tls_bio_ops.o: ../../include/name_code.h
@@ -99,6 +100,7 @@ tls_bio_ops.o: ../../include/vstream.h
 tls_bio_ops.o: ../../include/vstring.h
 tls_bio_ops.o: tls.h
 tls_bio_ops.o: tls_bio_ops.c
+tls_certkey.o: ../../include/argv.h
 tls_certkey.o: ../../include/msg.h
 tls_certkey.o: ../../include/name_code.h
 tls_certkey.o: ../../include/name_mask.h
@@ -122,6 +124,7 @@ tls_client.o: ../../include/vstring.h
 tls_client.o: tls.h
 tls_client.o: tls_client.c
 tls_client.o: tls_mgr.h
+tls_dh.o: ../../include/argv.h
 tls_dh.o: ../../include/msg.h
 tls_dh.o: ../../include/name_code.h
 tls_dh.o: ../../include/name_mask.h
@@ -131,6 +134,7 @@ tls_dh.o: ../../include/vstream.h
 tls_dh.o: ../../include/vstring.h
 tls_dh.o: tls.h
 tls_dh.o: tls_dh.c
+tls_level.o: ../../include/argv.h
 tls_level.o: ../../include/name_code.h
 tls_level.o: ../../include/name_mask.h
 tls_level.o: ../../include/sys_defs.h
@@ -152,6 +156,8 @@ tls_mgr.o: ../../include/vstring.h
 tls_mgr.o: tls_mgr.c
 tls_mgr.o: tls_mgr.h
 tls_misc.o: ../../include/argv.h
+tls_misc.o: ../../include/mail_conf.h
+tls_misc.o: ../../include/mail_params.h
 tls_misc.o: ../../include/msg.h
 tls_misc.o: ../../include/mymalloc.h
 tls_misc.o: ../../include/name_code.h
@@ -191,6 +197,7 @@ tls_prng_file.o: ../../include/mymalloc.h
 tls_prng_file.o: ../../include/sys_defs.h
 tls_prng_file.o: tls_prng.h
 tls_prng_file.o: tls_prng_file.c
+tls_rsa.o: ../../include/argv.h
 tls_rsa.o: ../../include/name_code.h
 tls_rsa.o: ../../include/name_mask.h
 tls_rsa.o: ../../include/sys_defs.h
@@ -212,6 +219,7 @@ tls_scache.o: ../../include/vstream.h
 tls_scache.o: ../../include/vstring.h
 tls_scache.o: tls_scache.c
 tls_scache.o: tls_scache.h
+tls_seed.o: ../../include/argv.h
 tls_seed.o: ../../include/msg.h
 tls_seed.o: ../../include/name_code.h
 tls_seed.o: ../../include/name_mask.h
@@ -238,6 +246,7 @@ tls_server.o: ../../include/vstring.h
 tls_server.o: tls.h
 tls_server.o: tls_mgr.h
 tls_server.o: tls_server.c
+tls_session.o: ../../include/argv.h
 tls_session.o: ../../include/msg.h
 tls_session.o: ../../include/mymalloc.h
 tls_session.o: ../../include/name_code.h
@@ -248,6 +257,7 @@ tls_session.o: ../../include/vstream.h
 tls_session.o: ../../include/vstring.h
 tls_session.o: tls.h
 tls_session.o: tls_session.c
+tls_stream.o: ../../include/argv.h
 tls_stream.o: ../../include/iostuff.h
 tls_stream.o: ../../include/msg.h
 tls_stream.o: ../../include/name_code.h
@@ -258,10 +268,12 @@ tls_stream.o: ../../include/vstream.h
 tls_stream.o: ../../include/vstring.h
 tls_stream.o: tls.h
 tls_stream.o: tls_stream.c
+tls_verify.o: ../../include/argv.h
 tls_verify.o: ../../include/msg.h
 tls_verify.o: ../../include/mymalloc.h
 tls_verify.o: ../../include/name_code.h
 tls_verify.o: ../../include/name_mask.h
+tls_verify.o: ../../include/stringops.h
 tls_verify.o: ../../include/sys_defs.h
 tls_verify.o: ../../include/vbuf.h
 tls_verify.o: ../../include/vstream.h
index b3ca996fe6cc8828ce143ff4a9fbaa48d6b9b726..058d7676ade66549cbaa49fec1cb17a6c6df375b 100644 (file)
   * Utility library.
   */
 #include <name_code.h>
+#include <argv.h>
 
  /*
   * TLS enforcement levels. Non-sentinel values may also be used to indicate
   * the actual security level of a session.
+  * 
+  * XXX TLS_LEV_NOTFOUND no longer belongs in this list. The SMTP client will
+  * have to use something else to report that policy table lookup failed.
   */
-#define TLS_LEV_NOTFOUND       -1      /* sentinel */
+#define TLS_LEV_INVALID                -2      /* sentinel */
+#define TLS_LEV_NOTFOUND       -1      /* XXX not in policy table */
 #define TLS_LEV_NONE           0       /* plain-text only */
 #define TLS_LEV_MAY            1       /* wildcard */
 #define TLS_LEV_ENCRYPT                2       /* encrypted connection */
-#define TLS_LEV_VERIFY         3       /* certificate verified */
-#define TLS_LEV_SECURE         4       /* "secure" verification */
+#define TLS_LEV_FPRINT         3       /* "peer" CA-less verification */
+#define TLS_LEV_VERIFY         4       /* certificate verified */
+#define TLS_LEV_SECURE         5       /* "secure" verification */
 
-extern NAME_CODE tls_level_table[];
+extern const NAME_CODE tls_level_table[];
 
 #define tls_level_lookup(s) name_code(tls_level_table, NAME_CODE_FLAG_NONE, (s))
 #define str_tls_level(l) str_name_code(tls_level_table, (l))
@@ -69,42 +75,93 @@ extern NAME_CODE tls_level_table[];
  /*
   * TLS session context, also used by the VSTREAM call-back routines for SMTP
   * input/output, and by OpenSSL call-back routines for key verification.
+  * 
+  * Only some members are (read-only) accessible by the public.
   */
 #define CCERT_BUFSIZ   256
 
 typedef struct {
-    SSL    *con;
-    BIO    *internal_bio;              /* postfix/TLS side of pair */
-    BIO    *network_bio;               /* network side of pair */
-    char   *cache_type;                        /* tlsmgr(8) cache type if enabled */
-    char   *serverid;                  /* unique server identifier */
+    /* Public, read-only. */
     char   *peer_CN;                   /* Peer Common Name */
     char   *issuer_CN;                 /* Issuer Common Name */
     char   *peer_fingerprint;          /* ASCII fingerprint */
-    char   *peername;
-    int     enforce_verify_errors;
-    int     enforce_CN;
-    int     hostname_matched;
-    int     peer_verified;
+    int     peer_status;               /* Certificate and match status */
     const char *protocol;
     const char *cipher_name;
     int     cipher_usebits;
     int     cipher_algbits;
+    /* Private. */
+    SSL    *con;
+    BIO    *internal_bio;              /* postfix/TLS side of pair */
+    BIO    *network_bio;               /* network side of pair */
+    char   *cache_type;                        /* tlsmgr(8) cache type if enabled */
+    char   *serverid;                  /* unique server identifier */
+    char   *namaddr;                   /* nam[addr] for logging */
+    int     tls_level;                 /* Application security level */
     int     log_level;                 /* TLS library logging level */
     int     session_reused;            /* this session was reused */
-} TLScontext_t;
+    int     am_server;                 /* Are we an SSL server or client? */
+} TLS_SESS_STATE;
+
+ /*
+  * Peer status bits. TLS_CERT_FLAG_MATCHED implies TLS_CERT_FLAG_TRUSTED
+  * only in the case of a hostname match.
+  */
+#define TLS_CERT_FLAG_PRESENT          (1<<0)
+#define TLS_CERT_FLAG_ALTNAME          (1<<1)
+#define TLS_CERT_FLAG_TRUSTED          (1<<2)
+#define TLS_CERT_FLAG_MATCHED          (1<<3)
+#define TLS_CERT_FLAG_LOGGED           (1<<4)  /* Logged trust chain error */
+
+#define TLS_CERT_IS_PRESENT(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_PRESENT))
+#define TLS_CERT_IS_ALTNAME(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_ALTNAME))
+#define TLS_CERT_IS_TRUSTED(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_TRUSTED))
+#define TLS_CERT_IS_MATCHED(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_MATCHED))
+
+ /*
+  * Opaque client context handle.
+  */
+typedef struct TLS_APPL_STATE TLS_APPL_STATE;
+
+#ifdef TLS_INTERNAL
+
+ /*
+  * Client and Server application contexts
+  */
+struct TLS_APPL_STATE {
+    SSL_CTX *ssl_ctx;
+    char   *cache_type;
+    char   *cipher_exclusions;         /* Last cipher selection state */
+    char   *cipher_list;               /* Last cipher selection state */
+    int     cipher_grade;              /* Last cipher selection state */
+    VSTRING *why;
+};
+
+ /*
+  * tls_misc.c One time finalization of application context.
+  */
+extern void tls_free_app_context(TLS_APPL_STATE *);
+
+ /*
+  * tls_misc.c
+  */
+
+extern void tls_param_init(void);
 
  /*
-  * Client protocol selection bitmask
+  * Protocol selection.
   */
+#define TLS_PROTOCOL_INVALID   (~0)    /* All protocol bits masked */
 #define TLS_PROTOCOL_SSLv2     (1<<0)  /* SSLv2 */
 #define TLS_PROTOCOL_SSLv3     (1<<1)  /* SSLv3 */
 #define TLS_PROTOCOL_TLSv1     (1<<2)  /* TLSv1 */
-#define TLS_ALL_PROTOCOLS      \
+#define TLS_KNOWN_PROTOCOLS    \
        ( TLS_PROTOCOL_SSLv2 | TLS_PROTOCOL_SSLv3 | TLS_PROTOCOL_TLSv1 )
 
+extern int tls_protocol_mask(const char *);
+
  /*
-  * tls_misc.c
+  * Cipher grade selection.
   */
 #define TLS_CIPHER_NONE                0
 #define TLS_CIPHER_NULL                1
@@ -113,24 +170,20 @@ typedef struct {
 #define TLS_CIPHER_MEDIUM      4
 #define TLS_CIPHER_HIGH                5
 
-extern NAME_MASK tls_protocol_table[];
-extern NAME_CODE tls_cipher_level_table[];
-
-#define tls_protocol_mask(tag, protocols) \
-    name_mask_delim_opt((tag), tls_protocol_table, (protocols), \
-                       ":" NAME_MASK_DEFAULT_DELIM, \
-                       NAME_MASK_ANY_CASE | NAME_MASK_RETURN)
+extern const NAME_CODE tls_cipher_grade_table[];
 
-#define tls_protocol_names(tag, mask) \
-    str_name_mask_opt((VSTRING *)0, (tag), tls_protocol_table, (mask), \
-                     NAME_MASK_FATAL|NAME_MASK_COMMA)
+#define tls_cipher_grade(str) \
+    name_code(tls_cipher_grade_table, NAME_CODE_FLAG_NONE, (str))
+#define str_tls_cipher_grade(gr) \
+    str_name_code(tls_cipher_grade_table, (gr))
 
-#define tls_cipher_level(str) \
-    name_code(tls_cipher_level_table, NAME_CODE_FLAG_NONE, (str))
+ /*
+  * Cipher lists with exclusions.
+  */
+extern const char *tls_set_ciphers(TLS_APPL_STATE *, const char *,
+                                          const char *, const char *);
 
-#define TLS_END_EXCLUDE ((char *)0)
-extern const char *tls_cipher_list(int,...);
-extern const char *tls_set_cipher_list(SSL_CTX *, const char *);
+#endif
 
  /*
   * tls_client.c
@@ -145,27 +198,44 @@ typedef struct {
     const char *dkey_file;
     const char *CAfile;
     const char *CApath;
-} tls_client_init_props;
+    const char *fpt_dgst;              /* Fingerprint digest algorithm */
+} TLS_CLIENT_INIT_PROPS;
 
 typedef struct {
-    SSL_CTX *ctx;
+    TLS_APPL_STATE *ctx;
     VSTREAM *stream;
     int     log_level;
     int     timeout;
     int     tls_level;                 /* Security level */
-    char   *nexthop;                   /* destination domain */
-    char   *host;                      /* MX hostname */
-    char   *serverid;                  /* Session cache key */
-    int     protocols;                 /* Encrypt level protocols, 0 => all */
-    char   *cipherlist;                        /* Encrypt level ciphers */
-    char   *certmatch;                 /* Verify level match patterns */
-} tls_client_start_props;
-
-extern SSL_CTX *tls_client_init(const tls_client_init_props *);
-extern TLScontext_t *tls_client_start(const tls_client_start_props *);
-
-#define tls_client_stop(ctx , stream, timeout, failure, TLScontext) \
-       tls_session_stop((ctx), (stream), (timeout), (failure), (TLScontext))
+    const char *nexthop;               /* destination domain */
+    const char *host;                  /* MX hostname */
+    const char *namaddr;               /* nam[addr] for logging */
+    const char *serverid;              /* Session cache key */
+    const char *protocols;             /* Enabled protocols */
+    const char *cipher_grade;          /* Minimum cipher grade */
+    const char *cipher_exclusions;     /* Ciphers to exclude */
+    const ARGV *matchargv;             /* Cert match patterns */
+    const char *fpt_dgst;              /* Fingerprint digest algorithm */
+} TLS_CLIENT_START_PROPS;
+
+extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *);
+extern TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *);
+
+#define tls_client_stop(ctx, stream, timeout, failure, TLScontext) \
+       tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext))
+
+#define TLS_CLIENT_INIT(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
+    a10) \
+    tls_client_init((((props)->a1), ((props)->a2), ((props)->a3), \
+    ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
+    ((props)->a8), ((props)->a9), ((props)->a10), (props)))
+
+#define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
+    a10, a11, a12, a13, a14) \
+    tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \
+    ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
+    ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
+    ((props)->a12), ((props)->a13), ((props)->a14), (props)))
 
  /*
   * tls_server.c
@@ -182,35 +252,49 @@ typedef struct {
     const char *dkey_file;
     const char *CAfile;
     const char *CApath;
-    const char *cipherlist;
-    int     protocols;                 /* protocols, 0 => all */
+    const char *protocols;
     const char *dh1024_param_file;
     const char *dh512_param_file;
     int     ask_ccert;
-} tls_server_props;
+    const char *fpt_dgst;              /* Fingerprint digest algorithm */
+} TLS_SERVER_INIT_PROPS;
 
 typedef struct {
-    SSL_CTX *ctx;                      /* SSL application context */
+    TLS_APPL_STATE *ctx;               /* TLS application context */
     VSTREAM *stream;                   /* Client stream */
     int     log_level;                 /* TLS log level */
     int     timeout;                   /* TLS handshake timeout */
     int     requirecert;               /* Insist on client cert? */
-    char   *serverid;                  /* Server instance (salt cache key) */
-    char   *peername;                  /* Client name */
-    char   *peeraddr;                  /* Client address */
-} tls_server_start_props;
-
-extern SSL_CTX *tls_server_init(const tls_server_props *);
-extern TLScontext_t *tls_server_start(const tls_server_start_props *props);
-
-#define tls_server_stop(ctx , stream, timeout, failure, TLScontext) \
-       tls_session_stop((ctx), (stream), (timeout), (failure), (TLScontext))
+    const char *serverid;              /* Server instance (salt cache key) */
+    const char *namaddr;               /* Client nam[addr] for logging */
+    const char *cipher_grade;
+    const char *cipher_exclusions;
+    const char *fpt_dgst;              /* Fingerprint digest algorithm */
+} TLS_SERVER_START_PROPS;
+
+extern TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *);
+extern TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props);
+
+#define tls_server_stop(ctx, stream, timeout, failure, TLScontext) \
+       tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext))
+
+#define TLS_SERVER_INIT(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
+    a10, a11, a12, a13, a14, a15, a16) \
+    tls_server_init((((props)->a1), ((props)->a2), ((props)->a3), \
+    ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
+    ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
+    ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
+    ((props)->a16), (props)))
+
+#define TLS_SERVER_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
+    tls_server_start((((props)->a1), ((props)->a2), ((props)->a3), \
+    ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
+    ((props)->a8), ((props)->a9), ((props)->a10), (props)))
 
  /*
   * tls_session.c
   */
-extern void tls_session_stop(SSL_CTX *, VSTREAM *, int, int,
-                                    TLScontext_t *);
+extern void tls_session_stop(TLS_APPL_STATE *, VSTREAM *, int, int, TLS_SESS_STATE *);
 
 #ifdef TLS_INTERNAL
 
@@ -222,7 +306,7 @@ extern SSL_SESSION *tls_session_activate(const char *, int);
  /*
   * tls_stream.c.
   */
-extern void tls_stream_start(VSTREAM *, TLScontext_t *);
+extern void tls_stream_start(VSTREAM *, TLS_SESS_STATE *);
 extern void tls_stream_stop(VSTREAM *);
 
  /*
@@ -231,7 +315,7 @@ extern void tls_stream_stop(VSTREAM *);
   * Because of its ugly multi-personality user interface we invoke it via
   * not-so-ugly single-personality wrappers.
   */
-extern int tls_bio(int, int, TLScontext_t *,
+extern int tls_bio(int, int, TLS_SESS_STATE *,
                           int (*) (SSL *),     /* handshake */
                           int (*) (SSL *, void *, int),        /* read */
                           int (*) (SSL *, const void *, int),  /* write */
@@ -268,8 +352,10 @@ extern RSA *tls_tmp_rsa_cb(SSL *, int, int);
  /*
   * tls_verify.c
   */
-extern char *tls_peer_CN(X509 *);
-extern char *tls_issuer_CN(X509 *);
+extern char *tls_peer_CN(X509 *, const TLS_SESS_STATE *);
+extern char *tls_issuer_CN(X509 *, const TLS_SESS_STATE *);
+extern const char *tls_dns_name(const GENERAL_NAME *, const TLS_SESS_STATE *);
+extern char *tls_fingerprint(X509 *, const char *);
 extern int tls_verify_certificate_callback(int, X509_STORE_CTX *);
 
  /*
@@ -285,10 +371,10 @@ extern int tls_set_my_certificate_key_info(SSL_CTX *, const char *,
   * tls_misc.c
   */
 extern int TLScontext_index;
-extern int TLSscache_index;
 
-extern TLScontext_t *tls_alloc_context(int, const char *);
-extern void tls_free_context(TLScontext_t *);
+extern TLS_APPL_STATE *tls_alloc_app_context(SSL_CTX *);
+extern TLS_SESS_STATE *tls_alloc_sess_context(int, const char *);
+extern void tls_free_context(TLS_SESS_STATE *);
 extern void tls_check_version(void);
 extern long tls_bug_bits(void);
 extern void tls_print_errors(void);
@@ -312,6 +398,9 @@ extern int tls_ext_seed(int);
 /*      IBM T.J. Watson Research
 /*      P.O. Box 704
 /*      Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 #endif                                 /* USE_TLS */
index bc359baf85561dfd88cc5d833e983852008951ed..39e0b66cb4c58ae5b73cfa71f47bca5a01eceab6 100644 (file)
 /*     int tls_bio_connect(fd, timeout, context)
 /*     int     fd;
 /*     int     timeout;
-/*     TLScontext_t *context;
+/*     TLS_SESS_STATE *context;
 /*
 /*     int tls_bio_accept(fd, timeout, context)
 /*     int     fd;
 /*     int     timeout;
-/*     TLScontext_t *context;
+/*     TLS_SESS_STATE *context;
 /*
 /*     int tls_bio_shutdown(fd, timeout, context)
 /*     int     fd;
 /*     int     timeout;
-/*     TLScontext_t *context;
+/*     TLS_SESS_STATE *context;
 /*
 /*     int tls_bio_read(fd, buf, len, timeout, context)
 /*     int     fd;
 /*     void    *buf;
 /*     int     len;
 /*     int     timeout;
-/*     TLScontext_t *context;
+/*     TLS_SESS_STATE *context;
 /*
 /*     int tls_bio_write(fd, buf, len, timeout, context)
 /*     int     fd;
 /*     void    *buf;
 /*     int     len;
 /*     int     timeout;
-/*     TLScontext_t *context;
+/*     TLS_SESS_STATE *context;
 /* DESCRIPTION
 /*     This layer synchronizes the TLS network buffers with the network
 /*     while performing TLS handshake or input/output operations.
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
@@ -241,7 +244,7 @@ static int network_biopair_interop(int fd, int timeout, BIO *network_bio)
 
 /* tls_bio - perform SSL input/output operation with extreme prejudice */
 
-int     tls_bio(int fd, int timeout, TLScontext_t *TLScontext,
+int     tls_bio(int fd, int timeout, TLS_SESS_STATE *TLScontext,
                        int (*hsfunc) (SSL *),
                        int (*rfunc) (SSL *, void *, int),
                        int (*wfunc) (SSL *, const void *, int),
@@ -297,7 +300,7 @@ int     tls_bio(int fd, int timeout, TLScontext_t *TLScontext,
         */
        if (err == SSL_ERROR_SSL) {
            if (ERR_peek_error() == 0x0407006AL) {
-               pfixtls_print_errors();
+               tls_print_errors();
                msg_info("OpenSSL <= 0.9.5a workaround called: certificate errors ignored");
                err = SSL_get_error(TLScontext->con, status);
            }
index 0c77c8c4a672d5fae05e41c3e60ddf2713785a01..04d186c36a4bb89dc1b030057169620858de04e2 100644 (file)
@@ -1,22 +1,22 @@
 /*++
 /* NAME
-/*     tls
+/*     tls_client
 /* SUMMARY
 /*     client-side TLS engine
 /* SYNOPSIS
 /*     #include <tls.h>
 /*
-/*     SSL_CTX *tls_client_init(init_props)
-/*     const tls_client_init_props *init_props;
+/*     TLS_APPL_STATE *tls_client_init(init_props)
+/*     const TLS_CLIENT_INIT_PROPS *init_props;
 /*
-/*     TLScontext_t *tls_client_start(start_props)
-/*     const tls_client_start_props *start_props;
+/*     TLS_SESS_STATE *tls_client_start(start_props)
+/*     const TLS_CLIENT_START_PROPS *start_props;
 /*
-/*     void    tls_client_stop(client_ctx, stream, failure, TLScontext)
-/*     SSL_CTX *client_ctx;
+/*     void    tls_client_stop(app_ctx, stream, failure, TLScontext)
+/*     TLS_APPL_STATE *app_ctx;
 /*     VSTREAM *stream;
 /*     int     failure;
-/*     TLScontext_t *TLScontext;
+/*     TLS_SESS_STATE *TLScontext;
 /* DESCRIPTION
 /*     This module is the interface between Postfix TLS clients,
 /*     the OpenSSL library and the TLS entropy and cache manager.
@@ -50,7 +50,7 @@
 /*     tls_client_init() is called once when the SMTP client
 /*     initializes.
 /*     Certificate details are also decided during this phase,
-/*     so that peer-specific behavior is not possible.
+/*     so peer-specific certificate selection is not possible.
 /*
 /*     tls_client_start() activates the TLS session over an established
 /*     stream. We expect that network buffers are flushed and
@@ -60,8 +60,8 @@
 /*     SSL_shutdown() to the peer and resets all connection specific
 /*     TLS data. As RFC2487 does not specify a separate shutdown, it
 /*     is assumed that the underlying TCP connection is shut down
-/*     immediately afterwards, so we don't care about additional data
-/*     coming through the channel.
+/*     immediately afterwards. Any further writes to the channel will
+/*     be discarded, and any further reads will report end-of-file.
 /*     If the failure flag is set, no SSL_shutdown() handshake is performed.
 /*
 /*     Once the TLS connection is initiated, information about the TLS
 /*     The last two values may differ from each other when export-strength
 /*     encryption is used.
 /*
-/*     The status of the peer certificate verification is available in
-/*     TLScontext->peer_verified. It is set to 1 when the certificate could
-/*     be verified.
 /*     If the peer offered a certificate, part of the certificate data are
 /*     available as:
+/* .IP TLScontext->peer_status
+/*     A bitmask field that records the status of the peer certificate
+/*     verification. This consists of one or more of
+/*     TLS_CERT_FLAG_PRESENT, TLS_CERT_FLAG_ALTNAME, TLS_CERT_FLAG_TRUSTED
+/*     and TLS_CERT_FLAG_MATCHED.
 /* .IP TLScontext->peer_CN
 /*     Extracted CommonName of the peer, or zero-length string if the
 /*     information could not be extracted.
 /* .IP TLScontext->issuer_CN
-/*     extracted CommonName of the issuer, or zero-length string if the
+/*     Extracted CommonName of the issuer, or zero-length string if the
 /*     information could not be extracted.
+/* .IP TLScontext->peer_fingerprint
+/*     At the fingerprint security level, if the peer presented a certificate
+/*     the fingerprint of the certificate.
 /* .PP
-/*     Otherwise these fields are set to null pointers.
+/*     If no peer certificate is presented the peer_status is set to 0.
 /* LICENSE
 /* .ad
 /* .fi
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
 
 /* load_clnt_session - load session from client cache (non-callback) */
 
-static SSL_SESSION *load_clnt_session(TLScontext_t *TLScontext)
+static SSL_SESSION *load_clnt_session(TLS_SESS_STATE *TLScontext)
 {
     const char *myname = "load_clnt_session";
     SSL_SESSION *session = 0;
@@ -198,7 +206,7 @@ static SSL_SESSION *load_clnt_session(TLScontext_t *TLScontext)
 static int new_client_session_cb(SSL *ssl, SSL_SESSION *session)
 {
     const char *myname = "new_client_session_cb";
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
     VSTRING *session_data;
 
     /*
@@ -257,8 +265,11 @@ static int new_client_session_cb(SSL *ssl, SSL_SESSION *session)
 
 /* uncache_session - remove session from the external cache */
 
-static void uncache_session(TLScontext_t *TLScontext)
+static void uncache_session(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext)
 {
+    SSL_SESSION *session = SSL_get_session(TLScontext->con);
+
+    SSL_CTX_remove_session(ctx, session);
     if (TLScontext->cache_type == 0 || TLScontext->serverid == 0)
        return;
 
@@ -270,17 +281,23 @@ static void uncache_session(TLScontext_t *TLScontext)
 
 /* tls_client_init - initialize client-side TLS engine */
 
-SSL_CTX *tls_client_init(const tls_client_init_props *props)
+TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
 {
     long    off = 0;
-    SSL_CTX *client_ctx;
     int     cachable;
-
-    /* See skeleton in OpenSSL apps/s_client.c. */
+    SSL_CTX *client_ctx;
+    TLS_APPL_STATE *app_ctx;
+    const EVP_MD *md_alg;
+    unsigned int md_len;
 
     if (props->log_level >= 2)
        msg_info("initializing the client-side TLS engine");
 
+    /*
+     * Load (mostly cipher related) TLS-library internal main.cf parameters.
+     */
+    tls_param_init();
+
     /*
      * Detect mismatch between compile-time headers and run-time library.
      */
@@ -294,6 +311,38 @@ SSL_CTX *tls_client_init(const tls_client_init_props *props)
     SSL_load_error_strings();
     OpenSSL_add_ssl_algorithms();
 
+    /*
+     * Create an application data index for SSL objects, so that we can
+     * attach TLScontext information; this information is needed inside
+     * tls_verify_certificate_callback().
+     */
+    if (TLScontext_index < 0) {
+       if ((TLScontext_index = SSL_get_ex_new_index(0, 0, 0, 0, 0)) < 0) {
+           msg_warn("Cannot allocate SSL application data index: "
+                    "disabling TLS support");
+           return (0);
+       }
+    }
+
+    /*
+     * If the administrator specifies an unsupported digest algorithm, fail
+     * now, rather than in the middle of a TLS handshake.
+     */
+    if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) {
+       msg_warn("Digest algorithm \"%s\" not found: disabling TLS support",
+                props->fpt_dgst);
+       return (0);
+    }
+
+    /*
+     * Sanity check: Newer shared libraries may use larger digests.
+     */
+    if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) {
+       msg_warn("Digest algorithm \"%s\" output size %u too large:"
+                " disabling TLS support", props->fpt_dgst, md_len);
+       return (0);
+    }
+
     /*
      * Initialize the PRNG (Pseudo Random Number Generator) with some seed
      * from external and internal sources. Don't enable TLS without some real
@@ -313,12 +362,18 @@ SSL_CTX *tls_client_init(const tls_client_init_props *props)
      * SSLv2 greeting allowing the best we can offer: TLSv1. We can restrict
      * this with the options setting later, anyhow.
      */
-    client_ctx = SSL_CTX_new(SSLv23_client_method());
-    if (client_ctx == NULL) {
+    ERR_clear_error();
+    if ((client_ctx = SSL_CTX_new(SSLv23_client_method())) == 0) {
+       msg_warn("cannot allocate client SSL_CTX: disabling TLS support");
        tls_print_errors();
        return (0);
     }
 
+    /*
+     * See the verify callback in tls_verify.c
+     */
+    SSL_CTX_set_verify_depth(client_ctx, props->verifydepth + 1);
+
     /*
      * Protocol selection is destination dependent, so we delay the protocol
      * selection options to the per-session SSL object.
@@ -345,6 +400,7 @@ SSL_CTX *tls_client_init(const tls_client_init_props *props)
      */
     if (tls_set_ca_certificate_info(client_ctx,
                                    props->CAfile, props->CApath) < 0) {
+       /* tls_set_ca_certificate_info() already logs a warning. */
        SSL_CTX_free(client_ctx);               /* 200411 */
        return (0);
     }
@@ -371,6 +427,7 @@ SSL_CTX *tls_client_init(const tls_client_init_props *props)
        && tls_set_my_certificate_key_info(client_ctx, props->cert_file,
                                         props->key_file, props->dcert_file,
                                           props->dkey_file) < 0) {
+       /* tls_set_my_certificate_key_info() already logs a warning. */
        SSL_CTX_free(client_ctx);               /* 200411 */
        return (0);
     }
@@ -400,27 +457,22 @@ SSL_CTX *tls_client_init(const tls_client_init_props *props)
      * sessions from the external cache, so we must delete them directly (not
      * via a callback).
      */
-
-    if (TLSscache_index < 0)
-       TLSscache_index =
-           SSL_CTX_get_ex_new_index(0, "TLScontext ex_data index",
-                                    NULL, NULL, NULL);
-
     if (tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK)
        cachable = 0;
 
-    if (!SSL_CTX_set_ex_data(client_ctx, TLSscache_index,
-                            (void *) props->cache_type)) {
-       msg_warn("Session cache off: error saving cache type in SSL context.");
-       tls_print_errors();
-       cachable = 0;
-    }
+    /*
+     * Allocate an application context, and populate with mandatory protocol
+     * and cipher data.
+     */
+    app_ctx = tls_alloc_app_context(client_ctx);
 
     /*
      * The external session cache is implemented by the tlsmgr(8) process.
      */
     if (cachable) {
 
+       app_ctx->cache_type = mystrdup(props->cache_type);
+
        /*
         * OpenSSL does not use callbacks to load sessions from a client
         * cache, so we must invoke that function directly. Apparently,
@@ -445,23 +497,17 @@ SSL_CTX *tls_client_init(const tls_client_init_props *props)
                                       SSL_SESS_CACHE_NO_AUTO_CLEAR);
        SSL_CTX_sess_set_new_cb(client_ctx, new_client_session_cb);
     }
-
-    /*
-     * Create a global index so that we can attach TLScontext information to
-     * SSL objects; this information is needed inside
-     * tls_verify_certificate_callback().
-     */
-    if (TLScontext_index < 0)
-       TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index",
-                                               NULL, NULL, NULL);
-    return (client_ctx);
+    return (app_ctx);
 }
 
 /* match_hostname -  match hostname against pattern */
 
-static int match_hostname(const char *peerid, ARGV *cmatch_argv,
-                                 const char *nexthop, const char *hname)
+static int match_hostname(const char *peerid,
+                                 const TLS_CLIENT_START_PROPS *props)
 {
+    const ARGV *cmatch_argv = props->matchargv;
+    const char *nexthop = props->nexthop;
+    const char *hname = props->host;
     const char *pattern;
     const char *pattern_left;
     int     sub;
@@ -515,33 +561,41 @@ static int match_hostname(const char *peerid, ARGV *cmatch_argv,
     return (0);
 }
 
-/* verify_extract_peer - verify peer name and extract peer information */
+/* verify_extract_name - verify peer name and extract peer information */
 
-static void verify_extract_peer(const char *nexthop, const char *hname,
-                                     const char *certmatch, X509 *peercert,
-                                       TLScontext_t *TLScontext)
+static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert,
+                                       const TLS_CLIENT_START_PROPS *props)
 {
     int     i;
     int     r;
-    int     hostname_matched = 0;
-    int     dNSName_found = 0;
-    int     verify_peername;
-    ARGV   *cmatch_argv = 0;
+    int     matched = 0;
+    const char *dnsname;
+    const GENERAL_NAME *gn;
 
     STACK_OF(GENERAL_NAME) * gens;
 
-    TLScontext->peer_verified =
-       (SSL_get_verify_result(TLScontext->con) == X509_V_OK);
+    /*
+     * On exit both peer_CN and issuer_CN should be set.
+     */
+    TLScontext->issuer_CN = tls_issuer_CN(peercert, TLScontext);
 
-    verify_peername =
-       (TLScontext->enforce_CN != 0 && TLScontext->peer_verified != 0);
+    /*
+     * Is the certificate trust chain valid and trusted?
+     */
+    if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
+       TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED;
 
-    if (verify_peername) {
-       cmatch_argv = argv_split(certmatch, "\t\n\r, :");
+    if (TLS_CERT_IS_TRUSTED(TLScontext) && props->tls_level >= TLS_LEV_VERIFY) {
 
        /*
-        * Verify the dNSName(s) in the peer certificate against the
-        * peername.
+        * Verify the dNSName(s) in the peer certificate against the nexthop
+        * and hostname.
+        * 
+        * If DNS names are present, we use the first matching (or else simply
+        * the first) DNS name as the subject CN. The CommonName in the
+        * issuer DN is obsolete when SubjectAltName is available. This
+        * yields much less surprising logs, because we log the name we
+        * verified or a name we checked and failed to match.
         * 
         * XXX: The nexthop and host name may both be the same network address
         * rather than a DNS name. In this case we really should be looking
@@ -554,60 +608,106 @@ static void verify_extract_peer(const char *nexthop, const char *hname,
         */
        gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
        if (gens) {
-           for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i) {
-               const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
-
-               if (gn->type == GEN_DNS) {
-                   dNSName_found++;
-                   if ((hostname_matched =
-                      match_hostname((char *) gn->d.ia5->data, cmatch_argv,
-                                     nexthop, hname)) != 0)
-                       break;
+           r = sk_GENERAL_NAME_num(gens);
+           for (i = 0; i < r && !matched; ++i) {
+               gn = sk_GENERAL_NAME_value(gens, i);
+               if (gn->type != GEN_DNS)
+                   continue;
+
+               /*
+                * Even if we have an invalid DNS name, we still ultimately
+                * ignore the CommonName, because subjectAltName:DNS is
+                * present (though malformed). Replace any previous peer_CN
+                * if empty or we get a match.
+                * 
+                * We always set at least an empty peer_CN if the ALTNAME cert
+                * flag is set. If not, we set peer_CN from the cert
+                * CommonName below, so peer_CN is always non-null on return.
+                */
+               TLScontext->peer_status |= TLS_CERT_FLAG_ALTNAME;
+               dnsname = tls_dns_name(gn, TLScontext);
+               if (dnsname && *dnsname) {
+                   matched = match_hostname(dnsname, props);
+                   if (TLScontext->peer_CN
+                       && (matched || *TLScontext->peer_CN == 0)) {
+                       myfree(TLScontext->peer_CN);
+                       TLScontext->peer_CN = 0;
+                   }
                }
+               if (TLScontext->peer_CN == 0)
+                   TLScontext->peer_CN = mystrdup(dnsname ? dnsname : "");
            }
+
+           /*
+            * (Sam Rushing, Ironport) Free stack *and* member GENERAL_NAME
+            * objects
+            */
            sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
        }
-    }
-    if (dNSName_found) {
-       if (!hostname_matched)
-           msg_info("certificate peer name verification failed for "
-                    "%s: %d dNSNames in certificate found, "
-                    "but none match", hname, dNSName_found);
-    }
-    if ((TLScontext->peer_CN = tls_peer_CN(peercert)) == 0)
-       TLScontext->peer_CN = mystrdup("");
-
-    if ((TLScontext->issuer_CN = tls_issuer_CN(peercert)) == 0)
-       TLScontext->issuer_CN = mystrdup("");
-
-    if (!dNSName_found && verify_peername) {
 
        /*
-        * Verify the CommonName in the peer certificate against the
-        * peername.
+        * No subjectAltNames, peer_CN is taken from CommonName.
         */
-       if (TLScontext->peer_CN[0] != '\0') {
-           hostname_matched = match_hostname(TLScontext->peer_CN, cmatch_argv,
-                                             nexthop, hname);
-           if (!hostname_matched)
-               msg_info("certificate peer name verification failed "
-                        "for nexthop=%s, host=%s: CommonName mis-match: %s",
-                        nexthop, hname, TLScontext->peer_CN);
+       if (TLScontext->peer_CN == 0) {
+           TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);
+           if (*TLScontext->peer_CN)
+               matched = match_hostname(TLScontext->peer_CN, props);
        }
-    }
-    if (cmatch_argv)
-       cmatch_argv = argv_free(cmatch_argv);
-    TLScontext->hostname_matched = hostname_matched;
-
-    if (TLScontext->log_level >= 1) {
-       if (TLScontext->peer_verified
-           && (!TLScontext->enforce_CN || TLScontext->hostname_matched))
-           msg_info("Verified: subject_CN=%s, issuer=%s",
-                    TLScontext->peer_CN, TLScontext->issuer_CN);
-       else
-           msg_info("Unverified: subject_CN=%s, issuer=%s",
+       if (matched)
+           TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;
+
+       /*
+        * - Matched: Trusted and peername matches - Trusted: Signed by
+        * trusted CA(s), but peername not matched - Untrusted: Can't verify
+        * the trust chain, reason already logged.
+        */
+       if (TLScontext->log_level >= 2)
+           msg_info("%s: %s subject_CN=%s, issuer_CN=%s", props->namaddr,
+                    TLS_CERT_IS_MATCHED(TLScontext) ? "Matched" :
+                 TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
                     TLScontext->peer_CN, TLScontext->issuer_CN);
-    }
+    } else
+       TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);
+
+    /*
+     * Give them a clue. Problems with trust chain verification were logged
+     * when the session was first negotiated, before the session was stored
+     * into the cache. We don't want mystery failures, so log the fact the
+     * real problem is to be found in the past.
+     */
+    if (TLScontext->session_reused
+       && !TLS_CERT_IS_TRUSTED(TLScontext)
+       && TLScontext->log_level >= 1)
+       msg_info("%s: re-using session with untrusted certificate, "
+                "look for details earlier in the log", props->namaddr);
+}
+
+/* verify_extract_print - extract and verify peer fingerprint */
+
+static void verify_extract_print(TLS_SESS_STATE *TLScontext, X509 *peercert,
+                                        const TLS_CLIENT_START_PROPS *props)
+{
+    char  **cpp;
+
+    /* Non-null by contract */
+    TLScontext->peer_fingerprint = tls_fingerprint(peercert, props->fpt_dgst);
+
+    if (props->tls_level != TLS_LEV_FPRINT)
+       return;
+
+    /*
+     * Compare the fingerprint against each acceptable value, ignoring
+     * upper/lower case differences.
+     */
+    for (cpp = props->matchargv->argv; *cpp; ++cpp)
+       if (strcasecmp(TLScontext->peer_fingerprint, *cpp) == 0) {
+           TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;
+           break;
+       }
+    if (props->log_level >= 2)
+       msg_info("%s %s%s fingerprint %s", props->namaddr,
+                TLS_CERT_IS_MATCHED(TLScontext) ? "Matched " : "",
+                props->fpt_dgst, TLScontext->peer_fingerprint);
 }
 
  /*
@@ -615,25 +715,68 @@ static void verify_extract_peer(const char *nexthop, const char *hname,
   * buffers are flushed and the "220 Ready to start TLS" was received by us,
   * so that we can immediately start the TLS handshake process.
   */
-TLScontext_t *tls_client_start(const tls_client_start_props *props)
+TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
 {
     int     sts;
+    int     protomask;
+    const char *cipher_list;
     SSL_SESSION *session;
     SSL_CIPHER *cipher;
     X509   *peercert;
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
+    TLS_APPL_STATE *app_ctx = props->ctx;
+    VSTRING *myserverid;
 
     if (props->log_level >= 1)
-       msg_info("setting up TLS connection to %s", props->host);
+       msg_info("setting up TLS connection to %s", props->namaddr);
 
     /*
-     * Before we create an SSL, update the SSL_CTX cipherlist if necessary.
+     * First make sure we have valid protocol and cipher parameters
+     * 
+     * The cipherlist will be applied to the global SSL context, where it can be
+     * repeatedly reset if necessary, but the protocol restrictions will be
+     * is applied to the SSL connection, because protocol restrictions in the
+     * global context cannot be cleared.
      */
-    if (tls_set_cipher_list(props->ctx, props->cipherlist) == 0) {
-       msg_warn("Invalid cipherlist \"%s\": aborting TLS session",
-                props->cipherlist);
+
+    /*
+     * OpenSSL will ignore cached sessions that use the wrong protocol. So we
+     * do not need to filter out cached sessions with the "wrong" protocol,
+     * rather OpenSSL will simply negotiate a new session.
+     * 
+     * Still, we salt the session lookup key with the protocol list, so that
+     * sessions found in the cache are always acceptable.
+     */
+    protomask = tls_protocol_mask(props->protocols);
+    if (protomask == TLS_PROTOCOL_INVALID) {
+       /* tls_protocol_mask() logs no warning. */
+       msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session",
+                props->namaddr, props->protocols);
        return (0);
     }
+    myserverid = vstring_alloc(100);
+    vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask);
+
+    /*
+     * Per session cipher selection for sessions with mandatory encryption
+     * 
+     * By the time a TLS client is negotiating ciphers it has already offered to
+     * re-use a session, it is too late to renege on the offer. So we must
+     * not attempt to re-use sessions whose ciphers are too weak. We salt the
+     * session lookup key with the cipher list, so that sessions found in the
+     * cache are always acceptable.
+     */
+    cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade,
+                                 props->cipher_exclusions);
+    if (cipher_list == 0) {
+       msg_warn("%s: %s: aborting TLS session",
+                props->namaddr, vstring_str(app_ctx->why));
+       vstring_free(myserverid);
+       return (0);
+    }
+    if (props->log_level >= 2)
+       msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list);
+    vstring_sprintf_append(myserverid, "&c=%s", cipher_list);
 
     /*
      * Allocate a new TLScontext for the new connection and get an SSL
@@ -643,11 +786,12 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
      * If session caching was enabled when TLS was initialized, the cache type
      * is stored in the client SSL context.
      */
-    TLScontext = tls_alloc_context(props->log_level, props->host);
-    TLScontext->serverid = mystrdup(props->serverid);
-    TLScontext->cache_type = SSL_CTX_get_ex_data(props->ctx, TLSscache_index);
+    TLScontext = tls_alloc_sess_context(props->log_level, props->namaddr);
+    TLScontext->cache_type = app_ctx->cache_type;
+
+    TLScontext->serverid = vstring_export(myserverid);
 
-    if ((TLScontext->con = (SSL *) SSL_new(props->ctx)) == NULL) {
+    if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
        msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
        tls_print_errors();
        tls_free_context(TLScontext);
@@ -661,19 +805,13 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
     }
 
     /*
-     * Set the verification parameters to be checked in
-     * tls_verify_certificate_callback().
+     * Apply session protocol restrictions.
      */
-    if (props->tls_level >= TLS_LEV_VERIFY) {
-       TLScontext->enforce_verify_errors = 1;
-       TLScontext->enforce_CN = 1;
-       SSL_set_verify(TLScontext->con, SSL_VERIFY_PEER,
-                      tls_verify_certificate_callback);
-    } else {
-       TLScontext->enforce_verify_errors = 0;
-       TLScontext->enforce_CN = 0;
-    }
-    TLScontext->hostname_matched = 0;
+    if (protomask != 0)
+       SSL_set_options(TLScontext->con,
+                  ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L)
+                | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L)
+              | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L));
 
     /*
      * The TLS connection is realized by a BIO_pair, so obtain the pair.
@@ -689,55 +827,11 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
        tls_free_context(TLScontext);
        return (0);
     }
-#define DISABLE_ALL (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1)
 
     /*
-     * Per session protocol selection for sessions with mandatory encryption
-     * 
-     * OpenSSL will ignore cached sessions that use the wrong protocol. So we do
-     * not need to filter out cached sessions with the "wrong" protocol,
-     * rather OpenSSL will simply negotiate a new session.
-     * 
-     * Still, we expect the caller to salt the session lookup key with the
-     * protocol list, so that sessions found in the cache are always
-     * acceptable.
-     * 
-     * Not enabling any protocols explicitly, enables all.
-     */
-    if (props->tls_level >= TLS_LEV_ENCRYPT
-       && props->protocols != 0 && props->protocols != TLS_ALL_PROTOCOLS) {
-       long    disable = DISABLE_ALL;
-
-       if (props->protocols & TLS_PROTOCOL_TLSv1)
-           disable &= ~SSL_OP_NO_TLSv1;
-       if (props->protocols & TLS_PROTOCOL_SSLv3)
-           disable &= ~SSL_OP_NO_SSLv3;
-       if (props->protocols & TLS_PROTOCOL_SSLv2)
-           disable &= ~SSL_OP_NO_SSLv2;
-
-       SSL_set_options(TLScontext->con, disable);
-    }
-
-    /*
-     * Try to load an existing session from the TLS session cache.
-     * 
-     * By the time a TLS client is negotiating ciphers it has already offered to
-     * re-use a session, it is too late to renege on the offer. So we must
-     * not attempt to re-use sessions whose ciphers are too weak. We expect
-     * the caller to salt the session lookup key with the cipher list, so
-     * that sessions found in the cache are always acceptable.
-     * 
      * XXX To avoid memory leaks we must always call SSL_SESSION_free() after
      * calling SSL_set_session(), regardless of whether or not the session
      * will be reused.
-     * 
-     * XXX: We rely on the client including any non-default cipherlist in the
-     * serverid cache lookup key so as to avoid fetching sessions with
-     * incompatible ciphers. We could save the cipher name into the cache
-     * together with the serialized session, and compare it against the
-     * cipherlist here, but this is unlikely to be worth the trouble. A sane
-     * administrator should use at most a handful of cipherlists, especially
-     * when setting policy for domains served by a common MX host.
      */
     if (TLScontext->cache_type) {
        session = load_clnt_session(TLScontext);
@@ -805,19 +899,12 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
     sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout,
                          TLScontext);
     if (sts <= 0) {
-       msg_info("SSL_connect error to %s: %d", props->host, sts);
+       msg_info("SSL_connect error to %s: %d", props->namaddr, sts);
        tls_print_errors();
-       uncache_session(TLScontext);
+       uncache_session(app_ctx->ssl_ctx, TLScontext);
        tls_free_context(TLScontext);
        return (0);
     }
-
-    /*
-     * The TLS engine is active. Switch to the tls_timed_read/write()
-     * functions and make the TLScontext available to those functions.
-     */
-    tls_stream_start(props->stream, TLScontext);
-
     /* Only log_level==4 dumps everything */
     if (props->log_level < 4)
        BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);
@@ -828,23 +915,26 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
      */
     TLScontext->session_reused = SSL_session_reused(TLScontext->con);
     if (props->log_level >= 2 && TLScontext->session_reused)
-       msg_info("Reusing old session");
+       msg_info("%s: Reusing old session", TLScontext->namaddr);
 
     /*
      * Do peername verification if requested and extract useful information
      * from the certificate for later use.
      */
     if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) {
-       verify_extract_peer(props->nexthop, props->host, props->certmatch,
-                           peercert, TLScontext);
+       TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT;
+
+       /*
+        * Peer name or fingerprint verification as requested.
+        * Unconditionally set peer_CN, issuer_CN and peer_fingerprint.
+        */
+       verify_extract_name(TLScontext, peercert, props);
+       verify_extract_print(TLScontext, peercert, props);
        X509_free(peercert);
-    }
-    if (TLScontext->enforce_CN && !TLScontext->hostname_matched) {
-       msg_info("Server certificate could not be verified for %s:"
-                " hostname mismatch", props->host);
-       tls_client_stop(props->ctx, props->stream, props->timeout, 0,
-                       TLScontext);
-       return (0);
+    } else {
+       TLScontext->issuer_CN = mystrdup("");
+       TLScontext->peer_CN = mystrdup("");
+       TLScontext->peer_fingerprint = mystrdup("");
     }
 
     /*
@@ -856,10 +946,20 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
     TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher,
                                             &(TLScontext->cipher_algbits));
 
+    /*
+     * The TLS engine is active. Switch to the tls_timed_read/write()
+     * functions and make the TLScontext available to those functions.
+     */
+    tls_stream_start(props->stream, TLScontext);
+
+    /*
+     * All the key facts in a single log entry.
+     */
     if (props->log_level >= 1)
-       msg_info("TLS connection established to %s: %s with cipher %s"
-                " (%d/%d bits)", props->host,
-                TLScontext->protocol, TLScontext->cipher_name,
+       msg_info("%s TLS connection established to %s: %s with cipher %s "
+             "(%d/%d bits)", TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" :
+                TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
+             props->namaddr, TLScontext->protocol, TLScontext->cipher_name,
                 TLScontext->cipher_usebits, TLScontext->cipher_algbits);
 
     tls_int_seed();
index 03affcfdc34260b110e8c46b7d4fa27cc436e247..32063200ef9fb27592b6fd911e71a78846d8be47 100644 (file)
@@ -17,8 +17,8 @@
 /*     because they evaluate their arguments only once.
 /*
 /*     tls_level_lookup() converts a TLS level from symbolic name
-/*     to internal form. The result is TLS_NOTFOUND for an unknown
-/*     level.
+/*     to internal form. When an unknown level is specified,
+/*     tls_level_lookup() logs no warning, and returns TLS_LEV_INVALID.
 /*
 /*     str_tls_level() converts a TLS level from internal form to
 /*     symbolic name. The result is a null pointer for an unknown
@@ -34,6 +34,9 @@
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
 
 /* Application-specific. */
 
-NAME_CODE tls_level_table[] = {
+ /*
+  * Order is critical:
+  * 
+  * Levels > "encrypt" are expected to match a peer certificate.
+  * 
+  * Levels >= "verify" are expected to require a valid CA trust-chain
+  * 
+  * This forces "fingerprint" between "encrypt" and "verify".
+  */
+const NAME_CODE tls_level_table[] = {
     "none", TLS_LEV_NONE,
     "may", TLS_LEV_MAY,
     "encrypt", TLS_LEV_ENCRYPT,
+    "fingerprint", TLS_LEV_FPRINT,
     "verify", TLS_LEV_VERIFY,
     "secure", TLS_LEV_SECURE,
-    0, TLS_LEV_NOTFOUND,
+    0, TLS_LEV_INVALID,
 };
index 2d05b0ba82baeac04500eb585765f2c6b8681912..a1f9060a63b097d0405d4ebec8015ec48e5a4541 100644 (file)
@@ -7,27 +7,50 @@
 /*     #define TLS_INTERNAL
 /*     #include <tls.h>
 /*
-/*     TLScontext_t *tls_alloc_context(log_level, peername)
+/*     char    *var_tls_high_clist;
+/*     char    *var_tls_medium_clist;
+/*     char    *var_tls_low_clist;
+/*     char    *var_tls_export_clist;
+/*     char    *var_tls_null_clist;
+/*     int     var_tls_daemon_rand_bytes;
+/*
+/*     TLS_APPL_STATE *tls_alloc_app_context(ssl_ctx)
+/*     SSL_CTX *ssl_ctx;
+/*
+/*     void    tls_free_app_context(app_ctx)
+/*     void    *app_ctx;
+/*
+/*     TLS_SESS_STATE *tls_alloc_sess_context(log_level, namaddr)
 /*     int     log_level;
-/*     const char *peername;
+/*     const char *namaddr;
 /*
 /*     void    tls_free_context(TLScontext)
-/*     TLScontext_t *TLScontext;
+/*     TLS_SESS_STATE *TLScontext;
 /*
 /*     void    tls_check_version()
 /*
 /*     long    tls_bug_bits()
 /*
-/*     const char *tls_set_cipher_list(ssl_ctx, cipher_list)
-/*     SSL_CTX *ssl_ctx;
-/*     char    *cipher_list;
+/*     void    tls_param_init()
+/*
+/*     int     tls_protocol_mask(plist)
+/*     const char *plist;
+/*
+/*     int     tls_cipher_grade(name)
+/*     const char *name;
+/*
+/*     const char *str_tls_cipher_grade(grade)
+/*     int     grade;
 /*
-/*     const char *tls_cipher_list(cipher_level, ...)
-/*     int     cipher_level;
+/*     const char *tls_set_ciphers(app_ctx, context, grade, exclusions)
+/*     TLS_APPL_STATE *app_ctx;
+/*     const char *context;
+/*     int     grade;
+/*     const char *exclusions;
 /*
 /*     void    tls_print_errors()
 /*
-/*     void    tls_info_callback(ssl, where, ret)
+/*     void    tls_info_callback(ssl, where, ret)
 /*     const SSL *ssl; /* unused */
 /*     int     where;
 /*     int     ret;
 /*     This module implements routines that support the TLS client
 /*     and server internals.
 /*
-/*     tls_alloc_context() creates an initialized TLScontext
-/*     structure with the specified peer name and logging level.
+/*     tls_alloc_app_context() creates an application context that
+/*     holds the SSL context for the application and related cached state.
+/*
+/*     tls_free_app_context() deallocates the application context and its
+/*     contents (the application context is stored outside the TLS library).
+/*
+/*     tls_alloc_sess_context() creates an initialized TLS session context
+/*     structure with the specified log mask and peer name[addr].
 /*
 /*     tls_free_context() destroys a TLScontext structure
 /*     together with OpenSSL structures that are attached to it.
 /*     for the run-time library. Some of the bug work-arounds are
 /*     not appropriate for some library versions.
 /*
-/*     tls_set_cipher_list() updates the cipher list of the specified SSL
-/*     context. Returns the new cipherlist on success, otherwise logs a
-/*     suitable warning and returns 0. The storage for the return value
-/*     is overwritted with each call.
+/*     tls_param_init() loads main.cf parameters used internally in
+/*     TLS library. Any errors are fatal.
+/*
+/*     tls_protocol_mask() returns a bitmask of excluded protocols, given
+/*     a list (plist) of protocols to include or (preceded by a '!') exclude.
+/*     If "plist" contains invalid protocol names, TLS_PROTOCOL_INVALID is
+/*     returned and no warning is logged.
+/*
+/*     tls_cipher_grade() converts a case-insensitive cipher grade
+/*     name (high, medium, low, export, null) to the corresponding
+/*     TLS_CIPHER_ constant.  When the input specifies an unrecognized
+/*     grade, tls_cipher_grade() logs no warning, and returns
+/*     TLS_CIPHER_NONE.
+/*
+/*     str_tls_cipher_grade() converts a cipher grade to a name.
+/*     When the input specifies an undefined grade, str_tls_cipher_grade()
+/*     logs no warning, returns a null pointer.
 /*
-/*     tls_cipher_list() generates a cipher list from the specified
-/*     grade, minus any ciphers specified via a null-terminated
-/*     list of string-valued exclusions. The result is overwritten
-/*     upon each call.
+/*     tls_set_ciphers() generates a cipher list from the specified
+/*     grade, minus any ciphers specified via a list of exclusions.
+/*     The cipherlist is applied to the supplied SSL context if it
+/*     is different from the most recently applied value. The return
+/*     value is the cipherlist used and is overwritten upon each call.
+/*     When the input is invalid, tls_set_ciphers() logs a warning with
+/*     the specified context, and returns a null pointer result.
 /*
 /*     tls_print_errors() queries the OpenSSL error stack,
 /*     logs the error messages, and clears the error stack.
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
 #include <stringops.h>
 #include <argv.h>
 
-/* TLS library. */
+ /*
+  * Global library.
+  */
+#include <mail_params.h>
+#include <mail_conf.h>
 
+ /*
+  * TLS library.
+  */
 #define TLS_INTERNAL
 #include <tls.h>
 
 /* Application-specific. */
 
  /*
-  * Index to attach TLScontext pointers to SSL objects, so that they can be
-  * accessed by call-back routines.
+  * Tunable parameters.
   */
-int     TLScontext_index = -1;
+char   *var_tls_high_clist;
+char   *var_tls_medium_clist;
+char   *var_tls_low_clist;
+char   *var_tls_export_clist;
+char   *var_tls_null_clist;
+int     var_tls_daemon_rand_bytes;
 
  /*
-  * Index to attach session cache names SSL_CTX objects.
+  * Index to attach TLScontext pointers to SSL objects, so that they can be
+  * accessed by call-back routines.
   */
-int     TLSscache_index = -1;
+int     TLScontext_index = -1;
 
  /*
   * Protocol name <=> mask conversion.
   */
-NAME_MASK tls_protocol_table[] = {
+static const NAME_CODE protocol_table[] = {
     SSL_TXT_SSLV2, TLS_PROTOCOL_SSLv2,
     SSL_TXT_SSLV3, TLS_PROTOCOL_SSLv3,
     SSL_TXT_TLSV1, TLS_PROTOCOL_TLSv1,
-    0, 0,
+    0, TLS_PROTOCOL_INVALID,
 };
 
-char   *var_tls_high_clist;
-char   *var_tls_medium_clist;
-char   *var_tls_low_clist;
-char   *var_tls_export_clist;
-char   *var_tls_null_clist;
-
  /*
   * Ciphersuite name <=> code conversion.
   */
-NAME_CODE tls_cipher_level_table[] = {
+const NAME_CODE tls_cipher_grade_table[] = {
     "high", TLS_CIPHER_HIGH,
     "medium", TLS_CIPHER_MEDIUM,
     "low", TLS_CIPHER_LOW,
     "export", TLS_CIPHER_EXPORT,
     "null", TLS_CIPHER_NULL,
+    "invalid", TLS_CIPHER_NONE,
     0, TLS_CIPHER_NONE,
 };
 
@@ -177,12 +232,12 @@ typedef struct {
   * broken ciphers other than AES and CAMELLIA.
   */
 typedef struct {
-    char   *ssl_name;
-    int     alg_bits;
-    char   *evp_name;
-}       cipher_probe_t;
+    const char *ssl_name;
+    const int alg_bits;
+    const char *evp_name;
+} cipher_probe_t;
 
-static cipher_probe_t cipher_probes[] = {
+static const cipher_probe_t cipher_probes[] = {
     "AES", 256, "AES-256-CBC",
     "CAMELLIA", 256, "CAMELLIA-256-CBC",
     0, 0, 0,
@@ -190,7 +245,7 @@ static cipher_probe_t cipher_probes[] = {
 
 /* tls_exclude_missing - Append exclusions for missing ciphers */
 
-static void tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
+static const char *tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
 {
     const char *myname = "tls_exclude_missing";
     static ARGV *exclude;              /* Cached */
@@ -198,7 +253,7 @@ static void tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
 
     STACK_OF(SSL_CIPHER) * ciphers;
     SSL_CIPHER *c;
-    cipher_probe_t *probe;
+    const cipher_probe_t *probe;
     int     alg_bits;
     int     num;
     int     i;
@@ -209,7 +264,7 @@ static void tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
      * An SSL cipher-suite name for a family of ciphers that use the same
      * symmetric algorithm at two or more key sizes, typically 128/256 bits.
      * 
-     * The key size (typically 256) that OpenSSL fails check, and assumes is
+     * The key size (typically 256) that OpenSSL fails to check, and assumes
      * available when another key size (typically 128) is usable.
      * 
      * The OpenSSL name of the symmetric algorithm associated with the SSL
@@ -276,46 +331,127 @@ static void tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
     }
     for (i = 0; i < exclude->argc; ++i)
        vstring_sprintf_append(buf, ":!%s", exclude->argv[i]);
+    return (vstring_str(buf));
 }
 
-/* tls_set_cipher_list - Set SSL_CTX cipher list */
+/* tls_apply_cipher_list - update SSL_CTX cipher list */
 
-const char *tls_set_cipher_list(SSL_CTX *ssl_ctx, const char *spec)
+static const char *tls_apply_cipher_list(TLS_APPL_STATE *app_ctx,
+                                        const char *context, VSTRING *spec)
 {
-    static VSTRING *buf;
-    const char *ex_spec;
+    const char *new = tls_exclude_missing(app_ctx->ssl_ctx, spec);
 
-    if (buf == 0)
-       buf = vstring_alloc(10);
+    ERR_clear_error();
+    if (SSL_CTX_set_cipher_list(app_ctx->ssl_ctx, new) == 0) {
+       tls_print_errors();
+       vstring_sprintf(app_ctx->why, "invalid %s cipher list: \"%s\"",
+                       context, new);
+       return (0);
+    }
+    return (new);
+}
 
-    vstring_strcpy(buf, spec);
-    tls_exclude_missing(ssl_ctx, buf);
-    ex_spec = vstring_str(buf);
+/* tls_protocol_mask - Bitmask of protocols to exclude */
 
-    ERR_clear_error();
-    if (SSL_CTX_set_cipher_list(ssl_ctx, ex_spec) != 0)
-       return (ex_spec);
+int     tls_protocol_mask(const char *plist)
+{
+    char   *save;
+    char   *tok;
+    char   *cp;
+    int     code;
+    int     exclude = 0;
+    int     include = 0;
+
+    save = cp = mystrdup(plist);
+    while ((tok = mystrtok(&cp, "\t\n\r ,:")) != 0) {
+       if (*tok == '!')
+           exclude |= code =
+               name_code(protocol_table, NAME_CODE_FLAG_NONE, ++tok);
+       else
+           include |= code =
+               name_code(protocol_table, NAME_CODE_FLAG_NONE, tok);
+       if (code == TLS_PROTOCOL_INVALID)
+           return TLS_PROTOCOL_INVALID;
+    }
+    myfree(save);
 
-    tls_print_errors();
-    return (0);
+    /*
+     * When the include list is empty, use only the explicit exclusions.
+     * Otherwise, also exclude the complement of the include list from the
+     * built-in list of known protocols. There is no way to exclude protocols
+     * we don't know about at compile time, and this is unavoidable because
+     * the OpenSSL API works with compile-time *exclusion* bit-masks.
+     */
+    return (include ? (exclude | (TLS_KNOWN_PROTOCOLS & ~include)) : exclude);
+}
+
+/* tls_param_init - Load TLS related config parameters */
+
+void    tls_param_init(void)
+{
+    static const CONFIG_STR_TABLE str_table[] = {
+       VAR_TLS_HIGH_CLIST, DEF_TLS_HIGH_CLIST, &var_tls_high_clist, 1, 0,
+       VAR_TLS_MEDIUM_CLIST, DEF_TLS_MEDIUM_CLIST, &var_tls_medium_clist, 1, 0,
+       VAR_TLS_LOW_CLIST, DEF_TLS_LOW_CLIST, &var_tls_low_clist, 1, 0,
+       VAR_TLS_EXPORT_CLIST, DEF_TLS_EXPORT_CLIST, &var_tls_export_clist, 1, 0,
+       VAR_TLS_NULL_CLIST, DEF_TLS_NULL_CLIST, &var_tls_null_clist, 1, 0,
+       0,
+    };
+    static const CONFIG_INT_TABLE int_table[] = {
+       VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 1, 0,
+       0,
+    };
+    static int init_done;
+
+    if (init_done)
+       return;
+    init_done = 1;
+
+    get_mail_conf_str_table(str_table);
+    get_mail_conf_int_table(int_table);
 }
 
-/* tls_cipher_list - Cipherlist for given grade, less exclusions */
+/* tls_set_ciphers - Set SSL context cipher list */
 
-const char *tls_cipher_list(int cipher_level,...)
+const char *tls_set_ciphers(TLS_APPL_STATE *app_ctx, const char *context,
+                                 const char *grade, const char *exclusions)
 {
-    const char *myname = "tls_cipher_list";
+    const char *myname = "tls_set_ciphers";
     static VSTRING *buf;
-    va_list ap;
-    const char *exclude;
-    char   *tok;
+    int     new_grade;
     char   *save;
     char   *cp;
+    char   *tok;
+    const char *new_list;
 
-    buf = buf ? buf : vstring_alloc(10);
+    new_grade = tls_cipher_grade(grade);
+    if (new_grade == TLS_CIPHER_NONE) {
+       vstring_sprintf(app_ctx->why, "invalid %s cipher grade: \"%s\"",
+                       context, grade);
+       return (0);
+    }
+    if (buf == 0)
+       buf = vstring_alloc(10);
     VSTRING_RESET(buf);
 
-    switch (cipher_level) {
+    /*
+     * Given cached state and identical input, we return the same result.
+     */
+    if (app_ctx->cipher_list) {
+       if (new_grade == app_ctx->cipher_grade
+           && strcmp(app_ctx->cipher_exclusions, exclusions) == 0)
+           return (app_ctx->cipher_list);
+
+       /* Change required, flush cached state */
+       app_ctx->cipher_grade = TLS_CIPHER_NONE;
+
+       myfree(app_ctx->cipher_exclusions);
+       app_ctx->cipher_exclusions = 0;
+
+       myfree(app_ctx->cipher_list);
+       app_ctx->cipher_list = 0;
+    }
+    switch (new_grade) {
     case TLS_CIPHER_HIGH:
        vstring_strcpy(buf, var_tls_high_clist);
        break;
@@ -331,52 +467,95 @@ const char *tls_cipher_list(int cipher_level,...)
     case TLS_CIPHER_NULL:
        vstring_strcpy(buf, var_tls_null_clist);
        break;
-    case TLS_CIPHER_NONE:
-       return 0;
     default:
 
        /*
         * The caller MUST provide a valid cipher grade
         */
-       msg_panic("%s: invalid cipher grade: %d", myname, cipher_level);
+       msg_panic("invalid %s cipher grade: %d", context, new_grade);
     }
 
     /*
      * The base lists for each grade can't be empty.
      */
     if (VSTRING_LEN(buf) == 0)
-       msg_panic("%s: empty cipherlist", myname);
+       msg_panic("%s: empty \"%s\" cipherlist", myname, grade);
 
-    va_start(ap, cipher_level);
-    while ((exclude = va_arg(ap, char *)) != 0) {
-       if (*exclude == '\0')
-           continue;
-       save = cp = mystrdup(exclude);
-       while ((tok = mystrtok(&cp, "\t\n\r ,:")) != 0) {
+    /*
+     * Apply locally-specified exclusions.
+     */
+#define CIPHER_SEP "\t\n\r ,:"
+    if (exclusions != 0) {
+       cp = save = mystrdup(exclusions);
+       while ((tok = mystrtok(&cp, CIPHER_SEP)) != 0) {
 
            /*
             * Can't exclude ciphers that start with modifiers.
             */
            if (strchr("!+-@", *tok)) {
-               msg_warn("%s: can't exclude '!+-@' modifiers, '%s' ignored",
-                        myname, tok);
-               continue;
+               vstring_sprintf(app_ctx->why,
+                               "invalid unary '!+-@' in %s cipher "
+                               "exclusion: \"%s\"", context, tok);
+               return (0);
            }
            vstring_sprintf_append(buf, ":!%s", tok);
        }
        myfree(save);
     }
-    va_end(ap);
+    if ((new_list = tls_apply_cipher_list(app_ctx, context, buf)) == 0)
+       return (0);
 
-    return (vstring_str(buf));
+    /* Cache new state */
+    app_ctx->cipher_grade = new_grade;
+    app_ctx->cipher_exclusions = mystrdup(exclusions);
+
+    return (app_ctx->cipher_list = mystrdup(new_list));
 }
 
+/* tls_alloc_app_context - allocate TLS application context */
 
-/* tls_alloc_context - allocate TLScontext */
+TLS_APPL_STATE *tls_alloc_app_context(SSL_CTX *ssl_ctx)
+{
+    TLS_APPL_STATE *app_ctx;
+
+    app_ctx = (TLS_APPL_STATE *) mymalloc(sizeof(*app_ctx));
+
+    memset((char *) app_ctx, 0, sizeof(*app_ctx));
+    app_ctx->ssl_ctx = ssl_ctx;
+
+    /* See also: cache purging code in tls_set_ciphers(). */
+    app_ctx->cipher_grade = TLS_CIPHER_NONE;
+    app_ctx->cipher_exclusions = 0;
+    app_ctx->cipher_list = 0;
+    app_ctx->cache_type = 0;
+    app_ctx->why = vstring_alloc(1);
+
+    return (app_ctx);
+}
 
-TLScontext_t *tls_alloc_context(int log_level, const char *peername)
+/* tls_free_app_context - Free TLS application context */
+
+void    tls_free_app_context(TLS_APPL_STATE *app_ctx)
+{
+    if (app_ctx->ssl_ctx)
+       SSL_CTX_free(app_ctx->ssl_ctx);
+    if (app_ctx->cache_type)
+       myfree(app_ctx->cache_type);
+    /* See also: cache purging code in tls_set_ciphers(). */
+    if (app_ctx->cipher_exclusions)
+       myfree(app_ctx->cipher_exclusions);
+    if (app_ctx->cipher_list)
+       myfree(app_ctx->cipher_list);
+    if (app_ctx->why)
+       vstring_free(app_ctx->why);
+    myfree((char *) app_ctx);
+}
+
+/* tls_alloc_sess_context - allocate TLS session context */
+
+TLS_SESS_STATE *tls_alloc_sess_context(int log_level, const char *namaddr)
 {
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
 
     /*
      * PORTABILITY: Do not assume that null pointers are all-zero bits. Use
@@ -387,11 +566,12 @@ TLScontext_t *tls_alloc_context(int log_level, const char *peername)
      * 
      * However, it's OK to use memset() to zero integer values.
      */
-    TLScontext = (TLScontext_t *) mymalloc(sizeof(TLScontext_t));
+    TLScontext = (TLS_SESS_STATE *) mymalloc(sizeof(TLS_SESS_STATE));
     memset((char *) TLScontext, 0, sizeof(*TLScontext));
     TLScontext->con = 0;
     TLScontext->internal_bio = 0;
     TLScontext->network_bio = 0;
+    TLScontext->cache_type = 0;
     TLScontext->serverid = 0;
     TLScontext->peer_CN = 0;
     TLScontext->issuer_CN = 0;
@@ -399,14 +579,14 @@ TLScontext_t *tls_alloc_context(int log_level, const char *peername)
     TLScontext->protocol = 0;
     TLScontext->cipher_name = 0;
     TLScontext->log_level = log_level;
-    TLScontext->peername = lowercase(mystrdup(peername));
+    TLScontext->namaddr = lowercase(mystrdup(namaddr));
 
     return (TLScontext);
 }
 
 /* tls_free_context - deallocate TLScontext and members */
 
-void    tls_free_context(TLScontext_t *TLScontext)
+void    tls_free_context(TLS_SESS_STATE *TLScontext)
 {
 
     /*
@@ -419,8 +599,8 @@ void    tls_free_context(TLScontext_t *TLScontext)
     if (TLScontext->network_bio)
        BIO_free(TLScontext->network_bio);
 
-    if (TLScontext->peername)
-       myfree(TLScontext->peername);
+    if (TLScontext->namaddr)
+       myfree(TLScontext->namaddr);
     if (TLScontext->serverid)
        myfree(TLScontext->serverid);
 
@@ -601,8 +781,19 @@ void    tls_info_callback(const SSL *s, int where, int ret)
            msg_info("%s:failed in %s",
                     str, SSL_state_string_long((SSL *) s));
        else if (ret < 0) {
-           msg_info("%s:error in %s",
-                    str, SSL_state_string_long((SSL *) s));
+#ifndef LOG_NON_ERROR_STATES
+           switch (SSL_get_error((SSL *) s, ret)) {
+           case SSL_ERROR_WANT_READ:
+           case SSL_ERROR_WANT_WRITE:
+               /* Don't log non-error states. */
+               break;
+           default:
+#endif
+               msg_info("%s:error in %s",
+                        str, SSL_state_string_long((SSL *) s));
+#ifndef LOG_NON_ERROR_STATES
+           }
+#endif
        }
     }
 }
index 481a67f98a44b79b097ba860d06b593380bbc666..efca6be42bf2776b1d09fc0d49f3ef66cebe65c9 100644 (file)
@@ -6,17 +6,17 @@
 /* SYNOPSIS
 /*     #include <tls.h>
 /*
-/*     SSL_CTX *tls_server_init(props)
-/*     const tls_server_props *props;
+/*     TLS_APPL_STATE *tls_server_init(props)
+/*     const TLS_SERVER_INIT_PROPS *props;
 /*
-/*     TLScontext_t *tls_server_start(props)
-/*     const tls_server_start_props *props;
+/*     TLS_SESS_STATE *tls_server_start(props)
+/*     const TLS_SERVER_START_PROPS *props;
 /*
-/*     void    tls_server_stop(server_ctx, stream, failure, TLScontext)
-/*     SSL_CTX *server_ctx;
+/*     void    tls_server_stop(app_ctx, stream, failure, TLScontext)
+/*     TLS_APPL_STATE *app_ctx;
 /*     VSTREAM *stream;
 /*     int     failure;
-/*     TLScontext_t *TLScontext;
+/*     TLS_SESS_STATE *TLScontext;
 /* DESCRIPTION
 /*     This module is the interface between Postfix TLS servers,
 /*     the OpenSSL library, and the TLS entropy and cache manager.
@@ -34,8 +34,8 @@
 /*     SSL_shutdown() to the peer and resets all connection specific
 /*     TLS data. As RFC2487 does not specify a separate shutdown, it
 /*     is assumed that the underlying TCP connection is shut down
-/*     immediately afterwards, so we don't care about additional data
-/*     coming through the channel.
+/*     immediately afterwards. Any further writes to the channel will
+/*     be discarded, and any further reads will report end-of-file.
 /*     If the failure flag is set, no SSL_shutdown() handshake is performed.
 /*
 /*     Once the TLS connection is initiated, information about the TLS
 /*     The last two values may differ from each other when export-strength
 /*     encryption is used.
 /*
-/*     The status of the peer certificate verification is available in
-/*     TLScontext->peer_verified. It is set to 1 when the certificate could
-/*     be verified.
 /*     If the peer offered a certificate, part of the certificate data are
 /*     available as:
+/* .IP TLScontext->peer_status
+/*     A bitmask field that records the status of the peer certificate
+/*     verification. One or more of TLS_CERT_FLAG_PRESENT and
+/*     TLS_CERT_FLAG_TRUSTED.
 /* .IP TLScontext->peer_CN
 /*     Extracted CommonName of the peer, or zero-length string
 /*     when information could not be extracted.
 /*     Extracted CommonName of the issuer, or zero-length string
 /*     when information could not be extracted.
 /* .IP TLScontext->peer_fingerprint
-/*     Fingerprint of the certificate, or null pointer when no
-/*     certificate digest is available.
+/*     Fingerprint of the certificate, or zero-length string when no peer
+/*     certificate is available.
 /* .PP
-/*     Otherwise these fields are set to null pointers.
+/*     If no peer certificate is presented the peer_status is set to 0.
 /* LICENSE
 /* .ad
 /* .fi
@@ -87,6 +88,9 @@
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
 
 /* Application-specific. */
 
-/* We must keep some of the info available */
-static const char hexcodes[] = "0123456789ABCDEF";
-
  /*
   * The session_id_context indentifies the service that created a session.
   * This information is used to distinguish between multiple TLS-based
   * servers running on the same server. We use the name of the mail system.
   */
-static char server_session_id_context[] = "Postfix/TLS";
+static const char server_session_id_context[] = "Postfix/TLS";
 
 /* get_server_session_cb - callback to retrieve session from server cache */
 
@@ -139,7 +140,7 @@ static SSL_SESSION *get_server_session_cb(SSL *ssl, unsigned char *session_id,
                                                  int *unused_copy)
 {
     const char *myname = "get_server_session_cb";
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
     VSTRING *cache_id;
     VSTRING *session_data = vstring_alloc(2048);
     SSL_SESSION *session = 0;
@@ -158,7 +159,7 @@ static SSL_SESSION *get_server_session_cb(SSL *ssl, unsigned char *session_id,
     GEN_CACHE_ID(cache_id, session_id, session_id_length, TLScontext->serverid);
 
     if (TLScontext->log_level >= 2)
-       msg_info("looking up session %s in %s cache",
+       msg_info("%s: looking up session %s in %s cache", TLScontext->namaddr,
                 STR(cache_id), TLScontext->cache_type);
 
     /*
@@ -168,8 +169,9 @@ static SSL_SESSION *get_server_session_cb(SSL *ssl, unsigned char *session_id,
                       session_data) == TLS_MGR_STAT_OK) {
        session = tls_session_activate(STR(session_data), LEN(session_data));
        if (session && (TLScontext->log_level >= 2))
-           msg_info("reloaded session %s from %s cache",
-                    STR(cache_id), TLScontext->cache_type);
+           msg_info("%s: reloaded session %s from %s cache",
+                    TLScontext->namaddr, STR(cache_id),
+                    TLScontext->cache_type);
     }
 
     /*
@@ -183,7 +185,7 @@ static SSL_SESSION *get_server_session_cb(SSL *ssl, unsigned char *session_id,
 
 /* uncache_session - remove session from internal & external cache */
 
-static void uncache_session(SSL_CTX *ctx, TLScontext_t *TLScontext)
+static void uncache_session(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext)
 {
     VSTRING *cache_id;
     SSL_SESSION *session = SSL_get_session(TLScontext->con);
@@ -197,7 +199,7 @@ static void uncache_session(SSL_CTX *ctx, TLScontext_t *TLScontext)
                 TLScontext->serverid);
 
     if (TLScontext->log_level >= 2)
-       msg_info("remove session %s from %s cache",
+       msg_info("%s: remove session %s from %s cache", TLScontext->namaddr,
                 STR(cache_id), TLScontext->cache_type);
 
     tls_mgr_delete(TLScontext->cache_type, STR(cache_id));
@@ -210,7 +212,7 @@ static int new_server_session_cb(SSL *ssl, SSL_SESSION *session)
 {
     const char *myname = "new_server_session_cb";
     VSTRING *cache_id;
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
     VSTRING *session_data;
 
     if ((TLScontext = SSL_get_ex_data(ssl, TLScontext_index)) == 0)
@@ -220,7 +222,7 @@ static int new_server_session_cb(SSL *ssl, SSL_SESSION *session)
                 TLScontext->serverid);
 
     if (TLScontext->log_level >= 2)
-       msg_info("save session %s to %s cache",
+       msg_info("%s: save session %s to %s cache", TLScontext->namaddr,
                 STR(cache_id), TLScontext->cache_type);
 
     /*
@@ -244,18 +246,25 @@ static int new_server_session_cb(SSL *ssl, SSL_SESSION *session)
 
 /* tls_server_init - initialize the server-side TLS engine */
 
-SSL_CTX *tls_server_init(const tls_server_props *props)
+TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
 {
+    SSL_CTX *server_ctx;
     long    off = 0;
     int     verify_flags = SSL_VERIFY_NONE;
-    SSL_CTX *server_ctx;
     int     cachable;
-
-    /* See skeleton at OpenSSL apps/s_server.c. */
+    int     protomask;
+    TLS_APPL_STATE *app_ctx;
+    const EVP_MD *md_alg;
+    unsigned int md_len;
 
     if (props->log_level >= 2)
        msg_info("initializing the server-side TLS engine");
 
+    /*
+     * Load (mostly cipher related) TLS-library internal main.cf parameters.
+     */
+    tls_param_init();
+
     /*
      * Detect mismatch between compile-time headers and run-time library.
      */
@@ -269,6 +278,49 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
     SSL_load_error_strings();
     OpenSSL_add_ssl_algorithms();
 
+    /*
+     * First validate the protocols. If these are invalid, we can't continue.
+     */
+    protomask = tls_protocol_mask(props->protocols);
+    if (protomask == TLS_PROTOCOL_INVALID) {
+       /* tls_protocol_mask() logs no warning. */
+       msg_warn("Invalid TLS protocol list \"%s\": disabling TLS support",
+                props->protocols);
+       return (0);
+    }
+
+    /*
+     * Create an application data index for SSL objects, so that we can
+     * attach TLScontext information; this information is needed inside
+     * tls_verify_certificate_callback().
+     */
+    if (TLScontext_index < 0) {
+       if ((TLScontext_index = SSL_get_ex_new_index(0, 0, 0, 0, 0)) < 0) {
+           msg_warn("Cannot allocate SSL application data index: "
+                    "disabling TLS support");
+           return (0);
+       }
+    }
+
+    /*
+     * If the administrator specifies an unsupported digest algorithm, fail
+     * now, rather than in the middle of a TLS handshake.
+     */
+    if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) {
+       msg_warn("Digest algorithm \"%s\" not found: disabling TLS support",
+                props->fpt_dgst);
+       return (0);
+    }
+
+    /*
+     * Sanity check: Newer shared libraries may use larger digests.
+     */
+    if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) {
+       msg_warn("Digest algorithm \"%s\" output size %u too large:"
+                " disabling TLS support", props->fpt_dgst, md_len);
+       return (0);
+    }
+
     /*
      * Initialize the PRNG (Pseudo Random Number Generator) with some seed
      * from external and internal sources. Don't enable TLS without some real
@@ -290,52 +342,39 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
      * the protocol level, we can add an option to not use SSLv2/v3/TLSv1
      * later.
      */
-    server_ctx = SSL_CTX_new(SSLv23_server_method());
-    if (server_ctx == NULL) {
+    ERR_clear_error();
+    if ((server_ctx = SSL_CTX_new(SSLv23_server_method())) == 0) {
+       msg_warn("cannot allocate server SSL_CTX: disabling TLS support");
        tls_print_errors();
        return (0);
     }
 
+    /*
+     * See the verify callback in tls_verify.c
+     */
+    SSL_CTX_set_verify_depth(server_ctx, props->verifydepth + 1);
+
     /*
      * Protocol work-arounds, OpenSSL version dependent.
      */
     off |= tls_bug_bits();
     SSL_CTX_set_options(server_ctx, off);
 
-#define DISABLE_ALL (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1)
-
     /*
-     * Global protocol selection. Not enabling any explicitly, enables all.
+     * Global protocol selection.
      */
-    if (props->protocols != 0 && props->protocols != TLS_ALL_PROTOCOLS) {
-       long    disable = DISABLE_ALL;
-
-       if (props->protocols & TLS_PROTOCOL_TLSv1)
-           disable &= ~SSL_OP_NO_TLSv1;
-       if (props->protocols & TLS_PROTOCOL_SSLv3)
-           disable &= ~SSL_OP_NO_SSLv3;
-       if (props->protocols & TLS_PROTOCOL_SSLv2)
-           disable &= ~SSL_OP_NO_SSLv2;
-
-       SSL_CTX_set_options(server_ctx, disable);
-    }
+    if (protomask != 0)
+       SSL_CTX_set_options(server_ctx,
+                  ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L)
+                | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L)
+              | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L));
 
     /*
-     * Set the call-back routine for verbose logging.
+     * Set the call-back routine to debug handshake progress.
      */
     if (props->log_level >= 2)
        SSL_CTX_set_info_callback(server_ctx, tls_info_callback);
 
-    /*
-     * Override the default cipher list with our own list.
-     */
-    if (tls_set_cipher_list(server_ctx, props->cipherlist) == 0) {
-       SSL_CTX_free(server_ctx);
-       msg_warn("Invalid cipherlist \"%s\": disabling TLS support",
-                props->cipherlist);
-       return (0);                             /* Already logged */
-    }
-
     /*
      * Load the CA public key certificates for both the server cert and for
      * the verification of client certificates. As provided by OpenSSL we
@@ -349,6 +388,7 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
      */
     if (tls_set_ca_certificate_info(server_ctx,
                                    props->CAfile, props->CApath) < 0) {
+       /* tls_set_ca_certificate_info() already logs a warning. */
        SSL_CTX_free(server_ctx);               /* 200411 */
        return (0);
     }
@@ -369,6 +409,7 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
     if (tls_set_my_certificate_key_info(server_ctx, props->cert_file,
                                        props->key_file, props->dcert_file,
                                        props->dkey_file) < 0) {
+       /* tls_set_my_certificate_key_info() already logs a warning. */
        SSL_CTX_free(server_ctx);               /* 200411 */
        return (0);
     }
@@ -422,6 +463,12 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
        SSL_CTX_set_client_CA_list(server_ctx,
                                   SSL_load_client_CA_file(props->CAfile));
 
+    /*
+     * Initialize our own TLS server handle, before diving into the details
+     * of TLS session cache management.
+     */
+    app_ctx = tls_alloc_app_context(server_ctx);
+
     /*
      * The session cache is implemented by the tlsmgr(8) server.
      * 
@@ -433,21 +480,9 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
      * Victor Duchovni.
      */
 
-    if (TLSscache_index < 0)
-       TLSscache_index =
-           SSL_CTX_get_ex_new_index(0, "TLScontext ex_data index",
-                                    NULL, NULL, NULL);
-
     if (tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK)
        cachable = 0;
 
-    if (cachable &&
-       !SSL_CTX_set_ex_data(server_ctx, TLSscache_index,
-                            (void *) props->cache_type)) {
-       msg_warn("Session cache off: error saving cache type in SSL context.");
-       tls_print_errors();
-       cachable = 0;
-    }
     if (cachable || props->set_sessid) {
 
        /*
@@ -476,6 +511,8 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
                                       SSL_SESS_CACHE_SERVER |
                                       SSL_SESS_CACHE_NO_AUTO_CLEAR);
        if (cachable) {
+           app_ctx->cache_type = mystrdup(props->cache_type);
+
            SSL_CTX_sess_set_get_cb(server_ctx, get_server_session_cb);
            SSL_CTX_sess_set_new_cb(server_ctx, new_server_session_cb);
        }
@@ -496,16 +533,7 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
        SSL_CTX_set_session_cache_mode(server_ctx, SSL_SESS_CACHE_OFF);
     }
 
-    /*
-     * Create a global index so that we can attach TLScontext information to
-     * SSL objects; this information is needed inside
-     * tls_verify_certificate_callback().
-     */
-    if (TLScontext_index < 0)
-       TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index",
-                                               NULL, NULL, NULL);
-
-    return (server_ctx);
+    return (app_ctx);
 }
 
  /*
@@ -513,32 +541,42 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
   * the SMTP buffers are flushed and the "220 Ready to start TLS" was sent to
   * the client, so that we can immediately start the TLS handshake process.
   */
-TLScontext_t *tls_server_start(const tls_server_start_props *props)
+TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props)
 {
     int     sts;
-    int     j;
-    int     verify_flags;
-    unsigned int n;
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
     SSL_CIPHER *cipher;
     X509   *peer;
-    unsigned char md[EVP_MAX_MD_SIZE];
     char    buf[CCERT_BUFSIZ];
+    const char *cipher_list;
+    TLS_APPL_STATE *app_ctx = props->ctx;
 
     if (props->log_level >= 1)
-       msg_info("setting up TLS connection from %s[%s]",
-                props->peername, props->peeraddr);
+       msg_info("setting up TLS connection from %s", props->namaddr);
+
+    cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade,
+                                 props->cipher_exclusions);
+    if (cipher_list == 0) {
+       msg_warn("%s: %s: aborting TLS session", props->namaddr,
+                vstring_str(app_ctx->why));
+       return (0);
+    }
+    if (props->log_level >= 2)
+       msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list);
 
     /*
      * Allocate a new TLScontext for the new connection and get an SSL
      * structure. Add the location of TLScontext to the SSL to later retrieve
      * the information inside the tls_verify_certificate_callback().
      */
-    TLScontext = tls_alloc_context(props->log_level, props->peername);
-    TLScontext->cache_type = SSL_CTX_get_ex_data(props->ctx, TLSscache_index);
+    TLScontext = tls_alloc_sess_context(props->log_level, props->namaddr);
+    TLScontext->cache_type = app_ctx->cache_type;
+
     TLScontext->serverid = mystrdup(props->serverid);
+    TLScontext->am_server = 1;
 
-    if ((TLScontext->con = (SSL *) SSL_new(props->ctx)) == NULL) {
+    ERR_clear_error();
+    if ((TLScontext->con = (SSL *) SSL_new(app_ctx->ssl_ctx)) == 0) {
        msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
        tls_print_errors();
        tls_free_context(TLScontext);
@@ -551,21 +589,6 @@ TLScontext_t *tls_server_start(const tls_server_start_props *props)
        return (0);
     }
 
-    /*
-     * Set the verification parameters to be checked in
-     * tls_verify_certificate_callback().
-     */
-    if (props->requirecert) {
-       verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
-       verify_flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-       TLScontext->enforce_verify_errors = 1;
-       SSL_set_verify(TLScontext->con, verify_flags,
-                      tls_verify_certificate_callback);
-    } else {
-       TLScontext->enforce_verify_errors = 0;
-    }
-    TLScontext->enforce_CN = 0;
-
     /*
      * The TLS connection is realized by a BIO_pair, so obtain the pair.
      * 
@@ -624,8 +647,7 @@ TLScontext_t *tls_server_start(const tls_server_start_props *props)
     sts = tls_bio_accept(vstream_fileno(props->stream), props->timeout,
                         TLScontext);
     if (sts <= 0) {
-       msg_info("SSL_accept error from %s[%s]: %d",
-                props->peername, props->peeraddr, sts);
+       msg_info("SSL_accept error from %s: %d", props->namaddr, sts);
        tls_print_errors();
        tls_free_context(TLScontext);
        return (0);
@@ -639,8 +661,8 @@ TLScontext_t *tls_server_start(const tls_server_start_props *props)
      * session was negotiated.
      */
     TLScontext->session_reused = SSL_session_reused(TLScontext->con);
-    if (props->log_level >= 2 && TLScontext->session_reused)
-       msg_info("Reusing old session");
+    if (TLScontext->log_level >= 2 && TLScontext->session_reused)
+       msg_info("%s: Reusing old session", TLScontext->namaddr);
 
     /*
      * Let's see whether a peer certificate is available and what is the
@@ -648,8 +670,9 @@ TLScontext_t *tls_server_start(const tls_server_start_props *props)
      */
     peer = SSL_get_peer_certificate(TLScontext->con);
     if (peer != NULL) {
+       TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT;
        if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
-           TLScontext->peer_verified = 1;
+           TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED;
 
        if (props->log_level >= 2) {
            X509_NAME_oneline(X509_get_subject_name(peer),
@@ -659,50 +682,22 @@ TLScontext_t *tls_server_start(const tls_server_start_props *props)
                              buf, sizeof(buf));
            msg_info("issuer=%s", buf);
        }
-       if (X509_digest(peer, EVP_md5(), md, &n) && n > 0) {
-           TLScontext->peer_fingerprint = mymalloc(n * 3);
-           for (j = 0; j < (int) n; j++) {
-               TLScontext->peer_fingerprint[j * 3] =
-                   hexcodes[(md[j] & 0xf0) >> 4U];
-               TLScontext->peer_fingerprint[(j * 3) + 1] =
-                   hexcodes[(md[j] & 0x0f)];
-               if (j + 1 != (int) n)
-                   TLScontext->peer_fingerprint[(j * 3) + 2] = ':';
-               else
-                   TLScontext->peer_fingerprint[(j * 3) + 2] = '\0';
-           }
-           if (props->log_level >= 1)
-               msg_info("fingerprint=%s", TLScontext->peer_fingerprint);
-       }
-       if ((TLScontext->peer_CN = tls_peer_CN(peer)) == 0)
-           TLScontext->peer_CN = mystrdup("");
-       if ((TLScontext->issuer_CN = tls_issuer_CN(peer)) == 0)
-           TLScontext->issuer_CN = mystrdup("");
+       TLScontext->peer_CN = tls_peer_CN(peer, TLScontext);
+       TLScontext->issuer_CN = tls_issuer_CN(peer, TLScontext);
+       TLScontext->peer_fingerprint = tls_fingerprint(peer, props->fpt_dgst);
 
        if (props->log_level >= 1) {
-           if (TLScontext->peer_verified)
-               msg_info("Verified: subject_CN=%s, issuer=%s",
-                        TLScontext->peer_CN, TLScontext->issuer_CN);
-           else
-               msg_info("Unverified: subject_CN=%s, issuer=%s",
-                        TLScontext->peer_CN, TLScontext->issuer_CN);
+           msg_info("%s: %s: subject_CN=%s, issuer=%s, fingerprint=%s",
+                    props->namaddr,
+                 TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
+                    TLScontext->peer_CN, TLScontext->issuer_CN,
+                    TLScontext->peer_fingerprint);
        }
        X509_free(peer);
-    }
-
-    /*
-     * If this is a cached session, we have to check by hand if the cached
-     * session peer was verified.
-     */
-    if (props->requirecert) {
-       if (!TLScontext->peer_verified || !TLScontext->peer_CN) {
-           if (TLScontext->session_reused == 0)
-               msg_panic("tls_server_start: peer was not verified");
-           msg_info("Re-used session without peer certificate removed");
-           uncache_session(props->ctx, TLScontext);
-           tls_free_context(TLScontext);
-           return (0);
-       }
+    } else {
+       TLScontext->peer_CN = mystrdup("");
+       TLScontext->issuer_CN = mystrdup("");
+       TLScontext->peer_fingerprint = mystrdup("");
     }
 
     /*
@@ -720,11 +715,16 @@ TLScontext_t *tls_server_start(const tls_server_start_props *props)
      */
     tls_stream_start(props->stream, TLScontext);
 
+    /*
+     * All the key facts in a single log entry.
+     */
     if (props->log_level >= 1)
-       msg_info("TLS connection established from %s[%s]: %s with cipher %s (%d/%d bits)",
-                props->peername, props->peeraddr,
-                TLScontext->protocol, TLScontext->cipher_name,
+       msg_info("%s TLS connection established from %s: %s with cipher %s "
+             "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous"
+                : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
+             props->namaddr, TLScontext->protocol, TLScontext->cipher_name,
                 TLScontext->cipher_usebits, TLScontext->cipher_algbits);
+
     tls_int_seed();
 
     return (TLScontext);
index 864bc4627076b3ef195a158fbe38d029b21215f7..8fc11cf26029259a3834eda854bcaa1e4ff031a9 100644 (file)
@@ -7,11 +7,11 @@
 /*     #include <tls.h>
 /*
 /*     void    tls_session_stop(ctx, stream, timeout, failure, TLScontext)
-/*     SSL_CTX *ctx;
+/*     TLS_APPL_STATE *ctx;
 /*     VSTREAM *stream;
 /*     int     timeout;
 /*     int     failure;
-/*     TLScontext_t *TLScontext;
+/*     TLS_SESS_STATE *TLScontext;
 /*
 /*     VSTRING *tls_session_passivate(session)
 /*     SSL_SESSION *session;
@@ -49,6 +49,9 @@
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
@@ -74,8 +77,8 @@
 
 /* tls_session_stop - shut down the TLS connection and reset state */
 
-void    tls_session_stop(SSL_CTX *unused_ctx, VSTREAM *stream, int timeout,
-                                int failure, TLScontext_t *TLScontext)
+void    tls_session_stop(TLS_APPL_STATE *unused_ctx, VSTREAM *stream, int timeout,
+                                int failure, TLS_SESS_STATE *TLScontext)
 {
     const char *myname = "tls_session_stop";
     int     retval;
index 19531407e8c65b85ed257b53ff8f326ac725b69b..ca73a11366048c7d20a83774ad73d9fb5cca5c27 100644 (file)
@@ -9,7 +9,7 @@
 /*
 /*     void    tls_stream_start(stream, context)
 /*     VSTREAM *stream;
-/*     TLScontext_t *context;
+/*     TLS_SESS_STATE *context;
 /*
 /*     void    tls_stream_stop(stream)
 /*     VSTREAM *stream;
@@ -72,9 +72,9 @@ static ssize_t tls_timed_read(int fd, void *buf, size_t len, int timeout,
 {
     const char *myname = "tls_timed_read";
     ssize_t ret;
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
 
-    TLScontext = (TLScontext_t *) context;
+    TLScontext = (TLS_SESS_STATE *) context;
     if (!TLScontext)
        msg_panic("%s: no context", myname);
 
@@ -91,9 +91,9 @@ static ssize_t tls_timed_write(int fd, void *buf, size_t len, int timeout,
                                       void *context)
 {
     const char *myname = "tls_timed_write";
-    TLScontext_t *TLScontext;
+    TLS_SESS_STATE *TLScontext;
 
-    TLScontext = (TLScontext_t *) context;
+    TLScontext = (TLS_SESS_STATE *) context;
     if (!TLScontext)
        msg_panic("%s: no context", myname);
 
@@ -105,7 +105,7 @@ static ssize_t tls_timed_write(int fd, void *buf, size_t len, int timeout,
 
 /* tls_stream_start - start VSTREAM over TLS */
 
-void    tls_stream_start(VSTREAM *stream, TLScontext_t *context)
+void    tls_stream_start(VSTREAM *stream, TLS_SESS_STATE *context)
 {
     vstream_control(stream,
                    VSTREAM_CTL_READ_FN, tls_timed_read,
index 2c9edd008796b4eddf1cda3818a8256620fcca16..0c9075061d68bfaed9ce9ce2d1022a8de69cfda9 100644 (file)
@@ -7,26 +7,47 @@
 /*     #define TLS_INTERNAL
 /*     #include <tls.h>
 /*
-/*     char *tls_peer_CN(peercert)
+/*     char *tls_peer_CN(peercert, TLScontext)
 /*     X509   *peercert;
+/*     TLS_SESS_STATE *TLScontext;
 /*
-/*     char *tls_issuer_CN(peercert)
+/*     char *tls_issuer_CN(peercert, TLScontext)
 /*     X509   *peercert;
+/*     TLS_SESS_STATE *TLScontext;
+/*
+/*     const char *tls_dns_name(gn, TLScontext)
+/*     const GENERAL_NAME *gn;
+/*     TLS_SESS_STATE *TLScontext;
+/*
+/*     char *tls_fingerprint(peercert, dgst)
+/*     X509   *peercert;
+/*     const char *dgst;
 /*
 /*     int     tls_verify_certificate_callback(ok, ctx)
 /*     int     ok;
 /*     X509_STORE_CTX *ctx;
 /* DESCRIPTION
 /*     tls_peer_CN() returns the text CommonName for the peer
-/*     certificate subject, or a null pointer if no CommonName was
+/*     certificate subject, or an empty string if no CommonName was
 /*     found. The result is allocated with mymalloc() and must be
 /*     freed by the caller.
 /*
 /*     tls_issuer_CN() returns the text CommonName for the peer
-/*     certificate issuer, or a null pointer if no CommonName was
+/*     certificate issuer, or an empty string if no CommonName was
 /*     found. The result is allocated with mymalloc() and must be
 /*     freed by the caller.
 /*
+/*     tls_dns_name() returns the string value of a GENERAL_NAME
+/*     from a DNS subjectAltName extension. If non-printable characters
+/*     are found, a null string is returned instead. Further sanity
+/*     checks may be added if the need arises.
+/*
+/*     tls_fingerprint() returns a fingerprint of the the given
+/*     certificate using the requested message digest. Panics if the
+/*     (previously verified) digest algorithm is not found. The return
+/*     value is dynamically allocated with mymalloc(), and the caller
+/*     must eventually free it with myfree().
+/*
 /*     tls_verify_callback() is called several times (directly or
 /*     indirectly) from crypto/x509/x509_vfy.c. It is called as
 /*     a final check, and if it returns "0", the handshake is
 /*     are disabled when verification failed because of some
 /*     earlier problem.
 /* .IP ctx
-/*     TLS client or server context. This also specifies the
-/*     TLScontext with enforcement options.
+/*     SSL application context. This links to the Postfix TLScontext
+/*     with enforcement and logging options.
+/* .IP gn
+/*     An OpenSSL GENERAL_NAME structure holding a DNS subjectAltName
+/*     to be decoded and checked for validity.
+/* .IP peercert
+/*     Server or client X.509 certificate.
+/* .IP dgst
+/*     Name of a message digest algorithm suitable for computing secure
+/*     (1st pre-image resistant) message digests of certificates. For now,
+/*     md5, sha1, or member of SHA-2 family if supported by OpenSSL.
+/* .IP TLScontext
+/*     Server or client context for warning messages.
 /* DIAGNOSTICS
-/*     tls_peer_CN() and tls_issuer_CN() log a warning and return
-/*     a null pointer when 1) the requested information is not
-/*     available in the specified certificate, 2) the result
-/*     exceeds a fixed limit, or 3) the result contains null
-/*     characters.
+/*     tls_peer_CN(), tls_issuer_CN() and tls_dns_name() log a warning
+/*     when 1) the requested information is not available in the specified
+/*     certificate, 2) the result exceeds a fixed limit, 3) the result
+/*     contains NUL characters or the result contains non-printable or
+/*     non-ASCII characters.
 /* LICENSE
 /* .ad
 /* .fi
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Victor Duchovni
+/*     Morgan Stanley
 /*--*/
 
 /* System library. */
 
 #include <sys_defs.h>
+#include <ctype.h>
 
 #ifdef USE_TLS
 #include <string.h>
 
 #include <msg.h>
 #include <mymalloc.h>
+#include <stringops.h>
 
 /* TLS library. */
 
 #define TLS_INTERNAL
 #include <tls.h>
 
+/* Application-specific. */
+
+static const char hexcodes[] = "0123456789ABCDEF";
+
 /* tls_verify_certificate_callback - verify peer certificate info */
 
 int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
 {
-    char    buf[1024];
-    X509   *err_cert;
+    char    buf[CCERT_BUFSIZ];
+    X509   *cert;
     int     err;
     int     depth;
-    int     verify_depth;
     SSL    *con;
-    TLScontext_t *TLScontext;
-
-    /* Adapted from OpenSSL apps/s_cb.c */
+    TLS_SESS_STATE *TLScontext;
 
-    err_cert = X509_STORE_CTX_get_current_cert(ctx);
-    err = X509_STORE_CTX_get_error(ctx);
     depth = X509_STORE_CTX_get_error_depth(ctx);
-
+    cert = X509_STORE_CTX_get_current_cert(ctx);
     con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
     TLScontext = SSL_get_ex_data(con, TLScontext_index);
 
-    X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
-    if (TLScontext->log_level >= 2)
-       msg_info("certificate verification depth=%d subject=%s", depth, buf);
-
     /*
-     * Test for a too long certificate chain, because that error condition is
-     * not handled by the OpenSSL library.
+     * The callback function is called repeatedly, first with the root
+     * certificate, and then with each intermediate certificate ending with
+     * the peer certificate.
+     * 
+     * With each call, the validity of the current certificate (usage bits,
+     * attributes, expiration, ... checked by the OpenSSL library) is
+     * available in the "ok" argument. Error details are available via
+     * X509_STORE_CTX API.
+     * 
+     * We never terminate the SSL handshake in the verification callback, rather
+     * we allow the TLS handshake to continue, but mark the session as
+     * unverified. The application is responsible for closing any sessions
+     * with unverified credentials.
+     * 
+     * Certificate chain depth limit violations are mis-reported by the OpenSSL
+     * library, from SSL_CTX_set_verify(3):
+     * 
+     * The certificate verification depth set with SSL[_CTX]_verify_depth()
+     * stops the verification at a certain depth. The error message produced
+     * will be that of an incomplete certificate chain and not
+     * X509_V_ERR_CERT_CHAIN_TOO_LONG as may be expected.
+     * 
+     * We set a limit that is one higher than the user requested limit. If this
+     * higher limit is reached, we raise an error even a trusted root CA is
+     * present at this depth. This disambiguates trust chain truncation from
+     * an incomplete trust chain.
      */
-    verify_depth = SSL_get_verify_depth(con);
-    if (ok && (verify_depth >= 0) && (depth > verify_depth)) {
+    if (depth >= SSL_get_verify_depth(con)) {
        ok = 0;
-       err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
-       X509_STORE_CTX_set_error(ctx, err);
+       X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
     }
-    if (!ok) {
-       msg_info("certificate verification failed for %s: num=%d:%s",
-                TLScontext->peername, err,
-                X509_verify_cert_error_string(err));
+    if (TLScontext->log_level >= 2) {
+       X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
+       msg_info("%s: certificate verification depth=%d verify=%d subject=%s",
+                TLScontext->namaddr, depth, ok, printable(buf, '?'));
     }
 
     /*
-     * We delay peername verification until the SSL handshake completes. The
-     * peername verification previously done here is now called directly from
-     * tls_client_start(). This substantially simplifies the cache interface.
+     * If no errors, or we are not logging verification errors, we are done.
      */
+    if (ok || (TLScontext->peer_status & TLS_CERT_FLAG_LOGGED) != 0)
+       return (1);
 
     /*
-     * Other causes for verification failure.
+     * One counter-example is enough.
      */
-    switch (ctx->error) {
-    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+    TLScontext->peer_status |= TLS_CERT_FLAG_LOGGED;
+
+#define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server")
+
+    /*
+     * Specific causes for verification failure.
+     */
+    switch (err = X509_STORE_CTX_get_error(ctx)) {
+    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+       msg_info("certificate verification failed for %s: "
+                "self-signed certificate", TLScontext->namaddr);
+       break;
+    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+
+       /*
+        * There is no difference between issuing cert not provided and
+        * provided, but not found in CAfile/CApath. Either way, we don't
+        * trust it.
+        */
        X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),
                          buf, sizeof(buf));
-       msg_info("certificate verification failed for %s:"
-                "issuer %s certificate unavailable",
-                TLScontext->peername, buf);
+       msg_info("certificate verification failed for %s: untrusted issuer %s",
+                TLScontext->namaddr, printable(buf, '?'));
        break;
     case X509_V_ERR_CERT_NOT_YET_VALID:
     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
-       msg_info("certificate verification failed for %s:"
-                "certificate not yet valid",
-                TLScontext->peername);
+       msg_info("%s certificate verification failed for %s: certificate not"
+                " yet valid", PURPOSE, TLScontext->namaddr);
        break;
     case X509_V_ERR_CERT_HAS_EXPIRED:
     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
-       msg_info("certificate verification failed for %s:"
-                "certificate has expired",
-                TLScontext->peername);
+       msg_info("%s certificate verification failed for %s: certificate has"
+                " expired", PURPOSE, TLScontext->namaddr);
+       break;
+    case X509_V_ERR_INVALID_PURPOSE:
+       msg_info("certificate verification failed for %s: not designated for "
+                "use as a %s certificate", TLScontext->namaddr, PURPOSE);
+       break;
+    case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+       msg_info("certificate verification failed for %s: "
+                "certificate chain longer than limit(%d)",
+                TLScontext->namaddr, SSL_get_verify_depth(con) - 1);
+       break;
+    default:
+       msg_info("%s certificate verification failed for %s: num=%d:%s",
+                PURPOSE, TLScontext->namaddr, err,
+                X509_verify_cert_error_string(err));
        break;
     }
-    if (TLScontext->log_level >= 2)
-       msg_info("verify return: %d", ok);
 
-    /*
-     * Never fail in case of opportunistic mode.
-     */
-    if (TLScontext->enforce_verify_errors)
-       return (ok);
-    else
-       return (1);
+    return (1);
 }
 
 #ifndef DONT_GRIPE
@@ -196,95 +271,223 @@ int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
 
 /* tls_text_name - extract certificate property value by name */
 
-static char *tls_text_name(X509_NAME *name, int nid, char *label, int gripe)
+static char *tls_text_name(X509_NAME *name, int nid, const char *label,
+                               const TLS_SESS_STATE *TLScontext, int gripe)
 {
-    int     len;
+    const char *myname = "tls_text_name";
     int     pos;
     X509_NAME_ENTRY *entry;
     ASN1_STRING *entry_str;
-    unsigned char *tmp;
-    char   *result;
+    int     typ;
+    int     len;
+    unsigned char *val;
+    unsigned char *utf;
+    char   *cp;
 
-    if (name == 0
-       || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
+    if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
        if (gripe != DONT_GRIPE) {
-           msg_warn("peer certificate has no %s", label);
+           msg_warn("%s: %s: peer certificate has no %s",
+                    myname, TLScontext->namaddr, label);
            tls_print_errors();
        }
        return (0);
     }
-
 #if 0
+
     /*
-     * If the match is required unambiguous, insist that that no
-     * other values be present.
+     * If the match is required unambiguous, insist that that no other values
+     * be present.
      */
-    if (unique == UNIQUE && X509_NAME_get_index_by_NID(name, nid, pos) >= 0) {
-       msg_warn("multiple %ss in peer certificate", label);
+    if (X509_NAME_get_index_by_NID(name, nid, pos) >= 0) {
+       msg_warn("%s: %s: multiple %ss in peer certificate",
+                myname, TLScontext->namaddr, label);
        return (0);
     }
 #endif
 
     if ((entry = X509_NAME_get_entry(name, pos)) == 0) {
        /* This should not happen */
-       msg_warn("error reading peer certificate %s entry", label);
+       msg_warn("%s: %s: error reading peer certificate %s entry",
+                myname, TLScontext->namaddr, label);
        tls_print_errors();
        return (0);
     }
-
     if ((entry_str = X509_NAME_ENTRY_get_data(entry)) == 0) {
        /* This should not happen */
-       msg_warn("error reading peer certificate %s data", label);
+       msg_warn("%s: %s: error reading peer certificate %s data",
+                myname, TLScontext->namaddr, label);
        tls_print_errors();
        return (0);
     }
 
-    if ((len = ASN1_STRING_to_UTF8(&tmp, entry_str)) < 0) {
-       /* This should not happen */
-       msg_warn("error decoding peer certificate %s data", label);
-       tls_print_errors();
-       return (0);
-    }
+    /*
+     * Peername checks are security sensitive, carefully scrutinize the
+     * input!
+     */
+    typ = ASN1_STRING_type(entry_str);
+    len = ASN1_STRING_length(entry_str);
+    val = ASN1_STRING_data(entry_str);
 
     /*
-     * Since the peer CN is used in peer verification, take care to detect
-     * truncation due to excessive length or internal NULs.
+     * http://www.apps.ietf.org/rfc/rfc3280.html#sec-4.1.2.4 Quick Summary:
+     * 
+     * The DirectoryString type is defined as a choice of PrintableString,
+     * TeletexString, BMPString, UTF8String, and UniversalString.  The
+     * UTF8String encoding is the preferred encoding, and all certificates
+     * issued after December 31, 2003 MUST use the UTF8String encoding of
+     * DirectoryString (except as noted below).
+     * 
+     * XXX: 2007, the above has not happened yet (of course), and we continue to
+     * see new certificates with T61STRING (Teletex) attribute values.
+     * 
+     * XXX: 2007, at this time there are only two ASN.1 fixed width multi-byte
+     * string encodings, BMPSTRING (16 bit Unicode) and UniversalString
+     * (32-bit Unicode). The only variable width ASN.1 string encoding is
+     * UTF8 with all the other encodings being 1 byte wide subsets or subsets
+     * of ASCII.
+     * 
+     * Relying on this could simplify the code, because we would never convert
+     * unexpected single-byte encodings, but is involves too many cases to be
+     * sure that we have a complete set and the assumptions may become false.
+     * So, we pessimistically convert encodings not blessed by RFC 2459, and
+     * filter out all types that are not string types as a side-effect of
+     * UTF8 conversion (the ASN.1 library knows which types are string types
+     * and how wide they are...).
+     * 
+     * XXX: Two possible states after switch, either "utf == val" and it MUST
+     * NOT be freed with OPENSSL_free(), or "utf != val" and it MUST be freed
+     * with OPENSSL_free().
      */
+    switch (typ) {
+    case V_ASN1_PRINTABLESTRING:               /* X.500 portable ASCII
+                                                * printables */
+    case V_ASN1_IA5STRING:                     /* ISO 646 ~ ASCII */
+    case V_ASN1_T61STRING:                     /* Essentially ISO-Latin */
+    case V_ASN1_UTF8STRING:                    /* UTF8 */
+       utf = val;
+       break;
+
+    default:
+
+       /*
+        * May shrink in wash, but BMPSTRING only shrinks by 50%. Others may
+        * shrink by up to 75%. We Sanity check the length before bothering
+        * to copy any large strings to convert to UTF8, only to find out
+        * they don't fit. So long as no new MB types are introduced, and
+        * weird string encodings unsanctioned by RFC 3280, are used in the
+        * issuer or subject DN, this "conservative" estimate will be exact.
+        */
+       len >>= (typ == V_ASN1_BMPSTRING) ? 1 : 2;
+       if (len >= CCERT_BUFSIZ) {
+           msg_warn("%s: %s: peer %s too long: %d",
+                    myname, TLScontext->namaddr, label, len);
+           return (0);
+       }
+       if ((len = ASN1_STRING_to_UTF8(&utf, entry_str)) < 0) {
+           msg_warn("%s: %s: error decoding peer %s of ASN.1 type=%d",
+                    myname, TLScontext->namaddr, label, typ);
+           tls_print_errors();
+           return (0);
+       }
+    }
+#define RETURN(x) do { if (utf!=val) OPENSSL_free(utf); return (x); } while (0)
+
     if (len >= CCERT_BUFSIZ) {
-       OPENSSL_free(tmp);
-       msg_warn("peer %s too long: %d", label, (int) len);
-       return (0);
+       msg_warn("%s: %s: peer %s too long: %d",
+                myname, TLScontext->namaddr, label, len);
+       RETURN(0);
+    }
+    if (len != strlen((char *) utf)) {
+       msg_warn("%s: %s: internal NUL in peer %s",
+                myname, TLScontext->namaddr, label);
+       RETURN(0);
     }
+    for (cp = (char *) utf; *cp; cp++) {
+       if (!ISASCII(*cp) || !ISPRINT(*cp)) {
+           msg_warn("%s: %s: non-printable characters in peer %s",
+                    myname, TLScontext->namaddr, label);
+           RETURN(0);
+       }
+    }
+    cp = mystrdup((char *) utf);
+    RETURN(cp);
+}
+
+/* tls_dns_name - Extract valid DNS name from subjectAltName value */
+
+const char *tls_dns_name(const GENERAL_NAME * gn,
+                                const TLS_SESS_STATE *TLScontext)
+{
+    const char *myname = "tls_dns_name";
+    char   *cp;
+    const char *dnsname;
+
+    /*
+     * Peername checks are security sensitive, carefully scrutinize the
+     * input!
+     */
+    if (gn->type != GEN_DNS)
+       msg_panic("%s: Non DNS input argument", myname);
 
     /*
-     * Standard UTF8 does not encode NUL as 0b11000000, that is
-     * a Java "feature". So we need to check for embedded NULs.
+     * We expect the OpenSSL library to construct GEN_DNS extesion objects as
+     * ASN1_IA5STRING values. Check we got the right union member.
      */
-    if (strlen((char *) tmp) != len) {
-       msg_warn("internal NUL in peer %s", label);
-       OPENSSL_free(tmp);
+    if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) {
+       msg_warn("%s: %s: invalid ASN1 value type in subjectAltName",
+                myname, TLScontext->namaddr);
        return (0);
     }
 
-    result = mystrdup((char *) tmp);
-    OPENSSL_free(tmp);
-    return (result);
+    /*
+     * Safe to treat as an ASCII string possibly holding a DNS name
+     */
+    dnsname = (char *) ASN1_STRING_data(gn->d.ia5);
+
+    /*
+     * Per Dr. Steven Henson of the OpenSSL development team, ASN1_IA5STRING
+     * values can have internal ASCII NUL values in this context because
+     * their length is taken from the decoded ASN1 buffer, a trailing NUL is
+     * always appended to make sure that the string is terminated, but the
+     * ASN.1 length may differ from strlen().
+     */
+    if (ASN1_STRING_length(gn->d.ia5) != strlen(dnsname)) {
+       msg_warn("%s: %s: internal NUL in subjectAltName",
+                myname, TLScontext->namaddr);
+       return 0;
+    }
+
+    /*
+     * XXX: Should we be more strict and call valid_hostname()? So long as
+     * the name is safe to handle, if it is not a valid hostname, it will not
+     * compare equal to the expected peername, so being more strict than
+     * "printable" is likely excessive...
+     */
+    for (cp = (char *) dnsname; cp && *cp; cp++)
+       if (!ISASCII(*cp) || !ISPRINT(*cp)) {
+           cp = mystrdup(dnsname);
+           msg_warn("%s: %s: non-printable characters in subjectAltName: %s",
+                    myname, TLScontext->namaddr, printable(cp, '?'));
+           myfree(cp);
+           return 0;
+       }
+    return (dnsname);
 }
 
 /* tls_peer_CN - extract peer common name from certificate */
 
-char   *tls_peer_CN(X509 *peercert)
+char   *tls_peer_CN(X509 *peercert, const TLS_SESS_STATE *TLScontext)
 {
     char   *cn;
 
-    cn = tls_text_name(X509_get_subject_name(peercert),
-                      NID_commonName, "subject CN", DO_GRIPE);
-    return (cn);
+    cn = tls_text_name(X509_get_subject_name(peercert), NID_commonName,
+                      "subject CN", TLScontext, DO_GRIPE);
+    return (cn ? cn : mystrdup(""));
 }
 
 /* tls_issuer_CN - extract issuer common name from certificate */
 
-char   *tls_issuer_CN(X509 *peer)
+char   *tls_issuer_CN(X509 *peer, const TLS_SESS_STATE *TLScontext)
 {
     X509_NAME *name;
     char   *cn;
@@ -295,10 +498,45 @@ char   *tls_issuer_CN(X509 *peer)
      * If no issuer CN field, use Organization instead. CA certs without a CN
      * are common, so we only complain if the organization is also missing.
      */
-    if ((cn = tls_text_name(name, NID_commonName, "issuer CN", DONT_GRIPE)) == 0)
+    if ((cn = tls_text_name(name, NID_commonName,
+                           "issuer CN", TLScontext, DONT_GRIPE)) == 0)
        cn = tls_text_name(name, NID_organizationName,
-                          "issuer Organization", DO_GRIPE);
-    return (cn);
+                          "issuer Organization", TLScontext, DO_GRIPE);
+    return (cn ? cn : mystrdup(""));
+}
+
+/* tls_fingerprint - extract fingerprint from certificate */
+
+char   *tls_fingerprint(X509 *peercert, const char *dgst)
+{
+    const char *myname = "tls_fingerprint";
+    const EVP_MD *md_alg;
+    unsigned char md_buf[EVP_MAX_MD_SIZE];
+    unsigned int md_len;
+    int     i;
+    char   *result = 0;
+
+    /* Previously available in "init" routine. */
+    if ((md_alg = EVP_get_digestbyname(dgst)) == 0)
+       msg_panic("%s: digest algorithm \"%s\" not found", myname, dgst);
+
+    /* Fails when serialization to ASN.1 runs out of memory */
+    if (X509_digest(peercert, md_alg, md_buf, &md_len) == 0)
+       msg_fatal("%s: error computing certificate %s digest (out of memory?)",
+                 myname, dgst);
+
+    /* Check for OpenSSL contract violation */
+    if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
+       msg_panic("%s: unexpectedly large %s digest size: %u",
+                 myname, dgst, md_len);
+
+    result = mymalloc(md_len * 3);
+    for (i = 0; i < md_len; i++) {
+       result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
+       result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
+       result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
+    }
+    return (result);
 }
 
 #endif
index 39843e6eb3c1c4d52df3597b2cd56f85cdb63564..acf2fa959bf2ad15ebf535ea34da13961a2b4198 100644 (file)
   * Tunables.
   */
 char   *var_tls_rand_source;
-int     var_tls_daemon_rand_bytes;
 int     var_tls_rand_bytes;
 int     var_tls_reseed_period;
 int     var_tls_prng_exch_period;
@@ -925,7 +924,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_TLS_RAND_SOURCE, DEF_TLS_RAND_SOURCE, &var_tls_rand_source, 0, 0,
        VAR_TLS_RAND_EXCH_NAME, DEF_TLS_RAND_EXCH_NAME, &var_tls_rand_exch_name, 0, 0,
        VAR_SMTPD_TLS_SCACHE_DB, DEF_SMTPD_TLS_SCACHE_DB, &var_smtpd_tls_scache_db, 0, 0,
@@ -933,7 +932,7 @@ int     main(int argc, char **argv)
        VAR_LMTP_TLS_SCACHE_DB, DEF_LMTP_TLS_SCACHE_DB, &var_lmtp_tls_scache_db, 0, 0,
        0,
     };
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 1, 0,
        VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_exch_period, 1, 0,
        VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, 0,
@@ -941,7 +940,7 @@ int     main(int argc, char **argv)
        VAR_LMTP_TLS_SCACHTIME, DEF_LMTP_TLS_SCACHTIME, &var_lmtp_tls_scache_timeout, 0, 0,
        0,
     };
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_TLS_RAND_BYTES, DEF_TLS_RAND_BYTES, &var_tls_rand_bytes, 1, 0,
        VAR_SMTPD_TLS_LOGLEVEL, DEF_SMTPD_TLS_LOGLEVEL, &var_smtpd_tls_loglevel, 0, 0,
        VAR_SMTP_TLS_LOGLEVEL, DEF_SMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0,
index 5ce2ca8b3a7e2a19c62326735da7e526b48e2d41..fed4cfb38e66ee2f96ab686860c10f6a3e763b31 100644 (file)
@@ -549,7 +549,7 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
        VAR_LOCAL_TRANSPORT, DEF_LOCAL_TRANSPORT, &var_local_transport, 1, 0,
        VAR_VIRT_TRANSPORT, DEF_VIRT_TRANSPORT, &var_virt_transport, 1, 0,
@@ -573,7 +573,7 @@ int     main(int argc, char **argv)
        VAR_VRFY_RELAY_MAPS, DEF_VRFY_RELAY_MAPS, &var_vrfy_relay_maps, 0, 0,
        0,
     };
-    static CONFIG_BOOL_TABLE bool_table[] = {
+    static const CONFIG_BOOL_TABLE bool_table[] = {
        VAR_SWAP_BANGPATH, DEF_SWAP_BANGPATH, &var_swap_bangpath,
        VAR_APP_DOT_MYDOMAIN, DEF_APP_DOT_MYDOMAIN, &var_append_dot_mydomain,
        VAR_APP_AT_MYORIGIN, DEF_APP_AT_MYORIGIN, &var_append_at_myorigin,
index 18a3716be2463dc43c70ff5974542a9ffbfcfc85..4747d33e77d27c3d39c9ec3cbdcf7d2ab290e9ac 100644 (file)
@@ -519,7 +519,7 @@ int     dict_changed(void)
  /*
   * Mapping between flag names and flag values.
   */
-static NAME_MASK dict_mask[] = {
+static const NAME_MASK dict_mask[] = {
     "warn_dup", (1 << 0),              /* if file, warn about dups */
     "ignore_dup", (1 << 1),            /* if file, ignore dups */
     "try0null", (1 << 2),              /* do not append 0 to key/value */
index c44e3d643f9287adddf0f3ac2e392ee84e394823..05e6743f982e06a9deacf448167260cc1a2ff683 100644 (file)
@@ -270,7 +270,8 @@ static void dict_cdbm_update(DICT *dict, const char *name, const char *value)
     if (r < 0)
        msg_fatal("error writing %s: %m", dict_cdbm->tmp_path);
     else if (r > 0) {
-       if (dict->flags & (DICT_FLAG_DUP_IGNORE | DICT_FLAG_DUP_REPLACE));
+       if (dict->flags & (DICT_FLAG_DUP_IGNORE | DICT_FLAG_DUP_REPLACE))
+            /* void */ ;
        else if (dict->flags & DICT_FLAG_DUP_WARN)
            msg_warn("%s: duplicate entry: \"%s\"",
                     dict_cdbm->dict.name, name);
index 233039c08e837d0386762880dd69eda87fdd1e58..3e0beb7d6639ff97774b5e9c1d5ac21adbd70ac0 100644 (file)
@@ -215,7 +215,7 @@ typedef struct {
     struct DICT *(*open) (const char *, int, int);
 } DICT_OPEN_INFO;
 
-static DICT_OPEN_INFO dict_open_info[] = {
+static const DICT_OPEN_INFO dict_open_info[] = {
 #ifdef HAS_CDB
     DICT_TYPE_CDB, dict_cdb_open,
 #endif
@@ -261,7 +261,7 @@ static HTABLE *dict_open_hash;
 static void dict_open_init(void)
 {
     const char *myname = "dict_open_init";
-    DICT_OPEN_INFO *dp;
+    const DICT_OPEN_INFO *dp;
 
     if (dict_open_hash != 0)
        msg_panic("%s: multiple initialization", myname);
index 06e2c43b7b3a5d898b21caa73705f82da1b5e4a6..c0ad50675dbebb422c5f8ae275e8b75a44e4cbf8 100644 (file)
@@ -117,7 +117,7 @@ INET_PROTO_INFO *inet_proto_table = 0;
 #define INET_PROTO_MASK_IPV4   (1<<0)
 #define INET_PROTO_MASK_IPV6   (1<<1)
 
-static NAME_MASK proto_table[] = {
+static const NAME_MASK proto_table[] = {
 #ifdef HAS_IPV6
     INET_PROTO_NAME_ALL, INET_PROTO_MASK_IPV4 | INET_PROTO_MASK_IPV6,
     INET_PROTO_NAME_IPV6, INET_PROTO_MASK_IPV6,
index ac7acd00b091ff55ea51eb5d0ed4175d67723764..bf1680cc2f5680baa2b21e9c64218596e5bf1729 100644 (file)
@@ -611,12 +611,12 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_VERIFY_MAP, DEF_VERIFY_MAP, &var_verify_map, 0, 0,
        VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
        0,
     };
-    static CONFIG_TIME_TABLE time_table[] = {
+    static const CONFIG_TIME_TABLE time_table[] = {
        VAR_VERIFY_POS_EXP, DEF_VERIFY_POS_EXP, &var_verify_pos_exp, 1, 0,
        VAR_VERIFY_POS_TRY, DEF_VERIFY_POS_TRY, &var_verify_pos_try, 1, 0,
        VAR_VERIFY_NEG_EXP, DEF_VERIFY_NEG_EXP, &var_verify_neg_exp, 1, 0,
index 7d6e1b8e8617a368da49ade3b465901b4d8f1e2c..88d969ca5c3ff5ceaa814ec7e3a122eaaa48a405 100644 (file)
@@ -490,12 +490,12 @@ MAIL_VERSION_STAMP_DECLARE;
 
 int     main(int argc, char **argv)
 {
-    static CONFIG_INT_TABLE int_table[] = {
+    static const CONFIG_INT_TABLE int_table[] = {
        VAR_VIRT_MINUID, DEF_VIRT_MINUID, &var_virt_minimum_uid, 1, 0,
        VAR_VIRT_MAILBOX_LIMIT, DEF_VIRT_MAILBOX_LIMIT, &var_virt_mailbox_limit, 0, 0,
        0,
     };
-    static CONFIG_STR_TABLE str_table[] = {
+    static const CONFIG_STR_TABLE str_table[] = {
        VAR_MAIL_SPOOL_DIR, DEF_MAIL_SPOOL_DIR, &var_mail_spool_dir, 0, 0,
        VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
        VAR_VIRT_UID_MAPS, DEF_VIRT_UID_MAPS, &var_virt_uid_maps, 0, 0,
index 0e6267c7c88c3615a64a21eb9feb35f03fe4e091..d45e28dc17afee1362734a9b2f277cbd3bb85a99 100644 (file)
@@ -189,7 +189,7 @@ typedef struct {
     struct XSASL_CLIENT_IMPL *(*client_init) (const char *, const char *);
 } XSASL_CLIENT_IMPL_INFO;
 
-static XSASL_CLIENT_IMPL_INFO client_impl_info[] = {
+static const XSASL_CLIENT_IMPL_INFO client_impl_info[] = {
 #ifdef XSASL_TYPE_CYRUS
     XSASL_TYPE_CYRUS, xsasl_cyrus_client_init,
 #endif
@@ -201,7 +201,7 @@ static XSASL_CLIENT_IMPL_INFO client_impl_info[] = {
 XSASL_CLIENT_IMPL *xsasl_client_init(const char *client_type,
                                             const char *path_info)
 {
-    XSASL_CLIENT_IMPL_INFO *xp;
+    const XSASL_CLIENT_IMPL_INFO *xp;
 
     for (xp = client_impl_info; xp->client_type; xp++)
        if (strcmp(client_type, xp->client_type) == 0)
@@ -214,7 +214,7 @@ XSASL_CLIENT_IMPL *xsasl_client_init(const char *client_type,
 
 ARGV   *xsasl_client_types(void)
 {
-    XSASL_CLIENT_IMPL_INFO *xp;
+    const XSASL_CLIENT_IMPL_INFO *xp;
     ARGV   *argv = argv_alloc(1);
 
     for (xp = client_impl_info; xp->client_type; xp++)
index c4c6d44ece67ef6fb3bf9d6d4bd90ed7e8149a91..617ff2fd98711b5bb43355d4131ecc1e8bb02400 100644 (file)
@@ -60,7 +60,7 @@
  /*
   * SASL Security options.
   */
-static NAME_MASK xsasl_cyrus_sec_mask[] = {
+static const NAME_MASK xsasl_cyrus_sec_mask[] = {
     "noplaintext", SASL_SEC_NOPLAINTEXT,
     "noactive", SASL_SEC_NOACTIVE,
     "nodictionary", SASL_SEC_NODICTIONARY,
index 2e382f24a0e365a65a14118b94be61fe8e538a4b..36bed9e7d57d63a6ac59f615676c4ac386a09156 100644 (file)
  /*
   * Security properties as specified in the Postfix main.cf file.
   */
-static NAME_MASK xsasl_dovecot_conf_sec_props[] = {
+static const NAME_MASK xsasl_dovecot_conf_sec_props[] = {
     "noplaintext", SEC_PROPS_NOPLAINTEXT,
     "noactive", SEC_PROPS_NOACTIVE,
     "nodictionary", SEC_PROPS_NODICTIONARY,
@@ -115,7 +115,7 @@ static NAME_MASK xsasl_dovecot_conf_sec_props[] = {
   * Security properties as specified in the Dovecot protocol. See
   * http://wiki.dovecot.org/Authentication_Protocol.
   */
-static NAME_MASK xsasl_dovecot_serv_sec_props[] = {
+static const NAME_MASK xsasl_dovecot_serv_sec_props[] = {
     "plaintext", SEC_PROPS_NOPLAINTEXT,
     "active", SEC_PROPS_NOACTIVE,
     "dictionary", SEC_PROPS_NODICTIONARY,
index 23531cd4a7facbfe3dd6df828e45da46aba460ae..28204f7bb8e9a6993c833f7c8148521d8e9bbf40 100644 (file)
@@ -195,7 +195,7 @@ typedef struct {
     struct XSASL_SERVER_IMPL *(*server_init) (const char *, const char *);
 } XSASL_SERVER_IMPL_INFO;
 
-static XSASL_SERVER_IMPL_INFO server_impl_info[] = {
+static const XSASL_SERVER_IMPL_INFO server_impl_info[] = {
 #ifdef XSASL_TYPE_CYRUS
     {XSASL_TYPE_CYRUS, xsasl_cyrus_server_init},
 #endif
@@ -210,7 +210,7 @@ static XSASL_SERVER_IMPL_INFO server_impl_info[] = {
 XSASL_SERVER_IMPL *xsasl_server_init(const char *server_type,
                                             const char *path_info)
 {
-    XSASL_SERVER_IMPL_INFO *xp;
+    const XSASL_SERVER_IMPL_INFO *xp;
 
     for (xp = server_impl_info; xp->server_type; xp++)
        if (strcmp(server_type, xp->server_type) == 0)
@@ -223,7 +223,7 @@ XSASL_SERVER_IMPL *xsasl_server_init(const char *server_type,
 
 ARGV   *xsasl_server_types(void)
 {
-    XSASL_SERVER_IMPL_INFO *xp;
+    const XSASL_SERVER_IMPL_INFO *xp;
     ARGV   *argv = argv_alloc(1);
 
     for (xp = server_impl_info; xp->server_type; xp++)