From: Wietse Venema Date: Wed, 9 Jan 2008 05:00:00 +0000 (-0500) Subject: postfix-2.5-20080109 X-Git-Tag: v2.5.0-RC1~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e2813429402b25abce688884bc036f6c12208d53;p=thirdparty%2Fpostfix.git postfix-2.5-20080109 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 3b8209c42..b54aff891 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -100,6 +100,7 @@ -TFILE -TFORWARD_INFO -THBC_ACTION_CALL_BACKS +-THBC_CALL_BACKS -THBC_CHECKS -THBC_MAP_INFO -THBC_OUTPUT_CALL_BACKS @@ -234,10 +235,16 @@ -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 @@ -268,7 +275,7 @@ -TXSASL_SERVER -TXSASL_SERVER_IMPL -TXSASL_SERVER_IMPL_INFO --Tcipher_probe +-Tcipher_probe_t -Toff_t -Tregex_t -Tregmatch_t @@ -277,8 +284,3 @@ -Tsfsistat -Tsize_t -Tssize_t --Ttls_client_init_props --Ttls_client_start_props --Ttls_info_t --Ttls_server_props --Ttls_server_start_props diff --git a/postfix/HISTORY b/postfix/HISTORY index b0787657c..b8302f295 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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
 and 
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. diff --git a/postfix/README_FILES/STRESS_README b/postfix/README_FILES/STRESS_README index bcd5ffc83..dbdd3171f 100644 --- a/postfix/README_FILES/STRESS_README +++ b/postfix/README_FILES/STRESS_README @@ -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: SSyymmppttoommss ooff PPoossttffiixx SSMMTTPP sseerrvveerr oovveerrllooaadd 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. diff --git a/postfix/README_FILES/TLS_README b/postfix/README_FILES/TLS_README index 7c5011927..e11a09668 100644 --- a/postfix/README_FILES/TLS_README +++ b/postfix/README_FILES/TLS_README @@ -5,10 +5,10 @@ PPoossttffiixx TTLLSS SSuuppppoorrtt WWAARRNNIINNGG 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. WWhhaatt PPoossttffiixx TTLLSS ssuuppppoorrtt ddooeess ffoorr yyoouu @@ -126,7 +126,7 @@ SSeerrvveerr--ssiiddee cceerrttiiffiiccaattee aanndd 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 +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 nnoott public Internet MX hosts, Postfix 2.3 supports +For servers that are nnoott 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: % ccaatt sseerrvveerr__cceerrtt..ppeemm iinntteerrmmeeddiiaattee__CCAA..ppeemm >> sseerrvveerr..ppeemm @@ -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 SSuuppppoorrttiinngg AAUUTTHH oovveerr TTLLSS oonnllyy @@ -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: - % ooppeennssssll ggeennddhh --oouutt //eettcc//ppoossttffiixx//ddhh__11002244..ppeemm --22 --rraanndd //vvaarr//rruunn//eeggdd--ppooooll - 11002244 - % ooppeennssssll ggeennddhh --oouutt //eettcc//ppoossttffiixx//ddhh__551122..ppeemm --22 --rraanndd //vvaarr//rruunn//eeggdd--ppooooll 551122 + % ooppeennssssll ggeennddhh --oouutt //eettcc//ppoossttffiixx//ddhh__551122..ppeemm --22 551122 + % ooppeennssssll ggeennddhh --oouutt //eettcc//ppoossttffiixx//ddhh__11002244..ppeemm --22 11002244 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: TTLLSS ssuuppppoorrtt iinn tthhee LLMMTTPP ddeelliivveerryy aaggeenntt -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. CClliieenntt--ssiiddee cceerrttiiffiiccaattee aanndd pprriivvaattee kkeeyy ccoonnffiigguurraattiioonn -Do not configure client certificates unless you mmuusstt 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 mmuusstt 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 @@ mmaayy Opportunistic TLS. eennccrryypptt Mandatory TLS encryption. +ffiinnggeerrpprriinntt + Certificate fingerprint verification. vveerriiffyy Mandatory server certificate verification. sseeccuurree @@ -941,11 +937,11 @@ MMaannddaattoorryy TTLLSS eennccrryyppttiioonn 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 +CCeerrttiiffiiccaattee ffiinnggeerrpprriinntt vveerriiffiiccaattiioonn + +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 +ssmmttpp__ttllss__ffiinnggeerrpprriinntt__ddiiggeesstt 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 + MMaannddaattoorryy sseerrvveerr cceerrttiiffiiccaattee vveerriiffiiccaattiioonn 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 @@ nnoonnee mmaayy Opportunistic TLS. No additional attributes are supported at this level. eennccrryypptt - 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. +ffiinnggeerrpprriinntt + 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 mmaattcchh attribute, or else the main.cf + ssmmttpp__ttllss__ffiinnggeerrpprriinntt__cceerrtt__mmaattcchh parameter, lists the valid fingerprints of + the server certificate. The digest algorithm used to calculate fingerprints + is selected by the ssmmttpp__ttllss__ffiinnggeerrpprriinntt__ddiiggeesstt 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. vveerriiffyy 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). sseeccuurree - 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 NNoottee:: 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: SSeerrvveerr cceerrttiiffiiccaattee vveerriiffiiccaattiioonn ddeepptthh -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 CClliieenntt--ssiiddee cciipphheerr ccoonnttrroollss @@ -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 CClliieenntt--ssiiddee SSMMTTPPSS ssuuppppoorrtt @@ -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 @@ CCrreeddiittss * 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. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index cc1d9e95d..a1b9ec374 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -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 ============================================== diff --git a/postfix/TLS_TODO b/postfix/TLS_TODO index 575c25ff3..05590100c 100644 --- a/postfix/TLS_TODO +++ b/postfix/TLS_TODO @@ -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. diff --git a/postfix/WISHLIST b/postfix/WISHLIST index 179fbcba1..de66e9fe9 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -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 diff --git a/postfix/html/STRESS_README.html b/postfix/html/STRESS_README.html index 61a0e7032..1ea44d77b 100644 --- a/postfix/html/STRESS_README.html +++ b/postfix/html/STRESS_README.html @@ -24,9 +24,10 @@ Stress-Dependent Configuration 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.

+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.

Topics covered in this document:

@@ -55,8 +56,7 @@ switch configuration settings under overload.

Symptoms of Postfix SMTP server overload

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:

    -
  • 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 @@ -92,9 +81,22 @@ connect to this instead of the public SMTP service.

    connection after CONNECT" events. This happens because remote SMTP clients disconnect before Postfix answers the connection.

    +
  • 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 last two symptoms also happen without overload.

+

NOTE: The first two symptoms may also happen without overload, +for example:

    diff --git a/postfix/html/TLS_README.html b/postfix/html/TLS_README.html index 81965f443..9d6157aec 100644 --- a/postfix/html/TLS_README.html +++ b/postfix/html/TLS_README.html @@ -21,7 +21,7 @@

    WARNING

    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

    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

    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.

    For servers that are not 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.

    +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, @@ -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).

    -

    Example: the certificate for "server.dom.ain" was issued by +

    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:

    @@ -283,15 +287,7 @@ 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).

    +$smtpd_tls_CAfile or install it in the $smtpd_tls_CApath directory.

    RSA key and certificate examples:

    @@ -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.

    -

    When you configure Postfix to request 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 @@ -450,12 +446,13 @@ supported).

-

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 +is never offered due to insufficient privileges to access the Postfix +SMTP server private key. This is intended behavior.

You can ENFORCE the use of TLS, @@ -481,7 +478,8 @@ by default and should only seldom be used.

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 < 5.0 and Win32 >=5.0 when run on a port<>25 and OE (5.01 Mac on all ports).

@@ -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.

+offers anonymous ciphers to remote SMTP clients, these are automatically +suppressed +when the Postfix SMTP server is configured to ask for client +certificates.

Example:

@@ -553,18 +553,26 @@ logged.

-

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
 
@@ -661,23 +669,30 @@ 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).

+
permit_tls_clientcerts

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. -

+
permit_tls_all_clientcerts

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.

+
check_ccert_access type: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 CA issues the client certificates, and @@ -704,16 +719,10 @@ certificate must no longer be used (e.g. an employee leaving).

-

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: 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:

-
 /etc/postfix/main.cf:
@@ -766,27 +775,29 @@ and not specifying an smtpd_tls_d
     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 ≥ 2.5:
+    smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
 
-

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.

+

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:

-% openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024
-% openssl gendh -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512
+% openssl gendh -out /etc/postfix/dh_512.pem -2 512
+% openssl gendh -out /etc/postfix/dh_1024.pem -2 1024
 
