]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.11-20131117
authorWietse Venema <wietse@porcupine.org>
Sun, 17 Nov 2013 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 18 Nov 2013 01:10:48 +0000 (20:10 -0500)
20 files changed:
postfix/HISTORY
postfix/WISHLIST
postfix/html/mysql_table.5.html
postfix/html/pcre_table.5.html
postfix/html/postconf.5.html
postfix/html/regexp_table.5.html
postfix/html/smtp-sink.1.html
postfix/man/man5/mysql_table.5
postfix/man/man5/postconf.5
postfix/mantools/man2html
postfix/mantools/postlink
postfix/proto/mysql_table
postfix/proto/postconf.proto
postfix/src/global/dict_mysql.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/posttls-finger/posttls-finger.c
postfix/src/tls/tls_dane.c
postfix/src/tls/tls_misc.c
postfix/src/util/dict_test.c

index cb6cd436a8f8116b9d9a46db50d2d96bff19968f..65846c70b2024c7744c35c8177c73c7039c4c631 100644 (file)
@@ -19111,3 +19111,36 @@ Apologies for any names omitted.
        cleanup/cleanup_map11.c, cleanup/cleanup_map1n.c,
        cleanup/cleanup_masquerade.c, cleanup/cleanup_message.c,
        cleanup/cleanup_milter.c.
+
+20131116
+
+       Feature: MySQL client support for option_file, option_group,
+       tls_cert_file, tls_key_file, tls_CAfile, tls_CApath,
+       tls_verify_cert. See mysql_table(5).  Code by Gareth Palmer.
+       Files: proto/mysql_table, global/dict_mysql.c.
+
+       Cleanup: DANE support. Keep the attributes of TA certificates
+       obtained via "IN TLSA 2 0 X" RRs, while continuing to only
+       use the key from "IN TLSA 2 1 X" RRs.  This means in the
+       "2 0 X" case that we re-sign the TA certificate in place,
+       rather than synthesize a vanilla cert around just the key.
+       Viktor Dukhovni. File: tls/tls_dane.c.
+
+       Bugfix: posttls-finger parsing of destination and optional
+       match values. Viktor Dukhovni.  File:
+       posttls-finger/posttls-finger.c.
+
+       Cleanup: When wrap_signed is false (OpenSSL 1.0.2 some day),
+       we don't have to sign trust anchors, and don't generate a
+       key to do so.  Thus don't attempt to re-sign trust-anchor
+       certificates (IN TLSA 2 0 X) in this case. Viktor Dukhovni.
+       File: tls/tls_dane.c.
+
+       Feature: configurable DANE digest algorithm priority. Use
+       only the most-preferred, shared, digest algorithm for any
+       give (usage, selector) combination. Viktor Dukhovni.
+       mantools/postlink, proto/postconf.proto, global/mail_params.h,
+       tls/tls_dane.c, tls/tls_misc.c.
+
+       Bugfix: FreeBSD nroff workaround messed up. File:
+       mantools/postlink.
index aa77857b81091dd66eaae8b8f934b3991dfcc0c4..92f2cb53f323ede25112d51d77c9a52313f7be6d 100644 (file)
@@ -4,6 +4,9 @@ Wish list:
 
        Make been_here flag BH_FLAG_FOLD configurable for masochists.
 
+       Allow LMDB-based caches to be shared. This requires a new
+       flag that says a database is concurrency-safe.
+
        Preserve case in smtpd_resolve_addr() and add a structure
        member for the case-folded address.
 
index 52d4c46da0f9e683bec9dc2e6725d4f64282a223..c40b1723c1d5cbcd21ab52386ac13cb5231cfb16 100644 (file)
@@ -256,15 +256,63 @@ MYSQL_TABLE(5)                                                  MYSQL_TABLE(5)
               limit is exceeded.  Setting the limit to 1  ensures
               that lookups do not return multiple values.
 
+       <b>option_file</b>
+              Read  options  from  the  given file instead of the
+              default my.cnf location.
+
+              This parameter is available with Postfix  2.11  and
+              later.
+
+       <b>option_group</b>
+              Read options from the given group.
+
+              This  parameter  is available with Postfix 2.11 and
+              later.
+
+       <b>tls_cert_file</b>
+              File containing client's X509 certificate.
+
+              This parameter is available with Postfix  2.11  and
+              later.
+
+       <b>tls_key_file</b>
+              File  containing  the  private key corresponding to
+              <b>tls_cert_file</b>.
+
+              This parameter is available with Postfix  2.11  and
+              later.
+
+       <b>tls_CAfile</b>
+              File  containing  certificates  for all of the X509
+              Certificate Authorities the client will  recognize.
+              Takes precedence over <b>tls_CApath</b>.
+
+              This  parameter  is available with Postfix 2.11 and
+              later.
+
+       <b>tls_CApath</b>
+              Directory  containing  X509  Certificate  Authority
+              certificates in separate individual files.
+
+              This  parameter  is available with Postfix 2.11 and
+              later.
+
+       <b>tls_verify_cert (default: no)</b>
+              Verify that the server's name  matches  the  common
+              name in the certficate.
+
+              This  parameter  is available with Postfix 2.11 and
+              later.
+
 <b>OBSOLETE QUERY INTERFACE</b>
-       This  section describes an interface that is deprecated as
-       of Postfix 2.2. It is replaced by the more  general  <b>query</b>
-       interface  described  above.   If  the  <b>query</b> parameter is
-       defined, the legacy  parameters  described  here  ignored.
-       Please  migrate  to the new interface as the legacy inter-
+       This section describes an interface that is deprecated  as
+       of  Postfix  2.2. It is replaced by the more general <b>query</b>
+       interface described above.   If  the  <b>query</b>  parameter  is
+       defined,  the  legacy  parameters  described here ignored.
+       Please migrate to the new interface as the  legacy  inter-
        face may be removed in a future release.
 
-       The following parameters can be used to fill in  a  SELECT
+       The  following  parameters can be used to fill in a SELECT
        template statement of the form:
 
            SELECT [<b>select_field</b>]
@@ -272,7 +320,7 @@ MYSQL_TABLE(5)                                                  MYSQL_TABLE(5)
            WHERE [<b>where_field</b>] = '%s'
                  [<b>additional_conditions</b>]
 
-       The  specifier %s is replaced by the search string, and is
+       The specifier %s is replaced by the search string, and  is
        escaped so if it contains single quotes or other odd char-
        acters, it will not cause a parse error, or worse, a secu-
        rity problem.
@@ -304,7 +352,7 @@ MYSQL_TABLE(5)                                                  MYSQL_TABLE(5)
        <a href="MYSQL_README.html">MYSQL_README</a>, Postfix MYSQL client guide
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>HISTORY</b>
index eac6faa92a97b14928c74812cdcb34295904b219..7a51ce1fa5e5d001c3e48e1088c98c39de62d7dc 100644 (file)
@@ -10,9 +10,9 @@ PCRE_TABLE(5)                                                    PCRE_TABLE(5)
        pcre_table - format of Postfix PCRE tables
 
 <b>SYNOPSIS</b>
