mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-22 09:57:34 +00:00
postfix-2.11-20131117
This commit is contained in:
parent
897f730f14
commit
e96f9e5c3d
@ -19111,3 +19111,36 @@ Apologies for any names omitted.
|
|||||||
cleanup/cleanup_map11.c, cleanup/cleanup_map1n.c,
|
cleanup/cleanup_map11.c, cleanup/cleanup_map1n.c,
|
||||||
cleanup/cleanup_masquerade.c, cleanup/cleanup_message.c,
|
cleanup/cleanup_masquerade.c, cleanup/cleanup_message.c,
|
||||||
cleanup/cleanup_milter.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.
|
||||||
|
@ -4,6 +4,9 @@ Wish list:
|
|||||||
|
|
||||||
Make been_here flag BH_FLAG_FOLD configurable for masochists.
|
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
|
Preserve case in smtpd_resolve_addr() and add a structure
|
||||||
member for the case-folded address.
|
member for the case-folded address.
|
||||||
|
|
||||||
|
@ -256,6 +256,54 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
|||||||
limit is exceeded. Setting the limit to 1 ensures
|
limit is exceeded. Setting the limit to 1 ensures
|
||||||
that lookups do not return multiple values.
|
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>
|
<b>OBSOLETE QUERY INTERFACE</b>
|
||||||
This section describes an interface that is deprecated as
|
This section describes an interface that is deprecated as
|
||||||
of Postfix 2.2. It is replaced by the more general <b>query</b>
|
of Postfix 2.2. It is replaced by the more general <b>query</b>
|
||||||
|
@ -10,9 +10,9 @@ PCRE_TABLE(5) PCRE_TABLE(5)
|
|||||||
pcre_table - format of Postfix PCRE tables
|
pcre_table - format of Postfix PCRE tables
|
||||||
|
|
||||||
<b>SYNOPSIS</b>
|
<b>SYNOPSIS</b>
|
||||||
<b>postmap -q "<i></b>string</i><b>" <a href="pcre_table.5.html">pcre</a>:/etc/postfix/<i></b>filename[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> <<i>inputfile</i>
|
<b>postmap -q - <a href="pcre_table.5.html">pcre</a>:/etc/postfix/</b><i>filename</i> <<i>inputfile</i>
|
||||||
|
|
||||||
<b>DESCRIPTION</b>
|
<b>DESCRIPTION</b>
|
||||||
The Postfix mail system uses optional tables for address
|
The Postfix mail system uses optional tables for address
|
||||||
@ -39,15 +39,15 @@ PCRE_TABLE(5) PCRE_TABLE(5)
|
|||||||
<b>TABLE FORMAT</b>
|
<b>TABLE FORMAT</b>
|
||||||
The general form of a PCRE table is:
|
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-
|
When <i>pattern</i> matches the input string, use the cor-
|
||||||
responding <i>result</i> value.
|
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
|
When <i>pattern</i> does <b>not</b> match the input string, use
|
||||||
the corresponding <i>result</i> value.
|
the corresponding <i>result</i> value.
|
||||||
|
|
||||||
<b>if /<i></b>pattern</i><b>/<i></b>flags[0m
|
<b>if /</b><i>pattern</i><b>/</b><i>flags</i>
|
||||||
|
|
||||||
<b>endif</b> Match the input string against the patterns between
|
<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
|
<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.
|
This feature is available in Postfix 2.1 and later.
|
||||||
|
|
||||||
<b>if !/<i></b>pattern</i><b>/<i></b>flags[0m
|
<b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
|
||||||
|
|
||||||
<b>endif</b> Match the input string against the patterns between
|
<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
|
<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,
|
a whitespace character as part of the pattern,
|
||||||
escape it with backslash.
|
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)
|
<b>A</b> (default: off)
|
||||||
Toggles the PCRE_ANCHORED flag. When this flag is
|
Toggles the PCRE_ANCHORED flag. When this flag is
|
||||||
|
@ -11311,7 +11311,7 @@ to Postfix 2.9.6 or later. </p>
|
|||||||
<p> Lookup the associated DANE TLSA RRset even when a hostname is
|
<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
|
not an alias and its address records lie in an unsigned zone. This
|
||||||
is unlikely to ever yield DNSSEC validated results, since child
|
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
|
locally configured non-root trust-anchors. We anticipate that such
|
||||||
mechanisms will not be used for just the "_tcp" subdomain of a host.
|
mechanisms will not be used for just the "_tcp" subdomain of a host.
|
||||||
Suppressing the TLSA RRset lookup reduces latency and avoids potential
|
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>
|
<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>
|
</DD>
|
||||||
|
|
||||||
<DT><b><a name="tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a>
|
<DT><b><a name="tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a>
|
||||||
|
@ -10,9 +10,9 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
|
|||||||
regexp_table - format of Postfix regular expression tables
|
regexp_table - format of Postfix regular expression tables
|
||||||
|
|
||||||
<b>SYNOPSIS</b>
|
<b>SYNOPSIS</b>
|
||||||
<b>postmap -q "<i></b>string</i><b>" <a href="regexp_table.5.html">regexp</a>:/etc/postfix/<i></b>filename[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> <<i>inputfile</i>
|
<b>postmap -q - <a href="regexp_table.5.html">regexp</a>:/etc/postfix/</b><i>filename</i> <<i>inputfile</i>
|
||||||
|
|
||||||
<b>DESCRIPTION</b>
|
<b>DESCRIPTION</b>
|
||||||
The Postfix mail system uses optional tables for address
|
The Postfix mail system uses optional tables for address
|
||||||
@ -39,15 +39,15 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
|
|||||||
<b>TABLE FORMAT</b>
|
<b>TABLE FORMAT</b>
|
||||||
The general form of a Postfix regular expression table is:
|
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-
|
When <i>pattern</i> matches the input string, use the cor-
|
||||||
responding <i>result</i> value.
|
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
|
When <i>pattern</i> does <b>not</b> match the input string, use
|
||||||
the corresponding <i>result</i> value.
|
the corresponding <i>result</i> value.
|
||||||
|
|
||||||
<b>if /<i></b>pattern</i><b>/<i></b>flags[0m
|
<b>if /</b><i>pattern</i><b>/</b><i>flags</i>
|
||||||
|
|
||||||
<b>endif</b> Match the input string against the patterns between
|
<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
|
<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.
|
This feature is available in Postfix 2.1 and later.
|
||||||
|
|
||||||
<b>if !/<i></b>pattern</i><b>/<i></b>flags[0m
|
<b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
|
||||||
|
|
||||||
<b>endif</b> Match the input string against the patterns between
|
<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
|
<b>if</b> and <b>endif</b>, if and only if that same input string
|
||||||
|
@ -12,7 +12,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
|||||||
<b>SYNOPSIS</b>
|
<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>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>DESCRIPTION</b>
|
||||||
<b>smtp-sink</b> listens on the named host (or address) and port.
|
<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</b> Do not announce SASL authentication support.
|
||||||
|
|
||||||
<b>-A <i></b>delay[0m
|
<b>-A</b> <i>delay</i>
|
||||||
Wait <i>delay</i> seconds after responding to DATA, then
|
Wait <i>delay</i> seconds after responding to DATA, then
|
||||||
abort prematurely with a 550 reply status. Do not
|
abort prematurely with a 550 reply status. Do not
|
||||||
read further input from the client; this is an
|
read further input from the client; this is an
|
||||||
attempt to block the client before it sends ".".
|
attempt to block the client before it sends ".".
|
||||||
Specify a zero delay value to abort immediately.
|
Specify a zero delay value to abort immediately.
|
||||||
|
|
||||||
<b>-b <i></b>soft-bounce-reply[0m
|
<b>-b</b> <i>soft-bounce-reply</i>
|
||||||
Use <i>soft-bounce-reply</i> for soft reject responses.
|
Use <i>soft-bounce-reply</i> for soft reject responses.
|
||||||
The default reply is "450 4.3.0 Error: command
|
The default reply is "450 4.3.0 Error: command
|
||||||
failed".
|
failed".
|
||||||
|
|
||||||
<b>-B <i></b>hard-bounce-reply[0m
|
<b>-B</b> <i>hard-bounce-reply</i>
|
||||||
Use <i>hard-bounce-reply</i> for hard reject responses.
|
Use <i>hard-bounce-reply</i> for hard reject responses.
|
||||||
The default reply is "500 5.3.0 Error: command
|
The default reply is "500 5.3.0 Error: command
|
||||||
failed".
|
failed".
|
||||||
@ -70,7 +70,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
|||||||
|
|
||||||
<b>-C</b> Disable XCLIENT support.
|
<b>-C</b> Disable XCLIENT support.
|
||||||
|
|
||||||
<b>-d <i></b>dump-template[0m
|
<b>-d</b> <i>dump-template</i>
|
||||||
Dump each mail transaction to a single-message file
|
Dump each mail transaction to a single-message file
|
||||||
whose name is created by expanding the <i>dump-tem-</i>
|
whose name is created by expanding the <i>dump-tem-</i>
|
||||||
<i>plate</i> via strftime(3) and appending a pseudo-random
|
<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
|
Note: this option keeps one capture file open for
|
||||||
every mail transaction in progress.
|
every mail transaction in progress.
|
||||||
|
|
||||||
<b>-D <i></b>dump-template[0m
|
<b>-D</b> <i>dump-template</i>
|
||||||
Append mail transactions to a multi-message dump
|
Append mail transactions to a multi-message dump
|
||||||
file whose name is created by expanding the <i>dump-</i>
|
file whose name is created by expanding the <i>dump-</i>
|
||||||
<i>template</i> via strftime(3). If the template contains
|
<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>-E</b> Do not announce ENHANCEDSTATUSCODES support.
|
||||||
|
|
||||||
<b>-f <i></b>command,command,...[0m
|
<b>-f</b> <i>command,command,...</i>
|
||||||
Reject the specified commands with a hard (5xx)
|
Reject the specified commands with a hard (5xx)
|
||||||
error code. This option implies <b>-p</b>.
|
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>-F</b> Disable XFORWARD support.
|
||||||
|
|
||||||
<b>-h <i></b>hostname[0m
|
<b>-h</b> <i>hostname</i>
|
||||||
Use <i>hostname</i> in the SMTP greeting, in the HELO
|
Use <i>hostname</i> in the SMTP greeting, in the HELO
|
||||||
response, and in the EHLO response. The default
|
response, and in the EHLO response. The default
|
||||||
hostname is "smtp-sink".
|
hostname is "smtp-sink".
|
||||||
|
|
||||||
<b>-L</b> Enable LMTP instead of SMTP.
|
<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-
|
An upper bound on the maximal number of simultane-
|
||||||
ous connections that <b>smtp-sink</b> will handle. This
|
ous connections that <b>smtp-sink</b> will handle. This
|
||||||
prevents the process from running out of file
|
prevents the process from running out of file
|
||||||
descriptors. Excess connections will stay queued in
|
descriptors. Excess connections will stay queued in
|
||||||
the TCP/IP stack.
|
the TCP/IP stack.
|
||||||
|
|
||||||
<b>-M <i></b>count[0m
|
<b>-M</b> <i>count</i>
|
||||||
Terminate after receiving <i>count</i> messages.
|
Terminate after receiving <i>count</i> messages.
|
||||||
|
|
||||||
<b>-n <i></b>count[0m
|
<b>-n</b> <i>count</i>
|
||||||
Terminate after <i>count</i> sessions.
|
Terminate after <i>count</i> sessions.
|
||||||
|
|
||||||
<b>-p</b> Do not announce support for ESMTP command pipelin-
|
<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
|
<b>-P</b> Change the server greeting so that it appears to
|
||||||
come through a CISCO PIX system. Implies <b>-e</b>.
|
come through a CISCO PIX system. Implies <b>-e</b>.
|
||||||
|
|
||||||
<b>-q <i></b>command,command,...[0m
|
<b>-q</b> <i>command,command,...</i>
|
||||||
Disconnect (without replying) after receiving one
|
Disconnect (without replying) after receiving one
|
||||||
of the specified commands.
|
of the specified commands.
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
|||||||
and use quotes to protect white space from the
|
and use quotes to protect white space from the
|
||||||
shell. Command names are case-insensitive.
|
shell. Command names are case-insensitive.
|
||||||
|
|
||||||
<b>-Q <i></b>command,command,...[0m
|
<b>-Q</b> <i>command,command,...</i>
|
||||||
Send a 421 reply and disconnect after receiving one
|
Send a 421 reply and disconnect after receiving one
|
||||||
of the specified commands.
|
of the specified commands.
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ SMTP-SINK(1) SMTP-SINK(1)
|
|||||||
and use quotes to protect white space from the
|
and use quotes to protect white space from the
|
||||||
shell. Command names are case-insensitive.
|
shell. Command names are case-insensitive.
|
||||||
|
|
||||||
<b>-r <i></b>command,command,...[0m
|
<b>-r</b> <i>command,command,...</i>
|
||||||
Reject the specified commands with a soft (4xx)
|
Reject the specified commands with a soft (4xx)
|
||||||
error code. This option implies <b>-p</b>.
|
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
|
and use quotes to protect white space from the
|
||||||
shell. Command names are case-insensitive.
|
shell. Command names are case-insensitive.
|
||||||
|
|
||||||
<b>-R <i></b>root-directory[0m
|
<b>-R</b> <i>root-directory</i>
|
||||||
Change the process root directory to the specified
|
Change the process root directory to the specified
|
||||||
location. This option requires super-user privi-
|
location. This option requires super-user privi-
|
||||||
leges. See also the <b>-u</b> option.
|
leges. See also the <b>-u</b> option.
|
||||||
|
|
||||||
<b>-s <i></b>command,command,...[0m
|
<b>-s</b> <i>command,command,...</i>
|
||||||
Log the named commands to syslogd.
|
Log the named commands to syslogd.
|
||||||
|
|
||||||
Examples of commands are CONNECT, HELO, EHLO, LHLO,
|
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
|
tab), \<i>ddd</i> (up to three octal digits) and \\ (the
|
||||||
backslash character).
|
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
|
Limit the time for receiving a command or sending a
|
||||||
response. The time limit is specified in seconds.
|
response. The time limit is specified in seconds.
|
||||||
|
|
||||||
<b>-T <i></b>windowsize[0m
|
<b>-T</b> <i>windowsize</i>
|
||||||
Override the default TCP window size. To work
|
Override the default TCP window size. To work
|
||||||
around broken TCP window scaling implementations,
|
around broken TCP window scaling implementations,
|
||||||
specify a value > 0 and < 65536.
|
specify a value > 0 and < 65536.
|
||||||
|
|
||||||
<b>-u <i></b>username[0m
|
<b>-u</b> <i>username</i>
|
||||||
Switch to the specified user privileges after open-
|
Switch to the specified user privileges after open-
|
||||||
ing the network socket and optionally changing the
|
ing the network socket and optionally changing the
|
||||||
process root directory. This option is required
|
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>-v</b> Show the SMTP conversations.
|
||||||
|
|
||||||
<b>-w <i></b>delay[0m
|
<b>-w</b> <i>delay</i>
|
||||||
Wait <i>delay</i> seconds before responding to a DATA com-
|
Wait <i>delay</i> seconds before responding to a DATA com-
|
||||||
mand.
|
mand.
|
||||||
|
|
||||||
<b>-W <i></b>command:delay[:odds][0m
|
<b>-W</b> <i>command:delay[:odds]</i>
|
||||||
Wait <i>delay</i> seconds before responding to <i>command</i>.
|
Wait <i>delay</i> seconds before responding to <i>command</i>.
|
||||||
If <i>odds</i> is also specified (a number between 1-99
|
If <i>odds</i> is also specified (a number between 1-99
|
||||||
inclusive), wait for a random multiple of <i>delay</i>.
|
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
|
interface) TCP port <i>port</i>. Both <i>host</i> and <i>port</i> may be
|
||||||
specified in numeric or symbolic form.
|
specified in numeric or symbolic form.
|
||||||
|
|
||||||
<b>unix:<i></b>pathname[0m
|
<b>unix:</b><i>pathname</i>
|
||||||
Listen on the UNIX-domain socket at <i>pathname</i>.
|
Listen on the UNIX-domain socket at <i>pathname</i>.
|
||||||
|
|
||||||
<i>backlog</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-
|
The format of the <b>smtp-sink</b> generated headers is as fol-
|
||||||
lows:
|
lows:
|
||||||
|
|
||||||
<b>X-Client-Addr: <i></b>text[0m
|
<b>X-Client-Addr:</b> <i>text</i>
|
||||||
The client IP address without enclosing []. An IPv6
|
The client IP address without enclosing []. An IPv6
|
||||||
address is prefixed with "ipv6:". This record is
|
address is prefixed with "ipv6:". This record is
|
||||||
always present.
|
always present.
|
||||||
|
|
||||||
<b>X-Client-Proto: <i></b>text[0m
|
<b>X-Client-Proto:</b> <i>text</i>
|
||||||
The client protocol: SMTP, ESMTP or LMTP. This
|
The client protocol: SMTP, ESMTP or LMTP. This
|
||||||
record is always present.
|
record is always present.
|
||||||
|
|
||||||
<b>X-Helo-Args: <i></b>text[0m
|
<b>X-Helo-Args:</b> <i>text</i>
|
||||||
The arguments of the last HELO or EHLO command
|
The arguments of the last HELO or EHLO command
|
||||||
before this mail delivery transaction. This record
|
before this mail delivery transaction. This record
|
||||||
is present only if the client sent a recognizable
|
is present only if the client sent a recognizable
|
||||||
HELO or EHLO command before the DATA command.
|
HELO or EHLO command before the DATA command.
|
||||||
|
|
||||||
<b>X-Mail-Args: <i></b>text[0m
|
<b>X-Mail-Args:</b> <i>text</i>
|
||||||
The arguments of the MAIL command that started this
|
The arguments of the MAIL command that started this
|
||||||
mail delivery transaction. This record is present
|
mail delivery transaction. This record is present
|
||||||
exactly once.
|
exactly once.
|
||||||
|
|
||||||
<b>X-Rcpt-Args: <i></b>text[0m
|
<b>X-Rcpt-Args:</b> <i>text</i>
|
||||||
The arguments of an RCPT command within this mail
|
The arguments of an RCPT command within this mail
|
||||||
delivery transaction. There is one record for each
|
delivery transaction. There is one record for each
|
||||||
RCPT command, and they are in the order as sent by
|
RCPT command, and they are in the order as sent by
|
||||||
the client.
|
the client.
|
||||||
|
|
||||||
<b>Received: <i></b>text[0m
|
<b>Received:</b> <i>text</i>
|
||||||
A message header for compatibility with mail pro-
|
A message header for compatibility with mail pro-
|
||||||
cessing software. This three-line header marks the
|
cessing software. This three-line header marks the
|
||||||
end of the headers provided by <b>smtp-sink</b>, and is
|
end of the headers provided by <b>smtp-sink</b>, and is
|
||||||
formatted as follows:
|
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
|
The HELO or EHLO command argument and client
|
||||||
IP address. If the client did not send HELO
|
IP address. If the client did not send HELO
|
||||||
or EHLO, the client IP address is used
|
or EHLO, the client IP address is used
|
||||||
instead.
|
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 hostname specified with the <b>-h</b> option,
|
||||||
the client protocol (see <b>X-Client-Proto</b>
|
the client protocol (see <b>X-Client-Proto</b>
|
||||||
above), and the pseudo-random portion of the
|
above), and the pseudo-random portion of the
|
||||||
|
@ -256,6 +256,39 @@ A setting of zero disables the limit. Lookups fail with a
|
|||||||
temporary error if the limit is exceeded. Setting the
|
temporary error if the limit is exceeded. Setting the
|
||||||
limit to 1 ensures that lookups do not return multiple
|
limit to 1 ensures that lookups do not return multiple
|
||||||
values.
|
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"
|
.SH "OBSOLETE QUERY INTERFACE"
|
||||||
.na
|
.na
|
||||||
.nf
|
.nf
|
||||||
|
@ -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
|
Lookup the associated DANE TLSA RRset even when a hostname is
|
||||||
not an alias and its address records lie in an unsigned zone. This
|
not an alias and its address records lie in an unsigned zone. This
|
||||||
is unlikely to ever yield DNSSEC validated results, since child
|
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
|
locally configured non-root trust-anchors. We anticipate that such
|
||||||
mechanisms will not be used for just the "_tcp" subdomain of a host.
|
mechanisms will not be used for just the "_tcp" subdomain of a host.
|
||||||
Suppressing the TLSA RRset lookup reduces latency and avoids potential
|
Suppressing the TLSA RRset lookup reduces latency and avoids potential
|
||||||
@ -11006,6 +11006,49 @@ bytes (equivalent to 256 bits) is sufficient to generate a 128bit
|
|||||||
(or 168bit) session key.
|
(or 168bit) session key.
|
||||||
.PP
|
.PP
|
||||||
This feature is available in Postfix 2.2 and later.
|
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)
|
.SH tls_dane_trust_anchor_digest_enable (default: trust-anchor-assertion)
|
||||||
RFC 6698 trust-anchor digest support in the Postfix TLS library.
|
RFC 6698 trust-anchor digest support in the Postfix TLS library.
|
||||||
Specify zero or more of the following options, separated by comma or
|
Specify zero or more of the following options, separated by comma or
|
||||||
|
@ -47,7 +47,7 @@ sed '
|
|||||||
s;'$ESC'\[4m;<i>;g
|
s;'$ESC'\[4m;<i>;g
|
||||||
s;'$ESC'\[24m;</i>;g
|
s;'$ESC'\[24m;</i>;g
|
||||||
# Undo gratuitous whitespace changes.
|
# Undo gratuitous whitespace changes.
|
||||||
s;\( *\)\(</[bi]>\);\2\1;g
|
#s;\( *\)\(</[bi]>\);\2\1;g
|
||||||
# End nroff ANSI escape sequence workarounds.
|
# End nroff ANSI escape sequence workarounds.
|
||||||
s;</i>\( *\)<i>;\1;g
|
s;</i>\( *\)<i>;\1;g
|
||||||
s;</b>\( *\)<b>;\1;g
|
s;</b>\( *\)<b>;\1;g
|
||||||
|
@ -716,6 +716,7 @@ while (<>) {
|
|||||||
s;\btls_append_default_CA\b;<a href="postconf.5.html#tls_append_default_CA">$&</a>;g;
|
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_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_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;\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;
|
s;\bfrozen_delivered_to\b;<a href="postconf.5.html#frozen_delivered_to">$&</a>;g;
|
||||||
|
@ -244,6 +244,39 @@
|
|||||||
# temporary error if the limit is exceeded. Setting the
|
# temporary error if the limit is exceeded. Setting the
|
||||||
# limit to 1 ensures that lookups do not return multiple
|
# limit to 1 ensures that lookups do not return multiple
|
||||||
# values.
|
# 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
|
# OBSOLETE QUERY INTERFACE
|
||||||
# .ad
|
# .ad
|
||||||
# .fi
|
# .fi
|
||||||
|
@ -15438,7 +15438,7 @@ configuration parameter. See there for details. </p>
|
|||||||
<p> Lookup the associated DANE TLSA RRset even when a hostname is
|
<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
|
not an alias and its address records lie in an unsigned zone. This
|
||||||
is unlikely to ever yield DNSSEC validated results, since child
|
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
|
locally configured non-root trust-anchors. We anticipate that such
|
||||||
mechanisms will not be used for just the "_tcp" subdomain of a host.
|
mechanisms will not be used for just the "_tcp" subdomain of a host.
|
||||||
Suppressing the TLSA RRset lookup reduces latency and avoids potential
|
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>
|
are not prepared to handle the new TLSA RRset. </p>
|
||||||
|
|
||||||
<p> This feature is available in Postfix 2.11. </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>
|
||||||
|
@ -91,6 +91,25 @@
|
|||||||
/* releases.
|
/* releases.
|
||||||
/* .IP hosts
|
/* .IP hosts
|
||||||
/* List of hosts to connect to.
|
/* 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
|
/* .PP
|
||||||
/* For example, if you want the map to reference databases of
|
/* For example, if you want the map to reference databases of
|
||||||
/* the name "your_db" and execute a query like this: select
|
/* the name "your_db" and execute a query like this: select
|
||||||
@ -217,6 +236,8 @@ typedef struct {
|
|||||||
CFG_PARSER *parser;
|
CFG_PARSER *parser;
|
||||||
char *query;
|
char *query;
|
||||||
char *result_format;
|
char *result_format;
|
||||||
|
char *option_file;
|
||||||
|
char *option_group;
|
||||||
void *ctx;
|
void *ctx;
|
||||||
int expansion_limit;
|
int expansion_limit;
|
||||||
char *username;
|
char *username;
|
||||||
@ -226,6 +247,14 @@ typedef struct {
|
|||||||
PLMYSQL *pldb;
|
PLMYSQL *pldb;
|
||||||
#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
|
#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
|
||||||
HOST *active_host;
|
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
|
#endif
|
||||||
} DICT_MYSQL;
|
} DICT_MYSQL;
|
||||||
|
|
||||||
@ -242,12 +271,11 @@ typedef struct {
|
|||||||
|
|
||||||
/* internal function declarations */
|
/* internal function declarations */
|
||||||
static PLMYSQL *plmysql_init(ARGV *);
|
static PLMYSQL *plmysql_init(ARGV *);
|
||||||
static MYSQL_RES *plmysql_query(DICT_MYSQL *, const char *, VSTRING *, char *,
|
static MYSQL_RES *plmysql_query(DICT_MYSQL *, const char *, VSTRING *);
|
||||||
char *, char *);
|
|
||||||
static void plmysql_dealloc(PLMYSQL *);
|
static void plmysql_dealloc(PLMYSQL *);
|
||||||
static void plmysql_close_host(HOST *);
|
static void plmysql_close_host(HOST *);
|
||||||
static void plmysql_down_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 *);
|
static const char *dict_mysql_lookup(DICT *, const char *);
|
||||||
DICT *dict_mysql_open(const char *, int, int);
|
DICT *dict_mysql_open(const char *, int, int);
|
||||||
static void dict_mysql_close(DICT *);
|
static void dict_mysql_close(DICT *);
|
||||||
@ -349,10 +377,7 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* do the query - set dict->error & cleanup if there's an error */
|
/* do the query - set dict->error & cleanup if there's an error */
|
||||||
if ((query_res = plmysql_query(dict_mysql, name, query,
|
if ((query_res = plmysql_query(dict_mysql, name, query)) == 0) {
|
||||||
dict_mysql->dbname,
|
|
||||||
dict_mysql->username,
|
|
||||||
dict_mysql->password)) == 0) {
|
|
||||||
dict->error = DICT_ERR_RETRY;
|
dict->error = DICT_ERR_RETRY;
|
||||||
return (0);
|
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 */
|
/* dict_mysql_get_active - get an active connection */
|
||||||
|
|
||||||
static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname,
|
static HOST *dict_mysql_get_active(DICT_MYSQL *dict_mysql)
|
||||||
char *username, char *password)
|
|
||||||
{
|
{
|
||||||
const char *myname = "dict_mysql_get_active";
|
const char *myname = "dict_mysql_get_active";
|
||||||
|
PLMYSQL *PLDB = dict_mysql->pldb;
|
||||||
HOST *host;
|
HOST *host;
|
||||||
int count = RETRY_CONN_MAX;
|
int count = RETRY_CONN_MAX;
|
||||||
|
|
||||||
@ -457,7 +482,7 @@ static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname,
|
|||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: attempting to connect to host %s", myname,
|
msg_info("%s: attempting to connect to host %s", myname,
|
||||||
host->hostname);
|
host->hostname);
|
||||||
plmysql_connect_single(host, dbname, username, password);
|
plmysql_connect_single(dict_mysql, host);
|
||||||
if (host->stat == STATACTIVE)
|
if (host->stat == STATACTIVE)
|
||||||
return host;
|
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,
|
static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
|
||||||
const char *name,
|
const char *name,
|
||||||
VSTRING *query,
|
VSTRING *query)
|
||||||
char *dbname,
|
|
||||||
char *username,
|
|
||||||
char *password)
|
|
||||||
{
|
{
|
||||||
PLMYSQL *PLDB = dict_mysql->pldb;
|
|
||||||
HOST *host;
|
HOST *host;
|
||||||
MYSQL_RES *res = 0;
|
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
|
#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
|
* 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
|
* 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)
|
if ((host->db = mysql_init(NULL)) == NULL)
|
||||||
msg_fatal("dict_mysql: insufficient memory");
|
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,
|
if (mysql_real_connect(host->db,
|
||||||
(host->type == TYPEINET ? host->name : 0),
|
(host->type == TYPEINET ? host->name : 0),
|
||||||
username,
|
dict_mysql->username,
|
||||||
password,
|
dict_mysql->password,
|
||||||
dbname,
|
dict_mysql->dbname,
|
||||||
host->port,
|
host->port,
|
||||||
(host->type == TYPEUNIX ? host->name : 0),
|
(host->type == TYPEUNIX ? host->name : 0),
|
||||||
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)
|
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;
|
CFG_PARSER *p = dict_mysql->parser;
|
||||||
VSTRING *buf;
|
VSTRING *buf;
|
||||||
char *hosts;
|
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->password = cfg_get_str(p, "password", "", 0, 0);
|
||||||
dict_mysql->dbname = cfg_get_str(p, "dbname", "", 1, 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->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
|
* 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->dbname);
|
||||||
myfree(dict_mysql->query);
|
myfree(dict_mysql->query);
|
||||||
myfree(dict_mysql->result_format);
|
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)
|
if (dict_mysql->hosts)
|
||||||
argv_free(dict_mysql->hosts);
|
argv_free(dict_mysql->hosts);
|
||||||
if (dict_mysql->ctx)
|
if (dict_mysql->ctx)
|
||||||
|
@ -3103,6 +3103,13 @@ extern char *var_tls_ssl_options;
|
|||||||
#define DEF_TLS_BC_PKEY_FPRINT 0
|
#define DEF_TLS_BC_PKEY_FPRINT 0
|
||||||
extern bool var_tls_bc_pkey_fprint;
|
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
|
* External interface for enabling trust-anchor digests, which are risky
|
||||||
* when the corresponding certificate is missing from the peer chain (this
|
* when the corresponding certificate is missing from the peer chain (this
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||||
* patchlevel; they change the release date only.
|
* patchlevel; they change the release date only.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20131114"
|
#define MAIL_RELEASE_DATE "20131117"
|
||||||
#define MAIL_VERSION_NUMBER "2.11"
|
#define MAIL_VERSION_NUMBER "2.11"
|
||||||
|
|
||||||
#ifdef SNAPSHOT
|
#ifdef SNAPSHOT
|
||||||
|
@ -1745,9 +1745,6 @@ static void parse_match(STATE *state, int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
|
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
|
|
||||||
switch (state->level) {
|
switch (state->level) {
|
||||||
case TLS_LEV_SECURE:
|
case TLS_LEV_SECURE:
|
||||||
state->match = argv_alloc(2);
|
state->match = argv_alloc(2);
|
||||||
@ -1826,14 +1823,17 @@ int main(int argc, char *argv[])
|
|||||||
mail_conf_suck();
|
mail_conf_suck();
|
||||||
parse_options(&state, argc, argv);
|
parse_options(&state, argc, argv);
|
||||||
mail_params_init();
|
mail_params_init();
|
||||||
|
|
||||||
parse_match(&state, argc, argv);
|
|
||||||
parse_tas(&state);
|
parse_tas(&state);
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
/* The first non-option argument is the destination. */
|
/* The first non-option argument is the destination. */
|
||||||
if (argc < optind)
|
if (!argc)
|
||||||
usage();
|
usage();
|
||||||
state.dest = mystrdup(argv[optind]);
|
|
||||||
|
state.dest = mystrdup(argv[0]);
|
||||||
|
parse_match(&state, --argc, ++argv);
|
||||||
|
|
||||||
/* Don't talk to remote systems as root */
|
/* Don't talk to remote systems as root */
|
||||||
if (!geteuid())
|
if (!geteuid())
|
||||||
|
@ -235,17 +235,29 @@ static int wrap_signed = 0;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
static const EVP_MD *signmd;
|
static const EVP_MD *signmd;
|
||||||
|
static const char *signalg;
|
||||||
|
|
||||||
static EVP_PKEY *danekey;
|
static EVP_PKEY *danekey;
|
||||||
static ASN1_OBJECT *serverAuth;
|
static ASN1_OBJECT *serverAuth;
|
||||||
|
|
||||||
static const char *sha256 = "sha256";
|
/*
|
||||||
static const EVP_MD *sha256md;
|
* https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml
|
||||||
static int sha256len;
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
static const char *sha512 = "sha512";
|
#define MAXDIGESTS 256 /* RFC limit */
|
||||||
static const EVP_MD *sha512md;
|
digest_info digest_table[] = {
|
||||||
static int sha512len;
|
{"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;
|
static int digest_mask;
|
||||||
|
|
||||||
@ -271,6 +283,46 @@ void tls_dane_verbose(int on)
|
|||||||
dane_verbose = 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 */
|
/* gencakey - generate interal DANE root CA key */
|
||||||
|
|
||||||
static EVP_PKEY *gencakey(void)
|
static EVP_PKEY *gencakey(void)
|
||||||
@ -278,8 +330,6 @@ static EVP_PKEY *gencakey(void)
|
|||||||
EVP_PKEY *key = 0;
|
EVP_PKEY *key = 0;
|
||||||
|
|
||||||
#ifdef WRAP_SIGNED
|
#ifdef WRAP_SIGNED
|
||||||
int len;
|
|
||||||
unsigned char *p;
|
|
||||||
EC_KEY *eckey;
|
EC_KEY *eckey;
|
||||||
EC_GROUP *group;
|
EC_GROUP *group;
|
||||||
|
|
||||||
@ -312,16 +362,44 @@ static void dane_init(void)
|
|||||||
TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
|
TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
int digest_pref = 0;
|
||||||
|
char *cp;
|
||||||
|
char *save;
|
||||||
|
char *tok;
|
||||||
|
digest_info *di;
|
||||||
|
|
||||||
digest_mask =
|
digest_mask =
|
||||||
name_mask_opt(VAR_TLS_DANE_TA_DGST, ta_dgsts, var_tls_dane_ta_dgst,
|
name_mask_opt(VAR_TLS_DANE_TA_DGST, ta_dgsts, var_tls_dane_ta_dgst,
|
||||||
NAME_MASK_ANY_CASE | NAME_MASK_FATAL);
|
NAME_MASK_ANY_CASE | NAME_MASK_FATAL);
|
||||||
|
|
||||||
if ((sha256md = EVP_get_digestbyname(sha256)) != 0)
|
save = cp = mystrdup(var_tls_dane_digests);
|
||||||
sha256len = EVP_MD_size(sha256md);
|
while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
|
||||||
if ((sha512md = EVP_get_digestbyname(sha512)) != 0)
|
for (di = digest_table; di->alg; ++di)
|
||||||
sha512len = EVP_MD_size(sha512md);
|
if (strcasecmp(tok, di->alg) == 0)
|
||||||
signmd = sha256md ? sha256md : EVP_sha1();
|
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 */
|
/* Don't report old news */
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
@ -344,7 +422,7 @@ int tls_dane_avail(void)
|
|||||||
dane_init();
|
dane_init();
|
||||||
|
|
||||||
#ifdef DANE_TLSA_SUPPORT
|
#ifdef DANE_TLSA_SUPPORT
|
||||||
return (sha256md && sha512md && serverAuth);
|
return (signalg && serverAuth);
|
||||||
#else
|
#else
|
||||||
return (0);
|
return (0);
|
||||||
#endif
|
#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)
|
static int tlsa_rr_cmp(DNS_RR *a, DNS_RR *b)
|
||||||
{
|
{
|
||||||
if (a->data_len == b->data_len)
|
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));
|
return (memcmp(a->data, b->data, a->data_len));
|
||||||
return ((a->data_len > b->data_len) ? 1 : -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse_tlsa_rrs - parse a validated TLSA RRset */
|
/* 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;
|
uint8_t mtype;
|
||||||
int mlen;
|
int mlen;
|
||||||
const unsigned char *p;
|
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)
|
if (rr == 0)
|
||||||
msg_panic("null TLSA rr");
|
msg_panic("null TLSA rr");
|
||||||
|
|
||||||
for ( /* nop */ ; rr; rr = rr->next) {
|
for ( /* nop */ ; rr; rr = rr->next) {
|
||||||
const char *mdalg = 0;
|
const char *mdalg = 0;
|
||||||
int mdlen;
|
|
||||||
char *digest;
|
char *digest;
|
||||||
int same = (strcasecmp(rr->rname, rr->qname) == 0);
|
int same = (strcasecmp(rr->rname, rr->qname) == 0);
|
||||||
uint8_t *ip = (uint8_t *) rr->data;
|
uint8_t *ip = (uint8_t *) rr->data;
|
||||||
X509 *x = 0; /* OpenSSL tries to re-use *x if x!=0 */
|
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 */
|
EVP_PKEY *k = 0; /* OpenSSL tries to re-use *k if k!=0 */
|
||||||
|
digest_info *di;
|
||||||
|
|
||||||
#define rcname(rr) (same ? "" : rr->qname)
|
#define rcname(rr) (same ? "" : rr->qname)
|
||||||
#define rarrow(rr) (same ? "" : " -> ")
|
#define rarrow(rr) (same ? "" : " -> ")
|
||||||
@ -638,26 +740,34 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mtype = *ip++) {
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
switch (mtype) {
|
||||||
default:
|
default:
|
||||||
|
if ((di = dane_digest_info(mtype)) == 0) {
|
||||||
msg_warn("unsupported matching type %u in RR: "
|
msg_warn("unsupported matching type %u in RR: "
|
||||||
"%s%s%s IN TLSA %u %u %u ...", mtype, rcname(rr),
|
"%s%s%s IN TLSA %u %u %u ...", mtype, rcname(rr),
|
||||||
rarrow(rr), rr->rname, usage, selector, mtype);
|
rarrow(rr), rr->rname, usage, selector, mtype);
|
||||||
continue;
|
continue;
|
||||||
case DNS_TLSA_MATCHING_TYPE_SHA256:
|
|
||||||
if (!mdalg) {
|
|
||||||
mdalg = sha256;
|
|
||||||
mdlen = sha256len;
|
|
||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
if (di->pref < 0) {
|
||||||
case DNS_TLSA_MATCHING_TYPE_SHA512:
|
msg_warn("digest algorithm %s locally disabled, in RR: "
|
||||||
if (!mdalg) {
|
"%s%s%s IN TLSA %u %u %u ...", di->alg,
|
||||||
mdalg = sha512;
|
rcname(rr), rarrow(rr), rr->rname,
|
||||||
mdlen = sha512len;
|
usage, selector, mtype);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (mlen != mdlen) {
|
if (mlen != di->len) {
|
||||||
msg_warn("malformed %s digest, length %u, in RR: "
|
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,
|
rcname(rr), rarrow(rr), rr->rname,
|
||||||
usage, selector, mtype);
|
usage, selector, mtype);
|
||||||
continue;
|
continue;
|
||||||
@ -667,7 +777,7 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
|
|||||||
if (!(digest_mask & TLS_DANE_ENABLE_CC)) {
|
if (!(digest_mask & TLS_DANE_ENABLE_CC)) {
|
||||||
msg_warn("%s trust-anchor %s digests disabled, in RR: "
|
msg_warn("%s trust-anchor %s digests disabled, in RR: "
|
||||||
"%s%s%s IN TLSA %u %u %u ...", TLS_DANE_CC,
|
"%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);
|
usage, selector, mtype);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -676,14 +786,14 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
|
|||||||
if (!(digest_mask & TLS_DANE_ENABLE_TAA)) {
|
if (!(digest_mask & TLS_DANE_ENABLE_TAA)) {
|
||||||
msg_warn("%s trust-anchor %s digests disabled, in RR: "
|
msg_warn("%s trust-anchor %s digests disabled, in RR: "
|
||||||
"%s%s%s IN TLSA %u %u %u ...", TLS_DANE_TAA,
|
"%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);
|
usage, selector, mtype);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dane_add(dane, usage, selector, mdalg,
|
digest = tls_digest_encode((unsigned char *) ip, di->len);
|
||||||
digest = tls_digest_encode((unsigned char *) ip, mdlen));
|
dane_add(dane, usage, selector, di->alg, digest);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
|
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);
|
X509_free(x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
|
case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
|
||||||
if (!d2i_PUBKEY(&k, &p, mlen)) {
|
if (!d2i_PUBKEY(&k, &p, mlen)) {
|
||||||
msg_warn("malformed %s in RR: "
|
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
|
* 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, signalg);
|
||||||
digest = tls_data_fprint((char *) ip, mlen, sha256));
|
dane_add(dane, usage, selector, mdalg = signalg, digest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save state
|
||||||
|
*/
|
||||||
|
prev_usage_selector = (usage << 8 | selector);
|
||||||
|
prev_mtype = mtype;
|
||||||
|
|
||||||
if (msg_verbose || dane_verbose) {
|
if (msg_verbose || dane_verbose) {
|
||||||
switch (mtype) {
|
switch (mtype) {
|
||||||
default:
|
default:
|
||||||
@ -803,7 +921,13 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
|
|||||||
dane->expires = 1 + event_time() + rrs->ttl;
|
dane->expires = 1 + event_time() + rrs->ttl;
|
||||||
|
|
||||||
if (rrs->dnssec_valid) {
|
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);
|
rrs = dns_rr_sort(rrs, tlsa_rr_cmp);
|
||||||
parse_tlsa_rrs(dane, rrs);
|
parse_tlsa_rrs(dane, rrs);
|
||||||
} else
|
} else
|
||||||
@ -905,7 +1029,7 @@ int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
|
|||||||
msg_warn("trust-anchor files not supported");
|
msg_warn("trust-anchor files not supported");
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
mdalg = sha256md ? sha256 : "sha1";
|
mdalg = signalg ? signalg : "sha1";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio,
|
* 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;
|
char **dgst;
|
||||||
ARGV *certs;
|
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) {
|
if (tlsa->pkeys) {
|
||||||
char *pkey_dgst = tls_pkey_fprint(cert, tlsa->mdalg);
|
char *pkey_dgst = tls_pkey_fprint(cert, tlsa->mdalg);
|
||||||
|
|
||||||
for (dgst = tlsa->pkeys->argv; !matched && *dgst; ++dgst)
|
for (dgst = tlsa->pkeys->argv; !matched && *dgst; ++dgst)
|
||||||
if (strcasecmp(pkey_dgst, *dgst) == 0)
|
if (strcasecmp(pkey_dgst, *dgst) == 0)
|
||||||
matched = 1;
|
matched = MATCHED_PKEY;
|
||||||
if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
|
if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
|
||||||
&& matched)
|
&& matched)
|
||||||
msg_info("%s: depth=%d matched %s public-key %s digest=%s",
|
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)
|
for (dgst = certs->argv; !matched && *dgst; ++dgst)
|
||||||
if (strcasecmp(cert_dgst, *dgst) == 0)
|
if (strcasecmp(cert_dgst, *dgst) == 0)
|
||||||
matched = 1;
|
matched = MATCHED_CERT;
|
||||||
if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
|
if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
|
||||||
&& matched)
|
&& matched)
|
||||||
msg_info("%s: depth=%d matched %s certificate %s digest %s",
|
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);
|
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) {
|
if (akid && akid->issuer) {
|
||||||
int i;
|
int i;
|
||||||
general_name_stack_t *gens = akid->issuer;
|
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);
|
GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
|
||||||
|
|
||||||
if (gn->type == GEN_DIRNAME)
|
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)));
|
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" */
|
/* wrap_key - wrap TA "key" as issuer of "subject" */
|
||||||
|
|
||||||
static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
|
static int wrap_key(TLS_SESS_STATE *TLScontext, int depth,
|
||||||
int depth)
|
EVP_PKEY *key, X509 *subject)
|
||||||
{
|
{
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
int selfsigned = 0;
|
||||||
X509 *cert = 0;
|
X509 *cert = 0;
|
||||||
AUTHORITY_KEYID *akid;
|
AUTHORITY_KEYID *akid;
|
||||||
X509_NAME *name = X509_get_issuer_name(subject);
|
X509_NAME *name = X509_get_issuer_name(subject);
|
||||||
|
X509_NAME *akid_name;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record the depth of the intermediate wrapper certificate, logged in
|
* Record the depth of the intermediate wrapper certificate, logged in
|
||||||
* the verify callback, unlike the parent root CA.
|
* the verify callback.
|
||||||
*/
|
*/
|
||||||
if (!key)
|
if (TLScontext->tadepth < 0) {
|
||||||
TLScontext->tadepth = depth;
|
TLScontext->tadepth = depth + 1;
|
||||||
else if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
|
if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
|
||||||
msg_info("%s: depth=%d chain is trust-anchor signed",
|
msg_info("%s: depth=%d chain is trust-anchor signed",
|
||||||
TLScontext->namaddr, depth);
|
TLScontext->namaddr, depth);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If key is NULL generate a self-signed root CA, with key "danekey",
|
* 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);
|
return (0);
|
||||||
|
|
||||||
akid = X509_get_ext_d2i(subject, NID_authority_key_identifier, 0, 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();
|
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_gmtime_adj(X509_get_notAfter(cert), 30 * 86400L)
|
||||||
|| !X509_set_pubkey(cert, key ? key : danekey)
|
|| !X509_set_pubkey(cert, key ? key : danekey)
|
||||||
|| !add_ext(0, cert, NID_basic_constraints, "CA:TRUE")
|
|| !add_ext(0, cert, NID_basic_constraints, "CA:TRUE")
|
||||||
|| (key && !add_akid(cert, akid))
|
|| (key && !selfsigned && !add_akid(cert, akid))
|
||||||
|| !add_skid(cert, akid)
|
|| !add_skid(cert, akid)
|
||||||
|| (wrap_signed
|
|| (wrap_signed
|
||||||
&& (!X509_sign(cert, danekey, signmd)
|
&& (!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");
|
msg_warn("error generating DANE wrapper certificate");
|
||||||
tls_print_errors();
|
tls_print_errors();
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -1229,7 +1378,7 @@ static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
|
|||||||
if (akid)
|
if (akid)
|
||||||
AUTHORITY_KEYID_free(akid);
|
AUTHORITY_KEYID_free(akid);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (key && wrap_signed)
|
if (key && !selfsigned && wrap_signed)
|
||||||
grow_chain(&TLScontext->untrusted, cert, 0);
|
grow_chain(&TLScontext->untrusted, cert, 0);
|
||||||
else
|
else
|
||||||
grow_chain(&TLScontext->trusted, cert, serverAuth);
|
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);
|
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 */
|
/* ta_signed - is certificate signed by a TLSA cert or pkey */
|
||||||
|
|
||||||
static int ta_signed(TLS_SESS_STATE *TLScontext, X509 *cert, int depth)
|
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;
|
continue;
|
||||||
/* Check signature, since some other TA may work if not this. */
|
/* Check signature, since some other TA may work if not this. */
|
||||||
if (X509_verify(cert, pk) > 0)
|
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);
|
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)
|
for (k = dane->pkeys; !done && k; k = k->next)
|
||||||
if (X509_verify(cert, k->pkey) > 0)
|
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);
|
return (done);
|
||||||
}
|
}
|
||||||
@ -1297,6 +1496,7 @@ static void set_trust(TLS_SESS_STATE *TLScontext, X509_STORE_CTX *ctx)
|
|||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
int i;
|
int i;
|
||||||
|
int match;
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
EVP_PKEY *takey;
|
EVP_PKEY *takey;
|
||||||
X509 *ca;
|
X509 *ca;
|
||||||
@ -1331,10 +1531,21 @@ static void set_trust(TLS_SESS_STATE *TLScontext, X509_STORE_CTX *ctx)
|
|||||||
ca = sk_X509_delete(in, i);
|
ca = sk_X509_delete(in, i);
|
||||||
|
|
||||||
/* Is it a trust anchor? */
|
/* Is it a trust anchor? */
|
||||||
if (tls_dane_match(TLScontext, TLS_DANE_TA, ca, depth + 1)) {
|
match = tls_dane_match(TLScontext, TLS_DANE_TA, ca, depth + 1);
|
||||||
if ((takey = X509_get_pubkey(ca)) != 0
|
if (match) {
|
||||||
&& wrap_key(TLScontext, takey, cert, depth))
|
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);
|
EVP_PKEY_free(takey);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg_panic("unexpected tls_dane_match result: %d", match);
|
||||||
|
}
|
||||||
cert = 0;
|
cert = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
/* char *var_tls_eecdh_strong;
|
/* char *var_tls_eecdh_strong;
|
||||||
/* char *var_tls_eecdh_ultra;
|
/* char *var_tls_eecdh_ultra;
|
||||||
/* char *var_tls_dane_ta_dgst;
|
/* char *var_tls_dane_ta_dgst;
|
||||||
|
/* char *var_tls_dane_digests;
|
||||||
/* int var_tls_daemon_rand_bytes;
|
/* int var_tls_daemon_rand_bytes;
|
||||||
/* bool var_tls_append_def_CA;
|
/* bool var_tls_append_def_CA;
|
||||||
/* bool var_tls_preempt_clist;
|
/* bool var_tls_preempt_clist;
|
||||||
@ -220,6 +221,7 @@ char *var_tls_null_clist;
|
|||||||
int var_tls_daemon_rand_bytes;
|
int var_tls_daemon_rand_bytes;
|
||||||
char *var_tls_eecdh_strong;
|
char *var_tls_eecdh_strong;
|
||||||
char *var_tls_eecdh_ultra;
|
char *var_tls_eecdh_ultra;
|
||||||
|
char *var_tls_dane_digests;
|
||||||
char *var_tls_dane_ta_dgst;
|
char *var_tls_dane_ta_dgst;
|
||||||
bool var_tls_append_def_CA;
|
bool var_tls_append_def_CA;
|
||||||
char *var_tls_bug_tweaks;
|
char *var_tls_bug_tweaks;
|
||||||
@ -227,6 +229,7 @@ char *var_tls_ssl_options;
|
|||||||
bool var_tls_bc_pkey_fprint;
|
bool var_tls_bc_pkey_fprint;
|
||||||
bool var_tls_multi_wildcard;
|
bool var_tls_multi_wildcard;
|
||||||
char *var_tls_mgr_service;
|
char *var_tls_mgr_service;
|
||||||
|
char *tls_dane_digests;
|
||||||
|
|
||||||
#ifdef VAR_TLS_PREEMPT_CLIST
|
#ifdef VAR_TLS_PREEMPT_CLIST
|
||||||
bool 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_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_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_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_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,
|
VAR_TLS_MGR_SERVICE, DEF_TLS_MGR_SERVICE, &var_tls_mgr_service, 1, 0,
|
||||||
0,
|
0,
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Proof-of-concept test program. Create, update or read a database. When
|
* Proof-of-concept test program. Create, update or read a database. Type
|
||||||
* the input is a name=value pair, the database is updated, otherwise the
|
* '?' for a list of commands.
|
||||||
* program assumes that the input specifies a lookup key and prints the
|
|
||||||
* corresponding value.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* System library. */
|
/* System library. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user