@@ -841,6 +852,8 @@ key configuration
  • Mandating TLS encryption +
  • Certificate fingerprint verification +
  • Mandating server certificate verification
  • Secure server certificate verification @@ -866,14 +879,14 @@ key configuration

    TLS support in the LMTP delivery agent

    -

    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 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 LMTP delivery agent can communicate with LMTP servers listening +

    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 @@ -887,7 +900,8 @@ The "null" ciphers provide authentication without encryption.

    Client-side certificate and private key configuration

    -

    Do not configure client certificates unless you must present +

    Do not configure Postfix SMTP client certificates unless you must +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:

    @@ -951,15 +965,7 @@ 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).

    +$smtp_tls_CAfile or install it in the $smtp_tls_CApath directory.

    RSA key and certificate examples:

    @@ -1212,6 +1218,8 @@ in the sections that follow.

    Opportunistic TLS.
    encrypt
    Mandatory TLS encryption. +
    fingerprint
    +
    Certificate fingerprint verification.
    verify
    Mandatory server certificate verification.
    secure
    @@ -1314,11 +1322,12 @@ on TLS limitations above.

    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.

    At this security level and higher, the smtp_tls_mandatory_protocols @@ -1437,13 +1446,82 @@ use the new policy table instead.

    +

    Certificate fingerprint verification +

    + +

    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 smtp_tls_fingerprint_digest 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
    +
    +
    +

    Mandatory server certificate verification

    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_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 above.

    @@ -1492,7 +1571,7 @@ Postfix 2.3 and later should use the new TLS policy settings.

    Example:

    -

    In this example, the client encrypts all traffic to the +

    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.

    @@ -1543,7 +1622,8 @@ 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 +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.

    @@ -1578,9 +1658,11 @@ should use the new TLS policy settings.

    Secure-channel TLS without transport(5) table overrides:

    -

    The client will encrypt all traffic and verify the destination name +

    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 example.com, but these are not used when +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 @@ -1729,35 +1811,50 @@ describe the corresponding table syntax:

    -
    none
    -
    No TLS. No additional attributes are supported at this level.
    - -
    may
    -
    Opportunistic TLS. No additional attributes are supported at this -level.
    - -
    encrypt
    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.
    - -
    verify
    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).
    - -
    secure
    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). -
    +
    none
    No TLS. No +additional attributes are supported at this level.
    + +
    may
    Opportunistic TLS. +No additional attributes are supported at this level.
    + +
    encrypt
    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" attribute +overrides the main.cf smtp_tls_mandatory_protocols parameter.
    + +
    fingerprint
    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 match attribute, or else +the main.cf smtp_tls_fingerprint_cert_match parameter, +lists the valid fingerprints of the server certificate. The +digest algorithm used to calculate fingerprints is selected by the +smtp_tls_fingerprint_digest 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.
    + +
    verify
    Mandatory +server 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_verify_cert_match parameter value when no optional +"match" attribute is specified).
    + +
    secure
    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).
    @@ -1789,6 +1886,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
    @@ -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
     
    @@ -2040,18 +2143,26 @@ postfix/smtp[pid]: Host offered STARTTLS: [hostname.example.com]

    Server certificate verification depth

    -

    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).

    - -

    Example:

    +

    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
     
    @@ -2067,7 +2178,8 @@ methods. See smtp_tls_policy_maps ciphers on a per-destination basis.

    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.

    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 @@ -2405,7 +2520,7 @@ but don't require them from all clients.

    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. +
  • 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. + diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index 9e1659cde..949e74009 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -424,10 +424,10 @@ SMTP(8) SMTP(8) obsolete smtp_tls_per_site parameter. smtp_tls_mandatory_protocols (SSLv3, TLSv1) - 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. - smtp_tls_scert_verifydepth (5) + smtp_tls_scert_verifydepth (9) 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: + + smtp_tls_fingerprint_cert_match (empty) + List of acceptable remote SMTP server certificate + fingerprints for the "fingerprint" TLS security + level (smtp_tls_security_level = fingerprint). + + smtp_tls_fingerprint_digest (md5) + The message digest algorithm used to construct + remote SMTP server certificate fingerprints. + OBSOLETE STARTTLS CONTROLS - 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. smtp_use_tls (no) - 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. smtp_enforce_tls (no) - 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. smtp_tls_enforce_peername (yes) - 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. smtp_tls_per_site (empty) 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. smtp_tls_cipherlist (empty) @@ -513,27 +524,27 @@ SMTP(8) SMTP(8) RESOURCE AND RATE CONTROLS smtp_destination_concurrency_limit ($default_destina- tion_concurrency_limit) - 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. smtp_destination_recipient_limit ($default_destina- tion_recipient_limit) - The maximal number of recipients per delivery via + The maximal number of recipients per delivery via the smtp message delivery transport. smtp_connect_timeout (30s) - 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). smtp_helo_timeout (300s) - 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. lmtp_lhlo_timeout (300s) - 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. smtp_mail_timeout (300s) - 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. smtp_rcpt_timeout (300s) - 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. smtp_data_init_timeout (120s) - 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. smtp_data_xfer_timeout (180s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP message content. smtp_data_done_timeout (600s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP ".", and for receiving the server response. smtp_quit_timeout (300s) - 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). smtp_mx_session_limit (2) - 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 relay host, or zero (no limit). smtp_rset_timeout (20s) - 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: smtp_connection_cache_destinations (empty) - Permanently enable SMTP connection caching for the + Permanently enable SMTP connection caching for the specified destinations. smtp_connection_cache_on_demand (yes) - 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) smtp_connection_cache_time_limit (2s) 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: connection_cache_protocol_timeout (5s) - Time limit for connection cache connect, send or + Time limit for connection cache connect, send or receive operations. TROUBLE SHOOTING CONTROLS debug_peer_level (2) - 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 debug_peer_list parameter. debug_peer_list (empty) - 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 $debug_peer_level. error_notice_recipient (postmaster) - 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. internal_mail_filter_classes (empty) - 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 non_smtpd_milters, header_checks and body_checks. notify_classes (resource, software) - The list of error classes that are reported to the + The list of error classes that are reported to the postmaster. MISCELLANEOUS CONTROLS best_mx_transport (empty) - 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. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. daemon_timeout (18000s) - 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. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal + The maximal number of digits after the decimal point when logging sub-second delay values. disable_dns_lookups (no) - Disable DNS lookups in the Postfix SMTP and LMTP + Disable DNS lookups in the Postfix SMTP and LMTP clients. inet_interfaces (all) @@ -670,7 +681,7 @@ SMTP(8) SMTP(8) tem receives mail on. inet_protocols (ipv4) - The Internet protocols Postfix will attempt to use + The Internet protocols Postfix will attempt to use when making or accepting connections. ipc_timeout (3600s) @@ -678,75 +689,75 @@ SMTP(8) SMTP(8) over an internal communication channel. lmtp_tcp_port (24) - The default TCP port that the Postfix LMTP client + The default TCP port that the Postfix LMTP client connects to. max_idle (100s) - 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. max_use (100) - 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. process_id (read-only) - The process ID of a Postfix command or daemon + The process ID of a Postfix command or daemon process. process_name (read-only) - The process name of a Postfix command or daemon + The process name of a Postfix command or daemon process. proxy_interfaces (empty) 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. smtp_bind_address (empty) - 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. smtp_bind_address6 (empty) - 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. smtp_helo_name ($myhostname) - The hostname to send in the SMTP EHLO or HELO com- + The hostname to send in the SMTP EHLO or HELO com- mand. lmtp_lhlo_name ($myhostname) The hostname to send in the LMTP LHLO command. smtp_host_lookup (dns) - What mechanisms when the Postfix SMTP client uses + What mechanisms when the Postfix SMTP client uses to look up a host's IP address. smtp_randomize_addresses (yes) - Randomize the order of equal-preference MX host + Randomize the order of equal-preference MX host addresses. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (postfix) - 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: fallback_relay (empty) - 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: smtp_fallback_relay ($fallback_relay) - 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. SEE ALSO @@ -767,7 +778,7 @@ SMTP(8) SMTP(8) TLS_README, Postfix STARTTLS howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) @@ -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) diff --git a/postfix/html/master.5.html b/postfix/html/master.5.html index 68fe8dc19..e28361305 100644 --- a/postfix/html/master.5.html +++ b/postfix/html/master.5.html @@ -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 queue_directory configura- + The service name is a pathname relative to + the Postfix queue directory (pathname con- + trolled with the queue_directory configura- tion parameter in main.cf). + This feature is available as of Postfix ver- + sion 2.5. + Private (default: y) Whether or not access is restricted to the mail system. Internet (type inet) services can't be diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 0ea951e41..180c320b9 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -83,19 +83,6 @@ the sender. This feature is enabled with the transport_destination_concurrency_failed_cohort_limit">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 transport is the master.cf name of the message delivery -transport.

    - -

    This feature is available in Postfix 2.5 and later.

    - -
    access_map_reject_code @@ -2515,7 +2502,7 @@ created locally as the result of configuration or software error.
    empty_address_relayhost_maps_lookup_key -(default: <>)
    +(default: <>)

    The sender_dependent_relayhost_maps search string that will be used instead of the null sender address.

    @@ -3727,10 +3714,12 @@ clients, or it can be specified in the master.cf fil client, for example:

    +
    -  /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
     
    +

    This feature is available in Postfix 2.3 and later. @@ -4187,6 +4176,28 @@ configuration parameter. See there for details.

    This feature is available in Postfix 2.3 and later.

    +
    + +
    lmtp_tls_fingerprint_cert_match +(default: empty)
    + +

    The LMTP-specific version of the smtp_tls_fingerprint_cert_match +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.5 and later.

    + + +
    + +
    lmtp_tls_fingerprint_digest +(default: md5)
    + +

    The LMTP-specific version of the smtp_tls_fingerprint_digest +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.5 and later.

    + +
    lmtp_tls_key_file @@ -4278,7 +4289,7 @@ configuration parameter. See there for details.

    lmtp_tls_scert_verifydepth -(default: 5)
    +(default: 9)

    The LMTP-specific version of the smtp_tls_scert_verifydepth configuration parameter. See there for details.

    @@ -4297,6 +4308,17 @@ configuration parameter. See there for details.

    This feature is available in Postfix 2.3 and later.

    +
    + +
    lmtp_tls_security_level +(default: empty)
    + +

    The LMTP-specific version of the smtp_tls_security_level configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +
    lmtp_tls_session_cache_database @@ -4471,8 +4493,10 @@ protocol.
    permit_tls_clientcerts
    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).
    permit_tls_all_clientcerts
    @@ -4498,16 +4522,20 @@ is suitable for, e.g., pop-before-smtp lookup tables. message headers, and always append my own domain to incomplete header addresses.

    +
    -    local_header_rewrite_clients = static:all
    +local_header_rewrite_clients = static:all
     
    +

    The purist (and default) setting: rewrite headers only in mail from Postfix sendmail and in SMTP mail from this machine.

    +
    -    local_header_rewrite_clients = permit_inet_interfaces
    +local_header_rewrite_clients = permit_inet_interfaces
     
    +

    The intermediate setting: rewrite header addresses and append $myorigin or $mydomain information only with mail from Postfix @@ -4517,11 +4545,13 @@ sendmail, from local clients, or from authorized SMTP clients.

    rewriting when mail from a remote client is forwarded by a neighboring system.

    +
    -    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
     
    +
    @@ -5095,9 +5125,11 @@ The list is processed left to right, and processing stops at the first match. Thus,

    +
    -    masquerade_domains = foo.example.com example.com
    +masquerade_domains = foo.example.com example.com
     
    +

    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,

    +
    -    masquerade_domains = !foo.example.com example.com
    +masquerade_domains = !foo.example.com example.com
     
    +

    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 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).

    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.

    addresses from remote SMTP clients, so that those addresses cannot be confused with local addresses.

    +
    -    remote_header_rewrite_domain = domain.invalid
    +remote_header_rewrite_domain = domain.invalid
     
    +

    The default, purist, setting: don't rewrite headers from remote clients at all.

    +
    -    remote_header_rewrite_domain =
    +remote_header_rewrite_domain =
     
    +
    @@ -7295,10 +7333,12 @@ it can be specified in the master.cf file for a spec for example:

    +
    -  /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
     
    +

    Note 1: when inet_interfaces 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 master.cf file for a spec for example:

    +
    -  /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
     
    +

    Note 1: when inet_interfaces 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 master.cf fil client, for example:

    +
    -  /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
     
    +

    This feature is available in Postfix 2.0 and later. @@ -8052,10 +8096,12 @@ The default is to comply with RFC 82 a broken SMTP server, configure a special SMTP client in master.cf:

    +
    -    /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
     
    +

    and route mail for the destination in question to the "broken-smtp" @@ -8261,10 +8307,8 @@ client uses for TLS encrypted SMTP sessions.

    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.

    - -

    This feature should be available in Postfix 2.4 and later.

    +certificate. This feature is under construction as of Postfix version +2.3.

    @@ -8435,10 +8479,10 @@ well without them. The recommended setting is to let the defaults stand:

    -    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 =
     
    @@ -8565,6 +8609,7 @@ case only ciphers matching all the properties are excluded.

    Examples (some of these will cause problems):

    +
     smtp_tls_exclude_ciphers = aNULL
     smtp_tls_exclude_ciphers = MD5, DES
    @@ -8572,6 +8617,7 @@ case only ciphers matching all the properties are excluded. 

    smtp_tls_exclude_ciphers = AES256-SHA, DES-CBC3-MD5 smtp_tls_exclude_ciphers = kEDH+aRSA
    +

    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.

    This feature is available in Postfix 2.3 and later.

    + + +
    smtp_tls_fingerprint_cert_match +(default: empty)
    + +

    List of acceptable remote SMTP server certificate fingerprints +for the "fingerprint" TLS security level (smtp_tls_security_level = +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 smtp_tls_fingerprint_digest +parameter.

    + +

    When an smtp_tls_policy_maps 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.

    + +

    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.

    + +
    +
    +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
    +
    +
    + +

    This feature is available in Postfix 2.5 and later.

    + + +
    + +
    smtp_tls_fingerprint_digest +(default: md5)
    + +

    The message digest algorithm used to construct remote SMTP server +certificate fingerprints. At the "fingerprint" TLS security level +(smtp_tls_security_level = fingerprint), the server certificate is +verified by directly matching its fingerprint. 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.

    + +

    The default algorithm is md5; this is consistent with +the backwards compatible setting of the digest used to verify client +certificates in the SMTP server.

    + +

    The best practice algorithm is now sha1. 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. +

    + +

    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.

    + +

    To find the fingerprint of a specific certificate file, with a +specific digest algorithm, run: +

    + +
    +
    +$ openssl x509 -noout -fingerprint -digest -in certfile.pem
    +
    +
    + +

    The text to the right of "=" sign is the desired fingerprint. +For example:

    + +
    +
    +$ 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
    +
    +
    + +

    This feature is available in Postfix 2.5 and later.

    + +
    smtp_tls_key_file @@ -8730,22 +8885,36 @@ works in addition to the exclusions listed with 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 SSL_get_version(3)), are "SSLv2", "SSLv3" and -"TLSv1".

    +empty value means allow all protocols. The valid protocol names, (see +SSL_get_version(3)), are "SSLv2", "SSLv3" and "TLSv1".

    -

    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.

    +

    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.

    + +

    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.

    See the documentation of the smtp_tls_policy_maps parameter and TLS_README for more information about security levels.

    +

    Example:

    + +
    +smtp_tls_mandatory_protocols = TLSv1
    +# Alternative form with Postfix ≥ 2.5:
    +smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
    +
    +

    This feature is available in Postfix 2.3 and later.

    @@ -8903,6 +9072,20 @@ keyword overrides the main.cf main.cf +smtp_tls_fingerprint_cert_match parameter, lists the +valid "fingerprints" of the server certificate. The digest +algorithm used to calculate the fingerprint is selected by the +smtp_tls_fingerprint_digest 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.
    +
    verify
    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:

    -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
     
    +
    -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
     

    Note: The hostname strategy if listed in a non-default @@ -8962,13 +9152,20 @@ configurations in environments where DNS security is not assured.

    smtp_tls_scert_verifydepth -(default: 5)
    +(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.

    -

    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...).

    +

    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.

    This feature is available in Postfix 2.2 and later.

    @@ -8997,18 +9194,22 @@ the results of MX lookups in certificate verification is not immune to active Sample main.cf setting:

    +
     smtp_tls_secure_cert_match = nexthop
     
    +

    Sample policy table override:

    +
     example.net     secure match=example.com:.example.com
     .example.net    secure match=example.com:.example.com
     
    +

    This feature is available in Postfix 2.3 and later.

    @@ -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.
    +
    fingerprint
    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 smtp_tls_fingerprint_cert_match parameter lists +the valid "fingerprints" of the server certificate. The digest +algorithm used to calculate the fingerprint is selected by the +smtp_tls_fingerprint_digest parameter.
    +
    verify
    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.
    Examples:

    -

    No TLS, old-style: smtp_use_tls=no and smtp_enforce_tls=no.

    -main.cf:
    -    smtp_tls_security_level = none
    +# No TLS. Formerly: smtp_use_tls=no and smtp_enforce_tls=no.
    +smtp_tls_security_level = none
     
    -

    Opportunistic TLS:

    -main.cf:
    -    smtp_tls_security_level = may
    +# Opportunistic TLS.
    +smtp_tls_security_level = may
     
    -

    Mandatory (high-grade) TLS encryption:

    -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
     
    -

    Mandatory TLS verification, of hostname or nexthop domain:

    -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
    +
    + +
    +# 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
     
    -

    Secure channel TLS with exact nexthop name matching:

    -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 ≥ 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
     

    This feature is available in Postfix 2.3 and later.

    @@ -9673,9 +9893,12 @@ client network address information.
    check_ccert_access type:table
    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.
    +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.
    check_client_access type:table
    @@ -9708,9 +9931,13 @@ allowed to relay. This feature is available with Postfix version 2.2.
    permit_tls_clientcerts
    -
    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.
    +
    reject_rbl_client rbl_domain=d.d.d.d
    Reject the request when the reversed client network address is @@ -9853,7 +10080,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: -
     /etc/postfix/main.cf:
         smtpd_client_restrictions =
    @@ -10555,9 +10781,11 @@ at least one of the following restrictions. Otherwise Postfix will
     refuse to receive mail:
     

    +
    -    reject, defer, defer_if_permit, reject_unauth_destination
    +reject, defer, defer_if_permit, reject_unauth_destination
     
    +

    Specify a list of restrictions, separated by commas and/or whitespace. @@ -10851,18 +11079,22 @@ If a remote SMTP client is authenticated, the smtpd_recipient_restrictions = - permit_mynetworks, permit_sasl_authenticated, ... +smtpd_recipient_restrictions = + permit_mynetworks, permit_sasl_authenticated, ...

    +

    To reject all SMTP connections from unauthenticated clients, specify "smtpd_delay_reject = yes" (which is the default) and use:

    +
    -    smtpd_client_restrictions = permit_sasl_authenticated, reject
    +smtpd_client_restrictions = permit_sasl_authenticated, reject
     
    +

    See the SASL_README file for SASL configuration and operation details. @@ -11380,11 +11612,9 @@ with other MTAs.

    Example:

    -
    -    smtpd_tls_always_issue_session_ids = no
    +smtpd_tls_always_issue_session_ids = no
     
    -

    This feature is available in Postfix 2.3 and later.

    @@ -11421,13 +11651,21 @@ connections.

    smtpd_tls_ccert_verifydepth -(default: 5)
    +(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.

    + +

    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.

    This feature is available in Postfix 2.2 and later.

    @@ -11516,7 +11754,7 @@ Postfix 2.3 and later; use

    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.

    See the discussion under smtpd_tls_cert_file for more details.

    @@ -11542,9 +11780,11 @@ use with EDH ciphers.

    with other TLS packages, it is more secure to generate your own set of parameters with something like the following command:

    +
    -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
     
    +

    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 all the properties are excluded.

    Examples (some of these will cause problems):

    +
     smtpd_tls_exclude_ciphers = aNULL
     smtpd_tls_exclude_ciphers = MD5, DES
    @@ -11618,6 +11859,7 @@ only ciphers matching all the properties are excluded. 

    smtpd_tls_exclude_ciphers = AES256-SHA, DES-CBC3-MD5 smtpd_tls_exclude_ciphers = kEDH+aRSA
    +

    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.

    This feature is available in Postfix 2.3 and later.

    +
    + +
    smtpd_tls_fingerprint_digest +(default: md5)
    + +

    The message digest algorithm used to construct client-certificate +fingerprints for check_ccert_access and +permit_tls_clientcerts. The default algorithm is md5, +for backwards compatibility with Postfix releases prior to 2.5. +

    + +

    The best practice algorithm is now sha1. 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. +

    + +

    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.

    + +

    To find the fingerprint of a specific certificate file, with a +specific digest algorithm, run:

    + +
    +
    +$ openssl x509 -noout -fingerprint -digest -in certfile.pem
    +
    +
    + +

    The text to the right of "=" sign is the desired fingerprint. +For example:

    + +
    +
    +$ 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
    +
    +
    + +

    Example: client-certificate access table, with sha1 fingerprints:

    + +
    +
    +/etc/postfix/main.cf:
    +    smtpd_tls_fingerprint_digest = sha1
    +    smtpd_client_restrictions =
    +        check_ccert_access hash:/etc/postfix/access,
    +        reject
    +
    +
    +/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
    +
    +
    + +

    This feature is available in Postfix 2.5 and later.

    + +
    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.

    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 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.

    + +

    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.

    + +

    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.

    Example:

    -smtpd_tls_mandatory_protocols = SSLv3, TLSv1
    +smtpd_tls_mandatory_protocols = TLSv1
    +# Alternative form with Postfix ≥ 2.5:
    +smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
     

    This feature is available in Postfix 2.3 and later.

    @@ -11811,7 +12128,7 @@ that was recorded by the final destination can be trusted.

    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".

    @@ -11849,7 +12166,8 @@ be used only on dedicated servers.
    -

    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 @@ -12408,6 +12726,19 @@ parameter value, where transport is the master.cf the message delivery transport.

    + + +
    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 transport is the master.cf name of the message delivery +transport.

    + +

    This feature is available in Postfix 2.5 and later.

    + +
    transport_destination_concurrency_limit diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 9e1659cde..949e74009 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -424,10 +424,10 @@ SMTP(8) SMTP(8) obsolete smtp_tls_per_site parameter. smtp_tls_mandatory_protocols (SSLv3, TLSv1) - 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. - smtp_tls_scert_verifydepth (5) + smtp_tls_scert_verifydepth (9) 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: + + smtp_tls_fingerprint_cert_match (empty) + List of acceptable remote SMTP server certificate + fingerprints for the "fingerprint" TLS security + level (smtp_tls_security_level = fingerprint). + + smtp_tls_fingerprint_digest (md5) + The message digest algorithm used to construct + remote SMTP server certificate fingerprints. + OBSOLETE STARTTLS CONTROLS - 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. smtp_use_tls (no) - 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. smtp_enforce_tls (no) - 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. smtp_tls_enforce_peername (yes) - 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. smtp_tls_per_site (empty) 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. smtp_tls_cipherlist (empty) @@ -513,27 +524,27 @@ SMTP(8) SMTP(8) RESOURCE AND RATE CONTROLS smtp_destination_concurrency_limit ($default_destina- tion_concurrency_limit) - 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. smtp_destination_recipient_limit ($default_destina- tion_recipient_limit) - The maximal number of recipients per delivery via + The maximal number of recipients per delivery via the smtp message delivery transport. smtp_connect_timeout (30s) - 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). smtp_helo_timeout (300s) - 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. lmtp_lhlo_timeout (300s) - 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. smtp_mail_timeout (300s) - 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. smtp_rcpt_timeout (300s) - 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. smtp_data_init_timeout (120s) - 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. smtp_data_xfer_timeout (180s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP message content. smtp_data_done_timeout (600s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP ".", and for receiving the server response. smtp_quit_timeout (300s) - 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). smtp_mx_session_limit (2) - 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 relay host, or zero (no limit). smtp_rset_timeout (20s) - 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: smtp_connection_cache_destinations (empty) - Permanently enable SMTP connection caching for the + Permanently enable SMTP connection caching for the specified destinations. smtp_connection_cache_on_demand (yes) - 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) smtp_connection_cache_time_limit (2s) 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: connection_cache_protocol_timeout (5s) - Time limit for connection cache connect, send or + Time limit for connection cache connect, send or receive operations. TROUBLE SHOOTING CONTROLS debug_peer_level (2) - 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 debug_peer_list parameter. debug_peer_list (empty) - 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 $debug_peer_level. error_notice_recipient (postmaster) - 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. internal_mail_filter_classes (empty) - 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 non_smtpd_milters, header_checks and body_checks. notify_classes (resource, software) - The list of error classes that are reported to the + The list of error classes that are reported to the postmaster. MISCELLANEOUS CONTROLS best_mx_transport (empty) - 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. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. daemon_timeout (18000s) - 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. delay_logging_resolution_limit (2) - The maximal number of digits after the decimal + The maximal number of digits after the decimal point when logging sub-second delay values. disable_dns_lookups (no) - Disable DNS lookups in the Postfix SMTP and LMTP + Disable DNS lookups in the Postfix SMTP and LMTP clients. inet_interfaces (all) @@ -670,7 +681,7 @@ SMTP(8) SMTP(8) tem receives mail on. inet_protocols (ipv4) - The Internet protocols Postfix will attempt to use + The Internet protocols Postfix will attempt to use when making or accepting connections. ipc_timeout (3600s) @@ -678,75 +689,75 @@ SMTP(8) SMTP(8) over an internal communication channel. lmtp_tcp_port (24) - The default TCP port that the Postfix LMTP client + The default TCP port that the Postfix LMTP client connects to. max_idle (100s) - 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. max_use (100) - 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. process_id (read-only) - The process ID of a Postfix command or daemon + The process ID of a Postfix command or daemon process. process_name (read-only) - The process name of a Postfix command or daemon + The process name of a Postfix command or daemon process. proxy_interfaces (empty) 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. smtp_bind_address (empty) - 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. smtp_bind_address6 (empty) - 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. smtp_helo_name ($myhostname) - The hostname to send in the SMTP EHLO or HELO com- + The hostname to send in the SMTP EHLO or HELO com- mand. lmtp_lhlo_name ($myhostname) The hostname to send in the LMTP LHLO command. smtp_host_lookup (dns) - What mechanisms when the Postfix SMTP client uses + What mechanisms when the Postfix SMTP client uses to look up a host's IP address. smtp_randomize_addresses (yes) - Randomize the order of equal-preference MX host + Randomize the order of equal-preference MX host addresses. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (postfix) - 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: fallback_relay (empty) - 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: smtp_fallback_relay ($fallback_relay) - 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. SEE ALSO @@ -767,7 +778,7 @@ SMTP(8) SMTP(8) TLS_README, Postfix STARTTLS howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) @@ -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) diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 5c0872ada..555ff650c 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -398,7 +398,7 @@ SMTPD(8) SMTPD(8) server, do not announce or accept SASL authentica- tion over unencrypted connections. - smtpd_tls_ccert_verifydepth (5) + smtpd_tls_ccert_verifydepth (9) The verification depth for remote SMTP client cer- tificates. @@ -444,7 +444,7 @@ SMTPD(8) SMTPD(8) tory TLS security levels. smtpd_tls_mandatory_protocols (SSLv3, TLSv1) - The TLS protocols accepted by the Postfix SMTP + The SSL/TLS protocols accepted by the Postfix SMTP server with mandatory TLS encryption. smtpd_tls_received_header (no) @@ -455,9 +455,9 @@ SMTPD(8) SMTPD(8) CommonName. smtpd_tls_req_ccert (no) - 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. smtpd_tls_session_cache_database (empty) 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: + + smtpd_tls_fingerprint_digest (md5) + The message digest algorithm used to construct + client-certificate fingerprints for + check_ccert_access and permit_tls_clientcerts. + OBSOLETE STARTTLS CONTROLS 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) diff --git a/postfix/man/man5/master.5 b/postfix/man/man5/master.5 index 2a787a23a..414806353 100644 --- a/postfix/man/man5/master.5 +++ b/postfix/man/man5/master.5 @@ -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. diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 43469a2af..b842e89a6 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -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. -
    \fB\fItransport\fR_destination_concurrency_failed_cohort_limit -(default: $default_destination_concurrency_failed_cohort_limit)\fR
    -.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 diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index 40532a4db..873c5658c 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -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 diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 118ff8b95..b0014b5c6 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -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 diff --git a/postfix/mantools/postconf2man b/postfix/mantools/postconf2man index 360373d1f..234533f25 100755 --- a/postfix/mantools/postconf2man +++ b/postfix/mantools/postconf2man @@ -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 =~ /

    /) { $block =~ s/

    ]+>([^<]+)<\/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/\s*//g; $block =~ s/\s*<\/tt>//g; - $block =~ s/
    /\n.na\n.nf\n.in +4\n/g; - $block =~ s/<\/blockquote>/\n.in -4\n.fi\n.ad\n/g; + $block =~ s/
    /\n.sp\n.in +4\n/g; + $block =~ s/<\/blockquote>/\n.in -4\n/g; $block =~ s/\n
    /\n.br\n/g; $block =~ s/
    \s*/\n.br\n/g; + $block =~ s/≤/<=/g; $block =~ s/</=/g; $block =~ s/>/>/g; $block =~ s/&/\&/g; $block =~ s/\s+\n/\n/g; diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index 289ffcb73..be7948d38 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -216,6 +216,7 @@ while (<>) { s;\blmtp_tls_policy_maps\b;$&;g; s;\blmtp_tls_secure_cert_match\b;$&;g; s;\blmtp_tls_security_level\b;$&;g; + s;\blmtp_tls_fingerprint_cert_match\b;$&;g; s;\blmtp_tls_verify_cert_match\b;$&;g; s;\blmtp_tls_per_site\b;$&;g; s;\blmtp_tls_cert_file\b;$&;g; @@ -224,6 +225,7 @@ while (<>) { s;\blmtp_tls_dkey_file\b;$&;g; s;\blmtp_tls_CAfile\b;$&;g; s;\blmtp_tls_CApath\b;$&;g; + s;\blmtp_tls_fingerprint_digest\b;$&;g; s;\blmtp_tls_mandatory_ciphers\b;$&;g; s;\blmtp_tls_exclude_ciphers\b;$&;g; s;\blmtp_tls_mandatory_exclude_ciphers\b;$&;g; @@ -553,6 +555,7 @@ while (<>) { s;\bsmtp_tls_CAfile\b;$&;g; s;\bsmtp_tls_CApath\b;$&;g; s;\bsmtp_tls_cert_file\b;$&;g; + s;\bsmtp_tls_fingerprint_digest\b;$&;g; s;\bsmtp_tls_mandatory_ciphers\b;$&;g; s;\bsmtp_tls_cipherlist\b;$&;g; s;\bsmtp_tls_exclude_ciphers\b;$&;g; @@ -566,6 +569,7 @@ while (<>) { s;\bsmtp_tls_per_site\b;$&;g; s;\bsmtp_tls_policy_maps\b;$&;g; s;\bsmtp_tls_mandatory_protocols\b;$&;g; + s;\bsmtp_tls_fingerprint_cert_match\b;$&;g; s;\bsmtp_tls_verify_cert_match\b;$&;g; s;\bsmtp_tls_secure_cert_match\b;$&;g; s;\bsmtp_tls_scert_verifydepth\b;$&;g; @@ -589,6 +593,7 @@ while (<>) { s;\bsmtpd_tls_cert_file\b;$&;g; s;\bsmtpd_tls_cipherlist\b;$&;g; s;\bsmtpd_tls_exclude_ciphers\b;$&;g; + s;\bsmtpd_tls_fingerprint_digest\b;$&;g; s;\bsmtpd_tls_mandatory_ciphers\b;$&;g; s;\bsmtpd_tls_mandatory_exclude_ciphers\b;$&;g; s;\bsmtpd_tls_dcert_file\b;$&;g; diff --git a/postfix/mantools/xpostconf b/postfix/mantools/xpostconf index e221cf428..6721e0a38 100755 --- a/postfix/mantools/xpostconf +++ b/postfix/mantools/xpostconf @@ -58,7 +58,7 @@ open(POSTCONF, $protofile) || die " cannot open $protofile: $!\n"; while() { - next if /^#/; + next if /^#/ && $text eq ""; next unless ($name || /\S/); if (/^%(PARAM|CLASS)/) { diff --git a/postfix/proto/Makefile.in b/postfix/proto/Makefile.in index ec7e0d6ae..d2ffd2416 100644 --- a/postfix/proto/Makefile.in +++ b/postfix/proto/Makefile.in @@ -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 \ diff --git a/postfix/proto/STRESS_README.html b/postfix/proto/STRESS_README.html index 9d29979d4..9f6e7a4c8 100644 --- a/postfix/proto/STRESS_README.html +++ b/postfix/proto/STRESS_README.html @@ -24,9 +24,10 @@ Stress-Dependent Configuration

    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.

    +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.

    Topics covered in this document:

    @@ -55,8 +56,7 @@ switch configuration settings under overload.

    Symptoms of Postfix SMTP server overload

    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:

      -
    • 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 @@ -92,9 +81,22 @@ connect to this instead of the public SMTP service.

      connection after CONNECT" events. This happens because remote SMTP clients disconnect before Postfix answers the connection.

      +
    • 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 last two symptoms also happen without overload.

    +

    NOTE: The first two symptoms may also happen without overload, +for example:

      diff --git a/postfix/proto/TLS_README.html b/postfix/proto/TLS_README.html index 5ee992597..92889bc50 100644 --- a/postfix/proto/TLS_README.html +++ b/postfix/proto/TLS_README.html @@ -21,7 +21,7 @@

      WARNING

      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

      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

      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.

      For servers that are not 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.

      +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, @@ -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).

      -

      Example: the certificate for "server.dom.ain" was issued by +

      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:

      @@ -283,15 +287,7 @@ 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).

      +$smtpd_tls_CAfile or install it in the $smtpd_tls_CApath directory.

      RSA key and certificate examples:

      @@ -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.

      -

      When you configure Postfix to request 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 @@ -450,12 +446,13 @@ supported).

      -

      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 +is never offered due to insufficient privileges to access the Postfix +SMTP server private key. This is intended behavior.

      You can ENFORCE the use of TLS, @@ -481,7 +478,8 @@ by default and should only seldom be used.

      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 < 5.0 and Win32 >=5.0 when run on a port<>25 and OE (5.01 Mac on all ports).

      @@ -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.

      +offers anonymous ciphers to remote SMTP clients, these are automatically +suppressed +when the Postfix SMTP server is configured to ask for client +certificates.

      Example:

      @@ -553,18 +553,26 @@ logged.

      -

      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
       
      @@ -661,23 +669,30 @@ 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).

      +
      permit_tls_clientcerts

      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. -

      +
      permit_tls_all_clientcerts

      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.

      +
      check_ccert_access type: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 CA issues the client certificates, and @@ -704,16 +719,10 @@ certificate must no longer be used (e.g. an employee leaving).

      -

      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: 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:

      -
       /etc/postfix/main.cf:
      @@ -766,27 +775,29 @@ and not specifying an smtpd_tls_dcert_file. 

      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 ≥ 2.5: + smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
      -

      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.

      +

      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:

      -% openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024
      -% openssl gendh -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512
      +% openssl gendh -out /etc/postfix/dh_512.pem -2 512
      +% openssl gendh -out /etc/postfix/dh_1024.pem -2 1024
       
      @@ -841,6 +852,8 @@ key configuration
    • Mandating TLS encryption +
    • Certificate fingerprint verification +
    • Mandating server certificate verification
    • Secure server certificate verification @@ -866,14 +879,14 @@ key configuration

      TLS support in the LMTP delivery agent

      -

      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 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 LMTP delivery agent can communicate with LMTP servers listening +

      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 @@ -887,7 +900,8 @@ The "null" ciphers provide authentication without encryption.

      Client-side certificate and private key configuration

      -

      Do not configure client certificates unless you must present +

      Do not configure Postfix SMTP client certificates unless you must +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:

      @@ -951,15 +965,7 @@ 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).

      +$smtp_tls_CAfile or install it in the $smtp_tls_CApath directory.

      RSA key and certificate examples:

      @@ -1212,6 +1218,8 @@ in the sections that follow.

      Opportunistic TLS.
      encrypt
      Mandatory TLS encryption. +
      fingerprint
      +
      Certificate fingerprint verification.
      verify
      Mandatory server certificate verification.
      secure
      @@ -1314,11 +1322,12 @@ on TLS limitations above.

      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.

      At this security level and higher, the smtp_tls_mandatory_protocols @@ -1437,13 +1446,82 @@ use the new policy table instead.

      +

      Certificate fingerprint verification +

      + +

      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 smtp_tls_fingerprint_digest 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
      +
      +
      +

      Mandatory server certificate verification

      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

      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 above.

      @@ -1492,7 +1571,7 @@ Postfix 2.3 and later should use the new TLS policy settings.

      Example:

      -

      In this example, the client encrypts all traffic to the +

      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.

      @@ -1543,7 +1622,8 @@ 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 +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.

      @@ -1578,9 +1658,11 @@ should use the new TLS policy settings.

      Secure-channel TLS without transport(5) table overrides:

      -

      The client will encrypt all traffic and verify the destination name +

      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 example.com, but these are not used when +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 @@ -1729,35 +1811,50 @@ describe the corresponding table syntax:

      -
      none
      -
      No TLS. No additional attributes are supported at this level.
      - -
      may
      -
      Opportunistic TLS. No additional attributes are supported at this -level.
      - -
      encrypt
      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.
      - -
      verify
      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).
      - -
      secure
      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). -
      +
      none
      No TLS. No +additional attributes are supported at this level.
      + +
      may
      Opportunistic TLS. +No additional attributes are supported at this level.
      + +
      encrypt
      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" attribute +overrides the main.cf smtp_tls_mandatory_protocols parameter.
      + +
      fingerprint
      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 match attribute, or else +the main.cf smtp_tls_fingerprint_cert_match parameter, +lists the valid fingerprints of the server certificate. The +digest algorithm used to calculate fingerprints is selected by the +smtp_tls_fingerprint_digest 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.
      + +
      verify
      Mandatory +server 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_verify_cert_match parameter value when no optional +"match" attribute is specified).
      + +
      secure
      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).
      @@ -1789,6 +1886,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
      @@ -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
       
      @@ -2040,18 +2143,26 @@ postfix/smtp[pid]: Host offered STARTTLS: [hostname.example.com]

      Server certificate verification depth

      -

      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).

      - -

      Example:

      +

      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
       
      @@ -2067,7 +2178,8 @@ 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 +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.

      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 @@ -2405,7 +2520,7 @@ but don't require them from all clients.

      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. +
    • 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. +
    diff --git a/postfix/proto/master b/postfix/proto/master index 11f407933..15b82f4e2 100644 --- a/postfix/proto/master +++ b/postfix/proto/master @@ -100,11 +100,11 @@ # 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. diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index b05f1e7f5..038a7e84a 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -38,10 +38,18 @@ # * Text between is stripped out. The # must appear on separate lines. # +# * Text after a blank line must start with an HTML element. +# # Also: # # * All
    and
    text must be closed with and
    . # +# * Use
    ..
    for examples +# between narrative text, instead of indenting examples by hand. +# +# * Use
    ..
    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,

    +
    -    masquerade_domains = foo.example.com example.com
    +masquerade_domains = foo.example.com example.com
     
    +

    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,

    +
    -    masquerade_domains = !foo.example.com example.com
    +masquerade_domains = !foo.example.com example.com
     
    +

    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:

    +
    -  /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
     
    +

    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:

    +
    -  /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
     
    +

    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:

    +
    -  /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
     
    +

    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:

    +
    -    /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
     
    +

    and route mail for the destination in question to the "broken-smtp" @@ -4678,9 +4698,12 @@ client network address information.

    check_ccert_access type:table
    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.
    +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.
    check_client_access type:table
    @@ -4714,9 +4737,13 @@ allowed to relay. This feature is available with Postfix version 2.2.
    permit_tls_clientcerts
    -
    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.
    +
    reject_rbl_client rbl_domain=d.d.d.d
    Reject the request when the reversed client network address is @@ -4872,7 +4899,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: -
     /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:
     

    +
    -    reject, defer, defer_if_permit, reject_unauth_destination
    +reject, defer, defer_if_permit, reject_unauth_destination
     
    +

    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:

    +
    -    smtpd_recipient_restrictions =
    -        permit_mynetworks, permit_sasl_authenticated, ...
    +smtpd_recipient_restrictions =
    +    permit_mynetworks, permit_sasl_authenticated, ...
     
    +

    To reject all SMTP connections from unauthenticated clients, specify "smtpd_delay_reject = yes" (which is the default) and use:

    +
    -    smtpd_client_restrictions = permit_sasl_authenticated, reject
    +smtpd_client_restrictions = permit_sasl_authenticated, reject
     
    +

    See the SASL_README file for SASL configuration and operation details. @@ -8135,16 +8167,20 @@ considers local.

    addresses from remote SMTP clients, so that those addresses cannot be confused with local addresses.

    +
     
    -    remote_header_rewrite_domain = domain.invalid
    +remote_header_rewrite_domain = domain.invalid
     
    +

    The default, purist, setting: don't rewrite headers from remote clients at all.

    +
    -    remote_header_rewrite_domain =
    +remote_header_rewrite_domain =
     
    +
    %PARAM local_header_rewrite_clients permit_inet_interfaces @@ -8186,8 +8222,10 @@ protocol.
    permit_tls_clientcerts
    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).
    permit_tls_all_clientcerts
    @@ -8213,16 +8251,20 @@ is suitable for, e.g., pop-before-smtp lookup tables. message headers, and always append my own domain to incomplete header addresses.

    +
     
    -    local_header_rewrite_clients = static:all
    +local_header_rewrite_clients = static:all
     
    +

    The purist (and default) setting: rewrite headers only in mail from Postfix sendmail and in SMTP mail from this machine.

    +
    -    local_header_rewrite_clients = permit_inet_interfaces
    +local_header_rewrite_clients = permit_inet_interfaces
     
    +

    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.

    rewriting when mail from a remote client is forwarded by a neighboring system.

    +
    -    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 
     
    +
    %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

    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.

    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").

    %PARAM smtpd_tls_dcert_file

    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.

    See the discussion under smtpd_tls_cert_file for more details.

    @@ -8463,7 +8506,7 @@ may be annoying, so this option is "off" by default.

    %PARAM smtpd_tls_req_ccert 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".

    @@ -8472,13 +8515,21 @@ a warning written to the mail log.

    This feature is available in Postfix 2.2 and later.

    -%PARAM smtpd_tls_ccert_verifydepth 5 +%PARAM smtpd_tls_ccert_verifydepth 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.

    + +

    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.

    This feature is available in Postfix 2.2 and later.

    @@ -8535,12 +8586,12 @@ are not possible.

    %PARAM relay_clientcerts -

    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).

    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.

    with other TLS packages, it is more secure to generate your own set of parameters with something like the following command:

    +
    -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
     
    +

    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:

    -    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 =
     
    @@ -8925,13 +8978,20 @@ per-site TLS policies) for a possible work-around.

    This feature is available in Postfix 2.2 and later. With Postfix 2.3 and later use smtp_tls_policy_maps instead.

    -%PARAM smtp_tls_scert_verifydepth 5 +%PARAM smtp_tls_scert_verifydepth 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.

    -

    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...).

    +

    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.

    This feature is available in Postfix 2.2 and later.

    @@ -9203,7 +9263,7 @@ substitutions in regular expression maps.

    This feature is available in Postfix 2.3 and later.

    -%PARAM empty_address_relayhost_maps_lookup_key <> +%PARAM empty_address_relayhost_maps_lookup_key <>

    The sender_dependent_relayhost_maps search string that will be used instead of the null sender address.

    @@ -9252,10 +9312,12 @@ clients, or it can be specified in the master.cf file for a specific client, for example:

    +
    -  /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
     
    +

    This feature is available in Postfix 2.3 and later. @@ -9405,7 +9467,7 @@ parameter. See there for details.

    This feature is available in Postfix 2.3 and later.

    -%PARAM lmtp_tls_scert_verifydepth 5 +%PARAM lmtp_tls_scert_verifydepth 9

    The LMTP-specific version of the smtp_tls_scert_verifydepth configuration parameter. See there for details.

    @@ -9461,6 +9523,13 @@ parameter. See there for details.

    This feature is available in Postfix 2.3 and later.

    +%PARAM lmtp_tls_security_level + +

    The LMTP-specific version of the smtp_tls_security_level configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + %PARAM lmtp_tls_enforce_peername yes

    The LMTP-specific version of the smtp_tls_enforce_peername @@ -9625,10 +9694,8 @@ configuration parameter. See there for details.

    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.

    - -

    This feature should be available in Postfix 2.4 and later.

    +certificate. This feature is under construction as of Postfix version +2.3.

    %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. +
    fingerprint
    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 match attribute, or else the main.cf +smtp_tls_fingerprint_cert_match parameter, lists the +valid "fingerprints" of the server certificate. The digest +algorithm used to calculate the fingerprint is selected by the +smtp_tls_fingerprint_digest 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.
    +
    verify
    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:

    -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
     
    +
    -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
     

    Note: The hostname strategy if listed in a non-default @@ -9837,22 +9925,36 @@ configurations in environments where DNS security is not assured.

    %PARAM smtp_tls_mandatory_protocols 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 SSL_get_version(3)), are "SSLv2", "SSLv3" and -"TLSv1".

    +empty value means allow all protocols. The valid protocol names, (see +SSL_get_version(3)), are "SSLv2", "SSLv3" and "TLSv1".

    + +

    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.

    -

    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.

    See the documentation of the smtp_tls_policy_maps parameter and TLS_README for more information about security levels.

    +

    Example:

    + +
    +smtp_tls_mandatory_protocols = TLSv1
    +# Alternative form with Postfix ≥ 2.5:
    +smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
    +
    +

    This feature is available in Postfix 2.3 and later.

    %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:

    +
     smtp_tls_secure_cert_match = nexthop
     
    +

    Sample policy table override:

    +
     example.net     secure match=example.com:.example.com
     .example.net    secure match=example.com:.example.com
     
    +

    This feature is available in Postfix 2.3 and later.

    @@ -9997,18 +10103,31 @@ configuration parameter. See there for details.

    %PARAM smtpd_tls_mandatory_protocols 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.

    + +

    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.

    + +

    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.

    Example:

    -smtpd_tls_mandatory_protocols = SSLv3, TLSv1
    +smtpd_tls_mandatory_protocols = TLSv1
    +# Alternative form with Postfix ≥ 2.5:
    +smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
     

    This feature is available in Postfix 2.3 and later.

    @@ -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.
    +
    fingerprint
    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 smtp_tls_fingerprint_cert_match parameter lists +the valid "fingerprints" of the server certificate. The digest +algorithm used to calculate the fingerprint is selected by the +smtp_tls_fingerprint_digest parameter.
    +
    verify
    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.
    Examples:

    -

    No TLS, old-style: smtp_use_tls=no and smtp_enforce_tls=no.

    -main.cf:
    -    smtp_tls_security_level = none
    +# No TLS. Formerly: smtp_use_tls=no and smtp_enforce_tls=no.
    +smtp_tls_security_level = none
    +
    + +
    +# Opportunistic TLS.
    +smtp_tls_security_level = may
     
    -

    Opportunistic TLS:

    -main.cf:
    -    smtp_tls_security_level = may
    +# Mandatory (high-grade) TLS encryption.
    +smtp_tls_security_level = encrypt
    +smtp_tls_mandatory_ciphers = high
     
    -

    Mandatory (high-grade) TLS encryption:

    -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
     
    -

    Mandatory TLS verification, of hostname or nexthop domain:

    -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
     
    -

    Secure channel TLS with exact nexthop name matching:

    -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 ≥ 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
     

    This feature is available in Postfix 2.3 and later.

    @@ -10393,6 +10531,7 @@ only ciphers matching all the properties are excluded.

    Examples (some of these will cause problems):

    +
     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
     
    +

    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 all the properties are excluded.

    Examples (some of these will cause problems):

    +
     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
     
    +

    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. -

    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 @@ -10680,11 +10823,9 @@ with other MTAs.

    Example:

    -
    -    smtpd_tls_always_issue_session_ids = no
    +smtpd_tls_always_issue_session_ids = no
     
    -

    This feature is available in Postfix 2.3 and later.

    @@ -10728,6 +10869,180 @@ configuration parameter. See there for details.

    This feature is available in Postfix 2.4 and later.

    +%PARAM smtp_tls_fingerprint_digest md5 + +

    The message digest algorithm used to construct remote SMTP server +certificate fingerprints. At the "fingerprint" TLS security level +(smtp_tls_security_level = fingerprint), the server certificate is +verified by directly matching its fingerprint. 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.

    + +

    The default algorithm is md5; this is consistent with +the backwards compatible setting of the digest used to verify client +certificates in the SMTP server.

    + +

    The best practice algorithm is now sha1. 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. +

    + +

    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.

    + +

    To find the fingerprint of a specific certificate file, with a +specific digest algorithm, run: +

    + +
    +
    +$ openssl x509 -noout -fingerprint -digest -in certfile.pem
    +
    +
    + +

    The text to the right of "=" sign is the desired fingerprint. +For example:

    + +
    +
    +$ 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
    +
    +
    + +

    This feature is available in Postfix 2.5 and later.

    + +%PARAM smtp_tls_fingerprint_cert_match + +

    List of acceptable remote SMTP server certificate fingerprints +for the "fingerprint" TLS security level (smtp_tls_security_level = +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 smtp_tls_fingerprint_digest +parameter.

    + +

    When an smtp_tls_policy_maps 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.

    + +

    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.

    + +
    +
    +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
    +
    +
    + +

    This feature is available in Postfix 2.5 and later.

    + +%PARAM lmtp_tls_fingerprint_cert_match + +

    The LMTP-specific version of the smtp_tls_fingerprint_cert_match +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.5 and later.

    + +%PARAM lmtp_tls_fingerprint_digest md5 + +

    The LMTP-specific version of the smtp_tls_fingerprint_digest +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.5 and later.

    + +%PARAM smtpd_tls_fingerprint_digest md5 + +

    The message digest algorithm used to construct client-certificate +fingerprints for check_ccert_access and +permit_tls_clientcerts. The default algorithm is md5, +for backwards compatibility with Postfix releases prior to 2.5. +

    + +

    The best practice algorithm is now sha1. 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. +

    + +

    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.

    + +

    To find the fingerprint of a specific certificate file, with a +specific digest algorithm, run:

    + +
    +
    +$ openssl x509 -noout -fingerprint -digest -in certfile.pem
    +
    +
    + +

    The text to the right of "=" sign is the desired fingerprint. +For example:

    + +
    +
    +$ 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
    +
    +
    + +

    Example: client-certificate access table, with sha1 fingerprints:

    + +
    +
    +/etc/postfix/main.cf:
    +    smtpd_tls_fingerprint_digest = sha1
    +    smtpd_client_restrictions =
    +        check_ccert_access hash:/etc/postfix/access,
    +        reject
    +
    +
    +/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
    +
    +
    + +

    This feature is available in Postfix 2.5 and later.

    + %PARAM lmtp_pix_workaround_maps

    The LMTP-specific version of the smtp_pix_workaround_maps @@ -10950,7 +11265,7 @@ is the master.cf name of the message delivery transport.

    This feature is available in Postfix 2.5 and later.

    -%PARAM transport_destination_concurrency_failed_cohort_limit $default_destination_concurrency_failed_cohort_limit +%PARAM transport_destination_concurrency_failed_cohort_limit $default_destination_concurrency_failed_cohort_limit

    A transport-specific override for the default_destination_concurrency_failed_cohort_limit parameter value, diff --git a/postfix/src/anvil/anvil.c b/postfix/src/anvil/anvil.c index 793770090..ac45cf305 100644 --- a/postfix/src/anvil/anvil.c +++ b/postfix/src/anvil/anvil.c @@ -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, diff --git a/postfix/src/bounce/bounce.c b/postfix/src/bounce/bounce.c index 805144e95..ae62d21db 100644 --- a/postfix/src/bounce/bounce.c +++ b/postfix/src/bounce/bounce.c @@ -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, diff --git a/postfix/src/bounce/bounce_template.c b/postfix/src/bounce/bounce_template.c index 23f16b0a3..352944b59 100644 --- a/postfix/src/bounce/bounce_template.c +++ b/postfix/src/bounce/bounce_template.c @@ -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; diff --git a/postfix/src/cleanup/cleanup_bounce.c b/postfix/src/cleanup/cleanup_bounce.c index d0d4c4f3e..e5a9cf921 100644 --- a/postfix/src/cleanup/cleanup_bounce.c +++ b/postfix/src/cleanup/cleanup_bounce.c @@ -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; diff --git a/postfix/src/cleanup/cleanup_init.c b/postfix/src/cleanup/cleanup_init.c index c30c91e9c..bb3983c4d 100644 --- a/postfix/src/cleanup/cleanup_init.c +++ b/postfix/src/cleanup/cleanup_init.c @@ -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, diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index fee73bbe9..3abb2519a 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -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; diff --git a/postfix/src/cleanup/cleanup_milter.c b/postfix/src/cleanup/cleanup_milter.c index ed1adb8ff..7a76c52ef 100644 --- a/postfix/src/cleanup/cleanup_milter.c +++ b/postfix/src/cleanup/cleanup_milter.c @@ -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; diff --git a/postfix/src/flush/flush.c b/postfix/src/flush/flush.c index 853769144..2658819cd 100644 --- a/postfix/src/flush/flush.c +++ b/postfix/src/flush/flush.c @@ -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, diff --git a/postfix/src/global/cleanup_strerror.c b/postfix/src/global/cleanup_strerror.c index 3603f04c0..ce0bb40d0 100644 --- a/postfix/src/global/cleanup_strerror.c +++ b/postfix/src/global/cleanup_strerror.c @@ -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; diff --git a/postfix/src/global/cleanup_user.h b/postfix/src/global/cleanup_user.h index ede715d41..9d399cde7 100644 --- a/postfix/src/global/cleanup_user.h +++ b/postfix/src/global/cleanup_user.h @@ -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 diff --git a/postfix/src/global/data_redirect.c b/postfix/src/global/data_redirect.c index 95697075c..77a28e209 100644 --- a/postfix/src/global/data_redirect.c +++ b/postfix/src/global/data_redirect.c @@ -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, diff --git a/postfix/src/global/delivered_hdr.c b/postfix/src/global/delivered_hdr.c index 746998a57..2bbd2f6d1 100644 --- a/postfix/src/global/delivered_hdr.c +++ b/postfix/src/global/delivered_hdr.c @@ -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. diff --git a/postfix/src/global/dsn_mask.c b/postfix/src/global/dsn_mask.c index 251f6f6ac..3c183aa4a 100644 --- a/postfix/src/global/dsn_mask.c +++ b/postfix/src/global/dsn_mask.c @@ -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, diff --git a/postfix/src/global/ehlo_mask.c b/postfix/src/global/ehlo_mask.c index 811005487..d7501934b 100644 --- a/postfix/src/global/ehlo_mask.c +++ b/postfix/src/global/ehlo_mask.c @@ -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, diff --git a/postfix/src/global/ext_prop.c b/postfix/src/global/ext_prop.c index 9ae7cc493..29bce7bdd 100644 --- a/postfix/src/global/ext_prop.c +++ b/postfix/src/global/ext_prop.c @@ -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, diff --git a/postfix/src/global/header_body_checks.c b/postfix/src/global/header_body_checks.c index de8f58bc9..b5f2aa12b 100644 --- a/postfix/src/global/header_body_checks.c +++ b/postfix/src/global/header_body_checks.c @@ -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; diff --git a/postfix/src/global/header_body_checks.h b/postfix/src/global/header_body_checks.h index 2fc37677b..f397ae2a7 100644 --- a/postfix/src/global/header_body_checks.h +++ b/postfix/src/global/header_body_checks.h @@ -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); diff --git a/postfix/src/global/header_opts.c b/postfix/src/global/header_opts.c index 4a88ccb28..0461502ff 100644 --- a/postfix/src/global/header_opts.c +++ b/postfix/src/global/header_opts.c @@ -6,7 +6,7 @@ /* SYNOPSIS /* #include /* -/* 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))); } diff --git a/postfix/src/global/header_opts.h b/postfix/src/global/header_opts.h index cb6a48279..a0f26510a 100644 --- a/postfix/src/global/header_opts.h +++ b/postfix/src/global/header_opts.h @@ -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 diff --git a/postfix/src/global/input_transp.c b/postfix/src/global/input_transp.c index 46b881280..ca3af3409 100644 --- a/postfix/src/global/input_transp.c +++ b/postfix/src/global/input_transp.c @@ -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, diff --git a/postfix/src/global/int_filt.c b/postfix/src/global/int_filt.c index 1071b10d6..528824170 100644 --- a/postfix/src/global/int_filt.c +++ b/postfix/src/global/int_filt.c @@ -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, diff --git a/postfix/src/global/mail_conf.h b/postfix/src/global/mail_conf.h index a8bff1b57..89cce98c1 100644 --- a/postfix/src/global/mail_conf.h +++ b/postfix/src/global/mail_conf.h @@ -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 diff --git a/postfix/src/global/mail_conf_bool.c b/postfix/src/global/mail_conf_bool.c index f6a11024b..30d4813ba 100644 --- a/postfix/src/global/mail_conf_bool.c +++ b/postfix/src/global/mail_conf_bool.c @@ -19,10 +19,10 @@ /* 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); diff --git a/postfix/src/global/mail_conf_int.c b/postfix/src/global/mail_conf_int.c index e00e1de0a..1c2dcba43 100644 --- a/postfix/src/global/mail_conf_int.c +++ b/postfix/src/global/mail_conf_int.c @@ -23,10 +23,10 @@ /* 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, diff --git a/postfix/src/global/mail_conf_long.c b/postfix/src/global/mail_conf_long.c index 91e488a55..e9feaa3ad 100644 --- a/postfix/src/global/mail_conf_long.c +++ b/postfix/src/global/mail_conf_long.c @@ -23,10 +23,10 @@ /* 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, diff --git a/postfix/src/global/mail_conf_raw.c b/postfix/src/global/mail_conf_raw.c index 2e4c9832e..4c9c5bde7 100644 --- a/postfix/src/global/mail_conf_raw.c +++ b/postfix/src/global/mail_conf_raw.c @@ -19,10 +19,10 @@ /* 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]) diff --git a/postfix/src/global/mail_conf_str.c b/postfix/src/global/mail_conf_str.c index 1f8af32e3..8d8288ce3 100644 --- a/postfix/src/global/mail_conf_str.c +++ b/postfix/src/global/mail_conf_str.c @@ -23,10 +23,10 @@ /* 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]) diff --git a/postfix/src/global/mail_conf_time.c b/postfix/src/global/mail_conf_time.c index 09926c76f..64523e9da 100644 --- a/postfix/src/global/mail_conf_time.c +++ b/postfix/src/global/mail_conf_time.c @@ -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, diff --git a/postfix/src/global/mail_dict.c b/postfix/src/global/mail_dict.c index fab1db304..35ecffb88 100644 --- a/postfix/src/global/mail_dict.c +++ b/postfix/src/global/mail_dict.c @@ -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); diff --git a/postfix/src/global/mail_error.c b/postfix/src/global/mail_error.c index 9355c051f..8e9d40936 100644 --- a/postfix/src/global/mail_error.c +++ b/postfix/src/global/mail_error.c @@ -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, diff --git a/postfix/src/global/mail_error.h b/postfix/src/global/mail_error.h index ffe7b3806..89aee07e4 100644 --- a/postfix/src/global/mail_error.h +++ b/postfix/src/global/mail_error.h @@ -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 diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index 54e48368f..2cb19631d 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -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, diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 549ebc224..078d15b82 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 1d9229222..d8e7ab37f 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 diff --git a/postfix/src/global/mbox_conf.c b/postfix/src/global/mbox_conf.c index 1fc1276f8..2856d86ab 100644 --- a/postfix/src/global/mbox_conf.c +++ b/postfix/src/global/mbox_conf.c @@ -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); diff --git a/postfix/src/global/mime_state.c b/postfix/src/global/mime_state.c index bea9e0ad4..ac754c0a3 100644 --- a/postfix/src/global/mime_state.c +++ b/postfix/src/global/mime_state.c @@ -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; diff --git a/postfix/src/global/mime_state.h b/postfix/src/global/mime_state.h index 35f5c827f..88a4d7cf3 100644 --- a/postfix/src/global/mime_state.h +++ b/postfix/src/global/mime_state.h @@ -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); /* diff --git a/postfix/src/global/mkmap_open.c b/postfix/src/global/mkmap_open.c index f96cd472e..69a0d5727 100644 --- a/postfix/src/global/mkmap_open.c +++ b/postfix/src/global/mkmap_open.c @@ -76,14 +76,16 @@ /* * 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. diff --git a/postfix/src/global/mynetworks.c b/postfix/src/global/mynetworks.c index 12192ca3b..f2b9d5c22 100644 --- a/postfix/src/global/mynetworks.c +++ b/postfix/src/global/mynetworks.c @@ -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, diff --git a/postfix/src/global/pipe_command.c b/postfix/src/global/pipe_command.c index d305f79d0..ce3bad0a9 100644 --- a/postfix/src/global/pipe_command.c +++ b/postfix/src/global/pipe_command.c @@ -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 diff --git a/postfix/src/global/sys_exits.c b/postfix/src/global/sys_exits.c index 09c1db22e..bdd26b440 100644 --- a/postfix/src/global/sys_exits.c +++ b/postfix/src/global/sys_exits.c @@ -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)); diff --git a/postfix/src/global/sys_exits.h b/postfix/src/global/sys_exits.h index ee3b8ba32..bf4cce18e 100644 --- a/postfix/src/global/sys_exits.h +++ b/postfix/src/global/sys_exits.h @@ -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) diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c index 6788fc80f..6300111af 100644 --- a/postfix/src/local/local.c +++ b/postfix/src/local/local.c @@ -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, diff --git a/postfix/src/master/master.h b/postfix/src/master/master.h index f1dcdda4f..88dbb5622 100644 --- a/postfix/src/master/master.h +++ b/postfix/src/master/master.h @@ -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. diff --git a/postfix/src/master/master_listen.c b/postfix/src/master/master_listen.c index 50b972177..494d429f7 100644 --- a/postfix/src/master/master_listen.c +++ b/postfix/src/master/master_listen.c @@ -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 diff --git a/postfix/src/master/master_proto.h b/postfix/src/master/master_proto.h index a017b5a26..bfa0e04c6 100644 --- a/postfix/src/master/master_proto.h +++ b/postfix/src/master/master_proto.h @@ -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 diff --git a/postfix/src/master/master_vars.c b/postfix/src/master/master_vars.c index 33869b8c8..1457d6b4b 100644 --- a/postfix/src/master/master_vars.c +++ b/postfix/src/master/master_vars.c @@ -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, }; diff --git a/postfix/src/master/master_wakeup.c b/postfix/src/master/master_wakeup.c index 306514ede..ee6062023 100644 --- a/postfix/src/master/master_wakeup.c +++ b/postfix/src/master/master_wakeup.c @@ -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 diff --git a/postfix/src/milter/milter8.c b/postfix/src/milter/milter8.c index 37ce0060b..6247b601a 100644 --- a/postfix/src/milter/milter8.c +++ b/postfix/src/milter/milter8.c @@ -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; diff --git a/postfix/src/oqmgr/qmgr.c b/postfix/src/oqmgr/qmgr.c index 875ae625f..d895cc78d 100644 --- a/postfix/src/oqmgr/qmgr.c +++ b/postfix/src/oqmgr/qmgr.c @@ -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, diff --git a/postfix/src/oqmgr/qmgr_feedback.c b/postfix/src/oqmgr/qmgr_feedback.c index 6d62a6ed2..f341b9591 100644 --- a/postfix/src/oqmgr/qmgr_feedback.c +++ b/postfix/src/oqmgr/qmgr_feedback.c @@ -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, diff --git a/postfix/src/pickup/pickup.c b/postfix/src/pickup/pickup.c index 153f36326..526281826 100644 --- a/postfix/src/pickup/pickup.c +++ b/postfix/src/pickup/pickup.c @@ -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, diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c index 1a699c126..13a0da53f 100644 --- a/postfix/src/pipe/pipe.c +++ b/postfix/src/pipe/pipe.c @@ -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, }; diff --git a/postfix/src/postconf/extract.awk b/postfix/src/postconf/extract.awk index 77cd7440f..8619c3f03 100644 --- a/postfix/src/postconf/extract.awk +++ b/postfix/src/postconf/extract.awk @@ -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) { diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c index bb88fcd64..329a5ff1d 100644 --- a/postfix/src/postconf/postconf.c +++ b/postfix/src/postconf/postconf.c @@ -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); diff --git a/postfix/src/postdrop/postdrop.c b/postfix/src/postdrop/postdrop.c index 92170708f..630bdb300 100644 --- a/postfix/src/postdrop/postdrop.c +++ b/postfix/src/postdrop/postdrop.c @@ -157,7 +157,7 @@ */ 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, }; diff --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c index 132aedd6f..13eb9a681 100644 --- a/postfix/src/postfix/postfix.c +++ b/postfix/src/postfix/postfix.c @@ -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, diff --git a/postfix/src/postqueue/postqueue.c b/postfix/src/postqueue/postqueue.c index dad7b592b..7ced31f05 100644 --- a/postfix/src/postqueue/postqueue.c +++ b/postfix/src/postqueue/postqueue.c @@ -251,7 +251,7 @@ 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, diff --git a/postfix/src/proxymap/proxymap.c b/postfix/src/proxymap/proxymap.c index 481510a8d..937f370df 100644 --- a/postfix/src/proxymap/proxymap.c +++ b/postfix/src/proxymap/proxymap.c @@ -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, diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c index 99d0c6425..b3da982b1 100644 --- a/postfix/src/qmgr/qmgr.c +++ b/postfix/src/qmgr/qmgr.c @@ -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, diff --git a/postfix/src/qmgr/qmgr_feedback.c b/postfix/src/qmgr/qmgr_feedback.c index 6d62a6ed2..f341b9591 100644 --- a/postfix/src/qmgr/qmgr_feedback.c +++ b/postfix/src/qmgr/qmgr_feedback.c @@ -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, diff --git a/postfix/src/qmqpd/qmqpd.c b/postfix/src/qmqpd/qmqpd.c index dab3b09dc..a6b5e66f4 100644 --- a/postfix/src/qmqpd/qmqpd.c +++ b/postfix/src/qmqpd/qmqpd.c @@ -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, }; diff --git a/postfix/src/scache/scache.c b/postfix/src/scache/scache.c index f75ec306a..6a4164ef6 100644 --- a/postfix/src/scache/scache.c +++ b/postfix/src/scache/scache.c @@ -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, diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index e2da158ba..7c1d6e805 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -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; diff --git a/postfix/src/showq/showq.c b/postfix/src/showq/showq.c index 613f333e7..73517a60e 100644 --- a/postfix/src/showq/showq.c +++ b/postfix/src/showq/showq.c @@ -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, }; diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c index 0ebb292b3..7ab5241e9 100644 --- a/postfix/src/smtp/lmtp_params.c +++ b/postfix/src/smtp/lmtp_params.c @@ -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, @@ -19,14 +19,11 @@ 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, @@ -74,18 +71,17 @@ 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, diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 356967c7c..963256c96 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -325,9 +325,9 @@ /* 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 @@ -362,6 +362,15 @@ /* 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 @@ -593,16 +602,16 @@ /* 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"); diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 259d32ea9..da3f3034b 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -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 */ diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c index 947f5299c..e8e7887e9 100644 --- a/postfix/src/smtp/smtp_params.c +++ b/postfix/src/smtp/smtp_params.c @@ -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, @@ -20,14 +20,11 @@ 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, @@ -75,18 +72,17 @@ 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, diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 48d2e3eba..ed40eff5b 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -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 "." 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); diff --git a/postfix/src/smtp/smtp_sasl_proto.c b/postfix/src/smtp/smtp_sasl_proto.c index ce0877a1d..9e813b276 100644 --- a/postfix/src/smtp/smtp_sasl_proto.c +++ b/postfix/src/smtp/smtp_sasl_proto.c @@ -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 diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 97cc8ceb9..b67bc8524 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -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); diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index a7a3e9c5d..807ec3fcb 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -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 diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 231fe99f3..68775495a 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -316,7 +316,7 @@ /* 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. @@ -345,7 +345,7 @@ /* 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 @@ -353,7 +353,7 @@ /* 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 @@ -379,6 +379,12 @@ /* .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 @@ -888,6 +894,10 @@ /* 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, diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index b4e1aeb8a..899bb70f4 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -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 /* diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 81839bd39..f1c0366da 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -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, diff --git a/postfix/src/smtpd/smtpd_milter.c b/postfix/src/smtpd/smtpd_milter.c index 356debed5..28693b6f7 100644 --- a/postfix/src/smtpd/smtpd_milter.c +++ b/postfix/src/smtpd/smtpd_milter.c @@ -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 /* diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c index e4804de8f..c2fa84102 100644 --- a/postfix/src/smtpd/smtpd_proxy.c +++ b/postfix/src/smtpd/smtpd_proxy.c @@ -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. diff --git a/postfix/src/spawn/spawn.c b/postfix/src/spawn/spawn.c index 3e0613871..3ef6228f5 100644 --- a/postfix/src/spawn/spawn.c +++ b/postfix/src/spawn/spawn.c @@ -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, }; diff --git a/postfix/src/tls/Makefile.in b/postfix/src/tls/Makefile.in index d3e21510a..9ebaae1e4 100644 --- a/postfix/src/tls/Makefile.in +++ b/postfix/src/tls/Makefile.in @@ -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 diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index b3ca996fe..058d7676a 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -15,19 +15,25 @@ * Utility library. */ #include +#include /* * 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 */ diff --git a/postfix/src/tls/tls_bio_ops.c b/postfix/src/tls/tls_bio_ops.c index bc359baf8..39e0b66cb 100644 --- a/postfix/src/tls/tls_bio_ops.c +++ b/postfix/src/tls/tls_bio_ops.c @@ -10,31 +10,31 @@ /* 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. @@ -140,6 +140,9 @@ /* 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); } diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index 0c77c8c4a..04d186c36 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -1,22 +1,22 @@ /*++ /* NAME -/* tls +/* tls_client /* SUMMARY /* client-side TLS engine /* SYNOPSIS /* #include /* -/* 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 @@ -78,19 +78,24 @@ /* 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 @@ -110,6 +115,9 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Victor Duchovni +/* Morgan Stanley /*--*/ /* System library. */ @@ -149,7 +157,7 @@ /* 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(); diff --git a/postfix/src/tls/tls_level.c b/postfix/src/tls/tls_level.c index 03affcfdc..32063200e 100644 --- a/postfix/src/tls/tls_level.c +++ b/postfix/src/tls/tls_level.c @@ -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. */ @@ -50,11 +53,21 @@ /* 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, }; diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c index 2d05b0ba8..a1f9060a6 100644 --- a/postfix/src/tls/tls_misc.c +++ b/postfix/src/tls/tls_misc.c @@ -7,27 +7,50 @@ /* #define TLS_INTERNAL /* #include /* -/* 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; @@ -43,8 +66,14 @@ /* 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. @@ -57,15 +86,31 @@ /* 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. @@ -96,6 +141,9 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Victor Duchovni +/* Morgan Stanley /*--*/ /* System library. */ @@ -115,49 +163,56 @@ #include #include -/* TLS library. */ + /* + * Global library. + */ +#include +#include + /* + * TLS library. + */ #define TLS_INTERNAL #include /* 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 } } } diff --git a/postfix/src/tls/tls_server.c b/postfix/src/tls/tls_server.c index 481a67f98..efca6be42 100644 --- a/postfix/src/tls/tls_server.c +++ b/postfix/src/tls/tls_server.c @@ -6,17 +6,17 @@ /* SYNOPSIS /* #include /* -/* 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 @@ -52,11 +52,12 @@ /* 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. @@ -64,10 +65,10 @@ /* 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. */ @@ -122,15 +126,12 @@ /* 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); diff --git a/postfix/src/tls/tls_session.c b/postfix/src/tls/tls_session.c index 864bc4627..8fc11cf26 100644 --- a/postfix/src/tls/tls_session.c +++ b/postfix/src/tls/tls_session.c @@ -7,11 +7,11 @@ /* #include /* /* 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; diff --git a/postfix/src/tls/tls_stream.c b/postfix/src/tls/tls_stream.c index 19531407e..ca73a1136 100644 --- a/postfix/src/tls/tls_stream.c +++ b/postfix/src/tls/tls_stream.c @@ -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, diff --git a/postfix/src/tls/tls_verify.c b/postfix/src/tls/tls_verify.c index 2c9edd008..0c9075061 100644 --- a/postfix/src/tls/tls_verify.c +++ b/postfix/src/tls/tls_verify.c @@ -7,26 +7,47 @@ /* #define TLS_INTERNAL /* #include /* -/* 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 @@ -60,14 +81,25 @@ /* 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 @@ -87,11 +119,15 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Victor Duchovni +/* Morgan Stanley /*--*/ /* System library. */ #include +#include #ifdef USE_TLS #include @@ -100,93 +136,132 @@ #include #include +#include /* TLS library. */ #define TLS_INTERNAL #include +/* 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 diff --git a/postfix/src/tlsmgr/tlsmgr.c b/postfix/src/tlsmgr/tlsmgr.c index 39843e6eb..acf2fa959 100644 --- a/postfix/src/tlsmgr/tlsmgr.c +++ b/postfix/src/tlsmgr/tlsmgr.c @@ -225,7 +225,6 @@ * 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, diff --git a/postfix/src/trivial-rewrite/trivial-rewrite.c b/postfix/src/trivial-rewrite/trivial-rewrite.c index 5ce2ca8b3..fed4cfb38 100644 --- a/postfix/src/trivial-rewrite/trivial-rewrite.c +++ b/postfix/src/trivial-rewrite/trivial-rewrite.c @@ -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, diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index 18a3716be..4747d33e7 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -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 */ diff --git a/postfix/src/util/dict_cdb.c b/postfix/src/util/dict_cdb.c index c44e3d643..05e6743f9 100644 --- a/postfix/src/util/dict_cdb.c +++ b/postfix/src/util/dict_cdb.c @@ -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); diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index 233039c08..3e0beb7d6 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -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); diff --git a/postfix/src/util/inet_proto.c b/postfix/src/util/inet_proto.c index 06e2c43b7..c0ad50675 100644 --- a/postfix/src/util/inet_proto.c +++ b/postfix/src/util/inet_proto.c @@ -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, diff --git a/postfix/src/verify/verify.c b/postfix/src/verify/verify.c index ac7acd00b..bf1680cc2 100644 --- a/postfix/src/verify/verify.c +++ b/postfix/src/verify/verify.c @@ -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, diff --git a/postfix/src/virtual/virtual.c b/postfix/src/virtual/virtual.c index 7d6e1b8e8..88d969ca5 100644 --- a/postfix/src/virtual/virtual.c +++ b/postfix/src/virtual/virtual.c @@ -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, diff --git a/postfix/src/xsasl/xsasl_client.c b/postfix/src/xsasl/xsasl_client.c index 0e6267c7c..d45e28dc1 100644 --- a/postfix/src/xsasl/xsasl_client.c +++ b/postfix/src/xsasl/xsasl_client.c @@ -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++) diff --git a/postfix/src/xsasl/xsasl_cyrus_security.c b/postfix/src/xsasl/xsasl_cyrus_security.c index c4c6d44ec..617ff2fd9 100644 --- a/postfix/src/xsasl/xsasl_cyrus_security.c +++ b/postfix/src/xsasl/xsasl_cyrus_security.c @@ -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, diff --git a/postfix/src/xsasl/xsasl_dovecot_server.c b/postfix/src/xsasl/xsasl_dovecot_server.c index 2e382f24a..36bed9e7d 100644 --- a/postfix/src/xsasl/xsasl_dovecot_server.c +++ b/postfix/src/xsasl/xsasl_dovecot_server.c @@ -101,7 +101,7 @@ /* * 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, diff --git a/postfix/src/xsasl/xsasl_server.c b/postfix/src/xsasl/xsasl_server.c index 23531cd4a..28204f7bb 100644 --- a/postfix/src/xsasl/xsasl_server.c +++ b/postfix/src/xsasl/xsasl_server.c @@ -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++)