-       <b>postmap -q "<i></b>string</i><b>" <a href="pcre_table.5.html">pcre</a>:/etc/postfix/<i></b>filename\e[0m
+       <b>postmap -q "</b><i>string</i><b>" <a href="pcre_table.5.html">pcre</a>:/etc/postfix/</b><i>filename</i>
 
-       <b>postmap -q - <a href="pcre_table.5.html">pcre</a>:/etc/postfix/<i></b>filename</i> &lt;<i>inputfile</i>
+       <b>postmap -q - <a href="pcre_table.5.html">pcre</a>:/etc/postfix/</b><i>filename</i> &lt;<i>inputfile</i>
 
 <b>DESCRIPTION</b>
        The  Postfix  mail system uses optional tables for address
@@ -39,15 +39,15 @@ PCRE_TABLE(5)                                                    PCRE_TABLE(5)
 <b>TABLE FORMAT</b>
        The general form of a PCRE table is:
 
-       <b>/<i></b>pattern</i><b>/<i></b>flags result</i>
+       <b>/</b><i>pattern</i><b>/</b><i>flags result</i>
               When <i>pattern</i> matches the input string, use the cor-
               responding <i>result</i> value.
 
-       <b>!/<i></b>pattern</i><b>/<i></b>flags result</i>
+       <b>!/</b><i>pattern</i><b>/</b><i>flags result</i>
               When <i>pattern</i> does <b>not</b> match the input  string,  use
               the corresponding <i>result</i> value.
 
-       <b>if /<i></b>pattern</i><b>/<i></b>flags\e[0m
+       <b>if /</b><i>pattern</i><b>/</b><i>flags</i>
 
        <b>endif</b>  Match the input string against the patterns between
               <b>if</b> and <b>endif</b>, if and only if that same input string
@@ -58,7 +58,7 @@ PCRE_TABLE(5)                                                    PCRE_TABLE(5)
 
               This feature is available in Postfix 2.1 and later.
 
-       <b>if !/<i></b>pattern</i><b>/<i></b>flags\e[0m
+       <b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
 
        <b>endif</b>  Match the input string against the patterns between
               <b>if</b> and <b>endif</b>, if and only if that same input string
@@ -115,7 +115,7 @@ PCRE_TABLE(5)                                                    PCRE_TABLE(5)
               a whitespace character  as  part  of  the  pattern,
               escape it with backslash.
 
-              Note: do not use <b>#<i></b>comment</i> after patterns.
+              Note: do not use <b>#</b><i>comment</i> after patterns.
 
        <b>A</b> (default: off)
               Toggles  the PCRE_ANCHORED flag.  When this flag is
index 28a3b3e6dd0e5cf1de9c282173d9024bcfedb80d..c1523c001538b62e46e1febde2e62d0eeae747c5 100644 (file)
@@ -11311,7 +11311,7 @@ to Postfix 2.9.6 or later. </p>
 <p> Lookup the associated DANE TLSA RRset even when a hostname is
 not an alias and its address records lie in an unsigned zone.  This
 is unlikely to ever yield DNSSEC validated results, since child
-zones of unsigned zones are also unsigned in the absense of DLV or
+zones of unsigned zones are also unsigned in the absence of DLV or
 locally configured non-root trust-anchors.  We anticipate that such
 mechanisms will not be used for just the "_tcp" subdomain of a host.
 Suppressing the TLSA RRset lookup reduces latency and avoids potential
@@ -16211,6 +16211,55 @@ bytes (equivalent to 256 bits) is sufficient to generate a 128bit
 <p> This feature is available in Postfix 2.2 and later.  </p>
 
 
+</DD>
+
+<DT><b><a name="tls_dane_digests">tls_dane_digests</a>
+(default: sha512 sha256)</b></DT><DD>
+
+<p> <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> TLSA resource-record "matching type" digest algorithms
+in descending preference order.  All the specified algorithms must
+be supported by the underlying OpenSSL library, otherwise the Postfix
+SMTP client will not support DANE TLSA security. </p>
+
+<p> When for a particular combination of "certificate usage" and
+"selector" the TLSA RRset contains a well-formed record with a
+matching type of "0", i.e. a full value of the associated certificate
+or public key, the Postfix SMTP client will ignore all other matching
+types for the same certificate usage and selector.  In this case
+the first algorithm listed in <a href="postconf.5.html#tls_dane_digests">tls_dane_digests</a> will be used to
+compute a digest of the full value, which will then be used to match
+certificates or public keys in the server's certificate chain. </p>
+
+<p> Otherwise, when for a particular combination of "certificate
+usage" and "selector" the TLSA RRset contains a records with more
+than one non-zero matching type, i.e. multiple digest algorithms,
+only records with the highest preference digest are used after
+discarding any records with an incorrect digest length as unusable. </p>
+
+<p> This strategy ensures that the strongest digest supported by
+both the Postfix SMTP client and the remote server is used, and
+weaker digests are ignored.  This supports non-disruptive deprecation
+of outdated digest algorithms. </p>
+
+<p> The strategy requires that when a TLSA RRset provides association
+data for multiple certificates or public keys, all RRs with the same
+"certificate usage" and "selector" be published with the same set
+of digests.  In particular, during key rotation, when a certificate
+or public key is being replaced with another (and both are published
+during the transition) both the old and the new certificate MUST be
+specified with the same set of digests.  One can change the list of
+digest algorithms later, once old keys are retired.  At any given
+time change either the list of digests without changing the list of
+certificates or public keys or the list of certificates or public
+keys without changing the list of digests. </p>
+
+<p> It is expected that this algorithm agility mechanism will be
+published in a standards track RFC for SMTP with DANE, and perhaps
+in an eventual update to <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>. </p>
+
+<p> This feature is available in Postfix 2.11. </p>
+
+
 </DD>
 
 <DT><b><a name="tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a>
index 8a2bb3b20a45712c2e614fd7d1c17f5389b26bef..8a5b9f9d9e4116725245913614a2ac30626d2dc9 100644 (file)
@@ -10,9 +10,9 @@ REGEXP_TABLE(5)                                                REGEXP_TABLE(5)
        regexp_table - format of Postfix regular expression tables
 
 <b>SYNOPSIS</b>
-       <b>postmap -q "<i></b>string</i><b>" <a href="regexp_table.5.html">regexp</a>:/etc/postfix/<i></b>filename\e[0m
+       <b>postmap -q "</b><i>string</i><b>" <a href="regexp_table.5.html">regexp</a>:/etc/postfix/</b><i>filename</i>
 
-       <b>postmap -q - <a href="regexp_table.5.html">regexp</a>:/etc/postfix/<i></b>filename</i> &lt;<i>inputfile</i>
+       <b>postmap -q - <a href="regexp_table.5.html">regexp</a>:/etc/postfix/</b><i>filename</i> &lt;<i>inputfile</i>
 
 <b>DESCRIPTION</b>
        The Postfix mail system uses optional tables  for  address
@@ -39,15 +39,15 @@ REGEXP_TABLE(5)                                                REGEXP_TABLE(5)
 <b>TABLE FORMAT</b>
        The general form of a Postfix regular expression table is:
 
-       <b>/<i></b>pattern</i><b>/<i></b>flags result</i>
+       <b>/</b><i>pattern</i><b>/</b><i>flags result</i>
               When <i>pattern</i> matches the input string, use the cor-
               responding <i>result</i> value.
 
-       <b>!/<i></b>pattern</i><b>/<i></b>flags result</i>
+       <b>!/</b><i>pattern</i><b>/</b><i>flags result</i>
               When <i>pattern</i> does <b>not</b> match the input  string,  use
               the corresponding <i>result</i> value.
 
-       <b>if /<i></b>pattern</i><b>/<i></b>flags\e[0m
+       <b>if /</b><i>pattern</i><b>/</b><i>flags</i>
 
        <b>endif</b>  Match the input string against the patterns between
               <b>if</b> and <b>endif</b>, if and only if that same input string
@@ -58,7 +58,7 @@ REGEXP_TABLE(5)                                                REGEXP_TABLE(5)
 
               This feature is available in Postfix 2.1 and later.
 
-       <b>if !/<i></b>pattern</i><b>/<i></b>flags\e[0m
+       <b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
 
        <b>endif</b>  Match the input string against the patterns between
               <b>if</b> and <b>endif</b>, if and only if that same input string
index 96f49a0e347c048d69cb7886d5e8c865107d39d1..18768e9455b4436b042ad85f2ab312e38a6070b8 100644 (file)
@@ -12,7 +12,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
 <b>SYNOPSIS</b>
        <b>smtp-sink</b> [<i>options</i>] [<b>inet:</b>][<i>host</i>]:<i>port backlog</i>
 
-       <b>smtp-sink</b> [<i>options</i>] <b>unix:<i></b>pathname backlog</i>
+       <b>smtp-sink</b> [<i>options</i>] <b>unix:</b><i>pathname backlog</i>
 
 <b>DESCRIPTION</b>
        <b>smtp-sink</b> listens on the named host (or address) and port.
@@ -47,19 +47,19 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
 
        <b>-a</b>     Do not announce SASL authentication support.
 
-       <b>-A <i></b>delay\e[0m
+       <b>-A</b> <i>delay</i>
               Wait  <i>delay</i>  seconds after responding to DATA, then
               abort prematurely with a 550 reply status.  Do  not
               read  further  input  from  the  client; this is an
               attempt to block the client before  it  sends  ".".
               Specify a zero delay value to abort immediately.
 
-       <b>-b <i></b>soft-bounce-reply\e[0m
+       <b>-b</b> <i>soft-bounce-reply</i>
               Use  <i>soft-bounce-reply</i>  for  soft reject responses.
               The default reply  is  "450  4.3.0  Error:  command
               failed".
 
-       <b>-B <i></b>hard-bounce-reply\e[0m
+       <b>-B</b> <i>hard-bounce-reply</i>
               Use  <i>hard-bounce-reply</i>  for  hard reject responses.
               The default reply  is  "500  5.3.0  Error:  command
               failed".
@@ -70,7 +70,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
 
        <b>-C</b>     Disable XCLIENT support.
 
-       <b>-d <i></b>dump-template\e[0m
+       <b>-d</b> <i>dump-template</i>
               Dump each mail transaction to a single-message file
               whose name is created by  expanding  the  <i>dump-tem-</i>
               <i>plate</i> via strftime(3) and appending a pseudo-random
@@ -83,7 +83,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               Note: this option keeps one capture file  open  for
               every mail transaction in progress.
 
-       <b>-D <i></b>dump-template\e[0m
+       <b>-D</b> <i>dump-template</i>
               Append  mail  transactions  to a multi-message dump
               file whose name is created by expanding  the  <i>dump-</i>
               <i>template</i> via strftime(3).  If the template contains
@@ -98,7 +98,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
 
        <b>-E</b>     Do not announce ENHANCEDSTATUSCODES support.
 
-       <b>-f <i></b>command,command,...\e[0m
+       <b>-f</b> <i>command,command,...</i>
               Reject  the  specified  commands  with a hard (5xx)
               error code.  This option implies <b>-p</b>.
 
@@ -110,24 +110,24 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
 
        <b>-F</b>     Disable XFORWARD support.
 
-       <b>-h <i></b>hostname\e[0m
+       <b>-h</b> <i>hostname</i>
               Use <i>hostname</i> in the  SMTP  greeting,  in  the  HELO
               response,  and  in  the  EHLO response. The default
               hostname is "smtp-sink".
 
        <b>-L</b>     Enable LMTP instead of SMTP.
 
-       <b>-m <i></b>count</i> (default: 256)
+       <b>-m</b> <i>count</i> (default: 256)
               An upper bound on the maximal number of  simultane-
               ous  connections  that  <b>smtp-sink</b> will handle. This
               prevents the  process  from  running  out  of  file
               descriptors. Excess connections will stay queued in
               the TCP/IP stack.
 
-       <b>-M <i></b>count\e[0m
+       <b>-M</b> <i>count</i>
               Terminate after receiving <i>count</i> messages.
 
-       <b>-n <i></b>count\e[0m
+       <b>-n</b> <i>count</i>
               Terminate after <i>count</i> sessions.
 
        <b>-p</b>     Do not announce support for ESMTP command  pipelin-
@@ -136,7 +136,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
        <b>-P</b>     Change  the  server  greeting so that it appears to
               come through a CISCO PIX system. Implies <b>-e</b>.
 
-       <b>-q <i></b>command,command,...\e[0m
+       <b>-q</b> <i>command,command,...</i>
               Disconnect (without replying) after  receiving  one
               of the specified commands.
 
@@ -146,7 +146,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               and use quotes to  protect  white  space  from  the
               shell. Command names are case-insensitive.
 
-       <b>-Q <i></b>command,command,...\e[0m
+       <b>-Q</b> <i>command,command,...</i>
               Send a 421 reply and disconnect after receiving one
               of the specified commands.
 
@@ -156,7 +156,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               and  use  quotes  to  protect  white space from the
               shell. Command names are case-insensitive.
 
-       <b>-r <i></b>command,command,...\e[0m
+       <b>-r</b> <i>command,command,...</i>
               Reject the specified commands  with  a  soft  (4xx)
               error code.  This option implies <b>-p</b>.
 
@@ -166,12 +166,12 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               and use quotes to  protect  white  space  from  the
               shell. Command names are case-insensitive.
 
-       <b>-R <i></b>root-directory\e[0m
+       <b>-R</b> <i>root-directory</i>
               Change  the process root directory to the specified
               location.  This option requires  super-user  privi-
               leges. See also the <b>-u</b> option.
 
-       <b>-s <i></b>command,command,...\e[0m
+       <b>-s</b> <i>command,command,...</i>
               Log the named commands to syslogd.
 
               Examples of commands are CONNECT, HELO, EHLO, LHLO,
@@ -190,16 +190,16 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               tab),  \<i>ddd</i>  (up to three octal digits) and \\ (the
               backslash character).
 
-       <b>-t <i></b>timeout</i> (default: 100)
+       <b>-t</b> <i>timeout</i> (default: 100)
               Limit the time for receiving a command or sending a
               response.   The time limit is specified in seconds.
 
-       <b>-T <i></b>windowsize\e[0m
+       <b>-T</b> <i>windowsize</i>
               Override the  default  TCP  window  size.  To  work
               around  broken  TCP window scaling implementations,
               specify a value &gt; 0 and &lt; 65536.
 
-       <b>-u <i></b>username\e[0m
+       <b>-u</b> <i>username</i>
               Switch to the specified user privileges after open-
               ing  the network socket and optionally changing the
               process root directory.  This  option  is  required
@@ -208,11 +208,11 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
 
        <b>-v</b>     Show the SMTP conversations.
 
-       <b>-w <i></b>delay\e[0m
+       <b>-w</b> <i>delay</i>
               Wait <i>delay</i> seconds before responding to a DATA com-
               mand.
 
-       <b>-W <i></b>command:delay[:odds]\e[0m
+       <b>-W</b> <i>command:delay[:odds]</i>
               Wait  <i>delay</i>  seconds  before responding to <i>command</i>.
               If <i>odds</i> is also specified (a  number  between  1-99
               inclusive),  wait  for  a random multiple of <i>delay</i>.
@@ -226,7 +226,7 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               interface) TCP port <i>port</i>. Both <i>host</i> and <i>port</i> may be
               specified in numeric or symbolic form.
 
-       <b>unix:<i></b>pathname\e[0m
+       <b>unix:</b><i>pathname</i>
               Listen on the UNIX-domain socket at <i>pathname</i>.
 
        <i>backlog</i>
@@ -251,45 +251,45 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
        The format of the <b>smtp-sink</b> generated headers is  as  fol-
        lows:
 
-       <b>X-Client-Addr: <i></b>text\e[0m
+       <b>X-Client-Addr:</b> <i>text</i>
               The client IP address without enclosing []. An IPv6
               address is prefixed with "ipv6:".  This  record  is
               always present.
 
-       <b>X-Client-Proto: <i></b>text\e[0m
+       <b>X-Client-Proto:</b> <i>text</i>
               The  client  protocol:  SMTP,  ESMTP  or LMTP. This
               record is always present.
 
-       <b>X-Helo-Args: <i></b>text\e[0m
+       <b>X-Helo-Args:</b> <i>text</i>
               The arguments of the  last  HELO  or  EHLO  command
               before  this mail delivery transaction. This record
               is present only if the client sent  a  recognizable
               HELO or EHLO command before the DATA command.
 
-       <b>X-Mail-Args: <i></b>text\e[0m
+       <b>X-Mail-Args:</b> <i>text</i>
               The arguments of the MAIL command that started this
               mail delivery transaction. This record  is  present
               exactly once.
 
-       <b>X-Rcpt-Args: <i></b>text\e[0m
+       <b>X-Rcpt-Args:</b> <i>text</i>
               The  arguments  of an RCPT command within this mail
               delivery transaction. There is one record for  each
               RCPT  command, and they are in the order as sent by
               the client.
 
-       <b>Received: <i></b>text\e[0m
+       <b>Received:</b> <i>text</i>
               A message header for compatibility with  mail  pro-
               cessing  software. This three-line header marks the
               end of the headers provided by  <b>smtp-sink</b>,  and  is
               formatted as follows:
 
-              <b>from <i></b>helo</i> <b>([<i></b>addr</i><b>])</b>
+              <b>from</b> <i>helo</i> <b>([</b><i>addr</i><b>])</b>
                      The HELO or EHLO command argument and client
                      IP address.  If the client did not send HELO
                      or  EHLO,  the  client  IP  address  is used
                      instead.
 
-              <b>by <i></b>host</i> <b>(smtp-sink) with <i></b>proto</i> <b>id <i></b>random</i><b>;</b>
+              <b>by</b> <i>host</i> <b>(smtp-sink) with</b> <i>proto</i> <b>id</b> <i>random</i><b>;</b>
                      The hostname specified with the  <b>-h</b>  option,
                      the   client  protocol  (see  <b>X-Client-Proto</b>
                      above), and the pseudo-random portion of the
index d79aa2330bc1db598b5686e572ce746349e2e18d..dd3ec9b4c107a5de52292dfcc97ac004e257dfb4 100644 (file)
@@ -256,6 +256,39 @@ A setting of zero disables the limit. Lookups fail with a
 temporary error if the limit is exceeded.  Setting the
 limit to 1 ensures that lookups do not return multiple
 values.
+.IP "\fBoption_file\fR"
+Read options from the given file instead of the default my.cnf
+location.
+.sp
+This parameter is available with Postfix 2.11 and later.
+.IP "\fBoption_group\fR"
+Read options from the given group.
+.sp
+This parameter is available with Postfix 2.11 and later.
+.IP "\fBtls_cert_file\fR"
+File containing client's X509 certificate.
+.sp
+This parameter is available with Postfix 2.11 and later.
+.IP "\fBtls_key_file\fR"
+File containing the private key corresponding to \fBtls_cert_file\fR.
+.sp
+This parameter is available with Postfix 2.11 and later.
+.IP "\fBtls_CAfile\fR"
+File containing certificates for all of the X509 Certificate
+Authorities the client will recognize.  Takes precedence over
+\fBtls_CApath\fR.
+.sp
+This parameter is available with Postfix 2.11 and later.
+.IP "\fBtls_CApath\fR"
+Directory containing X509 Certificate Authority certificates
+in separate individual files.
+.sp
+This parameter is available with Postfix 2.11 and later.
+.IP "\fBtls_verify_cert (default: no)\fR"
+Verify that the server's name matches the common name in the
+certficate.
+.sp
+This parameter is available with Postfix 2.11 and later.
 .SH "OBSOLETE QUERY INTERFACE"
 .na
 .nf
index 58b9886bcf0f3d642bc21dfe36ca83c420774d66..4f9068d199e7cf7f9d0033dd69cd18a6f8e2ad05 100644 (file)
@@ -4173,7 +4173,7 @@ Example:
 .ft C
 /etc/postfix/main.cf:
     postscreen_access_list = permit_mynetworks,
-               cidr:/etc/postfix/postscreen_access.cidr
+                cidr:/etc/postfix/postscreen_access.cidr
     postscreen_blacklist_action = enforce
 .fi
 .ad
@@ -4393,7 +4393,7 @@ Example:
 .na
 .ft C
 /etc/postfix/dnsbl_reply:
-   secret.zen.spamhaus.org     zen.spamhaus.org
+   secret.zen.spamhaus.org      zen.spamhaus.org
 .fi
 .ad
 .ft R
@@ -6962,7 +6962,7 @@ As in the example above, we show two matching fingerprints:
 .na
 .ft C
 /etc/postfix/tls_policy:
-    example.com        fingerprint
+    example.com fingerprint
         match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
         match=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
 .fi
@@ -7079,7 +7079,7 @@ This feature is available in Postfix 2.5 and later.
 Lookup the associated DANE TLSA RRset even when a hostname is
 not an alias and its address records lie in an unsigned zone.  This
 is unlikely to ever yield DNSSEC validated results, since child
-zones of unsigned zones are also unsigned in the absense of DLV or
+zones of unsigned zones are also unsigned in the absence of DLV or
 locally configured non-root trust-anchors.  We anticipate that such
 mechanisms will not be used for just the "_tcp" subdomain of a host.
 Suppressing the TLSA RRset lookup reduces latency and avoids potential
@@ -7506,8 +7506,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=EC:3B:2D:B0:5B:B1:FB:6D:20:A3:9D:72:F6:8D:12:35
+        match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
 .fi
 .ad
 .ft R
@@ -11006,6 +11006,49 @@ bytes (equivalent to 256 bits) is sufficient to generate a 128bit
 (or 168bit) session key.
 .PP
 This feature is available in Postfix 2.2 and later.
+.SH tls_dane_digests (default: sha512 sha256)
+RFC 6698 TLSA resource-record "matching type" digest algorithms
+in descending preference order.  All the specified algorithms must
+be supported by the underlying OpenSSL library, otherwise the Postfix
+SMTP client will not support DANE TLSA security.
+.PP
+When for a particular combination of "certificate usage" and
+"selector" the TLSA RRset contains a well-formed record with a
+matching type of "0", i.e. a full value of the associated certificate
+or public key, the Postfix SMTP client will ignore all other matching
+types for the same certificate usage and selector.  In this case
+the first algorithm listed in tls_dane_digests will be used to
+compute a digest of the full value, which will then be used to match
+certificates or public keys in the server's certificate chain.
+.PP
+Otherwise, when for a particular combination of "certificate
+usage" and "selector" the TLSA RRset contains a records with more
+than one non-zero matching type, i.e. multiple digest algorithms,
+only records with the highest preference digest are used after
+discarding any records with an incorrect digest length as unusable.
+.PP
+This strategy ensures that the strongest digest supported by
+both the Postfix SMTP client and the remote server is used, and
+weaker digests are ignored.  This supports non-disruptive deprecation
+of outdated digest algorithms.
+.PP
+The strategy requires that when a TLSA RRset provides association
+data for multiple certificates or public keys, all RRs with the same
+"certificate usage" and "selector" be published with the same set
+of digests.  In particular, during key rotation, when a certificate
+or public key is being replaced with another (and both are published
+during the transition) both the old and the new certificate MUST be
+specified with the same set of digests.  One can change the list of
+digest algorithms later, once old keys are retired.  At any given
+time change either the list of digests without changing the list of
+certificates or public keys or the list of certificates or public
+keys without changing the list of digests.
+.PP
+It is expected that this algorithm agility mechanism will be
+published in a standards track RFC for SMTP with DANE, and perhaps
+in an eventual update to RFC 6698.
+.PP
+This feature is available in Postfix 2.11.
 .SH tls_dane_trust_anchor_digest_enable (default: trust-anchor-assertion)
 RFC 6698 trust-anchor digest support in the Postfix TLS library.
 Specify zero or more of the following options, separated by comma or
index 2b8e3bc4920a90fb530feee469d0733d58866c2d..f9896f07b94df6f1b6fb9200707dafcf85fd4848 100755 (executable)
@@ -47,7 +47,7 @@ sed '
        s;'$ESC'\[4m;<i>;g
        s;'$ESC'\[24m;</i>;g
        # Undo gratuitous whitespace changes.
-       s;\(  *\)\(</[bi]>\);\2\1;g
+       #s;\(  *\)\(</[bi]>\);\2\1;g
        # End nroff ANSI escape sequence workarounds.
        s;</i>\( *\)<i>;\1;g
        s;</b>\( *\)<b>;\1;g
index 233a9828fd4cf1ad4f9bed074cdd0e2f760e11ad..e827d314bceab1293e0f11d4334e96773b25df26 100755 (executable)
@@ -716,6 +716,7 @@ while (<>) {
     s;\btls_append_default_CA\b;<a href="postconf.5.html#tls_append_default_CA">$&</a>;g;
     s;\btls_legacy_public_key_fingerprints\b;<a href="postconf.5.html#tls_legacy_public_key_fingerprint">$&</a>;g;
     s;\btls_dane_trust_anchor_digest_enable\b;<a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">$&</a>;g;
+    s;\btls_dane_digests\b;<a href="postconf.5.html#tls_dane_digests">$&</a>;g;
     s;\btls_wildcard_matches_multiple_labels\b;<a href="postconf.5.html#tls_wildcard_matches_multiple_labels">$&</a>;g;
  
     s;\bfrozen_delivered_to\b;<a href="postconf.5.html#frozen_delivered_to">$&</a>;g;
index 4e84316f67383415b6cfbd461e2a29d8868f1f2c..d422e7d4632466f3cb22936827226948ec0955db 100644 (file)
 #      temporary error if the limit is exceeded.  Setting the
 #      limit to 1 ensures that lookups do not return multiple
 #      values.
+# .IP "\fBoption_file\fR"
+#      Read options from the given file instead of the default my.cnf
+#      location.
+# .sp
+#      This parameter is available with Postfix 2.11 and later.
+# .IP "\fBoption_group\fR"
+#      Read options from the given group.
+# .sp
+#      This parameter is available with Postfix 2.11 and later.
+# .IP "\fBtls_cert_file\fR"
+#      File containing client's X509 certificate.
+# .sp
+#      This parameter is available with Postfix 2.11 and later.
+# .IP "\fBtls_key_file\fR"
+#      File containing the private key corresponding to \fBtls_cert_file\fR.
+# .sp
+#      This parameter is available with Postfix 2.11 and later.
+# .IP "\fBtls_CAfile\fR"
+#      File containing certificates for all of the X509 Certificate
+#      Authorities the client will recognize.  Takes precedence over
+#      \fBtls_CApath\fR.
+# .sp
+#      This parameter is available with Postfix 2.11 and later.
+# .IP "\fBtls_CApath\fR"
+#      Directory containing X509 Certificate Authority certificates
+#      in separate individual files.
+# .sp
+#      This parameter is available with Postfix 2.11 and later.
+# .IP "\fBtls_verify_cert (default: no)\fR"
+#      Verify that the server's name matches the common name in the
+#      certficate.
+# .sp
+#      This parameter is available with Postfix 2.11 and later.
 # OBSOLETE QUERY INTERFACE
 # .ad
 # .fi
index 1a72ee4e55ec42c05bf2b704574fb122595a56e7..89be6ccbf3260ae72bd696b36d2ac08fc5dc44c3 100644 (file)
@@ -15438,7 +15438,7 @@ configuration parameter.  See there for details. </p>
 <p> Lookup the associated DANE TLSA RRset even when a hostname is
 not an alias and its address records lie in an unsigned zone.  This
 is unlikely to ever yield DNSSEC validated results, since child
-zones of unsigned zones are also unsigned in the absense of DLV or
+zones of unsigned zones are also unsigned in the absence of DLV or
 locally configured non-root trust-anchors.  We anticipate that such
 mechanisms will not be used for just the "_tcp" subdomain of a host.
 Suppressing the TLSA RRset lookup reduces latency and avoids potential
@@ -15446,3 +15446,48 @@ interoperability problems with nameservers for unsigned zones that
 are not prepared to handle the new TLSA RRset.  </p>
 
 <p> This feature is available in Postfix 2.11. </p>
+
+%PARAM tls_dane_digests sha512 sha256
+
+<p> RFC 6698 TLSA resource-record "matching type" digest algorithms
+in descending preference order.  All the specified algorithms must
+be supported by the underlying OpenSSL library, otherwise the Postfix
+SMTP client will not support DANE TLSA security. </p>
+
+<p> When for a particular combination of "certificate usage" and
+"selector" the TLSA RRset contains a well-formed record with a
+matching type of "0", i.e. a full value of the associated certificate
+or public key, the Postfix SMTP client will ignore all other matching
+types for the same certificate usage and selector.  In this case
+the first algorithm listed in tls_dane_digests will be used to
+compute a digest of the full value, which will then be used to match
+certificates or public keys in the server's certificate chain. </p>
+
+<p> Otherwise, when for a particular combination of "certificate
+usage" and "selector" the TLSA RRset contains a records with more
+than one non-zero matching type, i.e. multiple digest algorithms,
+only records with the highest preference digest are used after
+discarding any records with an incorrect digest length as unusable. </p>
+
+<p> This strategy ensures that the strongest digest supported by
+both the Postfix SMTP client and the remote server is used, and
+weaker digests are ignored.  This supports non-disruptive deprecation
+of outdated digest algorithms. </p>
+
+<p> The strategy requires that when a TLSA RRset provides association
+data for multiple certificates or public keys, all RRs with the same
+"certificate usage" and "selector" be published with the same set
+of digests.  In particular, during key rotation, when a certificate
+or public key is being replaced with another (and both are published
+during the transition) both the old and the new certificate MUST be
+specified with the same set of digests.  One can change the list of
+digest algorithms later, once old keys are retired.  At any given
+time change either the list of digests without changing the list of
+certificates or public keys or the list of certificates or public
+keys without changing the list of digests. </p>
+
+<p> It is expected that this algorithm agility mechanism will be
+published in a standards track RFC for SMTP with DANE, and perhaps
+in an eventual update to RFC 6698. </p>
+
+<p> This feature is available in Postfix 2.11. </p>
index a3e231a4ed204b569fb1b48953bd960944095edb..e899a148934c9ce4ed00f1253152f1407d57b0ca 100644 (file)
 /*     releases.
 /* .IP hosts
 /*     List of hosts to connect to.
+/* .IP option_file
+/*      Read options from the given file instead of the default my.cnf
+/*      location.
+/* .IP option_group
+/*      Read options from the given group.
+/* .IP tls_cert_file
+/*      File containing client's X509 certificate.
+/* .IP tls_key_file
+/*      File containing the private key corresponding to \fItls_cert_file\fR.
+/* .IP tls_CAfile
+/*      File containing certificates for all of the X509 Certificate
+/*      Authorities the client will recognize.  Takes precedence over
+/*      \fItls_CApath\fR.
+/* .IP tls_CApath
+/*      Directory containing X509 Certificate Authority certificates
+/*      in separate individual files.
+/* .IP tls_verify_cert
+/*      Verify that the server's name matches the common name of the
+/*      certficate.
 /* .PP
 /*     For example, if you want the map to reference databases of
 /*     the name "your_db" and execute a query like this: select
@@ -217,6 +236,8 @@ typedef struct {
     CFG_PARSER *parser;
     char   *query;
     char   *result_format;
+    char   *option_file;
+    char   *option_group;
     void   *ctx;
     int     expansion_limit;
     char   *username;
@@ -226,6 +247,14 @@ typedef struct {
     PLMYSQL *pldb;
 #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
     HOST   *active_host;
+    char   *tls_cert_file;
+    char   *tls_key_file;
+    char   *tls_CAfile;
+    char   *tls_CApath;
+    char   *tls_ciphers;
+#if MYSQL_VERSION_ID >= 50023
+    int     tls_verify_cert;
+#endif
 #endif
 } DICT_MYSQL;
 
@@ -242,12 +271,11 @@ typedef struct {
 
 /* internal function declarations */
 static PLMYSQL *plmysql_init(ARGV *);
-static MYSQL_RES *plmysql_query(DICT_MYSQL *, const char *, VSTRING *, char *,
-                                       char *, char *);
+static MYSQL_RES *plmysql_query(DICT_MYSQL *, const char *, VSTRING *);
 static void plmysql_dealloc(PLMYSQL *);
 static void plmysql_close_host(HOST *);
 static void plmysql_down_host(HOST *);
-static void plmysql_connect_single(HOST *, char *, char *, char *);
+static void plmysql_connect_single(DICT_MYSQL *, HOST *);
 static const char *dict_mysql_lookup(DICT *, const char *);
 DICT   *dict_mysql_open(const char *, int, int);
 static void dict_mysql_close(DICT *);
@@ -349,10 +377,7 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
        return (0);
 
     /* do the query - set dict->error & cleanup if there's an error */
-    if ((query_res = plmysql_query(dict_mysql, name, query,
-                                  dict_mysql->dbname,
-                                  dict_mysql->username,
-                                  dict_mysql->password)) == 0) {
+    if ((query_res = plmysql_query(dict_mysql, name, query)) == 0) {
        dict->error = DICT_ERR_RETRY;
        return (0);
     }
@@ -428,10 +453,10 @@ static HOST *dict_mysql_find_host(PLMYSQL *PLDB, unsigned stat, unsigned type)
 
 /* dict_mysql_get_active - get an active connection */
 
-static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname,
-                                          char *username, char *password)
+static HOST *dict_mysql_get_active(DICT_MYSQL *dict_mysql)
 {
     const char *myname = "dict_mysql_get_active";
+    PLMYSQL *PLDB = dict_mysql->pldb;
     HOST   *host;
     int     count = RETRY_CONN_MAX;
 
@@ -457,7 +482,7 @@ static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname,
        if (msg_verbose)
            msg_info("%s: attempting to connect to host %s", myname,
                     host->hostname);
-       plmysql_connect_single(host, dbname, username, password);
+       plmysql_connect_single(dict_mysql, host);
        if (host->stat == STATACTIVE)
            return host;
     }
@@ -485,17 +510,12 @@ static void dict_mysql_event(int unused_event, char *context)
 
 static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
                                        const char *name,
-                                       VSTRING *query,
-                                       char *dbname,
-                                       char *username,
-                                       char *password)
+                                       VSTRING *query)
 {
-    PLMYSQL *PLDB = dict_mysql->pldb;
     HOST   *host;
     MYSQL_RES *res = 0;
 
-    while ((host = dict_mysql_get_active(PLDB, dbname, username, password)) != NULL) {
-
+    while ((host = dict_mysql_get_active(dict_mysql)) != NULL) {
 #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
 
        /*
@@ -534,15 +554,32 @@ static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
  * used to reconnect to a single database when one is down or none is
  * connected yet. Log all errors and set the stat field of host accordingly
  */
-static void plmysql_connect_single(HOST *host, char *dbname, char *username, char *password)
+static void plmysql_connect_single(DICT_MYSQL *dict_mysql, HOST *host)
 {
     if ((host->db = mysql_init(NULL)) == NULL)
        msg_fatal("dict_mysql: insufficient memory");
+    if (dict_mysql->option_file)
+       mysql_options(host->db, MYSQL_READ_DEFAULT_FILE, dict_mysql->option_file);
+    if (dict_mysql->option_group)
+       mysql_options(host->db, MYSQL_READ_DEFAULT_GROUP, dict_mysql->option_group);
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
+    if (dict_mysql->tls_key_file || dict_mysql->tls_cert_file ||
+       dict_mysql->tls_CAfile || dict_mysql->tls_CApath || dict_mysql->tls_ciphers)
+       mysql_ssl_set(host->db,
+                     dict_mysql->tls_key_file, dict_mysql->tls_cert_file,
+                     dict_mysql->tls_CAfile, dict_mysql->tls_CApath,
+                     dict_mysql->tls_ciphers);
+#if MYSQL_VERSION_ID >= 50023
+    if (dict_mysql->tls_verify_cert != -1)
+       mysql_options(host->db, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+                     &dict_mysql->tls_verify_cert);
+#endif
+#endif
     if (mysql_real_connect(host->db,
                           (host->type == TYPEINET ? host->name : 0),
-                          username,
-                          password,
-                          dbname,
+                          dict_mysql->username,
+                          dict_mysql->password,
+                          dict_mysql->dbname,
                           host->port,
                           (host->type == TYPEUNIX ? host->name : 0),
                           0)) {
@@ -582,7 +619,7 @@ static void plmysql_down_host(HOST *host)
 
 static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
 {
-    const char *myname = "mysqlname_parse";
+    const char *myname = "mysql_parse_config";
     CFG_PARSER *p = dict_mysql->parser;
     VSTRING *buf;
     char   *hosts;
@@ -591,6 +628,18 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
     dict_mysql->password = cfg_get_str(p, "password", "", 0, 0);
     dict_mysql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
     dict_mysql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0);
+    dict_mysql->option_file = cfg_get_str(p, "option_file", NULL, 0, 0);
+    dict_mysql->option_group = cfg_get_str(p, "option_group", NULL, 0, 0);
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
+    dict_mysql->tls_key_file = cfg_get_str(p, "tls_key_file", NULL, 0, 0);
+    dict_mysql->tls_cert_file = cfg_get_str(p, "tls_cert_file", NULL, 0, 0);
+    dict_mysql->tls_CAfile = cfg_get_str(p, "tls_CAfile", NULL, 0, 0);
+    dict_mysql->tls_CApath = cfg_get_str(p, "tls_CApath", NULL, 0, 0);
+    dict_mysql->tls_ciphers = cfg_get_str(p, "tls_ciphers", NULL, 0, 0);
+#if MYSQL_VERSION_ID >= 50023
+    dict_mysql->tls_verify_cert = cfg_get_bool(p, "tls_verify_cert", -1);
+#endif
+#endif
 
     /*
      * XXX: The default should be non-zero for safety, but that is not
@@ -759,6 +808,22 @@ static void dict_mysql_close(DICT *dict)
     myfree(dict_mysql->dbname);
     myfree(dict_mysql->query);
     myfree(dict_mysql->result_format);
+    if (dict_mysql->option_file)
+       myfree(dict_mysql->option_file);
+    if (dict_mysql->option_group)
+       myfree(dict_mysql->option_group);
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
+    if (dict_mysql->tls_key_file)
+       myfree(dict_mysql->tls_key_file);
+    if (dict_mysql->tls_cert_file)
+       myfree(dict_mysql->tls_cert_file);
+    if (dict_mysql->tls_CAfile)
+       myfree(dict_mysql->tls_CAfile);
+    if (dict_mysql->tls_CApath)
+       myfree(dict_mysql->tls_CApath);
+    if (dict_mysql->tls_ciphers)
+       myfree(dict_mysql->tls_ciphers);
+#endif
     if (dict_mysql->hosts)
        argv_free(dict_mysql->hosts);
     if (dict_mysql->ctx)
index 063977b4fe56d05232b2286c0ec947365d073586..d181947a0422633060375445ce728d344cebcd78 100644 (file)
@@ -3103,6 +3103,13 @@ extern char *var_tls_ssl_options;
 #define DEF_TLS_BC_PKEY_FPRINT 0
 extern bool var_tls_bc_pkey_fprint;
 
+ /*
+  * Ordered list of DANE digest algorithms.
+  */
+#define VAR_TLS_DANE_DIGESTS   "tls_dane_digests"
+#define DEF_TLS_DANE_DIGESTS   "sha512 sha256"
+extern char *var_tls_dane_digests;
+
  /*
   * External interface for enabling trust-anchor digests, which are risky
   * when the corresponding certificate is missing from the peer chain (this
index 13cd38b5d21e6c81fe7bc41c68286b53f8f46377..65a35257964c983dfdba66c9241ecb234e362cb9 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20131114"
+#define MAIL_RELEASE_DATE      "20131117"
 #define MAIL_VERSION_NUMBER    "2.11"
 
 #ifdef SNAPSHOT
index 407dfb3dbc0b054ef3e233a11421c88b763de0e6..2971c30b31cde2aa5225595c880489e075c577b5 100644 (file)
@@ -1745,11 +1745,8 @@ static void parse_match(STATE *state, int argc, char *argv[])
 {
 #ifdef USE_TLS
 
-    argc -= optind;
-    argv += optind;
-
     switch (state->level) {
-    case TLS_LEV_SECURE:
+       case TLS_LEV_SECURE:
        state->match = argv_alloc(2);
        while (*argv)
            argv_split_append(state->match, *argv++, "");
@@ -1826,14 +1823,17 @@ int     main(int argc, char *argv[])
     mail_conf_suck();
     parse_options(&state, argc, argv);
     mail_params_init();
-
-    parse_match(&state, argc, argv);
     parse_tas(&state);
 
+    argc -= optind;
+    argv += optind;
+
     /* The first non-option argument is the destination. */
-    if (argc < optind)
+    if (!argc)
        usage();
-    state.dest = mystrdup(argv[optind]);
+
+    state.dest = mystrdup(argv[0]);
+    parse_match(&state, --argc, ++argv);
 
     /* Don't talk to remote systems as root */
     if (!geteuid())
index 8e499832b41b2e86c2192d993e7db409c5f85a91..6e6e1fb9c002677d6c5b54402dd0df6ab0e7f4c3 100644 (file)
@@ -235,17 +235,29 @@ static int wrap_signed = 0;
 
 #endif
 static const EVP_MD *signmd;
+static const char *signalg;
 
 static EVP_PKEY *danekey;
 static ASN1_OBJECT *serverAuth;
 
-static const char *sha256 = "sha256";
-static const EVP_MD *sha256md;
-static int sha256len;
-
-static const char *sha512 = "sha512";
-static const EVP_MD *sha512md;
-static int sha512len;
+/*
+ * https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml
+ */
+typedef struct digest_info {
+    const char *alg;                   /* 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 */
+}       digest_info;
+
+#define MAXDIGESTS 256                 /* RFC limit */
+digest_info digest_table[] = {
+    {"full", 0, 0, 0, DNS_TLSA_MATCHING_TYPE_NO_HASH_USED},
+    {"sha256", 0, 0, -1, DNS_TLSA_MATCHING_TYPE_SHA256},
+    {"sha512", 0, 0, -1, DNS_TLSA_MATCHING_TYPE_SHA512},
+    {0, 0, 0, 0, 0}
+};
 
 static int digest_mask;
 
@@ -271,6 +283,46 @@ void    tls_dane_verbose(int on)
     dane_verbose = on;
 }
 
+/* digest_info_cmp - qsort() comparator for digest_table */
+
+static int digest_info_cmp(const void *a, const void *b)
+{
+    register const digest_info *ai = (const digest_info *) a;
+    register const digest_info *bi = (const digest_info *) b;
+
+    /*
+     * Negative preferences sort last.  Otherwise, sort in ascending order.
+     */
+    if (ai->pref == bi->pref)
+       return (0);
+    if (ai->pref < 0 || bi->pref < 0)
+       return bi->pref - ai->pref;
+    return ai->pref - bi->pref;
+}
+
+/* dane_digest_info - locate digest_table entry for given IANA id */
+
+static digest_info *dane_digest_info(uint8_t dane_id)
+{
+    digest_info *di;
+
+    for (di = digest_table; di->alg; ++di)
+       if (di->dane_id == dane_id)
+           return (di);
+    return (0);
+}
+
+/* dane_digest_pref - digest preference by IANA id */
+
+static int dane_digest_pref(uint8_t dane_id)
+{
+    digest_info *di = dane_digest_info(dane_id);
+
+    if (di && di->pref >= 0)
+       return (di->pref);
+    return (MAXDIGESTS + dane_id);
+}
+
 /* gencakey - generate interal DANE root CA key */
 
 static EVP_PKEY *gencakey(void)
@@ -278,8 +330,6 @@ static EVP_PKEY *gencakey(void)
     EVP_PKEY *key = 0;
 
 #ifdef WRAP_SIGNED
-    int     len;
-    unsigned char *p;
     EC_KEY *eckey;
     EC_GROUP *group;
 
@@ -312,16 +362,44 @@ static void dane_init(void)
        TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
        0,
     };
+    int     digest_pref = 0;
+    char   *cp;
+    char   *save;
+    char   *tok;
+    digest_info *di;
 
     digest_mask =
        name_mask_opt(VAR_TLS_DANE_TA_DGST, ta_dgsts, var_tls_dane_ta_dgst,
                      NAME_MASK_ANY_CASE | NAME_MASK_FATAL);
 
-    if ((sha256md = EVP_get_digestbyname(sha256)) != 0)
-       sha256len = EVP_MD_size(sha256md);
-    if ((sha512md = EVP_get_digestbyname(sha512)) != 0)
-       sha512len = EVP_MD_size(sha512md);
-    signmd = sha256md ? sha256md : EVP_sha1();
+    save = cp = mystrdup(var_tls_dane_digests);
+    while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
+       for (di = digest_table; di->alg; ++di)
+           if (strcasecmp(tok, di->alg) == 0)
+               break;
+       if (di->alg != 0
+           && (di->md = EVP_get_digestbyname(di->alg)) != 0
+           && (di->len = EVP_MD_size(di->md)) > 0
+           && di->len <= EVP_MAX_MD_SIZE) {
+
+           /*
+            * The most preferred digest will be used for cert signing and
+            * digesting for comparison.
+            */
+           if ((di->pref = ++digest_pref) == 1) {
+               signalg = di->alg;
+               signmd = di->md;
+           }
+       } else {
+           msg_warn("Unsupported DANE digest algorithm: %s", tok);
+           continue;
+       }
+    }
+    myfree(save);
+
+    if (digest_pref > 0)
+       qsort(digest_table, digest_pref, sizeof(digest_table[0]),
+             digest_info_cmp);
 
     /* Don't report old news */
     ERR_clear_error();
@@ -344,7 +422,7 @@ int     tls_dane_avail(void)
        dane_init();
 
 #ifdef DANE_TLSA_SUPPORT
-    return (sha256md && sha512md && serverAuth);
+    return (signalg && serverAuth);
 #else
     return (0);
 #endif
@@ -574,9 +652,27 @@ static void dane_add(TLS_DANE *dane, int certusage, int selector,
 
 static int tlsa_rr_cmp(DNS_RR *a, DNS_RR *b)
 {
-    if (a->data_len == b->data_len)
-       return (memcmp(a->data, b->data, a->data_len));
-    return ((a->data_len > b->data_len) ? 1 : -1);
+    int     cmp;
+
+    /*
+     * 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;
+
+#define signedcmp(x, y) (((int)(y)) - ((int)(x)))
+
+       if ((cmp = signedcmp(ai[0], bi[0])) != 0
+           || (cmp = signedcmp(ai[1], bi[1])) != 0
+         || (cmp = dane_digest_pref(ai[2]) - dane_digest_pref(bi[2])) != 0)
+           return (cmp);
+    }
+    if ((cmp = a->data_len - b->data_len) != 0)
+       return (cmp);
+    return (memcmp(a->data, b->data, a->data_len));
 }
 
 /* parse_tlsa_rrs - parse a validated TLSA RRset */
@@ -588,18 +684,24 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
     uint8_t mtype;
     int     mlen;
     const unsigned char *p;
+    uint32_t prev_usage_selector;      /* Previous (usage<<8|selector) */
+    uint32_t prev_mtype;               /* Previous valid mtype for above */
+
+#define NO_PREV 0xffffffff                     /* Not any usage|selector or
+                                                * mtype */
+    prev_usage_selector = NO_PREV;
 
     if (rr == 0)
        msg_panic("null TLSA rr");
 
     for ( /* nop */ ; rr; rr = rr->next) {
        const char *mdalg = 0;
-       int     mdlen;
        char   *digest;
        int     same = (strcasecmp(rr->rname, rr->qname) == 0);
        uint8_t *ip = (uint8_t *) rr->data;
        X509   *x = 0;                  /* OpenSSL tries to re-use *x if x!=0 */
        EVP_PKEY *k = 0;                /* OpenSSL tries to re-use *k if k!=0 */
+       digest_info *di;
 
 #define rcname(rr) (same ? "" : rr->qname)
 #define rarrow(rr) (same ? "" : " -> ")
@@ -638,26 +740,34 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
            break;
        }
 
-       switch (mtype = *ip++) {
-       default:
-           msg_warn("unsupported matching type %u in RR: "
-                    "%s%s%s IN TLSA %u %u %u ...", mtype, rcname(rr),
-                    rarrow(rr), rr->rname, usage, selector, mtype);
+       /*
+        * Skip all but the most preferred matching type for any given
+        * (usage, selector) combination.
+        */
+       mtype = *ip++;
+       if (prev_usage_selector != (usage << 8 | selector))
+           prev_mtype = NO_PREV;
+       else if (prev_mtype != NO_PREV && prev_mtype != mtype)
            continue;
-       case DNS_TLSA_MATCHING_TYPE_SHA256:
-           if (!mdalg) {
-               mdalg = sha256;
-               mdlen = sha256len;
+
+       switch (mtype) {
+       default:
+           if ((di = dane_digest_info(mtype)) == 0) {
+               msg_warn("unsupported matching type %u in RR: "
+                        "%s%s%s IN TLSA %u %u %u ...", mtype, rcname(rr),
+                        rarrow(rr), rr->rname, usage, selector, mtype);
+               continue;
            }
-           /* FALLTHROUGH */
-       case DNS_TLSA_MATCHING_TYPE_SHA512:
-           if (!mdalg) {
-               mdalg = sha512;
-               mdlen = sha512len;
+           if (di->pref < 0) {
+               msg_warn("digest algorithm %s locally disabled, in RR: "
+                        "%s%s%s IN TLSA %u %u %u ...", di->alg,
+                        rcname(rr), rarrow(rr), rr->rname,
+                        usage, selector, mtype);
+               continue;
            }
-           if (mlen != mdlen) {
+           if (mlen != di->len) {
                msg_warn("malformed %s digest, length %u, in RR: "
-                        "%s%s%s IN TLSA %u %u %u ...", mdalg, mlen,
+                        "%s%s%s IN TLSA %u %u %u ...", di->alg, mlen,
                         rcname(rr), rarrow(rr), rr->rname,
                         usage, selector, mtype);
                continue;
@@ -667,7 +777,7 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
                if (!(digest_mask & TLS_DANE_ENABLE_CC)) {
                    msg_warn("%s trust-anchor %s digests disabled, in RR: "
                             "%s%s%s IN TLSA %u %u %u ...", TLS_DANE_CC,
-                            mdalg, rcname(rr), rarrow(rr), rr->rname,
+                            di->alg, rcname(rr), rarrow(rr), rr->rname,
                             usage, selector, mtype);
                    continue;
                }
@@ -676,14 +786,14 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
                if (!(digest_mask & TLS_DANE_ENABLE_TAA)) {
                    msg_warn("%s trust-anchor %s digests disabled, in RR: "
                             "%s%s%s IN TLSA %u %u %u ...", TLS_DANE_TAA,
-                            mdalg, rcname(rr), rarrow(rr), rr->rname,
+                            di->alg, rcname(rr), rarrow(rr), rr->rname,
                             usage, selector, mtype);
                    continue;
                }
                break;
            }
-           dane_add(dane, usage, selector, mdalg,
-                  digest = tls_digest_encode((unsigned char *) ip, mdlen));
+           digest = tls_digest_encode((unsigned char *) ip, di->len);
+           dane_add(dane, usage, selector, di->alg, digest);
            break;
 
        case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
@@ -726,6 +836,7 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
                }
                X509_free(x);
                break;
+
            case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
                if (!d2i_PUBKEY(&k, &p, mlen)) {
                    msg_warn("malformed %s in RR: "
@@ -747,12 +858,19 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
 
            /*
             * The cert or key was valid, just digest the raw object, and
-            * encode the digest value.  We choose SHA256.
+            * encode the digest value.
             */
-           dane_add(dane, usage, selector, mdalg = sha256,
-                    digest = tls_data_fprint((char *) ip, mlen, sha256));
+           digest = tls_data_fprint((char *) ip, mlen, signalg);
+           dane_add(dane, usage, selector, mdalg = signalg, digest);
            break;
        }
+
+       /*
+        * Save state
+        */
+       prev_usage_selector = (usage << 8 | selector);
+       prev_mtype = mtype;
+
        if (msg_verbose || dane_verbose) {
            switch (mtype) {
            default:
@@ -803,7 +921,13 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
        dane->expires = 1 + event_time() + rrs->ttl;
 
        if (rrs->dnssec_valid) {
-           /* Sort for deterministic digest in session cache lookup key */
+
+           /*
+            * 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);
            parse_tlsa_rrs(dane, rrs);
        } else
@@ -905,7 +1029,7 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
        msg_warn("trust-anchor files not supported");
        return (0);
     }
-    mdalg = sha256md ? sha256 : "sha1";
+    mdalg = signalg ? signalg : "sha1";
 
     /*
      * On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio,
@@ -1001,12 +1125,20 @@ int     tls_dane_match(TLS_SESS_STATE *TLScontext, int usage,
        char  **dgst;
        ARGV   *certs;
 
+       /*
+        * 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 = 1;
+                   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",
@@ -1034,7 +1166,7 @@ int     tls_dane_match(TLS_SESS_STATE *TLScontext, int usage,
 
            for (dgst = certs->argv; !matched && *dgst; ++dgst)
                if (strcasecmp(cert_dgst, *dgst) == 0)
-                   matched = 1;
+                   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",
@@ -1139,15 +1271,10 @@ static int add_skid(X509 *cert, AUTHORITY_KEYID *akid)
     return (ret);
 }
 
-/* set_issuer - set issuer DN to match akid if specified */
+/* akid_issuer_name - get akid issuer directory name */
 
-static int set_issuer_name(X509 *cert, AUTHORITY_KEYID *akid)
+static X509_NAME *akid_issuer_name(AUTHORITY_KEYID *akid)
 {
-
-    /*
-     * If subject's akid specifies an authority key identifer issuer name, we
-     * must use that.
-     */
     if (akid && akid->issuer) {
        int     i;
        general_name_stack_t *gens = akid->issuer;
@@ -1156,9 +1283,24 @@ static int set_issuer_name(X509 *cert, AUTHORITY_KEYID *akid)
            GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
 
            if (gn->type == GEN_DIRNAME)
-               return (X509_set_issuer_name(cert, gn->d.dirn));
+               return (gn->d.dirn);
        }
     }
+    return (0);
+}
+
+/* set_issuer - set issuer DN to match akid if specified */
+
+static int set_issuer_name(X509 *cert, AUTHORITY_KEYID *akid)
+{
+    X509_NAME *name = akid_issuer_name(akid);
+
+    /*
+     * If subject's akid specifies an authority key identifer issuer name, we
+     * must use that.
+     */
+    if (name)
+       return (X509_set_issuer_name(cert, name));
     return (X509_set_issuer_name(cert, X509_get_subject_name(cert)));
 }
 
@@ -1179,23 +1321,26 @@ static void grow_chain(x509_stack_t **skptr, X509 *cert, ASN1_OBJECT *trust)
 
 /* wrap_key - wrap TA "key" as issuer of "subject" */
 
-static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
-                           int depth)
+static int wrap_key(TLS_SESS_STATE *TLScontext, int depth,
+                           EVP_PKEY *key, X509 *subject)
 {
     int     ret = 1;
+    int     selfsigned = 0;
     X509   *cert = 0;
     AUTHORITY_KEYID *akid;
     X509_NAME *name = X509_get_issuer_name(subject);
+    X509_NAME *akid_name;
 
     /*
      * Record the depth of the intermediate wrapper certificate, logged in
-     * the verify callback, unlike the parent root CA.
+     * the verify callback.
      */
-    if (!key)
-       TLScontext->tadepth = depth;
-    else if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
-       msg_info("%s: depth=%d chain is trust-anchor signed",
-                TLScontext->namaddr, depth);
+    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);
+    }
 
     /*
      * If key is NULL generate a self-signed root CA, with key "danekey",
@@ -1205,6 +1350,9 @@ static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
        return (0);
 
     akid = X509_get_ext_d2i(subject, NID_authority_key_identifier, 0, 0);
+    if ((akid_name = akid_issuer_name(akid)) == 0
+       || X509_NAME_cmp(name, akid_name) == 0)
+       selfsigned = 1;
 
     ERR_clear_error();
 
@@ -1217,11 +1365,12 @@ static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
        || !X509_gmtime_adj(X509_get_notAfter(cert), 30 * 86400L)
        || !X509_set_pubkey(cert, key ? key : danekey)
        || !add_ext(0, cert, NID_basic_constraints, "CA:TRUE")
-       || (key && !add_akid(cert, akid))
+       || (key && !selfsigned && !add_akid(cert, akid))
        || !add_skid(cert, akid)
        || (wrap_signed
            && (!X509_sign(cert, danekey, signmd)
-               || (key && !wrap_key(TLScontext, 0, cert, depth + 1))))) {
+               || (key && !selfsigned
+                   && !wrap_key(TLScontext, depth + 1, 0, cert))))) {
        msg_warn("error generating DANE wrapper certificate");
        tls_print_errors();
        ret = 0;
@@ -1229,7 +1378,7 @@ static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
     if (akid)
        AUTHORITY_KEYID_free(akid);
     if (ret) {
-       if (key && wrap_signed)
+       if (key && !selfsigned && wrap_signed)
            grow_chain(&TLScontext->untrusted, cert, 0);
        else
            grow_chain(&TLScontext->trusted, cert, serverAuth);
@@ -1239,6 +1388,56 @@ static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
     return (ret);
 }
 
+/* wrap_cert - wrap "tacert" as issuer of "subject" */
+
+static int wrap_cert(TLS_SESS_STATE *TLScontext, int depth,
+                            X509 *tacert, X509 *subject)
+{
+    int     ret = 1;
+    X509   *cert;
+    int     len;
+    unsigned char *asn1;
+    unsigned char *buf;
+
+    TLScontext->tadepth = depth;
+    if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
+       msg_info("%s: depth=%d trust-anchor certificate",
+                TLScontext->namaddr, depth);
+
+    /*
+     * If the TA certificate is self-issued, use it directly.
+     */
+    if (!wrap_signed
+       || X509_check_issued(tacert, tacert) == X509_V_OK) {
+       grow_chain(&TLScontext->trusted, tacert, serverAuth);
+       return (ret);
+    }
+    /* Deep-copy tacert by converting to ASN.1 and back */
+    len = i2d_X509(tacert, NULL);
+    asn1 = buf = (unsigned char *) mymalloc(len);
+    i2d_X509(tacert, &buf);
+    if (buf - asn1 != len)
+       msg_panic("i2d_X509 failed to encode TA certificate");
+
+    buf = asn1;
+    cert = d2i_X509(0, (unsigned const char **) &buf, len);
+    if (!cert || (buf - asn1) != len)
+       msg_panic("d2i_X509 failed to decode TA certificate");
+    myfree((char *) asn1);
+
+    grow_chain(&TLScontext->untrusted, cert, 0);
+
+    /* Sign and wrap TA cert with internal "danekey" */
+    if (!X509_sign(cert, danekey, signmd)
+       || !wrap_key(TLScontext, depth + 1, danekey, cert)) {
+       msg_warn("error generating DANE wrapper certificate");
+       tls_print_errors();
+       ret = 0;
+    }
+    X509_free(cert);
+    return (ret);
+}
+
 /* ta_signed - is certificate signed by a TLSA cert or pkey */
 
 static int ta_signed(TLS_SESS_STATE *TLScontext, X509 *cert, int depth)
@@ -1262,7 +1461,7 @@ static int ta_signed(TLS_SESS_STATE *TLScontext, X509 *cert, int depth)
                continue;
            /* Check signature, since some other TA may work if not this. */
            if (X509_verify(cert, pk) > 0)
-               done = wrap_key(TLScontext, pk, cert, depth);
+               done = wrap_cert(TLScontext, depth + 1, x->cert, cert);
            EVP_PKEY_free(pk);
        }
     }
@@ -1286,7 +1485,7 @@ static int ta_signed(TLS_SESS_STATE *TLScontext, X509 *cert, int depth)
      */
     for (k = dane->pkeys; !done && k; k = k->next)
        if (X509_verify(cert, k->pkey) > 0)
-           done = wrap_key(TLScontext, k->pkey, cert, depth);
+           done = wrap_key(TLScontext, depth, k->pkey, cert);
 
     return (done);
 }
@@ -1297,6 +1496,7 @@ 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;
@@ -1331,10 +1531,21 @@ static void set_trust(TLS_SESS_STATE *TLScontext, X509_STORE_CTX *ctx)
        ca = sk_X509_delete(in, i);
 
        /* Is it a trust anchor? */
-       if (tls_dane_match(TLScontext, TLS_DANE_TA, ca, depth + 1)) {
-           if ((takey = X509_get_pubkey(ca)) != 0
-               && wrap_key(TLScontext, takey, cert, depth))
+       match = tls_dane_match(TLScontext, TLS_DANE_TA, ca, depth + 1);
+       if (match) {
+           switch (match) {
+           case MATCHED_CERT:
+               wrap_cert(TLScontext, depth, ca, cert);
+               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);
+           }
            cert = 0;
            break;
        }
index 492c6f50c0ab57070e7ab9bc7353e3411de17691..4bd8b9b03ae5d566c243ef2d67f14fa1f5fff78a 100644 (file)
@@ -15,6 +15,7 @@
 /*     char    *var_tls_eecdh_strong;
 /*     char    *var_tls_eecdh_ultra;
 /*     char    *var_tls_dane_ta_dgst;
+/*     char    *var_tls_dane_digests;
 /*     int     var_tls_daemon_rand_bytes;
 /*     bool    var_tls_append_def_CA;
 /*     bool    var_tls_preempt_clist;
@@ -220,6 +221,7 @@ char   *var_tls_null_clist;
 int     var_tls_daemon_rand_bytes;
 char   *var_tls_eecdh_strong;
 char   *var_tls_eecdh_ultra;
+char   *var_tls_dane_digests;
 char   *var_tls_dane_ta_dgst;
 bool    var_tls_append_def_CA;
 char   *var_tls_bug_tweaks;
@@ -227,6 +229,7 @@ char   *var_tls_ssl_options;
 bool    var_tls_bc_pkey_fprint;
 bool    var_tls_multi_wildcard;
 char   *var_tls_mgr_service;
+char   *tls_dane_digests;
 
 #ifdef VAR_TLS_PREEMPT_CLIST
 bool    var_tls_preempt_clist;
@@ -594,6 +597,7 @@ void    tls_param_init(void)
        VAR_TLS_EECDH_ULTRA, DEF_TLS_EECDH_ULTRA, &var_tls_eecdh_ultra, 1, 0,
        VAR_TLS_BUG_TWEAKS, DEF_TLS_BUG_TWEAKS, &var_tls_bug_tweaks, 0, 0,
        VAR_TLS_SSL_OPTIONS, DEF_TLS_SSL_OPTIONS, &var_tls_ssl_options, 0, 0,
+       VAR_TLS_DANE_DIGESTS, DEF_TLS_DANE_DIGESTS, &var_tls_dane_digests, 1, 0,
        VAR_TLS_DANE_TA_DGST, DEF_TLS_DANE_TA_DGST, &var_tls_dane_ta_dgst, 0, 0,
        VAR_TLS_MGR_SERVICE, DEF_TLS_MGR_SERVICE, &var_tls_mgr_service, 1, 0,
        0,
index 409b634b9188e2f168e9eb987bf278a6e59406bf..55910f7566bb797bf95e89334ecc3d72c79ed6a9 100644 (file)
@@ -1,8 +1,6 @@
  /*
-  * Proof-of-concept test program. Create, update or read a database. When
-  * the input is a name=value pair, the database is updated, otherwise the
-  * program assumes that the input specifies a lookup key and prints the
-  * corresponding value.
+  * Proof-of-concept test program. Create, update or read a database. Type
+  * '?' for a list of commands.
   */
 
 /* System library. */