]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.6-20200720
authorWietse Venema <wietse@porcupine.org>
Mon, 20 Jul 2020 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 20 Jul 2020 23:06:56 +0000 (21:06 -0200)
60 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/COMPATIBILITY_README
postfix/README_FILES/TLS_README
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/conf/main.cf
postfix/html/COMPATIBILITY_README.html
postfix/html/TLS_README.html
postfix/html/lmtp.8.html
postfix/html/mailq.1.html
postfix/html/makedefs.1.html
postfix/html/newaliases.1.html
postfix/html/postconf.5.html
postfix/html/posttls-finger.1.html
postfix/html/sendmail.1.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/man/man1/posttls-finger.1
postfix/man/man1/sendmail.1
postfix/man/man5/postconf.5
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/proto/COMPATIBILITY_README.html
postfix/proto/TLS_README.html
postfix/proto/postconf.proto
postfix/src/global/mail_params.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/posttls-finger/posttls-finger.c
postfix/src/sendmail/sendmail.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_tls_policy.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpstone/smtp-sink.c
postfix/src/tls/Makefile.in
postfix/src/tls/tls.h
postfix/src/tls/tls_certkey.c
postfix/src/tls/tls_client.c
postfix/src/tls/tls_dane.c
postfix/src/tls/tls_dh.c
postfix/src/tls/tls_fprint.c
postfix/src/tls/tls_misc.c
postfix/src/tls/tls_proxy.h
postfix/src/tls/tls_proxy_client_print.c
postfix/src/tls/tls_proxy_client_scan.c
postfix/src/tls/tls_proxy_context_print.c
postfix/src/tls/tls_proxy_context_scan.c
postfix/src/tls/tls_rsa.c
postfix/src/tls/tls_scache.c
postfix/src/tls/tls_server.c
postfix/src/tls/tls_verify.c
postfix/src/tlsproxy/tlsproxy.c
postfix/src/util/dict.h
postfix/src/util/hex_code.c
postfix/src/util/hex_code.h
postfix/src/util/mymalloc.c
postfix/src/util/mymalloc.h

index 48b655e40d0af551a9feb7515973e87b9c1e3c38..3f054f2ed17e735b3698c8e6905a67e5455e746e 100644 (file)
 -TDICT_THASH
 -TDICT_UNION
 -TDICT_UNIX
+-TDICT_UTF8_BACKUP
 -TDICT_WRAPPER
 -TDNS_FIXED
 -TDNS_REPLY
 -TEC_KEY
 -TEDIT_FILE
 -TEVENT_MASK
+-TEVP_MD_CTX
 -TEVP_PKEY
 -TEXPAND_ATTR
 -TFILE
 -Tcipher_probe_t
 -Td2i_X509_t
 -Tdane_digest
+-Tdane_mtype
 -Tfilter_ctx
 -Tgeneral_name_stack_t
 -Tiana_digest
index 43dd50fc91a1751789583f94311b5c99dfa458ec..414a33065c72c72715ccd258725d392aa654ba81 100644 (file)
@@ -24903,19 +24903,108 @@ Apologies for any names omitted.
 20200626
 
        Typo: in postconf(5) documentation, AAAAA should be AAAA.
-       Christian Franke.  File: proto/postconf.proto.
+       Christian Franke. File: proto/postconf.proto.
 
        Bugfix (introduced: Postfix 2.11): The Postfix smtp(8)
        client did not send the right SNI name when the TLSA base
        domain was a secure CNAME expansion of the MX hostname (or
-       non-MX nexthop domain). Domains with CNAME expanded MX
-       hosts are not conformant with RFC5321, and so are rare.
-       Even more rare are MX hosts with TLSA records for their
-       CNAME expansion. For this to matter, the remote SMTP server
-       would also have to select its certificate based on the SNI
-       name in such a way that the original MX host would yield a
-       different certificate. Among the ~2 million hosts in the
-       DANE survey, none meet the conditions for returning a
-       different certificate for the expanded CNAME. Therefore,
-       sending the correct SNI name should not break existing mail
-       flows. Fixed by Viktor Dukhovni. File: src/tls/tls_client.c.
+       non-MX nexthop domain). Domains with CNAME expanded MX hosts
+       are not conformant with RFC5321, and so are rare. Even more
+       rare are MX hosts with TLSA records for their CNAME expansion.
+       For this to matter, the remote SMTP server would also have
+       to select its certificate based on the SNI name in such a
+       way that the original MX host would yield a different
+       certificate. Among the ~2 million hosts in the DANE survey,
+       none meet the conditions for returning a different certificate
+       for the expanded CNAME. Therefore, sending the correct SNI
+       name should not break existing mail flows. Fixed by Viktor
+       Dukhovni. File: src/tls/tls_client.c.
+
+20200705
+
+       Cleanup: OpenSSL-1.1.1 is the minimum supported version.
+       This is an LTS (long-term support) version that will reach
+       the end of life by 2023-09-11. This removes support for
+       export ciphers.
+
+       This also changes the Postfix default fingerprint digest
+       from MD5 to SHA256, but only when the compatibility_level
+       is set to '3' or higher.
+
+       Code by Viktor Dukhovni. Files: global/mail_params.c,
+       global/mail_params.h, posttls-finger/posttls-finger.c,
+       proto/COMPATIBILITY_README.html, proto/TLS_README.html,
+       proto/postconf.proto, smtp/smtp.c, smtp/smtp_tls_policy.c,
+       smtpd/smtpd.c, smtpd/smtpd_check.c, tls/Makefile.in,
+       tls/tls.h, tls/tls_certkey.c, tls/tls_client.c, tls/tls_dane.c,
+       tls/tls_dh.c, tls/tls_misc.c, tls/tls_rsa.c, tls/tls_server.c,
+       tls/tls_verify.c.
+
+20200710
+
+       Security: added a section to the sendmail(1) manpage for
+       security researchers and application developers, with an
+       example of using '--' to disable command option processing
+       for user-specified data. File sendmail/sendmail.c.
+
+       Error reporting: added '--' to a postalias command line to
+       make an obsecure error message less confusing. File
+       sendmail/sendmail.c.
+
+       Conversion from Postfix built-in DANE support to OpenSSL
+       DANE support. Code by Viktor Dukhovni. Files:
+       posttls-finger/posttls-finger.c, proto/postconf.proto,
+       smtp/smtp.c, smtp/smtp_proto.c, smtp/smtp_tls_policy.c,
+       tls/Makefile.in, tlsproxy/tlsproxy.c, tls/tls_client.c,
+       tls/tls_dane.c, tls/tls_fprint.c, tls/tls.h, tls/tls_misc.c,
+       tls/tls_proxy_client_print.c, tls/tls_proxy_client_scan.c,
+       tls/tls_proxy_context_print.c, tls/tls_proxy_context_scan.c,
+       tls/tls_proxy.h, tls/tls_verify.c, util/hex_code.c.
+
+       Bugfix (introduced: Postfix 3.0): minor memory leaks in the
+       Postfix TLS library, found during tests. File: tls/tls_misc.c.
+
+20200712
+
+       Cleanup: non-TLS builds were failing. File: util/tls_misc.c.
+
+       Bugfix (introduced: Postfix 3.0): 4kbyte per session memory
+       leak in the Postfix TLS library, found during tests. File:
+       tls/tls_misc.c.
+
+20200718
+
+       Cleanup TLS library: coding style, additional error message,
+       additional handling of internationalized domain name, and
+       dropping an unused variable.  Files: tls.h, tls_dane.c,
+       tls_proxy_client_scan.c, tls_client.c.
+
+       Noise suppression: shut up compilers that warn about
+       sizeof("text"). File: smtpstone/smtp-sink.c.
+
+20200719
+
+       Cleanup old API: mymemdup() should return "void *", the
+       same value type as its main argument, and the same result
+       type as mymalloc(). In a future update we can remove all
+       the noisy but unnecessary casts of their result values to
+       character pointer. Files: util/mymalloc.c, util/mymalloc.h.
+
+       Cleanup: don't split the sendmail -oA option value on comma
+       or whitespace, before passing the value to the postalias
+       command line. This results in unexpected behavior. File:
+       sendmail/sendmail.c.
+
+       Documentation: updated the manpage of the unprivileged(!)
+       sendmail(1) command with instructions to avoid privilege
+       esclation attacks in naive programs that run Postfix programs
+       with user-specified arguments. File: sendmail/sendmail.c.
+
+20200720
+
+       Bugfix (introduced: postfix 3.4): nullpointer dereference
+       in debug logging when tlsproxy is unavailable.  File:
+       posttls-finger/posttls-finger.c.
+
+       Final cleanups of the peername matching code.  File:
+       tls/tls_client.c.
index 20674ff6c82c04aeccae91e40e4aca49272d2ae8..9a274a09a3d541b8a3d6ab96b54d69ad730fa964 100644 (file)
@@ -42,6 +42,12 @@ The following messages may be logged:
 
   * Using backwards-compatible default setting smtputf8_enable=no
 
+  * Using backwards-compatible default setting smtpd_tls_fingerprint_digest=md5
+
+  * Using backwards-compatible default setting smtp_tls_fingerprint_digest=md5
+
+  * Using backwards-compatible default setting lmtp_tls_fingerprint_digest=md5
+
 If such a message is logged in the context of a legitimate request, the system
 administrator should make the backwards-compatible setting permanent in main.cf
 or master.cf, as detailed in the sections that follow.
@@ -210,7 +216,7 @@ domain names.
 
 U\bUs\bsi\bin\bng\bg b\bba\bac\bck\bkw\bwa\bar\brd\bds\bs-\b-c\bco\bom\bmp\bpa\bat\bti\bib\bbl\ble\be d\bde\bef\bfa\bau\bul\blt\bt s\bse\bet\btt\bti\bin\bng\bg s\bsm\bmt\btp\bpu\but\btf\bf8\b8_\b_e\ben\bna\bab\bbl\ble\be=\b=n\bno\bo
 
-The smtputf8_enable default value has changed from "no" to "yes. With the new
+The smtputf8_enable default value has changed from "no" to "yes". With the new
 "yes" setting, the Postfix SMTP server rejects non-ASCII addresses from clients
 that don't request SMTPUTF8 support, after Postfix is updated from an older
 version. The backwards-compatibility safety net is designed to prevent such
@@ -236,6 +242,70 @@ setting "smtputf8_enable = no" permanent in main.cf:
     # p\bpo\bos\bst\btc\bco\bon\bnf\bf s\bsm\bmt\btp\bpu\but\btf\bf8\b8_\b_e\ben\bna\bab\bbl\ble\be=\b=n\bno\bo
     # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
 
+U\bUs\bsi\bin\bng\bg b\bba\bac\bck\bkw\bwa\bar\brd\bds\bs-\b-c\bco\bom\bmp\bpa\bat\bti\bib\bbl\ble\be d\bde\bef\bfa\bau\bul\blt\bt s\bse\bet\btt\bti\bin\bng\bg s\bsm\bmt\btp\bpd\bd_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_d\bdi\big\bge\bes\bst\bt=\b=m\bmd\bd5\b5
+
+The smtpd_tls_fingerprint_digest default value has changed from "md5" to
+"sha256". With the new "sha256" setting, the Postfix SMTP server avoids using
+the deprecated "md5" algorithm and computes a more secure digest of the client
+certificate.
+
+If you're using the default "md5" setting, or even an explicit "sha1" (also
+deprecated) setting, you should consider switching to "sha256". This will
+require updating any associated lookup table keys with the "sha256" digests of
+the expected client certificate or public key.
+
+As long as the smtpd_tls_fingerprint_digest parameter is left at its implicit
+default value, and the compatibility_level setting is less than 3, Postfix logs
+a warning each time a client certificate or public key fingerprint is
+(potentially) used for access control:
+
+    postfix/smtpd[27560]: using backwards-compatible default setting
+        smtpd_tls_fingerprint_digest=md5 to compute certificate fingerprints
+
+Since any client certificate fingerprints are passed in policy service lookups,
+and Postfix doesn't know whether the fingerprint will be used, the warning may
+also be logged when policy lookups are performed for connections that used a
+client certificate, even if the policy service does not in fact examine the
+client certificate. To reduce the noise somewhat, such warnings are issued at
+most once per smtpd(8) process instance.
+
+If you prefer to stick with "md5", you can suppress the warnings by making that
+setting explicit. After addressing any other compatibility warnings, you can
+update your compatibility level.
+
+    # p\bpo\bos\bst\btc\bco\bon\bnf\bf s\bsm\bmt\btp\bpd\bd_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_d\bdi\big\bge\bes\bst\bt=\b=m\bmd\bd5\b5
+    # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
+
+U\bUs\bsi\bin\bng\bg b\bba\bac\bck\bkw\bwa\bar\brd\bds\bs-\b-c\bco\bom\bmp\bpa\bat\bti\bib\bbl\ble\be d\bde\bef\bfa\bau\bul\blt\bt s\bse\bet\btt\bti\bin\bng\bg s\bsm\bmt\btp\bp_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_d\bdi\big\bge\bes\bst\bt=\b=m\bmd\bd5\b5
+
+The smtp_tls_fingerprint_digest and lmtp_tls_fingerprint_digest default values
+have changed from "md5" to "sha256". With the new "sha256" setting, the Postfix
+SMTP and LMTP client avoids using the deprecated "md5" algorithm and computes a
+more secure digest of the server certificate.
+
+If you're using the default "md5" setting, or even an explicit "sha1" (also
+deprecated) setting, you should consider switching to "sha256". This will
+require updating any "fingerprint" security level policies in the TLS policy
+table to specify matching "sha256" digests of the expected server certificates
+or public keys.
+
+As long as the smtp_tls_fingerprint_digest (or LMTP equivalent) parameter is
+left at its implicit default value, and the compatibility_level setting is less
+than 3, Postfix logs a warning each time the "fingerprint" security level is
+used to specify matching "md5" digests of trusted server certificates or public
+keys:
+
+    postfix/smtp[27560]: using backwards-compatible default setting
+        smtp_tls_fingerprint_digest=md5 to compute certificate fingerprints
+
+If you prefer to stick with "md5", you can suppress the warnings by making that
+setting explicit. After addressing any other compatibility warnings, you can
+update your compatibility level.
+
+    # p\bpo\bos\bst\btc\bco\bon\bnf\bf '\b's\bsm\bmt\btp\bp_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_d\bdi\big\bge\bes\bst\bt =\b= m\bmd\bd5\b5'\b' \\b\
+        '\b'l\blm\bmt\btp\bp_\b_t\btl\bls\bs_\b_f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt_\b_d\bdi\big\bge\bes\bst\bt =\b= m\bmd\bd5\b5'\b'
+    # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
+
 T\bTu\bur\brn\bni\bin\bng\bg o\bof\bff\bf t\bth\bhe\be b\bba\bac\bck\bkw\bwa\bar\brd\bds\bs-\b-c\bco\bom\bmp\bpa\bat\bti\bib\bbi\bil\bli\bit\bty\by s\bsa\baf\bfe\bet\bty\by n\bne\bet\bt
 
 Backwards compatibility is turned off by updating the compatibility_level
index 05105ead43ce3bde3a457e00b15a099adeed8324..57ebbea993de5f3df73b19283c03f37de6a230c1 100644 (file)
@@ -545,7 +545,12 @@ server access control:
 
 The digest algorithm used to compute 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.
+algorithm is s\bsh\bha\ba2\b25\b56\b6 with Postfix >= 3.6 and the c\bco\bom\bmp\bpa\bat\bti\bib\bbi\bil\bli\bit\bty\by_\b_l\ble\bev\bve\bel\bl set to 3 or
+higher. With Postfix <= 3.5, the default algorithm is m\bmd\bd5\b5. The best-practice
+algorithm is now s\bsh\bha\ba2\b25\b56\b6. Recent advances in hash function cryptanalysis have
+led to md5 and sha1 being deprecated in favor of sha256. However, as long as
+there are no known "second pre-image" attacks against the older algorithms,
+their use in this context, though not recommended, is still likely safe.
 
 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
@@ -596,26 +601,12 @@ command extracts the public key always in "PEM" format. We pipe the result to
 another OpenSSL command that converts the key to DER and then to the "dgst"
 command to compute the fingerprint.
 
-The actual command to transform the key to DER format depends on the version of
-OpenSSL used. With OpenSSL 1.0.0 and later, the "pkey" command supports all key
-types. With OpenSSL 0.9.8 and earlier, the key type is always RSA (nobody uses
-DSA, and EC keys are not fully supported by 0.9.8), so the "rsa" command is
-used.
+Example:
 
-    # OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
     $ openssl x509 -in cert.pem -noout -pubkey |
         openssl pkey -pubin -outform DER |
-        openssl dgst -sha1 -c
-    (stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-
-    # OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-    $ openssl x509 -in cert.pem -noout -pubkey |
-        openssl rsa -pubin -outform DER |
-        openssl dgst -md5 -c
-    (stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
-
-Note: Postfix 2.9.0-2.9.5 computed the public key fingerprint incorrectly. To
-use public-key fingerprints, upgrade to Postfix 2.9.6 or later.
+        openssl dgst -sha256 -c
+    (stdin)= 64:3f:1f:f6:e5:1e:d4:2a:...:8b:fc:09:1a:61:98:b5:bc:7c:60:58
 
 S\bSe\ber\brv\bve\ber\br-\b-s\bsi\bid\bde\be c\bci\bip\bph\bhe\ber\br c\bco\bon\bnt\btr\bro\bol\bls\bs
 
@@ -1130,6 +1121,14 @@ 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.
 
+The default algorithm is s\bsh\bha\ba2\b25\b56\b6 with Postfix >= 3.6 and the c\bco\bom\bmp\bpa\bat\bti\bib\bbi\bil\bli\bit\bty\by_\b_l\ble\bev\bve\bel\bl
+set to 3 or higher; with Postfix <= 3.5, the default algorithm is m\bmd\bd5\b5. The
+best-practice algorithm is now s\bsh\bha\ba2\b25\b56\b6. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of sha256.
+However, as long as there are no known "second pre-image" attacks against the
+older algorithms, their use in this context, though not recommended, is still
+likely safe.
+
 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
@@ -1139,22 +1138,22 @@ trusted just prior to the transition.
 
         relayhost = [mailhub.example.com]
         smtp_tls_security_level = fingerprint
-        smtp_tls_fingerprint_digest = md5
+        smtp_tls_fingerprint_digest = sha256
         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
+            51:e9:af:2e:1e:40:1f:de:64:...:30:35:2d:09:16:31:5a:eb:82:76
+            b6:b4:72:34:e2:59:cd:fb:c2:...:63:0d:4d:cc:2c:7d:84:de:e6:2f
 
 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
+        smtp_tls_fingerprint_digest = sha256
 
     /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
+            match=51:e9:af:2e:1e:40:1f:de:...:35:2d:09:16:31:5a:eb:82:76
+            match=b6:b4:72:34:e2:59:cd:fb:...:0d:4d:cc:2c:7d:84:de:e6:2f
 
 To extract the public key fingerprint from an X.509 certificate, you need to
 extract the public key from the certificate and compute the appropriate digest
@@ -1163,26 +1162,12 @@ command extracts the public key always in "PEM" format. We pipe the result to
 another OpenSSL command that converts the key to DER and then to the "dgst"
 command to compute the fingerprint.
 
-The actual command to transform the key to DER format depends on the version of
-OpenSSL used. With OpenSSL 1.0.0 and later, the "pkey" command supports all key
-types. With OpenSSL 0.9.8 and earlier, the key type is always RSA (nobody uses
-DSA, and EC keys are not fully supported by 0.9.8), so the "rsa" command is
-used.
+Example:
 
-    # OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
     $ openssl x509 -in cert.pem -noout -pubkey |
         openssl pkey -pubin -outform DER |
-        openssl dgst -sha1 -c
-    (stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-
-    # OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-    $ openssl x509 -in cert.pem -noout -pubkey |
-        openssl rsa -pubin -outform DER |
-        openssl dgst -md5 -c
-    (stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
-
-Note: Postfix 2.9.0-2.9.5 computed the public key fingerprint incorrectly. To
-use public-key fingerprints, upgrade to Postfix 2.9.6 or later.
+        openssl dgst -sha256 -c
+    (stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:...:09:1a:61:98:b5:bc:7c:60:58
 
 M\bMa\ban\bnd\bda\bat\bto\bor\bry\by s\bse\ber\brv\bve\ber\br c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be v\bve\ber\bri\bif\bfi\bic\bca\bat\bti\bio\bon\bn
 
@@ -1837,7 +1822,7 @@ Example:
     /etc/postfix/main.cf:
         smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
         # Postfix 2.5 and later
-        smtp_tls_fingerprint_digest = md5
+        smtp_tls_fingerprint_digest = sha256
     /etc/postfix/tls_policy:
         example.edu             none
         example.mil             may
@@ -1848,8 +1833,8 @@ Example:
         [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
+            match=b6:b4:72:34:e2:59:cd:fb:...:0d:4d:cc:2c:7d:84:de:e6:2f
+            match=51:e9:af:2e:1e:40:1f:de:...:35:2d:09:16:31:5a:eb:82:76
         # Postfix 2.6 and later
         example.info            may protocols=!SSLv2 ciphers=medium
     exclude=3DES
index 3fc80718ba699df95d02ab83fe029a9c7f454bdb..a6576c3b92a6c6643a6b47010ccd7a6fb6e5dcb3 100644 (file)
@@ -25,6 +25,20 @@ more recent Eclipse Public License 2.0. Recipients can choose to take
 the software under the license of their choice. Those who are more
 comfortable with the IPL can continue with that license.
 
+Incompatible change with snapshot 20200705
+==========================================
+
+The minimum OpenSSL version is 1.1.1, which will reach the end
+of life by 20203-09-11. 
+
+The default digest has changed from md5 to sha256 (Postfix 3.6 with
+compatibility_level >= 3). With a lower compatibility_level setting,
+Postfix defaults to using md5, and logs a warning when a Postfix
+configuration specifies no explicit digest type.
+
+Export-grade Diffie-Hellman key exchange is no longer supported,
+and the tlsproxy_tls_dh512_param_file parameter is ignored,
+
 Incompatible change with snapshot 20200531
 ==========================================
 
index 5f69e9fd2e2716a1f44eb0c837e05f12dd28c787..44c37dcec5b4cc756693bd022f553bdee785c5a7 100644 (file)
@@ -1,7 +1,10 @@
 Wish list:
 
-       Move the tls_dane_avail() and DANE-requested test into
-       tls_client_start().
+       Update makedefs and sys-defs.h for current Linux kernels and
+       *BSD releases.
+
+       When deleting a recipient with a milter, delete the recipient from
+       the duplicate filter, so that the recipient can be added back.
 
        DNS wrapper class, like XSASL, to support different stub
        resolvers without contaminating Postfix programs with the
index 9247ef7be94091a9438293858d34172989701a61..00a3506590618eaf29ce01ef510312129cbd3eb5 100644 (file)
@@ -27,7 +27,7 @@
 #
 # The level below is what should be used with new (not upgrade) installs.
 #
-compatibility_level = 2
+compatibility_level = 3
 
 # SOFT BOUNCE
 #
index d527e1981a3e27f902885a06e0d71ad4f4a0580f..30e9f2bcb3005f7e63a1584944464c2e4f1d10c2 100644 (file)
@@ -72,6 +72,15 @@ setting relay_domains=$mydestination </a> </p>
 <li> <p> <a href="#smtputf8_enable"> Using backwards-compatible
 default setting smtputf8_enable=no</a> </p>
 
+<li> <p> <a href="#smtpd_digest"> Using backwards-compatible
+default setting smtpd_tls_fingerprint_digest=md5</a> </p>
+
+<li> <p> <a href="#smtp_digest"> Using backwards-compatible
+default setting smtp_tls_fingerprint_digest=md5</a> </p>
+
+<li> <p> <a href="#smtp_digest"> Using backwards-compatible
+default setting lmtp_tls_fingerprint_digest=md5</a> </p>
+
 </ul>
 
 <p> If such a message is logged in the context of a legitimate
@@ -327,7 +336,7 @@ explicit list of domain names. </p>
 <h2> <a name="smtputf8_enable"> Using backwards-compatible default
 setting smtputf8_enable=no</a> </h2>
 
-<p> The <a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> default value has changed from "no" to "yes.
+<p> The <a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> default value has changed from "no" to "yes".
 With the new "yes" setting, the Postfix SMTP server rejects non-ASCII
 addresses from clients that don't request SMTPUTF8 support, after
 Postfix is updated from an older version. The backwards-compatibility
@@ -366,6 +375,92 @@ in <a href="postconf.5.html">main.cf</a>:
 </pre>
 </blockquote>
 
+<h2> <a name="smtpd_digest"> Using backwards-compatible
+default setting smtpd_tls_fingerprint_digest=md5</a> </h2>
+
+<p> The <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> default value has changed from
+"md5" to "sha256".  With the new "sha256" setting, the Postfix SMTP
+server avoids using the deprecated "md5" algorithm and computes a more
+secure digest of the client certificate.  </p>
+
+<p> If you're using the default "md5" setting, or even an explicit
+"sha1" (also deprecated) setting, you should consider switching to
+"sha256".  This will require updating any associated lookup table keys
+with the "sha256" digests of the expected client certificate or public
+key.  </p>
+
+<p> As long as the <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> parameter is left at its
+implicit default value, and the <a href="postconf.5.html#compatibility_level">compatibility_level</a> setting is less than
+3, Postfix logs a warning each time a client certificate or public key
+fingerprint is (potentially) used for access control: </p>
+
+<blockquote>
+<pre>
+postfix/smtpd[27560]: using backwards-compatible default setting
+    <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a>=md5 to compute certificate fingerprints
+</pre>
+</blockquote>
+
+<p> Since any client certificate fingerprints are passed in policy service
+lookups, and Postfix doesn't know whether the fingerprint will be used, the
+warning may also be logged when policy lookups are performed for connections
+that used a client certificate, even if the policy service does not in fact
+examine the client certificate.  To reduce the noise somewhat, such warnings
+are issued at most once per <a href="smtpd.8.html">smtpd(8)</a> process instance.  </p>
+
+<p> If you prefer to stick with "md5", you can suppress the warnings by
+making that setting explicit.  After addressing any other compatibility
+warnings, you can <a href="#turnoff">update</a> your compatibility level.
+</p>
+
+<blockquote>
+<pre>
+# <b>postconf <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a>=md5</b>
+# <b>postfix reload</b>
+</pre>
+</blockquote>
+
+<h2> <a name="smtp_digest"> Using backwards-compatible
+default setting smtp_tls_fingerprint_digest=md5</a> </h2>
+
+<p> The <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> and <a href="postconf.5.html#lmtp_tls_fingerprint_digest">lmtp_tls_fingerprint_digest</a>
+default values have changed from "md5" to "sha256".  With the new
+"sha256" setting, the Postfix SMTP and LMTP client avoids using the
+deprecated "md5" algorithm and computes a more secure digest of the
+server certificate.  </p>
+
+<p> If you're using the default "md5" setting, or even an explicit
+"sha1" (also deprecated) setting, you should consider switching to
+"sha256".  This will require updating any "fingerprint" security level
+policies in the TLS policy table to specify matching "sha256" digests of
+the expected server certificates or public keys.  </p>
+
+<p> As long as the <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> (or LMTP equivalent)
+parameter is left at its implicit default value, and the
+<a href="postconf.5.html#compatibility_level">compatibility_level</a> setting is less than 3, Postfix logs a warning each
+time the "fingerprint" security level is used to specify matching "md5"
+digests of trusted server certificates or public keys: </p>
+
+<blockquote>
+<pre>
+postfix/smtp[27560]: using backwards-compatible default setting
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a>=md5 to compute certificate fingerprints
+</pre>
+</blockquote>
+
+<p> If you prefer to stick with "md5", you can suppress the warnings by
+making that setting explicit.  After addressing any other compatibility
+warnings, you can <a href="#turnoff">update</a> your compatibility level.
+</p>
+
+<blockquote>
+<pre>
+# <b>postconf '<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5' \
+    '<a href="postconf.5.html#lmtp_tls_fingerprint_digest">lmtp_tls_fingerprint_digest</a> = md5' </b>
+# <b>postfix reload</b>
+</pre>
+</blockquote>
+
 <h2> <a name="turnoff">Turning off the backwards-compatibility safety net</a> </h2>
 
 <p> Backwards compatibility is turned off by updating the
index ed2dfe15f20ea8013c55484a511f7d82f6cf27ec..4af1be12ecbbc3b995c52b4e2ef3d3cf1bb45203 100644 (file)
@@ -783,8 +783,14 @@ table. </p> </dd>
 
 <p> The digest algorithm used to compute the client certificate
 fingerprints is specified with the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a>
-parameter.  The default is "md5", for compatibility with Postfix
-versions &lt; 2.5. </p>
+parameter. The default algorithm is <b>sha256</b> with Postfix &ge;
+3.6 and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher. With
+Postfix &le; 3.5, the default algorithm is <b>md5</b>.  The
+best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in
+favor of sha256.  However, as long as there are no known "second
+pre-image" attacks against the older algorithms, their use in this
+context, though not recommended, is still likely safe.  </p>
 
 <p> The <a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> feature must be used with caution,
 because it can result in too many access permissions.  Use this
@@ -847,30 +853,15 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> Example: </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
-(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
+    openssl dgst -sha256 -c
+(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:...:8b:fc:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
-<p> Note: Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
 
 <h3><a name="server_cipher">Server-side cipher controls</a> </h3>
 
@@ -1510,6 +1501,15 @@ match attributes can be employed. The ":" character is not used as a
 delimiter as it occurs between each pair of fingerprint (hexadecimal)
 digits. </p>
 
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher; with Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The
+best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in
+favor of sha256.  However, as long as there are no known "second
+pre-image" attacks against the older algorithms, their use in this
+context, though not recommended, is still likely safe.  </p>
+
 <p> Example: fingerprint TLS security with an internal mailhub.
 Two matching fingerprints are listed. The <a href="postconf.5.html#relayhost">relayhost</a> may be multiple
 physical hosts behind a load-balancer, each with its own private/public
@@ -1521,10 +1521,10 @@ another, and both keys are trusted just prior to the transition. </p>
 <pre>
     <a href="postconf.5.html#relayhost">relayhost</a> = [mailhub.example.com]
     <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = fingerprint
-    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = sha256
     <a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> =
-        3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
-        EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+        51:e9:af:2e:1e:40:1f:de:64:...:30:35:2d:09:16:31:5a:eb:82:76
+        b6:b4:72:34:e2:59:cd:fb:c2:...:63:0d:4d:cc:2c:7d:84:de:e6:2f
 </pre>
 </blockquote>
 
@@ -1534,15 +1534,15 @@ As in the example above, we show two matching fingerprints: </p>
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/tls_policy
-    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = sha256
 </pre>
 </blockquote>
 <blockquote>
 <pre>
 /etc/postfix/tls_policy:
     example.com fingerprint
-        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
-        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+        match=51:e9:af:2e:1e:40:1f:de:...:35:2d:09:16:31:5a:eb:82:76
+        match=b6:b4:72:34:e2:59:cd:fb:...:0d:4d:cc:2c:7d:84:de:e6:2f
 </pre>
 </blockquote>
 
@@ -1554,30 +1554,15 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> Example: </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
-(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
+    openssl dgst -sha256 -c
+(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:...:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
-<p> Note: Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
 
 <h4><a name="client_tls_verify"> Mandatory server certificate verification </a> </h4>
 
@@ -2400,7 +2385,7 @@ Example:
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/tls_policy
     # Postfix 2.5 and later
-    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = sha256
 /etc/postfix/tls_policy:
     example.edu             none
     example.mil             may
@@ -2411,8 +2396,8 @@ Example:
     [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
+        match=b6:b4:72:34:e2:59:cd:fb:...:0d:4d:cc:2c:7d:84:de:e6:2f
+        match=51:e9:af:2e:1e:40:1f:de:...:35:2d:09:16:31:5a:eb:82:76
     # Postfix 2.6 and later
     example.info            may protocols=!SSLv2 ciphers=medium exclude=3DES
 </pre>
index f79f4e04e00506b8d56d1143e7cfcce919881ee9..3c20579eff8e3299eb03eed9e34b4c540817d138 100644 (file)
@@ -567,7 +567,7 @@ SMTP(8)                                                                SMTP(8)
               for   the   "fingerprint"  TLS  security  level  (<b><a href="postconf.5.html#smtp_tls_security_level">smtp_tls_secu</a>-</b>
               <b><a href="postconf.5.html#smtp_tls_security_level">rity_level</a></b> = fingerprint).
 
-       <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> (md5)</b>
+       <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> (see 'postconf -d' output)</b>
               The message digest  algorithm  used  to  construct  remote  SMTP
               server certificate fingerprints.
 
@@ -826,12 +826,12 @@ SMTP(8)                                                                SMTP(8)
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The increment in verbose logging level when a next-hop  destina-
+              The increment in verbose logging level when a  nexthop  destina-
               tion,  remote client or server name or network address matches a
               pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of next-hop destination, remote client  or  server
+              Optional list of nexthop destination, remote  client  or  server
               name  or  network  address  patterns that, if matched, cause the
               verbose logging level to increase by  the  amount  specified  in
               $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
index 02f20fe8913d3963b9dd36d8887fe0eb3d9987d6..a83307fc69fdf11893827d2ae3fc1fdf9fe54fa5 100644 (file)
@@ -45,24 +45,27 @@ SENDMAIL(1)                                                        SENDMAIL(1)
                      ery attempt will be made until  the  mail  is  taken  off
                      hold.
 
-              This   mode   of  operation  is  implemented  by  executing  the
+              <b>#</b>      The  message  is  forced  to expire. See the <a href="postsuper.1.html"><b>postsuper</b>(1)</a>
+                     options <b>-e</b> or <b>-f</b>.
+
+              This  mode  of  operation  is  implemented  by   executing   the
               <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
 
        <b>newaliases</b>
-              Initialize the alias database.  If no input  file  is  specified
-              (with  the  <b>-oA</b>  option,  see  below), the program processes the
-              file(s) specified with the <b><a href="postconf.5.html#alias_database">alias_database</a></b> configuration  parame-
-              ter.   If  no alias database type is specified, the program uses
-              the type specified with the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b>  configuration
+              Initialize  the  alias  database.  If no input file is specified
+              (with the <b>-oA</b> option, see  below),  the  program  processes  the
+              file(s)  specified with the <b><a href="postconf.5.html#alias_database">alias_database</a></b> configuration parame-
+              ter.  If no alias database type is specified, the  program  uses
+              the  type specified with the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration
               parameter.  This mode of operation is implemented by running the
               <a href="postalias.1.html"><b>postalias</b>(1)</a> command.
 
               Note: it may take a minute or so before an alias database update
-              becomes  visible.  Use the "<b>postfix reload</b>" command to eliminate
+              becomes visible. Use the "<b>postfix reload</b>" command  to  eliminate
               this delay.
 
-       These and other features can be selected by specifying the  appropriate
-       combination  of  command-line  options. Some features are controlled by
+       These  and other features can be selected by specifying the appropriate
+       combination of command-line options. Some features  are  controlled  by
        parameters in the <a href="postconf.5.html"><b>main.cf</b></a> configuration file.
 
        The following options are recognized:
@@ -70,13 +73,13 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-Am</b> (ignored)
 
        <b>-Ac</b> (ignored)
-              Postfix sendmail uses the same configuration file regardless  of
+              Postfix  sendmail uses the same configuration file regardless of
               whether or not a message is an initial submission.
 
        <b>-B</b> <i>body</i><b>_</b><i>type</i>
               The message body MIME type: <b>7BIT</b> or <b>8BITMIME</b>.
 
-       <b>-bd</b>    Go  into  daemon  mode. This mode of operation is implemented by
+       <b>-bd</b>    Go into daemon mode. This mode of operation  is  implemented  by
               executing the "<b>postfix start</b>" command.
 
        <b>-bh</b> (ignored)
@@ -86,8 +89,8 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-bi</b>    Initialize alias database. See the <b>newaliases</b> command above.
 
-       <b>-bl</b>    Go into daemon mode. To accept only local  connections  as  with
-              Sendmail's  <b>-bl</b>  option, specify "<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = loopback</b>" in
+       <b>-bl</b>    Go  into  daemon  mode. To accept only local connections as with
+              Sendmail's <b>-bl</b> option, specify "<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> =  loopback</b>"  in
               the Postfix <a href="postconf.5.html"><b>main.cf</b></a> configuration file.
 
        <b>-bm</b>    Read mail from standard input and arrange for delivery.  This is
@@ -95,17 +98,17 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-bp</b>    List the mail queue. See the <b>mailq</b> command above.
 
-       <b>-bs</b>    Stand-alone  SMTP  server mode. Read SMTP commands from standard
-              input, and write responses to standard output.   In  stand-alone
-              SMTP  server  mode,  mail relaying and other access controls are
-              disabled by default. To enable them,  run  the  process  as  the
+       <b>-bs</b>    Stand-alone SMTP server mode. Read SMTP commands  from  standard
+              input,  and  write responses to standard output.  In stand-alone
+              SMTP server mode, mail relaying and other  access  controls  are
+              disabled  by  default.  To  enable  them, run the process as the
               <b><a href="postconf.5.html#mail_owner">mail_owner</a></b> user.
 
-              This  mode  of  operation is implemented by running the <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
+              This mode of operation is implemented by  running  the  <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
               daemon.
 
-       <b>-bv</b>    Do not collect or deliver a  message.  Instead,  send  an  email
-              report  after  verifying each recipient address.  This is useful
+       <b>-bv</b>    Do  not  collect  or  deliver  a message. Instead, send an email
+              report after verifying each recipient address.  This  is  useful
               for testing address rewriting and routing configurations.
 
               This feature is available in Postfix version 2.1 and later.
@@ -113,58 +116,58 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-C</b> <i>config</i><b>_</b><i>file</i>
 
        <b>-C</b> <i>config</i><b>_</b><i>dir</i>
-              The path name of the Postfix <a href="postconf.5.html"><b>main.cf</b></a>  file,  or  of  its  parent
-              directory.  This  information  is  ignored with Postfix versions
+              The  path  name  of  the  Postfix <a href="postconf.5.html"><b>main.cf</b></a> file, or of its parent
+              directory. This information is  ignored  with  Postfix  versions
               before 2.3.
 
               With Postfix version 3.2 and later, a non-default directory must
-              be  authorized  in  the default <a href="postconf.5.html"><b>main.cf</b></a> file, through the alter-
+              be authorized in the default <a href="postconf.5.html"><b>main.cf</b></a> file,  through  the  alter-
               nate_config_directories  or  <a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a>  parame-
               ters.
 
-              With  all Postfix versions, you can specify a directory pathname
-              with the MAIL_CONFIG environment variable to override the  loca-
+              With all Postfix versions, you can specify a directory  pathname
+              with  the MAIL_CONFIG environment variable to override the loca-
               tion of configuration files.
 
        <b>-F</b> <i>full</i><b>_</b><i>name</i>
-              Set  the  sender  full name. This overrides the NAME environment
+              Set the sender full name. This overrides  the  NAME  environment
               variable, and is used only with messages that have no <b>From:</b> mes-
               sage header.
 
        <b>-f</b> <i>sender</i>
-              Set  the  envelope  sender  address.  This  is the address where
+              Set the envelope sender  address.  This  is  the  address  where
               delivery problems are sent to. With Postfix versions before 2.1,
-              the   <b>Errors-To:</b>  message  header  overrides  the  error  return
+              the  <b>Errors-To:</b>  message  header  overrides  the  error   return
               address.
 
-       <b>-G</b>     Gateway (relay) submission, as opposed to initial  user  submis-
-              sion.   Either do not rewrite addresses at all, or update incom-
-              plete addresses  with  the  domain  information  specified  with
+       <b>-G</b>     Gateway  (relay)  submission, as opposed to initial user submis-
+              sion.  Either do not rewrite addresses at all, or update  incom-
+              plete  addresses  with  the  domain  information  specified with
               <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a></b>.
 
               This option is ignored before Postfix version 2.3.
 
        <b>-h</b> <i>hop</i><b>_</b><i>count</i> (ignored)
-              Hop  count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configuration parameter
+              Hop count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configuration  parameter
               instead.
 
        <b>-I</b>     Initialize alias database. See the <b>newaliases</b> command above.
 
-       <b>-i</b>     When reading a message from standard input, don't treat  a  line
+       <b>-i</b>     When  reading  a message from standard input, don't treat a line
               with only a <b>.</b> character as the end of input.
 
        <b>-L</b> <i>label</i> (ignored)
-              The  logging  label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b> configuration parameter
+              The logging label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b>  configuration  parameter
               instead.
 
        <b>-m</b> (ignored)
               Backwards compatibility.
 
        <b>-N</b> <i>dsn</i> (default: 'delay, failure')
-              Delivery  status  notification   control.   Specify   either   a
+              Delivery   status   notification   control.   Specify  either  a
               comma-separated list with one or more of <b>failure</b> (send notifica-
-              tion when delivery fails), <b>delay</b> (send notification when  deliv-
-              ery  is delayed), or <b>success</b> (send notification when the message
+              tion  when delivery fails), <b>delay</b> (send notification when deliv-
+              ery is delayed), or <b>success</b> (send notification when the  message
               is delivered); or specify <b>never</b> (don't send any notifications at
               all).
 
@@ -174,50 +177,50 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Backwards compatibility.
 
        <b>-oA</b><i>alias</i><b>_</b><i>database</i>
-              Non-default  alias  database. Specify <i>pathname</i> or <i>type</i>:<i>pathname</i>.
+              Non-default alias database. Specify <i>pathname</i>  or  <i>type</i>:<i>pathname</i>.
               See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
 
        <b>-O</b> <i>option=value</i> (ignored)
-              Set the named <i>option</i> to <i>value</i>. Use the equivalent  configuration
+              Set  the named <i>option</i> to <i>value</i>. Use the equivalent configuration
               parameter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
        <b>-o7</b> (ignored)
 
        <b>-o8</b> (ignored)
-              To  send 8-bit or binary content, use an appropriate MIME encap-
+              To send 8-bit or binary content, use an appropriate MIME  encap-
               sulation and specify the appropriate <b>-B</b> command-line option.
 
-       <b>-oi</b>    When reading a message from standard input, don't treat  a  line
+       <b>-oi</b>    When  reading  a message from standard input, don't treat a line
               with only a <b>.</b> character as the end of input.
 
        <b>-om</b> (ignored)
               The sender is never eliminated from alias etc. expansions.
 
        <b>-o</b> <i>x value</i> (ignored)
-              Set  option <i>x</i> to <i>value</i>. Use the equivalent configuration parame-
+              Set option <i>x</i> to <i>value</i>. Use the equivalent configuration  parame-
               ter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
        <b>-r</b> <i>sender</i>
-              Set the envelope sender  address.  This  is  the  address  where
+              Set  the  envelope  sender  address.  This  is the address where
               delivery problems are sent to. With Postfix versions before 2.1,
-              the  <b>Errors-To:</b>  message  header  overrides  the  error   return
+              the   <b>Errors-To:</b>  message  header  overrides  the  error  return
               address.
 
        <b>-R</b> <i>return</i>
-              Delivery  status notification control.  Specify "hdrs" to return
-              only the header when a message bounces, "full" to return a  full
+              Delivery status notification control.  Specify "hdrs" to  return
+              only  the header when a message bounces, "full" to return a full
               copy (the default behavior).
 
               The <b>-R</b> option specifies an upper bound; Postfix will return only
-              the header, when a full copy would exceed the  <a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a>
+              the  header, when a full copy would exceed the <a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a>
               setting.
 
               This option is ignored before Postfix version 2.10.
 
-       <b>-q</b>     Attempt  to deliver all queued mail. This is implemented by exe-
+       <b>-q</b>     Attempt to deliver all queued mail. This is implemented by  exe-
               cuting the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
 
-              Warning: flushing undeliverable mail frequently will  result  in
+              Warning:  flushing  undeliverable mail frequently will result in
               poor delivery performance of all other mail.
 
        <b>-q</b><i>interval</i> (ignored)
@@ -226,21 +229,21 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-qI</b><i>queueid</i>
               Schedule immediate delivery of mail with the specified queue ID.
-              This  option  is  implemented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> com-
+              This option is implemented by executing  the  <a href="postqueue.1.html"><b>postqueue</b>(1)</a>  com-
               mand, and is available with Postfix version 2.4 and later.
 
        <b>-qR</b><i>site</i>
-              Schedule immediate delivery of all mail that is queued  for  the
-              named  <i>site</i>. This option accepts only <i>site</i> names that are eligi-
-              ble for the "fast flush" service, and is implemented by  execut-
+              Schedule  immediate  delivery of all mail that is queued for the
+              named <i>site</i>. This option accepts only <i>site</i> names that are  eligi-
+              ble  for the "fast flush" service, and is implemented by execut-
               ing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.  See <a href="flush.8.html"><b>flush</b>(8)</a> for more information
               about the "fast flush" service.
 
        <b>-qS</b><i>site</i>
-              This command is not implemented. Use the  slower  "<b>sendmail  -q</b>"
+              This  command  is  not implemented. Use the slower "<b>sendmail -q</b>"
               command instead.
 
-       <b>-t</b>     Extract  recipients from message headers. These are added to any
+       <b>-t</b>     Extract recipients from message headers. These are added to  any
               recipients specified on the command line.
 
               With Postfix versions prior to 2.1, this option requires that no
@@ -256,23 +259,23 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               This feature is available in Postfix 2.3 and later.
 
        <b>-XV</b> (Postfix 2.2 and earlier: <b>-V</b>)
-              Variable Envelope Return Path. Given an envelope sender  address
-              of  the  form  <i>owner-listname</i>@<i>origin</i>, each recipient <i>user</i>@<i>domain</i>
+              Variable  Envelope Return Path. Given an envelope sender address
+              of the form <i>owner-listname</i>@<i>origin</i>,  each  recipient  <i>user</i>@<i>domain</i>
               receives mail with a personalized envelope sender address.
 
-              By  default,  the  personalized  envelope  sender   address   is
-              <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>.  The  default <b>+</b> and <b>=</b> charac-
-              ters are configurable with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b>  configu-
+              By   default,   the  personalized  envelope  sender  address  is
+              <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The default <b>+</b> and  <b>=</b>  charac-
+              ters  are configurable with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configu-
               ration parameter.
 
        <b>-XV</b><i>xy</i> (Postfix 2.2 and earlier: <b>-V</b><i>xy</i>)
-              As  <b>-XV</b>,  but  uses  <i>x</i>  and  <i>y</i> as the VERP delimiter characters,
+              As <b>-XV</b>, but uses <i>x</i> and  <i>y</i>  as  the  VERP  delimiter  characters,
               instead of the characters specified with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delim</a>-</b>
               <b><a href="postconf.5.html#default_verp_delimiters">iters</a></b> configuration parameter.
 
        <b>-v</b>     Send an email report of the first delivery attempt (Postfix ver-
-              sions 2.1 and later). Mail delivery always happens in the  back-
-              ground.  When multiple <b>-v</b> options are given, enable verbose log-
+              sions  2.1 and later). Mail delivery always happens in the back-
+              ground. When multiple <b>-v</b> options are given, enable verbose  log-
               ging for debugging purposes.
 
        <b>-X</b> <i>log</i><b>_</b><i>file</i> (ignored)
@@ -280,12 +283,42 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               configuration parameters instead.
 
 <b>SECURITY</b>
-       By design, this program is not set-user (or group) id. However, it must
-       handle data from untrusted, possibly remote, users.   Thus,  the  usual
-       precautions need to be taken against malicious inputs.
+       By design, this program is not set-user (or group) id.  It is  prepared
+       to handle message content from untrusted, possibly remote, users.
+
+       However,  like  most  Postfix programs, this program does not enforce a
+       security policy on its command-line arguments.  Instead, it  relies  on
+       the  UNIX system to enforce access policies based on the effective user
+       and group IDs of the process. Concretely, this means that running Post-
+       fix  commands as root (from sudo or equivalent) on behalf of a non-root
+       user is likely to create privilege escalation opportunities.
+
+       If an application runs any Postfix programs on behalf of users that  do
+       not have normal shell access to Postfix commands, then that application
+       MUST restrict user-specified command-line arguments to avoid  privilege
+       escalation.
+
+       <b>o</b>      Filter  all  command-line  arguments, for example arguments that
+              contain a pathname or that specify  a  database  access  method.
+              These  pathname  checks  must reject user-controlled symlinks or
+              hardlinks to sensitive files, and must not be vulnerable to TOC-
+              TOU race attacks.
+
+       <b>o</b>      Disable  command  options  processing  for all command arguments
+              that contain user-specified data. For example, the Postfix <a href="sendmail.1.html"><b>send-</b></a>
+              <a href="sendmail.1.html"><b>mail</b>(1)</a> command line MUST be structured as follows:
+
+                  <b>/path/to/sendmail</b> <i>system-arguments</i> <b>--</b> <i>user-arguments</i>
+
+              Here,  the  "<b>--</b>"  disables  command  option  processing  for all
+              <i>user-arguments</i> that follow.
+
+              Without the "<b>--</b>", a malicious user could  enable  Postfix  <a href="sendmail.1.html"><b>send-</b></a>
+              <a href="sendmail.1.html"><b>mail</b>(1)</a>  command  options,  by  specifying an email address that
+              starts with "<b>-</b>".
 
 <b>DIAGNOSTICS</b>
-       Problems  are  logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>, and to the standard
+       Problems are logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>, and to  the  standard
        error stream.
 
 <b>ENVIRONMENT</b>
@@ -299,12 +332,12 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Enable debugging with an external command, as specified with the
               <b><a href="postconf.5.html#debugger_command">debugger_command</a></b> configuration parameter.
 
-       <b>NAME</b>   The  sender full name. This is used only with messages that have
+       <b>NAME</b>   The sender full name. This is used only with messages that  have
               no <b>From:</b> message header. See also the <b>-F</b> option above.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to  this  pro-
-       gram.   The  text  below  provides  only a parameter summary. See <a href="postconf.5.html"><b>post-</b></a>
+       The  following  <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to this pro-
+       gram.  The text below provides only  a  parameter  summary.  See  <a href="postconf.5.html"><b>post-</b></a>
        <a href="postconf.5.html"><b>conf</b>(5)</a> for more details including examples.
 
 <b>COMPATIBILITY CONTROLS</b>
@@ -315,7 +348,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               line endings from &lt;CR&gt;&lt;LF&gt; into UNIX format (&lt;LF&gt;).
 
 <b>TROUBLE SHOOTING CONTROLS</b>
-       The  <a href="DEBUG_README.html">DEBUG_README</a>  file gives examples of how to troubleshoot a Postfix
+       The <a href="DEBUG_README.html">DEBUG_README</a> file gives examples of how to troubleshoot  a  Postfix
        system.
 
        <b><a href="postconf.5.html#debugger_command">debugger_command</a> (empty)</b>
@@ -323,13 +356,15 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               invoked with the -D option.
 
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in verbose logging level when a remote client or
-              server matches a pattern in the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
+              The increment in verbose logging level when a  nexthop  destina-
+              tion,  remote client or server name or network address matches a
+              pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of remote client or  server  hostname  or  network
-              address  patterns  that  cause  the  verbose  logging  level  to
-              increase by the amount specified in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
+              Optional list of nexthop destination, remote  client  or  server
+              name  or  network  address  patterns that, if matched, cause the
+              verbose logging level to increase by  the  amount  specified  in
+              $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
 <b>ACCESS CONTROLS</b>
        Available in Postfix version 2.2 and later:
@@ -341,13 +376,13 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               List of users who are authorized to view the queue.
 
        <b><a href="postconf.5.html#authorized_submit_users">authorized_submit_users</a> (<a href="DATABASE_README.html#types">static</a>:anyone)</b>
-              List of users who are authorized to submit mail with  the  <a href="sendmail.1.html"><b>send-</b></a>
+              List  of  users who are authorized to submit mail with the <a href="sendmail.1.html"><b>send-</b></a>
               <a href="sendmail.1.html"><b>mail</b>(1)</a> command (and with the privileged <a href="postdrop.1.html"><b>postdrop</b>(1)</a> helper com-
               mand).
 
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a> (50000)</b>
-              The maximal amount of original message text that is  sent  in  a
+              The  maximal  amount  of original message text that is sent in a
               non-delivery notification.
 
        <b><a href="postconf.5.html#fork_attempts">fork_attempts</a> (5)</b>
@@ -361,11 +396,11 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               in the primary message headers.
 
        <b><a href="postconf.5.html#queue_run_delay">queue_run_delay</a> (300s)</b>
-              The time between <a href="QSHAPE_README.html#deferred_queue">deferred queue</a>  scans  by  the  queue  manager;
+              The  time  between  <a href="QSHAPE_README.html#deferred_queue">deferred  queue</a>  scans by the queue manager;
               prior to Postfix 2.4 the default value was 1000s.
 
 <b>FAST FLUSH CONTROLS</b>
-       The  <a href="ETRN_README.html">ETRN_README</a> file describes configuration and operation details for
+       The <a href="ETRN_README.html">ETRN_README</a> file describes configuration and operation details  for
        the Postfix "fast flush" service.
 
        <b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
@@ -373,26 +408,26 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               tion logfiles with mail that is queued to those destinations.
 
 <b>VERP CONTROLS</b>
-       The  <a href="VERP_README.html">VERP_README</a>  file describes configuration and operation details of
+       The <a href="VERP_README.html">VERP_README</a> file describes configuration and operation  details  of
        Postfix support for variable envelope return path addresses.
 
        <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
               The two default VERP delimiter characters.
 
        <b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
-              The characters Postfix accepts as VERP delimiter  characters  on
+              The  characters  Postfix accepts as VERP delimiter characters on
               the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line and in SMTP commands.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
-              The  alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are updated with
+              The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are updated  with
               "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
 
        <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
               The location of all postfix administrative commands.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of the Postfix <a href="postconf.5.html">main.cf</a> and  <a href="master.5.html">master.cf</a>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#daemon_directory">daemon_directory</a> (see 'postconf -d' output)</b>
@@ -403,46 +438,46 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               and <a href="postmap.1.html"><b>postmap</b>(1)</a> commands.
 
        <b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
-              The  time  after which the sender receives a copy of the message
+              The time after which the sender receives a copy of  the  message
               headers of mail that is still queued.
 
        <b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
-              The list of environment parameters  that  a  privileged  Postfix
-              process  will  import  from  a  non-Postfix  parent  process, or
+              The  list  of  environment  parameters that a privileged Postfix
+              process will  import  from  a  non-Postfix  parent  process,  or
               name=value environment overrides.
 
        <b><a href="postconf.5.html#mail_owner">mail_owner</a> (postfix)</b>
-              The UNIX system account that owns the  Postfix  queue  and  most
+              The  UNIX  system  account  that owns the Postfix queue and most
               Postfix daemon processes.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
               The location of the Postfix top-level queue directory.
 
        <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
-              Don't  rewrite  message  headers from remote clients at all when
-              this parameter is empty; otherwise, rewrite message headers  and
+              Don't rewrite message headers from remote clients  at  all  when
+              this  parameter is empty; otherwise, rewrite message headers and
               append the specified domain name to incomplete addresses.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A  prefix  that  is  prepended  to  the  process  name in syslog
+              A prefix that  is  prepended  to  the  process  name  in  syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Postfix 3.2 and later:
 
        <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a> (empty)</b>
               A list of non-default Postfix configuration directories that may
-              be  specified with "-c <a href="postconf.5.html#config_directory">config_directory</a>" on the command line (in
-              the case of <a href="sendmail.1.html"><b>sendmail</b>(1)</a>, with  the  "-C"  option),  or  via  the
+              be specified with "-c <a href="postconf.5.html#config_directory">config_directory</a>" on the command line  (in
+              the  case  of  <a href="sendmail.1.html"><b>sendmail</b>(1)</a>,  with  the  "-C" option), or via the
               MAIL_CONFIG environment parameter.
 
        <b><a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a> (empty)</b>
-              An  optional  list of non-default Postfix configuration directo-
-              ries; these directories belong to additional  Postfix  instances
-              that  share  the Postfix executable files and documentation with
-              the default Postfix instance, and  that  are  started,  stopped,
+              An optional list of non-default Postfix  configuration  directo-
+              ries;  these  directories belong to additional Postfix instances
+              that share the Postfix executable files and  documentation  with
+              the  default  Postfix  instance,  and that are started, stopped,
               etc., together with the default Postfix instance.
 
 <b>FILES</b>
@@ -463,7 +498,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        syslogd(8), system logging
 
 <b>README_FILES</b>
-       Use  "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to locate
+       Use "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to  locate
        this information.
        <a href="DEBUG_README.html">DEBUG_README</a>, Postfix debugging howto
        <a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
index 62b29d9f67e4ce64c9101c92f3c2e2a4857d9768..8129c30fc816d1799931ca3b00e8cbe41ad39efb 100644 (file)
@@ -4,7 +4,7 @@
 <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
 <title> Postfix manual - makedefs(1) </title>
 </head> <body> <pre>
-MAKEDEFS(1)                                                        MAKEDEFS(1)
+MAKEDEFS(1)                 General Commands Manual                MAKEDEFS(1)
 
 <b>NAME</b>
        makedefs - Postfix makefile configuration utility
@@ -110,45 +110,45 @@ MAKEDEFS(1)                                                        MAKEDEFS(1)
                      Disable support for POSIX getpwnam_r/getpwuid_r.
 
               <b>-DNO_RES_NCALLS</b>
-                     Do   not   build  with  the  threadsafe  resolver(5)  API
+                     Do  not  build  with  the  threadsafe   resolver(5)   API
                      (res_ninit() etc.).
 
               <b>-DNO_SIGSETJMP</b>
-                     Use  setjmp()/longjmp()   instead   of   sigsetjmp()/sig-
-                     longjmp().   By  default,  Postfix  uses sigsetjmp()/sig-
+                     Use   setjmp()/longjmp()   instead   of  sigsetjmp()/sig-
+                     longjmp().  By  default,  Postfix  uses  sigsetjmp()/sig-
                      longjmp() when they appear to work.
 
               <b>-DNO_SNPRINTF</b>
-                     Use sprintf() instead of snprintf(). By default,  Postfix
+                     Use  sprintf() instead of snprintf(). By default, Postfix
                      uses snprintf() except on ancient systems.
 
        <b>DEBUG=</b><i>debug</i><b>_</b><i>level</i>
-              Specifies  a  non-default  debugging  level.  The default is <b>-g</b>.
+              Specifies a non-default debugging  level.  The  default  is  <b>-g</b>.
               Specify <b>DEBUG=</b> to turn off debugging.
 
        <b>OPT=</b><i>optimization</i><b>_</b><i>level</i>
-              Specifies a non-default optimization level. The default  is  <b>-O</b>.
+              Specifies  a  non-default optimization level. The default is <b>-O</b>.
               Specify <b>OPT=</b> to turn off optimization.
 
        <b>POSTFIX_INSTALL_OPTS=</b><i>-option...</i>
-              Specifies  options for the postfix-install command, separated by
-              whitespace.   Currently,   the   only   supported   option    is
+              Specifies options for the postfix-install command, separated  by
+              whitespace.    Currently,   the   only   supported   option   is
               <b>-keep-build-mtime</b>.
 
        <b>SHLIB_CFLAGS=</b><i>flags</i>
-              Override  the  compiler  flags  (typically, "-fPIC") for Postfix
+              Override the compiler flags  (typically,  "-fPIC")  for  Postfix
               dynamically-linked libraries and database plugins.
 
               This feature was introduced with Postfix 3.0.
 
        <b>SHLIB_RPATH=</b><i>rpath</i>
-              Override the  runpath  (typically,  "'-Wl,-rpath,${SHLIB_DIR}'")
+              Override  the  runpath  (typically, "'-Wl,-rpath,${SHLIB_DIR}'")
               for Postfix dynamically-linked libraries.
 
               This feature was introduced with Postfix 3.0.
 
        <b>SHLIB_SUFFIX=</b><i>suffix</i>
-              Override  the  filename  suffix  (typically,  ".so") for Postfix
+              Override the filename  suffix  (typically,  ".so")  for  Postfix
               dynamically-linked libraries and database plugins.
 
               This feature was introduced with Postfix 3.0.
@@ -156,7 +156,7 @@ MAKEDEFS(1)                                                        MAKEDEFS(1)
        <b>shared=yes</b>
 
        <b>shared=no</b>
-              Enable  (disable)   Postfix   builds   with   dynamically-linked
+              Enable   (disable)   Postfix   builds   with  dynamically-linked
               libraries typically named $<a href="postconf.5.html#shlib_directory">shlib_directory</a>/libpostfix-*.so.*.
 
               This feature was introduced with Postfix 3.0.
@@ -164,39 +164,39 @@ MAKEDEFS(1)                                                        MAKEDEFS(1)
        <b>dynamicmaps=yes</b>
 
        <b>dynamicmaps=no</b>
-              Enable  (disable)  Postfix  builds  with  the configuration file
+              Enable (disable) Postfix  builds  with  the  configuration  file
               $<a href="postconf.5.html#meta_directory">meta_directory</a>/dynamicmaps.cf and dynamically-loadable database
-              plugins  typically  named  postfix-*.so.*.   The setting "dynam-
-              icmaps=yes"  implicitly   enables   Postfix   dynamically-linked
+              plugins typically named  postfix-*.so.*.   The  setting  "dynam-
+              icmaps=yes"   implicitly   enables   Postfix  dynamically-linked
               libraries.
 
               This feature was introduced with Postfix 3.0.
 
        <b>pie=yes</b>
 
-       <b>pie=no</b> Enable  (disable)  Postfix builds with position-independent exe-
+       <b>pie=no</b> Enable (disable) Postfix builds with  position-independent  exe-
               cutables, on platforms where this is supported.
 
               This feature was introduced with Postfix 3.0.
 
        <i>installation</i><b>_</b><i>parameter</i><b>=</b><i>value</i>...
-              Override the compiled-in default value of the specified  instal-
-              lation  parameter(s).  The following parameters are supported in
+              Override  the compiled-in default value of the specified instal-
+              lation parameter(s). The following parameters are  supported  in
               this context:
 
-              <a href="postconf.5.html#command_directory">command_directory</a> <a href="postconf.5.html#config_directory">config_directory</a> <a href="postconf.5.html#daemon_directory">daemon_directory</a>  <a href="postconf.5.html#data_directory">data_direc</a>-
-              <a href="postconf.5.html#data_directory">tory</a>  <a href="postconf.5.html#default_database_type">default_database_type</a>  <a href="postconf.5.html#html_directory">html_directory</a> <a href="postconf.5.html#mail_spool_directory">mail_spool_directory</a>
-              <a href="postconf.5.html#mailq_path">mailq_path</a>  <a href="postconf.5.html#manpage_directory">manpage_directory</a>   <a href="postconf.5.html#meta_directory">meta_directory</a>   <a href="postconf.5.html#newaliases_path">newaliases_path</a>
-              <a href="postconf.5.html#queue_directory">queue_directory</a>  <a href="postconf.5.html#readme_directory">readme_directory</a>  <a href="postconf.5.html#sendmail_path">sendmail_path</a> <a href="postconf.5.html#shlib_directory">shlib_directory</a>
+              <a href="postconf.5.html#command_directory">command_directory</a>  <a href="postconf.5.html#config_directory">config_directory</a> <a href="postconf.5.html#daemon_directory">daemon_directory</a> <a href="postconf.5.html#data_directory">data_direc</a>-
+              <a href="postconf.5.html#data_directory">tory</a> <a href="postconf.5.html#default_database_type">default_database_type</a>  <a href="postconf.5.html#html_directory">html_directory</a>  <a href="postconf.5.html#mail_spool_directory">mail_spool_directory</a>
+              <a href="postconf.5.html#mailq_path">mailq_path</a>   <a href="postconf.5.html#manpage_directory">manpage_directory</a>   <a href="postconf.5.html#meta_directory">meta_directory</a>  <a href="postconf.5.html#newaliases_path">newaliases_path</a>
+              <a href="postconf.5.html#queue_directory">queue_directory</a> <a href="postconf.5.html#readme_directory">readme_directory</a>  <a href="postconf.5.html#sendmail_path">sendmail_path</a>  <a href="postconf.5.html#shlib_directory">shlib_directory</a>
               <a href="postconf.5.html#openssl_path">openssl_path</a>
 
-              See the <a href="postconf.5.html">postconf(5)</a> manpage for a description of  these  parame-
+              See  the  <a href="postconf.5.html">postconf(5)</a> manpage for a description of these parame-
               ters.
 
               This feature was introduced with Postfix 3.0.
 
        <b>WARN=</b><i>warning</i><b>_</b><i>flags</i>
-              Specifies  non-default gcc compiler warning options for use when
+              Specifies non-default gcc compiler warning options for use  when
               "make" is invoked in a source subdirectory only.
 
 <b>LICENSE</b>
index 02f20fe8913d3963b9dd36d8887fe0eb3d9987d6..a83307fc69fdf11893827d2ae3fc1fdf9fe54fa5 100644 (file)
@@ -45,24 +45,27 @@ SENDMAIL(1)                                                        SENDMAIL(1)
                      ery attempt will be made until  the  mail  is  taken  off
                      hold.
 
-              This   mode   of  operation  is  implemented  by  executing  the
+              <b>#</b>      The  message  is  forced  to expire. See the <a href="postsuper.1.html"><b>postsuper</b>(1)</a>
+                     options <b>-e</b> or <b>-f</b>.
+
+              This  mode  of  operation  is  implemented  by   executing   the
               <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
 
        <b>newaliases</b>
-              Initialize the alias database.  If no input  file  is  specified
-              (with  the  <b>-oA</b>  option,  see  below), the program processes the
-              file(s) specified with the <b><a href="postconf.5.html#alias_database">alias_database</a></b> configuration  parame-
-              ter.   If  no alias database type is specified, the program uses
-              the type specified with the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b>  configuration
+              Initialize  the  alias  database.  If no input file is specified
+              (with the <b>-oA</b> option, see  below),  the  program  processes  the
+              file(s)  specified with the <b><a href="postconf.5.html#alias_database">alias_database</a></b> configuration parame-
+              ter.  If no alias database type is specified, the  program  uses
+              the  type specified with the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration
               parameter.  This mode of operation is implemented by running the
               <a href="postalias.1.html"><b>postalias</b>(1)</a> command.
 
               Note: it may take a minute or so before an alias database update
-              becomes  visible.  Use the "<b>postfix reload</b>" command to eliminate
+              becomes visible. Use the "<b>postfix reload</b>" command  to  eliminate
               this delay.
 
-       These and other features can be selected by specifying the  appropriate
-       combination  of  command-line  options. Some features are controlled by
+       These  and other features can be selected by specifying the appropriate
+       combination of command-line options. Some features  are  controlled  by
        parameters in the <a href="postconf.5.html"><b>main.cf</b></a> configuration file.
 
        The following options are recognized:
@@ -70,13 +73,13 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-Am</b> (ignored)
 
        <b>-Ac</b> (ignored)
-              Postfix sendmail uses the same configuration file regardless  of
+              Postfix  sendmail uses the same configuration file regardless of
               whether or not a message is an initial submission.
 
        <b>-B</b> <i>body</i><b>_</b><i>type</i>
               The message body MIME type: <b>7BIT</b> or <b>8BITMIME</b>.
 
-       <b>-bd</b>    Go  into  daemon  mode. This mode of operation is implemented by
+       <b>-bd</b>    Go into daemon mode. This mode of operation  is  implemented  by
               executing the "<b>postfix start</b>" command.
 
        <b>-bh</b> (ignored)
@@ -86,8 +89,8 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-bi</b>    Initialize alias database. See the <b>newaliases</b> command above.
 
-       <b>-bl</b>    Go into daemon mode. To accept only local  connections  as  with
-              Sendmail's  <b>-bl</b>  option, specify "<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = loopback</b>" in
+       <b>-bl</b>    Go  into  daemon  mode. To accept only local connections as with
+              Sendmail's <b>-bl</b> option, specify "<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> =  loopback</b>"  in
               the Postfix <a href="postconf.5.html"><b>main.cf</b></a> configuration file.
 
        <b>-bm</b>    Read mail from standard input and arrange for delivery.  This is
@@ -95,17 +98,17 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-bp</b>    List the mail queue. See the <b>mailq</b> command above.
 
-       <b>-bs</b>    Stand-alone  SMTP  server mode. Read SMTP commands from standard
-              input, and write responses to standard output.   In  stand-alone
-              SMTP  server  mode,  mail relaying and other access controls are
-              disabled by default. To enable them,  run  the  process  as  the
+       <b>-bs</b>    Stand-alone SMTP server mode. Read SMTP commands  from  standard
+              input,  and  write responses to standard output.  In stand-alone
+              SMTP server mode, mail relaying and other  access  controls  are
+              disabled  by  default.  To  enable  them, run the process as the
               <b><a href="postconf.5.html#mail_owner">mail_owner</a></b> user.
 
-              This  mode  of  operation is implemented by running the <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
+              This mode of operation is implemented by  running  the  <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
               daemon.
 
-       <b>-bv</b>    Do not collect or deliver a  message.  Instead,  send  an  email
-              report  after  verifying each recipient address.  This is useful
+       <b>-bv</b>    Do  not  collect  or  deliver  a message. Instead, send an email
+              report after verifying each recipient address.  This  is  useful
               for testing address rewriting and routing configurations.
 
               This feature is available in Postfix version 2.1 and later.
@@ -113,58 +116,58 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-C</b> <i>config</i><b>_</b><i>file</i>
 
        <b>-C</b> <i>config</i><b>_</b><i>dir</i>
-              The path name of the Postfix <a href="postconf.5.html"><b>main.cf</b></a>  file,  or  of  its  parent
-              directory.  This  information  is  ignored with Postfix versions
+              The  path  name  of  the  Postfix <a href="postconf.5.html"><b>main.cf</b></a> file, or of its parent
+              directory. This information is  ignored  with  Postfix  versions
               before 2.3.
 
               With Postfix version 3.2 and later, a non-default directory must
-              be  authorized  in  the default <a href="postconf.5.html"><b>main.cf</b></a> file, through the alter-
+              be authorized in the default <a href="postconf.5.html"><b>main.cf</b></a> file,  through  the  alter-
               nate_config_directories  or  <a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a>  parame-
               ters.
 
-              With  all Postfix versions, you can specify a directory pathname
-              with the MAIL_CONFIG environment variable to override the  loca-
+              With all Postfix versions, you can specify a directory  pathname
+              with  the MAIL_CONFIG environment variable to override the loca-
               tion of configuration files.
 
        <b>-F</b> <i>full</i><b>_</b><i>name</i>
-              Set  the  sender  full name. This overrides the NAME environment
+              Set the sender full name. This overrides  the  NAME  environment
               variable, and is used only with messages that have no <b>From:</b> mes-
               sage header.
 
        <b>-f</b> <i>sender</i>
-              Set  the  envelope  sender  address.  This  is the address where
+              Set the envelope sender  address.  This  is  the  address  where
               delivery problems are sent to. With Postfix versions before 2.1,
-              the   <b>Errors-To:</b>  message  header  overrides  the  error  return
+              the  <b>Errors-To:</b>  message  header  overrides  the  error   return
               address.
 
-       <b>-G</b>     Gateway (relay) submission, as opposed to initial  user  submis-
-              sion.   Either do not rewrite addresses at all, or update incom-
-              plete addresses  with  the  domain  information  specified  with
+       <b>-G</b>     Gateway  (relay)  submission, as opposed to initial user submis-
+              sion.  Either do not rewrite addresses at all, or update  incom-
+              plete  addresses  with  the  domain  information  specified with
               <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a></b>.
 
               This option is ignored before Postfix version 2.3.
 
        <b>-h</b> <i>hop</i><b>_</b><i>count</i> (ignored)
-              Hop  count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configuration parameter
+              Hop count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configuration  parameter
               instead.
 
        <b>-I</b>     Initialize alias database. See the <b>newaliases</b> command above.
 
-       <b>-i</b>     When reading a message from standard input, don't treat  a  line
+       <b>-i</b>     When  reading  a message from standard input, don't treat a line
               with only a <b>.</b> character as the end of input.
 
        <b>-L</b> <i>label</i> (ignored)
-              The  logging  label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b> configuration parameter
+              The logging label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b>  configuration  parameter
               instead.
 
        <b>-m</b> (ignored)
               Backwards compatibility.
 
        <b>-N</b> <i>dsn</i> (default: 'delay, failure')
-              Delivery  status  notification   control.   Specify   either   a
+              Delivery   status   notification   control.   Specify  either  a
               comma-separated list with one or more of <b>failure</b> (send notifica-
-              tion when delivery fails), <b>delay</b> (send notification when  deliv-
-              ery  is delayed), or <b>success</b> (send notification when the message
+              tion  when delivery fails), <b>delay</b> (send notification when deliv-
+              ery is delayed), or <b>success</b> (send notification when the  message
               is delivered); or specify <b>never</b> (don't send any notifications at
               all).
 
@@ -174,50 +177,50 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Backwards compatibility.
 
        <b>-oA</b><i>alias</i><b>_</b><i>database</i>
-              Non-default  alias  database. Specify <i>pathname</i> or <i>type</i>:<i>pathname</i>.
+              Non-default alias database. Specify <i>pathname</i>  or  <i>type</i>:<i>pathname</i>.
               See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
 
        <b>-O</b> <i>option=value</i> (ignored)
-              Set the named <i>option</i> to <i>value</i>. Use the equivalent  configuration
+              Set  the named <i>option</i> to <i>value</i>. Use the equivalent configuration
               parameter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
        <b>-o7</b> (ignored)
 
        <b>-o8</b> (ignored)
-              To  send 8-bit or binary content, use an appropriate MIME encap-
+              To send 8-bit or binary content, use an appropriate MIME  encap-
               sulation and specify the appropriate <b>-B</b> command-line option.
 
-       <b>-oi</b>    When reading a message from standard input, don't treat  a  line
+       <b>-oi</b>    When  reading  a message from standard input, don't treat a line
               with only a <b>.</b> character as the end of input.
 
        <b>-om</b> (ignored)
               The sender is never eliminated from alias etc. expansions.
 
        <b>-o</b> <i>x value</i> (ignored)
-              Set  option <i>x</i> to <i>value</i>. Use the equivalent configuration parame-
+              Set option <i>x</i> to <i>value</i>. Use the equivalent configuration  parame-
               ter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
        <b>-r</b> <i>sender</i>
-              Set the envelope sender  address.  This  is  the  address  where
+              Set  the  envelope  sender  address.  This  is the address where
               delivery problems are sent to. With Postfix versions before 2.1,
-              the  <b>Errors-To:</b>  message  header  overrides  the  error   return
+              the   <b>Errors-To:</b>  message  header  overrides  the  error  return
               address.
 
        <b>-R</b> <i>return</i>
-              Delivery  status notification control.  Specify "hdrs" to return
-              only the header when a message bounces, "full" to return a  full
+              Delivery status notification control.  Specify "hdrs" to  return
+              only  the header when a message bounces, "full" to return a full
               copy (the default behavior).
 
               The <b>-R</b> option specifies an upper bound; Postfix will return only
-              the header, when a full copy would exceed the  <a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a>
+              the  header, when a full copy would exceed the <a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a>
               setting.
 
               This option is ignored before Postfix version 2.10.
 
-       <b>-q</b>     Attempt  to deliver all queued mail. This is implemented by exe-
+       <b>-q</b>     Attempt to deliver all queued mail. This is implemented by  exe-
               cuting the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
 
-              Warning: flushing undeliverable mail frequently will  result  in
+              Warning:  flushing  undeliverable mail frequently will result in
               poor delivery performance of all other mail.
 
        <b>-q</b><i>interval</i> (ignored)
@@ -226,21 +229,21 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-qI</b><i>queueid</i>
               Schedule immediate delivery of mail with the specified queue ID.
-              This  option  is  implemented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> com-
+              This option is implemented by executing  the  <a href="postqueue.1.html"><b>postqueue</b>(1)</a>  com-
               mand, and is available with Postfix version 2.4 and later.
 
        <b>-qR</b><i>site</i>
-              Schedule immediate delivery of all mail that is queued  for  the
-              named  <i>site</i>. This option accepts only <i>site</i> names that are eligi-
-              ble for the "fast flush" service, and is implemented by  execut-
+              Schedule  immediate  delivery of all mail that is queued for the
+              named <i>site</i>. This option accepts only <i>site</i> names that are  eligi-
+              ble  for the "fast flush" service, and is implemented by execut-
               ing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.  See <a href="flush.8.html"><b>flush</b>(8)</a> for more information
               about the "fast flush" service.
 
        <b>-qS</b><i>site</i>
-              This command is not implemented. Use the  slower  "<b>sendmail  -q</b>"
+              This  command  is  not implemented. Use the slower "<b>sendmail -q</b>"
               command instead.
 
-       <b>-t</b>     Extract  recipients from message headers. These are added to any
+       <b>-t</b>     Extract recipients from message headers. These are added to  any
               recipients specified on the command line.
 
               With Postfix versions prior to 2.1, this option requires that no
@@ -256,23 +259,23 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               This feature is available in Postfix 2.3 and later.
 
        <b>-XV</b> (Postfix 2.2 and earlier: <b>-V</b>)
-              Variable Envelope Return Path. Given an envelope sender  address
-              of  the  form  <i>owner-listname</i>@<i>origin</i>, each recipient <i>user</i>@<i>domain</i>
+              Variable  Envelope Return Path. Given an envelope sender address
+              of the form <i>owner-listname</i>@<i>origin</i>,  each  recipient  <i>user</i>@<i>domain</i>
               receives mail with a personalized envelope sender address.
 
-              By  default,  the  personalized  envelope  sender   address   is
-              <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>.  The  default <b>+</b> and <b>=</b> charac-
-              ters are configurable with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b>  configu-
+              By   default,   the  personalized  envelope  sender  address  is
+              <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The default <b>+</b> and  <b>=</b>  charac-
+              ters  are configurable with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configu-
               ration parameter.
 
        <b>-XV</b><i>xy</i> (Postfix 2.2 and earlier: <b>-V</b><i>xy</i>)
-              As  <b>-XV</b>,  but  uses  <i>x</i>  and  <i>y</i> as the VERP delimiter characters,
+              As <b>-XV</b>, but uses <i>x</i> and  <i>y</i>  as  the  VERP  delimiter  characters,
               instead of the characters specified with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delim</a>-</b>
               <b><a href="postconf.5.html#default_verp_delimiters">iters</a></b> configuration parameter.
 
        <b>-v</b>     Send an email report of the first delivery attempt (Postfix ver-
-              sions 2.1 and later). Mail delivery always happens in the  back-
-              ground.  When multiple <b>-v</b> options are given, enable verbose log-
+              sions  2.1 and later). Mail delivery always happens in the back-
+              ground. When multiple <b>-v</b> options are given, enable verbose  log-
               ging for debugging purposes.
 
        <b>-X</b> <i>log</i><b>_</b><i>file</i> (ignored)
@@ -280,12 +283,42 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               configuration parameters instead.
 
 <b>SECURITY</b>
-       By design, this program is not set-user (or group) id. However, it must
-       handle data from untrusted, possibly remote, users.   Thus,  the  usual
-       precautions need to be taken against malicious inputs.
+       By design, this program is not set-user (or group) id.  It is  prepared
+       to handle message content from untrusted, possibly remote, users.
+
+       However,  like  most  Postfix programs, this program does not enforce a
+       security policy on its command-line arguments.  Instead, it  relies  on
+       the  UNIX system to enforce access policies based on the effective user
+       and group IDs of the process. Concretely, this means that running Post-
+       fix  commands as root (from sudo or equivalent) on behalf of a non-root
+       user is likely to create privilege escalation opportunities.
+
+       If an application runs any Postfix programs on behalf of users that  do
+       not have normal shell access to Postfix commands, then that application
+       MUST restrict user-specified command-line arguments to avoid  privilege
+       escalation.
+
+       <b>o</b>      Filter  all  command-line  arguments, for example arguments that
+              contain a pathname or that specify  a  database  access  method.
+              These  pathname  checks  must reject user-controlled symlinks or
+              hardlinks to sensitive files, and must not be vulnerable to TOC-
+              TOU race attacks.
+
+       <b>o</b>      Disable  command  options  processing  for all command arguments
+              that contain user-specified data. For example, the Postfix <a href="sendmail.1.html"><b>send-</b></a>
+              <a href="sendmail.1.html"><b>mail</b>(1)</a> command line MUST be structured as follows:
+
+                  <b>/path/to/sendmail</b> <i>system-arguments</i> <b>--</b> <i>user-arguments</i>
+
+              Here,  the  "<b>--</b>"  disables  command  option  processing  for all
+              <i>user-arguments</i> that follow.
+
+              Without the "<b>--</b>", a malicious user could  enable  Postfix  <a href="sendmail.1.html"><b>send-</b></a>
+              <a href="sendmail.1.html"><b>mail</b>(1)</a>  command  options,  by  specifying an email address that
+              starts with "<b>-</b>".
 
 <b>DIAGNOSTICS</b>
-       Problems  are  logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>, and to the standard
+       Problems are logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>, and to  the  standard
        error stream.
 
 <b>ENVIRONMENT</b>
@@ -299,12 +332,12 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Enable debugging with an external command, as specified with the
               <b><a href="postconf.5.html#debugger_command">debugger_command</a></b> configuration parameter.
 
-       <b>NAME</b>   The  sender full name. This is used only with messages that have
+       <b>NAME</b>   The sender full name. This is used only with messages that  have
               no <b>From:</b> message header. See also the <b>-F</b> option above.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to  this  pro-
-       gram.   The  text  below  provides  only a parameter summary. See <a href="postconf.5.html"><b>post-</b></a>
+       The  following  <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to this pro-
+       gram.  The text below provides only  a  parameter  summary.  See  <a href="postconf.5.html"><b>post-</b></a>
        <a href="postconf.5.html"><b>conf</b>(5)</a> for more details including examples.
 
 <b>COMPATIBILITY CONTROLS</b>
@@ -315,7 +348,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               line endings from &lt;CR&gt;&lt;LF&gt; into UNIX format (&lt;LF&gt;).
 
 <b>TROUBLE SHOOTING CONTROLS</b>
-       The  <a href="DEBUG_README.html">DEBUG_README</a>  file gives examples of how to troubleshoot a Postfix
+       The <a href="DEBUG_README.html">DEBUG_README</a> file gives examples of how to troubleshoot  a  Postfix
        system.
 
        <b><a href="postconf.5.html#debugger_command">debugger_command</a> (empty)</b>
@@ -323,13 +356,15 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               invoked with the -D option.
 
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in verbose logging level when a remote client or
-              server matches a pattern in the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
+              The increment in verbose logging level when a  nexthop  destina-
+              tion,  remote client or server name or network address matches a
+              pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of remote client or  server  hostname  or  network
-              address  patterns  that  cause  the  verbose  logging  level  to
-              increase by the amount specified in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
+              Optional list of nexthop destination, remote  client  or  server
+              name  or  network  address  patterns that, if matched, cause the
+              verbose logging level to increase by  the  amount  specified  in
+              $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
 <b>ACCESS CONTROLS</b>
        Available in Postfix version 2.2 and later:
@@ -341,13 +376,13 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               List of users who are authorized to view the queue.
 
        <b><a href="postconf.5.html#authorized_submit_users">authorized_submit_users</a> (<a href="DATABASE_README.html#types">static</a>:anyone)</b>
-              List of users who are authorized to submit mail with  the  <a href="sendmail.1.html"><b>send-</b></a>
+              List  of  users who are authorized to submit mail with the <a href="sendmail.1.html"><b>send-</b></a>
               <a href="sendmail.1.html"><b>mail</b>(1)</a> command (and with the privileged <a href="postdrop.1.html"><b>postdrop</b>(1)</a> helper com-
               mand).
 
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a> (50000)</b>
-              The maximal amount of original message text that is  sent  in  a
+              The  maximal  amount  of original message text that is sent in a
               non-delivery notification.
 
        <b><a href="postconf.5.html#fork_attempts">fork_attempts</a> (5)</b>
@@ -361,11 +396,11 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               in the primary message headers.
 
        <b><a href="postconf.5.html#queue_run_delay">queue_run_delay</a> (300s)</b>
-              The time between <a href="QSHAPE_README.html#deferred_queue">deferred queue</a>  scans  by  the  queue  manager;
+              The  time  between  <a href="QSHAPE_README.html#deferred_queue">deferred  queue</a>  scans by the queue manager;
               prior to Postfix 2.4 the default value was 1000s.
 
 <b>FAST FLUSH CONTROLS</b>
-       The  <a href="ETRN_README.html">ETRN_README</a> file describes configuration and operation details for
+       The <a href="ETRN_README.html">ETRN_README</a> file describes configuration and operation details  for
        the Postfix "fast flush" service.
 
        <b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
@@ -373,26 +408,26 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               tion logfiles with mail that is queued to those destinations.
 
 <b>VERP CONTROLS</b>
-       The  <a href="VERP_README.html">VERP_README</a>  file describes configuration and operation details of
+       The <a href="VERP_README.html">VERP_README</a> file describes configuration and operation  details  of
        Postfix support for variable envelope return path addresses.
 
        <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
               The two default VERP delimiter characters.
 
        <b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
-              The characters Postfix accepts as VERP delimiter  characters  on
+              The  characters  Postfix accepts as VERP delimiter characters on
               the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line and in SMTP commands.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
-              The  alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are updated with
+              The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are updated  with
               "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
 
        <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
               The location of all postfix administrative commands.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of the Postfix <a href="postconf.5.html">main.cf</a> and  <a href="master.5.html">master.cf</a>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#daemon_directory">daemon_directory</a> (see 'postconf -d' output)</b>
@@ -403,46 +438,46 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               and <a href="postmap.1.html"><b>postmap</b>(1)</a> commands.
 
        <b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
-              The  time  after which the sender receives a copy of the message
+              The time after which the sender receives a copy of  the  message
               headers of mail that is still queued.
 
        <b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
-              The list of environment parameters  that  a  privileged  Postfix
-              process  will  import  from  a  non-Postfix  parent  process, or
+              The  list  of  environment  parameters that a privileged Postfix
+              process will  import  from  a  non-Postfix  parent  process,  or
               name=value environment overrides.
 
        <b><a href="postconf.5.html#mail_owner">mail_owner</a> (postfix)</b>
-              The UNIX system account that owns the  Postfix  queue  and  most
+              The  UNIX  system  account  that owns the Postfix queue and most
               Postfix daemon processes.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
               The location of the Postfix top-level queue directory.
 
        <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
-              Don't  rewrite  message  headers from remote clients at all when
-              this parameter is empty; otherwise, rewrite message headers  and
+              Don't rewrite message headers from remote clients  at  all  when
+              this  parameter is empty; otherwise, rewrite message headers and
               append the specified domain name to incomplete addresses.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A  prefix  that  is  prepended  to  the  process  name in syslog
+              A prefix that  is  prepended  to  the  process  name  in  syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Postfix 3.2 and later:
 
        <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a> (empty)</b>
               A list of non-default Postfix configuration directories that may
-              be  specified with "-c <a href="postconf.5.html#config_directory">config_directory</a>" on the command line (in
-              the case of <a href="sendmail.1.html"><b>sendmail</b>(1)</a>, with  the  "-C"  option),  or  via  the
+              be specified with "-c <a href="postconf.5.html#config_directory">config_directory</a>" on the command line  (in
+              the  case  of  <a href="sendmail.1.html"><b>sendmail</b>(1)</a>,  with  the  "-C" option), or via the
               MAIL_CONFIG environment parameter.
 
        <b><a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a> (empty)</b>
-              An  optional  list of non-default Postfix configuration directo-
-              ries; these directories belong to additional  Postfix  instances
-              that  share  the Postfix executable files and documentation with
-              the default Postfix instance, and  that  are  started,  stopped,
+              An optional list of non-default Postfix  configuration  directo-
+              ries;  these  directories belong to additional Postfix instances
+              that share the Postfix executable files and  documentation  with
+              the  default  Postfix  instance,  and that are started, stopped,
               etc., together with the default Postfix instance.
 
 <b>FILES</b>
@@ -463,7 +498,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        syslogd(8), system logging
 
 <b>README_FILES</b>
-       Use  "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to locate
+       Use "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to  locate
        this information.
        <a href="DEBUG_README.html">DEBUG_README</a>, Postfix debugging howto
        <a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
index a29f9223e976bfefcabb3e0c434e50f2008c6d8b..13d621cc66769b42e8404666cbefd7a03e80e999 100644 (file)
@@ -5354,7 +5354,7 @@ configuration parameter.  See there for details. </p>
 </DD>
 
 <DT><b><a name="lmtp_tls_fingerprint_digest">lmtp_tls_fingerprint_digest</a>
-(default: md5)</b></DT><DD>
+(default: see "postconf -d" output)</b></DT><DD>
 
 <p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a>
 configuration parameter.  See there for details. </p>
@@ -5721,6 +5721,15 @@ The fingerprint digest algorithm is configurable via the
 <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> parameter (hard-coded as md5 prior to
 Postfix version 2.5).  </dd>
 
+<dd> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </dd>
+
 <dt><b><a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> </b></dt>
 
 <dd> Append the domain name in $<a href="postconf.5.html#myorigin">myorigin</a> or $<a href="postconf.5.html#mydomain">mydomain</a> when the
@@ -9560,6 +9569,15 @@ feature.  The fingerprint digest algorithm is configurable via the
 <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> parameter (hard-coded as md5 prior to
 Postfix version 2.5).  </p>
 
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </p>
+
 <p> Postfix lookup tables are in the form of (key, value) pairs.
 Since we only need the key, the value can be chosen freely, e.g.
 the name of the user or host:
@@ -9575,10 +9593,6 @@ D7:04:2F:A7:0B:8C:A5:21:FA:31:77:E1:41:8A:EE:80 lutzpc.at.home </p>
 an appropriate <a href="access.5.html">access(5)</a> policy for each client.
 See <a href="RESTRICTION_CLASS_README.html">RESTRICTION_CLASS_README</a>.</p>
 
-<p> <b>Note:</b> Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
-
 <p>This feature is available with Postfix version 2.2.</p>
 
 
@@ -12573,6 +12587,10 @@ is a message digest of the server certificate (or public key). The
 digest algorithm is selected via the <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b>
 parameter. </p>
 
+<p> The colons between each pair of nibbles in the fingerprint value
+are optional (Postfix &ge; 3.6). These were required in earlier
+Postfix releases. </p>
+
 <p> When an <b><a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a></b> table entry specifies the
 "fingerprint" security level, any "match" attributes in that entry specify
 the list of valid fingerprints for the corresponding destination. Multiple
@@ -12590,10 +12608,10 @@ another, and both keys are trusted just prior to the transition. </p>
 <pre>
 <a href="postconf.5.html#relayhost">relayhost</a> = [mailhub.example.com]
 <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = fingerprint
-<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = sha256
 <a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> =
-    3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
-    EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+    cd:fc:d8:db:f8:c4:82:96:6c:...:28:71:e8:f5:8d:a5:0d:9b:d4:a6
+    dd:5c:ef:f5:c3:bc:64:25:36:...:99:36:06:ce:40:ef:de:2e:ad:a4
 </pre>
 </blockquote>
 
@@ -12604,7 +12622,7 @@ As in the example above, we show two matching fingerprints: </p>
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/tls_policy
-    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = sha256
 </pre>
 </blockquote>
 
@@ -12612,8 +12630,8 @@ As in the example above, we show two matching fingerprints: </p>
 <pre>
 /etc/postfix/tls_policy:
     example.com fingerprint
-        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
-        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+        match=51:e9:af:2e:1e:40:1f:...:64:0a:30:35:2d:09:16:31:5a:eb:82:76
+        match=b6:b4:72:34:e2:59:cd:...:c2:ca:63:0d:4d:cc:2c:7d:84:de:e6:2f
 </pre>
 </blockquote>
 
@@ -12623,7 +12641,7 @@ As in the example above, we show two matching fingerprints: </p>
 </DD>
 
 <DT><b><a name="smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a>
-(default: md5)</b></DT><DD>
+(default: see "postconf -d" output)</b></DT><DD>
 
 <p> The message digest algorithm used to construct remote SMTP server
 certificate fingerprints. At the "fingerprint" TLS security level
@@ -12636,19 +12654,19 @@ 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 (or public/private key-pair) that has the same fingerprint. </p>
 
-<p> The default algorithm is <b>md5</b>; this is consistent with
-the backwards compatible setting of the digest used to verify client
-certificates in the SMTP server. </p>
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>. </p>
 
-<p> The best practice algorithm is now <b>sha1</b>. Recent advances in hash
-function cryptanalysis have led to md5 being deprecated in favor of sha1.
-However, as long as there are no known "second pre-image" attacks
-against md5, its use in this context can still be considered safe.
-</p>
+<p> The best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image" attacks
+against the older algorithms, their use in this context, though not
+recommended, is still likely safe.  </p>
 
 <p> While additional digest algorithms are often available with OpenSSL's
 libcrypto, only those used by libssl in SSL cipher suites are available to
-Postfix. For now this means just md5 or sha1. </p>
+Postfix.  You'll likely find support for md5, sha1, sha256 and sha512. </p>
 
 <p> To find the fingerprint of a specific certificate file, with a
 specific digest algorithm, run:
@@ -12665,8 +12683,8 @@ For example: </p>
 
 <blockquote>
 <pre>
-$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
-SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+$ openssl x509 -noout -fingerprint -sha256 -in cert.pem
+SHA256 Fingerprint=D4:6A:AB:19:24:...:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
 </pre>
 </blockquote>
 
@@ -12678,29 +12696,16 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> The actual command to transform the key to DER format depends on the
+version of OpenSSL used. As of OpenSSL 1.0.0, the "pkey" command supports
+all key types. </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
+# OpenSSL &ge; 1.0 with SHA-256 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
-(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-</pre>
-</blockquote>
-
-<blockquote>
-<pre>
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
+    openssl dgst -sha256 -c
+(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:...:fc:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
 
@@ -12708,10 +12713,6 @@ $ openssl x509 -in cert.pem -noout -pubkey |
 fingerprint and public key fingerprint when the TLS loglevel is 2 or
 higher. </p>
 
-<p> <b>Note:</b> Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
-
 <p> This feature is available in Postfix 2.5 and later. </p>
 
 
@@ -13204,8 +13205,12 @@ Example:
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/tls_policy
-    # Postfix 2.5 and later
-    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+    # Postfix 2.5 and later.
+    #
+    # The default digest is sha256 with Postfix &ge; 3.6 and
+    # compatibility level &ge; 3.
+    #
+    <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = sha256
 </pre>
 
 <pre>
@@ -13219,8 +13224,8 @@ Example:
     [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
+        match=b6:b4:72:34:e2:59:cd:...:c2:ca:63:0d:4d:cc:2c:7d:84:de:e6:2f
+        match=51:e9:af:2e:1e:40:1f:...:64:0a:30:35:2d:09:16:31:5a:eb:82:76
 </pre>
 
 <p> <b>Note:</b> The <b>hostname</b> strategy if listed in a non-default
@@ -14249,7 +14254,14 @@ Postfix version 2.5).  This feature requires "<a href="postconf.5.html#smtpd_tls
 = yes" and is available with Postfix version
 2.2 and later. </dd>
 
-<br>
+<dd> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </dd>
 
 <dd> Alternatively, <a href="postconf.5.html#check_ccert_access">check_ccert_access</a> accepts an explicit search
 order (Postfix 3.5 and later). The default search order as described
@@ -14371,6 +14383,15 @@ The fingerprint digest algorithm is configurable via the
 Postfix version 2.5).  This feature requires "<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a>
 = yes" and is available with Postfix version 2.2 and later.</dd>
 
+<dd> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </dd>
+
 <dt><b><a name="reject_rbl_client">reject_rbl_client <i>rbl_domain=d.d.d.d</i></a></b></dt>
 
 <dd>Reject the request when the reversed client network address is
@@ -17174,15 +17195,24 @@ The DSA algorithm is obsolete and should not be used. </p>
 <p> File with DH parameters that the Postfix SMTP server should
 use with non-export EDH ciphers. </p>
 
+<p> The best-practice choice of parameters uses a 2048-bit prime.  This is fine,
+despite the historical "1024" in the parameter name.  Do not be tempted to use
+much larger values, performance degrades quickly, and you may also cease to
+interoperate with some mainstream SMTP clients.  As of Postfix 3.1, the
+compiled-in default prime is 2048-bits, and it is not strictly necessary,
+though perhaps somewhat beneficial to generate custom DH parameters. </p>
+
 <p> 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 commands:  </p>
 
 <blockquote>
 <pre>
-openssl dhparam -out /etc/postfix/dh512.pem 512
-openssl dhparam -out /etc/postfix/dh1024.pem 1024
 openssl dhparam -out /etc/postfix/dh2048.pem 2048
+openssl dhparam -out /etc/postfix/dh1024.pem 1024
+# As of Postfix 3.6, export-grade 512-bit DH parameters are no longer
+# supported or needed.
+openssl dhparam -out /etc/postfix/dh512.pem 512
 </pre>
 </blockquote>
 
@@ -17220,6 +17250,9 @@ grade is "medium" with Postfix releases after the middle of 2015,
 and as a result export-grade cipher suites are by default not used.
 </p>
 
+<p> With Postfix &ge; 3.6 export-grade Diffie-Hellman key exchange
+is no longer supported, and this parameter is silently ignored. </p>
+
 <p> See also the discussion under the <a href="postconf.5.html#smtpd_tls_dh1024_param_file">smtpd_tls_dh1024_param_file</a>
 configuration parameter.  </p>
 
@@ -17298,32 +17331,32 @@ compiled and linked with OpenSSL 1.0.0 or later. </p>
 (default: see "postconf -d" output)</b></DT><DD>
 
 <p> The Postfix SMTP server security grade for ephemeral elliptic-curve
-Diffie-Hellman (EECDH) key exchange. </p>
+Diffie-Hellman (EECDH) key exchange.   As of Postfix 3.6, the value of
+this parameter is always ignored, and Postfix behaves as though th
+<b>auto</b> value (described below) was chosen.
+</p>
 
 <p> The available choices are: </p>
 
 <dl>
 
+<dt><b>auto</b></dt> <dd> Use the most preferred curve that is
+supported by both the client and the server.  This setting requires
+Postfix &ge; 3.2 compiled and linked with OpenSSL &ge; 1.0.2.  This
+is the default setting under the above conditions (and the only
+setting used with Postfix &ge; 3.6). </dd>
+
 <dt><b>none</b></dt> <dd> Don't use EECDH. Ciphers based on EECDH key
 exchange will be disabled. This is the default in Postfix versions
 2.6 and 2.7. </dd>
 
-<dt><b>strong</b></dt> <dd> Use EECDH with approximately 128
-bits of security at a reasonable computational cost. This is the
-current best-practice trade-off between security and computational
-efficiency. This is the default in Postfix version 2.8 and later.
-</dd>
+<dt><b>strong</b></dt> <dd> Use EECDH with approximately 128 bits of
+security at a reasonable computational cost. This is the default in
+Postfix versions 2.8&ndash;3.5.  </dd>
 
 <dt><b>ultra</b></dt> <dd> Use EECDH with approximately 192 bits of
 security at computational cost that is approximately twice as high
-as 128 bit strength ECC. Barring significant progress in attacks on
-elliptic curve crypto-systems, the "strong" curve is sufficient for most
-users. </dd>
-
-<dt><b>auto</b></dt> <dd> Use the most preferred curve that is
-supported by both the client and the server.  This setting requires
-Postfix &ge; 3.2 compiled and linked with OpenSSL &ge; 1.0.2.  This
-is the default setting under the above conditions.  </dd>
+as 128 bit strength ECC. </dd>
 
 </dl>
 
@@ -17380,24 +17413,25 @@ key exchange with RSA authentication. </p>
 </DD>
 
 <DT><b><a name="smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a>
-(default: md5)</b></DT><DD>
+(default: see "postconf -d" output)</b></DT><DD>
 
-<p> The message digest algorithm to construct remote SMTP
-client-certificate
-fingerprints or public key fingerprints (Postfix 2.9 and later)
-for <b><a href="postconf.5.html#check_ccert_access">check_ccert_access</a></b> and <b><a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a></b>. The
-default algorithm is <b>md5</b>, for backwards compatibility with Postfix
-releases prior to 2.5.  </p>
+<p> The message digest algorithm to construct remote SMTP client-certificate
+fingerprints or public key fingerprints (Postfix 2.9 and later) for
+<b><a href="postconf.5.html#check_ccert_access">check_ccert_access</a></b> and <b><a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a></b>. </p>
 
-<p> Advances in hash
-function cryptanalysis have led to md5 being deprecated in favor of sha1.
-However, as long as there are no known "second pre-image" attacks
-against md5, its use in this context can still be considered safe.
-</p>
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b><a href="postconf.5.html#compatibility_level">compatibility_level</a></b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>. </p>
+
+<p> The best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image" attacks
+against the older algorithms, their use in this context, though not
+recommended, is still likely safe.  </p>
 
 <p> While additional digest algorithms are often available with OpenSSL's
 libcrypto, only those used by libssl in SSL cipher suites are available to
-Postfix. </p>
+Postfix.  You'll likely find support for md5, sha1, sha256 and sha512. </p>
 
 <p> To find the fingerprint of a specific certificate file, with a
 specific digest algorithm, run: </p>
@@ -17413,8 +17447,8 @@ For example: </p>
 
 <blockquote>
 <pre>
-$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
-SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+$ openssl x509 -noout -fingerprint -sha256 -in cert.pem
+SHA256 Fingerprint=D4:6A:AB:19:24:...:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
 </pre>
 </blockquote>
 
@@ -17426,46 +17460,26 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> Example: </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
+    openssl dgst -sha256 -c
 (stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
 
-<blockquote>
-<pre>
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
-</pre>
-</blockquote>
-
 <p> The Postfix SMTP server and client log the peer (leaf) certificate
 fingerprint and public key fingerprint when the TLS loglevel is 2 or
 higher. </p>
 
-<p> <b>Note:</b> Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
-
-<p> Example: client-certificate access table, with sha1 fingerprints: </p>
+<p> Example: client-certificate access table, with sha256 fingerprints: </p>
 
 <blockquote>
 <pre>
 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
-    <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> = sha1
+    <a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> = sha256
     <a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> =
         <a href="postconf.5.html#check_ccert_access">check_ccert_access</a> <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/access,
         reject
@@ -17473,9 +17487,9 @@ to Postfix 2.9.6 or later. </p>
 <pre>
 /etc/postfix/access:
     # Action folded to next line...
-    AF:88:7C:AD:51:95:6F:36:96:F6:01:FB:2E:48:CD:AB:49:25:A2:3B
+    AF:88:7C:AD:51:95:6F:36:96:...: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
+    85:16:78:FD:73:6E:CE:70:E0:...:5F:0D:3C:C8:6D:C4:2C:24:59:E1
         <a href="postconf.5.html#permit_auth_destination">permit_auth_destination</a>
 </pre>
 </blockquote>
@@ -19423,6 +19437,9 @@ for further details.  The default SMTP server cipher grade is
 "medium" with Postfix releases after the middle of 2015, and as a
 result export-grade cipher suites are by default not used.  </p>
 
+<p> With Postfix &ge; 3.6 export-grade Diffie-Hellman key exchange
+is no longer supported, and this parameter is silently ignored. </p>
+
 <p> This feature is available in Postfix 2.8 and later. </p>
 
 
index 4a47a4818b8982eb6da6488747d8cb97367b2d16..fd9d83baa307c929477e9b4b7fe8d150c4de0280 100644 (file)
@@ -4,7 +4,7 @@
 <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
 <title> Postfix manual - posttls-finger(1) </title>
 </head> <body> <pre>
-POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
+POSTTLS-FINGER(1)           General Commands Manual          POSTTLS-FINGER(1)
 
 <b>NAME</b>
        posttls-finger - Probe the TLS properties of an ESMTP or LMTP server.
@@ -104,77 +104,78 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
               tificates.  To see the actual chain  sent  by  the  remote  SMTP
               server leave <i>CAfile</i> and <i>CApath</i> unset.
 
-       <b>-d</b> <i>mdalg</i> (default: <b>sha1</b>)
+       <b>-d</b> <i>mdalg</i> (default: <b>$<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b>)
               The  message  digest  algorithm to use for reporting remote SMTP
               server fingerprints and matching against user provided  certifi-
               cate fingerprints (with DANE TLSA records the algorithm is spec-
-              ified in the DNS).
+              ified in the DNS).   In  Postfix  versions  prior  to  3.6,  the
+              default value was "sha1".
 
-       <b>-f</b>     Lookup the associated DANE TLSA RRset even when  a  hostname  is
-              not  an  alias  and its address records lie in an unsigned zone.
+       <b>-f</b>     Lookup  the  associated  DANE TLSA RRset even when a hostname is
+              not an alias and its address records lie in  an  unsigned  zone.
               See <a href="postconf.5.html#smtp_tls_force_insecure_host_tlsa_lookup">smtp_tls_force_insecure_host_tlsa_lookup</a> for details.
 
        <b>-F</b> <i>CAfile.pem</i> (default: none)
               The PEM formatted CAfile for remote SMTP server certificate ver-
-              ification.   By  default no CAfile is used and no public CAs are
+              ification.  By default no CAfile is used and no public  CAs  are
               trusted.
 
        <b>-g</b> <i>grade</i> (default: medium)
-              The minimum  TLS  cipher  grade  used  by  posttls-finger.   See
+              The  minimum  TLS  cipher  grade  used  by  posttls-finger.  See
               <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> for details.
 
        <b>-h</b> <i>host</i><b>_</b><i>lookup</i> (default: <b>dns</b>)
-              The  hostname  lookup  methods used for the connection.  See the
+              The hostname lookup methods used for the  connection.   See  the
               documentation of <a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> for syntax and semantics.
 
        <b>-H</b> <i>chainfiles</i> (default: <i>none</i>)
               List of files with a sequence PEM-encoded TLS client certificate
-              chains.   The  list can be built-up incrementally, by specifying
-              the option multiple times, or all at once via a comma or  white-
-              space  separated  list  of  filenames.  Each chain starts with a
-              private key, which is followed immediately by the  corresponding
-              certificate,  and  optionally by additional issuer certificates.
+              chains.  The list can be built-up incrementally,  by  specifying
+              the  option multiple times, or all at once via a comma or white-
+              space separated list of filenames.  Each  chain  starts  with  a
+              private  key, which is followed immediately by the corresponding
+              certificate, and optionally by additional  issuer  certificates.
               Each new key begins a new chain for the corresponding algorithm.
-              This  option  is  mutually  exclusive  with  the below <b>-k</b> and <b>-K</b>
+              This option is mutually exclusive  with  the  below  <b>-k</b>  and  <b>-K</b>
               options.
 
        <b>-k</b> <i>certfile</i> (default: <i>keyfile</i>)
-              File  with  PEM-encoded  TLS  client  certificate  chain.   This
+              File   with  PEM-encoded  TLS  client  certificate  chain.  This
               defaults to <i>keyfile</i> if one is specified.
 
        <b>-K</b> <i>keyfile</i> (default: <i>certfile</i>)
-              File  with PEM-encoded TLS client private key.  This defaults to
+              File with PEM-encoded TLS client private key.  This defaults  to
               <i>certfile</i> if one is specified.
 
        <b>-l</b> <i>level</i> (default: <b>dane</b> or <b>secure</b>)
-              The security level for the connection, default  <b>dane</b>  or  <b>secure</b>
+              The  security  level  for the connection, default <b>dane</b> or <b>secure</b>
               depending on whether DNSSEC is available.  For syntax and seman-
-              tics, see the documentation  of  <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a>.   When
-              <b>dane</b>  or <b>dane-only</b> is supported and selected, if no TLSA records
-              are found, or all the records found  are  unusable,  the  <i>secure</i>
-              level  will  be  used  instead.   The <b>fingerprint</b> security level
+              tics,  see  the  documentation of <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a>.  When
+              <b>dane</b> or <b>dane-only</b> is supported and selected, if no TLSA  records
+              are  found,  or  all  the records found are unusable, the <i>secure</i>
+              level will be used  instead.   The  <b>fingerprint</b>  security  level
               allows you to test certificate or public-key fingerprint matches
               before you deploy them in the policy table.
 
-              Note,  since <b>posttls-finger</b> does not actually deliver any email,
-              the <b>none</b>, <b>may</b> and <b>encrypt</b> security levels are not  very  useful.
+              Note, since <b>posttls-finger</b> does not actually deliver any  email,
+              the  <b>none</b>,  <b>may</b> and <b>encrypt</b> security levels are not very useful.
               Since <b>may</b> and <b>encrypt</b> don't require peer certificates, they will
-              often negotiate anonymous TLS ciphersuites, so you  won't  learn
+              often  negotiate  anonymous TLS ciphersuites, so you won't learn
               much about the remote SMTP server's certificates at these levels
               if it also supports anonymous TLS (though you may learn that the
               server supports anonymous TLS).
 
        <b>-L</b> <i>logopts</i> (default: <b>routine,certmatch</b>)
-              Fine-grained  TLS  logging  options.  To  tune  the TLS features
+              Fine-grained TLS logging  options.  To  tune  the  TLS  features
               logged during the TLS handshake, specify one or more of:
 
               <b>0, none</b>
-                     These yield no TLS logging; you'll generally  want  more,
+                     These  yield  no TLS logging; you'll generally want more,
                      but this is handy if you just want the trust chain:
                      $ posttls-finger -cC -L none destination
 
               <b>1, routine, summary</b>
-                     These  synonymous  values yield a normal one-line summary
+                     These synonymous values yield a normal  one-line  summary
                      of the TLS connection.
 
               <b>2, debug</b>
@@ -182,104 +183,104 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
                      and verbose.
 
               <b>3, ssl-expert</b>
-                     These  synonymous  values  combine  debug  with ssl-hand-
+                     These synonymous  values  combine  debug  with  ssl-hand-
                      shake-packet-dump.  For experts only.
 
               <b>4, ssl-developer</b>
-                     These synonymous values combine ssl-expert with  ssl-ses-
-                     sion-packet-dump.   For  experts only, and in most cases,
+                     These  synonymous values combine ssl-expert with ssl-ses-
+                     sion-packet-dump.  For experts only, and in  most  cases,
                      use wireshark instead.
 
               <b>ssl-debug</b>
-                     Turn on OpenSSL logging of the progress of the SSL  hand-
+                     Turn  on OpenSSL logging of the progress of the SSL hand-
                      shake.
 
               <b>ssl-handshake-packet-dump</b>
-                     Log  hexadecimal  packet  dumps of the SSL handshake; for
+                     Log hexadecimal packet dumps of the  SSL  handshake;  for
                      experts only.
 
               <b>ssl-session-packet-dump</b>
-                     Log hexadecimal packet dumps of the entire  SSL  session;
-                     only  useful to those who can debug SSL protocol problems
+                     Log  hexadecimal  packet dumps of the entire SSL session;
+                     only useful to those who can debug SSL protocol  problems
                      from hex dumps.
 
               <b>untrusted</b>
-                     Logs trust chain verification problems.  This  is  turned
-                     on  automatically  at security levels that use peer names
-                     signed by Certification Authorities to validate  certifi-
-                     cates.   So  while this setting is recognized, you should
+                     Logs  trust  chain verification problems.  This is turned
+                     on automatically at security levels that use  peer  names
+                     signed  by Certification Authorities to validate certifi-
+                     cates.  So while this setting is recognized,  you  should
                      never need to set it explicitly.
 
               <b>peercert</b>
-                     This logs a one line summary of the  remote  SMTP  server
+                     This  logs  a  one line summary of the remote SMTP server
                      certificate subject, issuer, and fingerprints.
 
               <b>certmatch</b>
-                     This  logs remote SMTP server certificate matching, show-
+                     This logs remote SMTP server certificate matching,  show-
                      ing  the  CN  and  each  subjectAltName  and  which  name
-                     matched.    With  DANE,  logs  matching  of  TLSA  record
+                     matched.   With  DANE,  logs  matching  of  TLSA   record
                      trust-anchor and end-entity certificates.
 
-              <b>cache</b>  This logs session cache operations, showing whether  ses-
-                     sion  caching  is  effective with the remote SMTP server.
-                     Automatically used when reconnecting with the <b>-r</b>  option;
+              <b>cache</b>  This  logs session cache operations, showing whether ses-
+                     sion caching is effective with the  remote  SMTP  server.
+                     Automatically  used when reconnecting with the <b>-r</b> option;
                      rarely needs to be set explicitly.
 
               <b>verbose</b>
                      Enables  verbose  logging  in  the  Postfix  TLS  driver;
                      includes all of peercert..cache and more.
 
-              The default is <b>routine,certmatch</b>. After a  reconnect,  <b>peercert</b>,
+              The  default  is <b>routine,certmatch</b>. After a reconnect, <b>peercert</b>,
               <b>certmatch</b> and <b>verbose</b> are automatically disabled while <b>cache</b> and
               <b>summary</b> are enabled.
 
        <b>-m</b> <i>count</i> (default: <b>5</b>)
-              When the <b>-r</b> <i>delay</i> option is specified, the <b>-m</b> option  determines
-              the  maximum  number  of reconnect attempts to use with a server
-              behind a load balancer, to see  whether  connection  caching  is
-              likely  to  be  effective for this destination.  Some MTAs don't
-              expose the underlying server identity in  their  EHLO  response;
-              with  these servers there will never be more than 1 reconnection
+              When  the <b>-r</b> <i>delay</i> option is specified, the <b>-m</b> option determines
+              the maximum number of reconnect attempts to use  with  a  server
+              behind  a  load  balancer,  to see whether connection caching is
+              likely to be effective for this destination.   Some  MTAs  don't
+              expose  the  underlying  server identity in their EHLO response;
+              with these servers there will never be more than 1  reconnection
               attempt.
 
        <b>-M</b> <i>insecure</i><b>_</b><i>mx</i><b>_</b><i>policy</i> (default: <b>dane</b>)
-              The TLS policy for MX hosts with "secure" TLSA records when  the
-              nexthop  destination  security  level is <b>dane</b>, but the MX record
+              The  TLS policy for MX hosts with "secure" TLSA records when the
+              nexthop destination security level is <b>dane</b>, but  the  MX  record
               was found via an "insecure" MX lookup.  See the <a href="postconf.5.html">main.cf</a> documen-
               tation for smtp_tls_insecure_mx_policy for details.
 
        <b>-o</b> <i>name=value</i>
-              Specify  zero or more times to override the value of the <a href="postconf.5.html">main.cf</a>
-              parameter <i>name</i> with <i>value</i>.  Possible use-cases include  overrid-
-              ing  the  values  of  TLS library parameters, or "<a href="postconf.5.html#myhostname">myhostname</a>" to
+              Specify zero or more times to override the value of the  <a href="postconf.5.html">main.cf</a>
+              parameter  <i>name</i> with <i>value</i>.  Possible use-cases include overrid-
+              ing the values of TLS library  parameters,  or  "<a href="postconf.5.html#myhostname">myhostname</a>"  to
               configure the SMTP EHLO name sent to the remote server.
 
        <b>-p</b> <i>protocols</i> (default: !SSLv2)
-              List of  TLS  protocols  that  posttls-finger  will  exclude  or
+              List  of  TLS  protocols  that  posttls-finger  will  exclude or
               include.  See <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> for details.
 
        <b>-P</b> <i>CApath/</i> (default: none)
-              The  OpenSSL  CApath/  directory  (indexed  via c_rehash(1)) for
+              The OpenSSL CApath/  directory  (indexed  via  c_rehash(1))  for
               remote SMTP server certificate verification.  By default no CAp-
               ath is used and no public CAs are trusted.
 
        <b>-r</b> <i>delay</i>
-              With  a  cacheable  TLS  session, disconnect and reconnect after
+              With a cacheable TLS session,  disconnect  and  reconnect  after
               <i>delay</i> seconds. Report whether the session is re-used. Retry if a
-              new  server  is  encountered, up to 5 times or as specified with
-              the <b>-m</b> option.  By default reconnection is disabled,  specify  a
+              new server is encountered, up to 5 times or  as  specified  with
+              the  <b>-m</b>  option.  By default reconnection is disabled, specify a
               positive delay to enable this behavior.
 
        <b>-s</b> <i>servername</i>
-              The  server  name  to  send  with the TLS Server Name Indication
-              (SNI) extension.  When the server has DANE  TLSA  records,  this
-              parameter  is  ignored and the TLSA base domain is used instead.
-              Otherwise, SNI is not used by default, but  can  be  enabled  by
+              The server name to send with  the  TLS  Server  Name  Indication
+              (SNI)  extension.   When  the server has DANE TLSA records, this
+              parameter is ignored and the TLSA base domain is  used  instead.
+              Otherwise,  SNI  is  not  used by default, but can be enabled by
               specifying the desired value with this option.
 
-       <b>-S</b>     Disable  SMTP;  that  is, connect to an LMTP server. The default
-              port for LMTP over TCP is 24.  Alternative ports  can  specified
-              by  appending "<i>:servicename</i>" or ":<i>portnumber</i>" to the destination
+       <b>-S</b>     Disable SMTP; that is, connect to an LMTP  server.  The  default
+              port  for  LMTP over TCP is 24.  Alternative ports can specified
+              by appending "<i>:servicename</i>" or ":<i>portnumber</i>" to the  destination
               argument.
 
        <b>-t</b> <i>timeout</i> (default: <b>30</b>)
@@ -287,7 +288,7 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
               reading the remote server's 220 banner.
 
        <b>-T</b> <i>timeout</i> (default: <b>30</b>)
-              The  SMTP/LMTP command timeout for EHLO/LHLO, STARTTLS and QUIT.
+              The SMTP/LMTP command timeout for EHLO/LHLO, STARTTLS and QUIT.
 
        <b>-v</b>     Enable verbose Postfix  logging.   Specify  more  than  once  to
               increase the level of verbose logging.
index 02f20fe8913d3963b9dd36d8887fe0eb3d9987d6..a83307fc69fdf11893827d2ae3fc1fdf9fe54fa5 100644 (file)
@@ -45,24 +45,27 @@ SENDMAIL(1)                                                        SENDMAIL(1)
                      ery attempt will be made until  the  mail  is  taken  off
                      hold.
 
-              This   mode   of  operation  is  implemented  by  executing  the
+              <b>#</b>      The  message  is  forced  to expire. See the <a href="postsuper.1.html"><b>postsuper</b>(1)</a>
+                     options <b>-e</b> or <b>-f</b>.
+
+              This  mode  of  operation  is  implemented  by   executing   the
               <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
 
        <b>newaliases</b>
-              Initialize the alias database.  If no input  file  is  specified
-              (with  the  <b>-oA</b>  option,  see  below), the program processes the
-              file(s) specified with the <b><a href="postconf.5.html#alias_database">alias_database</a></b> configuration  parame-
-              ter.   If  no alias database type is specified, the program uses
-              the type specified with the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b>  configuration
+              Initialize  the  alias  database.  If no input file is specified
+              (with the <b>-oA</b> option, see  below),  the  program  processes  the
+              file(s)  specified with the <b><a href="postconf.5.html#alias_database">alias_database</a></b> configuration parame-
+              ter.  If no alias database type is specified, the  program  uses
+              the  type specified with the <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration
               parameter.  This mode of operation is implemented by running the
               <a href="postalias.1.html"><b>postalias</b>(1)</a> command.
 
               Note: it may take a minute or so before an alias database update
-              becomes  visible.  Use the "<b>postfix reload</b>" command to eliminate
+              becomes visible. Use the "<b>postfix reload</b>" command  to  eliminate
               this delay.
 
-       These and other features can be selected by specifying the  appropriate
-       combination  of  command-line  options. Some features are controlled by
+       These  and other features can be selected by specifying the appropriate
+       combination of command-line options. Some features  are  controlled  by
        parameters in the <a href="postconf.5.html"><b>main.cf</b></a> configuration file.
 
        The following options are recognized:
@@ -70,13 +73,13 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-Am</b> (ignored)
 
        <b>-Ac</b> (ignored)
-              Postfix sendmail uses the same configuration file regardless  of
+              Postfix  sendmail uses the same configuration file regardless of
               whether or not a message is an initial submission.
 
        <b>-B</b> <i>body</i><b>_</b><i>type</i>
               The message body MIME type: <b>7BIT</b> or <b>8BITMIME</b>.
 
-       <b>-bd</b>    Go  into  daemon  mode. This mode of operation is implemented by
+       <b>-bd</b>    Go into daemon mode. This mode of operation  is  implemented  by
               executing the "<b>postfix start</b>" command.
 
        <b>-bh</b> (ignored)
@@ -86,8 +89,8 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-bi</b>    Initialize alias database. See the <b>newaliases</b> command above.
 
-       <b>-bl</b>    Go into daemon mode. To accept only local  connections  as  with
-              Sendmail's  <b>-bl</b>  option, specify "<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = loopback</b>" in
+       <b>-bl</b>    Go  into  daemon  mode. To accept only local connections as with
+              Sendmail's <b>-bl</b> option, specify "<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> =  loopback</b>"  in
               the Postfix <a href="postconf.5.html"><b>main.cf</b></a> configuration file.
 
        <b>-bm</b>    Read mail from standard input and arrange for delivery.  This is
@@ -95,17 +98,17 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-bp</b>    List the mail queue. See the <b>mailq</b> command above.
 
-       <b>-bs</b>    Stand-alone  SMTP  server mode. Read SMTP commands from standard
-              input, and write responses to standard output.   In  stand-alone
-              SMTP  server  mode,  mail relaying and other access controls are
-              disabled by default. To enable them,  run  the  process  as  the
+       <b>-bs</b>    Stand-alone SMTP server mode. Read SMTP commands  from  standard
+              input,  and  write responses to standard output.  In stand-alone
+              SMTP server mode, mail relaying and other  access  controls  are
+              disabled  by  default.  To  enable  them, run the process as the
               <b><a href="postconf.5.html#mail_owner">mail_owner</a></b> user.
 
-              This  mode  of  operation is implemented by running the <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
+              This mode of operation is implemented by  running  the  <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
               daemon.
 
-       <b>-bv</b>    Do not collect or deliver a  message.  Instead,  send  an  email
-              report  after  verifying each recipient address.  This is useful
+       <b>-bv</b>    Do  not  collect  or  deliver  a message. Instead, send an email
+              report after verifying each recipient address.  This  is  useful
               for testing address rewriting and routing configurations.
 
               This feature is available in Postfix version 2.1 and later.
@@ -113,58 +116,58 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-C</b> <i>config</i><b>_</b><i>file</i>
 
        <b>-C</b> <i>config</i><b>_</b><i>dir</i>
-              The path name of the Postfix <a href="postconf.5.html"><b>main.cf</b></a>  file,  or  of  its  parent
-              directory.  This  information  is  ignored with Postfix versions
+              The  path  name  of  the  Postfix <a href="postconf.5.html"><b>main.cf</b></a> file, or of its parent
+              directory. This information is  ignored  with  Postfix  versions
               before 2.3.
 
               With Postfix version 3.2 and later, a non-default directory must
-              be  authorized  in  the default <a href="postconf.5.html"><b>main.cf</b></a> file, through the alter-
+              be authorized in the default <a href="postconf.5.html"><b>main.cf</b></a> file,  through  the  alter-
               nate_config_directories  or  <a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a>  parame-
               ters.
 
-              With  all Postfix versions, you can specify a directory pathname
-              with the MAIL_CONFIG environment variable to override the  loca-
+              With all Postfix versions, you can specify a directory  pathname
+              with  the MAIL_CONFIG environment variable to override the loca-
               tion of configuration files.
 
        <b>-F</b> <i>full</i><b>_</b><i>name</i>
-              Set  the  sender  full name. This overrides the NAME environment
+              Set the sender full name. This overrides  the  NAME  environment
               variable, and is used only with messages that have no <b>From:</b> mes-
               sage header.
 
        <b>-f</b> <i>sender</i>
-              Set  the  envelope  sender  address.  This  is the address where
+              Set the envelope sender  address.  This  is  the  address  where
               delivery problems are sent to. With Postfix versions before 2.1,
-              the   <b>Errors-To:</b>  message  header  overrides  the  error  return
+              the  <b>Errors-To:</b>  message  header  overrides  the  error   return
               address.
 
-       <b>-G</b>     Gateway (relay) submission, as opposed to initial  user  submis-
-              sion.   Either do not rewrite addresses at all, or update incom-
-              plete addresses  with  the  domain  information  specified  with
+       <b>-G</b>     Gateway  (relay)  submission, as opposed to initial user submis-
+              sion.  Either do not rewrite addresses at all, or update  incom-
+              plete  addresses  with  the  domain  information  specified with
               <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a></b>.
 
               This option is ignored before Postfix version 2.3.
 
        <b>-h</b> <i>hop</i><b>_</b><i>count</i> (ignored)
-              Hop  count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configuration parameter
+              Hop count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configuration  parameter
               instead.
 
        <b>-I</b>     Initialize alias database. See the <b>newaliases</b> command above.
 
-       <b>-i</b>     When reading a message from standard input, don't treat  a  line
+       <b>-i</b>     When  reading  a message from standard input, don't treat a line
               with only a <b>.</b> character as the end of input.
 
        <b>-L</b> <i>label</i> (ignored)
-              The  logging  label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b> configuration parameter
+              The logging label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b>  configuration  parameter
               instead.
 
        <b>-m</b> (ignored)
               Backwards compatibility.
 
        <b>-N</b> <i>dsn</i> (default: 'delay, failure')
-              Delivery  status  notification   control.   Specify   either   a
+              Delivery   status   notification   control.   Specify  either  a
               comma-separated list with one or more of <b>failure</b> (send notifica-
-              tion when delivery fails), <b>delay</b> (send notification when  deliv-
-              ery  is delayed), or <b>success</b> (send notification when the message
+              tion  when delivery fails), <b>delay</b> (send notification when deliv-
+              ery is delayed), or <b>success</b> (send notification when the  message
               is delivered); or specify <b>never</b> (don't send any notifications at
               all).
 
@@ -174,50 +177,50 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Backwards compatibility.
 
        <b>-oA</b><i>alias</i><b>_</b><i>database</i>
-              Non-default  alias  database. Specify <i>pathname</i> or <i>type</i>:<i>pathname</i>.
+              Non-default alias database. Specify <i>pathname</i>  or  <i>type</i>:<i>pathname</i>.
               See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
 
        <b>-O</b> <i>option=value</i> (ignored)
-              Set the named <i>option</i> to <i>value</i>. Use the equivalent  configuration
+              Set  the named <i>option</i> to <i>value</i>. Use the equivalent configuration
               parameter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
        <b>-o7</b> (ignored)
 
        <b>-o8</b> (ignored)
-              To  send 8-bit or binary content, use an appropriate MIME encap-
+              To send 8-bit or binary content, use an appropriate MIME  encap-
               sulation and specify the appropriate <b>-B</b> command-line option.
 
-       <b>-oi</b>    When reading a message from standard input, don't treat  a  line
+       <b>-oi</b>    When  reading  a message from standard input, don't treat a line
               with only a <b>.</b> character as the end of input.
 
        <b>-om</b> (ignored)
               The sender is never eliminated from alias etc. expansions.
 
        <b>-o</b> <i>x value</i> (ignored)
-              Set  option <i>x</i> to <i>value</i>. Use the equivalent configuration parame-
+              Set option <i>x</i> to <i>value</i>. Use the equivalent configuration  parame-
               ter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
        <b>-r</b> <i>sender</i>
-              Set the envelope sender  address.  This  is  the  address  where
+              Set  the  envelope  sender  address.  This  is the address where
               delivery problems are sent to. With Postfix versions before 2.1,
-              the  <b>Errors-To:</b>  message  header  overrides  the  error   return
+              the   <b>Errors-To:</b>  message  header  overrides  the  error  return
               address.
 
        <b>-R</b> <i>return</i>
-              Delivery  status notification control.  Specify "hdrs" to return
-              only the header when a message bounces, "full" to return a  full
+              Delivery status notification control.  Specify "hdrs" to  return
+              only  the header when a message bounces, "full" to return a full
               copy (the default behavior).
 
               The <b>-R</b> option specifies an upper bound; Postfix will return only
-              the header, when a full copy would exceed the  <a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a>
+              the  header, when a full copy would exceed the <a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a>
               setting.
 
               This option is ignored before Postfix version 2.10.
 
-       <b>-q</b>     Attempt  to deliver all queued mail. This is implemented by exe-
+       <b>-q</b>     Attempt to deliver all queued mail. This is implemented by  exe-
               cuting the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
 
-              Warning: flushing undeliverable mail frequently will  result  in
+              Warning:  flushing  undeliverable mail frequently will result in
               poor delivery performance of all other mail.
 
        <b>-q</b><i>interval</i> (ignored)
@@ -226,21 +229,21 @@ SENDMAIL(1)                                                        SENDMAIL(1)
 
        <b>-qI</b><i>queueid</i>
               Schedule immediate delivery of mail with the specified queue ID.
-              This  option  is  implemented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> com-
+              This option is implemented by executing  the  <a href="postqueue.1.html"><b>postqueue</b>(1)</a>  com-
               mand, and is available with Postfix version 2.4 and later.
 
        <b>-qR</b><i>site</i>
-              Schedule immediate delivery of all mail that is queued  for  the
-              named  <i>site</i>. This option accepts only <i>site</i> names that are eligi-
-              ble for the "fast flush" service, and is implemented by  execut-
+              Schedule  immediate  delivery of all mail that is queued for the
+              named <i>site</i>. This option accepts only <i>site</i> names that are  eligi-
+              ble  for the "fast flush" service, and is implemented by execut-
               ing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.  See <a href="flush.8.html"><b>flush</b>(8)</a> for more information
               about the "fast flush" service.
 
        <b>-qS</b><i>site</i>
-              This command is not implemented. Use the  slower  "<b>sendmail  -q</b>"
+              This  command  is  not implemented. Use the slower "<b>sendmail -q</b>"
               command instead.
 
-       <b>-t</b>     Extract  recipients from message headers. These are added to any
+       <b>-t</b>     Extract recipients from message headers. These are added to  any
               recipients specified on the command line.
 
               With Postfix versions prior to 2.1, this option requires that no
@@ -256,23 +259,23 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               This feature is available in Postfix 2.3 and later.
 
        <b>-XV</b> (Postfix 2.2 and earlier: <b>-V</b>)
-              Variable Envelope Return Path. Given an envelope sender  address
-              of  the  form  <i>owner-listname</i>@<i>origin</i>, each recipient <i>user</i>@<i>domain</i>
+              Variable  Envelope Return Path. Given an envelope sender address
+              of the form <i>owner-listname</i>@<i>origin</i>,  each  recipient  <i>user</i>@<i>domain</i>
               receives mail with a personalized envelope sender address.
 
-              By  default,  the  personalized  envelope  sender   address   is
-              <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>.  The  default <b>+</b> and <b>=</b> charac-
-              ters are configurable with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b>  configu-
+              By   default,   the  personalized  envelope  sender  address  is
+              <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The default <b>+</b> and  <b>=</b>  charac-
+              ters  are configurable with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configu-
               ration parameter.
 
        <b>-XV</b><i>xy</i> (Postfix 2.2 and earlier: <b>-V</b><i>xy</i>)
-              As  <b>-XV</b>,  but  uses  <i>x</i>  and  <i>y</i> as the VERP delimiter characters,
+              As <b>-XV</b>, but uses <i>x</i> and  <i>y</i>  as  the  VERP  delimiter  characters,
               instead of the characters specified with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delim</a>-</b>
               <b><a href="postconf.5.html#default_verp_delimiters">iters</a></b> configuration parameter.
 
        <b>-v</b>     Send an email report of the first delivery attempt (Postfix ver-
-              sions 2.1 and later). Mail delivery always happens in the  back-
-              ground.  When multiple <b>-v</b> options are given, enable verbose log-
+              sions  2.1 and later). Mail delivery always happens in the back-
+              ground. When multiple <b>-v</b> options are given, enable verbose  log-
               ging for debugging purposes.
 
        <b>-X</b> <i>log</i><b>_</b><i>file</i> (ignored)
@@ -280,12 +283,42 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               configuration parameters instead.
 
 <b>SECURITY</b>
-       By design, this program is not set-user (or group) id. However, it must
-       handle data from untrusted, possibly remote, users.   Thus,  the  usual
-       precautions need to be taken against malicious inputs.
+       By design, this program is not set-user (or group) id.  It is  prepared
+       to handle message content from untrusted, possibly remote, users.
+
+       However,  like  most  Postfix programs, this program does not enforce a
+       security policy on its command-line arguments.  Instead, it  relies  on
+       the  UNIX system to enforce access policies based on the effective user
+       and group IDs of the process. Concretely, this means that running Post-
+       fix  commands as root (from sudo or equivalent) on behalf of a non-root
+       user is likely to create privilege escalation opportunities.
+
+       If an application runs any Postfix programs on behalf of users that  do
+       not have normal shell access to Postfix commands, then that application
+       MUST restrict user-specified command-line arguments to avoid  privilege
+       escalation.
+
+       <b>o</b>      Filter  all  command-line  arguments, for example arguments that
+              contain a pathname or that specify  a  database  access  method.
+              These  pathname  checks  must reject user-controlled symlinks or
+              hardlinks to sensitive files, and must not be vulnerable to TOC-
+              TOU race attacks.
+
+       <b>o</b>      Disable  command  options  processing  for all command arguments
+              that contain user-specified data. For example, the Postfix <a href="sendmail.1.html"><b>send-</b></a>
+              <a href="sendmail.1.html"><b>mail</b>(1)</a> command line MUST be structured as follows:
+
+                  <b>/path/to/sendmail</b> <i>system-arguments</i> <b>--</b> <i>user-arguments</i>
+
+              Here,  the  "<b>--</b>"  disables  command  option  processing  for all
+              <i>user-arguments</i> that follow.
+
+              Without the "<b>--</b>", a malicious user could  enable  Postfix  <a href="sendmail.1.html"><b>send-</b></a>
+              <a href="sendmail.1.html"><b>mail</b>(1)</a>  command  options,  by  specifying an email address that
+              starts with "<b>-</b>".
 
 <b>DIAGNOSTICS</b>
-       Problems  are  logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>, and to the standard
+       Problems are logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>, and to  the  standard
        error stream.
 
 <b>ENVIRONMENT</b>
@@ -299,12 +332,12 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Enable debugging with an external command, as specified with the
               <b><a href="postconf.5.html#debugger_command">debugger_command</a></b> configuration parameter.
 
-       <b>NAME</b>   The  sender full name. This is used only with messages that have
+       <b>NAME</b>   The sender full name. This is used only with messages that  have
               no <b>From:</b> message header. See also the <b>-F</b> option above.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to  this  pro-
-       gram.   The  text  below  provides  only a parameter summary. See <a href="postconf.5.html"><b>post-</b></a>
+       The  following  <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant to this pro-
+       gram.  The text below provides only  a  parameter  summary.  See  <a href="postconf.5.html"><b>post-</b></a>
        <a href="postconf.5.html"><b>conf</b>(5)</a> for more details including examples.
 
 <b>COMPATIBILITY CONTROLS</b>
@@ -315,7 +348,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               line endings from &lt;CR&gt;&lt;LF&gt; into UNIX format (&lt;LF&gt;).
 
 <b>TROUBLE SHOOTING CONTROLS</b>
-       The  <a href="DEBUG_README.html">DEBUG_README</a>  file gives examples of how to troubleshoot a Postfix
+       The <a href="DEBUG_README.html">DEBUG_README</a> file gives examples of how to troubleshoot  a  Postfix
        system.
 
        <b><a href="postconf.5.html#debugger_command">debugger_command</a> (empty)</b>
@@ -323,13 +356,15 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               invoked with the -D option.
 
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in verbose logging level when a remote client or
-              server matches a pattern in the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
+              The increment in verbose logging level when a  nexthop  destina-
+              tion,  remote client or server name or network address matches a
+              pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of remote client or  server  hostname  or  network
-              address  patterns  that  cause  the  verbose  logging  level  to
-              increase by the amount specified in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
+              Optional list of nexthop destination, remote  client  or  server
+              name  or  network  address  patterns that, if matched, cause the
+              verbose logging level to increase by  the  amount  specified  in
+              $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
 <b>ACCESS CONTROLS</b>
        Available in Postfix version 2.2 and later:
@@ -341,13 +376,13 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               List of users who are authorized to view the queue.
 
        <b><a href="postconf.5.html#authorized_submit_users">authorized_submit_users</a> (<a href="DATABASE_README.html#types">static</a>:anyone)</b>
-              List of users who are authorized to submit mail with  the  <a href="sendmail.1.html"><b>send-</b></a>
+              List  of  users who are authorized to submit mail with the <a href="sendmail.1.html"><b>send-</b></a>
               <a href="sendmail.1.html"><b>mail</b>(1)</a> command (and with the privileged <a href="postdrop.1.html"><b>postdrop</b>(1)</a> helper com-
               mand).
 
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a> (50000)</b>
-              The maximal amount of original message text that is  sent  in  a
+              The  maximal  amount  of original message text that is sent in a
               non-delivery notification.
 
        <b><a href="postconf.5.html#fork_attempts">fork_attempts</a> (5)</b>
@@ -361,11 +396,11 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               in the primary message headers.
 
        <b><a href="postconf.5.html#queue_run_delay">queue_run_delay</a> (300s)</b>
-              The time between <a href="QSHAPE_README.html#deferred_queue">deferred queue</a>  scans  by  the  queue  manager;
+              The  time  between  <a href="QSHAPE_README.html#deferred_queue">deferred  queue</a>  scans by the queue manager;
               prior to Postfix 2.4 the default value was 1000s.
 
 <b>FAST FLUSH CONTROLS</b>
-       The  <a href="ETRN_README.html">ETRN_README</a> file describes configuration and operation details for
+       The <a href="ETRN_README.html">ETRN_README</a> file describes configuration and operation details  for
        the Postfix "fast flush" service.
 
        <b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
@@ -373,26 +408,26 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               tion logfiles with mail that is queued to those destinations.
 
 <b>VERP CONTROLS</b>
-       The  <a href="VERP_README.html">VERP_README</a>  file describes configuration and operation details of
+       The <a href="VERP_README.html">VERP_README</a> file describes configuration and operation  details  of
        Postfix support for variable envelope return path addresses.
 
        <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
               The two default VERP delimiter characters.
 
        <b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
-              The characters Postfix accepts as VERP delimiter  characters  on
+              The  characters  Postfix accepts as VERP delimiter characters on
               the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line and in SMTP commands.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
-              The  alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are updated with
+              The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are updated  with
               "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
 
        <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
               The location of all postfix administrative commands.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of the Postfix <a href="postconf.5.html">main.cf</a> and  <a href="master.5.html">master.cf</a>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#daemon_directory">daemon_directory</a> (see 'postconf -d' output)</b>
@@ -403,46 +438,46 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               and <a href="postmap.1.html"><b>postmap</b>(1)</a> commands.
 
        <b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
-              The  time  after which the sender receives a copy of the message
+              The time after which the sender receives a copy of  the  message
               headers of mail that is still queued.
 
        <b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
-              The list of environment parameters  that  a  privileged  Postfix
-              process  will  import  from  a  non-Postfix  parent  process, or
+              The  list  of  environment  parameters that a privileged Postfix
+              process will  import  from  a  non-Postfix  parent  process,  or
               name=value environment overrides.
 
        <b><a href="postconf.5.html#mail_owner">mail_owner</a> (postfix)</b>
-              The UNIX system account that owns the  Postfix  queue  and  most
+              The  UNIX  system  account  that owns the Postfix queue and most
               Postfix daemon processes.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
               The location of the Postfix top-level queue directory.
 
        <b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
-              Don't  rewrite  message  headers from remote clients at all when
-              this parameter is empty; otherwise, rewrite message headers  and
+              Don't rewrite message headers from remote clients  at  all  when
+              this  parameter is empty; otherwise, rewrite message headers and
               append the specified domain name to incomplete addresses.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A  prefix  that  is  prepended  to  the  process  name in syslog
+              A prefix that  is  prepended  to  the  process  name  in  syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Postfix 3.2 and later:
 
        <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a> (empty)</b>
               A list of non-default Postfix configuration directories that may
-              be  specified with "-c <a href="postconf.5.html#config_directory">config_directory</a>" on the command line (in
-              the case of <a href="sendmail.1.html"><b>sendmail</b>(1)</a>, with  the  "-C"  option),  or  via  the
+              be specified with "-c <a href="postconf.5.html#config_directory">config_directory</a>" on the command line  (in
+              the  case  of  <a href="sendmail.1.html"><b>sendmail</b>(1)</a>,  with  the  "-C" option), or via the
               MAIL_CONFIG environment parameter.
 
        <b><a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a> (empty)</b>
-              An  optional  list of non-default Postfix configuration directo-
-              ries; these directories belong to additional  Postfix  instances
-              that  share  the Postfix executable files and documentation with
-              the default Postfix instance, and  that  are  started,  stopped,
+              An optional list of non-default Postfix  configuration  directo-
+              ries;  these  directories belong to additional Postfix instances
+              that share the Postfix executable files and  documentation  with
+              the  default  Postfix  instance,  and that are started, stopped,
               etc., together with the default Postfix instance.
 
 <b>FILES</b>
@@ -463,7 +498,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        syslogd(8), system logging
 
 <b>README_FILES</b>
-       Use  "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to locate
+       Use "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to  locate
        this information.
        <a href="DEBUG_README.html">DEBUG_README</a>, Postfix debugging howto
        <a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
index f79f4e04e00506b8d56d1143e7cfcce919881ee9..3c20579eff8e3299eb03eed9e34b4c540817d138 100644 (file)
@@ -567,7 +567,7 @@ SMTP(8)                                                                SMTP(8)
               for   the   "fingerprint"  TLS  security  level  (<b><a href="postconf.5.html#smtp_tls_security_level">smtp_tls_secu</a>-</b>
               <b><a href="postconf.5.html#smtp_tls_security_level">rity_level</a></b> = fingerprint).
 
-       <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> (md5)</b>
+       <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> (see 'postconf -d' output)</b>
               The message digest  algorithm  used  to  construct  remote  SMTP
               server certificate fingerprints.
 
@@ -826,12 +826,12 @@ SMTP(8)                                                                SMTP(8)
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The increment in verbose logging level when a next-hop  destina-
+              The increment in verbose logging level when a  nexthop  destina-
               tion,  remote client or server name or network address matches a
               pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of next-hop destination, remote client  or  server
+              Optional list of nexthop destination, remote  client  or  server
               name  or  network  address  patterns that, if matched, cause the
               verbose logging level to increase by  the  amount  specified  in
               $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
index b81b864cdf63060e3d157fbd2cbd73b23f21668b..1258376b7700e6b6ef890b4bf63b9904bd581cd8 100644 (file)
@@ -516,7 +516,7 @@ SMTPD(8)                                                              SMTPD(8)
 
        Available in Postfix version 2.5 and later:
 
-       <b><a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> (md5)</b>
+       <b><a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> (see 'postconf -d' output)</b>
               The  message  digest  algorithm   to   construct   remote   SMTP
               client-certificate   fingerprints  or  public  key  fingerprints
               (Postfix  2.9  and  later)  for  <b><a href="postconf.5.html#check_ccert_access">check_ccert_access</a></b>   and   <b>per-</b>
@@ -675,13 +675,15 @@ SMTPD(8)                                                              SMTPD(8)
        or debugger.
 
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in verbose logging level when a remote client or
-              server matches a pattern in the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
+              The  increment  in verbose logging level when a nexthop destina-
+              tion, remote client or server name or network address matches  a
+              pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of remote client or  server  hostname  or  network
-              address  patterns  that  cause  the  verbose  logging  level  to
-              increase by the amount specified in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
+              Optional  list  of  nexthop destination, remote client or server
+              name or network address patterns that,  if  matched,  cause  the
+              verbose  logging  level  to  increase by the amount specified in
+              $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
               The recipient of postmaster notifications  about  mail  delivery
index 9529c20c1a4f68fd13857e8306ebdb7a6d2deda1..93995eed66424a93309d4e4399e1df8d87041529 100644 (file)
@@ -102,11 +102,12 @@ certificate block.  If you specify \fB\-F \fICAfile\fR or
 \fB\-P \fICApath\fR, the OpenSSL library may augment the chain with
 missing issuer certificates.  To see the actual chain sent by the
 remote SMTP server leave \fICAfile\fR and \fICApath\fR unset.
-.IP "\fB\-d \fImdalg\fR (default: \fBsha1\fR)"
+.IP "\fB\-d \fImdalg\fR (default: \fB$smtp_tls_fingerprint_digest\fR)"
 The message digest algorithm to use for reporting remote SMTP server
 fingerprints and matching against user provided certificate
 fingerprints (with DANE TLSA records the algorithm is specified
-in the DNS).
+in the DNS).  In Postfix versions prior to 3.6, the default value
+was "sha1".
 .IP "\fB\-f\fR"
 Lookup the associated DANE TLSA RRset even when a hostname is not an
 alias and its address records lie in an unsigned zone.  See
index e52861b1b736499610ab6a77c25029f5e9940c87..3722a178732d852f3732ee2d0e08de80e31c448f 100644 (file)
@@ -45,6 +45,9 @@ selected for delivery.
 .IP \fB!\fR
 The message is in the \fBhold\fR queue, i.e. no further delivery
 attempt will be made until the mail is taken off hold.
+.IP \fB#\fR
+The message is forced to expire. See the \fBpostsuper\fR(1)
+options \fB\-e\fR or \fB\-f\fR.
 .RE
 .IP
 This mode of operation is implemented by executing the
@@ -258,10 +261,43 @@ Log mailer traffic. Use the \fBdebug_peer_list\fR and
 .nf
 .ad
 .fi
-By design, this program is not set\-user (or group) id. However,
-it must handle data from untrusted, possibly remote, users.
-Thus, the usual precautions need to be taken against malicious
-inputs.
+By design, this program is not set\-user (or group) id.
+It is prepared to handle message content from untrusted,
+possibly remote, users.
+
+However, like most Postfix programs, this program does not
+enforce a security policy on its command\-line arguments.
+Instead, it relies on the UNIX system to enforce access
+policies based on the effective user and group IDs of the
+process. Concretely, this means that running Postfix commands
+as root (from sudo or equivalent) on behalf of a non\-root
+user is likely to create privilege escalation opportunities.
+
+If an application runs any Postfix programs on behalf of
+users that do not have normal shell access to Postfix
+commands, then that application MUST restrict user\-specified
+command\-line arguments to avoid privilege escalation.
+.IP \(bu
+Filter all command\-line arguments, for example arguments
+that contain a pathname or that specify a database access
+method. These pathname checks must reject user\-controlled
+symlinks or hardlinks to sensitive files, and must not be
+vulnerable to TOCTOU race attacks.
+.IP \(bu
+Disable command options processing for all command arguments
+that contain user\-specified data. For example, the Postfix
+\fBsendmail\fR(1) command line MUST be structured as follows:
+
+.nf
+    \fB/path/to/sendmail\fR \fIsystem\-arguments\fR \fB\-\-\fR \fIuser\-arguments\fR
+.fi
+
+Here, the "\fB\-\-\fR" disables command option processing for
+all \fIuser\-arguments\fR that follow.
+.IP
+Without the "\fB\-\-\fR", a malicious user could enable Postfix
+\fBsendmail\fR(1) command options, by specifying an email
+address that starts with "\fB\-\fR".
 .SH DIAGNOSTICS
 .ad
 .fi
@@ -312,12 +348,13 @@ Postfix system.
 The external command to execute when a Postfix daemon program is
 invoked with the \-D option.
 .IP "\fBdebug_peer_level (2)\fR"
-The increment in verbose logging level when a remote client or
-server matches a pattern in the debug_peer_list parameter.
+The increment in verbose logging level when a nexthop destination,
+remote client or server name or network address matches a pattern
+given with the debug_peer_list parameter.
 .IP "\fBdebug_peer_list (empty)\fR"
-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.
+Optional list of nexthop destination, remote client or server
+name or network address patterns that, if matched, cause the verbose
+logging level to increase by the amount specified in $debug_peer_level.
 .SH "ACCESS CONTROLS"
 .na
 .nf
index db912da018c2306b9b0eaf59b733e0a45586a1f3..9f7e8a7824e523926b9d4cfe783416e14de21152 100644 (file)
@@ -3212,7 +3212,7 @@ 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)
+.SH lmtp_tls_fingerprint_digest (default: see "postconf \-d" output)
 The LMTP\-specific version of the smtp_tls_fingerprint_digest
 configuration parameter.  See there for details.
 .PP
@@ -3412,6 +3412,15 @@ The fingerprint digest algorithm is configurable via the
 smtpd_tls_fingerprint_digest parameter (hard\-coded as md5 prior to
 Postfix version 2.5).
 .br
+The default algorithm is \fBsha256\fR with Postfix >= 3.6
+and the \fBcompatibility_level\fR set to 3 or higher. With Postfix
+<= 3.5, the default algorithm is \fBmd5\fR.  The best\-practice
+algorithm is now \fBsha256\fR. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre\-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.
+.br
 .IP "\fBpermit_tls_all_clientcerts \fR"
 Append the domain name in $myorigin or $mydomain when the
 remote SMTP client TLS certificate is successfully verified, regardless of
@@ -5910,6 +5919,15 @@ 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
+The default algorithm is \fBsha256\fR with Postfix >= 3.6
+and the \fBcompatibility_level\fR set to 3 or higher. With Postfix
+<= 3.5, the default algorithm is \fBmd5\fR.  The best\-practice
+algorithm is now \fBsha256\fR. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre\-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.
+.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.
 the name of the user or host:
@@ -5929,10 +5947,6 @@ For more fine\-grained control, use check_ccert_access to select
 an appropriate \fBaccess\fR(5) policy for each client.
 See RESTRICTION_CLASS_README.
 .PP
-\fBNote:\fR Postfix 2.9.0-2.9.5 computed the public key
-fingerprint incorrectly. To use public\-key fingerprints, upgrade
-to Postfix 2.9.6 or later.
-.PP
 This feature is available with Postfix version 2.2.
 .SH relay_destination_concurrency_limit (default: $default_destination_concurrency_limit)
 The maximal number of parallel deliveries to the same destination
@@ -8079,6 +8093,10 @@ is a message digest of the server certificate (or public key). The
 digest algorithm is selected via the \fBsmtp_tls_fingerprint_digest\fR
 parameter.
 .PP
+The colons between each pair of nibbles in the fingerprint value
+are optional (Postfix >= 3.6). These were required in earlier
+Postfix releases.
+.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
@@ -8098,10 +8116,10 @@ another, and both keys are trusted just prior to the transition.
 .ft C
 relayhost = [mailhub.example.com]
 smtp_tls_security_level = fingerprint
-smtp_tls_fingerprint_digest = md5
+smtp_tls_fingerprint_digest = sha256
 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
+    cd:fc:d8:db:f8:c4:82:96:6c:...:28:71:e8:f5:8d:a5:0d:9b:d4:a6
+    dd:5c:ef:f5:c3:bc:64:25:36:...:99:36:06:ce:40:ef:de:2e:ad:a4
 .fi
 .ad
 .ft R
@@ -8116,7 +8134,7 @@ As in the example above, we show two matching fingerprints:
 .ft C
 /etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
-    smtp_tls_fingerprint_digest = md5
+    smtp_tls_fingerprint_digest = sha256
 .fi
 .ad
 .ft R
@@ -8128,15 +8146,15 @@ As in the example above, we show two matching fingerprints:
 .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
+        match=51:e9:af:2e:1e:40:1f:...:64:0a:30:35:2d:09:16:31:5a:eb:82:76
+        match=b6:b4:72:34:e2:59:cd:...:c2:ca:63:0d:4d:cc:2c:7d:84:de:e6:2f
 .fi
 .ad
 .ft R
 .in -4
 .PP
 This feature is available in Postfix 2.5 and later.
-.SH smtp_tls_fingerprint_digest (default: md5)
+.SH smtp_tls_fingerprint_digest (default: see "postconf \-d" output)
 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
@@ -8148,18 +8166,19 @@ 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 (or public/private key\-pair) 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.
+The default algorithm is \fBsha256\fR with Postfix >= 3.6
+and the \fBcompatibility_level\fR set to 3 or higher. With Postfix
+<= 3.5, the default algorithm is \fBmd5\fR.
 .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.
+The best\-practice algorithm is now \fBsha256\fR. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre\-image" attacks
+against the older algorithms, their use in this context, though not
+recommended, is still likely 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.
+Postfix.  You'll likely find support for md5, sha1, sha256 and sha512.
 .PP
 To find the fingerprint of a specific certificate file, with a
 specific digest algorithm, run:
@@ -8181,8 +8200,8 @@ For example:
 .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
+$ openssl x509 \-noout \-fingerprint \-sha256 \-in cert.pem
+SHA256 Fingerprint=D4:6A:AB:19:24:...:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
 .fi
 .ad
 .ft R
@@ -8196,36 +8215,19 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint.
 .PP
-The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used.
+The actual command to transform the key to DER format depends on the
+version of OpenSSL used. As of OpenSSL 1.0.0, the "pkey" command supports
+all key types.
 .sp
 .in +4
 .nf
 .na
 .ft C
-# OpenSSL 1.0 with all certificates and SHA\-1 fingerprints.
+# OpenSSL >= 1.0 with SHA\-256 fingerprints.
 $ openssl x509 \-in cert.pem \-noout \-pubkey |
     openssl pkey \-pubin \-outform DER |
-    openssl dgst \-sha1 \-c
-(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-.fi
-.ad
-.ft R
-.in -4
-.sp
-.in +4
-.nf
-.na
-.ft C
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 \-in cert.pem \-noout \-pubkey |
-    openssl rsa \-pubin \-outform DER |
-    openssl dgst \-md5 \-c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
+    openssl dgst \-sha256 \-c
+(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:...:fc:09:1a:61:98:b5:bc:7c:60:58
 .fi
 .ad
 .ft R
@@ -8235,10 +8237,6 @@ The Postfix SMTP server and client log the peer (leaf) certificate
 fingerprint and public key fingerprint when the TLS loglevel is 2 or
 higher.
 .PP
-\fBNote:\fR Postfix 2.9.0-2.9.5 computed the public key
-fingerprint incorrectly. To use public\-key fingerprints, upgrade
-to Postfix 2.9.6 or later.
-.PP
 This feature is available in Postfix 2.5 and later.
 .SH smtp_tls_force_insecure_host_tlsa_lookup (default: no)
 Lookup the associated DANE TLSA RRset even when a hostname is
@@ -8682,8 +8680,12 @@ Example:
 .ft C
 /etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
-    # Postfix 2.5 and later
-    smtp_tls_fingerprint_digest = md5
+    # Postfix 2.5 and later.
+    #
+    # The default digest is sha256 with Postfix >= 3.6 and
+    # compatibility level >= 3.
+    #
+    smtp_tls_fingerprint_digest = sha256
 .fi
 .ad
 .ft R
@@ -8701,8 +8703,8 @@ Example:
     [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
+        match=b6:b4:72:34:e2:59:cd:...:c2:ca:63:0d:4d:cc:2c:7d:84:de:e6:2f
+        match=51:e9:af:2e:1e:40:1f:...:64:0a:30:35:2d:09:16:31:5a:eb:82:76
 .fi
 .ad
 .ft R
@@ -9532,6 +9534,14 @@ Postfix version 2.5).  This feature requires "smtpd_tls_ask_ccert
 = yes" and is available with Postfix version
 2.2 and later.
 .br
+The default algorithm is \fBsha256\fR with Postfix >= 3.6
+and the \fBcompatibility_level\fR set to 3 or higher. With Postfix
+<= 3.5, the default algorithm is \fBmd5\fR.  The best\-practice
+algorithm is now \fBsha256\fR. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre\-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.
 .br
 Alternatively, check_ccert_access accepts an explicit search
 order (Postfix 3.5 and later). The default search order as described
@@ -9639,6 +9649,15 @@ smtpd_tls_fingerprint_digest parameter (hard\-coded as md5 prior to
 Postfix version 2.5).  This feature requires "smtpd_tls_ask_ccert
 = yes" and is available with Postfix version 2.2 and later.
 .br
+The default algorithm is \fBsha256\fR with Postfix >= 3.6
+and the \fBcompatibility_level\fR set to 3 or higher. With Postfix
+<= 3.5, the default algorithm is \fBmd5\fR.  The best\-practice
+algorithm is now \fBsha256\fR. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre\-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.
+.br
 .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
@@ -11852,6 +11871,13 @@ This feature is available in Postfix 2.2 and later.
 File with DH parameters that the Postfix SMTP server should
 use with non\-export EDH ciphers.
 .PP
+The best\-practice choice of parameters uses a 2048\-bit prime.  This is fine,
+despite the historical "1024" in the parameter name.  Do not be tempted to use
+much larger values, performance degrades quickly, and you may also cease to
+interoperate with some mainstream SMTP clients.  As of Postfix 3.1, the
+compiled\-in default prime is 2048\-bits, and it is not strictly necessary,
+though perhaps somewhat beneficial to generate custom DH parameters.
+.PP
 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 commands:
@@ -11860,9 +11886,11 @@ set of parameters with something like the following commands:
 .nf
 .na
 .ft C
-openssl dhparam \-out /etc/postfix/dh512.pem 512
-openssl dhparam \-out /etc/postfix/dh1024.pem 1024
 openssl dhparam \-out /etc/postfix/dh2048.pem 2048
+openssl dhparam \-out /etc/postfix/dh1024.pem 1024
+# As of Postfix 3.6, export\-grade 512\-bit DH parameters are no longer
+# supported or needed.
+openssl dhparam \-out /etc/postfix/dh512.pem 512
 .fi
 .ad
 .ft R
@@ -11897,6 +11925,9 @@ use with export\-grade EDH ciphers.  The default SMTP server cipher
 grade is "medium" with Postfix releases after the middle of 2015,
 and as a result export\-grade cipher suites are by default not used.
 .PP
+With Postfix >= 3.6 export\-grade Diffie\-Hellman key exchange
+is no longer supported, and this parameter is silently ignored.
+.PP
 See also the discussion under the smtpd_tls_dh1024_param_file
 configuration parameter.
 .PP
@@ -11959,32 +11990,32 @@ This feature is available in Postfix 2.6 and later, when Postfix is
 compiled and linked with OpenSSL 1.0.0 or later.
 .SH smtpd_tls_eecdh_grade (default: see "postconf \-d" output)
 The Postfix SMTP server security grade for ephemeral elliptic\-curve
-Diffie\-Hellman (EECDH) key exchange.
+Diffie\-Hellman (EECDH) key exchange.   As of Postfix 3.6, the value of
+this parameter is always ignored, and Postfix behaves as though th
+\fBauto\fR value (described below) was chosen.
 .PP
 The available choices are:
+.IP "\fBauto\fR"
+Use the most preferred curve that is
+supported by both the client and the server.  This setting requires
+Postfix >= 3.2 compiled and linked with OpenSSL >= 1.0.2.  This
+is the default setting under the above conditions (and the only
+setting used with Postfix >= 3.6).
+.br
 .IP "\fBnone\fR"
 Don't use EECDH. Ciphers based on EECDH key
 exchange will be disabled. This is the default in Postfix versions
 2.6 and 2.7.
 .br
 .IP "\fBstrong\fR"
-Use EECDH with approximately 128
-bits of security at a reasonable computational cost. This is the
-current best\-practice trade\-off between security and computational
-efficiency. This is the default in Postfix version 2.8 and later.
+Use EECDH with approximately 128 bits of
+security at a reasonable computational cost. This is the default in
+Postfix versions 2.8-3.5.
 .br
 .IP "\fBultra\fR"
 Use EECDH with approximately 192 bits of
 security at computational cost that is approximately twice as high
-as 128 bit strength ECC. Barring significant progress in attacks on
-elliptic curve crypto\-systems, the "strong" curve is sufficient for most
-users.
-.br
-.IP "\fBauto\fR"
-Use the most preferred curve that is
-supported by both the client and the server.  This setting requires
-Postfix >= 3.2 compiled and linked with OpenSSL >= 1.0.2.  This
-is the default setting under the above conditions.
+as 128 bit strength ECC.
 .br
 .br
 .PP
@@ -12032,22 +12063,24 @@ 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 to construct remote SMTP
-client\-certificate
-fingerprints or public key fingerprints (Postfix 2.9 and later)
-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.
+.SH smtpd_tls_fingerprint_digest (default: see "postconf \-d" output)
+The message digest algorithm to construct remote SMTP client\-certificate
+fingerprints or public key fingerprints (Postfix 2.9 and later) for
+\fBcheck_ccert_access\fR and \fBpermit_tls_clientcerts\fR.
+.PP
+The default algorithm is \fBsha256\fR with Postfix >= 3.6
+and the \fBcompatibility_level\fR set to 3 or higher. With Postfix
+<= 3.5, the default algorithm is \fBmd5\fR.
 .PP
-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.
+The best\-practice algorithm is now \fBsha256\fR. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre\-image" attacks
+against the older algorithms, their use in this context, though not
+recommended, is still likely 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.
+Postfix.  You'll likely find support for md5, sha1, sha256 and sha512.
 .PP
 To find the fingerprint of a specific certificate file, with a
 specific digest algorithm, run:
@@ -12069,8 +12102,8 @@ For example:
 .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
+$ openssl x509 \-noout \-fingerprint \-sha256 \-in cert.pem
+SHA256 Fingerprint=D4:6A:AB:19:24:...:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
 .fi
 .ad
 .ft R
@@ -12084,57 +12117,33 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint.
 .PP
-The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used.
+Example:
 .sp
 .in +4
 .nf
 .na
 .ft C
-# OpenSSL 1.0 with all certificates and SHA\-1 fingerprints.
 $ openssl x509 \-in cert.pem \-noout \-pubkey |
     openssl pkey \-pubin \-outform DER |
-    openssl dgst \-sha1 \-c
+    openssl dgst \-sha256 \-c
 (stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
 .fi
 .ad
 .ft R
 .in -4
-.sp
-.in +4
-.nf
-.na
-.ft C
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 \-in cert.pem \-noout \-pubkey |
-    openssl rsa \-pubin \-outform DER |
-    openssl dgst \-md5 \-c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
-.fi
-.ad
-.ft R
-.in -4
 .PP
 The Postfix SMTP server and client log the peer (leaf) certificate
 fingerprint and public key fingerprint when the TLS loglevel is 2 or
 higher.
 .PP
-\fBNote:\fR Postfix 2.9.0-2.9.5 computed the public key
-fingerprint incorrectly. To use public\-key fingerprints, upgrade
-to Postfix 2.9.6 or later.
-.PP
-Example: client\-certificate access table, with sha1 fingerprints:
+Example: client\-certificate access table, with sha256 fingerprints:
 .sp
 .in +4
 .nf
 .na
 .ft C
 /etc/postfix/main.cf:
-    smtpd_tls_fingerprint_digest = sha1
+    smtpd_tls_fingerprint_digest = sha256
     smtpd_client_restrictions =
         check_ccert_access hash:/etc/postfix/access,
         reject
@@ -12146,9 +12155,9 @@ Example: client\-certificate access table, with sha1 fingerprints:
 .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
+    AF:88:7C:AD:51:95:6F:36:96:...: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
+    85:16:78:FD:73:6E:CE:70:E0:...:5F:0D:3C:C8:6D:C4:2C:24:59:E1
         permit_auth_destination
 .fi
 .ad
@@ -13551,6 +13560,9 @@ for further details.  The default SMTP server cipher grade is
 "medium" with Postfix releases after the middle of 2015, and as a
 result export\-grade cipher suites are by default not used.
 .PP
+With Postfix >= 3.6 export\-grade Diffie\-Hellman key exchange
+is no longer supported, and this parameter is silently ignored.
+.PP
 This feature is available in Postfix 2.8 and later.
 .SH tlsproxy_tls_dkey_file (default: $smtpd_tls_dkey_file)
 File with the Postfix \fBtlsproxy\fR(8) server DSA private key in PEM
index 1aaae63d321f0d79169c1604741adeda49cc3411..697f0f6536f82209add0756ca06cdd36973e783f 100644 (file)
@@ -527,7 +527,7 @@ Available in Postfix version 2.5 and later:
 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"
+.IP "\fBsmtp_tls_fingerprint_digest (see 'postconf -d' output)\fR"
 The message digest algorithm used to construct remote SMTP server
 certificate fingerprints.
 .PP
@@ -744,11 +744,11 @@ used for DNS lookups.
 .ad
 .fi
 .IP "\fBdebug_peer_level (2)\fR"
-The increment in verbose logging level when a next\-hop destination,
+The increment in verbose logging level when a nexthop destination,
 remote client or server name or network address matches a pattern
 given with the debug_peer_list parameter.
 .IP "\fBdebug_peer_list (empty)\fR"
-Optional list of next\-hop destination, remote client or server
+Optional list of nexthop destination, remote client or server
 name or network address patterns that, if matched, cause the verbose
 logging level to increase by the amount specified in $debug_peer_level.
 .IP "\fBerror_notice_recipient (postmaster)\fR"
index d7f65af0906323f3a3038badfc69e70a018cba75..b646af00e3bc5880ad1b39f4ceaa972dec8b5f95 100644 (file)
@@ -470,11 +470,10 @@ 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 to construct remote SMTP
-client\-certificate
-fingerprints or public key fingerprints (Postfix 2.9 and later)
-for \fBcheck_ccert_access\fR and \fBpermit_tls_clientcerts\fR.
+.IP "\fBsmtpd_tls_fingerprint_digest (see 'postconf -d' output)\fR"
+The message digest algorithm to construct remote SMTP client\-certificate
+fingerprints or public key fingerprints (Postfix 2.9 and later) for
+\fBcheck_ccert_access\fR and \fBpermit_tls_clientcerts\fR.
 .PP
 Available in Postfix version 2.6 and later:
 .IP "\fBsmtpd_tls_protocols (!SSLv2, !SSLv3)\fR"
@@ -611,12 +610,13 @@ Postfix mail system. The methods vary from making the software log
 a lot of detail, to running some daemon processes under control of
 a call tracer or debugger.
 .IP "\fBdebug_peer_level (2)\fR"
-The increment in verbose logging level when a remote client or
-server matches a pattern in the debug_peer_list parameter.
+The increment in verbose logging level when a nexthop destination,
+remote client or server name or network address matches a pattern
+given with the debug_peer_list parameter.
 .IP "\fBdebug_peer_list (empty)\fR"
-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.
+Optional list of nexthop destination, remote client or server
+name or network address patterns that, if matched, cause the verbose
+logging level to increase by the amount specified in $debug_peer_level.
 .IP "\fBerror_notice_recipient (postmaster)\fR"
 The recipient of postmaster notifications about mail delivery
 problems that are caused by policy, resource, software or protocol
index 291979d982d72759ef56cd4470555fbceaf1afa4..a6b027f60fcf1132310782058e66cd93617af40c 100644 (file)
@@ -72,6 +72,15 @@ setting relay_domains=$mydestination </a> </p>
 <li> <p> <a href="#smtputf8_enable"> Using backwards-compatible
 default setting smtputf8_enable=no</a> </p>
 
+<li> <p> <a href="#smtpd_digest"> Using backwards-compatible
+default setting smtpd_tls_fingerprint_digest=md5</a> </p>
+
+<li> <p> <a href="#smtp_digest"> Using backwards-compatible
+default setting smtp_tls_fingerprint_digest=md5</a> </p>
+
+<li> <p> <a href="#smtp_digest"> Using backwards-compatible
+default setting lmtp_tls_fingerprint_digest=md5</a> </p>
+
 </ul>
 
 <p> If such a message is logged in the context of a legitimate
@@ -327,7 +336,7 @@ explicit list of domain names. </p>
 <h2> <a name="smtputf8_enable"> Using backwards-compatible default
 setting smtputf8_enable=no</a> </h2>
 
-<p> The smtputf8_enable default value has changed from "no" to "yes.
+<p> The smtputf8_enable default value has changed from "no" to "yes".
 With the new "yes" setting, the Postfix SMTP server rejects non-ASCII
 addresses from clients that don't request SMTPUTF8 support, after
 Postfix is updated from an older version. The backwards-compatibility
@@ -366,6 +375,92 @@ in main.cf:
 </pre>
 </blockquote>
 
+<h2> <a name="smtpd_digest"> Using backwards-compatible
+default setting smtpd_tls_fingerprint_digest=md5</a> </h2>
+
+<p> The smtpd_tls_fingerprint_digest default value has changed from
+"md5" to "sha256".  With the new "sha256" setting, the Postfix SMTP
+server avoids using the deprecated "md5" algorithm and computes a more
+secure digest of the client certificate.  </p>
+
+<p> If you're using the default "md5" setting, or even an explicit
+"sha1" (also deprecated) setting, you should consider switching to
+"sha256".  This will require updating any associated lookup table keys
+with the "sha256" digests of the expected client certificate or public
+key.  </p>
+
+<p> As long as the smtpd_tls_fingerprint_digest parameter is left at its
+implicit default value, and the compatibility_level setting is less than
+3, Postfix logs a warning each time a client certificate or public key
+fingerprint is (potentially) used for access control: </p>
+
+<blockquote>
+<pre>
+postfix/smtpd[27560]: using backwards-compatible default setting
+    smtpd_tls_fingerprint_digest=md5 to compute certificate fingerprints
+</pre>
+</blockquote>
+
+<p> Since any client certificate fingerprints are passed in policy service
+lookups, and Postfix doesn't know whether the fingerprint will be used, the
+warning may also be logged when policy lookups are performed for connections
+that used a client certificate, even if the policy service does not in fact
+examine the client certificate.  To reduce the noise somewhat, such warnings
+are issued at most once per smtpd(8) process instance.  </p>
+
+<p> If you prefer to stick with "md5", you can suppress the warnings by
+making that setting explicit.  After addressing any other compatibility
+warnings, you can <a href="#turnoff">update</a> your compatibility level.
+</p>
+
+<blockquote>
+<pre>
+# <b>postconf smtpd_tls_fingerprint_digest=md5</b>
+# <b>postfix reload</b>
+</pre>
+</blockquote>
+
+<h2> <a name="smtp_digest"> Using backwards-compatible
+default setting smtp_tls_fingerprint_digest=md5</a> </h2>
+
+<p> The smtp_tls_fingerprint_digest and lmtp_tls_fingerprint_digest
+default values have changed from "md5" to "sha256".  With the new
+"sha256" setting, the Postfix SMTP and LMTP client avoids using the
+deprecated "md5" algorithm and computes a more secure digest of the
+server certificate.  </p>
+
+<p> If you're using the default "md5" setting, or even an explicit
+"sha1" (also deprecated) setting, you should consider switching to
+"sha256".  This will require updating any "fingerprint" security level
+policies in the TLS policy table to specify matching "sha256" digests of
+the expected server certificates or public keys.  </p>
+
+<p> As long as the smtp_tls_fingerprint_digest (or LMTP equivalent)
+parameter is left at its implicit default value, and the
+compatibility_level setting is less than 3, Postfix logs a warning each
+time the "fingerprint" security level is used to specify matching "md5"
+digests of trusted server certificates or public keys: </p>
+
+<blockquote>
+<pre>
+postfix/smtp[27560]: using backwards-compatible default setting
+    smtp_tls_fingerprint_digest=md5 to compute certificate fingerprints
+</pre>
+</blockquote>
+
+<p> If you prefer to stick with "md5", you can suppress the warnings by
+making that setting explicit.  After addressing any other compatibility
+warnings, you can <a href="#turnoff">update</a> your compatibility level.
+</p>
+
+<blockquote>
+<pre>
+# <b>postconf 'smtp_tls_fingerprint_digest = md5' \
+    'lmtp_tls_fingerprint_digest = md5' </b>
+# <b>postfix reload</b>
+</pre>
+</blockquote>
+
 <h2> <a name="turnoff">Turning off the backwards-compatibility safety net</a> </h2>
 
 <p> Backwards compatibility is turned off by updating the
index 8f1022589207d2194a3b9d3a941bf900a2565489..79732e9044b7d7003db4ea68e133569b5dd00446 100644 (file)
@@ -783,8 +783,14 @@ table. </p> </dd>
 
 <p> The digest algorithm used to compute the client certificate
 fingerprints is specified with the main.cf smtpd_tls_fingerprint_digest
-parameter.  The default is "md5", for compatibility with Postfix
-versions &lt; 2.5. </p>
+parameter. The default algorithm is <b>sha256</b> with Postfix &ge;
+3.6 and the <b>compatibility_level</b> set to 3 or higher. With
+Postfix &le; 3.5, the default algorithm is <b>md5</b>.  The
+best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in
+favor of sha256.  However, as long as there are no known "second
+pre-image" attacks against the older algorithms, their use in this
+context, though not recommended, is still likely safe.  </p>
 
 <p> The permit_tls_all_clientcerts feature must be used with caution,
 because it can result in too many access permissions.  Use this
@@ -847,30 +853,15 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> Example: </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
-(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
+    openssl dgst -sha256 -c
+(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:...:8b:fc:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
-<p> Note: Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
 
 <h3><a name="server_cipher">Server-side cipher controls</a> </h3>
 
@@ -1510,6 +1501,15 @@ match attributes can be employed. The ":" character is not used as a
 delimiter as it occurs between each pair of fingerprint (hexadecimal)
 digits. </p>
 
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b>compatibility_level</b> set to 3 or higher; with Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The
+best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in
+favor of sha256.  However, as long as there are no known "second
+pre-image" attacks against the older algorithms, their use in this
+context, though not recommended, is still likely safe.  </p>
+
 <p> Example: fingerprint TLS security with an internal mailhub.
 Two matching fingerprints are listed. The relayhost may be multiple
 physical hosts behind a load-balancer, each with its own private/public
@@ -1521,10 +1521,10 @@ another, and both keys are trusted just prior to the transition. </p>
 <pre>
     relayhost = [mailhub.example.com]
     smtp_tls_security_level = fingerprint
-    smtp_tls_fingerprint_digest = md5
+    smtp_tls_fingerprint_digest = sha256
     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
+        51:e9:af:2e:1e:40:1f:de:64:...:30:35:2d:09:16:31:5a:eb:82:76
+        b6:b4:72:34:e2:59:cd:fb:c2:...:63:0d:4d:cc:2c:7d:84:de:e6:2f
 </pre>
 </blockquote>
 
@@ -1534,15 +1534,15 @@ As in the example above, we show two matching fingerprints: </p>
 <pre>
 /etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
-    smtp_tls_fingerprint_digest = md5
+    smtp_tls_fingerprint_digest = sha256
 </pre>
 </blockquote>
 <blockquote>
 <pre>
 /etc/postfix/tls_policy:
     example.com        fingerprint
-        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
-        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+        match=51:e9:af:2e:1e:40:1f:de:...:35:2d:09:16:31:5a:eb:82:76
+        match=b6:b4:72:34:e2:59:cd:fb:...:0d:4d:cc:2c:7d:84:de:e6:2f
 </pre>
 </blockquote>
 
@@ -1554,30 +1554,15 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> Example: </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
-(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
+    openssl dgst -sha256 -c
+(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:...:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
-<p> Note: Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
 
 <h4><a name="client_tls_verify"> Mandatory server certificate verification </a> </h4>
 
@@ -2400,7 +2385,7 @@ Example:
 /etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
     # Postfix 2.5 and later
-    smtp_tls_fingerprint_digest = md5
+    smtp_tls_fingerprint_digest = sha256
 /etc/postfix/tls_policy:
     example.edu             none
     example.mil             may
@@ -2411,8 +2396,8 @@ Example:
     [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
+       match=b6:b4:72:34:e2:59:cd:fb:...:0d:4d:cc:2c:7d:84:de:e6:2f
+       match=51:e9:af:2e:1e:40:1f:de:...:35:2d:09:16:31:5a:eb:82:76
     # Postfix 2.6 and later
     example.info            may protocols=!SSLv2 ciphers=medium exclude=3DES
 </pre>
index b5ea36aed8de9b6548a68e4e9064fa83d91b2794..bf814ce5f985cc82eed528aa1389e4e2940502d2 100644 (file)
@@ -5120,7 +5120,14 @@ Postfix version 2.5).  This feature requires "smtpd_tls_ask_ccert
 = yes" and is available with Postfix version
 2.2 and later. </dd>
 
-<br>
+<dd> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b>compatibility_level</b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </dd>
 
 <dd> Alternatively, check_ccert_access accepts an explicit search
 order (Postfix 3.5 and later). The default search order as described
@@ -5243,6 +5250,15 @@ smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
 Postfix version 2.5).  This feature requires "smtpd_tls_ask_ccert
 = yes" and is available with Postfix version 2.2 and later.</dd>
 
+<dd> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b>compatibility_level</b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </dd>
+
 <dt><b><a name="reject_rbl_client">reject_rbl_client <i>rbl_domain=d.d.d.d</i></a></b></dt>
 
 <dd>Reject the request when the reversed client network address is
@@ -9275,6 +9291,15 @@ The fingerprint digest algorithm is configurable via the
 smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
 Postfix version 2.5).  </dd>
 
+<dd> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b>compatibility_level</b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </dd>
+
 <dt><b>permit_tls_all_clientcerts </b></dt>
 
 <dd> Append the domain name in $myorigin or $mydomain when the
@@ -9711,6 +9736,15 @@ feature.  The fingerprint digest algorithm is configurable via the
 smtpd_tls_fingerprint_digest parameter (hard-coded as md5 prior to
 Postfix version 2.5).  </p>
 
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b>compatibility_level</b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>.  The best-practice
+algorithm is now <b>sha256</b>. Recent advances in hash function
+cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image"
+attacks against the older algorithms, their use in this context, though
+not recommended, is still likely safe.  </p>
+
 <p> Postfix lookup tables are in the form of (key, value) pairs.
 Since we only need the key, the value can be chosen freely, e.g.
 the name of the user or host:
@@ -9726,10 +9760,6 @@ relay_clientcerts = hash:/etc/postfix/relay_clientcerts
 an appropriate access(5) policy for each client.
 See RESTRICTION_CLASS_README.</p>
 
-<p> <b>Note:</b> Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
-
 <p>This feature is available with Postfix version 2.2.</p>
 
 %PARAM smtpd_tls_cipherlist
@@ -9754,15 +9784,24 @@ Postfix 2.3 and later; use smtpd_tls_mandatory_ciphers instead. </p>
 <p> File with DH parameters that the Postfix SMTP server should
 use with non-export EDH ciphers. </p>
 
+<p> The best-practice choice of parameters uses a 2048-bit prime.  This is fine,
+despite the historical "1024" in the parameter name.  Do not be tempted to use
+much larger values, performance degrades quickly, and you may also cease to
+interoperate with some mainstream SMTP clients.  As of Postfix 3.1, the
+compiled-in default prime is 2048-bits, and it is not strictly necessary,
+though perhaps somewhat beneficial to generate custom DH parameters. </p>
+
 <p> 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 commands:  </p>
 
 <blockquote>
 <pre>
-openssl dhparam -out /etc/postfix/dh512.pem 512
-openssl dhparam -out /etc/postfix/dh1024.pem 1024
 openssl dhparam -out /etc/postfix/dh2048.pem 2048
+openssl dhparam -out /etc/postfix/dh1024.pem 1024
+# As of Postfix 3.6, export-grade 512-bit DH parameters are no longer
+# supported or needed.
+openssl dhparam -out /etc/postfix/dh512.pem 512
 </pre>
 </blockquote>
 
@@ -9796,6 +9835,9 @@ grade is "medium" with Postfix releases after the middle of 2015,
 and as a result export-grade cipher suites are by default not used.
 </p>
 
+<p> With Postfix &ge; 3.6 export-grade Diffie-Hellman key exchange
+is no longer supported, and this parameter is silently ignored. </p>
+
 <p> See also the discussion under the smtpd_tls_dh1024_param_file
 configuration parameter.  </p>
 
@@ -11226,8 +11268,12 @@ Example:
 <pre>
 /etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
-    # Postfix 2.5 and later
-    smtp_tls_fingerprint_digest = md5
+    # Postfix 2.5 and later.
+    #
+    # The default digest is sha256 with Postfix &ge; 3.6 and
+    # compatibility level &ge; 3.
+    #
+    smtp_tls_fingerprint_digest = sha256
 </pre>
 
 <pre>
@@ -11241,8 +11287,8 @@ Example:
     [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
+        match=b6:b4:72:34:e2:59:cd:...:c2:ca:63:0d:4d:cc:2c:7d:84:de:e6:2f
+        match=51:e9:af:2e:1e:40:1f:...:64:0a:30:35:2d:09:16:31:5a:eb:82:76
 </pre>
 
 <p> <b>Note:</b> The <b>hostname</b> strategy if listed in a non-default
@@ -12316,7 +12362,7 @@ configuration parameter.  See there for details. </p>
 
 <p> This feature is available in Postfix 2.4 and later. </p>
 
-%PARAM smtp_tls_fingerprint_digest md5
+%PARAM smtp_tls_fingerprint_digest see "postconf -d" output
 
 <p> The message digest algorithm used to construct remote SMTP server
 certificate fingerprints. At the "fingerprint" TLS security level
@@ -12329,19 +12375,19 @@ 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 (or public/private key-pair) that has the same fingerprint. </p>
 
-<p> The default algorithm is <b>md5</b>; this is consistent with
-the backwards compatible setting of the digest used to verify client
-certificates in the SMTP server. </p>
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b>compatibility_level</b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>. </p>
 
-<p> The best practice algorithm is now <b>sha1</b>. Recent advances in hash
-function cryptanalysis have led to md5 being deprecated in favor of sha1.
-However, as long as there are no known "second pre-image" attacks
-against md5, its use in this context can still be considered safe.
-</p>
+<p> The best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image" attacks
+against the older algorithms, their use in this context, though not
+recommended, is still likely safe.  </p>
 
 <p> While additional digest algorithms are often available with OpenSSL's
 libcrypto, only those used by libssl in SSL cipher suites are available to
-Postfix. For now this means just md5 or sha1. </p>
+Postfix.  You'll likely find support for md5, sha1, sha256 and sha512. </p>
 
 <p> To find the fingerprint of a specific certificate file, with a
 specific digest algorithm, run:
@@ -12358,8 +12404,8 @@ For example: </p>
 
 <blockquote>
 <pre>
-$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
-SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+$ openssl x509 -noout -fingerprint -sha256 -in cert.pem
+SHA256 Fingerprint=D4:6A:AB:19:24:...:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
 </pre>
 </blockquote>
 
@@ -12371,29 +12417,16 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> The actual command to transform the key to DER format depends on the
+version of OpenSSL used. As of OpenSSL 1.0.0, the "pkey" command supports
+all key types. </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
+# OpenSSL &ge; 1.0 with SHA-256 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
-(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
-</pre>
-</blockquote>
-
-<blockquote>
-<pre>
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
+    openssl dgst -sha256 -c
+(stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:...:fc:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
 
@@ -12401,10 +12434,6 @@ $ openssl x509 -in cert.pem -noout -pubkey |
 fingerprint and public key fingerprint when the TLS loglevel is 2 or
 higher. </p>
 
-<p> <b>Note:</b> Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
-
 <p> This feature is available in Postfix 2.5 and later. </p>
 
 %PARAM smtp_tls_fingerprint_cert_match
@@ -12419,6 +12448,10 @@ is a message digest of the server certificate (or public key). The
 digest algorithm is selected via the <b>smtp_tls_fingerprint_digest</b>
 parameter. </p>
 
+<p> The colons between each pair of nibbles in the fingerprint value
+are optional (Postfix &ge; 3.6). These were required in earlier
+Postfix releases. </p>
+
 <p> When an <b>smtp_tls_policy_maps</b> table entry specifies the
 "fingerprint" security level, any "match" attributes in that entry specify
 the list of valid fingerprints for the corresponding destination. Multiple
@@ -12436,10 +12469,10 @@ another, and both keys are trusted just prior to the transition. </p>
 <pre>
 relayhost = [mailhub.example.com]
 smtp_tls_security_level = fingerprint
-smtp_tls_fingerprint_digest = md5
+smtp_tls_fingerprint_digest = sha256
 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
+    cd:fc:d8:db:f8:c4:82:96:6c:...:28:71:e8:f5:8d:a5:0d:9b:d4:a6
+    dd:5c:ef:f5:c3:bc:64:25:36:...:99:36:06:ce:40:ef:de:2e:ad:a4
 </pre>
 </blockquote>
 
@@ -12450,7 +12483,7 @@ As in the example above, we show two matching fingerprints: </p>
 <pre>
 /etc/postfix/main.cf:
     smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
-    smtp_tls_fingerprint_digest = md5
+    smtp_tls_fingerprint_digest = sha256
 </pre>
 </blockquote>
 
@@ -12458,8 +12491,8 @@ As in the example above, we show two matching fingerprints: </p>
 <pre>
 /etc/postfix/tls_policy:
     example.com        fingerprint
-        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
-        match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+        match=51:e9:af:2e:1e:40:1f:...:64:0a:30:35:2d:09:16:31:5a:eb:82:76
+        match=b6:b4:72:34:e2:59:cd:...:c2:ca:63:0d:4d:cc:2c:7d:84:de:e6:2f
 </pre>
 </blockquote>
 
@@ -12472,31 +12505,32 @@ configuration parameter.  See there for details. </p>
 
 <p> This feature is available in Postfix 2.5 and later. </p>
 
-%PARAM lmtp_tls_fingerprint_digest md5
+%PARAM lmtp_tls_fingerprint_digest see "postconf -d" output
 
 <p> The LMTP-specific version of the smtp_tls_fingerprint_digest
 configuration parameter.  See there for details. </p>
 
 <p> This feature is available in Postfix 2.5 and later. </p>
 
-%PARAM smtpd_tls_fingerprint_digest md5
+%PARAM smtpd_tls_fingerprint_digest see "postconf -d" output
 
-<p> The message digest algorithm to construct remote SMTP
-client-certificate
-fingerprints or public key fingerprints (Postfix 2.9 and later)
-for <b>check_ccert_access</b> and <b>permit_tls_clientcerts</b>. The
-default algorithm is <b>md5</b>, for backwards compatibility with Postfix
-releases prior to 2.5.  </p>
+<p> The message digest algorithm to construct remote SMTP client-certificate
+fingerprints or public key fingerprints (Postfix 2.9 and later) for
+<b>check_ccert_access</b> and <b>permit_tls_clientcerts</b>. </p>
 
-<p> Advances in hash
-function cryptanalysis have led to md5 being deprecated in favor of sha1.
-However, as long as there are no known "second pre-image" attacks
-against md5, its use in this context can still be considered safe.
-</p>
+<p> The default algorithm is <b>sha256</b> with Postfix &ge; 3.6
+and the <b>compatibility_level</b> set to 3 or higher. With Postfix
+&le; 3.5, the default algorithm is <b>md5</b>. </p>
+
+<p> The best-practice algorithm is now <b>sha256</b>. Recent advances in hash
+function cryptanalysis have led to md5 and sha1 being deprecated in favor of
+sha256.  However, as long as there are no known "second pre-image" attacks
+against the older algorithms, their use in this context, though not
+recommended, is still likely safe.  </p>
 
 <p> While additional digest algorithms are often available with OpenSSL's
 libcrypto, only those used by libssl in SSL cipher suites are available to
-Postfix. </p>
+Postfix.  You'll likely find support for md5, sha1, sha256 and sha512. </p>
 
 <p> To find the fingerprint of a specific certificate file, with a
 specific digest algorithm, run: </p>
@@ -12512,8 +12546,8 @@ For example: </p>
 
 <blockquote>
 <pre>
-$ openssl x509 -noout -fingerprint -sha1 -in cert.pem
-SHA1 Fingerprint=D4:6A:AB:19:24:79:F8:32:BB:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
+$ openssl x509 -noout -fingerprint -sha256 -in cert.pem
+SHA256 Fingerprint=D4:6A:AB:19:24:...:A6:CB:66:82:C0:8E:9B:EE:29:A8:1A
 </pre>
 </blockquote>
 
@@ -12525,46 +12559,26 @@ key always in "PEM" format. We pipe the result to another OpenSSL
 command that converts the key to DER and then to the "dgst" command
 to compute the fingerprint. </p>
 
-<p> The actual command to transform the key to DER format depends
-on the version of OpenSSL used. With OpenSSL 1.0.0 and later, the
-"pkey" command supports all key types. With OpenSSL 0.9.8 and
-earlier, the key type is always RSA (nobody uses DSA, and EC
-keys are not fully supported by 0.9.8), so the "rsa" command is
-used. </p>
+<p> Example: </p>
 <blockquote>
 <pre>
-# OpenSSL 1.0 with all certificates and SHA-1 fingerprints.
 $ openssl x509 -in cert.pem -noout -pubkey |
     openssl pkey -pubin -outform DER |
-    openssl dgst -sha1 -c
+    openssl dgst -sha256 -c
 (stdin)= 64:3f:1f:f6:e5:1e:d4:2a:56:8b:fc:09:1a:61:98:b5:bc:7c:60:58
 </pre>
 </blockquote>
 
-<blockquote>
-<pre>
-# OpenSSL 0.9.8 with RSA certificates and MD5 fingerprints.
-$ openssl x509 -in cert.pem -noout -pubkey |
-    openssl rsa -pubin -outform DER |
-    openssl dgst -md5 -c
-(stdin)= f4:62:60:f6:12:8f:d5:8d:28:4d:13:a7:db:b2:ff:50
-</pre>
-</blockquote>
-
 <p> The Postfix SMTP server and client log the peer (leaf) certificate
 fingerprint and public key fingerprint when the TLS loglevel is 2 or
 higher. </p>
 
-<p> <b>Note:</b> Postfix 2.9.0&ndash;2.9.5 computed the public key
-fingerprint incorrectly. To use public-key fingerprints, upgrade
-to Postfix 2.9.6 or later. </p>
-
-<p> Example: client-certificate access table, with sha1 fingerprints: </p>
+<p> Example: client-certificate access table, with sha256 fingerprints: </p>
 
 <blockquote>
 <pre>
 /etc/postfix/main.cf:
-    smtpd_tls_fingerprint_digest = sha1
+    smtpd_tls_fingerprint_digest = sha256
     smtpd_client_restrictions =
         check_ccert_access hash:/etc/postfix/access,
         reject
@@ -12572,9 +12586,9 @@ to Postfix 2.9.6 or later. </p>
 <pre>
 /etc/postfix/access:
     # Action folded to next line...
-    AF:88:7C:AD:51:95:6F:36:96:F6:01:FB:2E:48:CD:AB:49:25:A2:3B
+    AF:88:7C:AD:51:95:6F:36:96:...: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
+    85:16:78:FD:73:6E:CE:70:E0:...:5F:0D:3C:C8:6D:C4:2C:24:59:E1
         permit_auth_destination
 </pre>
 </blockquote>
@@ -12859,32 +12873,32 @@ EC algorithms have not been disabled by the vendor. </p>
 %PARAM smtpd_tls_eecdh_grade see "postconf -d" output
 
 <p> The Postfix SMTP server security grade for ephemeral elliptic-curve
-Diffie-Hellman (EECDH) key exchange. </p>
+Diffie-Hellman (EECDH) key exchange.   As of Postfix 3.6, the value of
+this parameter is always ignored, and Postfix behaves as though th
+<b>auto</b> value (described below) was chosen.
+</p>
 
 <p> The available choices are: </p>
 
 <dl>
 
+<dt><b>auto</b></dt> <dd> Use the most preferred curve that is
+supported by both the client and the server.  This setting requires
+Postfix &ge; 3.2 compiled and linked with OpenSSL &ge; 1.0.2.  This
+is the default setting under the above conditions (and the only
+setting used with Postfix &ge; 3.6). </dd>
+
 <dt><b>none</b></dt> <dd> Don't use EECDH. Ciphers based on EECDH key
 exchange will be disabled. This is the default in Postfix versions
 2.6 and 2.7. </dd>
 
-<dt><b>strong</b></dt> <dd> Use EECDH with approximately 128
-bits of security at a reasonable computational cost. This is the
-current best-practice trade-off between security and computational
-efficiency. This is the default in Postfix version 2.8 and later.
-</dd>
+<dt><b>strong</b></dt> <dd> Use EECDH with approximately 128 bits of
+security at a reasonable computational cost. This is the default in
+Postfix versions 2.8&ndash;3.5.  </dd>
 
 <dt><b>ultra</b></dt> <dd> Use EECDH with approximately 192 bits of
 security at computational cost that is approximately twice as high
-as 128 bit strength ECC. Barring significant progress in attacks on
-elliptic curve crypto-systems, the "strong" curve is sufficient for most
-users. </dd>
-
-<dt><b>auto</b></dt> <dd> Use the most preferred curve that is
-supported by both the client and the server.  This setting requires
-Postfix &ge; 3.2 compiled and linked with OpenSSL &ge; 1.0.2.  This
-is the default setting under the above conditions.  </dd>
+as 128 bit strength ECC. </dd>
 
 </dl>
 
@@ -15207,6 +15221,9 @@ for further details.  The default SMTP server cipher grade is
 "medium" with Postfix releases after the middle of 2015, and as a
 result export-grade cipher suites are by default not used.  </p>
 
+<p> With Postfix &ge; 3.6 export-grade Diffie-Hellman key exchange
+is no longer supported, and this parameter is silently ignored. </p>
+
 <p> This feature is available in Postfix 2.8 and later. </p>
 
 %PARAM tlsproxy_tls_dkey_file $smtpd_tls_dkey_file
index 91c70f75e21ed2012f6a971589e4e6298083e176..0efd00eda7d470d6bfd5c2ceee313c5eaf3b1084 100644 (file)
 /*     int     warn_compat_break_flush_domains;
 /*     int     warn_compat_break_mynetworks_style;
 /*
+/*     int     warn_compat_break_smtpd_tls_fpt_dgst;
+/*     int     warn_compat_break_smtp_tls_fpt_dgst;
+/*     int     warn_compat_break_lmtp_tls_fpt_dgst;
+/*
 /*     char    *var_maillog_file;
 /*     char    *var_maillog_file_pfxs;
 /*     char    *var_maillog_file_comp;
@@ -356,14 +360,21 @@ char   *var_drop_hdrs;
 char   *var_info_log_addr_form;
 bool    var_enable_orcpt;
 
-char   *var_maillog_file;
-char   *var_maillog_file_pfxs;
-char   *var_maillog_file_comp;
-char   *var_maillog_file_stamp;
-char   *var_postlog_service;
+char   *var_maillog_file;
+char   *var_maillog_file_pfxs;
+char   *var_maillog_file_comp;
+char   *var_maillog_file_stamp;
+char   *var_postlog_service;
 
 const char null_format_string[1] = "";
 
+ /*
+  * Compatibility level 3.
+  */
+int     warn_compat_break_smtpd_tls_fpt_dgst;
+int     warn_compat_break_smtp_tls_fpt_dgst;
+int     warn_compat_break_lmtp_tls_fpt_dgst;
+
  /*
   * Compatibility level 2.
   */
@@ -618,6 +629,23 @@ static void check_legacy_defaults(void)
      * bits.
      */
 
+    /*
+     * Look for specific parameters whose default changed when the
+     * compatibility level changed to 3.
+     */
+    if (var_compat_level < 3) {
+       if (mail_conf_lookup(VAR_SMTPD_TLS_FPT_DGST) == 0)
+           warn_compat_break_smtpd_tls_fpt_dgst = 1;
+       if (mail_conf_lookup(VAR_SMTP_TLS_FPT_DGST) == 0)
+           warn_compat_break_smtp_tls_fpt_dgst = 1;
+       if (mail_conf_lookup(VAR_LMTP_TLS_FPT_DGST) == 0)
+           warn_compat_break_lmtp_tls_fpt_dgst = 1;
+    } else {
+       warn_compat_break_smtpd_tls_fpt_dgst = 0;
+       warn_compat_break_smtp_tls_fpt_dgst = 0;
+       warn_compat_break_lmtp_tls_fpt_dgst = 0;
+    }
+
     /*
      * Look for specific parameters whose default changed when the
      * compatibility level changed to 2.
index a6119f1b2d9471b48fa6f3bb57356780b6592e5e..65906f18710dc15efdffdc80de0f5e0b25b9548f 100644 (file)
@@ -19,8 +19,8 @@ typedef int bool;
 #ifdef USE_TLS
 #include <openssl/opensslv.h>          /* OPENSSL_VERSION_NUMBER */
 #include <openssl/objects.h>           /* SN_* and NID_* macros */
-#if OPENSSL_VERSION_NUMBER < 0x1000200fUL
-#error "OpenSSL releases prior to 1.0.2 are no longer supported"
+#if OPENSSL_VERSION_NUMBER < 0x1010100fUL
+#error "OpenSSL releases prior to 1.1.1 are no longer supported"
 #endif
 #endif
 
@@ -52,7 +52,7 @@ extern bool var_show_unk_rcpt_table;
   */
 #define VAR_COMPAT_LEVEL       "compatibility_level"
 #define DEF_COMPAT_LEVEL       0
-#define CUR_COMPAT_LEVEL       2
+#define CUR_COMPAT_LEVEL       3
 extern int var_compat_level;
 
 extern int warn_compat_break_app_dot_mydomain;
@@ -64,6 +64,10 @@ extern int warn_compat_break_relay_domains;
 extern int warn_compat_break_flush_domains;
 extern int warn_compat_break_mynetworks_style;
 
+extern int warn_compat_break_smtpd_tls_fpt_dgst;
+extern int warn_compat_break_smtp_tls_fpt_dgst;
+extern int warn_compat_break_lmtp_tls_fpt_dgst;
+
  /*
   * What problem classes should be reported to the postmaster via email.
   * Default is bad problems only. See mail_error(3). Even when mail notices
@@ -1356,7 +1360,8 @@ extern char *var_smtpd_tls_excl_ciph;
 extern char *var_smtpd_tls_mand_excl;
 
 #define VAR_SMTPD_TLS_FPT_DGST "smtpd_tls_fingerprint_digest"
-#define DEF_SMTPD_TLS_FPT_DGST "md5"
+#define DEF_SMTPD_TLS_FPT_DGST "${{$compatibility_level} < {3} ? " \
+                                "{md5} : {sha256}}"
 extern char *var_smtpd_tls_fpt_dgst;
 
 #define VAR_SMTPD_TLS_512_FILE "smtpd_tls_dh512_param_file"
@@ -1517,9 +1522,11 @@ extern char *var_smtp_tls_excl_ciph;
 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 DEF_SMTP_TLS_FPT_DGST  "${{$compatibility_level} < {3} ? " \
+                                "{md5} : {sha256}}"
 #define VAR_LMTP_TLS_FPT_DGST  "lmtp_tls_fingerprint_digest"
-#define DEF_LMTP_TLS_FPT_DGST  "md5"
+#define DEF_LMTP_TLS_FPT_DGST  "${{$compatibility_level} < {3} ? " \
+                                "{md5} : {sha256}}"
 extern char *var_smtp_tls_fpt_dgst;
 
 #define VAR_SMTP_TLS_TAFILE    "smtp_tls_trust_anchor_file"
index 1326f7b260ad70b6b081632ed9ed3c83c0f59611..5fc6402a3d7fbacb0712130ffda2bf9cc62cebc0 100644 (file)
   * snapshots are called a.b-yyyymmdd, where a=major release number, b=minor
   * release number, c=patchlevel, and yyyymmdd is the release date:
   * yyyy=year, mm=month, dd=day.
-  * 
+  *
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20200627"
+#define MAIL_RELEASE_DATE      "20200720"
 #define MAIL_VERSION_NUMBER    "3.6"
 
 #ifdef SNAPSHOT
index a3a9946d327b7288ad5c68a2a8910ffa07033b87..aa859cb28b438fdc2cab783213fdf71f56643392 100644 (file)
 /*     \fB-P \fICApath\fR, the OpenSSL library may augment the chain with
 /*     missing issuer certificates.  To see the actual chain sent by the
 /*     remote SMTP server leave \fICAfile\fR and \fICApath\fR unset.
-/* .IP "\fB-d \fImdalg\fR (default: \fBsha1\fR)"
+/* .IP "\fB-d \fImdalg\fR (default: \fB$smtp_tls_fingerprint_digest\fR)"
 /*     The message digest algorithm to use for reporting remote SMTP server
 /*     fingerprints and matching against user provided certificate
 /*     fingerprints (with DANE TLSA records the algorithm is specified
-/*     in the DNS).
+/*     in the DNS).  In Postfix versions prior to 3.6, the default value
+/*     was "sha1".
 /* .IP "\fB-f\fR"
 /*     Lookup the associated DANE TLSA RRset even when a hostname is not an
 /*     alias and its address records lie in an unsigned zone.  See
@@ -876,16 +877,20 @@ static int starttls(STATE *state)
             * context attributes.
             */
            state->tls_context = tls_proxy_context_receive(state->stream);
-           if (state->log_mask &
-               (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT))
-               msg_info("%s: subject_CN=%s, issuer_CN=%s, "
-                        "fingerprint=%s, pkey_fingerprint=%s",
-                        state->namaddrport, state->tls_context->peer_CN,
-                        state->tls_context->issuer_CN,
-                        state->tls_context->peer_cert_fprint,
-                        state->tls_context->peer_pkey_fprint);
-           tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_NEW,
-                           state->tls_context);
+           if (state->tls_context) {
+               if (state->log_mask &
+                   (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT))
+                   msg_info("%s: subject_CN=%s, issuer_CN=%s, "
+                            "fingerprint=%s, pkey_fingerprint=%s",
+                            state->namaddrport, state->tls_context->peer_CN,
+                            state->tls_context->issuer_CN,
+                            state->tls_context->peer_cert_fprint,
+                            state->tls_context->peer_pkey_fprint);
+               tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_NEW,
+                               state->tls_context);
+           } else {
+               msg_warn("error receiving TLS proxy context");
+           }
        }
     } else {                                   /* tls_proxy_mode */
        state->tls_context =
@@ -1395,10 +1400,6 @@ static int dane_host_level(STATE *state, DNS_RR *addr)
     if (TLS_DANE_BASED(level)) {
        if (state->mx == 0 || state->mx->dnssec_valid ||
            state->mxinsec_level > TLS_LEV_MAY) {
-           if (state->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE))
-               tls_dane_verbose(1);
-           else
-               tls_dane_verbose(0);
 
            /* See addr loop in connect_remote() */
            if (state->ddane)
@@ -1423,8 +1424,7 @@ static int dane_host_level(STATE *state, DNS_RR *addr)
                             tls_dane_unusable(state->ddane) ?
                             "usable " : "");
                level = TLS_LEV_SECURE;
-           } else if (!TLS_DANE_HASTA(state->ddane)
-                      && !TLS_DANE_HASEE(state->ddane)) {
+           } else if (state->ddane->tlsa == 0) {
                msg_panic("DANE activated with no TLSA records to match");
            } else if (state->mx && !state->mx->dnssec_valid &&
                       state->mxinsec_level == TLS_LEV_ENCRYPT) {
@@ -1673,23 +1673,6 @@ static int finger(STATE *state)
     return (0);
 }
 
-#if defined(USE_TLS) && OPENSSL_VERSION_NUMBER < 0x10100000L
-
-/* ssl_cleanup - free memory allocated in the OpenSSL library */
-
-static void ssl_cleanup(void)
-{
-    ERR_remove_thread_state(0);                /* Thread-id is now a pointer */
-    ENGINE_cleanup();
-    CONF_modules_unload(1);
-    ERR_free_strings();
-    EVP_cleanup();
-    CRYPTO_cleanup_all_ex_data();
-}
-
-#endif                                 /* USE_TLS && OPENSSL_VERSION_NUMBER
-                                        * < 0x10100000L */
-
 /* run - do what we were asked to do. */
 
 static int run(STATE *state)
@@ -1833,7 +1816,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
 #ifdef USE_TLS
 #define TLSOPTS "A:Cd:fF:g:H:k:K:l:L:m:M:p:P:r:s:wX"
 
-    state->mdalg = mystrdup("sha1");
+    state->mdalg = 0;
     state->CApath = mystrdup("");
     state->CAfile = mystrdup("");
     state->chains = mystrdup("");
@@ -1888,7 +1871,8 @@ static void parse_options(STATE *state, int argc, char *argv[])
            state->print_trust = 1;
            break;
        case 'd':
-           myfree(state->mdalg);
+           if (state->mdalg)
+               myfree(state->mdalg);
            state->mdalg = mystrdup(optarg);
            break;
        case 'f':
@@ -2011,6 +1995,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
     if (state->options.logopts == 0)
        state->options.logopts = mystrdup("routine,certmatch");
     state->log_mask = tls_log_mask("-L option", state->options.logopts);
+    tls_dane_loglevel("-L option", state->options.logopts);
 
     if (state->options.level) {
        state->level = tls_level_lookup(state->options.level);
@@ -2024,21 +2009,6 @@ static void parse_options(STATE *state, int argc, char *argv[])
            msg_fatal("Invalid TLS level \"%s\"", state->options.level);
        }
     }
-
-    /*
-     * We first call tls_init(), which ultimately calls SSL_library_init(),
-     * since otherwise we can't tell whether we have the message digests
-     * required for DANE support.
-     */
-    tls_init(state);
-    if (TLS_DANE_BASED(state->level) && !tls_dane_avail()) {
-       msg_warn("DANE TLS support is not available, resorting to \"secure\"");
-       state->level = TLS_LEV_SECURE;
-    }
-    state->tls_bio = 0;
-    if (state->print_trust)
-       state->tls_bio = BIO_new_fp(stdout, BIO_NOCLOSE);
-
 #endif
 }
 
@@ -2047,9 +2017,10 @@ static void parse_options(STATE *state, int argc, char *argv[])
 static void parse_match(STATE *state, int argc, char *argv[])
 {
 #ifdef USE_TLS
+    int     smtp_mode = 1;
 
     switch (state->level) {
-       case TLS_LEV_SECURE:
+    case TLS_LEV_SECURE:
        state->match = argv_alloc(2);
        while (*argv)
            argv_split_append(state->match, *argv++, "");
@@ -2066,8 +2037,8 @@ static void parse_match(STATE *state, int argc, char *argv[])
     case TLS_LEV_FPRINT:
        state->dane = tls_dane_alloc();
        while (*argv)
-           tls_dane_add_ee_digests((TLS_DANE *) state->dane,
-                                   state->mdalg, *argv++, "");
+           tls_dane_add_fpt_digests((TLS_DANE *) state->dane, *argv++, "",
+                                    smtp_mode);
        break;
     case TLS_LEV_DANE:
     case TLS_LEV_DANE_ONLY:
@@ -2112,6 +2083,13 @@ int     main(int argc, char *argv[])
     char   *loopenv = getenv("VALGRINDLOOP");
     int     loop = loopenv ? atoi(loopenv) : 1;
     ARGV   *import_env;
+    static char *var_smtp_tls_fpt_dgst;
+    static const CONFIG_STR_TABLE smtp_str_table[] = {
+#ifdef USE_TLS
+       VAR_SMTP_TLS_FPT_DGST, DEF_SMTP_TLS_FPT_DGST, &var_smtp_tls_fpt_dgst, 1, 0,
+#endif
+       0,
+    };
 
     /* Don't die when a peer goes away unexpectedly. */
     signal(SIGPIPE, SIG_IGN);
@@ -2128,8 +2106,31 @@ int     main(int argc, char *argv[])
     mail_conf_suck();
     parse_options(&state, argc, argv);
     mail_params_init();
+    get_mail_conf_str_table(smtp_str_table);
     parse_tas(&state);
 
+#ifdef USE_TLS
+    /* Less surprising to default to the same fingerprint digest as smtp(8) */
+    if (state.mdalg)
+       warn_compat_break_smtp_tls_fpt_dgst = 0;
+    else
+       state.mdalg = mystrdup(var_smtp_tls_fpt_dgst);
+
+    /*
+     * We first call tls_init(), which ultimately calls SSL_library_init(),
+     * since otherwise we can't tell whether we have the message digests
+     * required for DANE support.
+     */
+    tls_init(&state);
+    if (TLS_DANE_BASED(state.level) && !tls_dane_avail()) {
+       msg_warn("DANE TLS support is not available, resorting to \"secure\"");
+       state.level = TLS_LEV_SECURE;
+    }
+    state.tls_bio = 0;
+    if (state.print_trust)
+       state.tls_bio = BIO_new_fp(stdout, BIO_NOCLOSE);
+#endif
+
     /* Enforce consistent operation of different Postfix parts. */
     import_env = mail_parm_split(VAR_IMPORT_ENVIRON, var_import_environ);
     update_env(import_env->argv);
@@ -2155,10 +2156,5 @@ int     main(int argc, char *argv[])
     /* Be valgrind friendly and clean-up */
     cleanup(&state);
 
-    /* OpenSSL 1.1.0 and later (de)initialization is implicit */
-#if defined(USE_TLS) && OPENSSL_VERSION_NUMBER < 0x10100000L
-    ssl_cleanup();
-#endif
-
     return (0);
 }
index 575ea48568455570960c08a21614297ee6f9fbac..40e2d26d4e07ff8859cff5b7fcaf3979ef1ea923 100644 (file)
@@ -39,6 +39,9 @@
 /* .IP \fB!\fR
 /*     The message is in the \fBhold\fR queue, i.e. no further delivery
 /*     attempt will be made until the mail is taken off hold.
+/* .IP \fB#\fR
+/*     The message is forced to expire. See the \fBpostsuper\fR(1)
+/*     options \fB-e\fR or \fB-f\fR.
 /* .RE
 /* .IP
 /*     This mode of operation is implemented by executing the
 /* SECURITY
 /* .ad
 /* .fi
-/*     By design, this program is not set-user (or group) id. However,
-/*     it must handle data from untrusted, possibly remote, users.
-/*     Thus, the usual precautions need to be taken against malicious
-/*     inputs.
+/*     By design, this program is not set-user (or group) id.
+/*     It is prepared to handle message content from untrusted,
+/*     possibly remote, users.
+/*
+/*     However, like most Postfix programs, this program does not
+/*     enforce a security policy on its command-line arguments.
+/*     Instead, it relies on the UNIX system to enforce access
+/*     policies based on the effective user and group IDs of the
+/*     process. Concretely, this means that running Postfix commands
+/*     as root (from sudo or equivalent) on behalf of a non-root
+/*     user is likely to create privilege escalation opportunities.
+/*
+/*     If an application runs any Postfix programs on behalf of
+/*     users that do not have normal shell access to Postfix
+/*     commands, then that application MUST restrict user-specified
+/*     command-line arguments to avoid privilege escalation.
+/* .IP \(bu
+/*     Filter all command-line arguments, for example arguments
+/*     that contain a pathname or that specify a database access
+/*     method. These pathname checks must reject user-controlled
+/*     symlinks or hardlinks to sensitive files, and must not be
+/*     vulnerable to TOCTOU race attacks.
+/* .IP \(bu
+/*     Disable command options processing for all command arguments
+/*     that contain user-specified data. For example, the Postfix
+/*     \fBsendmail\fR(1) command line MUST be structured as follows:
+/*
+/* .nf
+/*         \fB/path/to/sendmail\fR \fIsystem-arguments\fR \fB--\fR \fIuser-arguments\fR
+/* .fi
+/*
+/*     Here, the "\fB--\fR" disables command option processing for
+/*     all \fIuser-arguments\fR that follow.
+/* .IP
+/*     Without the "\fB--\fR", a malicious user could enable Postfix
+/*     \fBsendmail\fR(1) command options, by specifying an email
+/*     address that starts with "\fB-\fR".
 /* DIAGNOSTICS
 /*     Problems are logged to \fBsyslogd\fR(8) or \fBpostlogd\fR(8),
 /*     and to the standard error stream.
 /*     The external command to execute when a Postfix daemon program is
 /*     invoked with the -D option.
 /* .IP "\fBdebug_peer_level (2)\fR"
-/*     The increment in verbose logging level when a remote client or
-/*     server matches a pattern in the debug_peer_list parameter.
+/*     The increment in verbose logging level when a nexthop destination,
+/*     remote client or server name or network address matches a pattern
+/*     given with the debug_peer_list parameter.
 /* .IP "\fBdebug_peer_list (empty)\fR"
-/*     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.
+/*     Optional list of nexthop destination, remote client or server
+/*     name or network address patterns that, if matched, cause the verbose
+/*     logging level to increase by the amount specified in $debug_peer_level.
 /* ACCESS CONTROLS
 /* .ad
 /* .fi
@@ -1010,6 +1047,7 @@ int     main(int argc, char **argv)
     const char *dsn_envid = 0;
     int     saved_optind;
     ARGV   *import_env;
+    char   *alias_map_from_args = 0;
 
     /*
      * Fingerprint executables and core dumps.
@@ -1279,9 +1317,7 @@ int     main(int argc, char **argv)
            case 'A':
                if (optarg[1] == 0)
                    msg_fatal_status(EX_USAGE, "-oA requires pathname");
-               myfree(var_alias_db_map);
-               var_alias_db_map = mystrdup(optarg + 1);
-               set_mail_conf_str(VAR_ALIAS_DB_MAP, var_alias_db_map);
+               alias_map_from_args = optarg + 1;
                break;
            case '7':
            case '8':
@@ -1431,13 +1467,17 @@ int     main(int argc, char **argv)
        if (argv[OPTIND])
            msg_fatal_status(EX_USAGE,
                         "alias initialization mode requires no recipient");
-       if (*var_alias_db_map == 0)
+       if (alias_map_from_args == 0 && *var_alias_db_map == 0)
            return (0);
-       ext_argv = argv_alloc(2);
+       ext_argv = argv_alloc(3);
        argv_add(ext_argv, "postalias", (char *) 0);
        for (n = 0; n < msg_verbose; n++)
            argv_add(ext_argv, "-v", (char *) 0);
-       argv_split_append(ext_argv, var_alias_db_map, CHARS_COMMA_SP);
+       argv_add(ext_argv, "--", (char *) 0);
+       if (alias_map_from_args != 0)
+           argv_add(ext_argv, alias_map_from_args, (char *) 0);
+       else
+           argv_split_append(ext_argv, var_alias_db_map, CHARS_COMMA_SP);
        argv_terminate(ext_argv);
        mail_run_replace(var_command_dir, ext_argv->argv);
        /* NOTREACHED */
index 9f1357aa6e4c4a03738af5e34ef2f973ddbbc689..906ef9f2536c795460dd0357a32f88a14c2f3435 100644 (file)
 /*     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"
+/* .IP "\fBsmtp_tls_fingerprint_digest (see 'postconf -d' output)\fR"
 /*     The message digest algorithm used to construct remote SMTP server
 /*     certificate fingerprints.
 /* .PP
 /* .ad
 /* .fi
 /* .IP "\fBdebug_peer_level (2)\fR"
-/*     The increment in verbose logging level when a next-hop destination,
+/*     The increment in verbose logging level when a nexthop destination,
 /*     remote client or server name or network address matches a pattern
 /*     given with the debug_peer_list parameter.
 /* .IP "\fBdebug_peer_list (empty)\fR"
-/*     Optional list of next-hop destination, remote client or server
+/*     Optional list of nexthop destination, remote client or server
 /*     name or network address patterns that, if matched, cause the verbose
 /*     logging level to increase by the amount specified in $debug_peer_level.
 /* .IP "\fBerror_notice_recipient (postmaster)\fR"
@@ -1443,6 +1443,7 @@ static void pre_init(char *unused_name, char **unused_argv)
                            CApath = var_smtp_tls_CApath,
                            mdalg = var_smtp_tls_fpt_dgst);
        smtp_tls_list_init();
+       tls_dane_loglevel(VAR_LMTP_SMTP(TLS_LOGLEVEL), var_smtp_tls_loglevel);
 #else
        msg_warn("TLS has been selected, but TLS support is not compiled in");
 #endif
index 665dc9bd43ff663105bbd224312ee37ee9c6f3e2..7fd63486367de68f78ead1b50c9f52818750c99c 100644 (file)
@@ -1112,18 +1112,17 @@ static int smtp_start_tls(SMTP_STATE *state)
      * "QUIT".
      * 
      * See src/tls/tls_level.c and src/tls/tls.h. Levels above "encrypt" require
-     * matching.  Levels >= "dane" require CA or DNSSEC trust.
+     * matching.
      * 
-     * When DANE TLSA records specify an end-entity certificate, the trust and
-     * match bits always coincide, but it is fine to report the wrong
-     * end-entity certificate as untrusted rather than unmatched.
+     * NOTE: We use "IS_MATCHED" to satisfy policy, but "IS_SECURED" to log
+     * effective security.  Thus "half-dane" is never "Verified" only
+     * "Trusted", but matching is enforced here.
+     * 
+     * NOTE: When none of the TLSA records were usable, "dane" and "half-dane"
+     * fall back to "encrypt", updating the tls_context level accordingly, so
+     * we must check that here, and not state->tls->level.
      */
-    if (TLS_MUST_TRUST(state->tls->level))
-       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 (TLS_MUST_MATCH(state->tls->level))
+    if (TLS_MUST_MATCH(session->tls_context->level))
        if (!TLS_CERT_IS_MATCHED(session->tls_context))
            return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
                                   SMTP_RESP_FAKE(&fake, "4.7.5"),
index 4b394a9344883659ab3a37a765f87e3450be25d8..92a231df5fba83bf1be899b4ef484b33f025bb8a 100644 (file)
@@ -336,8 +336,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
            case TLS_LEV_FPRINT:
                if (!tls->dane)
                    tls->dane = tls_dane_alloc();
-               tls_dane_add_ee_digests(tls->dane,
-                                       var_smtp_tls_fpt_dgst, val, "|");
+               tls_dane_add_fpt_digests(tls->dane, val, "|", smtp_mode);
                break;
            case TLS_LEV_VERIFY:
            case TLS_LEV_SECURE:
@@ -618,10 +617,10 @@ static void *policy_create(const char *unused_key, void *context)
     case TLS_LEV_FPRINT:
        if (tls->dane == 0)
            tls->dane = tls_dane_alloc();
-       if (!TLS_DANE_HASEE(tls->dane)) {
-           tls_dane_add_ee_digests(tls->dane, var_smtp_tls_fpt_dgst,
-                                   var_smtp_tls_fpt_cmatch, CHARS_COMMA_SP);
-           if (!TLS_DANE_HASEE(tls->dane)) {
+       if (tls->dane->tlsa == 0) {
+           tls_dane_add_fpt_digests(tls->dane, var_smtp_tls_fpt_cmatch,
+                                    CHARS_COMMA_SP, smtp_mode);
+           if (tls->dane->tlsa == 0) {
                msg_warn("nexthop domain %s: configured at fingerprint "
                       "security level, but with no fingerprints to match.",
                         dest);
@@ -640,7 +639,7 @@ static void *policy_create(const char *unused_key, void *context)
        if (*var_smtp_tls_tafile) {
            if (tls->dane == 0)
                tls->dane = tls_dane_alloc();
-           if (!TLS_DANE_HASTA(tls->dane)
+           if (tls->dane->tlsa == 0
                && !load_tas(tls->dane, var_smtp_tls_tafile)) {
                MARK_INVALID(tls->why, &tls->level);
                return ((void *) tls);
@@ -909,7 +908,7 @@ static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter)
     /*
      * With DANE trust anchors, peername matching is not configurable.
      */
-    if (TLS_DANE_HASTA(dane)) {
+    if (dane->tlsa != 0) {
        tls->matchargv = argv_alloc(2);
        argv_add(tls->matchargv, dane->base_domain, ARGV_END);
        if (iter->mx) {
@@ -919,7 +918,7 @@ static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter)
                argv_add(tls->matchargv, iter->mx->rname,
                         iter->mx->qname, ARGV_END);
        }
-    } else if (!TLS_DANE_HASEE(dane))
+    } else
        msg_panic("empty DANE match list");
     tls->dane = dane;
     return;
index 2059bd5e2f00d020140ffcc3606964592317f5b8..4f3e52a20549d160e59e95e0d5cb07e05b37ea26 100644 (file)
 /*     authentication without encryption.
 /* .PP
 /*     Available in Postfix version 2.5 and later:
-/* .IP "\fBsmtpd_tls_fingerprint_digest (md5)\fR"
-/*     The message digest algorithm to construct remote SMTP
-/*     client-certificate
-/*     fingerprints or public key fingerprints (Postfix 2.9 and later)
-/*     for \fBcheck_ccert_access\fR and \fBpermit_tls_clientcerts\fR.
+/* .IP "\fBsmtpd_tls_fingerprint_digest (see 'postconf -d' output)\fR"
+/*     The message digest algorithm to construct remote SMTP client-certificate
+/*     fingerprints or public key fingerprints (Postfix 2.9 and later) for
+/*     \fBcheck_ccert_access\fR and \fBpermit_tls_clientcerts\fR.
 /* .PP
 /*     Available in Postfix version 2.6 and later:
 /* .IP "\fBsmtpd_tls_protocols (!SSLv2, !SSLv3)\fR"
 /*     a lot of detail, to running some daemon processes under control of
 /*     a call tracer or debugger.
 /* .IP "\fBdebug_peer_level (2)\fR"
-/*     The increment in verbose logging level when a remote client or
-/*     server matches a pattern in the debug_peer_list parameter.
+/*     The increment in verbose logging level when a nexthop destination,
+/*     remote client or server name or network address matches a pattern
+/*     given with the debug_peer_list parameter.
 /* .IP "\fBdebug_peer_list (empty)\fR"
-/*     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.
+/*     Optional list of nexthop destination, remote client or server
+/*     name or network address patterns that, if matched, cause the verbose
+/*     logging level to increase by the amount specified in $debug_peer_level.
 /* .IP "\fBerror_notice_recipient (postmaster)\fR"
 /*     The recipient of postmaster notifications about mail delivery
 /*     problems that are caused by policy, resource, software or protocol
index 485dbb1467124a1662beffa9d65297dcb546a8ba..0195182580eab56313e039f6d0891dcb5ef2b777 100644 (file)
@@ -1607,6 +1607,11 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
        int     i;
        char   *prints[2];
 
+       if (warn_compat_break_smtpd_tls_fpt_dgst)
+           msg_info("using backwards-compatible default setting "
+                    VAR_SMTPD_TLS_FPT_DGST "=md5 to compute certificate "
+                    "fingerprints");
+
        prints[0] = state->tls_context->peer_cert_fprint;
        prints[1] = state->tls_context->peer_pkey_fprint;
 
@@ -3196,9 +3201,17 @@ static int check_ccert_access(SMTPD_STATE *state, const char *acl_spec,
            switch (*action) {
            case SMTPD_ACL_SEARCH_CODE_CERT_FPRINT:
                match_this = state->tls_context->peer_cert_fprint;
+               if (warn_compat_break_smtpd_tls_fpt_dgst)
+                   msg_info("using backwards-compatible default setting "
+                            VAR_SMTPD_TLS_FPT_DGST "=md5 to compute "
+                            "certificate fingerprints");
                break;
            case SMTPD_ACL_SEARCH_CODE_PKEY_FPRINT:
                match_this = state->tls_context->peer_pkey_fprint;
+               if (warn_compat_break_smtpd_tls_fpt_dgst)
+                   msg_info("using backwards-compatible default setting "
+                            VAR_SMTPD_TLS_FPT_DGST "=md5 to compute "
+                            "certificate fingerprints");
                break;
            default:
                known_action = str_name_code(search_actions, *action);
@@ -3958,6 +3971,7 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
                            const char *reply_name, const char *reply_class,
                                        const char *def_acl)
 {
+    static int warned = 0;
     static VSTRING *action = 0;
     SMTPD_POLICY_CLNT *policy_clnt;
 
@@ -3999,6 +4013,23 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
 
     ENCODE_CN(subject, subject_buf, state->tls_context->peer_CN);
     ENCODE_CN(issuer, issuer_buf, state->tls_context->issuer_CN);
+
+    /*
+     * XXX: Too noisy to warn for each policy lookup, especially because we
+     * don't even know whether the policy server will use the fingerprint. So
+     * warn at most once per process, though on only lightly loaded servers,
+     * it might come close to one warning per inbound message.
+     */
+    if (!warned
+       && warn_compat_break_smtpd_tls_fpt_dgst
+       && state->tls_context
+       && state->tls_context->peer_cert_fprint
+       && *state->tls_context->peer_cert_fprint) {
+       warned = 1;
+       msg_info("using backwards-compatible default setting "
+                VAR_SMTPD_TLS_FPT_DGST "=md5 to compute certificate "
+                "fingerprints");
+    }
 #endif
 
     if (attr_clnt_request(policy_clnt->client,
index 4378d5ad3b6fe500489431e5470001273802e39f..cd228b6214344fb55d28b6d7c0d76cb334348457 100644 (file)
@@ -1354,7 +1354,7 @@ static void connect_event(int unused_event, void *unused_context)
            SOCKADDR_TO_HOSTADDR(sa, len, &state->client_addr,
                                 (MAI_SERVPORT_STR *) 0, sa->sa_family);
        else
-           strncpy(state->client_addr.buf, "local", sizeof("local"));
+           strncpy(state->client_addr.buf, "local", sizeof("local") + 0);
        if (msg_verbose)
            msg_info("connect (%s %s)",
 #ifdef AF_LOCAL
index fec7d4542eccb8e6a8b20f8be45871aef624f7c3..948afab9f56a7f8428f23660c2bf943a8f78d825 100644 (file)
@@ -1,7 +1,7 @@
 SHELL  = /bin/sh
 SRCS   = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c tls_fprint.c \
        tls_prng_exch.c tls_stream.c tls_bio_ops.c tls_misc.c tls_dh.c \
-       tls_rsa.c tls_verify.c tls_dane.c tls_certkey.c tls_session.c \
+       tls_verify.c tls_dane.c tls_certkey.c tls_session.c \
        tls_client.c tls_server.c tls_scache.c tls_mgr.c tls_seed.c \
        tls_level.c \
        tls_proxy_clnt.c tls_proxy_context_print.c tls_proxy_context_scan.c \
@@ -12,7 +12,7 @@ SRCS  = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c tls_fprint.c \
        tls_proxy_client_misc.c
 OBJS   = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \
        tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \
-       tls_rsa.o tls_verify.o tls_dane.o tls_certkey.o tls_session.o \
+       tls_verify.o tls_dane.o tls_certkey.o tls_session.o \
        tls_client.o tls_server.o tls_scache.o tls_mgr.o tls_seed.o \
        tls_level.o \
        tls_proxy_clnt.o tls_proxy_context_print.o tls_proxy_context_scan.o \
@@ -25,7 +25,7 @@ DEFS  = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
 INCL   =
 LIB    = lib$(LIB_PREFIX)tls$(LIB_SUFFIX)
-TESTPROG= tls_dh tls_mgr tls_rsa tls_dane tls_certkey
+TESTPROG= tls_dh tls_mgr tls_dane tls_certkey
 
 LIBS   = ../../lib/lib$(LIB_PREFIX)dns$(LIB_SUFFIX) \
        ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
@@ -121,11 +121,6 @@ tls_mgr: $(LIB) $(LIBS)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
        mv junk $@.o
 
-tls_rsa: $(LIB) $(LIBS)
-       mv $@.o junk
-       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-       mv junk $@.o
-
 tls_dane: $(LIB) $(LIBS)
        mv $@.o junk
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
@@ -206,6 +201,7 @@ tls_dane.o: ../../include/dns.h
 tls_dane.o: ../../include/events.h
 tls_dane.o: ../../include/hex_code.h
 tls_dane.o: ../../include/mail_params.h
+tls_dane.o: ../../include/midna_domain.h
 tls_dane.o: ../../include/msg.h
 tls_dane.o: ../../include/myaddrinfo.h
 tls_dane.o: ../../include/mymalloc.h
@@ -499,19 +495,6 @@ tls_proxy_server_scan.o: ../../include/vstring.h
 tls_proxy_server_scan.o: tls.h
 tls_proxy_server_scan.o: tls_proxy.h
 tls_proxy_server_scan.o: tls_proxy_server_scan.c
-tls_rsa.o: ../../include/argv.h
-tls_rsa.o: ../../include/check_arg.h
-tls_rsa.o: ../../include/dns.h
-tls_rsa.o: ../../include/msg.h
-tls_rsa.o: ../../include/myaddrinfo.h
-tls_rsa.o: ../../include/name_code.h
-tls_rsa.o: ../../include/name_mask.h
-tls_rsa.o: ../../include/sock_addr.h
-tls_rsa.o: ../../include/sys_defs.h
-tls_rsa.o: ../../include/vbuf.h
-tls_rsa.o: ../../include/vstream.h
-tls_rsa.o: ../../include/vstring.h
-tls_rsa.o: tls.h
 tls_rsa.o: tls_rsa.c
 tls_scache.o: ../../include/argv.h
 tls_scache.o: ../../include/check_arg.h
index 2a8cc11999611c249c77233620af721b8791467f..439f805c64c141addac5e3ec260a91105db98998 100644 (file)
@@ -52,7 +52,6 @@
 
 #define TLS_REQUIRED(l)                ((l) > TLS_LEV_MAY)
 #define TLS_MUST_MATCH(l)      ((l) > TLS_LEV_ENCRYPT)
-#define TLS_MUST_TRUST(l)      ((l) >= TLS_LEV_HALF_DANE)
 #define TLS_MUST_PKIX(l)       ((l) >= TLS_LEV_VERIFY)
 #define TLS_OPPORTUNISTIC(l)   ((l) == TLS_LEV_MAY || (l) == TLS_LEV_DANE)
 #define TLS_DANE_BASED(l)      \
@@ -84,36 +83,8 @@ extern const char *str_tls_level(int);
 #define ssl_cipher_stack_t STACK_OF(SSL_CIPHER)
 #define ssl_comp_stack_t STACK_OF(SSL_COMP)
 
-#if (OPENSSL_VERSION_NUMBER < 0x1000200fUL)
-#error "OpenSSL releases prior to 1.0.2 are no longer supported"
-#endif
-
- /* Backwards compatibility with OpenSSL < 1.1.0 */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-#define OpenSSL_version_num SSLeay
-#define OpenSSL_version SSLeay_version
-#define OPENSSL_VERSION SSLEAY_VERSION
-#define X509_STORE_up_ref(store) \
-       CRYPTO_add(&((store)->references), 1, CRYPTO_LOCK_X509)
-#define X509_up_ref(x) \
-       CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509)
-#define EVP_PKEY_up_ref(k) \
-       CRYPTO_add(&((k)->references), 1, CRYPTO_LOCK_EVP_PKEY)
-#define X509_STORE_CTX_get0_cert(ctx) ((ctx)->cert)
-#define X509_STORE_CTX_get0_untrusted(ctx) ((ctx)->untrusted)
-#define X509_STORE_CTX_set0_untrusted X509_STORE_CTX_set_chain
-#define X509_STORE_CTX_set0_trusted_stack X509_STORE_CTX_trusted_stack
-#define ASN1_STRING_get0_data ASN1_STRING_data
-#define X509_getm_notBefore X509_get_notBefore
-#define X509_getm_notAfter X509_get_notAfter
-#define TLS_method SSLv23_method
-#define TLS_client_method SSLv23_client_method
-#define TLS_server_method SSLv23_server_method
-#endif
-
- /* Backwards compatibility with OpenSSL < 1.1.1 */
-#if OPENSSL_VERSION_NUMBER < 0x1010100fUL
-#define SSL_CTX_set_num_tickets(ctx, num) ((void)0)
+#if (OPENSSL_VERSION_NUMBER < 0x1010100fUL)
+#error "OpenSSL releases prior to 1.1.1 are no longer supported"
 #endif
 
  /*-
@@ -186,52 +157,33 @@ typedef enum {
   * algorithm.
   */
 typedef struct TLS_TLSA {
-    char   *mdalg;                     /* Algorithm for this digest list */
-    ARGV   *certs;                     /* Complete certificate digests */
-    ARGV   *pkeys;                     /* SubjectPublicKeyInfo digests */
+    uint8_t usage;                     /* DANE certificate usage */
+    uint8_t selector;                  /* DANE selector */
+    uint8_t mtype;                     /* Algorithm for this digest list */
+    uint16_t length;                   /* Length of associated data */
+    unsigned char *data;               /* Associated data */
     struct TLS_TLSA *next;             /* Chain to next algorithm */
 } TLS_TLSA;
 
- /*
-  * Linked list of full X509 trust-anchor certs.
-  */
-typedef struct TLS_CERTS {
-    X509   *cert;
-    struct TLS_CERTS *next;
-} TLS_CERTS;
-
- /*
-  * Linked list of full EVP_PKEY trust-anchor public keys.
-  */
-typedef struct TLS_PKEYS {
-    EVP_PKEY *pkey;
-    struct TLS_PKEYS *next;
-} TLS_PKEYS;
-
 typedef struct TLS_DANE {
-    TLS_TLSA *ta;                      /* Trust-anchor cert/pubkey digests */
-    TLS_TLSA *ee;                      /* End-entity cert/pubkey digests */
-    TLS_CERTS *certs;                  /* Full trust-anchor certificates */
-    TLS_PKEYS *pkeys;                  /* Full trust-anchor public keys */
+    TLS_TLSA *tlsa;                    /* TLSA records */
     char   *base_domain;               /* Base domain of TLSA RRset */
     int     flags;                     /* Lookup status */
     time_t  expires;                   /* Expiration time of this record */
     int     refs;                      /* Reference count */
 } TLS_DANE;
 
-#define TLS_DANE_HASTA(d)      ((d) ? (d)->ta : 0)
-#define TLS_DANE_HASEE(d)      ((d) ? (d)->ee : 0)
-
  /*
   * tls_dane.c
   */
 extern int tls_dane_avail(void);
+extern void tls_dane_loglevel(const char *, const char *);
 extern void tls_dane_flush(void);
-extern void tls_dane_verbose(int);
 extern TLS_DANE *tls_dane_alloc(void);
-extern void tls_dane_add_ee_digests(TLS_DANE *, const char *, const char *,
-                                           const char *);
+extern void tls_tlsa_free(TLS_TLSA *);
 extern void tls_dane_free(TLS_DANE *);
+extern void tls_dane_add_fpt_digests(TLS_DANE *, const char *, const char *,
+                                            int);
 extern TLS_DANE *tls_dane_resolve(unsigned, const char *, DNS_RR *, int);
 extern int tls_dane_load_trustfile(TLS_DANE *, const char *);
 
@@ -250,6 +202,7 @@ typedef struct {
     char   *peer_sni;                  /* SNI sent to or by the peer */
     char   *peer_cert_fprint;          /* ASCII certificate fingerprint */
     char   *peer_pkey_fprint;          /* ASCII public key fingerprint */
+    int     level;                     /* Effective security level */
     int     peer_status;               /* Certificate and match status */
     const char *protocol;
     const char *cipher_name;
@@ -280,12 +233,10 @@ typedef struct {
     VSTREAM *stream;                   /* Blocking-mode SMTP session */
     /* DANE TLSA trust input and verification state */
     const TLS_DANE *dane;              /* DANE TLSA digests */
+    X509   *errorcert;                 /* Error certificate closest to leaf */
     int     errordepth;                        /* Chain depth of error cert */
-    int     tadepth;                   /* Chain depth of trust anchor */
     int     errorcode;                 /* First error at error depth */
-    X509   *errorcert;                 /* Error certificate closest to leaf */
-    x509_stack_t *untrusted;           /* Certificate chain fodder */
-    x509_stack_t *trusted;             /* Internal root CA list */
+    int     must_fail;                 /* Failed to load trust settings */
 } TLS_SESS_STATE;
 
  /*
@@ -329,6 +280,7 @@ extern int tls_log_mask(const char *, const char *);
 #define TLS_LOG_DEBUG                  (1<<7)
 #define TLS_LOG_TLSPKTS                        (1<<8)
 #define TLS_LOG_ALLPKTS                        (1<<9)
+#define TLS_LOG_DANE                   (1<<10)
 
  /*
   * Client and Server application contexts
@@ -651,40 +603,35 @@ extern int tls_bio(int, int, TLS_SESS_STATE *,
  /*
   * tls_dh.c
   */
-extern void tls_set_dh_from_file(const char *, int);
-extern DH *tls_tmp_dh_cb(SSL *, int, int);
-extern void tls_set_eecdh_curve(SSL_CTX *, const char *);
+extern void tls_set_dh_from_file(const char *);
+extern void tls_tmp_dh(SSL_CTX *);
 extern void tls_auto_eecdh_curves(SSL_CTX *, const char *);
 
- /*
-  * tls_rsa.c
-  */
-extern RSA *tls_tmp_rsa_cb(SSL *, int, int);
-
  /*
   * tls_verify.c
   */
 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 int tls_verify_certificate_callback(int, X509_STORE_CTX *);
 extern void tls_log_verify_error(TLS_SESS_STATE *);
 
  /*
   * tls_dane.c
   */
-extern int tls_dane_match(TLS_SESS_STATE *, int, X509 *, int);
-extern void tls_dane_set_callback(SSL_CTX *, TLS_SESS_STATE *);
+extern void tls_dane_log(TLS_SESS_STATE *);
+extern void tls_dane_digest_init(SSL_CTX *, const EVP_MD *);
+extern int tls_dane_enable(TLS_SESS_STATE *);
+extern TLS_TLSA *tlsa_prepend(TLS_TLSA *, uint8_t, uint8_t, uint8_t,
+                                     const unsigned char *, uint16_t);
 
  /*
   * tls_fprint.c
   */
 extern char *tls_digest_encode(const unsigned char *, int);
-extern char *tls_data_fprint(const char *, int, const char *);
 extern char *tls_cert_fprint(X509 *, const char *);
 extern char *tls_pkey_fprint(X509 *, const char *);
-extern char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *, long,
-                                        const char *);
+extern char *tls_serverid_digest(TLS_SESS_STATE *,
+                       const TLS_CLIENT_START_PROPS *, long, const char *);
 
  /*
   * tls_certkey.c
@@ -709,7 +656,7 @@ extern long tls_bug_bits(void);
 extern void tls_print_errors(void);
 extern void tls_info_callback(const SSL *, int, int);
 extern long tls_bio_dump_cb(BIO *, int, const char *, int, long, long);
-extern int tls_validate_digest(const char *);
+extern const EVP_MD *tls_validate_digest(const char *);
 
  /*
   * tls_seed.c
index be8d47000e0b51623beab6ce27ad4257dc70d61f..489c3557be3e6f36446aa574999d350afe72a970 100644 (file)
@@ -149,7 +149,6 @@ static void init_pem_load_state(pem_load_state_t *st, SSL_CTX *ctx, SSL *ssl,
 
 /* use_chain - load cert, key and chain into ctx or ssl */
 
-#if OPENSSL_VERSION_NUMBER >= 0x1010100fUL
 static int use_chain(pem_load_state_t *st)
 {
     int     ret;
@@ -181,54 +180,6 @@ static int use_chain(pem_load_state_t *st)
     return ret;
 }
 
-#else
-
-/* Legacy OpenSSL 1.0.2 and 1.1.0 interface */
-static int use_chain(pem_load_state_t *st)
-{
-    int     ret = 1;
-
-#define TRY(op, o) \
-    ((st->ctx && SSL_CTX_##op(st->ctx, st->o)) || \
-     (st->ssl && SSL_##op(st->ssl, st->o)))
-
-    /*
-     * This ensures the cert and key have the same type and match. A similar
-     * check is performed in use_PrivateKey(), but only if if the key and
-     * cert are of the same type.
-     */
-    if (!X509_check_private_key(st->cert, st->pkey))
-       ret = 0;
-
-    /*
-     * XXX: With OpenSSL 1.0.2, setting the certificate clears any previous
-     * mismatched key of the same type, so we don't detect conflicting chains
-     * for the same algorithm, and silently use the last one.
-     */
-
-    /* use_certificate() increments the refcount */
-    if (ret && !TRY(use_certificate, cert))
-       ret = 0;
-    X509_free(st->cert);
-    st->cert = 0;
-
-    /* use_PrivateKey() increments the refcount */
-    if (ret && !TRY(use_PrivateKey, pkey))
-       ret = 0;
-    EVP_PKEY_free(st->pkey);
-    st->pkey = 0;
-
-    /* set0_chain() does not increment the refcount */
-    if (!ret || !(ret = TRY(set0_chain, chain)))
-       sk_X509_pop_free(st->chain, X509_free);
-    /* The chain is now owned by the SSL library or freed, zero for next use */
-    st->chain = 0;
-
-    return ret;
-}
-
-#endif
-
 /* load_cert - decode and load a DER-encoded X509 certificate */
 
 static void load_cert(pem_load_state_t *st, unsigned char *buf,
@@ -418,7 +369,7 @@ static int load_pem_object(pem_load_state_t *st)
                   && strcmp(name, PEM_STRING_DSA) == 0)) {
        load_pkey(st, pkey_type, buf, buflen);
     } else if (!st->mixed) {
-       msg_warn("loading %s: ignoring PEM type: %s", st->source, name);
+       msg_warn("loading %s: ignoring PEM type: %s", st->source, name);
     }
     OPENSSL_free(name);
     OPENSSL_free(header);
@@ -697,17 +648,6 @@ int     main(int argc, char *argv[])
     char   *key_file = 0;
     SSL_CTX *ctx;
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-    /*
-     * Initialize the OpenSSL library by the book! To start with, we must
-     * initialize the algorithms. We want cleartext error messages instead of
-     * just error codes, so we load the error_strings.
-     */
-    SSL_load_error_strings();
-    OpenSSL_add_ssl_algorithms();
-#endif
-
     if (!(ctx = SSL_CTX_new(TLS_client_method()))) {
        tls_print_errors();
        exit(1);
index 139f0204f32f005cad0c6ba6fc1748bcfcde8f61..00e02dc22fbac13627c56da1dea5cd989b5ef536 100644 (file)
@@ -86,9 +86,8 @@
 /*     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,
-/*     TLS_CERT_FLAG_MATCHED and TLS_CERT_FLAG_SECURED.
+/*     verification. This consists of one or more of TLS_CERT_FLAG_PRESENT,
+/*     TLS_CERT_FLAG_TRUSTED, TLS_CERT_FLAG_MATCHED and TLS_CERT_FLAG_SECURED.
 /* .IP TLScontext->peer_CN
 /*     Extracted CommonName of the peer, or zero-length string if the
 /*     information could not be extracted.
@@ -304,15 +303,323 @@ static void uncache_session(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext)
     tls_mgr_delete(TLScontext->cache_type, TLScontext->serverid);
 }
 
+/* verify_extract_name - verify peer name and extract peer information */
+
+static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert,
+                                       const TLS_CLIENT_START_PROPS *props)
+{
+    int     verbose;
+
+    verbose = TLScontext->log_mask &
+       (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT);
+
+    /*
+     * On exit both peer_CN and issuer_CN should be set.
+     */
+    TLScontext->issuer_CN = tls_issuer_CN(peercert, TLScontext);
+    TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);
+
+    /*
+     * Is the certificate trust chain trusted and matched?  Any required name
+     * checks are now performed internally in OpenSSL.
+     */
+    if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) {
+       if (TLScontext->must_fail) {
+           msg_panic("%s: cert valid despite trust init failure",
+                     TLScontext->namaddr);
+       } else if (TLS_MUST_MATCH(TLScontext->level)) {
+
+           /*
+            * Fully secured only if not insecure like half-dane.  We use
+            * TLS_CERT_FLAG_MATCHED to satisfy policy, but
+            * TLS_CERT_FLAG_SECURED to log the effective security.
+            * 
+            * Would ideally also exclude "verify" (as opposed to "secure")
+            * here, because that can be subject to insecure MX indirection,
+            * but that's rather incompatible (and not even the case with
+            * explicitly chosen non-default match patterns).  Users have
+            * been warned.
+            */
+           if (!TLS_NEVER_SECURED(TLScontext->level))
+               TLScontext->peer_status |= TLS_CERT_FLAG_SECURED;
+           TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;
+
+           if (verbose) {
+               const char *peername = SSL_get0_peername(TLScontext->con);
+
+               if (peername)
+                   msg_info("%s: matched peername: %s",
+                            TLScontext->namaddr, peername);
+               tls_dane_log(TLScontext);
+           }
+       } else
+           TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED;
+    }
+
+    /*
+     * Give them a clue. Problems with trust chain verification are logged
+     * when the session is first negotiated, before the session is 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 (!TLS_CERT_IS_MATCHED(TLScontext)
+       && (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
+       if (TLScontext->session_reused == 0)
+           tls_log_verify_error(TLScontext);
+       else
+           msg_info("%s: re-using session with untrusted certificate, "
+                    "look for details earlier in the log", props->namaddr);
+    }
+}
+
+/* add_namechecks - tell OpenSSL what names to check */
+
+static void add_namechecks(TLS_SESS_STATE *TLScontext,
+                                  const TLS_CLIENT_START_PROPS *props)
+{
+    SSL    *ssl = TLScontext->con;
+    int     namechecks_count = 0;
+    int     i;
+
+    /* RFC6125: No part-label 'foo*bar.example.com' wildcards for SMTP */
+    SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+
+    for (i = 0; i < props->matchargv->argc; ++i) {
+       const char *name = props->matchargv->argv[i];
+       const char *aname;
+       int     match_subdomain = 0;
+
+       if (strcasecmp(name, "nexthop") == 0) {
+           name = props->nexthop;
+       } else if (strcasecmp(name, "dot-nexthop") == 0) {
+           name = props->nexthop;
+           match_subdomain = 1;
+       } else if (strcasecmp(name, "hostname") == 0) {
+           name = props->host;
+       } else {
+           if (*name == '.') {
+               if (*++name == 0) {
+                   msg_warn("%s: ignoring invalid match name: \".\"",
+                            TLScontext->namaddr);
+                   continue;
+               }
+               match_subdomain = 1;
+           }
+#ifndef NO_EAI
+           else {
+
+               /*
+                * Besides U+002E (full stop) IDNA2003 allows labels to be
+                * separated by any of the Unicode variants U+3002
+                * (ideographic full stop), U+FF0E (fullwidth full stop), and
+                * U+FF61 (halfwidth ideographic full stop). Their respective
+                * UTF-8 encodings are: E38082, EFBC8E and EFBDA1.
+                * 
+                * IDNA2008 does not permit (upper) case and other variant
+                * differences in U-labels. The midna_domain_to_ascii()
+                * function, based on UTS46, normalizes such differences
+                * away.
+                * 
+                * The IDNA to_ASCII conversion does not allow empty leading
+                * labels, so we handle these explicitly here.
+                */
+               unsigned char *cp = (unsigned char *) name;
+
+               if ((cp[0] == 0xe3 && cp[1] == 0x80 && cp[2] == 0x82)
+                   || (cp[0] == 0xef && cp[1] == 0xbc && cp[2] == 0x8e)
+                   || (cp[0] == 0xef && cp[1] == 0xbd && cp[2] == 0xa1)) {
+                   if (name[3]) {
+                       name = name + 3;
+                       match_subdomain = 1;
+                   }
+               }
+           }
+#endif
+       }
+
+       /*
+        * DNS subjectAltNames are required to be ASCII.
+        * 
+        * Per RFC 6125 Section 6.4.4 Matching the CN-ID, follows the same rules
+        * (6.4.1, 6.4.2 and 6.4.3) that apply to subjectAltNames.  In
+        * particular, 6.4.2 says that the reference identifier is coerced to
+        * ASCII, but no conversion is stated or implied for the CN-ID, so it
+        * seems it only matches if it is all ASCII.  Otherwise, it is some
+        * other sort of name.
+        */
+#ifndef NO_EAI
+       if (!allascii(name) && (aname = midna_domain_to_ascii(name)) != 0) {
+           if (msg_verbose)
+               msg_info("%s asciified to %s", name, aname);
+           name = aname;
+       }
+#endif
+
+       if (!match_subdomain) {
+           if (SSL_add1_host(ssl, name))
+               ++namechecks_count;
+           else
+               msg_warn("%s: error loading match name: \"%s\"",
+                        TLScontext->namaddr, name);
+       } else {
+           char   *dot_name = concatenate(".", name, (char *) 0);
+
+           if (SSL_add1_host(ssl, dot_name))
+               ++namechecks_count;
+           else
+               msg_warn("%s: error loading match name: \"%s\"",
+                        TLScontext->namaddr, dot_name);
+           myfree(dot_name);
+       }
+    }
+
+    /*
+     * If we failed to add any names, OpenSSL will perform no namechecks, so
+     * we set the "must_fail" bit to avoid verification false-positives.
+     */
+    if (namechecks_count == 0) {
+       msg_warn("%s: could not configure peer name checks",
+                TLScontext->namaddr);
+       TLScontext->must_fail = 1;
+    }
+}
+
+/* tls_auth_enable - set up TLS authentication */
+
+static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
+                                  const TLS_CLIENT_START_PROPS *props)
+{
+    const char *sni = 0;
+
+    if (props->sni && *props->sni) {
+#ifndef NO_EAI
+       const char *aname;
+
+#endif
+
+       /*
+        * MTA-STS policy plugin compatibility: with servername=hostname,
+        * Postfix must send the MX hostname (not CNAME expanded).
+        */
+       if (strcmp(props->sni, "hostname") == 0)
+           sni = props->host;
+       else if (strcmp(props->sni, "nexthop") == 0)
+           sni = props->nexthop;
+       else
+           sni = props->sni;
+
+       /*
+        * The SSL_set_tlsext_host_name() documentation does not promise that
+        * every implementation will convert U-label form to A-label form.
+        */
+#ifndef NO_EAI
+       if (!allascii(sni) && (aname = midna_domain_to_ascii(sni)) != 0) {
+           if (msg_verbose)
+               msg_info("%s asciified to %s", sni, aname);
+           sni = aname;
+       }
+#endif
+    }
+    switch (TLScontext->level) {
+    case TLS_LEV_HALF_DANE:
+    case TLS_LEV_DANE:
+    case TLS_LEV_DANE_ONLY:
+
+       /*
+        * With DANE sessions, send an SNI hint.  We don't care whether the
+        * server reports finding a matching certificate or not, so no
+        * callback is required to process the server response.  Our use of
+        * SNI is limited to giving servers that make use of SNI the best
+        * opportunity to find the certificate they promised via the
+        * associated TLSA RRs.
+        * 
+        * Since the hostname is DNSSEC-validated, it must be a DNS FQDN and
+        * thererefore valid for use with SNI.
+        */
+       if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
+           msg_warn("%s: error enabling DANE-based certificate validation",
+                    TLScontext->namaddr);
+           tls_print_errors();
+           return (0);
+       }
+       /* RFC7672 Section 3.1.1 specifies no name checks for DANE-EE(3) */
+       SSL_dane_set_flags(TLScontext->con, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
+
+       /* Per RFC7672 the SNI name is the TLSA base domain */
+       sni = props->dane->base_domain;
+       add_namechecks(TLScontext, props);
+       break;
+
+    case TLS_LEV_FPRINT:
+       /* Synthetic DANE for fingerprint security */
+       if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
+           msg_warn("%s: error enabling fingerprint certificate validation",
+                    props->namaddr);
+           tls_print_errors();
+           return (0);
+       }
+       SSL_dane_set_flags(TLScontext->con, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
+       break;
+
+    case TLS_LEV_SECURE:
+    case TLS_LEV_VERIFY:
+       if (TLScontext->dane != 0 && TLScontext->dane->tlsa != 0) {
+           /* Synthetic DANE for per-destination trust-anchors */
+           if (SSL_dane_enable(TLScontext->con, NULL) <= 0) {
+               msg_warn("%s: error configuring local trust anchors",
+                        props->namaddr);
+               tls_print_errors();
+               return (0);
+           }
+       }
+       add_namechecks(TLScontext, props);
+       break;
+    default:
+       break;
+    }
+
+    if (sni) {
+       if (strlen(sni) > TLSEXT_MAXLEN_host_name) {
+           msg_warn("%s: ignoring too long SNI hostname: %.100s",
+                    props->namaddr, sni);
+           return (0);
+       }
+
+       /*
+        * Failure to set a valid SNI hostname is a memory allocation error,
+        * and thus transient.  Since we must not cache the session if we
+        * failed to send the SNI name, we have little choice but to abort.
+        */
+       if (!SSL_set_tlsext_host_name(TLScontext->con, sni)) {
+           msg_warn("%s: error setting SNI hostname to: %s", props->namaddr,
+                    sni);
+           return (0);
+       }
+
+       /*
+        * The saved value is not presently used client-side, but could later
+        * be logged if acked by the server (requires new client-side
+        * callback to detect the ack).  For now this just maintains symmetry
+        * with the server code, where do record the received SNI for
+        * logging.
+        */
+       TLScontext->peer_sni = mystrdup(sni);
+       if (TLScontext->log_mask & TLS_LOG_DEBUG)
+           msg_info("%s: SNI hostname: %s", props->namaddr, sni);
+    }
+    return (1);
+}
+
 /* tls_client_init - initialize client-side TLS engine */
 
 TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
 {
+    SSL_CTX *client_ctx;
+    TLS_APPL_STATE *app_ctx;
+    const EVP_MD *fpt_alg;
     long    off = 0;
     int     cachable;
     int     scache_timeout;
-    SSL_CTX *client_ctx;
-    TLS_APPL_STATE *app_ctx;
     int     log_mask;
 
     /*
@@ -333,17 +640,6 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
      */
     tls_check_version();
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-    /*
-     * Initialize the OpenSSL library by the book! To start with, we must
-     * initialize the algorithms. We want cleartext error messages instead of
-     * just error codes, so we load the error_strings.
-     */
-    SSL_load_error_strings();
-    OpenSSL_add_ssl_algorithms();
-#endif
-
     /*
      * Create an application data index for SSL objects, so that we can
      * attach TLScontext information; this information is needed inside
@@ -361,7 +657,7 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
      * If the administrator specifies an unsupported digest algorithm, fail
      * now, rather than in the middle of a TLS handshake.
      */
-    if (!tls_validate_digest(props->mdalg)) {
+    if ((fpt_alg = tls_validate_digest(props->mdalg)) == 0) {
        msg_warn("disabling TLS support");
        return (0);
     }
@@ -402,6 +698,21 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
      */
     SSL_CTX_set_verify_depth(client_ctx, props->verifydepth + 1);
 
+    /*
+     * This is a prerequisite for enabling DANE support in OpenSSL, but not a
+     * commitment to use DANE, thus suitable for both DANE and non-DANE TLS
+     * connections.  Indeed we need this not just for DANE, but aslo for
+     * fingerprint and "tafile" support.  Since it just allocates memory, it
+     * should never fail except when we're likely to fail anyway.  Rather
+     * than try to run with crippled TLS support, just give up using TLS.
+     */
+    if (SSL_CTX_dane_enable(client_ctx) <= 0) {
+       msg_warn("OpenSSL DANE initialization failed: disabling TLS support");
+       tls_print_errors();
+       return (0);
+    }
+    tls_dane_digest_init(client_ctx, fpt_alg);
+
     /*
      * Protocol selection is destination dependent, so we delay the protocol
      * selection options to the per-session SSL object.
@@ -465,19 +776,6 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
        return (0);
     }
 
-    /*
-     * 2015-12-05: Ephemeral RSA removed from OpenSSL 1.1.0-dev
-     */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-    /*
-     * According to the OpenSSL documentation, temporary RSA key is needed
-     * export ciphers are in use. We have to provide one, so well, we just do
-     * it.
-     */
-    SSL_CTX_set_tmp_rsa_callback(client_ctx, tls_tmp_rsa_cb);
-#endif
-
     /*
      * With OpenSSL 1.0.2 and later the client EECDH curve list becomes
      * configurable with the preferred curve negotiated via the supported
@@ -558,309 +856,6 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
     return (app_ctx);
 }
 
-/* match_servername -  match servername against pattern */
-
-static int match_servername(const char *certid,
-                                   const TLS_CLIENT_START_PROPS *props)
-{
-    const ARGV *cmatch_argv;
-    const char *nexthop = props->nexthop;
-    const char *hname = props->host;
-    const char *domain;
-    const char *parent;
-    const char *aname;
-    int     match_subdomain;
-    int     i;
-    int     idlen;
-    int     domlen;
-
-    if ((cmatch_argv = props->matchargv) == 0)
-       return 0;
-
-#ifndef NO_EAI
-
-    /*
-     * DNS subjectAltNames are required to be ASCII.
-     * 
-     * Per RFC 6125 Section 6.4.4 Matching the CN-ID, follows the same rules
-     * (6.4.1, 6.4.2 and 6.4.3) that apply to subjectAltNames.  In
-     * particular, 6.4.2 says that the reference identifier is coerced to
-     * ASCII, but no conversion is stated or implied for the CN-ID, so it
-     * seems it only matches if it is all ASCII.  Otherwise, it is some other
-     * sort of name.
-     */
-    if (!allascii(certid))
-       return (0);
-    if (!allascii(nexthop) && (aname = midna_domain_to_ascii(nexthop)) != 0) {
-       if (msg_verbose)
-           msg_info("%s asciified to %s", nexthop, aname);
-       nexthop = aname;
-    }
-#endif
-
-    /*
-     * Match the certid against each pattern until we find a match.
-     */
-    for (i = 0; i < cmatch_argv->argc; ++i) {
-       match_subdomain = 0;
-       if (!strcasecmp(cmatch_argv->argv[i], "nexthop"))
-           domain = nexthop;
-       else if (!strcasecmp(cmatch_argv->argv[i], "hostname"))
-           domain = hname;
-       else if (!strcasecmp(cmatch_argv->argv[i], "dot-nexthop")) {
-           domain = nexthop;
-           match_subdomain = 1;
-       } else {
-           domain = cmatch_argv->argv[i];
-           if (*domain == '.') {
-               if (domain[1]) {
-                   ++domain;
-                   match_subdomain = 1;
-               }
-           }
-#ifndef NO_EAI
-
-           /*
-            * Besides U+002E (full stop) IDNA2003 allows labels to be
-            * separated by any of the Unicode variants U+3002 (ideographic
-            * full stop), U+FF0E (fullwidth full stop), and U+FF61
-            * (halfwidth ideographic full stop). Their respective UTF-8
-            * encodings are: E38082, EFBC8E and EFBDA1.
-            * 
-            * IDNA2008 does not permit (upper) case and other variant
-            * differences in U-labels. The midna_domain_to_ascii() function,
-            * based on UTS46, normalizes such differences away.
-            * 
-            * The IDNA to_ASCII conversion does not allow empty leading labels,
-            * so we handle these explicitly here.
-            */
-           else {
-               unsigned char *cp = (unsigned char *) domain;
-
-               if ((cp[0] == 0xe3 && cp[1] == 0x80 && cp[2] == 0x82)
-                   || (cp[0] == 0xef && cp[1] == 0xbc && cp[2] == 0x8e)
-                   || (cp[0] == 0xef && cp[1] == 0xbd && cp[2] == 0xa1)) {
-                   if (domain[3]) {
-                       domain = domain + 3;
-                       match_subdomain = 1;
-                   }
-               }
-           }
-           if (!allascii(domain)
-               && (aname = midna_domain_to_ascii(domain)) != 0) {
-               if (msg_verbose)
-                   msg_info("%s asciified to %s", domain, aname);
-               domain = aname;
-           }
-#endif
-       }
-
-       /*
-        * Sub-domain match: certid is any sub-domain of hostname.
-        */
-       if (match_subdomain) {
-           if ((idlen = strlen(certid)) > (domlen = strlen(domain)) + 1
-               && certid[idlen - domlen - 1] == '.'
-               && !strcasecmp(certid + (idlen - domlen), domain))
-               return (1);
-           else
-               continue;
-       }
-
-       /*
-        * Exact match and initial "*" match. The initial "*" in a certid
-        * matches one (if var_tls_multi_label is false) or more hostname
-        * components under the condition that the certid contains multiple
-        * hostname components.
-        */
-       if (!strcasecmp(certid, domain)
-           || (certid[0] == '*' && certid[1] == '.' && certid[2] != 0
-               && (parent = strchr(domain, '.')) != 0
-               && (idlen = strlen(certid + 1)) <= (domlen = strlen(parent))
-               && strcasecmp(var_tls_multi_wildcard == 0 ? parent :
-                             parent + domlen - idlen,
-                             certid + 1) == 0))
-           return (1);
-    }
-    return (0);
-}
-
-/* verify_extract_name - verify peer name and extract peer information */
-
-static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert,
-                                       const TLS_CLIENT_START_PROPS *props)
-{
-    int     i;
-    int     r;
-    int     matched = 0;
-    int     dnsname_match;
-    int     verify_peername = 0;
-    int     log_certmatch;
-    int     verbose;
-    const char *dnsname;
-    const GENERAL_NAME *gn;
-    general_name_stack_t *gens;
-
-    /*
-     * On exit both peer_CN and issuer_CN should be set.
-     */
-    TLScontext->issuer_CN = tls_issuer_CN(peercert, TLScontext);
-
-    /*
-     * 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;
-
-    /*
-     * With fingerprint or dane we may already be done. Otherwise, verify the
-     * peername if using traditional PKI or DANE with trust-anchors.
-     */
-    if (!TLS_CERT_IS_MATCHED(TLScontext)
-       && TLS_CERT_IS_TRUSTED(TLScontext)
-       && TLS_MUST_TRUST(props->tls_level))
-       verify_peername = 1;
-
-    /* Force cert processing so we can log the data? */
-    log_certmatch = TLScontext->log_mask & TLS_LOG_CERTMATCH;
-
-    /* Log cert details when processing? */
-    verbose = log_certmatch || (TLScontext->log_mask & TLS_LOG_VERBOSE);
-
-    if (verify_peername || log_certmatch) {
-
-       /*
-        * 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
-        * for GEN_IPADD entries, not GEN_DNS entries.
-        * 
-        * XXX: In ideal world the caller who used the address to build the
-        * connection would tell us that the nexthop is the connection
-        * address, but if that is not practical, we can parse the nexthop
-        * again here.
-        */
-       gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
-       if (gens) {
-           r = sk_GENERAL_NAME_num(gens);
-           for (i = 0; i < r; ++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) {
-                   if ((dnsname_match = match_servername(dnsname, props)) != 0)
-                       matched++;
-                   /* Keep the first matched name. */
-                   if (TLScontext->peer_CN
-                       && ((dnsname_match && matched == 1)
-                           || *TLScontext->peer_CN == 0)) {
-                       myfree(TLScontext->peer_CN);
-                       TLScontext->peer_CN = 0;
-                   }
-                   if (verbose)
-                       msg_info("%s: %ssubjectAltName: %s", props->namaddr,
-                                dnsname_match ? "Matched " : "", dnsname);
-               }
-               if (TLScontext->peer_CN == 0)
-                   TLScontext->peer_CN = mystrdup(dnsname ? dnsname : "");
-               if (matched && !log_certmatch)
-                   break;
-           }
-           if (verify_peername && matched)
-               TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;
-
-           /*
-            * (Sam Rushing, Ironport) Free stack *and* member GENERAL_NAME
-            * objects
-            */
-           sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
-       }
-
-       /*
-        * No subjectAltNames, peer_CN is taken from CommonName.
-        */
-       if (TLScontext->peer_CN == 0) {
-           TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);
-           if (*TLScontext->peer_CN)
-               matched = match_servername(TLScontext->peer_CN, props);
-           if (verify_peername && matched)
-               TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED;
-           if (verbose)
-               msg_info("%s %sCommonName %s", props->namaddr,
-                        matched ? "Matched " : "", TLScontext->peer_CN);
-       } else if (verbose) {
-           char   *tmpcn = tls_peer_CN(peercert, TLScontext);
-
-           /*
-            * Though the CommonName was superceded by a subjectAltName, log
-            * it when certificate match debugging was requested.
-            */
-           msg_info("%s CommonName %s", TLScontext->namaddr, tmpcn);
-           myfree(tmpcn);
-       }
-    } else
-       TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext);
-
-    /*
-     * Give them a clue. Problems with trust chain verification are logged
-     * when the session is first negotiated, before the session is 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 (!TLS_CERT_IS_TRUSTED(TLScontext)
-       && (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
-       if (TLScontext->session_reused == 0)
-           tls_log_verify_error(TLScontext);
-       else
-           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)
-{
-    TLScontext->peer_cert_fprint = tls_cert_fprint(peercert, props->mdalg);
-    TLScontext->peer_pkey_fprint = tls_pkey_fprint(peercert, props->mdalg);
-
-    /*
-     * Whether the level is "dane" or "fingerprint" when the peer certificate
-     * is matched without resorting to a separate CA, we set both the trusted
-     * and matched bits.  This simplifies logic in smtp_proto.c where "dane"
-     * must be trusted and matched, since some "dane" TLSA RRsets do use CAs.
-     * 
-     * This also suppresses spurious logging of the peer certificate as
-     * untrusted in verify_extract_name().
-     */
-    if (TLS_DANE_HASEE(props->dane)
-       && tls_dane_match(TLScontext, TLS_DANE_EE, peercert, 0))
-       TLScontext->peer_status |=
-           TLS_CERT_FLAG_TRUSTED | TLS_CERT_FLAG_MATCHED;
-}
-
  /*
   * This is the actual startup routine for the connection. We expect that the
   * buffers are flushed and the "220 Ready to start TLS" was received by us,
@@ -874,8 +869,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     SSL_SESSION *session = 0;
     TLS_SESS_STATE *TLScontext;
     TLS_APPL_STATE *app_ctx = props->ctx;
-    const char *sni = 0;
-    char   *myserverid;
     int     log_mask = app_ctx->log_mask;
 
     /*
@@ -883,8 +876,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      * errors even when disabled by default for opportunistic sessions. For
      * DANE this only applies when using trust-anchor associations.
      */
-    if (TLS_MUST_TRUST(props->tls_level)
-      && (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane)))
+    if (TLS_MUST_MATCH(props->tls_level))
        log_mask |= TLS_LOG_UNTRUSTED;
 
     if (log_mask & TLS_LOG_VERBOSE)
@@ -903,9 +895,18 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
                 props->namaddr, props->protocols);
        return (0);
     }
-    /* DANE requires SSLv3 or later, not SSLv2. */
+
+    /*
+     * Though RFC7672 set the floor at SSLv3, we really can and should
+     * require TLS 1.0, since e.g. we send SNI, which is a TLS 1.0 extension.
+     * No DANE domains have been observed to support only SSLv3.
+     * 
+     * XXX: Would be nice to make that TLS 1.2 at some point.  Users can choose
+     * to exclude TLS 1.0 and TLS 1.1 if they find they don't run into any
+     * problems doing that.
+     */
     if (TLS_DANE_BASED(props->tls_level))
-       protomask |= TLS_PROTOCOL_SSLv2;
+       protomask |= TLS_PROTOCOL_SSLv2 | TLS_PROTOCOL_SSLv3;
 
     /*
      * Allocate a new TLScontext for the new connection and get an SSL
@@ -917,6 +918,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      */
     TLScontext = tls_alloc_sess_context(log_mask, props->namaddr);
     TLScontext->cache_type = app_ctx->cache_type;
+    TLScontext->level = props->tls_level;
 
     if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
        msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
@@ -942,9 +944,79 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     if (log_mask & TLS_LOG_VERBOSE)
        msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list);
 
+    TLScontext->stream = props->stream;
+    TLScontext->mdalg = props->mdalg;
+
+    /* Alias DANE digest info from props */
+    TLScontext->dane = props->dane;
+
+    if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
+       msg_warn("Could not set application data for 'TLScontext->con'");
+       tls_print_errors();
+       tls_free_context(TLScontext);
+       return (0);
+    }
+
+    /*
+     * Apply session protocol restrictions.
+     */
+    if (protomask != 0)
+       SSL_set_options(TLScontext->con, TLS_SSL_OP_PROTOMASK(protomask));
+
+    /*
+     * When applicable, configure DNS-based or synthetic (fingerprint or
+     * local trust anchor) DANE authentication, enable an appropriate SNI
+     * name and peer name matching.
+     * 
+     * NOTE, this can change the effective security level, and needs to happen
+     * early.
+     */
+    if (!tls_auth_enable(TLScontext, props)) {
+       tls_free_context(TLScontext);
+       return (0);
+    }
+
+    /*
+     * Try to convey the configured TLSA records for this connection to the
+     * OpenSSL library.  If none are "usable", we'll fall back to "encrypt"
+     * when authentication is not mandatory, otherwise we must arrange to
+     * ensure authentication failure.
+     */
+    if (TLScontext->dane && TLScontext->dane->tlsa) {
+       int     usable = tls_dane_enable(TLScontext);
+       int     must_fail = usable <= 0;
+
+       if (usable == 0) {
+           switch (TLScontext->level) {
+           case TLS_LEV_HALF_DANE:
+           case TLS_LEV_DANE:
+               msg_warn("%s: all TLSA records unusable, fallback to "
+                        "unauthenticated TLS", TLScontext->namaddr);
+               must_fail = 0;
+               TLScontext->level = TLS_LEV_ENCRYPT;
+               break;
+
+           case TLS_LEV_FPRINT:
+               msg_warn("%s: all fingerprints unusable", TLScontext->namaddr);
+               break;
+           case TLS_LEV_DANE_ONLY:
+               msg_warn("%s: all TLSA records unusable", TLScontext->namaddr);
+               break;
+           case TLS_LEV_SECURE:
+           case TLS_LEV_VERIFY:
+               msg_warn("%s: all trust anchors unusable", TLScontext->namaddr);
+               break;
+           }
+       }
+       TLScontext->must_fail |= must_fail;
+    }
+
     /*
-     * OpenSSL will ignore cached sessions that use the wrong protocol. So we
-     * do not need to filter out cached sessions with the "wrong" protocol,
+     * We compute the policy digest after we compute the SNI name in
+     * tls_auth_enable() and possibly update the TLScontext security level.
+     * 
+     * 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.
      * 
      * We salt the session lookup key with the protocol list, so that sessions
@@ -965,33 +1037,22 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      * peer trust chain.  Therefore, we compute a digest of the sorted TA
      * parameters and append it to the serverid.
      */
-    myserverid = tls_serverid_digest(props, protomask, cipher_list);
-
-    TLScontext->serverid = myserverid;
-    TLScontext->stream = props->stream;
-    TLScontext->mdalg = props->mdalg;
-
-    /* Alias DANE digest info from props */
-    TLScontext->dane = props->dane;
-
-    if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
-       msg_warn("Could not set application data for 'TLScontext->con'");
-       tls_print_errors();
-       tls_free_context(TLScontext);
-       return (0);
-    }
+    TLScontext->serverid =
+       tls_serverid_digest(TLScontext, props, protomask, cipher_list);
 
     /*
-     * Apply session protocol restrictions.
+     * When authenticating the peer, use 80-bit plus OpenSSL security level
+     * 
+     * XXX: We should perhaps use security level 1 also for mandatory
+     * encryption, with only "may" tolerating weaker algorithms.  But that
+     * could mean no TLS 1.0 with OpenSSL >= 3.0 and encrypt, unless I get my
+     * patch in on time to conditionally re-enable SHA1 at security level 1,
+     * and we add code to make it so.
+     * 
+     * That said, with "encrypt", we could reasonably require TLS 1.2?
      */
-    if (protomask != 0)
-       SSL_set_options(TLScontext->con, TLS_SSL_OP_PROTOMASK(protomask));
-
-#ifdef SSL_SECOP_PEER
-    /* When authenticating the peer, use 80-bit plus OpenSSL security level */
-    if (TLS_MUST_MATCH(props->tls_level))
+    if (TLS_MUST_MATCH(TLScontext->level))
        SSL_set_security_level(TLScontext->con, 1);
-#endif
 
     /*
      * XXX To avoid memory leaks we must always call SSL_SESSION_free() after
@@ -1005,65 +1066,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
            SSL_SESSION_free(session);          /* 200411 */
        }
     }
-#ifdef TLSEXT_MAXLEN_host_name
-    if (TLS_DANE_BASED(props->tls_level)) {
-
-       /*
-        * With DANE sessions, send an SNI hint.  We don't care whether the
-        * server reports finding a matching certificate or not, so no
-        * callback is required to process the server response.  Our use of
-        * SNI is limited to giving servers that are (mis)configured to use
-        * SNI the best opportunity to find the certificate they promised via
-        * the associated TLSA RRs.  (Generally, server administrators should
-        * avoid SNI, and there are no plans to support SNI in the Postfix
-        * SMTP server).
-        * 
-        * Per RFC7672, the required SNI name is the TLSA "base domain" (the one
-        * used to construct the "_25._tcp.<fqdn>" TLSA record DNS query).
-        * 
-        * Since the hostname is DNSSEC-validated, it must be a DNS FQDN and
-        * thererefore valid for use with SNI.
-        */
-       sni = props->dane->base_domain;
-    } else if (props->sni && *props->sni) {
-
-       /*
-        * MTA-STS policy plugin compatibility: with servername=hostname,
-        * Postfix must send the MX hostname (not CNAME expanded).
-        */
-       if (strcmp(props->sni, "hostname") == 0)
-           sni = props->host;
-       else if (strcmp(props->sni, "nexthop") == 0)
-           sni = props->nexthop;
-       else
-           sni = props->sni;
-    }
-    if (sni && strlen(sni) <= TLSEXT_MAXLEN_host_name) {
-
-       /*
-        * Failure to set a valid SNI hostname is a memory allocation error,
-        * and thus transient.  Since we must not cache the session if we
-        * failed to send the SNI name, we have little choice but to abort.
-        */
-       if (!SSL_set_tlsext_host_name(TLScontext->con, sni)) {
-           msg_warn("%s: error setting SNI hostname to: %s", props->namaddr,
-                    sni);
-           tls_free_context(TLScontext);
-           return (0);
-       }
-
-       /*
-        * The saved value is not presently used client-side, but could later
-        * be logged if acked by the server (requires new client-side
-        * callback to detect the ack).  For now this just maintains symmetry
-        * with the server code, where do record the received SNI for
-        * logging.
-        */
-       TLScontext->peer_sni = mystrdup(sni);
-       if (log_mask & TLS_LOG_DEBUG)
-           msg_info("%s: SNI hostname: %s", props->namaddr, sni);
-    }
-#endif
 
     /*
      * Before really starting anything, try to seed the PRNG a little bit
@@ -1096,8 +1098,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     if (log_mask & TLS_LOG_TLSPKTS)
        BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
 
-    tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext);
-
     /*
      * If we don't trigger the handshake in the library, leave control over
      * SSL_connect/read/write/etc with the application.
@@ -1170,7 +1170,8 @@ TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext,
         * fingerprint first, and avoid logging verified as untrusted in the
         * call to verify_extract_name().
         */
-       verify_extract_print(TLScontext, peercert, props);
+       TLScontext->peer_cert_fprint = tls_cert_fprint(peercert, props->mdalg);
+       TLScontext->peer_pkey_fprint = tls_pkey_fprint(peercert, props->mdalg);
        verify_extract_name(TLScontext, peercert, props);
 
        if (TLScontext->log_mask &
@@ -1204,18 +1205,6 @@ TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext,
     if (TLScontext->stream != 0)
        tls_stream_start(props->stream, TLScontext);
 
-    /*
-     * Fully secured only if trusted, matched and not insecure like halfdane.
-     * Should perhaps also exclude "verify" (as opposed to "secure") here,
-     * because that can be subject to insecure MX indirection, but that's
-     * rather incompatible.  Users have been warned.
-     */
-    if (TLS_CERT_IS_PRESENT(TLScontext)
-       && TLS_CERT_IS_TRUSTED(TLScontext)
-       && TLS_CERT_IS_MATCHED(TLScontext)
-       && !TLS_NEVER_SECURED(props->tls_level))
-       TLScontext->peer_status |= TLS_CERT_FLAG_SECURED;
-
     /*
      * With the handshake done, extract TLS 1.3 signature metadata.
      */
index 013426b1197426809fbdea0cd1bddef806bc1a66..a31a513742201806aa1ca868fa2e58774c7bc22a 100644 (file)
@@ -6,91 +6,96 @@
 /* SYNOPSIS
 /*     #include <tls.h>
 /*
+/*     void tls_dane_loglevel(log_param, log_level);
+/*     const char *log_param;
+/*     const char *log_level;
+/*
 /*     int     tls_dane_avail()
 /*
 /*     void    tls_dane_flush()
 /*
-/*     void    tls_dane_verbose(on)
-/*     int     on;
-/*
 /*     TLS_DANE *tls_dane_alloc()
 /*
+/*      void    tls_tlsa_free(tlsa)
+/*      TLS_TLSA *tlsa;
+/*
 /*     void    tls_dane_free(dane)
 /*     TLS_DANE *dane;
 /*
-/*     void    tls_dane_add_ee_digests(dane, mdalg, digest, delim)
+/*     void    tls_dane_add_fpt_digests(dane, digest, delim, smtp_mode)
 /*     TLS_DANE *dane;
-/*     const char *mdalg;
 /*     const char *digest;
 /*     const char *delim;
+/*     int     smtp_mode;
+/*
+/*     TLS_TLSA *tlsa_prepend(tlsa, usage, selector, mtype, data, len)
+/*     TLS_TLSA *tlsa;
+/*     uint8_t usage;
+/*     uint8_t selector;
+/*     uint8_t mtype;
+/*     const unsigned char *data;
+/*     uint16_t length;
 /*
 /*     int     tls_dane_load_trustfile(dane, tafile)
 /*     TLS_DANE *dane;
 /*     const char *tafile;
 /*
-/*     int     tls_dane_match(TLSContext, usage, cert, depth)
-/*     TLS_SESS_STATE *TLScontext;
-/*     int     usage;
-/*     X509    *cert;
-/*     int     depth;
-/*
-/*     void    tls_dane_set_callback(ssl_ctx, TLScontext)
-/*     SSL_CTX *ssl_ctx;
-/*     TLS_SESS_STATE *TLScontext;
-/*
 /*     TLS_DANE *tls_dane_resolve(port, proto, hostrr, forcetlsa)
 /*     unsigned port;
 /*     const char *proto;
 /*     DNS_RR *hostrr;
 /*     int     forcetlsa;
 /*
+/*     void    tls_dane_digest_init(ctx, fpt_alg)
+/*     SSL_CTX *ctx;
+/*     const EVP_MD *fpt_alg;
+/*
+/*     void    tls_dane_enable(TLScontext)
+/*     TLS_SESS_STATE *TLScontext;
+/*
+/*     void    tls_dane_log(TLScontext)
+/*     TLS_SESS_STATE *TLScontext;
+/*
 /*     int     tls_dane_unusable(dane)
 /*     const TLS_DANE *dane;
 /*
 /*     int     tls_dane_notfound(dane)
 /*     const TLS_DANE *dane;
 /* DESCRIPTION
+/*     tls_dane_loglevel() allows the policy lookup functions in the DANE
+/*     library to examine the application's TLS loglevel in and possibly
+/*     produce a more detailed activity log.
+/*
 /*     tls_dane_avail() returns true if the features required to support DANE
-/*     are present in OpenSSL's libcrypto and in libresolv.  Since OpenSSL's
-/*     libcrypto is not initialized until we call tls_client_init(), calls
-/*     to tls_dane_avail() must be deferred until this initialization is
-/*     completed successufully.
+/*     are present in libresolv.
 /*
 /*     tls_dane_flush() flushes all entries from the cache, and deletes
 /*     the cache.
 /*
-/*     tls_dane_verbose() turns on verbose logging of TLSA record lookups.
-/*
 /*     tls_dane_alloc() returns a pointer to a newly allocated TLS_DANE
 /*     structure with null ta and ee digest sublists.
 /*
+/*     tls_tlsa_free() frees a TLSA record linked list.
+/*
 /*     tls_dane_free() frees the structure allocated by tls_dane_alloc().
 /*
-/*     tls_dane_add_ee_digests() splits "digest" using the characters in
-/*     "delim" as delimiters and stores the results on the EE match list
-/*     to match either a certificate or a public key.  This is an incremental
+/*     tls_dane_digest_init() configures OpenSSL to support the configured
+/*     DANE TLSA digests and private-use fingerprint digest.
+/*
+/*     tlsa_prepend() prepends a TLSA record to the head of a linked list
+/*     which may be null when the list is empty. The result value is the
+/*     new list head.
+/*
+/*     tls_dane_add_fpt_digests() splits "digest" using the characters in
+/*     "delim" as delimiters and generates corresponding synthetic DANE TLSA
+/*     records with matching type 255 (private-use), which we associated with
+/*     the configured fingerprint digest algorithm.  This is an incremental
 /*     interface, that builds a TLS_DANE structure outside the cache by
 /*     manually adding entries.
 /*
 /*     tls_dane_load_trustfile() imports trust-anchor certificates and
 /*     public keys from a file (rather than DNS TLSA records).
 /*
-/*     tls_dane_match() matches the full and/or public key digest of
-/*     "cert" against each candidate digest in TLScontext->dane. If usage
-/*     is TLS_DANE_EE, the match is against end-entity digests, otherwise
-/*     it is against trust-anchor digests.  Returns true if a match is found,
-/*     false otherwise.
-/*
-/*     tls_dane_set_callback() wraps the SSL certificate verification logic
-/*     in a function that modifies the input trust chain and trusted
-/*     certificate store to map DANE TA validation onto the existing PKI
-/*     verification model.  When TLScontext is NULL the callback is
-/*     cleared, otherwise it is set.  This callback should only be set
-/*     when out-of-band trust-anchors (via DNSSEC DANE TLSA records or
-/*     per-destination local configuration) are provided.  Such trust
-/*     anchors always override the legacy public CA PKI.  Otherwise, the
-/*     callback MUST be cleared.
-/*
 /*     tls_dane_resolve() maps a (port, protocol, hostrr) tuple to a
 /*     corresponding TLS_DANE policy structure found in the DNS.  The port
 /*     argument is in network byte order.  A null pointer is returned when
 /*     return value is a pointer to the corresponding TLS_DANE structure.
 /*     The caller must free the structure via tls_dane_free().
 /*
+/*     tls_dane_enable() enables DANE-style certificate checks for connections
+/*     that are configured with TLSA records.  The TLSA records may be from
+/*     DNS (at the "dane", "dane-only" and "half-dane" security levels), or be
+/*     synthetic in support of either the "fingerprint" level or local trust
+/*     anchor based validation with the "secure" and "verify" levels.  The
+/*     return value is the number of "usable" TLSA records loaded, or negative
+/*     if a record failed to load due to an internal OpenSSL problems, rather
+/*     than an issue with the record making that record "unusable".
+/*
+/*     tls_dane_log() logs successful verification via DNS-based or
+/*     synthetic DANE TLSA RRs (fingerprint or "tafile").
+/*
 /*     tls_dane_unusable() checks whether a cached TLS_DANE record is
 /*     the result of a validated RRset, with no usable elements.  In
 /*     this case, TLS is mandatory, but certificate verification is
 /*     a mandatory TLS fallback policy.
 /*
 /*     Arguments:
+/* .IP  ctx
+/*     SSL context to be configured with the chosen digest algorithms.
+/* .IP  fpt_alg
+/*     The OpenSSL EVP digest algorithm handle for the fingerprint digest.
+/* .IP  tlsa
+/*     TLSA record linked list head, initially NULL.
+/* .IP  usage
+/*     DANE TLSA certificate usage field.
+/* .IP  selector
+/*     DANE TLSA selector field.
+/* .IP  mtype
+/*     DANE TLSA matching type field
+/* .IP  data
+/*     DANE TLSA associated data field (raw binary form), copied for internal
+/*     use.  The caller is responsible for freeing his own copy.
+/* .IP  length
+/*     Length of DANE TLSA associated DATA field.
 /* .IP dane
 /*     Pointer to a TLS_DANE structure that lists the valid trust-anchor
 /*     and end-entity full-certificate and/or public-key digests.
 /*     When true, TLSA lookups are performed even when the qname and rname
 /*     are insecure.  This is only useful in the unlikely case that DLV is
 /*     used to secure the TLSA RRset in an otherwise insecure zone.
-/* .IP TLScontext
-/*     Client context with TA/EE matching data and related state.
-/* .IP usage
-/*     Trust anchor (TLS_DANE_TA) or end-entity (TLS_DANE_EE) digests?
-/* .IP cert
-/*     Certificate from peer trust chain (CA or leaf server).
-/* .IP depth
-/*     The certificate depth for logging.
-/* .IP ssl_ctx
-/*     The global SSL_CTX structure used to initialize child SSL
-/*     conenctions.
-/* .IP mdalg
-/*     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 log_param
+/*     The TLS log level parameter name whose value is the log_level argument.
+/* .IP log_level
+/*     The application TLS log level, which may affect dane lookup verbosity.
 /* .IP digest
 /*     The digest (or list of digests concatenated with characters from
 /*     "delim") to be added to the TLS_DANE record.
 /* .IP delim
 /*     The set of delimiter characters used above.
+/* .IP smtp_mode
+/*     Is the caller an SMTP client or an LMTP client?
+/* .IP tafile;
+/*     A file with trust anchor certificates or public keys in PEM format.
 /* LICENSE
 /* .ad
 /* .fi
 #include <msg.h>
 #include <mymalloc.h>
 #include <stringops.h>
+#include <midna_domain.h>
 #include <vstring.h>
 #include <events.h>                    /* event_time() */
 #include <timecmp.h>
 
 #undef DANE_TLSA_SUPPORT
 
-#if defined(TLSEXT_MAXLEN_host_name) && RES_USE_DNSSEC && RES_USE_EDNS0
+#if RES_USE_DNSSEC && RES_USE_EDNS0
 #define DANE_TLSA_SUPPORT
 static int dane_tlsa_support = 1;
 
@@ -216,35 +244,15 @@ static int dane_tlsa_support = 0;
 
 #endif
 
-static const char *signalg;
-static ASN1_OBJECT *serverAuth;
-
 /*
- * https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml
+ * A NULL alg field disables the algorithm at the codepoint passed to the
+ * SSL_CTX_dane_mtype_set(3) function.  The ordinals are used for digest
+ * agility, higher is "better" (presumed stronger).
  */
-typedef struct {
-    const char *mdalg;
-    uint8_t dane_id;
-} iana_digest;
-
-static iana_digest iana_table[] = {
-    {"", DNS_TLSA_MATCHING_TYPE_NO_HASH_USED},
-    {"sha256", DNS_TLSA_MATCHING_TYPE_SHA256},
-    {"sha512", DNS_TLSA_MATCHING_TYPE_SHA512},
-    {0, 0}
-};
-
-typedef struct dane_digest {
-    struct dane_digest *next;          /* linkage */
-    const char *mdalg;                 /* OpenSSL name */
-    const EVP_MD *md;                  /* OpenSSL EVP handle */
-    int     len;                       /* digest octet length */
-    int     pref;                      /* tls_dane_digests index or -1 */
-    uint8_t dane_id;                   /* IANA id */
-} dane_digest;
-
-#define MAXDIGESTS 256                 /* RFC limit */
-static dane_digest *digest_list;
+typedef struct dane_mtype {
+    const EVP_MD *alg;
+    uint8_t ord;
+} dane_mtype;
 
 /*
  * This is not intended to be a long-term cache of pre-parsed TLSA data,
@@ -255,213 +263,29 @@ static dane_digest *digest_list;
 #define CACHE_SIZE 20
 static CTABLE *dane_cache;
 
-static int dane_initialized;
-static int dane_verbose;
-
-/* tls_dane_verbose - enable/disable verbose logging */
-
-void    tls_dane_verbose(int on)
-{
-    dane_verbose = on;
-}
-
-/* add_digest - validate and append digest to digest list */
-
-static dane_digest *add_digest(char *mdalg, int pref)
-{
-    iana_digest *i;
-    dane_digest *d;
-    int     dane_id = -1;
-    const char *dane_mdalg = mdalg;
-    char   *value = split_at(mdalg, '=');
-    const EVP_MD *md = 0;
-    size_t  mdlen = 0;
-
-    if (value && *value) {
-       unsigned long l;
-       char   *endcp;
-
-       /*
-        * XXX: safe_strtoul() does not flag empty or white-space only input.
-        * Since we get idbuf by splitting white-space/comma delimited
-        * tokens, this is not a problem here. Fixed as of 210131209.
-        */
-       l = safe_strtoul(value, &endcp, 10);
-       if ((l == 0 && (errno == EINVAL || endcp == value))
-           || l >= MAXDIGESTS
-           || *endcp) {
-           msg_warn("Invalid matching type number in %s: %s=%s",
-                    VAR_TLS_DANE_DIGESTS, mdalg, value);
-           return (0);
-       }
-       dane_id = l;
-    }
-
-    /*
-     * Check for known IANA conflicts
-     */
-    for (i = iana_table; i->mdalg; ++i) {
-       if (*mdalg && strcasecmp(i->mdalg, mdalg) == 0) {
-           if (dane_id >= 0 && i->dane_id != dane_id) {
-               msg_warn("Non-standard value in %s: %s%s%s",
-                        VAR_TLS_DANE_DIGESTS, mdalg,
-                        value ? "=" : "", value ? value : "");
-               return (0);
-           }
-           dane_id = i->dane_id;
-       } else if (i->dane_id == dane_id) {
-           if (*mdalg) {
-               msg_warn("Non-standard algorithm in %s: %s%s%s",
-                        VAR_TLS_DANE_DIGESTS, mdalg,
-                        value ? "=" : "", value ? value : "");
-               return (0);
-           }
-           dane_mdalg = i->mdalg;
-       }
-    }
-
-    /*
-     * Check for unknown implicit digest or value
-     */
-    if (dane_id < 0 || (dane_id > 0 && !*dane_mdalg)) {
-       msg_warn("Unknown incompletely specified element in %s: %s%s%s",
-                VAR_TLS_DANE_DIGESTS, mdalg,
-                value ? "=" : "", value ? value : "");
-       return 0;
-    }
-
-    /*
-     * Check for duplicate entries
-     */
-    for (d = digest_list; d; d = d->next) {
-       if (strcasecmp(d->mdalg, dane_mdalg) == 0
-           || d->dane_id == dane_id) {
-           msg_warn("Duplicate element in %s: %s%s%s",
-                    VAR_TLS_DANE_DIGESTS, mdalg,
-                    value ? "=" : "", value ? value : "");
-           return (0);
-       }
-    }
-
-    if (*dane_mdalg
-       && ((md = EVP_get_digestbyname(dane_mdalg)) == 0
-           || (mdlen = EVP_MD_size(md)) <= 0
-           || mdlen > EVP_MAX_MD_SIZE)) {
-       msg_warn("Unimplemented digest algorithm in %s: %s%s%s",
-                VAR_TLS_DANE_DIGESTS, mdalg,
-                value ? "=" : "", value ? value : "");
-       return (0);
-    }
-    d = (dane_digest *) mymalloc(sizeof(*d));
-    d->next = digest_list;
-    d->mdalg = mystrdup(dane_mdalg);
-    d->md = md;
-    d->len = mdlen;
-    d->pref = pref;
-    d->dane_id = dane_id;
-
-    return (digest_list = d);
-}
-
-/* digest_byid - locate digest_table entry for given IANA id */
-
-static dane_digest *digest_byid(uint8_t dane_id)
-{
-    dane_digest *d;
-
-    for (d = digest_list; d; d = d->next)
-       if (d->dane_id == dane_id)
-           return (d);
-    return (0);
-}
+static int log_mask;
 
-/* digest_pref_byid - digest preference by IANA id */
+/* tls_dane_logmask - configure policy lookup logging */
 
-static int digest_pref_byid(uint8_t dane_id)
+void    tls_dane_loglevel(const char *log_param, const char *log_level)
 {
-    dane_digest *d = digest_byid(dane_id);
-
-    return (d ? (d->pref) : (MAXDIGESTS + dane_id));
-}
-
-/* dane_init - initialize DANE parameters */
-
-static void dane_init(void)
-{
-    int     digest_pref = 0;
-    char   *cp;
-    char   *save;
-    char   *tok;
-    static char fullmtype[] = "=0";
-    dane_digest *d;
-
-    /*
-     * Add the full matching type at highest preference and then the users
-     * configured list.
-     * 
-     * The most preferred digest will be used for hashing full values for
-     * comparison.
-     */
-    if (add_digest(fullmtype, 0)) {
-       save = cp = mystrdup(var_tls_dane_digests);
-       while ((tok = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
-           if ((d = add_digest(tok, ++digest_pref)) == 0) {
-               signalg = 0;
-               break;
-           }
-           if (digest_pref == 1) {
-               signalg = d->mdalg;
-           }
-       }
-       myfree(save);
-    }
-    /* Don't report old news */
-    ERR_clear_error();
-
-    /*
-     * DANE TLSA support requires working DANE digests.
-     */
-    if ((serverAuth = OBJ_nid2obj(NID_server_auth)) == 0) {
-       msg_warn("cannot designate intermediate TA certificates, "
-                "no DANE support");
-       tls_print_errors();
-       dane_tlsa_support = 0;
-    } else if (signalg == 0) {
-       msg_warn("digest algorithm initializaton failed, no DANE support");
-       tls_print_errors();
-       dane_tlsa_support = 0;
-    }
-    dane_initialized = 1;
+    log_mask = tls_log_mask(log_param, log_level);
 }
 
 /* tls_dane_avail - check for availability of dane required digests */
 
 int     tls_dane_avail(void)
 {
-    if (!dane_initialized)
-       dane_init();
     return (dane_tlsa_support);
 }
 
-/* tls_dane_flush - flush the cache */
-
-void    tls_dane_flush(void)
-{
-    if (dane_cache)
-       ctable_free(dane_cache);
-    dane_cache = 0;
-}
-
 /* tls_dane_alloc - allocate a TLS_DANE structure */
 
 TLS_DANE *tls_dane_alloc(void)
 {
     TLS_DANE *dane = (TLS_DANE *) mymalloc(sizeof(*dane));
 
-    dane->ta = 0;
-    dane->ee = 0;
-    dane->certs = 0;
-    dane->pkeys = 0;
+    dane->tlsa = 0;
     dane->base_domain = 0;
     dane->flags = 0;
     dane->expires = 0;
@@ -469,342 +293,229 @@ TLS_DANE *tls_dane_alloc(void)
     return (dane);
 }
 
-static void ta_cert_insert(TLS_DANE *d, X509 *x)
-{
-    TLS_CERTS *new = (TLS_CERTS *) mymalloc(sizeof(*new));
-
-    X509_up_ref(x);
-    new->cert = x;
-    new->next = d->certs;
-    d->certs = new;
-}
-
-static void free_ta_certs(TLS_DANE *d)
-{
-    TLS_CERTS *head;
-    TLS_CERTS *next;
-
-    for (head = d->certs; head; head = next) {
-       next = head->next;
-       X509_free(head->cert);
-       myfree((void *) head);
-    }
-}
-
-static void ta_pkey_insert(TLS_DANE *d, EVP_PKEY *k)
-{
-    TLS_PKEYS *new = (TLS_PKEYS *) mymalloc(sizeof(*new));
-
-    EVP_PKEY_up_ref(k);
-    new->pkey = k;
-    new->next = d->pkeys;
-    d->pkeys = new;
-}
+/* tls_tlsa_free - free a TLSA RR linked list */
 
-static void free_ta_pkeys(TLS_DANE *d)
+void    tls_tlsa_free(TLS_TLSA *tlsa)
 {
-    TLS_PKEYS *head;
-    TLS_PKEYS *next;
+    TLS_TLSA *next;
 
-    for (head = d->pkeys; head; head = next) {
-       next = head->next;
-       EVP_PKEY_free(head->pkey);
-       myfree((void *) head);
+    for (; tlsa; tlsa = next) {
+       next = tlsa->next;
+       myfree(tlsa->data);
+       myfree(tlsa);
     }
 }
 
-static void tlsa_free(TLS_TLSA *tlsa)
-{
-
-    myfree(tlsa->mdalg);
-    if (tlsa->certs)
-       argv_free(tlsa->certs);
-    if (tlsa->pkeys)
-       argv_free(tlsa->pkeys);
-    myfree((void *) tlsa);
-}
-
 /* tls_dane_free - free a TLS_DANE structure */
 
 void    tls_dane_free(TLS_DANE *dane)
 {
-    TLS_TLSA *tlsa;
-    TLS_TLSA *next;
-
     if (--dane->refs > 0)
        return;
-
-    /* De-allocate TA and EE lists */
-    for (tlsa = dane->ta; tlsa; tlsa = next) {
-       next = tlsa->next;
-       tlsa_free(tlsa);
-    }
-    for (tlsa = dane->ee; tlsa; tlsa = next) {
-       next = tlsa->next;
-       tlsa_free(tlsa);
-    }
-
-    /* De-allocate full trust-anchor certs and pkeys */
-    free_ta_certs(dane);
-    free_ta_pkeys(dane);
     if (dane->base_domain)
        myfree(dane->base_domain);
-
+    if (dane->tlsa)
+       tls_tlsa_free(dane->tlsa);
     myfree((void *) dane);
 }
 
-/* dane_free - ctable style */
+/* tlsa_prepend - Prepend internal-form TLSA record to the RRset linked list */
 
-static void dane_free(void *dane, void *unused_context)
+TLS_TLSA *tlsa_prepend(TLS_TLSA *tlsa, uint8_t usage, uint8_t selector,
+                              uint8_t mtype, const unsigned char *data,
+                              uint16_t data_len)
 {
-    tls_dane_free((TLS_DANE *) dane);
+    TLS_TLSA *head;
+
+    head = (TLS_TLSA *) mymalloc(sizeof(*head));
+    head->usage = usage;
+    head->selector = selector;
+    head->mtype = mtype;
+    head->length = data_len;
+    head->data = (unsigned char *) mymemdup(data, data_len);
+    head->next = tlsa;
+    return (head);
 }
 
-/* dane_locate - list head address of TLSA sublist for given algorithm */
+#define MAX_HEAD_BYTES 32
+#define MAX_TAIL_BYTES 32
+#define MAX_DUMP_BYTES (MAX_HEAD_BYTES + MAX_TAIL_BYTES)
 
-static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
-{
-    TLS_TLSA *new;
+/* tlsa_info - log import of a particular TLSA record */
 
-    /*
-     * Correct computation of the session cache serverid requires a TLSA
-     * digest list that is sorted by algorithm name.  Below we maintain the
-     * sort order (by algorithm name canonicalized to lowercase).
-     */
-    for (; *tlsap; tlsap = &(*tlsap)->next) {
-       int     cmp = strcasecmp(mdalg, (*tlsap)->mdalg);
-
-       if (cmp == 0)
-           return (tlsap);
-       if (cmp < 0)
-           break;
-    }
-
-    new = (TLS_TLSA *) mymalloc(sizeof(*new));
-    new->mdalg = lowercase(mystrdup(mdalg));
-    new->certs = 0;
-    new->pkeys = 0;
-    new->next = *tlsap;
-    *tlsap = new;
-
-    return (tlsap);
-}
-
-/* tls_dane_add_ee_digests - split and append digests */
-
-void    tls_dane_add_ee_digests(TLS_DANE *dane, const char *mdalg,
-                                     const char *digest, const char *delim)
+static void tlsa_info(const char *tag, const char *msg,
+                             uint8_t u, uint8_t s, uint8_t m,
+                             const unsigned char *data, ssize_t dlen)
 {
-    TLS_TLSA **tlsap = dane_locate(&dane->ee, mdalg);
-    TLS_TLSA *tlsa = *tlsap;
-
-    /* Delimited append, may append nothing */
-    if (tlsa->pkeys == 0)
-       tlsa->pkeys = argv_split(digest, delim);
-    else
-       argv_split_append(tlsa->pkeys, digest, delim);
-
-    /* Remove empty elements from the list */
-    if (tlsa->pkeys->argc == 0) {
-       argv_free(tlsa->pkeys);
-       tlsa->pkeys = 0;
-
-       if (tlsa->certs == 0) {
-           *tlsap = tlsa->next;
-           tlsa_free(tlsa);
-       }
-       return;
+    static VSTRING *top;
+    static VSTRING *bot;
+
+    if (top == 0)
+       top = vstring_alloc(2 * MAX_HEAD_BYTES);
+    if (bot == 0)
+       bot = vstring_alloc(2 * MAX_TAIL_BYTES);
+
+    if (dlen > MAX_DUMP_BYTES) {
+       hex_encode(top, (char *) data, MAX_HEAD_BYTES);
+       hex_encode(bot, (char *) data + dlen - MAX_TAIL_BYTES, MAX_TAIL_BYTES);
+    } else if (dlen > 0) {
+       hex_encode(top, (char *) data, dlen);
+    } else {
+       vstring_sprintf(top, "...");
     }
 
-    /*
-     * At the "fingerprint" security level certificate digests and public key
-     * digests are interchangeable.  Each leaf certificate is matched via
-     * either the public key digest or full certificate digest.  The DER
-     * encoding of a certificate is not a valid public key, and conversely,
-     * the DER encoding of a public key is not a valid certificate.  An
-     * attacker would need a 2nd-preimage that is feasible across types
-     * (given cert digest == some pkey digest) and yet presumably difficult
-     * within a type (e.g. given cert digest == some other cert digest).  No
-     * such attacks are known at this time, and it is expected that if any
-     * are found they would work within as well as across the cert/pkey data
-     * types.
-     */
-    if (tlsa->certs == 0)
-       tlsa->certs = argv_split(digest, delim);
-    else
-       argv_split_append(tlsa->certs, digest, delim);
+    msg_info("%s: %s: %u %u %u %s%s%s", tag, msg, u, s, m, STR(top),
+            dlen > MAX_DUMP_BYTES ? "..." : "",
+            dlen > MAX_DUMP_BYTES ? STR(bot) : "");
 }
 
-/* dane_add - add a digest entry */
+/* tlsa_carp - carp about a particular TLSA record */
 
-static void dane_add(TLS_DANE *dane, int certusage, int selector,
-                            const char *mdalg, char *digest)
+static void tlsa_carp(const char *s1, const char *s2, const char *s3,
+                           const char *s4, uint8_t u, uint8_t s, uint8_t m,
+                             const unsigned char *data, ssize_t dlen)
 {
-    TLS_TLSA **tlsap;
-    TLS_TLSA *tlsa;
-    ARGV  **argvp;
-
-    switch (certusage) {
-    case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
-       certusage = TLS_DANE_TA;
-       break;
-    case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
-       certusage = TLS_DANE_EE;                /* Collapse 1/3 -> 3 */
-       break;
-    default:
-       msg_panic("Unsupported DANE certificate usage: %d", certusage);
-    }
-
-    switch (selector) {
-    case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
-       selector = TLS_DANE_CERT;
-       break;
-    case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
-       selector = TLS_DANE_PKEY;
-       break;
-    default:
-       msg_panic("Unsupported DANE selector: %d", selector);
+    static VSTRING *top;
+    static VSTRING *bot;
+
+    if (top == 0)
+       top = vstring_alloc(2 * MAX_HEAD_BYTES);
+    if (bot == 0)
+       bot = vstring_alloc(2 * MAX_TAIL_BYTES);
+
+    if (dlen > MAX_DUMP_BYTES) {
+       hex_encode(top, (char *) data, MAX_HEAD_BYTES);
+       hex_encode(bot, (char *) data + dlen - MAX_TAIL_BYTES, MAX_TAIL_BYTES);
+    } else if (dlen > 0) {
+       hex_encode(top, (char *) data, dlen);
+    } else {
+       vstring_sprintf(top, "...");
     }
 
-    tlsap = (certusage == TLS_DANE_EE) ? &dane->ee : &dane->ta;
-    tlsa = *(tlsap = dane_locate(tlsap, mdalg));
-    argvp = (selector == TLS_DANE_PKEY) ? &tlsa->pkeys : &tlsa->certs;
-
-    if (*argvp == 0)
-       *argvp = argv_alloc(1);
-    argv_add(*argvp, digest, ARGV_END);
+    msg_warn("%s%s%s%s: %u %u %u %s%s%s", s1, s2, s3, s4, u, s, m, STR(top),
+            dlen > MAX_DUMP_BYTES ? "..." : "",
+            dlen > MAX_DUMP_BYTES ? STR(bot) : "");
 }
 
-#define FILTER_CTX_AGILITY_OK          (1<<0)
-#define FILTER_CTX_APPLY_AGILITY       (1<<1)
-#define FILTER_CTX_PARSE_DATA          (1<<2)
-
-#define FILTER_RR_DROP                 0
-#define FILTER_RR_KEEP                 1
-
-typedef struct filter_ctx {
-    TLS_DANE *dane;                    /* Parsed result */
-    int     count;                     /* Digest mtype count */
-    int     target;                    /* Digest mtype target count */
-    int     flags;                     /* Action/result bitmask */
-} filter_ctx;
-
-typedef int (*tlsa_filter) (DNS_RR *, filter_ctx *);
-
-/* tlsa_apply - apply filter to each rr in turn */
+/* tls_dane_flush - flush the cache */
 
-static DNS_RR *tlsa_apply(DNS_RR *rr, tlsa_filter filter, filter_ctx *ctx)
+void    tls_dane_flush(void)
 {
-    DNS_RR *head = 0;                  /* First retained RR */
-    DNS_RR *tail = 0;                  /* Last retained RR */
-    DNS_RR *next;
-
-    /*
-     * XXX Code that modifies or destroys DNS_RR lists or entries belongs in
-     * the DNS library, not here.
-     */
-    for ( /* nop */ ; rr; rr = next) {
-       next = rr->next;
-
-       if (filter(rr, ctx) == FILTER_RR_KEEP) {
-           tail = rr;
-           if (!head)
-               head = rr;
-       } else {
-           if (tail)
-               tail->next = rr->next;
-           rr->next = 0;
-           dns_rr_free(rr);
-       }
-    }
-    return (head);
+    if (dane_cache)
+       ctable_free(dane_cache);
+    dane_cache = 0;
 }
 
-/* usmdelta - packed usage/selector/mtype bits changing in next record */
+/* dane_free - ctable style */
 
-static unsigned int usmdelta(uint8_t u, uint8_t s, uint8_t m, DNS_RR *next)
+static void dane_free(void *dane, void *unused_context)
 {
-    uint8_t *ip = (next && next->data_len >= 3) ? (uint8_t *) next->data : 0;
-    uint8_t nu = ip ? *ip++ : ~u;
-    uint8_t ns = ip ? *ip++ : ~s;
-    uint8_t nm = ip ? *ip++ : ~m;
-
-    return (((u ^ nu) << 16) | ((s ^ ns) << 8) | (m ^ nm));
+    tls_dane_free((TLS_DANE *) dane);
 }
 
-/* tlsa_rr_cmp - qsort TLSA rrs in case shuffled by name server */
+/* tls_dane_add_fpt_digests - map fingerprint list to DANE TLSA RRset */
 
-static int tlsa_rr_cmp(DNS_RR *a, DNS_RR *b)
+void    tls_dane_add_fpt_digests(TLS_DANE *dane, const char *digest,
+                                        const char *delim, int smtp_mode)
 {
-    int     cmp;
+    ARGV   *values = argv_split(digest, delim);
+    ssize_t i;
+
+    if (smtp_mode) {
+       if (warn_compat_break_smtp_tls_fpt_dgst)
+           msg_info("using backwards-compatible default setting "
+                    VAR_SMTP_TLS_FPT_DGST "=md5 to compute certificate "
+                    "fingerprints");
+    } else {
+       if (warn_compat_break_lmtp_tls_fpt_dgst)
+           msg_info("using backwards-compatible default setting "
+                    VAR_LMTP_TLS_FPT_DGST "=md5 to compute certificate "
+                    "fingerprints");
+    }
 
-    /*
-     * Sort in ascending order, by usage, selector, matching type preference
-     * and payload.  The usage, selector and matching type are the first
-     * three unsigned octets of the RR data.
-     */
-    if (a->data_len > 2 && b->data_len > 2) {
-       uint8_t *ai = (uint8_t *) a->data;
-       uint8_t *bi = (uint8_t *) b->data;
+    for (i = 0; i < values->argc; ++i) {
+       const char *cp = values->argv[i];
+       size_t  ilen = strlen(cp);
+       VSTRING *raw;
 
-#define signedcmp(x, y) (((int)(x)) - ((int)(y)))
+       /*
+        * Decode optionally colon-separated hex-encoded string, the input
+        * value requires at most 3 bytes per byte of payload, which must not
+        * exceed the size of the widest supported hash function.
+        */
+       if (ilen > 3 * EVP_MAX_MD_SIZE) {
+           msg_warn("malformed fingerprint value: %.100s...",
+                    values->argv[i]);
+           continue;
+       }
+       raw = vstring_alloc(ilen / 2);
+       if (hex_decode_opt(raw, cp, ilen, HEX_DECODE_FLAG_ALLOW_COLON) == 0) {
+           myfree(raw);
+           msg_warn("malformed fingerprint value: %.384s", values->argv[i]);
+           continue;
+       }
 
-       if ((cmp = signedcmp(ai[0], bi[0])) != 0
-           || (cmp = signedcmp(ai[1], bi[1])) != 0
-           || (cmp = digest_pref_byid(ai[2]) -
-               digest_pref_byid(bi[2])) != 0)
-           return (cmp);
+       /*
+        * At the "fingerprint" security level certificate digests and public
+        * key digests are interchangeable.  Each leaf certificate is matched
+        * via either the public key digest or full certificate digest.  The
+        * DER encoding of a certificate is not a valid public key, and
+        * conversely, the DER encoding of a public key is not a valid
+        * certificate.  An attacker would need a 2nd-preimage that is
+        * feasible across types (given cert digest == some pkey digest) and
+        * yet presumably difficult within a type (e.g. given cert digest ==
+        * some other cert digest).  No such attacks are known at this time,
+        * and it is expected that if any are found they would work within as
+        * well as across the cert/pkey data types.
+        * 
+        * The private-use matching type "255" is mapped to the configured
+        * fingerprint digest, which may (harmlessly) coincide with one of
+        * the standard DANE digest algorithms.  The private code point is
+        * however unconditionally enabled.
+        */
+       if (log_mask & (TLS_LOG_VERBOSE | TLS_LOG_DANE))
+           tlsa_info("fingerprint", "digest as private-use TLSA record",
+                  3, 0, 255, (unsigned char *) STR(raw), VSTRING_LEN(raw));
+       dane->tlsa = tlsa_prepend(dane->tlsa, 3, 0, 255,
+                             (unsigned char *) STR(raw), VSTRING_LEN(raw));
+       dane->tlsa = tlsa_prepend(dane->tlsa, 3, 1, 255,
+                             (unsigned char *) STR(raw), VSTRING_LEN(raw));
+       vstring_free(raw);
     }
-    if ((cmp = a->data_len - b->data_len) != 0)
-       return (cmp);
-    return (memcmp(a->data, b->data, a->data_len));
+    argv_free(values);
 }
 
 /* parse_tlsa_rr - parse a validated TLSA RRset */
 
-static int parse_tlsa_rr(DNS_RR *rr, filter_ctx *ctx)
+static int parse_tlsa_rr(TLS_DANE *dane, DNS_RR *rr)
 {
-    uint8_t *ip;
+    const uint8_t *ip;
     uint8_t usage;
     uint8_t selector;
     uint8_t mtype;
     ssize_t dlen;
-    const unsigned char *data;
-    const unsigned char *p;
+    unsigned const char *data;
     int     iscname = strcasecmp(rr->rname, rr->qname);
-    const char *q = (iscname) ? (rr)->qname : "";
-    const char *a = (iscname) ? " -> " : "";
+    const char *q = iscname ? rr->qname : "";
+    const char *a = iscname ? " -> " : "";
     const char *r = rr->rname;
-    unsigned int change;
 
     if (rr->type != T_TLSA)
-       msg_panic("unexpected non-TLSA RR type %u for %s%s%s", rr->type,
-                 q, a, r);
+       msg_panic("%s%s%s: unexpected non-TLSA RR type: %u",
+                 q, a, r, rr->type);
 
     /* Drop truncated records */
     if ((dlen = rr->data_len - 3) < 0) {
-       msg_warn("truncated length %u RR: %s%s%s IN TLSA ...",
-                (unsigned) rr->data_len, q, a, r);
-       ctx->flags &= ~FILTER_CTX_AGILITY_OK;
-       return (FILTER_RR_DROP);
+       msg_warn("%s%s%s: truncated TLSA RR length == %u",
+                q, a, r, (unsigned) rr->data_len);
+       return (0);
     }
-    ip = (uint8_t *) rr->data;
+    ip = (const uint8_t *) rr->data;
     usage = *ip++;
     selector = *ip++;
     mtype = *ip++;
-    change = usmdelta(usage, selector, mtype, rr->next);
-    p = data = (const unsigned char *) ip;
+    data = (const unsigned char *) ip;
 
-    /*
-     * Handle digest agility for non-zero matching types.
-     */
-    if (mtype) {
-       if (ctx->count && (ctx->flags & FILTER_CTX_APPLY_AGILITY)) {
-           if (change & 0xffff00)              /* New usage/selector, */
-               ctx->count = 0;                 /* disable drop */
-           return (FILTER_RR_DROP);
-       }
-    }
     /*-
      * Drop unsupported usages.
      * Note: NO SUPPORT for usages 0/1 which do not apply to SMTP.
@@ -814,150 +525,24 @@ static int parse_tlsa_rr(DNS_RR *rr, filter_ctx *ctx)
     case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
        break;
     default:
-       msg_warn("unsupported certificate usage %u in RR: "
-                "%s%s%s IN TLSA %u ...", usage,
-                q, a, r, usage);
-       return (FILTER_RR_DROP);
+       tlsa_carp(q, a, r, "unsupported TLSA certificate usage",
+                 usage, selector, mtype, data, dlen);
+       return (0);
     }
 
     /*
-     * Drop unsupported selectors
+     * Drop private-use matching type, reserved for fingerprint matching.
      */
-    switch (selector) {
-    case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
-    case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
-       break;
-    default:
-       msg_warn("unsupported selector %u in RR: "
-                "%s%s%s IN TLSA %u %u ...", selector,
-                q, a, r, usage, selector);
-       return (FILTER_RR_DROP);
-    }
-
-    if (mtype) {
-       dane_digest *d = digest_byid(mtype);
-
-       if (d == 0) {
-           msg_warn("unsupported matching type %u in RR: "
-                    "%s%s%s IN TLSA %u %u %u ...", mtype,
-                    q, a, r, usage, selector, mtype);
-           return (FILTER_RR_DROP);
-       }
-       if (dlen != d->len) {
-           msg_warn("malformed %s digest, length %lu, in RR: "
-                    "%s%s%s IN TLSA %u %u %u ...",
-                    d->mdalg, (unsigned long) dlen,
-                    q, a, r, usage, selector, mtype);
-           ctx->flags &= ~FILTER_CTX_AGILITY_OK;
-           return (FILTER_RR_DROP);
-       }
-       /* New digest mtype next? Prepare to drop following RRs */
-       if (change && (change & 0xffff00) == 0
-           && (ctx->flags & FILTER_CTX_APPLY_AGILITY))
-           ++ctx->count;
-
-       if (ctx->flags & FILTER_CTX_PARSE_DATA) {
-           char   *digest = tls_digest_encode(data, dlen);
-
-           dane_add(ctx->dane, usage, selector, d->mdalg, digest);
-           if (msg_verbose || dane_verbose)
-               msg_info("using DANE RR: %s%s%s IN TLSA %u %u %u %s",
-                        q, a, r, usage, selector, mtype, digest);
-           myfree(digest);
-       }
-    } else {
-       X509   *x = 0;                  /* OpenSSL re-uses *x if x!=0 */
-       EVP_PKEY *k = 0;                /* OpenSSL re-uses *k if k!=0 */
-
-       /* Validate the cert or public key via d2i_mumble() */
-       switch (selector) {
-       case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
-           if (!d2i_X509(&x, &p, dlen) || dlen != p - data) {
-               msg_warn("malformed %s in RR: "
-                        "%s%s%s IN TLSA %u %u %u ...", "certificate",
-                        q, a, r, usage, selector, mtype);
-               if (x)
-                   X509_free(x);
-               return (FILTER_RR_DROP);
-           }
-           /* Also unusable if public key is malformed or unsupported */
-           k = X509_get_pubkey(x);
-           EVP_PKEY_free(k);
-           if (k == 0) {
-               msg_warn("malformed %s in RR: %s%s%s IN TLSA %u %u %u ...",
-                        "or unsupported certificate public key",
-                        q, a, r, usage, selector, mtype);
-               X509_free(x);
-               return (FILTER_RR_DROP);
-           }
-
-           /*
-            * When a full trust-anchor certificate is published via DNS, we
-            * may need to use it to validate the server trust chain. Store
-            * it away for later use.
-            */
-           if (usage == DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION
-               && (ctx->flags & FILTER_CTX_PARSE_DATA))
-               ta_cert_insert(ctx->dane, x);
-           X509_free(x);
-           break;
-
-       case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
-           if (!d2i_PUBKEY(&k, &p, dlen) || dlen != p - data) {
-               msg_warn("malformed %s in RR: %s%s%s IN TLSA %u %u %u ...",
-                        "public key", q, a, r, usage, selector, mtype);
-               if (k)
-                   EVP_PKEY_free(k);
-               return (FILTER_RR_DROP);
-           }
-
-           /*
-            * When a full trust-anchor public key is published via DNS, we
-            * may need to use it to validate the server trust chain. Store
-            * it away for later use.
-            */
-           if (usage == DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION
-               && (ctx->flags & FILTER_CTX_PARSE_DATA))
-               ta_pkey_insert(ctx->dane, k);
-           EVP_PKEY_free(k);
-           break;
-       }
-
-       /*
-        * The cert or key was valid, just digest the raw object, and encode
-        * the digest value.
-        */
-       if (ctx->flags & FILTER_CTX_PARSE_DATA) {
-           char   *digest = tls_data_fprint((char *) data, dlen, signalg);
-
-           dane_add(ctx->dane, usage, selector, signalg, digest);
-           if (msg_verbose || dane_verbose)
-               msg_info("using DANE RR: %s%s%s IN TLSA %u %u %u <%s>; "
-                        "%s digest %s", q, a, r, usage, selector, mtype,
-                        (selector == DNS_TLSA_SELECTOR_FULL_CERTIFICATE) ?
-                        "certificate" : "public key", signalg, digest);
-           myfree(digest);
-       }
+    if (mtype == 255) {
+       tlsa_carp(q, a, r, "reserved private-use matching type",
+                 usage, selector, mtype, data, dlen);
+       return (0);
     }
-    return (FILTER_RR_KEEP);
-}
-
-/* process_rrs - filter and parse the TLSA RRset */
-
-static DNS_RR *process_rrs(TLS_DANE *dane, DNS_RR *rrset)
-{
-    filter_ctx ctx;
-
-    ctx.dane = dane;
-    ctx.count = ctx.target = 0;
-    ctx.flags = FILTER_CTX_APPLY_AGILITY | FILTER_CTX_PARSE_DATA;
-
-    rrset = tlsa_apply(rrset, parse_tlsa_rr, &ctx);
-
-    if (dane->ta == 0 && dane->ee == 0)
-       dane->flags |= TLS_DANE_FLAG_EMPTY;
-
-    return (rrset);
+    if (log_mask & (TLS_LOG_VERBOSE | TLS_LOG_DANE))
+       tlsa_info("DNSSEC-signed TLSA record", r,
+                 usage, selector, mtype, data, dlen);
+    dane->tlsa = tlsa_prepend(dane->tlsa, usage, selector, mtype, data, dlen);
+    return (1);
 }
 
 /* dane_lookup - TLSA record lookup, ctable style */
@@ -965,14 +550,14 @@ static DNS_RR *process_rrs(TLS_DANE *dane, DNS_RR *rrset)
 static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
 {
     static VSTRING *why = 0;
-    int     ret;
     DNS_RR *rrs = 0;
-    TLS_DANE *dane;
+    DNS_RR *rr;
+    TLS_DANE *dane = tls_dane_alloc();
+    int     ret;
 
     if (why == 0)
        why = vstring_alloc(10);
 
-    dane = tls_dane_alloc();
     ret = dns_lookup(tlsa_fqdn, T_TLSA, RES_USE_DNSSEC, &rrs, 0, why);
 
     switch (ret) {
@@ -986,15 +571,12 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
        dane->expires = 1 + event_time() + rrs->ttl;
 
        if (rrs->dnssec_valid) {
+           int     n = 0;
 
-           /*
-            * Sort for deterministic digest in session cache lookup key. In
-            * addition we must arrange for more preferred matching types
-            * (full value or digest) to precede less preferred ones for the
-            * same usage and selector.
-            */
-           rrs = dns_rr_sort(rrs, tlsa_rr_cmp);
-           rrs = process_rrs(dane, rrs);
+           for (rr = rrs; rr != 0; rr = rr->next)
+               n += parse_tlsa_rr(dane, rr);
+           if (n == 0)
+               dane->flags |= TLS_DANE_FLAG_EMPTY;
        } else
            dane->flags |= TLS_DANE_FLAG_NORRS;
 
@@ -1132,18 +714,11 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
     long    len;
     int     tacount;
     char   *errtype = 0;               /* if error: cert or pkey? */
-    const char *mdalg;
 
     /* nop */
     if (tafile == 0 || *tafile == 0)
        return (1);
 
-    if (!dane_initialized)
-       dane_init();
-
-    /* Per-destination TA support is available even when DANE is not */
-    mdalg = signalg ? signalg : "sha1";
-
     /*
      * On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio,
      * calls PEM_read_bio() and then frees the bio.  It is just as easy to
@@ -1157,41 +732,38 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
     /* Don't report old news */
     ERR_clear_error();
 
+    /*
+     * OpenSSL implements DANE strictly, with DANE-TA(2) only matching issuer
+     * certificates, and never the leaf cert.  We also allow the
+     * trust-anchors to directly match the leaf certificate or public key.
+     */
     for (tacount = 0;
         errtype == 0 && PEM_read_bio(bp, &name, &header, &data, &len);
         ++tacount) {
-       const unsigned char *p = data;
-       int     usage = DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION;
-       int     selector;
-       char   *digest;
+       uint8_t daneta = DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION;
+       uint8_t daneee = DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE;
+       uint8_t mtype = DNS_TLSA_MATCHING_TYPE_NO_HASH_USED;
 
        if (strcmp(name, PEM_STRING_X509) == 0
            || strcmp(name, PEM_STRING_X509_OLD) == 0) {
-           X509   *cert = d2i_X509(0, &p, len);
-
-           if (cert && (p - data) == len) {
-               selector = DNS_TLSA_SELECTOR_FULL_CERTIFICATE;
-               digest = tls_data_fprint((char *) data, len, mdalg);
-               dane_add(dane, usage, selector, mdalg, digest);
-               myfree(digest);
-               ta_cert_insert(dane, cert);
-           } else
-               errtype = "certificate";
-           if (cert)
-               X509_free(cert);
+           uint8_t selector = DNS_TLSA_SELECTOR_FULL_CERTIFICATE;
+
+           if (log_mask & (TLS_LOG_VERBOSE | TLS_LOG_DANE))
+               tlsa_info("TA cert as TLSA record", tafile,
+                         daneta, selector, mtype, data, len);
+           dane->tlsa =
+               tlsa_prepend(dane->tlsa, daneta, selector, mtype, data, len);
+           dane->tlsa =
+               tlsa_prepend(dane->tlsa, daneee, selector, mtype, data, len);
        } else if (strcmp(name, PEM_STRING_PUBLIC) == 0) {
-           EVP_PKEY *pkey = d2i_PUBKEY(0, &p, len);
-
-           if (pkey && (p - data) == len) {
-               selector = DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO;
-               digest = tls_data_fprint((char *) data, len, mdalg);
-               dane_add(dane, usage, selector, mdalg, digest);
-               myfree(digest);
-               ta_pkey_insert(dane, pkey);
-           } else
-               errtype = "public key";
-           if (pkey)
-               EVP_PKEY_free(pkey);
+           uint8_t selector = DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO;
+
+           if (log_mask & (TLS_LOG_VERBOSE | TLS_LOG_DANE))
+               tlsa_info("TA pkey as TLSA record", tafile,
+                         daneta, selector, mtype, data, len);
+           dane->tlsa =
+               tlsa_prepend(dane->tlsa, daneta, selector, mtype, data, len);
+           dane->tlsa = tlsa_prepend(dane->tlsa, daneee, selector, mtype, data, len);
        }
 
        /*
@@ -1219,455 +791,225 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
     return (0);
 }
 
-/* tls_dane_match - match cert against given list of TA or EE digests */
-
-int     tls_dane_match(TLS_SESS_STATE *TLScontext, int usage,
-                              X509 *cert, int depth)
+int     tls_dane_enable(TLS_SESS_STATE *TLScontext)
 {
     const TLS_DANE *dane = TLScontext->dane;
-    TLS_TLSA *tlsa = (usage == TLS_DANE_EE) ? dane->ee : dane->ta;
-    const char *namaddr = TLScontext->namaddr;
-    const char *ustr = (usage == TLS_DANE_EE) ? "end entity" : "trust anchor";
-    int     matched;
-
-    for (matched = 0; tlsa && !matched; tlsa = tlsa->next) {
-       char  **dgst;
+    TLS_TLSA *tp;
+    SSL    *ssl = TLScontext->con;
+    int     usable = 0;
+    int     ret;
 
-       /*
-        * Note, set_trust() needs to know whether the match was for a pkey
-        * digest or a certificate digest.  We return MATCHED_PKEY or
-        * MATCHED_CERT accordingly.
-        */
-#define MATCHED_CERT 1
-#define MATCHED_PKEY 2
-
-       if (tlsa->pkeys) {
-           char   *pkey_dgst = tls_pkey_fprint(cert, tlsa->mdalg);
-
-           for (dgst = tlsa->pkeys->argv; !matched && *dgst; ++dgst)
-               if (strcasecmp(pkey_dgst, *dgst) == 0)
-                   matched = MATCHED_PKEY;
-           if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
-               && matched)
-               msg_info("%s: depth=%d matched %s public-key %s digest=%s",
-                        namaddr, depth, ustr, tlsa->mdalg, pkey_dgst);
-           myfree(pkey_dgst);
+    for (tp = dane->tlsa; tp != 0; tp = tp->next) {
+       ret = SSL_dane_tlsa_add(ssl, tp->usage, tp->selector,
+                               tp->mtype, tp->data, tp->length);
+       if (ret > 0) {
+           ++usable;
+           continue;
        }
-       if (tlsa->certs != 0 && !matched) {
-           char   *cert_dgst = tls_cert_fprint(cert, tlsa->mdalg);
-
-           for (dgst = tlsa->certs->argv; !matched && *dgst; ++dgst)
-               if (strcasecmp(cert_dgst, *dgst) == 0)
-                   matched = MATCHED_CERT;
-           if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
-               && matched)
-               msg_info("%s: depth=%d matched %s certificate %s digest %s",
-                        namaddr, depth, ustr, tlsa->mdalg, cert_dgst);
-           myfree(cert_dgst);
+       if (ret == 0) {
+           tlsa_carp(TLScontext->namaddr, ": ", "", "unusable TLSA RR",
+                     tp->usage, tp->selector, tp->mtype, tp->data,
+                     tp->length);
+           continue;
        }
+       /* Internal problem in OpenSSL */
+       tlsa_carp(TLScontext->namaddr, ": ", "", "error loading trust settings",
+                 tp->usage, tp->selector, tp->mtype, tp->data, tp->length);
+       tls_print_errors();
+       return (-1);
     }
-
-    return (matched);
-}
-
-/* add_ext - add simple extension (no config section references) */
-
-static int add_ext(X509 *issuer, X509 *subject, int ext_nid, char *ext_val)
-{
-    int     ret = 0;
-    X509V3_CTX v3ctx;
-    X509_EXTENSION *ext;
-
-    X509V3_set_ctx(&v3ctx, issuer, subject, 0, 0, 0);
-    if ((ext = X509V3_EXT_conf_nid(0, &v3ctx, ext_nid, ext_val)) != 0) {
-       ret = X509_add_ext(subject, ext, -1);
-       X509_EXTENSION_free(ext);
-    }
-    return ret;
+    return (usable);
 }
 
-/* set_serial - set serial number to match akid or use subject's plus 1 */
+/* tls_dane_digest_init - configure supported DANE digests */
 
-static int set_serial(X509 *cert, AUTHORITY_KEYID *akid, X509 *subject)
+void    tls_dane_digest_init(SSL_CTX *ctx, const EVP_MD * fpt_alg)
 {
-    int     ret = 0;
-    BIGNUM *bn;
-
-    if (akid && akid->serial)
-       return (X509_set_serialNumber(cert, akid->serial));
-
-    /*
-     * Add one to subject's serial to avoid collisions between TA serial and
-     * serial of signing root.
-     */
-    if ((bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(subject), 0)) != 0
-       && BN_add_word(bn, 1)
-       && BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(cert)))
-       ret = 1;
-
-    if (bn)
-       BN_free(bn);
-    return (ret);
-}
+    dane_mtype mtypes[256];
+    char   *cp;
+    char   *save;
+    char   *algname;
+    uint8_t m;
+    uint8_t ord = 0;
+    uint8_t maxtype;
 
-/* add_akid - add authority key identifier */
-
-static int add_akid(X509 *cert, AUTHORITY_KEYID *akid)
-{
-    ASN1_OCTET_STRING *id;
-    unsigned char c = 0;
-    int     nid = NID_authority_key_identifier;
-    int     ret = 0;
+    memset((char *) mtypes, 0, sizeof(mtypes));
 
     /*
-     * 0 will never be our subject keyid from a SHA-1 hash, but it could be
-     * our subject keyid if forced from child's akid.  If so, set our
-     * authority keyid to 1.  This way we are never self-signed, and thus
-     * exempt from any potential (off by default for now in OpenSSL)
-     * self-signature checks!
+     * The DANE SHA2-256(1) and SHA2-512(2) algorithms are disabled, unless
+     * explicitly enabled.  Other codepoints can be disabled explicitly by
+     * giving them an empty digest name, which also implicitly disables all
+     * smaller codepoints that are not explicitly assigned.
+     * 
+     * We reserve the private-use code point (255) for use with fingerprint
+     * matching.  It MUST NOT be accepted in DNS replies.
      */
-    id = ((akid && akid->keyid) ? akid->keyid : 0);
-    if (id && ASN1_STRING_length(id) == 1 && *ASN1_STRING_get0_data(id) == c)
-       c = 1;
-
-    if ((akid = AUTHORITY_KEYID_new()) != 0
-       && (akid->keyid = ASN1_OCTET_STRING_new()) != 0
-       && ASN1_OCTET_STRING_set(akid->keyid, (void *) &c, 1)
-       && X509_add1_ext_i2d(cert, nid, akid, 0, X509V3_ADD_DEFAULT) > 0)
-       ret = 1;
-    if (akid)
-       AUTHORITY_KEYID_free(akid);
-    return (ret);
-}
-
-/* add_skid - add subject key identifier to match child's akid */
-
-static int add_skid(X509 *cert, AUTHORITY_KEYID *akid)
-{
-    int     nid = NID_subject_key_identifier;
-
-    if (!akid || !akid->keyid)
-       return (add_ext(0, cert, nid, "hash"));
-    else
-       return (X509_add1_ext_i2d(cert, nid, akid->keyid, 0,
-                                 X509V3_ADD_DEFAULT) > 0);
-}
+    mtypes[1].alg = NULL;
+    mtypes[2].alg = NULL;
+    mtypes[255].alg = fpt_alg;
+    maxtype = 2;
 
-/* akid_issuer_name - get akid issuer directory name */
+    save = cp = mystrdup(var_tls_dane_digests);
+    while ((algname = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
+       char   *algcode = split_at(algname, '=');
+       int     codepoint = -1;
 
-static X509_NAME *akid_issuer_name(AUTHORITY_KEYID *akid)
-{
-    if (akid && akid->issuer) {
-       int     i;
-       general_name_stack_t *gens = akid->issuer;
-
-       for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
-           GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
+       if (algcode && *algcode) {
+           unsigned long l;
+           char   *endcp;
 
-           if (gn->type == GEN_DIRNAME)
-               return (gn->d.dirn);
+           /*
+            * XXX: safe_strtoul() does not flag empty or white-space only
+            * input.  Since we get algcode by splitting white-space/comma
+            * delimited tokens, this is not a problem here.
+            */
+           l = safe_strtoul(algcode, &endcp, 10);
+           if ((l == 0 && (errno == EINVAL || endcp == algcode))
+               || l >= 255 || *endcp) {
+               msg_warn("Invalid matching type number in %s: %s=%s",
+                        VAR_TLS_DANE_DIGESTS, algname, algcode);
+               continue;
+           }
+           if (l == 0 || l == 255) {
+               msg_warn("Reserved matching type number in %s: %s=%s",
+                        VAR_TLS_DANE_DIGESTS, algname, algcode);
+               continue;
+           }
+           codepoint = l;
        }
-    }
-    return (0);
-}
-
-/* set_issuer - set issuer DN to match akid if specified */
-
-static int set_issuer_name(X509 *cert, AUTHORITY_KEYID *akid, X509_NAME *subj)
-{
-    X509_NAME *name = akid_issuer_name(akid);
-
-    /*
-     * If subject's akid specifies an authority key identifier issuer name,
-     * we must use that.
-     */
-    if (name)
-       return (X509_set_issuer_name(cert, name));
-    return (X509_set_issuer_name(cert, subj));
-}
-
-/* grow_chain - add certificate to trusted or untrusted chain */
-
-static void grow_chain(TLS_SESS_STATE *TLScontext, int trusted, X509 *cert)
-{
-    x509_stack_t **xs = trusted ? &TLScontext->trusted : &TLScontext->untrusted;
-
-#define UNTRUSTED 0
-#define TRUSTED 1
-
-    if (!*xs && (*xs = sk_X509_new_null()) == 0)
-       msg_fatal("out of memory");
-    if (cert) {
-       if (trusted && !X509_add1_trust_object(cert, serverAuth))
-           msg_fatal("out of memory");
-       X509_up_ref(cert);
-       if (!sk_X509_push(*xs, cert))
-           msg_fatal("out of memory");
-    }
-}
-
-/* wrap_key - wrap TA "key" as issuer of "subject" */
-
-static void wrap_key(TLS_SESS_STATE *TLScontext, int depth,
-                            EVP_PKEY *key, X509 *subject)
-{
-    X509   *cert = 0;
-    AUTHORITY_KEYID *akid;
-    X509_NAME *name = X509_get_issuer_name(subject);
-
-    /*
-     * The subject name is never a NULL object unless we run out of memory.
-     * It may be an empty sequence, but the containing object always exists
-     * and its storage is owned by the certificate itself.
-     */
-    if (name == 0 || (cert = X509_new()) == 0)
-       msg_fatal("Out of memory");
-
-    /*
-     * Record the depth of the intermediate wrapper certificate, logged in
-     * the verify callback.
-     */
-    if (TLScontext->tadepth < 0) {
-       TLScontext->tadepth = depth + 1;
-       if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
-           msg_info("%s: depth=%d chain is trust-anchor signed",
-                    TLScontext->namaddr, depth);
-    }
-    akid = X509_get_ext_d2i(subject, NID_authority_key_identifier, 0, 0);
-
-    ERR_clear_error();
-
-    /* CA cert valid for +/- 30 days. */
-    if (!X509_set_version(cert, 2)
-       || !set_serial(cert, akid, subject)
-       || !set_issuer_name(cert, akid, name)
-       || !X509_gmtime_adj(X509_getm_notBefore(cert), -30 * 86400L)
-       || !X509_gmtime_adj(X509_getm_notAfter(cert), 30 * 86400L)
-       || !X509_set_subject_name(cert, name)
-       || !X509_set_pubkey(cert, key)
-       || !add_ext(0, cert, NID_basic_constraints, "CA:TRUE")
-       || (key && !add_akid(cert, akid))
-       || !add_skid(cert, akid)) {
-       tls_print_errors();
-       msg_fatal("error generating DANE wrapper certificate");
-    }
-    if (akid)
-       AUTHORITY_KEYID_free(akid);
-    grow_chain(TLScontext, TRUSTED, cert);
-    if (cert)
-       X509_free(cert);
-}
-
-/* wrap_cert - wrap "tacert" as trust-anchor. */
-
-static void wrap_cert(TLS_SESS_STATE *TLScontext, X509 *tacert, int depth)
-{
-    if (TLScontext->tadepth < 0)
-       TLScontext->tadepth = depth + 1;
-
-    if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
-       msg_info("%s: depth=%d trust-anchor certificate",
-                TLScontext->namaddr, depth);
-
-    grow_chain(TLScontext, TRUSTED, tacert);
-    return;
-}
-
-/* ta_signed - is certificate signed by a TLSA cert or pkey */
-
-static int ta_signed(TLS_SESS_STATE *TLScontext, X509 *cert, int depth)
-{
-    const TLS_DANE *dane = TLScontext->dane;
-    EVP_PKEY *pk;
-    TLS_PKEYS *k;
-    TLS_CERTS *x;
-    int     done = 0;
-
-    /*
-     * First check whether issued and signed by a TA cert, this is cheaper
-     * than the bare-public key checks below, since we can determine whether
-     * the candidate TA certificate issued the certificate to be checked
-     * first (name comparisons), before we bother with signature checks
-     * (public key operations).
-     */
-    for (x = dane->certs; !done && x; x = x->next) {
-       if (X509_check_issued(x->cert, cert) == X509_V_OK) {
-           if ((pk = X509_get_pubkey(x->cert)) == 0)
+       /* Disable any codepoint gaps */
+       if (codepoint > maxtype) {
+           while (++maxtype < codepoint)
+               mtypes[codepoint].alg = NULL;
+           maxtype = codepoint;
+       }
+       /* Handle explicitly disabled codepoints */
+       if (*algname == 0) {
+           /* Skip empty specifiers */
+           if (codepoint < 0)
                continue;
-           /* Check signature, since some other TA may work if not this. */
-           if ((done = (X509_verify(cert, pk) > 0)) != 0)
-               wrap_cert(TLScontext, x->cert, depth);
-           EVP_PKEY_free(pk);
+           mtypes[codepoint].alg = NULL;
+           continue;
        }
-    }
-
-    /*
-     * With bare TA public keys, we can't check whether the trust chain is
-     * issued by the key, but we can determine whether it is signed by the
-     * key, so we go with that.
-     * 
-     * Ideally, the corresponding certificate was presented in the chain, and we
-     * matched it by its public key digest one level up.  This code is here
-     * to handle adverse conditions imposed by sloppy administrators of
-     * receiving systems with poorly constructed chains.
-     * 
-     * We'd like to optimize out keys that should not match when the cert's
-     * authority key id does not match the key id of this key computed via
-     * the RFC keyid algorithm (SHA-1 digest of public key bit-string sans
-     * ASN1 tag and length thus also excluding the unused bits field that is
-     * logically part of the length).  However, some CAs have a non-standard
-     * authority keyid, so we lose.  Too bad.
-     * 
-     * This may push errors onto the stack when the certificate signature is not
-     * of the right type or length, throw these away.
-     */
-    for (k = dane->pkeys; !done && k; k = k->next)
-       if ((done = (X509_verify(cert, k->pkey) > 0)) != 0)
-           wrap_key(TLScontext, depth, k->pkey, cert);
-       else
-           ERR_clear_error();
-
-    return (done);
-}
-
-/* set_trust - configure for DANE validation */
-
-static void set_trust(TLS_SESS_STATE *TLScontext, X509_STORE_CTX *ctx)
-{
-    int     n;
-    int     i;
-    int     match;
-    int     depth = 0;
-    EVP_PKEY *takey;
-    X509   *ca;
-    X509   *cert = X509_STORE_CTX_get0_cert(ctx);
-    x509_stack_t *in = X509_STORE_CTX_get0_untrusted(ctx);
-
-    /* shallow copy */
-    if ((in = sk_X509_dup(in)) == 0)
-       msg_fatal("out of memory");
-
-    /*
-     * At each iteration we consume the issuer of the current cert.  This
-     * reduces the length of the "in" chain by one.  If no issuer is found,
-     * we are done.  We also stop when a certificate matches a TA in the
-     * peer's TLSA RRset.
-     * 
-     * Caller ensures that the initial certificate is not self-signed.
-     */
-    for (n = sk_X509_num(in); n > 0; --n, ++depth) {
-       for (i = 0; i < n; ++i)
-           if (X509_check_issued(sk_X509_value(in, i), cert) == X509_V_OK)
-               break;
-
-       /*
-        * Final untrusted element with no issuer in the peer's chain, it may
-        * however be signed by a pkey or cert obtained via a TLSA RR.
-        */
-       if (i == n)
+       switch (codepoint) {
+       case -1:
+           if (strcasecmp(algname, LN_sha256) == 0)
+               codepoint = 1;                  /* SHA2-256(1) */
+           else if (strcasecmp(algname, LN_sha512) == 0)
+               codepoint = 2;                  /* SHA2-512(2) */
+           else {
+               msg_warn("%s: digest algorithm %s needs an explicit number",
+                        VAR_TLS_DANE_DIGESTS, algname);
+               continue;
+           }
            break;
-
-       /* Peer's chain contains an issuer ca. */
-       ca = sk_X509_delete(in, i);
-
-       /* Is it a trust anchor? */
-       match = tls_dane_match(TLScontext, TLS_DANE_TA, ca, depth + 1);
-       if (match) {
-           switch (match) {
-           case MATCHED_CERT:
-               wrap_cert(TLScontext, ca, depth);
-               break;
-           case MATCHED_PKEY:
-               if ((takey = X509_get_pubkey(ca)) == 0)
-                   msg_panic("trust-anchor certificate has null pkey");
-               wrap_key(TLScontext, depth, takey, cert);
-               EVP_PKEY_free(takey);
-               break;
-           default:
-               msg_panic("unexpected tls_dane_match result: %d", match);
+       case 1:
+           if (strcasecmp(algname, LN_sha256) != 0) {
+               msg_warn("%s: matching type 1 can only be %s",
+                        VAR_TLS_DANE_DIGESTS, LN_sha256);
+               continue;
+           }
+           algname = LN_sha256;
+           break;
+       case 2:
+           if (strcasecmp(algname, LN_sha512) != 0) {
+               msg_warn("%s: matching type 2 can only be %s",
+                        VAR_TLS_DANE_DIGESTS, LN_sha512);
+               continue;
            }
-           cert = 0;
+           algname = LN_sha512;
+           break;
+       default:
            break;
        }
-       /* Add untrusted ca. */
-       grow_chain(TLScontext, UNTRUSTED, ca);
 
-       /* Final untrusted self-signed element? */
-       if (X509_check_issued(ca, ca) == X509_V_OK) {
-           cert = 0;
-           break;
+       if (mtypes[codepoint].ord != 0) {
+           msg_warn("%s: matching type %d specified more than once",
+                    VAR_TLS_DANE_DIGESTS, codepoint);
+           continue;
+       }
+       mtypes[codepoint].ord = ++ord;
+
+       if ((mtypes[codepoint].alg = EVP_get_digestbyname(algname)) == 0) {
+           msg_warn("%s: digest algorithm \"%s\"(%d) unknown",
+                    VAR_TLS_DANE_DIGESTS, algname, codepoint);
+           continue;
        }
-       /* Restart with issuer as subject */
-       cert = ca;
     }
+    myfree(save);
 
-    /*
-     * When the loop exits, if "cert" is set, it is not self-signed and has
-     * no issuer in the chain, we check for a possible signature via a DNS
-     * obtained TA cert or public key.  Otherwise, we found no TAs and no
-     * issuer, so set an empty list of TAs.
-     */
-    if (!cert || !ta_signed(TLScontext, cert, depth)) {
-       /* Create empty trust list if null, else NOP */
-       grow_chain(TLScontext, TRUSTED, 0);
+    for (m = 1; m != 0; m = m != maxtype ? m + 1 : 255) {
+
+       /*
+        * In OpenSSL higher order ordinals are preferred, but we list the
+        * most preferred algorithms first, so the last ordinal becomes 1,
+        * next-to-last, 2, ...
+        * 
+        * The ordinals of non-disabled algorithms are always positive, and the
+        * computed value cannot overflow 254 (the largest possible value of
+        * 'ord' after loading each valid codepoint at most once).
+        */
+       if (SSL_CTX_dane_mtype_set(ctx, mtypes[m].alg, m,
+                                  ord - mtypes[m].ord + 1) <= 0) {
+           msg_warn("%s: error configuring matching type %d",
+                    VAR_TLS_DANE_DIGESTS, m);
+           tls_print_errors();
+       }
     }
-    /* shallow free */
-    if (in)
-       sk_X509_free(in);
 }
 
-/* dane_cb - wrap chain verification for DANE */
+/* tls_dane_log - log DANE-based verification success */
 
-static int dane_cb(X509_STORE_CTX *ctx, void *app_ctx)
+void    tls_dane_log(TLS_SESS_STATE *TLScontext)
 {
-    const char *myname = "dane_cb";
-    TLS_SESS_STATE *TLScontext = (TLS_SESS_STATE *) app_ctx;
-    X509   *cert = X509_STORE_CTX_get0_cert(ctx);
+    static VSTRING *top;
+    static VSTRING *bot;
+    EVP_PKEY *mspki = 0;
+    int     depth = SSL_get0_dane_authority(TLScontext->con, NULL, &mspki);
+    uint8_t u, s, m;
+    unsigned const char *data;
+    size_t  dlen;
+
+    if (depth < 0)
+       return;                                 /* No DANE auth */
+
+    switch (TLScontext->level) {
+    case TLS_LEV_SECURE:
+    case TLS_LEV_VERIFY:
+       msg_info("%s: Matched trust anchor at depth %d",
+                TLScontext->namaddr, depth);
+       return;
+    }
 
-    /*
-     * Degenerate case: depth 0 self-signed cert.
-     * 
-     * XXX: Should we suppress name checks, ... when the leaf certificate is a
-     * TA.  After all they could sign any name they want.  However, this
-     * requires a bit of additional code.  For now we allow depth 0 TAs, but
-     * then the peer name has to match.
-     */
-    if (X509_check_issued(cert, cert) == X509_V_OK) {
+    if (top == 0)
+       top = vstring_alloc(2 * MAX_HEAD_BYTES);
+    if (bot == 0)
+       bot = vstring_alloc(2 * MAX_TAIL_BYTES);
 
-       /*
-        * Empty untrusted chain, could be NULL, but then ABI check less
-        * reliable, we may zero some other field, ...
-        */
-       grow_chain(TLScontext, UNTRUSTED, 0);
-       if (tls_dane_match(TLScontext, TLS_DANE_TA, cert, 0)) {
-           TLScontext->tadepth = 0;
-           grow_chain(TLScontext, TRUSTED, cert);
-       } else
-           grow_chain(TLScontext, TRUSTED, 0);
+    (void) SSL_get0_dane_tlsa(TLScontext->con, &u, &s, &m, &data, &dlen);
+    if (dlen > MAX_DUMP_BYTES) {
+       hex_encode(top, (char *) data, MAX_HEAD_BYTES);
+       hex_encode(bot, (char *) data + dlen - MAX_TAIL_BYTES, MAX_TAIL_BYTES);
     } else {
-       set_trust(TLScontext, ctx);
+       hex_encode(top, (char *) data, dlen);
     }
 
-    /*
-     * Check that setting the untrusted chain updates the expected structure
-     * member at the expected offset.
-     */
-    X509_STORE_CTX_set0_trusted_stack(ctx, TLScontext->trusted);
-    X509_STORE_CTX_set0_untrusted(ctx, TLScontext->untrusted);
-    if (X509_STORE_CTX_get0_untrusted(ctx) != TLScontext->untrusted)
-       msg_panic("%s: OpenSSL ABI change", myname);
-
-    return X509_verify_cert(ctx);
-}
-
-/* tls_dane_set_callback - set or clear verification wrapper callback */
+    switch (TLScontext->level) {
+    case TLS_LEV_FPRINT:
+       msg_info("%s: Matched fingerprint: %s%s%s", TLScontext->namaddr,
+                STR(top), dlen > MAX_DUMP_BYTES ? "..." : "",
+                dlen > MAX_DUMP_BYTES ? STR(bot) : "");
+       return;
 
-void    tls_dane_set_callback(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext)
-{
-    if (TLS_DANE_HASTA(TLScontext->dane))
-       SSL_CTX_set_cert_verify_callback(ctx, dane_cb, (void *) TLScontext);
-    else
-       SSL_CTX_set_cert_verify_callback(ctx, 0, 0);
+    default:
+       msg_info("%s: Matched DANE %s at depth %d: %u %u %u %s%s%s",
+                TLScontext->namaddr, mspki ?
+                "TA public key verified certificate" : depth ?
+                "TA certificate" : "EE certificate", depth, u, s, m,
+                STR(top), dlen > MAX_DUMP_BYTES ? "..." : "",
+                dlen > MAX_DUMP_BYTES ? STR(bot) : "");
+       return;
+    }
 }
 
 #ifdef TEST
@@ -1699,14 +1041,13 @@ static int verify_chain(SSL *ssl, x509_stack_t *chain, TLS_SESS_STATE *tctx)
     }
     X509_STORE_CTX_set_ex_data(store_ctx, store_ctx_idx, ssl);
 
+    /* We're *verifying* a server chain */
     X509_STORE_CTX_set_default(store_ctx, "ssl_server");
     X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx),
                           SSL_get0_param(ssl));
+    X509_STORE_CTX_set0_dane(store_ctx, SSL_get0_dane(ssl));
 
-    if (SSL_get_verify_callback(ssl))
-       X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl));
-
-    ret = dane_cb(store_ctx, tctx);
+    ret = X509_verify_cert(store_ctx);
 
     SSL_set_verify_result(ssl, X509_STORE_CTX_get_error(store_ctx));
     X509_STORE_CTX_free(store_ctx);
@@ -1714,9 +1055,9 @@ static int verify_chain(SSL *ssl, x509_stack_t *chain, TLS_SESS_STATE *tctx)
     return (ret);
 }
 
-static void add_tlsa(TLS_DANE *dane, char *argv[])
+static void load_tlsa_args(SSL *ssl, char *argv[])
 {
-    char   *digest;
+    const EVP_MD *md = 0;
     X509   *cert = 0;
     BIO    *bp;
     unsigned char *buf;
@@ -1724,7 +1065,7 @@ static void add_tlsa(TLS_DANE *dane, char *argv[])
     int     len;
     uint8_t u = atoi(argv[1]);
     uint8_t s = atoi(argv[2]);
-    const char *mdname = argv[3];
+    uint8_t m = atoi(argv[3]);
     EVP_PKEY *pkey;
 
     /* Unsupported usages are fatal */
@@ -1745,9 +1086,15 @@ static void add_tlsa(TLS_DANE *dane, char *argv[])
        msg_fatal("unsupported selector %u", s);
     }
 
-    /* Unsupported digests are fatal */
-    if (*mdname && !tls_validate_digest(mdname))
-       msg_fatal("unsupported digest algorithm: %s", mdname);
+    /* Unsupported selectors are fatal */
+    switch (m) {
+    case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
+    case DNS_TLSA_MATCHING_TYPE_SHA256:
+    case DNS_TLSA_MATCHING_TYPE_SHA512:
+       break;
+    default:
+       msg_fatal("unsupported matching type %u", m);
+    }
 
     if ((bp = BIO_new_file(argv[4], "r")) == NULL)
        msg_fatal("error opening %s: %m", argv[4]);
@@ -1763,26 +1110,49 @@ static void add_tlsa(TLS_DANE *dane, char *argv[])
     switch (s) {
     case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
        len = i2d_X509(cert, NULL);
+       if (len > 0xffff)
+           msg_fatal("certificate too long: %d", len);
        buf2 = buf = (unsigned char *) mymalloc(len);
        i2d_X509(cert, &buf2);
-       if (!*mdname)
-           ta_cert_insert(dane, cert);
        break;
     case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
        pkey = X509_get_pubkey(cert);
        len = i2d_PUBKEY(pkey, NULL);
+       if (len > 0xffff)
+           msg_fatal("public key too long: %d", len);
        buf2 = buf = (unsigned char *) mymalloc(len);
        i2d_PUBKEY(pkey, &buf2);
-       if (!*mdname)
-           ta_pkey_insert(dane, pkey);
        EVP_PKEY_free(pkey);
        break;
     }
+    X509_free(cert);
     OPENSSL_assert(buf2 - buf == len);
 
-    digest = tls_data_fprint((char *) buf, len, *mdname ? mdname : signalg);
-    dane_add(dane, u, s, *mdname ? mdname : signalg, digest);
-    myfree((void *) digest);
+    switch (m) {
+    case 0:
+       break;
+    case 1:
+       if ((md = EVP_get_digestbyname(LN_sha256)) == 0)
+           msg_fatal("Digest %s not found", LN_sha256);
+       break;
+    case 2:
+       if ((md = EVP_get_digestbyname(LN_sha512)) == 0)
+           msg_fatal("Digest %s not found", LN_sha512);
+       break;
+    default:
+       msg_fatal("Unsupported DANE mtype: %d", m);
+    }
+
+    if (md != 0) {
+       unsigned char mdbuf[EVP_MAX_MD_SIZE];
+       unsigned int mdlen = sizeof(mdbuf);
+
+       if (!EVP_Digest(buf, len, mdbuf, &mdlen, md, 0))
+           msg_fatal("Digest failure for mtype: %d", m);
+       myfree(buf);
+       buf = (unsigned char *) mymemdup(mdbuf, len = mdlen);
+    }
+    SSL_dane_tlsa_add(ssl, u, s, m, buf, len);
     myfree((void *) buf);
 }
 
@@ -1883,122 +1253,6 @@ static void usage(const char *progname)
     exit(1);
 }
 
-/* match_servername -  match servername against pattern */
-
-static int match_servername(const char *certid, ARGV *margv)
-{
-    const char *domain;
-    const char *parent;
-    int     match_subdomain;
-    int     i;
-    int     idlen;
-    int     domlen;
-
-    /*
-     * XXX EAI support.
-     */
-
-    /*
-     * Match the certid against each pattern until we find a match.
-     */
-    for (i = 0; i < margv->argc; ++i) {
-       match_subdomain = 0;
-       domain = margv->argv[i];
-       if (*domain == '.' && domain[1] != '\0') {
-           ++domain;
-           match_subdomain = 1;
-       }
-
-       /*
-        * Sub-domain match: certid is any sub-domain of hostname.
-        */
-       if (match_subdomain) {
-           if ((idlen = strlen(certid)) > (domlen = strlen(domain)) + 1
-               && certid[idlen - domlen - 1] == '.'
-               && !strcasecmp(certid + (idlen - domlen), domain))
-               return (1);
-           else
-               continue;
-       }
-
-       /*
-        * Exact match and initial "*" match. The initial "*" in a certid
-        * matches one (if var_tls_multi_label is false) or more hostname
-        * components under the condition that the certid contains multiple
-        * hostname components.
-        */
-       if (!strcasecmp(certid, domain)
-           || (certid[0] == '*' && certid[1] == '.' && certid[2] != 0
-               && (parent = strchr(domain, '.')) != 0
-               && (idlen = strlen(certid + 1)) <= (domlen = strlen(parent))
-               && strcasecmp(var_tls_multi_wildcard == 0 ? parent :
-                             parent + domlen - idlen,
-                             certid + 1) == 0))
-           return (1);
-    }
-    return (0);
-}
-
-static void check_name(TLS_SESS_STATE *tctx, X509 *cert, ARGV *margs)
-{
-    char   *cn;
-    int     matched = 0;
-    general_name_stack_t *gens;
-
-    if (SSL_get_verify_result(tctx->con) != X509_V_OK)
-       return;
-
-    tctx->peer_status |= TLS_CERT_FLAG_TRUSTED;
-
-    gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
-    if (gens) {
-       int     has_dnsname = 0;
-       int     num_gens = sk_GENERAL_NAME_num(gens);
-       int     i;
-
-       for (i = 0; !matched && i < num_gens; ++i) {
-           const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
-           const char *dnsname;
-
-           if (gn->type != GEN_DNS)
-               continue;
-           has_dnsname = 1;
-           tctx->peer_status |= TLS_CERT_FLAG_ALTNAME;
-           dnsname = tls_dns_name(gn, tctx);
-           if (dnsname && *dnsname
-               && (matched = match_servername(dnsname, margs)) != 0)
-               tctx->peer_status |= TLS_CERT_FLAG_MATCHED;
-       }
-       sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
-       if (has_dnsname)
-           return;
-    }
-    cn = tls_peer_CN(cert, tctx);
-    if (match_servername(cn, margs))
-       tctx->peer_status |= TLS_CERT_FLAG_MATCHED;
-    myfree(cn);
-}
-
-static void check_print(TLS_SESS_STATE *tctx, X509 *cert)
-{
-    if (TLS_DANE_HASEE(tctx->dane)
-       && tls_dane_match(tctx, TLS_DANE_EE, cert, 0))
-       tctx->peer_status |= TLS_CERT_FLAG_TRUSTED | TLS_CERT_FLAG_MATCHED;
-}
-
-static void check_peer(TLS_SESS_STATE *tctx, X509 *cert, int argc, char **argv)
-{
-    ARGV    match;
-
-    tctx->peer_status |= TLS_CERT_FLAG_PRESENT;
-    check_print(tctx, cert);
-    if (!TLS_CERT_IS_MATCHED(tctx)) {
-       match.argc = argc;
-       match.argv = argv;
-       check_name(tctx, cert, &match);
-    }
-}
-
 static SSL_CTX *ctx_init(const char *CAfile)
 {
     SSL_CTX *client_ctx;
@@ -2006,11 +1260,6 @@ static SSL_CTX *ctx_init(const char *CAfile)
     tls_param_init();
     tls_check_version();
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-    SSL_load_error_strings();
-    SSL_library_init();
-#endif
-
     if (!tls_validate_digest(LN_sha1))
        msg_fatal("%s digest algorithm not available", LN_sha1);
 
@@ -2023,6 +1272,11 @@ static SSL_CTX *ctx_init(const char *CAfile)
        msg_fatal("cannot allocate client SSL_CTX");
     SSL_CTX_set_verify_depth(client_ctx, 5);
 
+    /* Enable DANE support in OpenSSL */
+    if (SSL_CTX_dane_enable(client_ctx) <= 0) {
+       tls_print_errors();
+       msg_fatal("OpenSSL DANE initialization failed");
+    }
     if (tls_set_ca_certificate_info(client_ctx, CAfile, "") < 0) {
        tls_print_errors();
        msg_fatal("cannot load CAfile: %s", CAfile);
@@ -2035,8 +1289,10 @@ static SSL_CTX *ctx_init(const char *CAfile)
 int     main(int argc, char *argv[])
 {
     SSL_CTX *ssl_ctx;
+    const EVP_MD *fpt_alg;
     TLS_SESS_STATE *tctx;
     x509_stack_t *chain;
+    int     i;
 
     var_procname = mystrdup(basename(argv[0]));
     set_mail_conf_str(VAR_PROCNAME, var_procname);
@@ -2051,28 +1307,49 @@ int     main(int argc, char *argv[])
 
     tctx = tls_alloc_sess_context(TLS_LOG_NONE, argv[7]);
     tctx->namaddr = argv[7];
-    tctx->mdalg = LN_sha1;
+    tctx->mdalg = LN_sha256;
     tctx->dane = tls_dane_alloc();
 
+    if ((fpt_alg = tls_validate_digest(tctx->mdalg)) == 0)
+       msg_fatal("fingerprint digest algorithm %s not found",
+                 tctx->mdalg);
+    tls_dane_digest_init(ssl_ctx, fpt_alg);
+
     if ((tctx->con = SSL_new(ssl_ctx)) == 0
        || !SSL_set_ex_data(tctx->con, TLScontext_index, tctx)) {
        tls_print_errors();
        msg_fatal("Error allocating SSL connection");
     }
+    if (SSL_dane_enable(tctx->con, 0) <= 0) {
+       tls_print_errors();
+       msg_fatal("Error enabling DANE for SSL handle");
+    }
+    SSL_dane_set_flags(tctx->con, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
+    SSL_dane_set_flags(tctx->con, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+    for (i = 7; i < argc; ++i)
+       if (!SSL_add1_host(tctx->con, argv[i]))
+           msg_fatal("error adding hostname: %s", argv[i]);
+    load_tlsa_args(tctx->con, argv);
     SSL_set_connect_state(tctx->con);
-    add_tlsa((TLS_DANE *) tctx->dane, argv);
-    tls_dane_set_callback(ssl_ctx, tctx);
 
     /* Verify saved server chain */
     chain = load_chain(argv[6]);
-    verify_chain(tctx->con, chain, tctx);
-    check_peer(tctx, sk_X509_value(chain, 0), argc - 7, argv + 7);
+    i = verify_chain(tctx->con, chain, tctx);
     tls_print_errors();
 
-    msg_info("%s %s", TLS_CERT_IS_MATCHED(tctx) ? "Verified" :
-            TLS_CERT_IS_TRUSTED(tctx) ? "Trusted" : "Untrusted", argv[7]);
+    if (i > 0) {
+       const char *peername = SSL_get0_peername(tctx->con);
+
+       if (peername == 0)
+           peername = argv[7];
+       msg_info("Verified %s", peername);
+    } else {
+       i = SSL_get_verify_result(tctx->con);
+       msg_info("certificate verification failed for %s:%s: num=%d:%s",
+                argv[6], argv[7], i, X509_verify_cert_error_string(i));
+    }
 
-    return (TLS_CERT_IS_MATCHED(tctx) ? 0 : 1);
+    return (i <= 0);
 }
 
 #endif                                 /* TEST */
index 70db8e9d9f8130d4f5918b3b61038d7043a421be..a39a6390877b8044a047f517e1e00ca9b0df1d31 100644 (file)
@@ -7,46 +7,27 @@
 /*     #define TLS_INTERNAL
 /*     #include <tls.h>
 /*
-/*     void    tls_set_dh_from_file(path, bits)
+/*     void    tls_set_dh_from_file(path)
 /*     const char *path;
-/*     int     bits;
 /*
 /*     void    tls_auto_eecdh_curves(ctx, configured)
 /*     SSL_CTX *ctx;
 /*     char    *configured;
 /*
-/*     void    tls_set_eecdh_curve(server_ctx, grade)
-/*     SSL_CTX *server_ctx;
-/*     const char *grade;
-/*
-/*     DH      *tls_tmp_dh_cb(ssl, export, keylength)
-/*     SSL     *ssl; /* unused */
-/*     int     export;
-/*     int     keylength;
+/*     void    tls_tmp_dh(ctx)
+/*     SSL_CTX *ctx;
 /* DESCRIPTION
 /*     This module maintains parameters for Diffie-Hellman key generation.
 /*
-/*     tls_tmp_dh_cb() is a call-back routine for the
-/*     SSL_CTX_set_tmp_dh_callback() function.
+/*     tls_tmp_dh() returns the configured or compiled-in FFDHE
+/*     group parameters.
 /*
 /*     tls_set_dh_from_file() overrides compiled-in DH parameters
 /*     with those specified in the named files. The file format
-/*     is as expected by the PEM_read_DHparams() routine. The
-/*     "bits" argument must be 512 or 1024.
+/*     is as expected by the PEM_read_DHparams() routine.
 /*
 /*     tls_auto_eecdh_curves() enables negotiation of the most preferred curve
 /*     among the curves specified by the "configured" argument.
-/*
-/*     tls_set_eecdh_curve() enables ephemeral Elliptic-Curve DH
-/*     key exchange algorithms by instantiating in the server SSL
-/*     context a suitable curve (corresponding to the specified
-/*     EECDH security grade) from the set of named curves in RFC
-/*     4492 Section 5.1.1. Errors generate warnings, but do not
-/*     disable TLS, rather we continue without EECDH. A zero
-/*     result indicates that the grade is invalid or the corresponding
-/*     curve could not be used.  The "auto" grade enables multiple
-/*     curves, with the actual curve chosen as the most preferred
-/*     among those supported by both the server and the client.
 /* DIAGNOSTICS
 /*     In case of error, tls_set_dh_from_file() logs a warning and
 /*     ignores the request.
 /* Application-specific. */
 
  /*
-  * Compiled-in DH parameters.  Used when no parameters are explicitly loaded
-  * from a site-specific file.  Using an ASN.1 DER encoding avoids the need
-  * to explicitly manipulate the internal representation of DH parameter
-  * objects.
+  * Compiled-in FFDHE (finite-field ephemeral Diffie-Hellman) parameters.
+  * Used when no parameters are explicitly loaded from a site-specific file.
+  * Using an ASN.1 DER encoding avoids the need to explicitly manipulate the
+  * internal representation of DH parameter objects.
   * 
-  * 512-bit parameters are used for export ciphers, and 2048-bit parameters are
-  * used for non-export ciphers.  The non-export group is now 2048-bit, as
-  * 1024 bits is increasingly considered to weak by clients.  When greater
-  * security is required, use EECDH.
+  * The FFDHE group is now 2048-bit, as 1024 bits is increasingly considered to
+  * weak by clients.  When greater security is required, use EECDH.
   */
 
- /*-
-  * Generated via:
-  *   $ openssl dhparam -2 -outform DER 512 2>/dev/null |
-  *     hexdump -ve '/1 "0x%02x, "' | fmt
-  * TODO: generate at compile-time. But that is no good for the majority of
-  * sites that install pre-compiled binaries, and breaks reproducible builds.
-  * Instead, generate at installation time and use main.cf configuration.
-  */
-static unsigned char dh512_der[] = {
-    0x30, 0x46, 0x02, 0x41, 0x00, 0xd8, 0xbf, 0x11, 0xd6, 0x41, 0x2a, 0x7a,
-    0x9c, 0x78, 0xb2, 0xaa, 0x41, 0x23, 0x0a, 0xdc, 0xcf, 0xb7, 0x19, 0xc5,
-    0x16, 0x4c, 0xcb, 0x4a, 0xd0, 0xd2, 0x1f, 0x1f, 0x70, 0x24, 0x86, 0x6f,
-    0x51, 0x52, 0xc6, 0x5b, 0x28, 0xbb, 0x82, 0xe1, 0x24, 0x91, 0x3d, 0x4d,
-    0x95, 0x56, 0xf8, 0x0b, 0x2c, 0xe0, 0x36, 0x67, 0x88, 0x64, 0x15, 0x1f,
-    0x45, 0xd5, 0xb8, 0x0a, 0x00, 0x03, 0x76, 0x32, 0x0b, 0x02, 0x01, 0x02,
-};
-
  /*-
   * Generated via:
   *   $ openssl dhparam -2 -outform DER 2048 2>/dev/null |
@@ -138,108 +100,82 @@ static unsigned char dh512_der[] = {
   * Instead, generate at installation time and use main.cf configuration.
   */
 static unsigned char dh2048_der[] = {
-    0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x28, 0x1b,
-    0x68, 0x69, 0x90, 0x2f, 0x37, 0x9f, 0x5a, 0x50, 0x23, 0x73, 0x2c, 0x11,
-    0xf2, 0xac, 0x7c, 0x3e, 0x58, 0xb9, 0x23, 0x3e, 0x02, 0x07, 0x4d, 0xba,
-    0xd9, 0x2c, 0xc1, 0x9e, 0xf9, 0xc4, 0x2f, 0xbc, 0x8d, 0x86, 0x4b, 0x2a,
-    0x87, 0x86, 0x93, 0x32, 0x0f, 0x72, 0x40, 0xfe, 0x7e, 0xa2, 0xc1, 0x32,
-    0xf0, 0x65, 0x9c, 0xc3, 0x19, 0x25, 0x2d, 0xeb, 0x6a, 0x49, 0x94, 0x79,
-    0x2d, 0xa1, 0xbe, 0x05, 0x26, 0xac, 0x8d, 0x69, 0xdc, 0x2e, 0x7e, 0xb5,
-    0xfd, 0x3c, 0x2b, 0x7d, 0x43, 0x22, 0x53, 0xf6, 0x1e, 0x04, 0x45, 0xd7,
-    0x53, 0x84, 0xfd, 0x6b, 0x12, 0x72, 0x47, 0x04, 0xaf, 0xa4, 0xac, 0x4b,
-    0x55, 0xb6, 0x79, 0x42, 0x40, 0x88, 0x54, 0x48, 0xd5, 0x4d, 0x3a, 0xb2,
-    0xbf, 0x6c, 0x26, 0x95, 0x29, 0xdd, 0x8b, 0x9e, 0xed, 0xb8, 0x60, 0x8e,
-    0xb5, 0x35, 0xb6, 0x22, 0x44, 0x1f, 0xfb, 0x56, 0x74, 0xfe, 0xf0, 0x2c,
-    0xe6, 0x0c, 0x22, 0xc9, 0x35, 0xb3, 0x1b, 0x96, 0xbb, 0x0a, 0x5a, 0xc3,
-    0x09, 0xa0, 0xcc, 0xa5, 0x40, 0x90, 0x0f, 0x59, 0xa2, 0x89, 0x69, 0x2a,
-    0x69, 0x79, 0xe4, 0xd3, 0x24, 0xc6, 0x8c, 0xda, 0xbc, 0x98, 0x3a, 0x5b,
-    0x16, 0xae, 0x63, 0x6c, 0x0b, 0x43, 0x4f, 0xf3, 0x2e, 0xc8, 0xa9, 0x6b,
-    0x58, 0x6a, 0xa9, 0x8e, 0x64, 0x09, 0x3d, 0x88, 0x44, 0x4f, 0x97, 0x2c,
-    0x1d, 0x98, 0xb0, 0xa9, 0xc0, 0xb6, 0x8d, 0x19, 0x37, 0x1f, 0xb7, 0xc9,
-    0x86, 0xa8, 0xdc, 0x37, 0x4d, 0x64, 0x27, 0xf3, 0xf5, 0x2b, 0x7b, 0x6b,
-    0x76, 0x84, 0x3f, 0xc1, 0x23, 0x97, 0x2d, 0x71, 0xf7, 0xb6, 0xc2, 0x35,
-    0x28, 0x10, 0x96, 0xd6, 0x69, 0x0c, 0x2e, 0x1f, 0x9f, 0xdf, 0x82, 0x81,
-    0x57, 0x57, 0x39, 0xa5, 0xf2, 0x81, 0x29, 0x57, 0xf9, 0x2f, 0xd0, 0x03,
-    0xab, 0x02, 0x01, 0x02,
+    0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9e, 0x28, 0x15,
+    0xc5, 0xcc, 0x9b, 0x5a, 0xb0, 0xe9, 0xab, 0x74, 0x8b, 0x2a, 0x23, 0xce,
+    0xea, 0x87, 0xa0, 0x18, 0x09, 0xd0, 0x40, 0x2c, 0x93, 0x23, 0x5d, 0xc0,
+    0xe9, 0x78, 0x2c, 0x53, 0xd9, 0x3e, 0x21, 0x14, 0x89, 0x5c, 0x79, 0x73,
+    0x1e, 0xbd, 0x23, 0x1e, 0x18, 0x65, 0x6d, 0xd2, 0x3c, 0xeb, 0x41, 0xca,
+    0xbb, 0xa9, 0x99, 0x55, 0x84, 0xae, 0x9e, 0x70, 0x57, 0x25, 0x21, 0x42,
+    0xaa, 0xdb, 0x82, 0xc6, 0xe6, 0xf1, 0xcf, 0xb7, 0xbc, 0x2a, 0x56, 0xcc,
+    0x55, 0x1f, 0xad, 0xe9, 0x68, 0x18, 0x22, 0xfc, 0x09, 0x62, 0xc3, 0x32,
+    0x1b, 0x05, 0x1f, 0xce, 0xec, 0xe3, 0x6d, 0xb5, 0x79, 0xe0, 0x89, 0x45,
+    0xf3, 0xf3, 0x26, 0xa3, 0x81, 0xd9, 0x59, 0xee, 0xed, 0x78, 0xbe, 0x0e,
+    0xdd, 0xf7, 0xef, 0xcb, 0x81, 0x3f, 0x01, 0xb7, 0x10, 0x8f, 0x0d, 0xbe,
+    0x29, 0x21, 0x13, 0xff, 0x2a, 0x13, 0x25, 0x75, 0x99, 0xec, 0xf5, 0x2d,
+    0x49, 0x01, 0x1d, 0xa4, 0x13, 0xe8, 0x2c, 0xc8, 0x13, 0x60, 0x57, 0x98,
+    0xb1, 0x06, 0x45, 0x77, 0xa4, 0x24, 0xf9, 0x27, 0x3f, 0x08, 0xe6, 0x9b,
+    0x4b, 0x20, 0x3b, 0x43, 0x69, 0xa3, 0xcc, 0x9a, 0xc4, 0x3c, 0x1e, 0xec,
+    0xb7, 0x35, 0xe4, 0x59, 0x6b, 0x6d, 0x2a, 0xdf, 0xf7, 0x0b, 0xd4, 0x5a,
+    0x0f, 0x79, 0x80, 0xe1, 0x75, 0x4c, 0x10, 0xea, 0x26, 0xf0, 0xd5, 0xf3,
+    0xa6, 0x15, 0xa9, 0x3e, 0x3d, 0x0d, 0xb8, 0x53, 0x50, 0x49, 0x77, 0x49,
+    0x47, 0x43, 0x39, 0xee, 0xb8, 0x8a, 0xe5, 0x14, 0xc4, 0xe3, 0x10, 0xfb,
+    0xf5, 0x52, 0xef, 0xa5, 0x8f, 0xa4, 0x7e, 0x57, 0xb9, 0x5f, 0xda, 0x00,
+    0x18, 0xf0, 0x72, 0x29, 0xd4, 0xfe, 0x90, 0x5a, 0x1f, 0x1a, 0x40, 0xee,
+    0x4e, 0xfa, 0x3e, 0xf3, 0x72, 0x4b, 0xea, 0x44, 0x53, 0x43, 0x53, 0x57,
+    0x9b, 0x02, 0x01, 0x02,
 };
 
  /*
   * Cached results.
   */
-static DH *dh_1024 = 0;
-static DH *dh_512 = 0;
+static DH *dh_2048 = 0;
 
 /* tls_set_dh_from_file - set Diffie-Hellman parameters from file */
 
-void    tls_set_dh_from_file(const char *path, int bits)
+void    tls_set_dh_from_file(const char *path)
 {
     FILE   *paramfile;
-    DH    **dhPtr;
-
-    switch (bits) {
-    case 512:
-       dhPtr = &dh_512;
-       break;
-    case 1024:
-       dhPtr = &dh_1024;
-       break;
-    default:
-       msg_panic("Invalid DH parameters size %d, file %s", bits, path);
-    }
 
     /*
      * This function is the first to set the DH parameters, but free any
      * prior value just in case the call sequence changes some day.
      */
-    if (*dhPtr) {
-       DH_free(*dhPtr);
-       *dhPtr = 0;
+    if (dh_2048) {
+       DH_free(dh_2048);
+       dh_2048 = 0;
     }
     if ((paramfile = fopen(path, "r")) != 0) {
-       if ((*dhPtr = PEM_read_DHparams(paramfile, 0, 0, 0)) == 0) {
-           msg_warn("cannot load %d-bit DH parameters from file %s"
-                    " -- using compiled-in defaults", bits, path);
+       if ((dh_2048 = PEM_read_DHparams(paramfile, 0, 0, 0)) == 0) {
+           msg_warn("cannot load DH parameters from file %s"
+                    " -- using compiled-in defaults", path);
            tls_print_errors();
        }
        (void) fclose(paramfile);               /* 200411 */
     } else {
-       msg_warn("cannot load %d-bit DH parameters from file %s: %m"
-                " -- using compiled-in defaults", bits, path);
+       msg_warn("cannot load DH parameters from file %s: %m"
+                " -- using compiled-in defaults", path);
     }
 }
 
-/* tls_get_dh - get compiled-in DH parameters */
+/* tls_tmp_dh - configure FFDHE group */
 
-static DH *tls_get_dh(const unsigned char *p, size_t plen)
+void    tls_tmp_dh(SSL_CTX *ctx)
 {
-    const unsigned char *endp = p;
-    DH     *dh = 0;
-
-    if (d2i_DHparams(&dh, &endp, plen) && plen == endp - p)
-       return (dh);
-
-    msg_warn("cannot load compiled-in DH parameters");
-    if (dh)
-       DH_free(dh);
-    return (0);
-}
-
-/* tls_tmp_dh_cb - call-back for Diffie-Hellman parameters */
-
-DH     *tls_tmp_dh_cb(SSL *unused_ssl, int export, int keylength)
-{
-    DH     *dh_tmp;
-
-    if (export && keylength == 512) {          /* 40-bit export cipher */
-       if (dh_512 == 0)
-           dh_512 = tls_get_dh(dh512_der, sizeof(dh512_der));
-       dh_tmp = dh_512;
-    } else {                                   /* ADH, DHE-RSA or DSA */
-       if (dh_1024 == 0)
-           dh_1024 = tls_get_dh(dh2048_der, sizeof(dh2048_der));
-       dh_tmp = dh_1024;
+    if (dh_2048 == 0) {
+       const unsigned char *endp = dh2048_der;
+       DH     *dh = 0;
+
+       if (d2i_DHparams(&dh, &endp, sizeof(dh2048_der))
+           && sizeof(dh2048_der) == endp - dh2048_der) {
+           dh_2048 = dh;
+       } else {
+           DH_free(dh);                        /* Unlikely non-zero, but by
+                                                * the book */
+           msg_warn("error loading compiled-in DH parameters");
+       }
     }
-    return (dh_tmp);
+    if (ctx != 0 && dh_2048 != 0)
+       SSL_CTX_set_tmp_dh(ctx, dh_2048);
 }
 
 void    tls_auto_eecdh_curves(SSL_CTX *ctx, const char *configured)
@@ -309,77 +245,16 @@ void    tls_auto_eecdh_curves(SSL_CTX *ctx, const char *configured)
        tls_print_errors();
        RETURN;
     }
-
-    /*
-     * This is a NOP in OpenSSL 1.1.0 and later, where curves are always
-     * auto-negotiated.
-     */
-#if OPENSSL_VERSION_NUMBER < 0x10100000UL
-    if (SSL_CTX_set_ecdh_auto(ctx, 1) <= 0) {
-       msg_warn("failed to enable automatic ECDHE curve selection");
-       tls_print_errors();
-       RETURN;
-    }
-#endif
     RETURN;
 #endif
 }
 
-#define TLS_EECDH_INVALID      0
-#define TLS_EECDH_NONE         1
-#define TLS_EECDH_STRONG       2
-#define TLS_EECDH_ULTRA                3
-#define TLS_EECDH_AUTO         4
-
-void    tls_set_eecdh_curve(SSL_CTX *server_ctx, const char *grade)
-{
-#ifndef OPENSSL_NO_ECDH
-    int     g;
-    static NAME_CODE eecdh_table[] = {
-       "none", TLS_EECDH_NONE,
-       "strong", TLS_EECDH_STRONG,
-       "ultra", TLS_EECDH_ULTRA,
-       "auto", TLS_EECDH_AUTO,
-       0, TLS_EECDH_INVALID,
-    };
-
-    switch (g = name_code(eecdh_table, NAME_CODE_FLAG_NONE, grade)) {
-    default:
-       msg_panic("Invalid eecdh grade code: %d", g);
-    case TLS_EECDH_INVALID:
-       msg_warn("Invalid TLS eecdh grade \"%s\": EECDH disabled", grade);
-       return;
-    case TLS_EECDH_STRONG:
-       tls_auto_eecdh_curves(server_ctx, var_tls_eecdh_strong);
-       return;
-    case TLS_EECDH_ULTRA:
-       tls_auto_eecdh_curves(server_ctx, var_tls_eecdh_ultra);
-       return;
-    case TLS_EECDH_NONE:
-
-       /*
-        * Pretend "none" is "auto", the former is no longer supported or
-        * wise
-        */
-       msg_warn("The \"none\" eecdh grade is no longer supported, "
-                "using \"auto\" instead");
-    case TLS_EECDH_AUTO:
-       tls_auto_eecdh_curves(server_ctx, var_tls_eecdh_auto);
-       return;
-    }
-#endif
-    return;
-}
-
 #ifdef TEST
 
 int     main(int unused_argc, char **unused_argv)
 {
-    tls_tmp_dh_cb(0, 1, 512);
-    tls_tmp_dh_cb(0, 1, 1024);
-    tls_tmp_dh_cb(0, 1, 2048);
-    tls_tmp_dh_cb(0, 0, 512);
-    return (0);
+    tls_tmp_dh(0);
+    return (dh_2048 == 0);
 }
 
 #endif
index 2bb7e21befbf249e6229d005d7ba3daa79257c9d..268349fd2ad26e305936b6a02b499362cc4d5c5c 100644 (file)
@@ -6,7 +6,8 @@
 /* SYNOPSIS
 /*     #include <tls.h>
 /*
-/*     char    *tls_serverid_digest(props, protomask, ciphers)
+/*     char    *tls_serverid_digest(TLScontext, props, protomask, ciphers)
+/*     TLS_SESS_STATE *TLScontext;
 /*     const TLS_CLIENT_START_PROPS *props;
 /*     long    protomask;
 /*     const char *ciphers;
 /*     const unsigned char *md_buf;
 /*     const char *md_len;
 /*
-/*     char    *tls_data_fprint(buf, len, mdalg)
-/*     const char *buf;
-/*     int     len;
-/*     const char *mdalg;
-/*
 /*     char    *tls_cert_fprint(peercert, mdalg)
 /*     X509    *peercert;
 /*     const char *mdalg;
 /*     The return value is dynamically allocated with mymalloc(),
 /*     and the caller must eventually free it with myfree().
 /*
-/*     tls_data_fprint() digests unstructured data, and encodes the digested
-/*     result via tls_digest_encode().  The return value is dynamically
-/*     allocated with mymalloc(), and the caller must eventually free it
-/*     with myfree().
-/*
 /*     tls_cert_fprint() returns a fingerprint of the the given
 /*     certificate using the requested message digest, formatted
 /*     with tls_digest_encode(). Panics if the
 /*     and the caller must eventually free it with myfree().
 /*
 /*     tls_serverid_digest() suffixes props->serverid computed by the SMTP
-/*     client with "&" plus a digest of additional parameters
-/*     needed to ensure that re-used sessions are more likely to
-/*     be reused and that they will satisfy all protocol and
-/*     security requirements.
-/*     The return value is dynamically allocated with mymalloc(),
-/*     and the caller must eventually free it with myfree().
+/*     client with "&" plus a digest of additional parameters needed to ensure
+/*     that re-used sessions are more likely to be reused and that they will
+/*     satisfy all protocol and security requirements.  The return value is
+/*     dynamically allocated with mymalloc(), and the caller must eventually
+/*     free it with myfree().
 /*
 /*     Arguments:
 /* .IP peercert
 static const char hexcodes[] = "0123456789ABCDEF";
 
 #define checkok(ret)   (ok &= ((ret) ? 1 : 0))
-#define digest_data(p, l) checkok(EVP_DigestUpdate(mdctx, (char *)(p), (l)))
-#define digest_object(p) digest_data((p), sizeof(*(p)))
-#define digest_string(s) digest_data((s), strlen(s)+1)
-
-#define digest_dane(dane, memb) do { \
-       if ((dane)->memb != 0) \
-           checkok(digest_tlsa_usage(mdctx, (dane)->memb, #memb)); \
-    } while (0)
-
-#define digest_tlsa_argv(tlsa, memb) do { \
-       if ((tlsa)->memb) { \
-           digest_string(#memb); \
-           for (dgst = (tlsa)->memb->argv; *dgst; ++dgst) \
-               digest_string(*dgst); \
-       } \
-    } while (0)
-
-/* digest_tlsa_usage - digest TA or EE match list sorted by alg and value */
-
-static int digest_tlsa_usage(EVP_MD_CTX * mdctx, TLS_TLSA *tlsa,
-                                    const char *usage)
+#define digest_object(p) digest_data((unsigned char *)(p), sizeof(*(p)))
+#define digest_data(p, l) checkok(digest_bytes(mdctx, (p), (l)))
+#define digest_string(s) checkok(digest_chars(mdctx, (s)))
+#define digest_dane(tlsa) checkok(tls_digest_tlsa(mdctx, tlsa))
+
+/* digest_bytes - hash octet string of given length */
+
+static int digest_bytes(EVP_MD_CTX *ctx, const unsigned char *buf, size_t len)
 {
-    char  **dgst;
+    return (EVP_DigestUpdate(ctx, buf, len));
+}
+
+/* digest_chars - hash string including trailing NUL */
+
+static int digest_chars(EVP_MD_CTX *ctx, const char *s)
+{
+    return (EVP_DigestUpdate(ctx, s, strlen(s) + 1));
+}
+
+/* tlsa_cmp - compare TLSA RRs for sorting to canonical order */
+
+static int tlsa_cmp(const void *a, const void *b)
+{
+    TLS_TLSA *p = *(TLS_TLSA **) a;
+    TLS_TLSA *q = *(TLS_TLSA **) b;
+    int     d;
+
+    if ((d = (int) p->usage - (int) q->usage) != 0)
+       return d;
+    if ((d = (int) p->selector - (int) q->selector) != 0)
+       return d;
+    if ((d = (int) p->mtype - (int) q->mtype) != 0)
+       return d;
+    if ((d = (int) p->length - (int) q->length) != 0)
+       return d;
+    return (memcmp(p->data, q->data, p->length));
+}
+
+/* tls_digest_tlsa - fold in digest of sorced TLSA records */
+
+static int tls_digest_tlsa(EVP_MD_CTX *mdctx, TLS_TLSA *tlsa)
+{
+    TLS_TLSA *p;
+    TLS_TLSA **arr;
     int     ok = 1;
+    int     n;
+    int     i;
 
-    for (digest_string(usage); tlsa; tlsa = tlsa->next) {
-       digest_string(tlsa->mdalg);
-       digest_tlsa_argv(tlsa, pkeys);
-       digest_tlsa_argv(tlsa, certs);
+    for (n = 0, p = tlsa; p != 0; p = p->next)
+       ++n;
+    arr = (TLS_TLSA **) mymalloc(n * sizeof(*arr));
+    for (i = 0, p = tlsa; p; p = p->next)
+       arr[i++] = (void *) p;
+    qsort(arr, n, sizeof(arr[0]), tlsa_cmp);
+
+    digest_object(&n);
+    for (i = 0; i < n; ++i) {
+       digest_object(&arr[i]->usage);
+       digest_object(&arr[i]->selector);
+       digest_object(&arr[i]->mtype);
+       digest_object(&arr[i]->length);
+       digest_data(arr[i]->data, arr[i]->length);
     }
+    myfree((void *) arr);
     return (ok);
 }
 
 /* tls_serverid_digest - suffix props->serverid with parameter digest */
 
-char   *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
-                                   const char *ciphers)
+char   *tls_serverid_digest(TLS_SESS_STATE *TLScontext,
+                                   const TLS_CLIENT_START_PROPS *props,
+                                   long protomask, const char *ciphers)
 {
     EVP_MD_CTX *mdctx;
     const EVP_MD *md;
@@ -198,37 +223,35 @@ char   *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
     digest_string(ciphers);
 
     /*
-     * All we get from the session cache is a single bit telling us whether
-     * the certificate is trusted or not, but we need to know whether the
-     * trust is CA-based (in that case we must do name checks) or whether it
-     * is a direct end-point match.  We mustn't confuse the two, so it is
-     * best to process only TA trust in the verify callback and check the EE
-     * trust after. This works since re-used sessions always have access to
-     * the leaf certificate, while only the original session has the leaf and
-     * the full trust chain.
-     * 
-     * Only the trust anchor matchlist is hashed into the session key. The end
-     * entity certs are not used to determine whether a certificate is
-     * trusted or not, rather these are rechecked against the leaf cert
-     * outside the verification callback, each time a session is created or
-     * reused.
-     * 
-     * Therefore, the security context of the session does not depend on the EE
-     * matching data, which is checked separately each time.  So we exclude
-     * the EE part of the DANE structure from the serverid digest.
-     * 
-     * If the security level is "dane", we send SNI information to the peer.
-     * This may cause it to respond with a non-default certificate.  Since
-     * certificates for sessions with no or different SNI data may not match,
-     * we must include the SNI name in the session id.
+     * Ensure separation of caches for sessions where DANE trust
+     * configuration succeeded from those where it did not.  The latter
+     * should always see a certificate validation failure, both on initial
+     * handshake and on resumption.
      */
-    if (props->dane) {
-       digest_dane(props->dane, ta);
-#if 0
-       digest_dane(props->dane, ee);           /* See above */
-#endif
-       digest_string(TLS_DANE_BASED(props->tls_level) ? props->host : "");
+    digest_object(&TLScontext->must_fail);
+
+    /*
+     * DNS-based or synthetic DANE trust settings are potentially used at all
+     * levels above "encrypt".
+     */
+    if (TLScontext->level > TLS_LEV_ENCRYPT
+       && props->dane && props->dane->tlsa) {
+       digest_dane(props->dane->tlsa);
+    } else {
+       int     none = 0;               /* Record a TLSA RR count of zero */
+
+       digest_object(&none);
     }
+
+    /*
+     * Include the chosen SNI name, which can affect server certificate
+     * selection.
+     */
+    if (TLScontext->level > TLS_LEV_ENCRYPT && TLScontext->peer_sni)
+       digest_string(TLScontext->peer_sni);
+    else
+       digest_string("");
+
     checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
     EVP_MD_CTX_destroy(mdctx);
     if (!ok)
@@ -282,7 +305,7 @@ char   *tls_digest_encode(const unsigned char *md_buf, int md_len)
 
 /* tls_data_fprint - compute and encode digest of binary object */
 
-char   *tls_data_fprint(const char *buf, int len, const char *mdalg)
+static char *tls_data_fprint(const unsigned char *buf, int len, const char *mdalg)
 {
     EVP_MD_CTX *mdctx;
     const EVP_MD *md;
@@ -310,13 +333,13 @@ char   *tls_data_fprint(const char *buf, int len, const char *mdalg)
 char   *tls_cert_fprint(X509 *peercert, const char *mdalg)
 {
     int     len;
-    char   *buf;
-    char   *buf2;
+    unsigned char *buf;
+    unsigned char *buf2;
     char   *result;
 
     len = i2d_X509(peercert, NULL);
     buf2 = buf = mymalloc(len);
-    i2d_X509(peercert, (unsigned char **) &buf2);
+    i2d_X509(peercert, &buf2);
     if (buf2 - buf != len)
        msg_panic("i2d_X509 invalid result length");
 
@@ -340,17 +363,17 @@ char   *tls_pkey_fprint(X509 *peercert, const char *mdalg)
            msg_fatal("%s: error extracting legacy public-key fingerprint: %m",
                      myname);
 
-       result = tls_data_fprint((char *) key->data, key->length, mdalg);
+       result = tls_data_fprint(key->data, key->length, mdalg);
        return (result);
     } else {
        int     len;
-       char   *buf;
-       char   *buf2;
+       unsigned char *buf;
+       unsigned char *buf2;
        char   *result;
 
        len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), NULL);
        buf2 = buf = mymalloc(len);
-       i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **) &buf2);
+       i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), &buf2);
        if (buf2 - buf != len)
            msg_panic("i2d_X509_PUBKEY invalid result length");
 
index 24d8be5c7827e25a9e32710fe7da2ccef5f416cb..ecb93289881edd50e399c2fac5bf2806fd95aa9a 100644 (file)
 /*     TLS_APPL_STATE *app_ctx;
 /*     int     log_mask;
 /*
-/*     int     tls_validate_digest(dgst)
+/*     const EVP_MD *tls_validate_digest(dgst)
 /*     const char *dgst;
 /* DESCRIPTION
 /*     This module implements public and internal routines that
 /*     tls_update_app_logmask() changes the log mask of the
 /*     application TLS context to the new setting.
 /*
-/*     tls_validate_digest() returns non-zero if the named digest
-/*     is usable and zero otherwise.
+/*     tls_validate_digest() returns a static handle for the named
+/*     digest algorithm, or NULL on error.
 /* LICENSE
 /* .ad
 /* .fi
 #include <ctype.h>
 #include <string.h>
 
-#ifdef USE_TLS
-
 /* Utility library. */
 
 #include <vstream.h>
@@ -292,13 +290,11 @@ char   *var_tls_tkt_cipher;
 char   *var_openssl_path;
 char   *var_tls_server_sni_maps;
 bool    var_tls_fast_shutdown;
-
-static MAPS *tls_server_sni_maps;
-
-#ifdef VAR_TLS_PREEMPT_CLIST
 bool    var_tls_preempt_clist;
 
-#endif
+#ifdef USE_TLS
+
+static MAPS *tls_server_sni_maps;
 
  /*
   * Index to attach TLScontext pointers to SSL objects, so that they can be
@@ -519,6 +515,7 @@ static const NAME_MASK tls_log_table[] = {
     "certmatch", TLS_LOG_CERTMATCH,
     "verbose", TLS_LOG_VERBOSE,                /* Postfix TLS library verbose */
     "cache", TLS_LOG_CACHE,
+    "dane", TLS_LOG_DANE,              /* DANE policy construction */
     "ssl-debug", TLS_LOG_DEBUG,                /* SSL library debug/verbose */
     "ssl-handshake-packet-dump", TLS_LOG_TLSPKTS,
     "ssl-session-packet-dump", TLS_LOG_TLSPKTS | TLS_LOG_ALLPKTS,
@@ -822,7 +819,6 @@ const char *tls_set_ciphers(TLS_SESS_STATE *TLScontext, const char *grade,
 
 void    tls_get_signature_params(TLS_SESS_STATE *TLScontext)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x1010100fUL && defined(TLS1_3_VERSION)
     const char *kex_name = 0;
     const char *kex_curve = 0;
     const char *locl_sig_name = 0;
@@ -963,6 +959,8 @@ void    tls_get_signature_params(TLS_SESS_STATE *TLScontext)
         */
        if (SSL_get_peer_signature_nid(ssl, &nid) && nid != NID_undef)
            peer_sig_dgst = OBJ_nid2sn(nid);
+
+       X509_free(cert);
     }
     if (kex_name) {
        TLScontext->kex_name = mystrdup(kex_name);
@@ -983,7 +981,6 @@ void    tls_get_signature_params(TLS_SESS_STATE *TLScontext)
        if (peer_sig_dgst)
            SIG_PROP(TLScontext, !srvr, dgst) = mystrdup(peer_sig_dgst);
     }
-#endif                                         /* OPENSSL_VERSION_NUMBER ... */
 }
 
 /* tls_log_summary - TLS loglevel 1 one-liner, embellished with TLS 1.3 details */
@@ -1121,11 +1118,8 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
     TLScontext->mdalg = 0;                     /* Alias for props->mdalg */
     TLScontext->dane = 0;                      /* Alias for props->dane */
     TLScontext->errordepth = -1;
-    TLScontext->tadepth = -1;
     TLScontext->errorcode = X509_V_OK;
     TLScontext->errorcert = 0;
-    TLScontext->untrusted = 0;
-    TLScontext->trusted = 0;
 
     return (TLScontext);
 }
@@ -1158,12 +1152,24 @@ void    tls_free_context(TLS_SESS_STATE *TLScontext)
        myfree(TLScontext->peer_cert_fprint);
     if (TLScontext->peer_pkey_fprint)
        myfree(TLScontext->peer_pkey_fprint);
+    if (TLScontext->kex_name)
+       myfree((void *) TLScontext->kex_name);
+    if (TLScontext->kex_curve)
+       myfree((void *) TLScontext->kex_curve);
+    if (TLScontext->clnt_sig_name)
+       myfree((void *) TLScontext->clnt_sig_name);
+    if (TLScontext->clnt_sig_curve)
+       myfree((void *) TLScontext->clnt_sig_curve);
+    if (TLScontext->clnt_sig_dgst)
+       myfree((void *) TLScontext->clnt_sig_dgst);
+    if (TLScontext->srvr_sig_name)
+       myfree((void *) TLScontext->srvr_sig_name);
+    if (TLScontext->srvr_sig_curve)
+       myfree((void *) TLScontext->srvr_sig_curve);
+    if (TLScontext->srvr_sig_dgst)
+       myfree((void *) TLScontext->srvr_sig_dgst);
     if (TLScontext->errorcert)
        X509_free(TLScontext->errorcert);
-    if (TLScontext->untrusted)
-       sk_X509_pop_free(TLScontext->untrusted, X509_free);
-    if (TLScontext->trusted)
-       sk_X509_pop_free(TLScontext->trusted, X509_free);
 
     myfree((void *) TLScontext);
 }
@@ -1182,57 +1188,17 @@ static void tls_version_split(unsigned long version, TLS_VINFO *info)
      * 
      * The status nibble has one of the values 0 for development, 1 to e for
      * betas 1 to 14, and f for release. Parsed OpenSSL version number. for
-     * example
-     * 
-     * 0x000906000 == 0.9.6 dev 0x000906023 == 0.9.6b beta 3 0x00090605f ==
-     * 0.9.6e release
-     * 
-     * Versions prior to 0.9.3 have identifiers < 0x0930.  Versions between
-     * 0.9.3 and 0.9.5 had a version identifier with this interpretation:
-     * 
-     * MMNNFFRBB major minor fix final beta/patch
-     * 
-     * for example
-     * 
-     * 0x000904100 == 0.9.4 release 0x000905000 == 0.9.5 dev
-     * 
-     * Version 0.9.5a had an interim interpretation that is like the current
-     * one, except the patch level got the highest bit set, to keep continu-
-     * ity.  The number was therefore 0x0090581f.
+     * example: 0x1010103f == 1.1.1c.
      */
-
-    if (version < 0x0930) {
-       info->status = 0;
-       info->patch = version & 0x0f;
-       version >>= 4;
-       info->micro = version & 0x0f;
-       version >>= 4;
-       info->minor = version & 0x0f;
-       version >>= 4;
-       info->major = version & 0x0f;
-    } else if (version < 0x00905800L) {
-       info->patch = version & 0xff;
-       version >>= 8;
-       info->status = version & 0xf;
-       version >>= 4;
-       info->micro = version & 0xff;
-       version >>= 8;
-       info->minor = version & 0xff;
-       version >>= 8;
-       info->major = version & 0xff;
-    } else {
-       info->status = version & 0xf;
-       version >>= 4;
-       info->patch = version & 0xff;
-       version >>= 8;
-       info->micro = version & 0xff;
-       version >>= 8;
-       info->minor = version & 0xff;
-       version >>= 8;
-       info->major = version & 0xff;
-       if (version < 0x00906000L)
-           info->patch &= ~0x80;
-    }
+    info->status = version & 0xf;
+    version >>= 4;
+    info->patch = version & 0xff;
+    version >>= 8;
+    info->micro = version & 0xff;
+    version >>= 8;
+    info->minor = version & 0xff;
+    version >>= 8;
+    info->major = version & 0xff;
 }
 
 /* tls_check_version - Detect mismatch between headers and library. */
@@ -1494,29 +1460,11 @@ long    tls_bio_dump_cb(BIO *bio, int cmd, const char *argp, int argi,
     return (ret);
 }
 
-int     tls_validate_digest(const char *dgst)
+const EVP_MD *tls_validate_digest(const char *dgst)
 {
     const EVP_MD *md_alg;
     unsigned int md_len;
 
-    /*
-     * Register SHA-2 digests, if implemented and not already registered.
-     * Improves interoperability with clients and servers that prematurely
-     * deploy SHA-2 certificates.  Also facilitates DANE and TA support.
-     */
-#if defined(LN_sha256) && defined(NID_sha256) && !defined(OPENSSL_NO_SHA256)
-    if (!EVP_get_digestbyname(LN_sha224))
-       EVP_add_digest(EVP_sha224());
-    if (!EVP_get_digestbyname(LN_sha256))
-       EVP_add_digest(EVP_sha256());
-#endif
-#if defined(LN_sha512) && defined(NID_sha512) && !defined(OPENSSL_NO_SHA512)
-    if (!EVP_get_digestbyname(LN_sha384))
-       EVP_add_digest(EVP_sha384());
-    if (!EVP_get_digestbyname(LN_sha512))
-       EVP_add_digest(EVP_sha512());
-#endif
-
     /*
      * If the administrator specifies an unsupported digest algorithm, fail
      * now, rather than in the middle of a TLS handshake.
@@ -1534,7 +1482,7 @@ int     tls_validate_digest(const char *dgst)
                 dgst, md_len);
        return (0);
     }
-    return (1);
+    return md_alg;
 }
 
 #else
index 45058c35639e400ee0ede0adf20feaf04641d10e..f32f9a0c8494c8e829bf35f53fd132a35686b886 100644 (file)
@@ -160,6 +160,7 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
 #define TLS_ATTR_ISSUER_CN     "issuer_CN"
 #define TLS_ATTR_PEER_CERT_FPT "peer_fingerprint"
 #define TLS_ATTR_PEER_PKEY_FPT "peer_pubkey_fingerprint"
+#define TLS_ATTR_SEC_LEVEL      "level"
 #define TLS_ATTR_PEER_STATUS   "peer_status"
 #define TLS_ATTR_CIPHER_PROTOCOL "cipher_protocol"
 #define TLS_ATTR_CIPHER_NAME   "cipher_name"
@@ -252,30 +253,15 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
  /*
   * TLS_TLSA attributes.
   */
-#define TLS_ATTR_MDALG         "mdalg"
-#define TLS_ATTR_CERTS         "certs"
-#define TLS_ATTR_PKEYS         "pkeys"
-
- /*
-  * TLS_CERTS attributes.
-  */
-#define TLS_ATTR_CERT          "cert"
-
- /*
-  * TLS_PKEYS attributes.
-  */
-#define TLS_ATTR_PKEY          "pkey"
+#define TLS_ATTR_USAGE         "usage"
+#define TLS_ATTR_SELECTOR      "selector"
+#define TLS_ATTR_MTYPE         "mtype"
+#define TLS_ATTR_DATA          "data"
 
  /*
   * TLS_DANE attributes.
   */
-#define TLS_ATTR_TA            "ta"
-#define TLS_ATTR_EE            "ee"
-#define TLS_ATTR_CERTS         "certs"
-#define TLS_ATTR_PKEYS         "pkeys"
 #define TLS_ATTR_DOMAIN                "domain"
-#define TLS_ATTR_FLAGS         "flags"
-#define TLS_ATTR_EXP           "exp"
 
 #endif
 
index 00e38bf95eac6a51628a033524098233ffa8c470..ac628502e469860270985411c2777969e770bbb2 100644 (file)
@@ -180,110 +180,18 @@ int     tls_proxy_client_init_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
     return (ret);
 }
 
-/* tls_proxy_client_certs_print - send x509 certificates over stream */
-
-static int tls_proxy_client_certs_print(ATTR_PRINT_COMMON_FN print_fn,
-                                         VSTREAM *fp, int flags, void *ptr)
-{
-    TLS_CERTS *tls_certs = (TLS_CERTS *) ptr;
-    TLS_CERTS *tp;
-    int     count;
-    int     ret;
-
-    for (tp = tls_certs, count = 0; tp != 0; tp = tp->next, count++)
-        /* void */ ;
-    if (msg_verbose)
-       msg_info("tls_proxy_client_certs_print count=%d", count);
-
-    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
-                  SEND_ATTR_INT(TLS_ATTR_COUNT, count),
-                  ATTR_TYPE_END);
-
-    if (ret == 0 && count > 0) {
-       VSTRING *buf = vstring_alloc(100);
-       int     n;
-
-       for (tp = tls_certs, n = 0; ret == 0 && n < count; tp = tp->next, n++) {
-           size_t  len = i2d_X509(tp->cert, (unsigned char **) 0);
-           unsigned char *bp;
-
-           VSTRING_RESET(buf);
-           VSTRING_SPACE(buf, len);
-           bp = (unsigned char *) STR(buf);
-           i2d_X509(tp->cert, &bp);
-           if ((char *) bp - STR(buf) != len)
-               msg_panic("i2d_X509 failed to encode certificate");
-           vstring_set_payload_size(buf, len);
-           ret = print_fn(fp, flags | ATTR_FLAG_MORE,
-                          SEND_ATTR_DATA(TLS_ATTR_CERT, LEN(buf), STR(buf)),
-                          ATTR_TYPE_END);
-       }
-       vstring_free(buf);
-    }
-    /* Do not flush the stream. */
-    if (msg_verbose)
-       msg_info("tls_proxy_client_certs_print ret=%d", count);
-    return (ret);
-}
-
-/* tls_proxy_client_pkeys_print - send public keys over stream */
-
-static int tls_proxy_client_pkeys_print(ATTR_PRINT_COMMON_FN print_fn,
-                                         VSTREAM *fp, int flags, void *ptr)
-{
-    TLS_PKEYS *tls_pkeys = (TLS_PKEYS *) ptr;
-    TLS_PKEYS *tp;
-    int     count;
-    int     ret;
-
-    for (tp = tls_pkeys, count = 0; tp != 0; tp = tp->next, count++)
-        /* void */ ;
-    if (msg_verbose)
-       msg_info("tls_proxy_client_pkeys_print count=%d", count);
-
-    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
-                  SEND_ATTR_INT(TLS_ATTR_COUNT, count),
-                  ATTR_TYPE_END);
-
-    if (ret == 0 && count > 0) {
-       VSTRING *buf = vstring_alloc(100);
-       int     n;
-
-       for (tp = tls_pkeys, n = 0; ret == 0 && n < count; tp = tp->next, n++) {
-           size_t  len = i2d_PUBKEY(tp->pkey, (unsigned char **) 0);
-           unsigned char *bp;
-
-           VSTRING_RESET(buf);
-           VSTRING_SPACE(buf, len);
-           bp = (unsigned char *) STR(buf);
-           i2d_PUBKEY(tp->pkey, &bp);
-           if ((char *) bp - STR(buf) != len)
-               msg_panic("i2d_PUBKEY failed to encode public key");
-           vstring_set_payload_size(buf, len);
-           ret = print_fn(fp, flags | ATTR_FLAG_MORE,
-                          SEND_ATTR_DATA(TLS_ATTR_PKEY, LEN(buf), STR(buf)),
-                          ATTR_TYPE_END);
-       }
-       vstring_free(buf);
-    }
-    /* Do not flush the stream. */
-    if (msg_verbose)
-       msg_info("tls_proxy_client_pkeys_print ret=%d", count);
-    return (ret);
-}
-
 /* tls_proxy_client_tlsa_print - send TLS_TLSA over stream */
 
 static int tls_proxy_client_tlsa_print(ATTR_PRINT_COMMON_FN print_fn,
                                          VSTREAM *fp, int flags, void *ptr)
 {
-    TLS_TLSA *tls_tlsa = (TLS_TLSA *) ptr;
+    TLS_TLSA *head = (TLS_TLSA *) ptr;
     TLS_TLSA *tp;
     int     count;
     int     ret;
 
-    for (tp = tls_tlsa, count = 0; tp != 0; tp = tp->next, count++)
-        /* void */ ;
+    for (tp = head, count = 0; tp != 0; tp = tp->next)
+       ++count;
     if (msg_verbose)
        msg_info("tls_proxy_client_tlsa_print count=%d", count);
 
@@ -291,19 +199,14 @@ static int tls_proxy_client_tlsa_print(ATTR_PRINT_COMMON_FN print_fn,
                   SEND_ATTR_INT(TLS_ATTR_COUNT, count),
                   ATTR_TYPE_END);
 
-    if (ret == 0 && count > 0) {
-       int     n;
-
-       for (tp = tls_tlsa, n = 0; ret == 0 && n < count; tp = tp->next, n++) {
-           ret = print_fn(fp, flags | ATTR_FLAG_MORE,
-                          SEND_ATTR_STR(TLS_ATTR_MDALG, tp->mdalg),
-                          SEND_ATTR_FUNC(argv_attr_print,
-                                         (void *) tp->certs),
-                          SEND_ATTR_FUNC(argv_attr_print,
-                                         (void *) tp->pkeys),
-                          ATTR_TYPE_END);
-       }
-    }
+    for (tp = head; ret == 0 && tp != 0; tp = tp->next)
+       ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                      SEND_ATTR_INT(TLS_ATTR_USAGE, tp->usage),
+                      SEND_ATTR_INT(TLS_ATTR_SELECTOR, tp->selector),
+                      SEND_ATTR_INT(TLS_ATTR_MTYPE, tp->mtype),
+                      SEND_ATTR_DATA(TLS_ATTR_DATA, tp->length, tp->data),
+                      ATTR_TYPE_END);
+
     /* Do not flush the stream. */
     if (msg_verbose)
        msg_info("tls_proxy_client_tlsa_print ret=%d", count);
@@ -325,19 +228,12 @@ static int tls_proxy_client_dane_print(ATTR_PRINT_COMMON_FN print_fn,
        msg_info("tls_proxy_client_dane_print dane=%d", dane != 0);
 
     if (ret == 0 && dane != 0) {
+       /* Send the base_domain and RRs, we don't need the other fields */
        ret = print_fn(fp, flags | ATTR_FLAG_MORE,
-                      SEND_ATTR_FUNC(tls_proxy_client_tlsa_print,
-                                     (void *) dane->ta),
-                      SEND_ATTR_FUNC(tls_proxy_client_tlsa_print,
-                                     (void *) dane->ee),
-                      SEND_ATTR_FUNC(tls_proxy_client_certs_print,
-                                     (void *) dane->certs),
-                      SEND_ATTR_FUNC(tls_proxy_client_pkeys_print,
-                                     (void *) dane->pkeys),
                       SEND_ATTR_STR(TLS_ATTR_DOMAIN,
                                     STRING_OR_EMPTY(dane->base_domain)),
-                      SEND_ATTR_INT(TLS_ATTR_FLAGS, dane->flags),
-                      SEND_ATTR_LONG(TLS_ATTR_EXP, dane->expires),
+                      SEND_ATTR_FUNC(tls_proxy_client_tlsa_print,
+                                     (void *) dane->tlsa),
                       ATTR_TYPE_END);
     }
     /* Do not flush the stream. */
index 0d2b43b2d562a8ef2a4fabc1fb0d58b6309efc16..06a63765161ee24ebc6801be53dad1e0487ce999 100644 (file)
 
 /* TLS library. */
 
+#define TLS_INTERNAL
 #include <tls.h>
 #include <tls_proxy.h>
 
@@ -306,59 +307,6 @@ int     tls_proxy_client_init_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     return (ret);
 }
 
-/* tls_proxy_client_certs_free - destroy TLS_PKEYS from stream */
-
-static void tls_proxy_client_certs_free(TLS_CERTS *tp)
-{
-    if (tp->next)
-       tls_proxy_client_certs_free(tp->next);
-    if (tp->cert)
-       X509_free(tp->cert);
-    myfree((void *) tp);
-}
-
-/* tls_proxy_client_pkeys_free - destroy TLS_PKEYS from stream */
-
-static void tls_proxy_client_pkeys_free(TLS_PKEYS *tp)
-{
-    if (tp->next)
-       tls_proxy_client_pkeys_free(tp->next);
-    if (tp->pkey)
-       EVP_PKEY_free(tp->pkey);
-    myfree((void *) tp);
-}
-
-/* tls_proxy_client_tlsa_free - destroy TLS_TLSA from stream */
-
-static void tls_proxy_client_tlsa_free(TLS_TLSA *tp)
-{
-    if (tp->next)
-       tls_proxy_client_tlsa_free(tp->next);
-    myfree(tp->mdalg);
-    if (tp->certs)
-       argv_free(tp->certs);
-    if (tp->pkeys)
-       argv_free(tp->pkeys);
-    myfree((void *) tp);
-}
-
-/* tls_proxy_client_dane_free - destroy TLS_DANE from stream */
-
-static void tls_proxy_client_dane_free(TLS_DANE *dane)
-{
-    if (dane->ta)
-       tls_proxy_client_tlsa_free(dane->ta);
-    if (dane->ee)
-       tls_proxy_client_tlsa_free(dane->ee);
-    if (dane->certs)
-       tls_proxy_client_certs_free(dane->certs);
-    if (dane->pkeys)
-       tls_proxy_client_pkeys_free(dane->pkeys);
-    myfree(dane->base_domain);
-    if (dane->refs-- == 1)
-       myfree((void *) dane);
-}
-
 /* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */
 
 void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
@@ -376,169 +324,49 @@ void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
        argv_free((ARGV *) props->matchargv);
     myfree((void *) props->mdalg);
     if (props->dane)
-       tls_proxy_client_dane_free((TLS_DANE *) props->dane);
+       tls_dane_free((TLS_DANE *) props->dane);
     myfree((void *) props);
 }
 
-/* tls_proxy_client_certs_scan - receive TLS_CERTS from stream */
-
-static int tls_proxy_client_certs_scan(ATTR_SCAN_COMMON_FN scan_fn,
-                                         VSTREAM *fp, int flags, void *ptr)
-{
-    int     ret;
-    int     count;
-    VSTRING *buf = 0;
-    TLS_CERTS **tpp;
-    TLS_CERTS *head = 0;
-    TLS_CERTS *tp;
-    int     n;
-
-    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
-                 RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
-                 ATTR_TYPE_END);
-    if (msg_verbose)
-       msg_info("tls_proxy_client_certs_scan count=%d", count);
-
-    for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
-       *tpp = tp = (TLS_CERTS *) mymalloc(sizeof(*tp));
-       const unsigned char *bp;
-
-       if (buf == 0)
-           buf = vstring_alloc(100);
-
-       /*
-        * Note: memset() is not a portable way to initialize non-integer
-        * types.
-        */
-       memset(tp, 0, sizeof(*tp));
-       ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
-                     RECV_ATTR_DATA(TLS_ATTR_CERT, buf),
-                     ATTR_TYPE_END);
-       /* Always construct a well-formed structure. */
-       if (ret == 1) {
-           bp = (const unsigned char *) STR(buf);
-           if (d2i_X509(&tp->cert, &bp, LEN(buf)) == 0
-               || LEN(buf) != ((char *) bp) - STR(buf)) {
-               msg_warn("malformed certificate in TLS_CERTS");
-               ret = -1;
-           }
-       } else {
-           tp->cert = 0;
-       }
-       tp->next = 0;
-    }
-    if (buf)
-       vstring_free(buf);
-    if (ret != 1) {
-       tls_proxy_client_certs_free(head);
-       head = 0;
-    }
-    *(TLS_CERTS **) ptr = head;
-    if (msg_verbose)
-       msg_info("tls_proxy_client_certs_scan ret=%d", ret);
-    return (ret);
-}
-
-/* tls_proxy_client_pkeys_scan - receive TLS_PKEYS from stream */
-
-static int tls_proxy_client_pkeys_scan(ATTR_SCAN_COMMON_FN scan_fn,
-                                         VSTREAM *fp, int flags, void *ptr)
-{
-    int     ret;
-    int     count;
-    VSTRING *buf = vstring_alloc(100);
-    TLS_PKEYS **tpp;
-    TLS_PKEYS *head = 0;
-    TLS_PKEYS *tp;
-    int     n;
-
-    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
-                 RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
-                 ATTR_TYPE_END);
-    if (msg_verbose)
-       msg_info("tls_proxy_client_pkeys_scan count=%d", count);
-
-    for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
-       *tpp = tp = (TLS_PKEYS *) mymalloc(sizeof(*tp));
-       const unsigned char *bp;
-
-       if (buf == 0)
-           buf = vstring_alloc(100);
-
-       /*
-        * Note: memset() is not a portable way to initialize non-integer
-        * types.
-        */
-       memset(tp, 0, sizeof(*tp));
-       ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
-                     RECV_ATTR_DATA(TLS_ATTR_PKEY, buf),
-                     ATTR_TYPE_END);
-       /* Always construct a well-formed structure. */
-       if (ret == 1) {
-           bp = (const unsigned char *) STR(buf);
-           if (d2i_PUBKEY(&tp->pkey, &bp, LEN(buf)) == 0
-               || LEN(buf) != (char *) bp - STR(buf)) {
-               msg_warn("malformed public key in TLS_PKEYS");
-               ret = -1;
-           }
-       } else {
-           tp->pkey = 0;
-       }
-       tp->next = 0;
-    }
-    if (buf)
-       vstring_free(buf);
-    if (ret != 1) {
-       tls_proxy_client_pkeys_free(head);
-       head = 0;
-    }
-    *(TLS_PKEYS **) ptr = head;
-    if (msg_verbose)
-       msg_info("tls_proxy_client_pkeys_scan ret=%d", ret);
-    return (ret);
-}
-
 /* tls_proxy_client_tlsa_scan - receive TLS_TLSA from stream */
 
 static int tls_proxy_client_tlsa_scan(ATTR_SCAN_COMMON_FN scan_fn,
                                          VSTREAM *fp, int flags, void *ptr)
 {
-    int     ret;
+    static VSTRING *data;
+    TLS_TLSA *head;
     int     count;
-    TLS_TLSA **tpp;
-    TLS_TLSA *head = 0;
-    TLS_TLSA *tp;
-    int     n;
+    int     ret;
+
+    if (data == 0)
+       data = vstring_alloc(64);
 
     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
                  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
                  ATTR_TYPE_END);
-    if (msg_verbose)
+    if (ret == 1 && msg_verbose)
        msg_info("tls_proxy_client_tlsa_scan count=%d", count);
 
-    for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
-       *tpp = tp = (TLS_TLSA *) mymalloc(sizeof(*tp));
-       VSTRING *mdalg = vstring_alloc(25);
+    for (head = 0; ret == 1 && count > 0; --count) {
+       int     u, s, m;
 
-       /*
-        * Note: memset() is not a portable way to initialize non-integer
-        * types.
-        */
-       memset(tp, 0, sizeof(*tp));
-       /* Always construct a well-formed structure. */
-       tp->certs = 0;                          /* scan_fn may return early */
-       tp->pkeys = 0;
        ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
-                     RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
-                     RECV_ATTR_FUNC(argv_attr_scan, &tp->certs),
-                     RECV_ATTR_FUNC(argv_attr_scan, &tp->pkeys),
+                     RECV_ATTR_INT(TLS_ATTR_USAGE, &u),
+                     RECV_ATTR_INT(TLS_ATTR_SELECTOR, &s),
+                     RECV_ATTR_INT(TLS_ATTR_MTYPE, &m),
+                     RECV_ATTR_DATA(TLS_ATTR_DATA, data),
                      ATTR_TYPE_END);
-       tp->mdalg = vstring_export(mdalg);
-       tp->next = 0;
-       ret = (ret == 3 ? 1 : -1);
+       if (ret == 4) {
+           ret = 1;
+           /* This makes a copy of the static vstring content */
+           head = tlsa_prepend(head, u, s, m, (unsigned char *) STR(data),
+                               LEN(data));
+       } else
+           ret = -1;
     }
+
     if (ret != 1) {
-       tls_proxy_client_tlsa_free(head);
+       tls_tlsa_free(head);
        head = 0;
     }
     *(TLS_TLSA **) ptr = head;
@@ -564,41 +392,20 @@ static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
 
     if (ret == 1 && have_dane) {
        VSTRING *base_domain = vstring_alloc(25);
-       long    expires;
 
-       dane = (TLS_DANE *) mymalloc(sizeof(*dane));
-
-       /*
-        * Note: memset() is not a portable way to initialize non-integer
-        * types.
-        */
-       memset(dane, 0, sizeof(*dane));
-       /* Always construct a well-formed structure. */
-       dane->ta = 0;                           /* scan_fn may return early */
-       dane->ee = 0;
-       dane->certs = 0;
-       dane->pkeys = 0;
+       dane = tls_dane_alloc();
+       /* We only need the base domain and TLSA RRs */
        ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
-                     RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
-                                    &dane->ta),
-                     RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
-                                    &dane->ee),
-                     RECV_ATTR_FUNC(tls_proxy_client_certs_scan,
-                                    &dane->certs),
-                     RECV_ATTR_FUNC(tls_proxy_client_pkeys_scan,
-                                    &dane->pkeys),
                      RECV_ATTR_STR(TLS_ATTR_DOMAIN, base_domain),
-                     RECV_ATTR_INT(TLS_ATTR_FLAGS, &dane->flags),
-                     RECV_ATTR_LONG(TLS_ATTR_EXP, &expires),
+                     RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
+                                    &dane->tlsa),
                      ATTR_TYPE_END);
+
        /* Always construct a well-formed structure. */
        dane->base_domain = vstring_export(base_domain);
-       dane->expires = expires;
-       dane->refs = 1;
-       ret = (ret == 7 ? 1 : -1);
-       /* XXX if scan_fn() completed normally, sanity check dane->flags. */
+       ret = (ret == 2 ? 1 : -1);
        if (ret != 1) {
-           tls_proxy_client_dane_free(dane);
+           tls_dane_free(dane);
            dane = 0;
        }
     }
index dadd64f818ff50be53397a4270600bf9941ae0d6..4e7f9127d0d0497662d2053205dbe6a387b3ae9c 100644 (file)
@@ -70,6 +70,8 @@ int     tls_proxy_context_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
                                 STRING_OR_EMPTY(tp->peer_cert_fprint)),
                   SEND_ATTR_STR(TLS_ATTR_PEER_PKEY_FPT,
                                 STRING_OR_EMPTY(tp->peer_pkey_fprint)),
+                  SEND_ATTR_INT(TLS_ATTR_SEC_LEVEL,
+                                tp->level),
                   SEND_ATTR_INT(TLS_ATTR_PEER_STATUS,
                                 tp->peer_status),
                   SEND_ATTR_STR(TLS_ATTR_CIPHER_PROTOCOL,
index af216ac36425c734f822e06d90c448f0867d6ba0..1d463ada93375a767c2f8ef9d4a32a07fac9b737 100644 (file)
@@ -100,6 +100,8 @@ int     tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
                  RECV_ATTR_STR(TLS_ATTR_ISSUER_CN, issuer_CN),
                  RECV_ATTR_STR(TLS_ATTR_PEER_CERT_FPT, peer_cert_fprint),
                  RECV_ATTR_STR(TLS_ATTR_PEER_PKEY_FPT, peer_pkey_fprint),
+                 RECV_ATTR_INT(TLS_ATTR_SEC_LEVEL,
+                               &tls_context->level),
                  RECV_ATTR_INT(TLS_ATTR_PEER_STATUS,
                                &tls_context->peer_status),
                  RECV_ATTR_STR(TLS_ATTR_CIPHER_PROTOCOL, protocol),
@@ -137,7 +139,7 @@ int     tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     tls_context->srvr_sig_curve = vstring_export(srvr_sig_curve);
     tls_context->srvr_sig_dgst = vstring_export(srvr_sig_dgst);
     tls_context->namaddr = vstring_export(namaddr);
-    ret = (ret == 21 ? 1 : -1);
+    ret = (ret == 22 ? 1 : -1);
     if (ret != 1) {
        tls_proxy_context_free(tls_context);
        tls_context = 0;
index 67f2a2eeb5e58c899fcf4c7f28962434f7497aff..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,127 +0,0 @@
-/*++
-/* NAME
-/*     tls_rsa
-/* SUMMARY
-/*     RSA support
-/* SYNOPSIS
-/*     #define TLS_INTERNAL
-/*     #include <tls.h>
-/*
-/*     RSA     *tls_tmp_rsa_cb(ssl, export, keylength)
-/*     SSL     *ssl; /* unused */
-/*     int     export;
-/*     int     keylength;
-/* DESCRIPTION
-/*     tls_tmp_rsa_cb() is a call-back routine for the
-/*     SSL_CTX_set_tmp_rsa_callback() function.
-/*
-/*     This implementation will generate only 512-bit ephemeral
-/*     RSA keys for export ciphersuites. It will log a warning in
-/*     all other usage contexts.
-/* LICENSE
-/* .ad
-/* .fi
-/*     This software is free. You can do with it whatever you want.
-/*     The original author kindly requests that you acknowledge
-/*     the use of his software.
-/* AUTHOR(S)
-/*     Originally written by:
-/*     Lutz Jaenicke
-/*     BTU Cottbus
-/*     Allgemeine Elektrotechnik
-/*     Universitaetsplatz 3-4
-/*     D-03044 Cottbus, Germany
-/*
-/*     Updated by:
-/*     Wietse Venema
-/*     IBM T.J. Watson Research
-/*     P.O. Box 704
-/*     Yorktown Heights, NY 10598, USA
-/*
-/*     Viktor Dukhovni.
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <msg.h>
-
-#ifdef USE_TLS
-
-/* TLS library. */
-
-#define TLS_INTERNAL
-#include <tls.h>
-#include <openssl/rsa.h>
-
- /*
-  * 2015-12-05: Ephemeral RSA removed from OpenSSL 1.1.0-dev
-  */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-/* tls_tmp_rsa_cb - call-back to generate ephemeral RSA key */
-
-RSA    *tls_tmp_rsa_cb(SSL *unused_ssl, int export, int keylength)
-{
-    static RSA *rsa_tmp;
-
-    /*
-     * We generate ephemeral RSA keys only for export ciphersuites.  In all
-     * other contexts use of ephemeral RSA keys violates the SSL/TLS
-     * protocol, and only takes place when applications ask for trouble and
-     * set the SSL_OP_EPHEMERAL_RSA option.  Postfix should never do that.
-     */
-    if (!export || keylength != 512) {
-       msg_warn("%sexport %d-bit ephemeral RSA key requested",
-                export ? "" : "non-", keylength);
-       return 0;
-    }
-    if (rsa_tmp == 0) {
-       BIGNUM *e = BN_new();
-
-       if (e != 0 && BN_set_word(e, RSA_F4) && (rsa_tmp = RSA_new()) != 0)
-           if (!RSA_generate_key_ex(rsa_tmp, keylength, e, 0)) {
-               RSA_free(rsa_tmp);
-               rsa_tmp = 0;
-           }
-       if (e)
-           BN_free(e);
-    }
-    return (rsa_tmp);
-}
-
-#endif                                 /* OPENSSL_VERSION_NUMBER */
-
-#ifdef TEST
-
-#include <msg_vstream.h>
-
-int     main(int unused_argc, char *const argv[])
-{
-    int     ok = 0;
-
-    /*
-     * 2015-12-05: Ephemeral RSA removed from OpenSSL 1.1.0-dev
-     */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-    RSA    *rsa;
-
-    msg_vstream_init(argv[0], VSTREAM_ERR);
-
-    /* Export at 512-bits should work */
-    rsa = tls_tmp_rsa_cb(0, 1, 512);
-    ok = rsa != 0 && RSA_size(rsa) == 512 / 8;
-    ok = ok && PEM_write_RSAPrivateKey(stdout, rsa, 0, 0, 0, 0, 0);
-    tls_print_errors();
-
-    /* Non-export or unexpected bit length should fail */
-    ok = ok && tls_tmp_rsa_cb(0, 0, 512) == 0;
-    ok = ok && tls_tmp_rsa_cb(0, 1, 1024) == 0;
-#endif
-
-    return ok ? 0 : 1;
-}
-
-#endif
-
-#endif
index dcfd3d0a2bde6c451519c4958dbf7be02468e3bf..408d2868183f30ee46779bf3619fe7db4ea2abcc 100644 (file)
@@ -255,7 +255,8 @@ static int tls_scache_decode(TLS_SCACHE *cp, const char *cache_id,
 #define FREE_AND_RETURN(ptr, x) { vstring_free(ptr); return (x); }
 
     bin_data = vstring_alloc(hex_data_len / 2 + 1);
-    if (hex_decode(bin_data, hex_data, hex_data_len) == 0) {
+    if (hex_decode_opt(bin_data, hex_data, hex_data_len,
+                      HEX_DECODE_FLAG_ALLOW_COLON) == 0) {
        msg_warn("%s TLS cache: malformed entry for %s: %.100s",
                 cp->cache_label, cache_id, hex_data);
        FREE_AND_RETURN(bin_data, 0);
index 0b81d2b64b199c300342f116a7d0217238c6deda..bd3aca228c4a4d293297cc3819d179eb8fd69547 100644 (file)
@@ -166,15 +166,8 @@ static const char server_session_id_context[] = "Postfix/TLS";
 
 #define GET_SID(s, v, lptr)    ((v) = SSL_SESSION_get_id((s), (lptr)))
 
- /* OpenSSL 1.1.0 bitrot */
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 typedef const unsigned char *session_id_t;
 
-#else
-typedef unsigned char *session_id_t;
-
-#endif
-
 /* get_server_session_cb - callback to retrieve session from server cache */
 
 static SSL_SESSION *get_server_session_cb(SSL *ssl, session_id_t session_id,
@@ -370,17 +363,6 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
      */
     tls_check_version();
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-    /*
-     * Initialize the OpenSSL library by the book! To start with, we must
-     * initialize the algorithms. We want cleartext error messages instead of
-     * just error codes, so we load the error_strings.
-     */
-    SSL_load_error_strings();
-    OpenSSL_add_ssl_algorithms();
-#endif
-
     /*
      * First validate the protocols. If these are invalid, we can't continue.
      */
@@ -607,20 +589,6 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
        return (0);
     }
 
-    /*
-     * 2015-12-05: Ephemeral RSA removed from OpenSSL 1.1.0-dev
-     */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-
-    /*
-     * According to OpenSSL documentation, a temporary RSA key is needed when
-     * export ciphers are in use, because the certified key cannot be
-     * directly used.
-     */
-    SSL_CTX_set_tmp_rsa_callback(server_ctx, tls_tmp_rsa_cb);
-    SSL_CTX_set_tmp_rsa_callback(sni_ctx, tls_tmp_rsa_cb);
-#endif
-
     /*
      * Diffie-Hellman key generation parameters can either be loaded from
      * files (preferred) or taken from compiled in values. First, set the
@@ -629,19 +597,17 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
      * the error handling, since we do have default values compiled in, so we
      * will not abort but just log the error message.
      */
-    SSL_CTX_set_tmp_dh_callback(server_ctx, tls_tmp_dh_cb);
-    SSL_CTX_set_tmp_dh_callback(sni_ctx, tls_tmp_dh_cb);
     if (*props->dh1024_param_file != 0)
-       tls_set_dh_from_file(props->dh1024_param_file, 1024);
-    if (*props->dh512_param_file != 0)
-       tls_set_dh_from_file(props->dh512_param_file, 512);
+       tls_set_dh_from_file(props->dh1024_param_file);
+    tls_tmp_dh(server_ctx);
+    tls_tmp_dh(sni_ctx);
 
     /*
      * Enable EECDH if available, errors are not fatal, we just keep going
      * with any remaining key-exchange algorithms.
      */
-    tls_set_eecdh_curve(server_ctx, props->eecdh_grade);
-    tls_set_eecdh_curve(sni_ctx, props->eecdh_grade);
+    tls_auto_eecdh_curves(server_ctx, var_tls_eecdh_auto);
+    tls_auto_eecdh_curves(sni_ctx, var_tls_eecdh_auto);
 
     /*
      * If we want to check client certificates, we have to indicate it in
index 85d5f649d4d2fb5f7cccbd6c1b97788327f2a388..f32f32b4a71690f0d5c38d36eaecad31a5bc980f 100644 (file)
 /*     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;
 /* DESCRIPTION
 /*     tls_verify_certificate_callback() is called several times (directly
 /*     or indirectly) from crypto/x509/x509_vfy.c. It collects errors
 /*     freed by the caller; it contains UTF-8 without non-printable
 /*     ASCII characters.
 /*
-/*     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.
-/*
 /*     Arguments:
 /* .IP ok
 /*     Result of prior verification: non-zero means success.  In
 /* .IP TLScontext
 /*     Server or client context for warning messages.
 /* DIAGNOSTICS
-/*     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.
+/*     tls_peer_CN() and tls_issuer_CN() 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
@@ -152,7 +142,6 @@ int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
     X509   *cert;
     int     err;
     int     depth;
-    int     max_depth;
     SSL    *con;
     TLS_SESS_STATE *TLScontext;
 
@@ -163,35 +152,23 @@ int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
     TLScontext = SSL_get_ex_data(con, TLScontext_index);
     depth = X509_STORE_CTX_get_error_depth(ctx);
 
-    /* Don't log the internal root CA unless there's an unexpected error. */
-    if (ok && TLScontext->tadepth > 0 && depth > TLScontext->tadepth)
-       return (1);
-
     /*
-     * Certificate chain depth limit violations are mis-reported by the
-     * OpenSSL library, from SSL_CTX_set_verify(3):
+     * Transient failures to load the (DNS or synthetic TLSA) trust settings
+     * must poison certificate verification, since otherwise the default
+     * trust store may bless a certificate that would have failed
+     * verification with the preferred trust anchors (or fingerprints).
      * 
-     * 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.
-     */
-    max_depth = SSL_get_verify_depth(con) - 1;
-
-    /*
-     * 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.
+     * Since we unconditionally continue, or in any case if verification is
+     * about to succeed, there is eventually a final depth 0 callback, at
+     * which point we force an "unspecified" error.  The failure to load the
+     * trust settings was logged earlier.
      */
-    if (max_depth >= 0 && depth > max_depth) {
-       X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_CERT_CHAIN_TOO_LONG);
-       ok = 0;
+    if (TLScontext->must_fail) {
+       if (depth == 0) {
+           X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_UNSPECIFIED);
+           update_error_state(TLScontext, depth, cert, err);
+       }
+       return (1);
     }
     if (ok == 0)
        update_error_state(TLScontext, depth, cert, err);
@@ -410,77 +387,18 @@ static char *tls_text_name(X509_NAME *name, int nid, const char *label,
     TLS_TEXT_NAME_RETURN(mystrdup((char *) utf8_value));
 }
 
-/* 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;
-    int     len;
-
-    /*
-     * Peername checks are security sensitive, carefully scrutinize the
-     * input!
-     */
-    if (gn->type != GEN_DNS)
-       msg_panic("%s: Non DNS input argument", myname);
-
-    /*
-     * We expect the OpenSSL library to construct GEN_DNS extension objects as
-     * ASN1_IA5STRING values. Check we got the right union member.
-     */
-    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);
-    }
-
-    /*
-     * Safe to treat as an ASCII string possibly holding a DNS name
-     */
-    dnsname = (const char *) ASN1_STRING_get0_data(gn->d.ia5);
-    len = ASN1_STRING_length(gn->d.ia5);
-    TRIM0(dnsname, len);
-
-    /*
-     * 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 (len != 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...
-     */
-    if (*dnsname && !allprint(dnsname)) {
-       cp = mystrdup(dnsname);
-       msg_warn("%s: %s: non-printable characters in subjectAltName: %.100s",
-                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, const TLS_SESS_STATE *TLScontext)
 {
     char   *cn;
+    const char *san;
 
+    /* Absent a commonName, return a validated DNS-ID SAN */
     cn = tls_text_name(X509_get_subject_name(peercert), NID_commonName,
                       "subject CN", TLScontext, DONT_GRIPE);
+    if (cn == 0 && (san = SSL_get0_peername(TLScontext->con)) != 0)
+       cn = mystrdup(san);
     return (cn ? cn : mystrdup(""));
 }
 
index 7aad011be7478225e55f21b7769a29df46c18eb7..b11ce92c3fd9ba3975527face2816d428db93bf6 100644 (file)
@@ -996,13 +996,7 @@ static int tlsp_client_start_pre_handshake(TLSP_STATE *state)
 {
     state->client_start_props->ctx = state->appl_state;
     state->client_start_props->fd = state->ciphertext_fd;
-    /* These predicates and warning belong inside tls_client_start(). */
-    if (!tls_dane_avail()                      /* mandatory side effects!! */
-       &&TLS_DANE_BASED(state->client_start_props->tls_level))
-       msg_warn("%s: DANE requested, but not available",
-                state->client_start_props->namaddr);
-    else
-       state->tls_context = tls_client_start(state->client_start_props);
+    state->tls_context = tls_client_start(state->client_start_props);
     if (state->tls_context != 0)
        return (TLSP_STAT_OK);
 
@@ -1194,8 +1188,7 @@ static void tlsp_log_config_diff(const char *server_cfg, const char *client_cfg)
 /* tlsp_client_init - initialize a TLS client engine */
 
 static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params,
-                                         TLS_CLIENT_INIT_PROPS *init_props,
-                                               int dane_based)
+                                         TLS_CLIENT_INIT_PROPS *init_props)
 {
     TLS_APPL_STATE *appl_state;
     VSTRING *param_buf;
@@ -1228,8 +1221,8 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params,
     init_key = tls_proxy_client_init_with_names_to_string(
                                                      init_buf, init_props);
     init_buf_for_hashing = vstring_alloc(100);
-    init_key_for_hashing = STR(vstring_sprintf(init_buf_for_hashing, "%s%d\n",
-                                              init_key, dane_based));
+    init_key_for_hashing = STR(vstring_sprintf(init_buf_for_hashing, "%s\n",
+                                              init_key));
     if (tlsp_pre_jail_done == 0) {
        if (tlsp_pre_jail_client_param_key == 0
            || tlsp_pre_jail_client_init_key == 0) {
@@ -1426,8 +1419,7 @@ static void tlsp_get_request_event(int event, void *context)
            return;
        }
        state->appl_state = tlsp_client_init(state->tls_params,
-                                            state->client_init_props,
-                     TLS_DANE_BASED(state->client_start_props->tls_level));
+                                            state->client_init_props);
        ready = state->appl_state != 0;
        break;
     case TLS_PROXY_FLAG_ROLE_SERVER:
@@ -1714,7 +1706,6 @@ static void pre_jail_init_client(void)
     if (clnt_use_tls || var_tlsp_clnt_per_site[0] || var_tlsp_clnt_policy[0]) {
        TLS_CLIENT_PARAMS tls_params;
        TLS_CLIENT_INIT_PROPS init_props;
-       int     dane_based_mode;
 
        tls_pre_jail_init(TLS_ROLE_CLIENT);
 
@@ -1741,11 +1732,8 @@ static void pre_jail_init_client(void)
                                    CAfile = var_tlsp_clnt_CAfile,
                                    CApath = var_tlsp_clnt_CApath,
                                    mdalg = var_tlsp_clnt_fpt_dgst);
-       for (dane_based_mode = 0; dane_based_mode < 2; dane_based_mode++) {
-           if (tlsp_client_init(&tls_params, &init_props,
-                                dane_based_mode) == 0)
-               msg_warn("TLS client initialization failed");
-       }
+       if (tlsp_client_init(&tls_params, &init_props) == 0)
+           msg_warn("TLS client initialization failed");
     }
 }
 
index 5cba861515f950855117788db6ab29db335330fb..1381bcba18654a799685d9b05e0706e4481c119d 100644 (file)
@@ -257,7 +257,7 @@ typedef struct DICT_UTF8_BACKUP {
     const char *(*lookup) (struct DICT *, const char *);
     int     (*update) (struct DICT *, const char *, const char *);
     int     (*delete) (struct DICT *, const char *);
-}       DICT_UTF8_BACKUP;
+} DICT_UTF8_BACKUP;
 
 extern DICT *dict_utf8_activate(DICT *);
 
index 9e890353a3aaa6d94d89416a59f6491eba8bfa4c..3dfcb9818c2cb481a5e72fe40e0eb7d42b246a0f 100644 (file)
 /*     VSTRING *result;
 /*     const char *in;
 /*     ssize_t len;
+/*
+/*     VSTRING *hex_encode_opt(result, in, len, flags)
+/*     VSTRING *result;
+/*     const char *in;
+/*     ssize_t len;
+/*     int     flags;
+/*
+/*     VSTRING *hex_decode_opt(result, in, len, flags)
+/*     VSTRING *result;
+/*     const char *in;
+/*     ssize_t len;
+/*     int     flags;
 /* DESCRIPTION
 /*     hex_encode() takes a block of len bytes and encodes it as one
 /*     upper-case null-terminated string.  The result value is
 /*     lower-case, upper-case or mixed-case input. The result
 /*     value is the result argument. The result is null terminated,
 /*     whether or not that makes sense.
+/*
+/*     hex_encode_opt() enables extended functionality as controlled
+/*     with \fIflags\fR.
+/* .IP HEX_ENCODE_FLAG_NONE
+/*     The default: a self-documenting flag that enables no
+/*     functionality.
+/* .IP HEX_ENCODE_FLAG_USE_COLON
+/*     Inserts one ":" between bytes.
+/* .PP
+/*     hex_decode_opt() enables extended functionality as controlled
+/*     with \fIflags\fR.
+/* .IP HEX_DECODE_FLAG_NONE
+/*     The default: a self-documenting flag that enables no
+/*     functionality.
+/* .IP HEX_DECODE_FLAG_ALLOW_COLON
+/*     Allows, but does not require, one ":" between bytes.
 /* DIAGNOSTICS
 /*     hex_decode() returns a null pointer when the input contains
 /*     characters not in the hexadecimal alphabet.
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
@@ -57,9 +90,18 @@ static const unsigned char hex_chars[] = "0123456789ABCDEF";
 
 #define UCHAR_PTR(x) ((const unsigned char *)(x))
 
-/* hex_encode - raw data to encoded */
+/* hex_encode - ABI compatibility */
+
+#undef hex_encode
 
 VSTRING *hex_encode(VSTRING *result, const char *in, ssize_t len)
+{
+    return (hex_encode_opt(result, in, len, HEX_ENCODE_FLAG_NONE));
+}
+
+/* hex_encode_opt - raw data to encoded */
+
+VSTRING *hex_encode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
 {
     const unsigned char *cp;
     int     ch;
@@ -70,14 +112,25 @@ VSTRING *hex_encode(VSTRING *result, const char *in, ssize_t len)
        ch = *cp;
        VSTRING_ADDCH(result, hex_chars[(ch >> 4) & 0xf]);
        VSTRING_ADDCH(result, hex_chars[ch & 0xf]);
+       if ((flags & HEX_ENCODE_FLAG_USE_COLON) && count > 1)
+           VSTRING_ADDCH(result, ':');
     }
     VSTRING_TERMINATE(result);
     return (result);
 }
 
-/* hex_decode - encoded data to raw */
+/* hex_decode - ABI compatibility wrapper */
+
+#undef hex_decode
 
 VSTRING *hex_decode(VSTRING *result, const char *in, ssize_t len)
+{
+    return (hex_decode_opt(result, in, len, HEX_DECODE_FLAG_NONE));
+}
+
+/* hex_decode_opt - encoded data to raw */
+
+VSTRING *hex_decode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
 {
     const unsigned char *cp;
     ssize_t count;
@@ -107,12 +160,24 @@ VSTRING *hex_decode(VSTRING *result, const char *in, ssize_t len)
        else
            return (0);
        VSTRING_ADDCH(result, bin);
+
+       /*
+        * Support *colon-separated* input (no leading or trailing colons).
+        * After decoding "xx", skip a possible ':' preceding "yy" in
+        * "xx:yy".
+        */
+       if ((flags & HEX_DECODE_FLAG_ALLOW_COLON)
+           && count > 4 && cp[2] == ':') {
+           ++cp;
+           --count;
+       }
     }
     VSTRING_TERMINATE(result);
     return (result);
 }
 
 #ifdef TEST
+#include <argv.h>
 
  /*
   * Proof-of-concept test program: convert to hexadecimal and back.
@@ -126,6 +191,7 @@ int     main(int unused_argc, char **unused_argv)
     VSTRING *b1 = vstring_alloc(1);
     VSTRING *b2 = vstring_alloc(1);
     char   *test = "this is a test";
+    ARGV   *argv;
 
 #define DECODE(b,x,l) { \
        if (hex_decode((b),(x),(l)) == 0) \
@@ -160,6 +226,15 @@ int     main(int unused_argc, char **unused_argv)
     DECODE(b2, STR(b1), LEN(b1));
     VERIFY(STR(b2), test);
 
+    hex_encode_opt(b1, test, strlen(test), HEX_ENCODE_FLAG_USE_COLON);
+    argv = argv_split(STR(b1), ":");
+    if (argv->argc != strlen(test))
+       msg_panic("HEX_ENCODE_FLAG_USE_COLON");
+    if (hex_decode_opt(b2, STR(b1), LEN(b1), HEX_DECODE_FLAG_ALLOW_COLON) == 0)
+       msg_panic("HEX_DECODE_FLAG_ALLOW_COLON");
+    VERIFY(STR(b2), test);
+    argv_free(argv);
+
     vstring_free(b1);
     vstring_free(b2);
     return (0);
index 0936cdcb939b09e80e080d59ffc666378aadfbce..720977adb5895ad5f4141221028fe40de245ae3d 100644 (file)
  /*
   * External interface.
   */
+#define HEX_ENCODE_FLAG_NONE           (0)
+#define HEX_ENCODE_FLAG_USE_COLON      (1<<0)
+
+#define HEX_DECODE_FLAG_NONE   (0)
+#define HEX_DECODE_FLAG_ALLOW_COLON    (1<<0)
+
 extern VSTRING *hex_encode(VSTRING *, const char *, ssize_t);
 extern VSTRING *WARN_UNUSED_RESULT hex_decode(VSTRING *, const char *, ssize_t);
+extern VSTRING *hex_encode_opt(VSTRING *, const char *, ssize_t, int);
+extern VSTRING *WARN_UNUSED_RESULT hex_decode_opt(VSTRING *, const char *, ssize_t, int);
+
+#define hex_encode(res, in, len) \
+       hex_encode_opt((res), (in), (len), HEX_ENCODE_FLAG_NONE)
+#define hex_decode(res, in, len) \
+       hex_decode_opt((res), (in), (len), HEX_DECODE_FLAG_NONE)
 
 /* LICENSE
 /* .ad
index b5ec37d06d6a4eb8d1337dacfe453659dc25bd46..94f7bb3e7aa733e31e0290e67022740ca46222bd 100644 (file)
@@ -23,8 +23,8 @@
 /*     const char *str;
 /*     ssize_t len;
 /*
-/*     char    *mymemdup(ptr, len)
-/*     const char *ptr;
+/*     void    *mymemdup(ptr, len)
+/*     const void *ptr;
 /*     ssize_t len;
 /* DESCRIPTION
 /*     This module performs low-level memory management with error
@@ -261,7 +261,7 @@ char   *mystrndup(const char *str, ssize_t len)
 
 /* mymemdup - copy memory */
 
-char   *mymemdup(const void *ptr, ssize_t len)
+void   *mymemdup(const void *ptr, ssize_t len)
 {
     if (ptr == 0)
        msg_panic("mymemdup: null pointer argument");
index f245795cdb5c5770a60b99f4c2110294fea042c6..e2190f78620e65aa5f55a0fc42bfa73bbfa74907 100644 (file)
@@ -19,7 +19,7 @@ extern void *myrealloc(void *, ssize_t);
 extern void myfree(void *);
 extern char *mystrdup(const char *);
 extern char *mystrndup(const char *, ssize_t);
-extern char *mymemdup(const void *, ssize_t);
+extern void *mymemdup(const void *, ssize_t);
 
 /* LICENSE
 /* .ad