-TTLS_SERVER_INIT_PROPS
-TTLS_SERVER_START_PROPS
-TTLS_SESS_STATE
+-TTLS_TICKET_KEY
-TTLS_TLSA
-TTLS_VINFO
-TTLScontext_t
new MDB_MAP_FULL workaround by Howard Chu that ensures that
postfix will make progress as long as the disk is not full.
File: util/dict_lmdb.c.
+
+20130822
+
+ The status of LMDB databases is "not recommended". Unlike
+ other Postfix databases, LMDB does not grow beyond a specified
+ limit even when the file system has room. This show-stopper
+ bug breaks applications whose requirements grow with load:
+ postscreen(8), greylisting, tlsmgr(8) and verify(8).
+
+20130825
+
+ Bitrot: Arrange for shared keys in SMTP server session
+ tickets. Otherwise, with clients that enable session
+ tickets, the SMTP session cache is per-process and largely
+ ineffective. Older releases should add SSL_OP_NO_TICKET
+ to the SSL options bit mask in the SMTP server only. The
+ session ticket key validity interval (sum of initial issuing
+ and retired key validation intervals) must not exceed the
+ SSL session lifetime. Otherwise, clients may send valid
+ tickets for expired sessions, which the OpenSSL server code
+ mishandles (does not send a replacement ticket, patch
+ pending...).
+
+ We set the session lifetime to 2 times the configured cache
+ lifetime which is also the ticket issuing and retired
+ validation lifetime, so ticketed sessions last 1 to 2 times
+ the configured session lifetime and never longer than a
+ session's expiration time.
+
+ Code by Viktor Dukhovni. Files: .indent.pro, mantools/postlink,
+ proto/TLS_README.html, proto/postconf.proto, global/mail_params.h,
+ posttls-finger/posttls-finger.c, posttls-finger/tlsmgrmem.c,
+ smtpd/smtpd.c, tls/tls.h, tls/tls_client.c, tls/tls_mgr.c,
+ tls/tls_mgr.h, tls/tls_scache.c, tls/tls_scache.h,
+ tls/tls_server.c, tlsmgr/tlsmgr.c, tlsproxy/tlsproxy.c.
+
+ Robustness: Search for TLSA RRs at the resolved server name
+ (rname) and failing that request server name (qname), and
+ use whichever was found as the TLSA base domain for certificate
+ matching.
+
+ When we find a DNSSEC validated MX RRset, and the initial
+ next-hop domain is a CNAME, include both the initial and
+ final (the one with the actual MX RRs) domains in the list
+ of valid server certificate names.
+
+ When we find no MX records, then the initial next-hop domain
+ is obtained securely from the recipient domain or transport
+ next-hop. Without MX records, this is a destination hostname,
+ so we should generally do a TLSA lookup. If however the
+ address lookup yields an insecure result, and its rname is
+ equal to its qname (no CNAMEs), we reasonably assume that
+ the its child "_port._tcp" sub-domain is likewise insecure
+ (security here would require DLV just for this sub-domain).
+ This allows us to skip futile TLSA queries for most non-MX
+ destinations (those that are in insecure zones and are not
+ CNAMEs). This heuristic can be disabled by setting the new
+ main.cf parameter smtp_tls_force_insecure_host_tlsa_lookup
+ to "yes", the default is "no".
+
+ Finally, with MX hostnames, if the MX RRset is secure, we
+ look for TLSA RRs at the qname only when the MX host is an
+ alias with an insecure rname. If both the qname and the
+ rname are secure, as before we prefer the rname, but when
+ nothing is found there, fall back to the qname.
+
+ Code by Viktor Dukhovni. Files: mantools/postlink,
+ proto/postconf.proto, src/global/mail_params.h,
+ src/posttls-finger/posttls-finger.c, src/smtp/lmtp_params.c,
+ src/smtp/smtp.c, src/smtp/smtp.h, src/smtp/smtp_addr.c,
+ src/smtp/smtp_addr.h, src/smtp/smtp_connect.c,
+ src/smtp/smtp_params.c, src/smtp/smtp_tls_policy.c,
+ src/tls/tls.h, src/tls/tls_dane.c.
I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
+ W\bWa\bar\brn\bni\bin\bng\bg:\b: L\bLM\bMD\bDB\bB d\bda\bat\bta\bab\bba\bas\bse\bes\bs h\bha\bav\bve\be a\ba s\bsh\bho\bow\bw-\b-s\bst\bto\bop\bpp\bpe\ber\br b\bbu\bug\bg:\b: t\bth\bhe\bey\by d\bdo\bo n\bno\bot\bt g\bgr\bro\bow\bw b\bbe\bey\byo\bon\bnd\bd a\ba
+ s\bsp\bpe\bec\bci\bif\bfi\bie\bed\bd l\bli\bim\bmi\bit\bt,\b, a\ban\bnd\bd i\bin\bnt\btr\bro\bod\bdu\buc\bce\be a\ba "\b"d\bda\bat\bta\bab\bba\bas\bse\be f\bfu\bul\bll\bl"\b" h\bha\bar\brd\bd e\ber\brr\bro\bor\br c\bco\bon\bnd\bdi\bit\bti\bio\bon\bn t\bth\bha\bat\bt
+ d\bdo\boe\bes\bs n\bno\bot\bt e\bex\bxi\bis\bst\bt w\bwi\bit\bth\bh a\ban\bny\by o\bot\bth\bhe\ber\br P\bPo\bos\bst\btf\bfi\bix\bx d\bda\bat\bta\bab\bba\bas\bse\be t\bty\byp\bpe\be.\b. T\bTh\bhi\bis\bs i\bis\bs a\ba p\bpr\bro\bob\bbl\ble\bem\bm f\bfo\bor\br
+ p\bpr\bro\bog\bgr\bra\bam\bms\bs w\bwh\bho\bos\bse\be d\bda\bat\bta\bab\bba\bas\bse\be g\bgr\bro\bow\bws\bs w\bwi\bit\bth\bh s\bsy\bys\bst\bte\bem\bm l\blo\boa\bad\bd.\b. E\bEx\bxa\bam\bmp\bpl\ble\bes\bs a\bar\bre\be p\bpo\bos\bst\bts\bsc\bcr\bre\bee\ben\bn(\b(8\b8)\b),\b,
+ g\bgr\bre\bey\byl\bli\bis\bst\bti\bin\bng\bg,\b, v\bve\ber\bri\bif\bfy\by(\b(8\b8)\b) a\ban\bnd\bd t\btl\bls\bsm\bmg\bgr\br(\b(8\b8)\b).\b.
+
+ Y\bYo\bou\bu h\bha\bav\bve\be b\bbe\bee\ben\bn w\bwa\bar\brn\bne\bed\bd.\b.
+
Postfix uses databases of various kinds to store and look up information.
Postfix databases are specified as "type:name". OpenLDAP LMDB implements the
Postfix database type "lmdb". The name of a Postfix OpenLDAP LMDB database is
S\bSe\ber\brv\bve\ber\br-\b-s\bsi\bid\bde\be T\bTL\bLS\bS s\bse\bes\bss\bsi\bio\bon\bn c\bca\bac\bch\bhe\be
The Postfix SMTP server and the remote SMTP client negotiate a session, which
-takes some computer time and network bandwidth. By default, this session
-information is cached only in the smtpd(8) process actually using this session
-and is lost when the process terminates. To share the session information
-between multiple smtpd(8) processes, a persistent session cache can be used.
-You can specify any database type that can store objects of several kbytes and
-that supports the sequence operator. DBM databases are not suitable because
-they can only store small objects. The cache is maintained by the tlsmgr(8)
-process, so there is no problem with concurrent access. Session caching is
-highly recommended, because the cost of repeatedly negotiating TLS session keys
-is high.
+takes some computer time and network bandwidth. SSL protocol versions other
+than SSLv2 support resumption of cached sessions. Not only is this more CPU and
+bandwidth efficient, it also reduces latency as only one network round-trip is
+used to resume a session while it takes two round-trips to create a session
+from scratch.
+
+Since Postfix uses multiple smtpd(8) service processes, an in-memory cache is
+not sufficient for session re-use. Clients store at most one cached session per
+server and are very unlikey to repeatedly connect to the same server process.
+Thus session caching in the Postfix SMTP server generally requires a shared
+cache (an alternative available with Postfix >= 2.11 is described below).
+
+To share the session information between multiple smtpd(8) processes, a session
+cache database is used. You can specify any database type that can store
+objects of several kbytes and that supports the sequence operator. DBM
+databases are not suitable because they can only store small objects. The cache
+is maintained by the tlsmgr(8) process, so there is no problem with concurrent
+access. Session caching is highly recommended, because the cost of repeatedly
+negotiating TLS session keys is high.
+
+Starting with Postfix 2.11, linked with a compatible OpenSSL library (at least
+0.9.8h, preferably 1.0.0 or later) the Postfix SMTP server supports RFC 5077
+TLS session resumption without server-side state when the remote SMTP client
+also supports RFC 5077. The session is encrypted by the server in a session
+ticket returned to client for storage. When a client sends a valid session
+ticket, the server decrypts it and resumes the session, provided neither the
+ticket nor the session have expired. This makes it possible to resume cached
+sessions without allocating space for a shared database on the server. This
+feature can be disabled by setting the session cache timeout to zero, otherwise
+the timeout must be at least 2 minutes and at most 100 days.
+
+Note, session tickets can only be negotiated if the client disables SSLv2 and
+does not use the legacy SSLv2 compatible HELLO message. This is true by default
+with the Postfix >= 2.6 SMTP client.
Example:
/etc/postfix/main.cf:
smtpd_tls_session_cache_timeout = 3600s
+As of Postfix 2.11 this setting cannot exceed 100 days. If set <= 0, session
+caching is disabled. If set to a positive value less than 2 minutes, the
+minimum value of 2 minutes is used instead.
+
When the Postfix SMTP server does not save TLS sessions to an external cache
-database, client-side session caching is unlikely to be useful. To prevent such
-wastage, the Postfix SMTP server can be configured to not issue TLS session
-ids. By default the Postfix SMTP server always issues TLS session ids. This
-works around known interoperability issues with some MUAs, and prevents
+database, client-side session caching is unlikely to be useful. To reduce waste
+of client resources, the Postfix SMTP server can be configured to not issue TLS
+session ids. By default the Postfix SMTP server always issues TLS session ids.
+This works around known interoperability issues with some MUAs, and prevents
possible interoperability issues with other MTAs.
Example:
/etc/postfix/main.cf:
smtp_tls_session_cache_timeout = 3600s
+As of Postfix 2.11 this setting cannot exceed 100 days. If set <= 0, session
+caching is disabled. If set to a positive value less than 2 minutes, the
+minimum value of 2 minutes is used instead.
+
C\bCl\bli\bie\ben\bnt\bt T\bTL\bLS\bS l\bli\bim\bmi\bit\bta\bat\bti\bio\bon\bns\bs
The security properties of TLS communication channels are application specific.
<h2>Introduction</h2>
-<!--
-
-<dl> <dt> Note: </dt> <dd> <p> Postfix support for LMDB databases
-is suspended due to the existence of a hard limit (an "out of
-storage" failure mode that cannot be resolved by increasing the
-database size). </p> <p> Postfix may support LMDB again when it no
-longer limits the size of Postfix transactions, whether the limit
-is built into LMDB itself, or implicit by requiring an unbounded
-amount of memory to handle a large transaction. </p> </dd> </dl>
-
--->
+<blockquote> <p> <strong> Warning: LMDB databases have a show-stopper
+bug: they do not grow beyond a specified limit, and introduce a
+"database full" hard error condition that does not exist with any
+other Postfix database type. This is a problem for programs whose
+database grows with system load. Examples are <a href="postscreen.8.html">postscreen(8)</a>,
+greylisting, <a href="verify.8.html">verify(8)</a> and <a href="tlsmgr.8.html">tlsmgr(8)</a>. </strong> </p> <p> <strong>
+You have been warned. </strong> </p> </blockquote>
<p> Postfix uses databases of various kinds to store and look up
information. Postfix databases are specified as "type:name".
<h3><a name="server_tls_cache">Server-side TLS session cache</a> </h3>
-<p> The Postfix SMTP server and the remote SMTP client negotiate
-a session, which takes some computer time and network bandwidth.
-SSLv3, TLSv1 and later support resumption of cached sessions. Not
-is this more CPU and bandwidth efficient, it also reduces latency
-as it uses only one network round-trip instead of two. </p>
-
-<p> Since Postfix uses multiple <a href="smtpd.8.html">smtpd(8)</a> service processes, an in
-memory cache is not sufficient for session re-use. Clients store
+<p> The Postfix SMTP server and the remote SMTP client negotiate a
+session, which takes some computer time and network bandwidth. SSL
+protocol versions other than SSLv2 support resumption of cached
+sessions. Not only is this more CPU and bandwidth efficient, it
+also reduces latency as only one network round-trip is used to
+resume a session while it takes two round-trips to create a session
+from scratch. </p>
+
+<p> Since Postfix uses multiple <a href="smtpd.8.html">smtpd(8)</a> service processes, an
+in-memory cache is not sufficient for session re-use. Clients store
at most one cached session per server and are very unlikey to
-repeatedly connect to the same server process. With a per-process
-server cache, when a client attempts to reuse a session with a
-different process than the one that created it, a new session is
-negotiated and the old forgotten. Returning to the original server
-process later (except with back to back connections) does not help,
-as that session has most probably been replaced. Thus session
-caching in the Postfix SMTP server generally requires a shared cache
-(an alternative available with Postfix ≥ 2.11 is described below).
+repeatedly connect to the same server process. Thus session caching
+in the Postfix SMTP server generally requires a shared cache (an
+alternative available with Postfix ≥ 2.11 is described below).
</p>
<p> To share the session information between multiple
the cost of repeatedly negotiating TLS session keys is high.</p>
<p> Starting with Postfix 2.11, linked with a compatible OpenSSL
-library (at least 0.9.8h, preferrably 1.0.0 or later) the Postfix
+library (at least 0.9.8h, preferably 1.0.0 or later) the Postfix
SMTP server supports <a href="http://tools.ietf.org/html/rfc5077">RFC 5077</a> TLS session resumption without
server-side state when the remote SMTP client also supports <a href="http://tools.ietf.org/html/rfc5077">RFC</a>
<a href="http://tools.ietf.org/html/rfc5077">5077</a>. The session is encrypted by the server in a <i>session
</pre>
</blockquote>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled. If set to a positive value
+less than 2 minutes, the minimum value of 2 minutes is used instead. </p>
+
<p> When the Postfix SMTP server does not save TLS sessions to an
external cache database, client-side session caching is unlikely
to be useful. To reduce waste of client resources, the Postfix SMTP server can
</pre>
</blockquote>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled. If set to a positive value
+less than 2 minutes, the minimum value of 2 minutes is used instead. </p>
+
<h3><a name="client_tls_limits"> Client TLS limitations </a>
</h3>
low privilege.
<b>STANDARDS</b>
- None.
+ <a href="http://tools.ietf.org/html/rfc3463">RFC 3463</a> (Enhanced Status Codes)
<b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8).
Zero or more PEM-format files with trust-anchor
certificates and/or public keys.
- <b>smtp_tls_dane_notfound_tlsa_level (may)</b>
- The "degraded" security level when the "dane" secu-
- rity level is specified, but no validated DANE TLSA
- records are published.
-
- <b>smtp_tls_dane_unusable_tlsa_level (encrypt)</b>
- The "degraded" security level when the "dane" secu-
- rity level is specified, validated DANE TLSA
- records are present, but none are usable.
+ <b><a href="postconf.5.html#smtp_tls_force_insecure_host_tlsa_lookup">smtp_tls_force_insecure_host_tlsa_lookup</a> (no)</b>
+ Lookup the associated DANE TLSA RRset even when a
+ hostname is not an alias and its address records
+ lie in an unsigned zone.
<b><a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> (trust-anchor-asser-</b>
<b>tion)</b>
<p> This feature is available in Postfix 2.5 and later. </p>
+</DD>
+
+<DT><b><a name="lmtp_tls_force_insecure_host_tlsa_lookup">lmtp_tls_force_insecure_host_tlsa_lookup</a>
+(default: no)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_force_insecure_host_tlsa_lookup">smtp_tls_force_insecure_host_tlsa_lookup</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.11 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_tls_key_file">lmtp_tls_key_file</a>
<p> This feature is available in Postfix 2.5 and later. </p>
+</DD>
+
+<DT><b><a name="smtp_tls_force_insecure_host_tlsa_lookup">smtp_tls_force_insecure_host_tlsa_lookup</a>
+(default: no)</b></DT><DD>
+
+<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
+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
+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>
+
+
</DD>
<DT><b><a name="smtp_tls_key_file">smtp_tls_key_file</a>
<a href="tlsmgr.8.html">tlsmgr(8)</a> daemon and therefore per-smtp-instance <a href="master.5.html">master.cf</a> overrides
are not possible. </p>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled. If set to a positive value
+less than 2 minutes, the minimum value of 2 minutes is used instead. </p>
+
<p> This feature is available in Postfix 2.2 and later. </p>
<a href="tlsmgr.8.html">tlsmgr(8)</a> daemon and therefore per-smtpd-instance <a href="master.5.html">master.cf</a> overrides
are not possible. </p>
-<p> This feature is available in Postfix 2.2 and later. </p>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled, not just via the database, but
+also via <a href="http://tools.ietf.org/html/rfc5077">RFC 5077</a> TLS session tickets, which don't require server-side
+storage. If set to a positive value less than 2 minutes, the minimum
+value of 2 minutes is used instead. TLS session tickets require
+an OpenSSL library (at least version 0.9.8h) that provides full
+support for this TLS extension. </p>
+
+<p> This feature is available in Postfix 2.2 and later, and updated
+for TLS session ticket support in Postfix 2.11. </p>
</DD>
<DT><b><a name="tlsproxy_tls_session_cache_timeout">tlsproxy_tls_session_cache_timeout</a>
(default: $<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a>)</b></DT><DD>
-<p> The expiration time of Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server TLS session
-cache information. A cache cleanup is performed periodically every
-$<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a> seconds. See
-<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a> for further details. </p>
+<p> Obsolete expiration time of Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> server TLS session
+cache information. Since the cache is shared with <a href="smtpd.8.html">smtpd(8)</a> and managed
+by <a href="tlsmgr.8.html">tlsmgr(8)</a>, there is only one expiration time for the SMTP server cache
+shared by all three services, namely <a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a>. </p>
<p> This feature is available in Postfix 2.8 and later. </p>
(with DANE TLSA records the algorithm is specified
in the DNS).
+ <b>-f</b> Lookup the associated DANE TLSA RRset even when a
+ hostname is not an alias and its address records
+ lie in an unsigned zone. See smtp_tls_force_inse-
+ cure_host_tlsa_lookup for details.
+
<b>-F</b> <i>CAfile.pem</i> (default: none)
- The PEM formatted CAfile for remote SMTP server
- certificate verification. By default no CAfile is
+ The PEM formatted CAfile for remote SMTP server
+ certificate verification. By default no CAfile is
used and no public CAs are trusted.
<b>-g</b> <i>grade</i> (default: medium)
- The minimum TLS cipher grade used by posttls-fin-
+ The minimum TLS cipher grade used by posttls-fin-
ger. See <a href="postconf.5.html#smtp_tls_mandatory_ciphers">smtp_tls_mandatory_ciphers</a> for details.
<b>-h</b> <i>host</i><b>_</b><i>lookup</i> (default: <b>dns</b>)
- The hostname lookup methods used for the connec-
- tion. See the documentation of <a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a>
+ The hostname lookup methods used for the connec-
+ tion. See the documentation of <a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a>
for syntax and semantics.
<b>-l</b> <i>level</i> (default: <b>dane</b> or <b>secure</b>)
The security level for the connection, default <b>dane</b>
or <b>secure</b> depending on whether DNSSEC is available.
- For syntax and semantics, see the documentation of
+ For syntax and semantics, see the documentation of
<a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a>. When <b>dane</b> or <b>dane-only</b> is
- supported and selected, if no TLSA records are
- found, or all the records found are unusable, the
+ supported and selected, if no TLSA records are
+ found, or all the records found are unusable, the
<i>secure</i> level will be used instead. The <b>fingerprint</b>
- security level allows you to test certificate or
- public-key fingerprint matches before you deploy
+ security level allows you to test certificate or
+ public-key fingerprint matches before you deploy
them in the policy table.
- Note, since <b>posttls-finger</b> does not actually
- deliver any email, the <b>none</b>, <b>may</b> and <b>encrypt</b> secu-
- rity levels are not very useful. Since <b>may</b> and
- <b>encrypt</b> don't require peer certificates, they will
- often negotiate anonymous TLS ciphersuites, so you
- won't learn much about the remote SMTP server's
- certificates at these levels if it also supports
+ Note, since <b>posttls-finger</b> does not actually
+ deliver any email, the <b>none</b>, <b>may</b> and <b>encrypt</b> secu-
+ rity levels are not very useful. Since <b>may</b> and
+ <b>encrypt</b> don't require peer certificates, they will
+ often negotiate anonymous TLS ciphersuites, so you
+ won't learn much about the remote SMTP server's
+ certificates at these levels if it also supports
anonymous TLS (though you may learn that the server
supports anonymous TLS).
<b>-L</b> <i>logopts</i> (default: <b>routine,certmatch</b>)
- Fine-grained TLS logging options. To tune the TLS
- features logged during the TLS handshake, specify
+ Fine-grained TLS logging options. To tune the TLS
+ features logged during the TLS handshake, specify
one or more of:
<b>0, none</b>
These yield no TLS logging; you'll generally
- want more, but this is handy if you just
+ want more, but this is handy if you just
want the trust chain:
$ posttls-finger -cC -L none destination
<b>1, routine, summary</b>
- These synonymous values yield a normal one-
+ These synonymous values yield a normal one-
line summary of the TLS connection.
<b>2, debug</b>
ssl-debug, cache and verbose.
<b>3, ssl-expert</b>
- These synonymous values combine debug with
- ssl-handshake-packet-dump. For experts
+ These synonymous values combine debug with
+ ssl-handshake-packet-dump. For experts
only.
<b>4, ssl-developer</b>
- These synonymous values combine ssl-expert
- with ssl-session-packet-dump. For experts
+ These synonymous values combine ssl-expert
+ with ssl-session-packet-dump. For experts
only, and in most cases, use wireshark
instead.
<b>ssl-debug</b>
- Turn on OpenSSL logging of the progress of
+ Turn on OpenSSL logging of the progress of
the SSL handshake.
<b>ssl-handshake-packet-dump</b>
- Log hexadecimal packet dumps of the SSL
+ Log hexadecimal packet dumps of the SSL
handshake; for experts only.
<b>ssl-session-packet-dump</b>
- Log hexadecimal packet dumps of the entire
- SSL session; only useful to those who can
- debug SSL protocol problems from hex dumps.
+ Log hexadecimal packet dumps of the entire
+ SSL session; only useful to those who can
+ debug SSL protocol problems from hex dumps.
<b>untrusted</b>
- Logs trust chain verification problems.
- This is turned on automatically at security
- levels that use peer names signed by cer-
- tificate authorities to validate certifi-
+ Logs trust chain verification problems.
+ This is turned on automatically at security
+ levels that use peer names signed by cer-
+ tificate authorities to validate certifi-
cates. So while this setting is recognized,
- you should never need to set it explicitly.
+ you should never need to set it explicitly.
<b>peercert</b>
- This logs a one line summary of the remote
+ This logs a one line summary of the remote
SMTP server certificate subject, issuer, and
fingerprints.
<b>certmatch</b>
- This logs remote SMTP server certificate
- matching, showing the CN and each subjec-
+ This logs remote SMTP server certificate
+ matching, showing the CN and each subjec-
tAltName and which name matched. With DANE,
- logs matching of TLSA record trust-anchor
+ logs matching of TLSA record trust-anchor
and end-entity certificates.
- <b>cache</b> This logs session cache operations, showing
- whether session caching is effective with
- the remote SMTP server. Automatically used
+ <b>cache</b> This logs session cache operations, showing
+ whether session caching is effective with
+ the remote SMTP server. Automatically used
when reconnecting with the <b>-r</b> option; rarely
needs to be set explicitly.
<b>verbose</b>
- Enables verbose logging in the Postfix TLS
- driver; includes all of peercert..cache and
+ Enables verbose logging in the Postfix TLS
+ driver; includes all of peercert..cache and
more.
- The default is <b>routine,certmatch</b>. After a recon-
+ The default is <b>routine,certmatch</b>. After a recon-
nect, <b>peercert</b>, <b>certmatch</b> and <b>verbose</b> are automati-
cally disabled while <b>cache</b> and <b>summary</b> are enabled.
<b>-m</b> <i>count</i> (default: <b>5</b>)
- When the <b>-r</b> <i>delay</i> option is specified, the <b>-m</b>
- option determines the maximum number of reconnect
- attempts to use with a server behind a load-bal-
- acer, to see whether connection caching is likely
- to be effective for this destination. Some MTAs
- don't expose the underlying server identity in
- their EHLO response; with these servers there will
+ When the <b>-r</b> <i>delay</i> option is specified, the <b>-m</b>
+ option determines the maximum number of reconnect
+ attempts to use with a server behind a load-bal-
+ acer, to see whether connection caching is likely
+ to be effective for this destination. Some MTAs
+ don't expose the underlying server identity in
+ their EHLO response; with these servers there will
never be more than 1 reconnection attempt.
<b>-o</b> <i>name=value</i>
Specify zero or more times to override the value of
- the <a href="postconf.5.html">main.cf</a> parameter <i>name</i> with <i>value</i>. Possible
- use-cases include overriding the values of TLS
- library parameters, or "<a href="postconf.5.html#myhostname">myhostname</a>" to configure
+ the <a href="postconf.5.html">main.cf</a> parameter <i>name</i> with <i>value</i>. Possible
+ use-cases include overriding the values of TLS
+ library parameters, or "<a href="postconf.5.html#myhostname">myhostname</a>" to configure
the SMTP EHLO name sent to the remote server.
<b>-p</b> <i>protocols</i> (default: !SSLv2)
- List of TLS protocols that posttls-finger will
- exclude or include. See smtp_tls_mandatory_proto-
+ List of TLS protocols that posttls-finger will
+ exclude or include. See smtp_tls_mandatory_proto-
cols for details.
<b>-P</b> <i>CApath/</i> (default: none)
- The OpenSSL CApath/ directory (indexed via
- c_rehash(1)) for remote SMTP server certificate
- verification. By default no CApath is used and no
+ The OpenSSL CApath/ directory (indexed via
+ c_rehash(1)) for remote SMTP server certificate
+ verification. By default no CApath is used and no
public CAs are trusted.
<b>-r</b> <i>delay</i>
- With a cachable TLS session, disconnect and recon-
- nect after <i>delay</i> seconds. Report whether the ses-
- sion is re-used. Retry if a new server is encoun-
- tered, up to 5 times or as specified with the <b>-m</b>
+ With a cachable TLS session, disconnect and recon-
+ nect after <i>delay</i> seconds. Report whether the ses-
+ sion is re-used. Retry if a new server is encoun-
+ tered, up to 5 times or as specified with the <b>-m</b>
option. By default reconnection is disabled, spec-
ify a positive delay to enable this behavior.
- <b>-S</b> Disable SMTP; that is, connect to an LMTP server.
+ <b>-S</b> Disable SMTP; that is, connect to an LMTP server.
The default port for LMTP over TCP is 24. Alterna-
- tive ports can specified by appending "<i>:service-</i>
+ tive ports can specified by appending "<i>:service-</i>
<i>name</i>" or ":<i>portnumber</i>" to the destination argument.
<b>-t</b> <i>timeout</i> (default: <b>5</b>)
- The TCP connection timeout to use. This is also
- the timeout for reading the remote server's 220
+ The TCP connection timeout to use. This is also
+ the timeout for reading the remote server's 220
banner.
<b>-T</b> <i>timeout</i> (default: <b>30</b>)
The SMTP/LMTP command timeout for EHLO/LHLO, START-
TLS and QUIT.
- <b>-v</b> Enable verose Postfix logging. Specify more than
+ <b>-v</b> Enable verose Postfix logging. Specify more than
once to increase the level of verbose logging.
[<b>inet:</b>]<i>domain</i>[:<i>port</i>]
- Connect via TCP to domain <i>domain</i>, port <i>port</i>. The
- default port is <b>smtp</b> (or 24 with LMTP). With SMTP
- an MX lookup is performed to resolve the domain to
- a host, unless the domain is enclosed in <b>[]</b>. If
- you want to connect to a specific MX host, for
+ Connect via TCP to domain <i>domain</i>, port <i>port</i>. The
+ default port is <b>smtp</b> (or 24 with LMTP). With SMTP
+ an MX lookup is performed to resolve the domain to
+ a host, unless the domain is enclosed in <b>[]</b>. If
+ you want to connect to a specific MX host, for
instance <i>mx1.example.com</i>, specify [<i>mx1.example.com</i>]
as the destination and <i>example.com</i> as a <b>match</b> argu-
- ment. When using DNS, the destination domain is
- assumed fully qualified and no <a href="ADDRESS_CLASS_README.html#default_domain_class">default domain</a> or
- search suffixes are applied; you must use fully-
- qualified names or also enable <b>native</b> host lookups
+ ment. When using DNS, the destination domain is
+ assumed fully qualified and no default domain or
+ search suffixes are applied; you must use fully-
+ qualified names or also enable <b>native</b> host lookups
(these don't support <b>dane</b> or <b>dane-only</b> as no DNSSEC
validation information is available via <b>native</b>
lookups).
With no match arguments specified, certificate
peername matching uses the compiled-in default
strategies for each security level. If you specify
- one or more arguments, these will be used as the
- list of certificate or public-key digests to match
- for the <b>fingerprint</b> level, or as the list of DNS
+ one or more arguments, these will be used as the
+ list of certificate or public-key digests to match
+ for the <b>fingerprint</b> level, or as the list of DNS
names to match in the certificate at the <b>verify</b> and
- <b>secure</b> levels. If the security level is <b>dane</b>, or
- <b>dane-only</b> the match names are ignored, and <b>host-</b>
+ <b>secure</b> levels. If the security level is <b>dane</b>, or
+ <b>dane-only</b> the match names are ignored, and <b>host-</b>
<b>name, nexthop</b> strategies are used.
<b>ENVIRONMENT</b>
<b>MAIL_CONFIG</b>
- Read configuration parameters from a non-default
+ Read configuration parameters from a non-default
location.
<b>MAIL_VERBOSE</b>
<a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
Zero or more PEM-format files with trust-anchor
certificates and/or public keys.
- <b>smtp_tls_dane_notfound_tlsa_level (may)</b>
- The "degraded" security level when the "dane" secu-
- rity level is specified, but no validated DANE TLSA
- records are published.
-
- <b>smtp_tls_dane_unusable_tlsa_level (encrypt)</b>
- The "degraded" security level when the "dane" secu-
- rity level is specified, validated DANE TLSA
- records are present, but none are usable.
+ <b><a href="postconf.5.html#smtp_tls_force_insecure_host_tlsa_lookup">smtp_tls_force_insecure_host_tlsa_lookup</a> (no)</b>
+ Lookup the associated DANE TLSA RRset even when a
+ hostname is not an alias and its address records
+ lie in an unsigned zone.
<b><a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> (trust-anchor-asser-</b>
<b>tion)</b>
remote SMTP client certificate in order to allow
TLS connections to proceed.
- <b><a href="postconf.5.html#smtpd_tls_session_cache_database">smtpd_tls_session_cache_database</a> (empty)</b>
- Name of the file containing the optional Postfix
- SMTP server TLS session cache.
-
- <b><a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a> (3600s)</b>
- The expiration time of Postfix SMTP server TLS ses-
- sion cache information.
-
<b><a href="postconf.5.html#smtpd_tls_wrappermode">smtpd_tls_wrappermode</a> (no)</b>
Run the Postfix SMTP server in the non-standard
"wrapper" mode, instead of using the STARTTLS com-
ified, this overrides the obsolete parameters
<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> and <a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>.
- <b><a href="postconf.5.html#tlsproxy_tls_session_cache_timeout">tlsproxy_tls_session_cache_timeout</a> ($<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_ses</a>-</b>
- <b><a href="postconf.5.html#smtpd_tls_session_cache_timeout">sion_cache_timeout</a>)</b>
- The expiration time of Postfix <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> server
- TLS session cache information.
-
Available in Postfix version 2.11 and later:
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b>
- The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in mas-
+ The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in mas-
ter.cf.
<b>OBSOLETE STARTTLS SUPPORT CONTROLS</b>
- These parameters are supported for compatibility with
+ These parameters are supported for compatibility with
<a href="smtpd.8.html"><b>smtpd</b>(8)</a> legacy parameters.
<b><a href="postconf.5.html#tlsproxy_use_tls">tlsproxy_use_tls</a> ($<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b>
- Opportunistic TLS: announce STARTTLS support to
+ Opportunistic TLS: announce STARTTLS support to
remote SMTP clients, but do not require that
clients use TLS encryption.
<b><a href="postconf.5.html#tlsproxy_enforce_tls">tlsproxy_enforce_tls</a> ($<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b>
- Mandatory TLS: announce STARTTLS support to remote
- SMTP clients, and require that clients use TLS
+ Mandatory TLS: announce STARTTLS support to remote
+ SMTP clients, and require that clients use TLS
encryption.
<b>RESOURCE CONTROLS</b>
<b><a href="postconf.5.html#tlsproxy_watchdog_timeout">tlsproxy_watchdog_timeout</a> (10s)</b>
- How much time a <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> process may take to
+ How much time a <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> process may take to
process local or remote I/O before it is terminated
by a built-in watchdog timer.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
syslogd(5), system logging
<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>
fingerprints and matching against user provided certificate
fingerprints (with DANE TLSA records the algorithm is specified
in the DNS).
+.IP "\fB-f\fR"
+Lookup the associated DANE TLSA RRset even when a hostname is not an
+alias and its address records lie in an unsigned zone. See
+smtp_tls_force_insecure_host_tlsa_lookup for details.
.IP "\fB-F \fICAfile.pem\fR (default: none)"
The PEM formatted CAfile for remote SMTP server certificate
verification. By default no CAfile is used and no public CAs
configuration parameter. See there for details.
.PP
This feature is available in Postfix 2.5 and later.
+.SH lmtp_tls_force_insecure_host_tlsa_lookup (default: no)
+The LMTP-specific version of the smtp_tls_force_insecure_host_tlsa_lookup
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.11 and later.
.SH lmtp_tls_key_file (default: $lmtp_tls_cert_file)
The LMTP-specific version of the smtp_tls_key_file
configuration parameter. See there for details.
to Postfix 2.9.6 or later.
.PP
This feature is available in Postfix 2.5 and later.
+.SH smtp_tls_force_insecure_host_tlsa_lookup (default: no)
+Lookup the associated DANE TLSA RRset even when a hostname is
+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
+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
+interoperability problems with nameservers for unsigned zones that
+are not prepared to handle the new TLSA RRset.
+.PP
+This feature is available in Postfix 2.11.
.SH smtp_tls_key_file (default: $smtp_tls_cert_file)
File with the Postfix SMTP client RSA private key in PEM format.
This file may be combined with the Postfix SMTP client RSA certificate
\fBtlsmgr\fR(8) daemon and therefore per-smtp-instance master.cf overrides
are not possible.
.PP
+As of Postfix 2.11 this setting cannot exceed 100 days. If set
+<= 0, session caching is disabled. If set to a positive value
+less than 2 minutes, the minimum value of 2 minutes is used instead.
+.PP
This feature is available in Postfix 2.2 and later.
.SH smtp_tls_trust_anchor_file (default: empty)
Zero or more PEM-format files with trust-anchor certificates
\fBtlsmgr\fR(8) daemon and therefore per-smtpd-instance master.cf overrides
are not possible.
.PP
-This feature is available in Postfix 2.2 and later.
+As of Postfix 2.11 this setting cannot exceed 100 days. If set
+<= 0, session caching is disabled, not just via the database, but
+also via RFC 5077 TLS session tickets, which don't require server-side
+storage. If set to a positive value less than 2 minutes, the minimum
+value of 2 minutes is used instead. TLS session tickets require
+an OpenSSL library (at least version 0.9.8h) that provides full
+support for this TLS extension.
+.PP
+This feature is available in Postfix 2.2 and later, and updated
+for TLS session ticket support in Postfix 2.11.
.SH smtpd_tls_wrappermode (default: no)
Run the Postfix SMTP server in the non-standard "wrapper" mode,
instead of using the STARTTLS command.
.PP
This feature is available in Postfix 2.8 and later.
.SH tlsproxy_tls_session_cache_timeout (default: $smtpd_tls_session_cache_timeout)
-The expiration time of Postfix \fBtlsproxy\fR(8) server TLS session
-cache information. A cache cleanup is performed periodically every
-$smtpd_tls_session_cache_timeout seconds. See
-smtpd_tls_session_cache_timeout for further details.
+Obsolete expiration time of Postfix \fBtlsproxy\fR(8) server TLS session
+cache information. Since the cache is shared with \fBsmtpd\fR(8) and managed
+by \fBtlsmgr\fR(8), there is only one expiration time for the SMTP server cache
+shared by all three services, namely smtpd_tls_session_cache_timeout.
.PP
This feature is available in Postfix 2.8 and later.
.SH tlsproxy_use_tls (default: $smtpd_use_tls)
.SH "STANDARDS"
.na
.nf
-None.
+RFC 3463 (Enhanced Status Codes)
.SH DIAGNOSTICS
.ad
.fi
.IP "\fBsmtp_tls_trust_anchor_file (empty)\fR"
Zero or more PEM-format files with trust-anchor certificates
and/or public keys.
-.IP "\fBsmtp_tls_dane_notfound_tlsa_level (may)\fR"
-The "degraded" security level when the "dane" security level
-is specified, but no validated DANE TLSA records are published.
-.IP "\fBsmtp_tls_dane_unusable_tlsa_level (encrypt)\fR"
-The "degraded" security level when the "dane" security level
-is specified, validated DANE TLSA records are present, but none are
-usable.
+.IP "\fBsmtp_tls_force_insecure_host_tlsa_lookup (no)\fR"
+Lookup the associated DANE TLSA RRset even when a hostname is
+not an alias and its address records lie in an unsigned zone.
.IP "\fBtls_dane_trust_anchor_digest_enable (trust-anchor-assertion)\fR"
RFC 6698 trust-anchor digest support in the Postfix TLS library.
.IP "\fBtlsmgr_service_name (tlsmgr)\fR"
.PP
Available in Postfix version 2.11 and later:
.IP "\fBsmtp_connection_reuse_count_limit (0)\fR"
-When SMTP connection caching is enabled, the number of times that
-an SMTP session may be reused before it is closed, or zero (no limit).
+When SMTP connection caching is enabled, the number of times
+that an SMTP session may be reused before it is closed, or zero (no
+limit).
.SH "TROUBLE SHOOTING CONTROLS"
.na
.nf
.IP "\fBsmtpd_tls_req_ccert (no)\fR"
With mandatory TLS encryption, require a trusted remote SMTP client
certificate in order to allow TLS connections to proceed.
-.IP "\fBsmtpd_tls_session_cache_database (empty)\fR"
-Name of the file containing the optional Postfix SMTP server
-TLS session cache.
-.IP "\fBsmtpd_tls_session_cache_timeout (3600s)\fR"
-The expiration time of Postfix SMTP server TLS session cache
-information.
.IP "\fBsmtpd_tls_wrappermode (no)\fR"
Run the Postfix SMTP server in the non-standard "wrapper" mode,
instead of using the STARTTLS command.
The SMTP TLS security level for the Postfix \fBtlsproxy\fR(8) server;
when a non-empty value is specified, this overrides the obsolete
parameters smtpd_use_tls and smtpd_enforce_tls.
-.IP "\fBtlsproxy_tls_session_cache_timeout ($smtpd_tls_session_cache_timeout)\fR"
-The expiration time of Postfix \fBtlsproxy\fR(8) server TLS session
-cache information.
.PP
Available in Postfix version 2.11 and later:
.IP "\fBtlsmgr_service_name (tlsmgr)\fR"
s;\blmtp_tls_enforce_peername\b;<a href="postconf.5.html#lmtp_tls_enforce_peername">$&</a>;g;
s;\blmtp_tls_note_starttls_offer\b;<a href="postconf.5.html#lmtp_tls_note_starttls_offer">$&</a>;g;
s;\blmtp_tls_block_early_mail_reply\b;<a href="postconf.5.html#lmtp_tls_block_early_mail_reply">$&</a>;g;
+ s;\blmtp_tls_force_insecure_host_tlsa_lookup\b;<a href="postconf.5.html#lmtp_tls_force_insecure_host_tlsa_lookup">$&</a>;g;
s;\blmtp_sender_dependent_authentication\b;<a href="postconf.5.html#lmtp_sender_dependent_authentication">$&</a>;g;
s;\blmtp_sasl_path\b;<a href="postconf.5.html#lmtp_sasl_path">$&</a>;g;
s;\blmtp_lhlo_name\b;<a href="postconf.5.html#lmtp_lhlo_name">$&</a>;g;
s;\bsmtp_tls_session_cache_database\b;<a href="postconf.5.html#smtp_tls_session_cache_database">$&</a>;g;
s;\bsmtp_tls_session_cache_timeout\b;<a href="postconf.5.html#smtp_tls_session_cache_timeout">$&</a>;g;
s;\bsmtp_tls_block_early_mail_reply\b;<a href="postconf.5.html#smtp_tls_block_early_mail_reply">$&</a>;g;
+ s;\bsmtp_tls_force_insecure_host_tlsa_lookup\b;<a href="postconf.5.html#smtp_tls_force_insecure_host_tlsa_lookup">$&</a>;g;
s;\bsmtp_use_tls\b;<a href="postconf.5.html#smtp_use_tls">$&</a>;g;
s;\bsmtp_header_checks\b;<a href="postconf.5.html#smtp_header_checks">$&</a>;g;
s;\bsmtp_mime_header_checks\b;<a href="postconf.5.html#smtp_mime_header_checks">$&</a>;g;
s;\btlsproxy_tls_protocols\b;<a href="postconf.5.html#tlsproxy_tls_protocols">$&</a>;g;
s;\btlsproxy_tls_req_ccert\b;<a href="postconf.5.html#tlsproxy_tls_req_ccert">$&</a>;g;
s;\btlsproxy_tls_security_level\b;<a href="postconf.5.html#tlsproxy_tls_security_level">$&</a>;g;
- s;\btlsproxy_tls_session_cache_timeout\b;<a href="postconf.5.html#tlsproxy_tls_session_cache_timeout">$&</a>;g;
s;\btlsproxy_use_tls\b;<a href="postconf.5.html#tlsproxy_use_tls">$&</a>;g;
# Service-defined parameters...
<h2>Introduction</h2>
-<!--
-
-<dl> <dt> Note: </dt> <dd> <p> Postfix support for LMDB databases
-is suspended due to the existence of a hard limit (an "out of
-storage" failure mode that cannot be resolved by increasing the
-database size). </p> <p> Postfix may support LMDB again when it no
-longer limits the size of Postfix transactions, whether the limit
-is built into LMDB itself, or implicit by requiring an unbounded
-amount of memory to handle a large transaction. </p> </dd> </dl>
-
--->
+<blockquote> <p> <strong> Warning: LMDB databases have a show-stopper
+bug: they do not grow beyond a specified limit, and introduce a
+"database full" hard error condition that does not exist with any
+other Postfix database type. This is a problem for programs whose
+database grows with system load. Examples are postscreen(8),
+greylisting, verify(8) and tlsmgr(8). </strong> </p> <p> <strong>
+You have been warned. </strong> </p> </blockquote>
<p> Postfix uses databases of various kinds to store and look up
information. Postfix databases are specified as "type:name".
<h3><a name="server_tls_cache">Server-side TLS session cache</a> </h3>
-<p> The Postfix SMTP server and the remote SMTP client negotiate
-a session, which takes some computer time and network bandwidth.
-By default, this session information is cached only in the smtpd(8)
-process actually using this session and is lost when the process
-terminates. To share the session information between multiple
-smtpd(8) processes, a persistent session cache can be used. You
+<p> The Postfix SMTP server and the remote SMTP client negotiate a
+session, which takes some computer time and network bandwidth. SSL
+protocol versions other than SSLv2 support resumption of cached
+sessions. Not only is this more CPU and bandwidth efficient, it
+also reduces latency as only one network round-trip is used to
+resume a session while it takes two round-trips to create a session
+from scratch. </p>
+
+<p> Since Postfix uses multiple smtpd(8) service processes, an
+in-memory cache is not sufficient for session re-use. Clients store
+at most one cached session per server and are very unlikey to
+repeatedly connect to the same server process. Thus session caching
+in the Postfix SMTP server generally requires a shared cache (an
+alternative available with Postfix ≥ 2.11 is described below).
+</p>
+
+<p> To share the session information between multiple
+smtpd(8) processes, a session cache database is used. You
can specify any database type that can store objects of several
kbytes and that supports the sequence operator. DBM databases are
not suitable because they can only store small objects. The cache
concurrent access. Session caching is highly recommended, because
the cost of repeatedly negotiating TLS session keys is high.</p>
+<p> Starting with Postfix 2.11, linked with a compatible OpenSSL
+library (at least 0.9.8h, preferably 1.0.0 or later) the Postfix
+SMTP server supports RFC 5077 TLS session resumption without
+server-side state when the remote SMTP client also supports RFC
+5077. The session is encrypted by the server in a <i>session
+ticket</i> returned to client for storage. When a client sends a
+valid session ticket, the server decrypts it and resumes the session,
+provided neither the ticket nor the session have expired. This
+makes it possible to resume cached sessions without allocating space
+for a shared database on the server. This feature can be disabled
+by setting the session cache timeout to zero, otherwise the timeout
+must be at least 2 minutes and at most 100 days. </p>
+
+<p> Note, session tickets can only be negotiated if the client
+disables SSLv2 and does not use the legacy SSLv2 compatible HELLO
+message. This is true by default with the Postfix ≥ 2.6 SMTP
+client. </p>
+
<p> Example: </p>
<blockquote>
</pre>
</blockquote>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled. If set to a positive value
+less than 2 minutes, the minimum value of 2 minutes is used instead. </p>
+
<p> When the Postfix SMTP server does not save TLS sessions to an
external cache database, client-side session caching is unlikely
-to be useful. To prevent such wastage, the Postfix SMTP server can
+to be useful. To reduce waste of client resources, the Postfix SMTP server can
be configured to not issue TLS session ids. By default the Postfix
SMTP server always issues TLS session ids. This works around known
interoperability issues with some MUAs, and prevents possible
</pre>
</blockquote>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled. If set to a positive value
+less than 2 minutes, the minimum value of 2 minutes is used instead. </p>
+
<h3><a name="client_tls_limits"> Client TLS limitations </a>
</h3>
tlsmgr(8) daemon and therefore per-smtpd-instance master.cf overrides
are not possible. </p>
-<p> This feature is available in Postfix 2.2 and later. </p>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled, not just via the database, but
+also via RFC 5077 TLS session tickets, which don't require server-side
+storage. If set to a positive value less than 2 minutes, the minimum
+value of 2 minutes is used instead. TLS session tickets require
+an OpenSSL library (at least version 0.9.8h) that provides full
+support for this TLS extension. </p>
+
+<p> This feature is available in Postfix 2.2 and later, and updated
+for TLS session ticket support in Postfix 2.11. </p>
%PARAM relay_clientcerts
tlsmgr(8) daemon and therefore per-smtp-instance master.cf overrides
are not possible. </p>
+<p> As of Postfix 2.11 this setting cannot exceed 100 days. If set
+≤ 0, session caching is disabled. If set to a positive value
+less than 2 minutes, the minimum value of 2 minutes is used instead. </p>
+
<p> This feature is available in Postfix 2.2 and later. </p>
%PARAM smtp_use_tls no
%PARAM tlsproxy_tls_session_cache_timeout $smtpd_tls_session_cache_timeout
-<p> The expiration time of Postfix tlsproxy(8) server TLS session
-cache information. A cache cleanup is performed periodically every
-$smtpd_tls_session_cache_timeout seconds. See
-smtpd_tls_session_cache_timeout for further details. </p>
+<p> Obsolete expiration time of Postfix tlsproxy(8) server TLS session
+cache information. Since the cache is shared with smtpd(8) and managed
+by tlsmgr(8), there is only one expiration time for the SMTP server cache
+shared by all three services, namely smtpd_tls_session_cache_timeout. </p>
<p> This feature is available in Postfix 2.8 and later. </p>
exist with the smtp_connection_reuse_time_limit feature. </p>
<p> This feature is available in Postfix 2.11. </p>
+
+%PARAM lmtp_tls_force_insecure_host_tlsa_lookup no
+
+<p> The LMTP-specific version of the smtp_tls_force_insecure_host_tlsa_lookup
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.11 and later. </p>
+
+%PARAM smtp_tls_force_insecure_host_tlsa_lookup no
+
+<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
+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
+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>
/* The \fBdiscard\fR(8) mailer is not security-sensitive. It does not talk
/* to the network, and can be run chrooted at fixed low privilege.
/* STANDARDS
-/* None.
+/* RFC 3463 (Enhanced Status Codes)
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/*
#define DEF_SMTPD_TLS_SCACHE_DB ""
extern char *var_smtpd_tls_scache_db;
+#define MAX_SMTPD_TLS_SCACHETIME 8640000
#define VAR_SMTPD_TLS_SCACHTIME "smtpd_tls_session_cache_timeout"
#define DEF_SMTPD_TLS_SCACHTIME "3600s"
extern int var_smtpd_tls_scache_timeout;
extern char *var_smtp_tls_scache_db;
extern char *var_lmtp_tls_scache_db;
+#define MAX_SMTP_TLS_SCACHETIME 8640000
#define VAR_SMTP_TLS_SCACHTIME "smtp_tls_session_cache_timeout"
#define DEF_SMTP_TLS_SCACHTIME "3600s"
+#define MAX_LMTP_TLS_SCACHETIME 8640000
#define VAR_LMTP_TLS_SCACHTIME "lmtp_tls_session_cache_timeout"
#define DEF_LMTP_TLS_SCACHTIME "3600s"
extern int var_smtp_tls_scache_timeout;
#define DEF_LMTP_TLS_BLK_EARLY_MAIL_REPLY 0
extern bool var_smtp_tls_blk_early_mail_reply;
+#define VAR_SMTP_TLS_FORCE_TLSA "smtp_tls_force_insecure_host_tlsa_lookup"
+#define DEF_SMTP_TLS_FORCE_TLSA 0
+#define VAR_LMTP_TLS_FORCE_TLSA "lmtp_tls_force_insecure_host_tlsa_lookup"
+#define DEF_LMTP_TLS_FORCE_TLSA 0
+extern bool var_smtp_tls_force_tlsa;
+
/*
* SASL authentication support, SMTP server side.
*/
#define DEF_TLSP_TLS_RECHEAD "$" VAR_SMTPD_TLS_RECHEAD
extern bool var_tlsp_tls_received_header;
-#define VAR_TLSP_TLS_SCACHE_DB "tlsproxy_tls_session_cache_database"
-#define DEF_TLSP_TLS_SCACHE_DB "$" VAR_SMTPD_TLS_SCACHE_DB
-extern char *var_tlsp_tls_scache_db;
-
-#define VAR_TLSP_TLS_SCACHTIME "tlsproxy_tls_session_cache_timeout"
-#define DEF_TLSP_TLS_SCACHTIME "$" VAR_SMTPD_TLS_SCACHTIME
-extern int var_tlsp_tls_scache_timeout;
-
#define VAR_TLSP_TLS_SET_SESSID "tlsproxy_tls_always_issue_session_ids"
#define DEF_TLSP_TLS_SET_SESSID "$" VAR_SMTPD_TLS_SET_SESSID
extern bool var_tlsp_tls_set_sessid;
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20130818"
+#define MAIL_RELEASE_DATE "20130825"
#define MAIL_VERSION_NUMBER "2.11"
#ifdef SNAPSHOT
/* fingerprints and matching against user provided certificate
/* fingerprints (with DANE TLSA records the algorithm is specified
/* in the DNS).
+/* .IP "\fB-f\fR"
+/* Lookup the associated DANE TLSA RRset even when a hostname is not an
+/* alias and its address records lie in an unsigned zone. See
+/* smtp_tls_force_insecure_host_tlsa_lookup for details.
/* .IP "\fB-F \fICAfile.pem\fR (default: none)"
/* The PEM formatted CAfile for remote SMTP server certificate
/* verification. By default no CAfile is used and no public CAs
int log_mask; /* via tls_log_mask() */
int reconnect; /* -r option */
int max_reconnect; /* -m option */
+ int force_tlsa; /* -f option */
unsigned port; /* TCP port */
char *dest; /* Full destination spec */
char *addrport; /* [addr]:port */
char *nexthop; /* Nexthop domain for verification */
char *hostname; /* Hostname for verification */
DNS_RR *addr; /* IPv[46] Address to (re)connect to */
+ DNS_RR *mx; /* MX RRset qname, rname, valid */
int pass; /* Pass number, 2 for reconnect */
int nochat; /* disable chat logging */
char *helo; /* Server name from EHLO reply */
static DNS_RR *host_addr(STATE *, const char *);
-#define HNAME(addr) (addr->dnssec_valid ? addr->rname : addr->qname)
+#define HNAME(addr) (addr->qname)
/*
* Structure with broken-up SMTP server response.
case DNS_OK:
mx_names = dns_rr_sort(mx_names, dns_rr_compare_pref_any);
addr_list = mx_addr_list(state, mx_names);
+ state->mx = dns_rr_copy(mx_names);
dns_rr_free(mx_names);
if (addr_list == 0) {
msg_warn("no MX host for %s has a valid address record", domain);
static int dane_host_level(STATE *state, DNS_RR *addr)
{
int level = state->level;
+ int valid;
+ int mxvalid;
#ifdef USE_TLS
if (level == TLS_LEV_DANE) {
- if (addr->dnssec_valid) {
+
+ /*
+ * Suppress TLSA lookups for non-DNSSEC + non-MX + non-CNAME hosts.
+ * If the host address is not DNSSEC validated, the TLSA RRset is
+ * safely assumed to not be in a DNSSEC Look-aside Validation child
+ * zone.
+ */
+ mxvalid = state->mx == 0 || state->mx->dnssec_valid;
+ valid = addr->dnssec_valid;
+ if (!state->force_tlsa
+ && !valid
+ && state->mx == 0
+ && strcmp(addr->qname, addr->rname) == 0)
+ mxvalid = 0;
+ if (mxvalid) {
if (state->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE))
tls_dane_verbose(1);
else
tls_dane_free(state->ddane);
/* When TLSA lookups fail, next host */
- state->ddane = tls_dane_resolve(HNAME(addr), "tcp", state->port);
+ state->ddane = tls_dane_resolve(addr->qname,
+ valid ? addr->rname : 0,
+ "tcp", state->port);
if (!state->ddane) {
dsb_simple(state->why, "4.7.5",
"TLSA lookup error for %s:%u",
if (state->match)
argv_free(state->match);
argv_add(state->match = argv_alloc(2),
- "hostname", "nexthop", ARGV_END);
+ state->ddane->base_domain, ARGV_END);
+ if (state->mx) {
+ if (strcmp(state->mx->qname, state->mx->rname) == 0)
+ argv_add(state->match, state->mx->qname, ARGV_END);
+ else
+ argv_add(state->match, state->mx->rname,
+ state->mx->qname, ARGV_END);
+ }
}
} else {
level = TLS_LEV_SECURE;
if (state->addr)
dns_rr_free(state->addr);
state->addr = 0;
+ if (state->mx)
+ dns_rr_free(state->mx);
+ state->mx = 0;
if (state->nexthop)
myfree(state->nexthop);
if (cache_enabled && cache_count == 0) {
msg_info("Server declined session caching. Done reconnecting.");
state->reconnect = 0;
- } else if (cache_hits > 0) {
+ } else if (cache_hits > 0 && (state->log_mask & TLS_LOG_SESSTKT) != 0) {
msg_info("Found a previously used server. Done reconnecting.");
state->reconnect = 0;
} else if (state->max_reconnect-- <= 0) {
#ifdef USE_TLS
fprintf(stderr, "usage: %s %s \\\n\t%s \\\n\t%s \\\n\t%s"
" destination [match ...]\n", var_procname,
- "[-acCSv] [-t conn_tmout] [-T cmd_tmout] [-L logopts]",
+ "[-acCfSv] [-t conn_tmout] [-T cmd_tmout] [-L logopts]",
"[-h host_lookup] [-l level] [-d mdalg] [-g grade] [-p protocols]",
"[-A tafile] [-F CAfile.pem] [-P CApath/] [-m count] [-r delay]",
"[-o name=value]");
#define OPTS "a:ch:o:St:T:v"
#ifdef USE_TLS
-#define TLSOPTS "A:Cd:F:g:l:L:m:p:P:r:"
+#define TLSOPTS "A:Cd:fF:g:l:L:m:p:P:r:"
state->mdalg = mystrdup("sha1");
state->CApath = mystrdup("");
myfree(state->mdalg);
state->mdalg = mystrdup(optarg);
break;
+ case 'f':
+ state->force_tlsa = 1;
+ break;
case 'F':
myfree(state->CAfile);
state->CAfile = mystrdup(optarg);
return (TLS_MGR_STAT_OK);
}
-int tls_mgr_policy(const char *unused_type, int *cachable)
+int tls_mgr_policy(const char *unused_type, int *cachable, int *timeout)
{
if (cache_enabled && tls_cache == 0)
tls_cache = htable_create(1);
*cachable = cache_enabled;
+ *timeout = TLS_SESSION_LIFEMIN;
return (TLS_MGR_STAT_OK);
}
VAR_LMTP_TLS_ENFORCE_PN, DEF_LMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
VAR_LMTP_TLS_NOTEOFFER, DEF_LMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
VAR_LMTP_TLS_BLK_EARLY_MAIL_REPLY, DEF_LMTP_TLS_BLK_EARLY_MAIL_REPLY, &var_smtp_tls_blk_early_mail_reply,
+ VAR_LMTP_TLS_FORCE_TLSA, DEF_LMTP_TLS_FORCE_TLSA, &var_smtp_tls_force_tlsa,
#endif
VAR_LMTP_SENDER_AUTH, DEF_LMTP_SENDER_AUTH, &var_smtp_sender_auth,
VAR_LMTP_CNAME_OVERR, DEF_LMTP_CNAME_OVERR, &var_smtp_cname_overr,
/* .IP "\fBsmtp_tls_trust_anchor_file (empty)\fR"
/* Zero or more PEM-format files with trust-anchor certificates
/* and/or public keys.
-/* .IP "\fBsmtp_tls_dane_notfound_tlsa_level (may)\fR"
-/* The "degraded" security level when the "dane" security level
-/* is specified, but no validated DANE TLSA records are published.
-/* .IP "\fBsmtp_tls_dane_unusable_tlsa_level (encrypt)\fR"
-/* The "degraded" security level when the "dane" security level
-/* is specified, validated DANE TLSA records are present, but none are
-/* usable.
+/* .IP "\fBsmtp_tls_force_insecure_host_tlsa_lookup (no)\fR"
+/* Lookup the associated DANE TLSA RRset even when a hostname is
+/* not an alias and its address records lie in an unsigned zone.
/* .IP "\fBtls_dane_trust_anchor_digest_enable (trust-anchor-assertion)\fR"
/* RFC 6698 trust-anchor digest support in the Postfix TLS library.
/* .IP "\fBtlsmgr_service_name (tlsmgr)\fR"
/* .PP
/* Available in Postfix version 2.11 and later:
/* .IP "\fBsmtp_connection_reuse_count_limit (0)\fR"
-/* When SMTP connection caching is enabled, the number of times that
-/* an SMTP session may be reused before it is closed, or zero (no limit).
+/* When SMTP connection caching is enabled, the number of times
+/* that an SMTP session may be reused before it is closed, or zero (no
+/* limit).
/* TROUBLE SHOOTING CONTROLS
/* .ad
/* .fi
char *var_smtp_tls_eccert_file;
char *var_smtp_tls_eckey_file;
bool var_smtp_tls_blk_early_mail_reply;
+bool var_smtp_tls_force_tlsa;
#endif
VSTRING *addr; /* printable address or empty */
unsigned port; /* network byte order or null */
struct DNS_RR *rr; /* DNS resource record or null */
+ struct DNS_RR *mx; /* DNS resource record or null */
/* Private members. */
VSTRING *saved_dest; /* saved current nexthop */
struct SMTP_STATE *parent; /* parent linkage */
} SMTP_ITERATOR;
-#define SMTP_ITER_INIT(iter, _dest, _host, _addr, _port, _rr, state) do { \
+#define SMTP_ITER_INIT(iter, _dest, _host, _addr, _port, state) do { \
vstring_strcpy((iter)->dest, (_dest)); \
vstring_strcpy((iter)->host, (_host)); \
vstring_strcpy((iter)->addr, (_addr)); \
(iter)->port = (_port); \
- (iter)->rr = (_rr); \
+ (iter)->mx = (iter)->rr = 0; \
vstring_strcpy((iter)->saved_dest, ""); \
(iter)->parent = (state); \
} while (0)
extern SMTP_SESSION *smtp_session_activate(int, SMTP_ITERATOR *, VSTRING *, VSTRING *);
/*
- * What's in a name? With DANE TLSA we need the rr->rname (if validated).
+ * What's in a name?
*/
-#define SMTP_HNAME(rr) ( (var_smtp_cname_overr || rr->dnssec_valid) ? \
- (rr)->rname : (rr)->qname )
+#define SMTP_HNAME(rr) (var_smtp_cname_overr ? (rr)->rname : (rr)->qname)
/*
* smtp_connect.c
/* SYNOPSIS
/* #include "smtp_addr.h"
/*
-/* DNS_RR *smtp_domain_addr(name, misc_flags, why, found_myself)
+/* DNS_RR *smtp_domain_addr(name, mxrr, misc_flags, why, found_myself)
/* char *name;
+/* DNS_RR **mxrr;
/* int misc_flags;
/* DSN_BUF *why;
/* int *found_myself;
/* so that it contains only hosts that are more preferred than the
/* local mail server itself. The found_myself result parameter
/* is updated when the local MTA is MX host for the specified
-/* destination.
+/* destination. If MX records were found, the rname, qname,
+/* and dnssec validation status of the MX RRset are returned
+/* via mxrr, which the caller must free with dns_rr_free().
/*
/* When no mail exchanger is listed in the DNS for \fIname\fR, the
/* request is passed to smtp_host_addr().
/* smtp_domain_addr - mail exchanger address lookup */
-DNS_RR *smtp_domain_addr(char *name, int misc_flags, DSN_BUF *why,
- int *found_myself)
+DNS_RR *smtp_domain_addr(char *name, DNS_RR **mxrr, int misc_flags,
+ DSN_BUF *why, int *found_myself)
{
DNS_RR *mx_names;
DNS_RR *addr_list = 0;
mx_names = dns_rr_sort(mx_names, dns_rr_compare_pref_any);
best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE);
addr_list = smtp_addr_list(mx_names, why);
+ if (mxrr)
+ *mxrr = dns_rr_copy(mx_names); /* copies one record! */
dns_rr_free(mx_names);
if (addr_list == 0) {
/* Text does not change. */
* Internal interfaces.
*/
extern DNS_RR *smtp_host_addr(const char *, int, DSN_BUF *);
-extern DNS_RR *smtp_domain_addr(char *, int, DSN_BUF *, int *);
+extern DNS_RR *smtp_domain_addr(char *, DNS_RR **, int, DSN_BUF *, int *);
/* LICENSE
/* .ad
*
* We set dest=path for backwards compatibility.
*/
-#define NO_RR ((DNS_RR *) 0)
#define NO_PORT 0
- SMTP_ITER_INIT(iter, path, var_myhostname, path, NO_PORT, NO_RR, state);
+ SMTP_ITER_INIT(iter, path, var_myhostname, path, NO_PORT, state);
/*
* Opportunistic TLS for unix domain sockets does not make much sense,
}
#define NO_HOST "" /* safety */
#define NO_ADDR "" /* safety */
-#define NO_RR ((DNS_RR *) 0) /* safety */
- SMTP_ITER_INIT(iter, dest, NO_HOST, NO_ADDR, port, NO_RR, state);
+ SMTP_ITER_INIT(iter, dest, NO_HOST, NO_ADDR, port, state);
/*
* Resolve an SMTP server. Skip mail exchanger lookups when a quoted
} else {
int i_am_mx = 0;
- addr_list = smtp_domain_addr(domain, state->misc_flags,
+ addr_list = smtp_domain_addr(domain, &iter->mx, state->misc_flags,
why, &i_am_mx);
/* If we're MX host, don't connect to non-MX backups. */
if (i_am_mx)
/* XXX Code above assumes there is no code at this loop ending. */
}
dns_rr_free(addr_list);
+ if (iter->mx) {
+ dns_rr_free(iter->mx);
+ iter->mx = 0; /* Just in case */
+ }
myfree(dest_buf);
if (state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
break;
VAR_SMTP_TLS_ENFORCE_PN, DEF_SMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
VAR_SMTP_TLS_NOTEOFFER, DEF_SMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
VAR_SMTP_TLS_BLK_EARLY_MAIL_REPLY, DEF_SMTP_TLS_BLK_EARLY_MAIL_REPLY, &var_smtp_tls_blk_early_mail_reply,
+ VAR_SMTP_TLS_FORCE_TLSA, DEF_SMTP_TLS_FORCE_TLSA, &var_smtp_tls_force_tlsa,
#endif
VAR_SMTP_SENDER_AUTH, DEF_SMTP_SENDER_AUTH, &var_smtp_sender_auth,
VAR_SMTP_CNAME_OVERR, DEF_SMTP_CNAME_OVERR, &var_smtp_cname_overr,
{
VSTRING *key;
int valid = iter->rr && iter->rr->dnssec_valid;
+ int mxvalid = iter->mx == 0 || iter->mx->dnssec_valid;
/*
* Create an empty TLS Policy cache on the fly.
smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_NEXTHOP
| SMTP_KEY_FLAG_HOSTNAME
| SMTP_KEY_FLAG_PORT);
- vstring_sprintf_append(key, "%d", !!valid);
+ vstring_sprintf_append(key, "%d:%d", !!valid, !!mxvalid);
ctable_newcontext(policy_cache, (void *) iter);
*tls = *(SMTP_TLS_POLICY *) ctable_locate(policy_cache, STR(key));
vstring_free(key);
static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter)
{
TLS_DANE *dane;
- int valid = iter->rr && iter->rr->dnssec_valid;
+ int valid;
+ int mxvalid;
if (!iter->port) {
msg_warn("%s: the \"dane\" security level is invalid for delivery via"
}
return;
}
- if (!valid) {
+
+ /*
+ * If there were no MX records and the destination host is the original
+ * nexthop domain, or if the MX RRset is DNS validated, we can at least
+ * try DANE with the destination host prior to CNAME expansion, but we
+ * prefer CNAME expanded MX hosts if those are also secure.
+ *
+ * By default suppress TLSA lookups for non-DNSSEC + non-MX + non-CNAME
+ * hosts. If the host address is not DNSSEC validated, the TLSA RRset is
+ * safely assumed to not be in a DNSSEC Look-aside Validation child zone.
+ */
+ mxvalid = iter->mx == 0 || iter->mx->dnssec_valid;
+ valid = iter->rr && iter->rr->dnssec_valid;
+ if (!var_smtp_tls_force_tlsa
+ && !valid
+ && iter->mx == 0
+ && strcmp(iter->rr->qname, iter->rr->rname) == 0)
+ mxvalid = 0;
+
+ if (!mxvalid) {
if (tls->level == TLS_LEV_DANE) {
tls->level = TLS_LEV_MAY;
if (msg_verbose)
return;
}
/* When TLSA lookups fail, we defer the message */
- if ((dane = tls_dane_resolve(STR(iter->host), "tcp", iter->port)) == 0) {
+ if ((dane = tls_dane_resolve(iter->rr->qname, valid ? iter->rr->rname : 0,
+ "tcp", iter->port)) == 0) {
tls->level = TLS_LEV_INVALID;
dsb_simple(tls->why, "4.7.5", "TLSA lookup error for %s:%u",
STR(iter->host), ntohs(iter->port));
*/
if (TLS_DANE_HASTA(dane)) {
tls->matchargv = argv_alloc(2);
- argv_add(tls->matchargv, "hostname", "nexthop", ARGV_END);
+ argv_add(tls->matchargv, dane->base_domain, ARGV_END);
+ if (iter->mx) {
+ if (strcmp(iter->mx->qname, iter->mx->rname) == 0)
+ argv_add(tls->matchargv, iter->mx->qname, ARGV_END);
+ else
+ argv_add(tls->matchargv, iter->mx->rname,
+ iter->mx->qname, ARGV_END);
+ }
} else if (!TLS_DANE_HASEE(dane))
msg_panic("empty DANE match list");
tls->dane = dane;
/* .IP "\fBsmtpd_tls_req_ccert (no)\fR"
/* With mandatory TLS encryption, require a trusted remote SMTP client
/* certificate in order to allow TLS connections to proceed.
-/* .IP "\fBsmtpd_tls_session_cache_database (empty)\fR"
-/* Name of the file containing the optional Postfix SMTP server
-/* TLS session cache.
-/* .IP "\fBsmtpd_tls_session_cache_timeout (3600s)\fR"
-/* The expiration time of Postfix SMTP server TLS session cache
-/* information.
/* .IP "\fBsmtpd_tls_wrappermode (no)\fR"
/* Run the Postfix SMTP server in the non-standard "wrapper" mode,
/* instead of using the STARTTLS command.
char *var_smtpd_tls_mand_proto;
bool var_smtpd_tls_received_header;
bool var_smtpd_tls_req_ccert;
-int var_smtpd_tls_scache_timeout;
bool var_smtpd_tls_set_sessid;
char *var_smtpd_tls_fpt_dgst;
char *var_smtpd_tls_ciph;
log_level = var_smtpd_tls_loglevel,
verifydepth = var_smtpd_tls_ccert_vd,
cache_type = TLS_MGR_SCACHE_SMTPD,
- scache_timeout
- = var_smtpd_tls_scache_timeout,
set_sessid = var_smtpd_tls_set_sessid,
cert_file = cert_file,
key_file = var_smtpd_tls_key_file,
VAR_SMTPD_POLICY_TTL, DEF_SMTPD_POLICY_TTL, &var_smtpd_policy_ttl, 1, 0,
#ifdef USE_TLS
VAR_SMTPD_STARTTLS_TMOUT, DEF_SMTPD_STARTTLS_TMOUT, &var_smtpd_starttls_tmout, 1, 0,
- VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, 0,
#endif
VAR_MILT_CONN_TIME, DEF_MILT_CONN_TIME, &var_milt_conn_time, 1, 0,
VAR_MILT_CMD_TIME, DEF_MILT_CMD_TIME, &var_milt_cmd_time, 1, 0,
TLS_TLSA *ee; /* End-entity cert/pubkey digests */
TLS_CERTS *certs; /* Full trust-anchor certificates */
TLS_PKEYS *pkeys; /* Full trust-anchor public keys */
+ char *base_domain; /* Base domain of TLSA RRset */
int flags; /* Conflate cert and pkey digests */
time_t expires; /* Expiration time of this record */
int refs; /* Reference count */
extern void tls_dane_split(TLS_DANE *, int, int, const char *, const char *,
const char *);
extern void tls_dane_free(TLS_DANE *);
-extern TLS_DANE *tls_dane_resolve(const char *, const char *, unsigned);
+extern TLS_DANE *tls_dane_resolve(const char *, const char *, const char *,
+ unsigned);
extern int tls_dane_load_trustfile(TLS_DANE *, const char *);
/*
/* Private. */
SSL *con;
char *cache_type; /* tlsmgr(8) cache type if enabled */
+ int ticketed; /* Session ticket issued */
char *serverid; /* unique server identifier */
char *namaddr; /* nam[addr] for logging */
int log_mask; /* What to log */
#define TLS_LOG_DEBUG (1<<7)
#define TLS_LOG_TLSPKTS (1<<8)
#define TLS_LOG_ALLPKTS (1<<9)
+#define TLS_LOG_SESSTKT (1<<10)
/*
* Client and Server application contexts
const char *log_level;
int verifydepth;
const char *cache_type;
- long scache_timeout;
int set_sessid;
const char *cert_file;
const char *key_file;
tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext))
#define TLS_SERVER_INIT(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
- a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) \
+ a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) \
tls_server_init((((props)->a1), ((props)->a2), ((props)->a3), \
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
- ((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), \
- ((props)->a20), (props)))
+ ((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), (props)))
#define TLS_SERVER_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
tls_server_start((((props)->a1), ((props)->a2), ((props)->a3), \
{
long off = 0;
int cachable;
+ int scache_timeout;
SSL_CTX *client_ctx;
TLS_APPL_STATE *app_ctx;
int log_mask;
* sessions from the external cache, so we must delete them directly (not
* via a callback).
*/
- if (tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK)
+ if (tls_mgr_policy(props->cache_type, &cachable,
+ &scache_timeout) != TLS_MGR_STAT_OK)
+ scache_timeout = 0;
+ if (scache_timeout <= 0)
cachable = 0;
/*
SSL_SESS_CACHE_NO_INTERNAL_STORE |
SSL_SESS_CACHE_NO_AUTO_CLEAR);
SSL_CTX_sess_set_new_cb(client_ctx, new_client_session_cb);
+
+ /*
+ * OpenSSL ignores timed-out sessions. We need to set the internal
+ * cache timeout at least as high as the external cache timeout. This
+ * applies even if no internal cache is used. We set the session to
+ * twice the cache lifetime. This way a session always lasts longer
+ * than its lifetime in the cache.
+ */
+ SSL_CTX_set_timeout(client_ctx, 2 * scache_timeout);
}
return (app_ctx);
}
*/
if (!strcasecmp(certid, domain)
|| (certid[0] == '*' && certid[1] == '.' && certid[2] != 0
- && (parent = strchr(domain, '.')) != 0
- && (idlen = strlen(certid + 1)) <= (domlen = strlen(parent))
- && strcasecmp(var_tls_multi_wildcard == 0 ? parent :
- parent + domlen - idlen,
- certid + 1) == 0))
- return (1);
+ && (parent = strchr(domain, '.')) != 0
+ && (idlen = strlen(certid + 1)) <= (domlen = strlen(parent))
+ && strcasecmp(var_tls_multi_wildcard == 0 ? parent :
+ parent + domlen - idlen,
+ certid + 1) == 0))
+ return (1);
}
return (0);
}
/* SSL_CTX *ssl_ctx;
/* TLS_SESS_STATE *TLScontext;
/*
-/* TLS_DANE *tls_dane_resolve(host, proto, port)
-/* const char *host;
+/* TLS_DANE *tls_dane_resolve(qname, rname, proto, port)
+/* const char *qname;
+/* const char *rname;
/* const char *proto;
/* unsigned port;
/*
/* anchors always override the legacy public CA PKI. Otherwise, the
/* callback MUST be cleared.
/*
-/* tls_dane_resolve() maps a (host, protocol, port) triple to a
+/* tls_dane_resolve() maps a (qname, rname, protocol, port) tuple to a
/* a corresponding TLS_DANE policy structure found in the DNS. The port
/* argument is in network byte order. A null pointer is returned when
/* the DNS query for the TLSA record tempfailed. In all other cases the
/* .IP dane
/* Pointer to a TLS_DANE structure that lists the valid trust-anchor
/* and end-entity full-certificate and/or public-key digests.
-/* .IP host
+/* .IP qname
+/* FQDN of target service (original input form).
+/* .IP rname
/* DNSSEC validated (cname resolved) FQDN of target service.
/* .IP proto
/* Almost certainly "tcp".
dane->ee = 0;
dane->certs = 0;
dane->pkeys = 0;
+ dane->base_domain = 0;
dane->flags = flags;
dane->expires = 0;
dane->refs = 1;
/* De-allocate full trust-anchor certs and pkeys */
free_ta_certs(dane);
free_ta_pkeys(dane);
+ if (dane->base_domain)
+ myfree(dane->base_domain);
myfree((char *) dane);
}
return (void *) dane;
}
+/* resolve_host - resolve TLSA RRs for hostname (rname or qname) */
+
+static TLS_DANE *resolve_host(const char *host, const char *proto,
+ unsigned port)
+{
+ static VSTRING *query_domain;
+ TLS_DANE *dane;
+
+ if (query_domain == 0)
+ query_domain = vstring_alloc(64);
+
+ vstring_sprintf(query_domain, "_%u._%s.%s", ntohs(port), proto, host);
+ dane = (TLS_DANE *) ctable_locate(dane_cache, STR(query_domain));
+ if (timecmp(event_time(), dane->expires) > 0)
+ dane = (TLS_DANE *) ctable_refresh(dane_cache, STR(query_domain));
+ if (dane->base_domain == 0)
+ dane->base_domain = mystrdup(host);
+ return (dane);
+}
+
#endif
-/* tls_dane_resolve - cached map: (host, proto, port) -> TLS_DANE */
+/* tls_dane_resolve - cached map: (name, proto, port) -> TLS_DANE */
-TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
- unsigned port)
+TLS_DANE *tls_dane_resolve(const char *qname, const char *rname,
+ const char *proto, unsigned port)
{
- static VSTRING *qname;
TLS_DANE *dane = 0;
#ifdef DANE_TLSA_SUPPORT
if (!dane_cache)
dane_cache = ctable_create(CACHE_SIZE, dane_lookup, dane_free, 0);
- if (qname == 0)
- qname = vstring_alloc(64);
- vstring_sprintf(qname, "_%u._%s.%s", ntohs(port), proto, host);
- dane = (TLS_DANE *) ctable_locate(dane_cache, STR(qname));
- if (timecmp(event_time(), dane->expires) > 0)
- dane = (TLS_DANE *) ctable_refresh(dane_cache, STR(qname));
-
+ /*
+ * Try the rname first, if nothing there, try the qname. Note, lookup
+ * errors are distinct from success with nothing found. If the rname
+ * lookup fails we don't try the qname. The rname may be null when only
+ * the qname is in a secure zone.
+ */
+ if (rname)
+ dane = resolve_host(rname, proto, port);
+ if (!rname || (tls_dane_notfound(dane) && strcmp(qname, rname) != 0))
+ dane = resolve_host(qname, proto, port);
if (dane->flags & TLS_DANE_FLAG_ERROR)
return (0);
|| !add_skid(cert, akid)
|| (wrap_signed
&& (!X509_sign(cert, danekey, signmd)
- || (key && !wrap_key(TLScontext, 0, cert, depth + 1))))) {
+ || (key && !wrap_key(TLScontext, 0, cert, depth + 1))))) {
msg_warn("error generating DANE wrapper certificate");
tls_print_errors();
ret = 0;
}
#endif /* USE_TLS */
-
/* int tls_mgr_delete(cache_type, cache_id)
/* const char *cache_type;
/* const char *cache_id;
+/*
+/* TLS_TICKET_KEY *tls_mgr_key(keyname, timeout)
+/* unsigned char *keyname;
+/* int timeout;
/* DESCRIPTION
/* These routines communicate with the tlsmgr(8) server for
/* entropy and session cache management. Since these are
/* tls_mgr_delete() removes specified session from
/* the specified session cache.
/*
-/* Arguments
+/* tls_mgr_key() is used to retrieve the current TLS session ticket
+/* encryption or decryption keys.
+/*
+/* Arguments:
/* .IP cache_type
/* One of TLS_MGR_SCACHE_SMTPD, TLS_MGR_SCACHE_SMTP or
/* TLS_MGR_SCACHE_LMTP.
/* The result or input buffer.
/* .IP len
/* The length of the input buffer, or the amount of data requested.
+/* .IP keyname
+/* Is null when requesting the current encryption keys. Otherwise,
+/* keyname is a pointer to an array of TLS_TICKET_NAMELEN unsigned
+/* chars (not NUL terminated) that is an identifier for a key
+/* previously used to encrypt a session ticket. When encrypting
+/* a null result indicates that session tickets are not supported, when
+/* decrypting it indicates that no matching keys were found.
+/* .IP timeout
+/* The encryption key timeout. Once a key has been active for this many
+/* seconds it is retired and used only for decrypting previously issued
+/* session tickets for another timeout seconds, and is then destroyed.
+/* The timeout must not be longer than half the SSL session lifetime.
/* DIAGNOSTICS
/* All client functions return one of the following status codes:
/* .IP TLS_MGR_STAT_OK
#include <mail_params.h>
#include <mail_proto.h>
+
+/* TLS library. */
#include <tls_mgr.h>
/* Application-specific. */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
static ATTR_CLNT *tls_mgr;
/* tls_mgr_open - create client handle */
/* tls_mgr_policy - request caching policy */
-int tls_mgr_policy(const char *cache_type, int *cachable)
+int tls_mgr_policy(const char *cache_type, int *cachable, int *timeout)
{
int status;
ATTR_FLAG_MISSING, /* Reply attributes */
ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_INT, TLS_MGR_ATTR_CACHABLE, cachable,
- ATTR_TYPE_END) != 2)
+ ATTR_TYPE_INT, TLS_MGR_ATTR_SESSTOUT, timeout,
+ ATTR_TYPE_END) != 3)
status = TLS_MGR_STAT_FAIL;
return (status);
}
return (status);
}
+/* request_scache_key - ask tlsmgr(8) for matching key */
+
+static TLS_TICKET_KEY *request_scache_key(unsigned char *keyname)
+{
+ TLS_TICKET_KEY tmp;
+ static VSTRING *keybuf;
+ char *name;
+ size_t len;
+ int status;
+
+ /*
+ * Create the tlsmgr client handle.
+ */
+ if (tls_mgr == 0)
+ tls_mgr_open();
+
+ if (keybuf == 0)
+ keybuf = vstring_alloc(sizeof(tmp));
+
+ /* In tlsmgr requests we encode null key names as empty strings. */
+ name = keyname ? (char *) keyname : "";
+ len = keyname ? TLS_TICKET_NAMELEN : 0;
+
+ /*
+ * Send the request and receive the reply.
+ */
+ if (attr_clnt_request(tls_mgr,
+ ATTR_FLAG_NONE, /* Request */
+ ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_TKTKEY,
+ ATTR_TYPE_DATA, TLS_MGR_ATTR_KEYNAME, len, name,
+ ATTR_TYPE_END,
+ ATTR_FLAG_MISSING, /* Reply */
+ ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
+ ATTR_TYPE_DATA, TLS_MGR_ATTR_KEYBUF, keybuf,
+ ATTR_TYPE_END) != 2
+ || status != TLS_MGR_STAT_OK
+ || LEN(keybuf) != sizeof(tmp))
+ return (0);
+
+ memcpy((char *) &tmp, STR(keybuf), sizeof(tmp));
+ return (tls_scache_key_rotate(&tmp));
+}
+
+/* tls_mgr_key - session ticket key lookup, local cache, then tlsmgr(8) */
+
+TLS_TICKET_KEY *tls_mgr_key(unsigned char *keyname, int timeout)
+{
+ TLS_TICKET_KEY *key = 0;
+ time_t now = time((time_t *) 0);
+
+ /* A zero timeout disables session tickets. */
+ if (timeout <= 0)
+ return (0);
+
+ if ((key = tls_scache_key(keyname, now, timeout)) == 0)
+ key = request_scache_key(keyname);
+ return (key);
+}
+
#ifdef TEST
/* System library. */
/* Application-specific. */
-#define STR(x) vstring_str(x)
-#define LEN(x) VSTRING_LEN(x)
-
int main(int unused_ac, char **av)
{
VSTRING *inbuf = vstring_alloc(10);
argv_free(argv);
continue;
}
-
#define COMMAND(argv, str, len) \
(strcasecmp(argv->argv[0], str) == 0 && argv->argc == len)
/* DESCRIPTION
/* .nf
+ /*
+ * TLS library
+ */
+#include <tls_scache.h> /* Session ticket keys */
+
/*
* TLS manager protocol.
*/
#define TLS_MGR_REQ_LOOKUP "lookup"
#define TLS_MGR_REQ_UPDATE "update"
#define TLS_MGR_REQ_DELETE "delete"
+#define TLS_MGR_REQ_TKTKEY "tktkey"
#define TLS_MGR_ATTR_CACHABLE "cachable"
#define TLS_MGR_ATTR_CACHE_TYPE "cache_type"
#define TLS_MGR_ATTR_SEED "seed"
#define TLS_MGR_ATTR_SESSION "session"
#define TLS_MGR_ATTR_SIZE "size"
#define TLS_MGR_ATTR_STATUS "status"
+#define TLS_MGR_ATTR_KEYNAME "keyname"
+#define TLS_MGR_ATTR_KEYBUF "keybuf"
+#define TLS_MGR_ATTR_SESSTOUT "timeout"
/*
* TLS manager request status codes.
* Functional interface.
*/
extern int tls_mgr_seed(VSTRING *, int);
-extern int tls_mgr_policy(const char *, int *);
+extern int tls_mgr_policy(const char *, int *, int *);
extern int tls_mgr_lookup(const char *, const char *, VSTRING *);
extern int tls_mgr_update(const char *, const char *, const char *, ssize_t);
extern int tls_mgr_delete(const char *, const char *);
+extern TLS_TICKET_KEY *tls_mgr_key(unsigned char *, int);
/* LICENSE
/* .ad
/* int tls_scache_delete(cache, cache_id)
/* TLS_SCACHE *cache;
/* const char *cache_id;
+/*
+/* TLS_TICKET_KEY *tls_scache_key(keyname, now, timeout)
+/* unsigned char *keyname;
+/* time_t now;
+/* int timeout;
+/*
+/* TLS_TICKET_KEY *tls_scache_key_rotate(newkey)
+/* TLS_TICKET_KEY *newkey;
/* DESCRIPTION
/* This module maintains Postfix TLS session cache files.
/* each session is stored under a lookup key (hostname or
/* tls_scache_delete() removes the specified cache entry from
/* the specified TLS session cache.
/*
+/* tls_scache_key() locates a TLS session ticket key in a 2-element
+/* in-memory cache. A null result is returned if no unexpired matching
+/* key is found.
+/*
+/* tls_scache_key_rotate() saves a TLS session tickets key in the
+/* in-memory cache.
+/*
/* Arguments:
/* .IP dbname
/* The base name of the session cache file.
/*
/* Specify TLS_SCACHE_DONT_NEED_SESSION to avoid
/* saving the session information in the cache entry.
+/* .IP keyname
+/* Is null when requesting the current encryption keys. Otherwise,
+/* keyname is a pointer to an array of TLS_TICKET_NAMELEN unsigned
+/* chars (not NUL terminated) that is an identifier for a key
+/* previously used to encrypt a session ticket.
+/* .IP now
+/* Current epoch time passed by caller.
+/* .IP timeout
+/* TLS session ticket encryption lifetime.
+/* .IP newkey
+/* TLS session ticket key obtained from tlsmgr(8) to be added to
+ * internal cache.
/* DIAGNOSTICS
/* These routines terminate with a fatal run-time error
/* for unrecoverable database errors. This allows the
#include <hex_code.h>
#include <myflock.h>
#include <vstring.h>
+#include <timecmp.h>
/* Global library. */
char session[1]; /* actually a bunch of bytes */
} TLS_SCACHE_ENTRY;
+static TLS_TICKET_KEY *keys[2];
+
/*
* SLMs.
*/
myfree((char *) cp);
}
+/* tls_scache_key - find session ticket key for given key name */
+
+TLS_TICKET_KEY *tls_scache_key(unsigned char *keyname, time_t now, int timeout)
+{
+ int i;
+
+ /*
+ * The keys array contains 2 elements, the current signing key and the
+ * previous key.
+ *
+ * When name == 0 we are issuing a ticket, otherwise decrypting an existing
+ * ticket with the given key name. For new tickets we always use the
+ * current key if unexpired. For existing tickets, we use either the
+ * current or previous key with a validation expiration that is timeout
+ * longer than the signing expiration.
+ */
+ if (keyname) {
+ for (i = 0; i < 2 && keys[i]; ++i) {
+ if (memcmp(keyname, keys[i]->name, TLS_TICKET_NAMELEN) == 0) {
+ if (timecmp(keys[i]->tout + timeout, now) > 0)
+ return (keys[i]);
+ break;
+ }
+ }
+ } else if (keys[0]) {
+ if (timecmp(keys[0]->tout, now) > 0)
+ return (keys[0]);
+ }
+ return (0);
+}
+
+/* tls_scache_key_rotate - rotate session ticket keys */
+
+TLS_TICKET_KEY *tls_scache_key_rotate(TLS_TICKET_KEY *newkey)
+{
+
+ /*
+ * Allocate or re-use storage of retired key, then overwrite it, since
+ * caller's key data is ephemeral.
+ */
+ if (keys[1] == 0)
+ keys[1] = (TLS_TICKET_KEY *) mymalloc(sizeof(*newkey));
+ *keys[1] = *newkey;
+ newkey = keys[1];
+
+ /*
+ * Rotate if required, ensuring that the keys are sorted by expiration
+ * time with keys[0] expiring last.
+ */
+ if (keys[0] == 0 || keys[0]->tout < keys[1]->tout) {
+ keys[1] = keys[0];
+ keys[0] = newkey;
+ }
+ return (newkey);
+}
+
#endif
char *saved_cursor; /* cursor cache ID */
} TLS_SCACHE;
+#define TLS_TICKET_NAMELEN 16 /* RFC 5077 ticket key name length */
+#define TLS_TICKET_IVLEN 16 /* RFC 5077 ticket IV length */
+#define TLS_TICKET_KEYLEN 16 /* AES-128-CBC key size */
+#define TLS_TICKET_MACLEN 16 /* SHA-256 collision strength */
+#define TLS_SESSION_LIFEMIN 120 /* May you live to 120! */
+
+typedef struct TLS_TICKET_KEY {
+ unsigned char name[TLS_TICKET_NAMELEN];
+ unsigned char bits[TLS_TICKET_KEYLEN];
+ unsigned char hmac[TLS_TICKET_MACLEN];
+ time_t tout;
+} TLS_TICKET_KEY;
+
#define TLS_SCACHE_FLAG_DEL_SAVED_CURSOR (1<<0)
extern TLS_SCACHE *tls_scache_open(const char *, const char *, int, int);
extern int tls_scache_update(TLS_SCACHE *, const char *, const char *, ssize_t);
extern int tls_scache_delete(TLS_SCACHE *, const char *);
extern int tls_scache_sequence(TLS_SCACHE *, int, char **, VSTRING *);
+extern TLS_TICKET_KEY *tls_scache_key(unsigned char *, time_t, int);
+extern TLS_TICKET_KEY *tls_scache_key_rotate(TLS_TICKET_KEY *);
#define TLS_SCACHE_DONT_NEED_CACHE_ID ((char **) 0)
#define TLS_SCACHE_DONT_NEED_SESSION ((VSTRING *) 0)
return (1);
}
+#define NOENGINE ((ENGINE *) 0)
+#define TLS_TKT_NOKEYS -1 /* No keys for encryption */
+#define TLS_TKT_STALE 0 /* No matching keys for decryption */
+#define TLS_TKT_ACCEPT 1 /* Ticket decryptable and re-usable */
+#define TLS_TKT_REISSUE 2 /* Ticket decryptable, not re-usable */
+
+/* ticket_cb - configure tls session ticket encrypt/decrypt context */
+
+static int ticket_cb(SSL *con, unsigned char name[], unsigned char iv[],
+ EVP_CIPHER_CTX * ctx, HMAC_CTX * hctx, int create)
+{
+ static const EVP_MD *sha256;
+ static const EVP_CIPHER *aes128;
+ TLS_TICKET_KEY *key;
+ TLS_SESS_STATE *TLScontext = SSL_get_ex_data(con, TLScontext_index);
+ int timeout = ((int) SSL_CTX_get_timeout(SSL_get_SSL_CTX(con))) / 2;
+
+ if ((!sha256 && (sha256 = EVP_sha256()) == 0)
+ || (!aes128 && (aes128 = EVP_aes_128_cbc()) == 0)
+ || (key = tls_mgr_key(create ? 0 : name, timeout)) == 0
+ || (create && RAND_bytes(iv, TLS_TICKET_IVLEN) <= 0))
+ return (create ? TLS_TKT_NOKEYS : TLS_TKT_STALE);
+
+ HMAC_Init_ex(hctx, key->hmac, TLS_TICKET_MACLEN, sha256, NOENGINE);
+
+ if (create) {
+ EVP_EncryptInit_ex(ctx, aes128, NOENGINE, key->bits, iv);
+ memcpy((char *) name, (char *) key->name, TLS_TICKET_NAMELEN);
+ if (TLScontext->log_mask & TLS_LOG_CACHE)
+ msg_info("%s: Issuing session ticket, key expiration: %ld",
+ TLScontext->namaddr, (long) key->tout);
+ } else {
+ EVP_DecryptInit_ex(ctx, aes128, NOENGINE, key->bits, iv);
+ if (TLScontext->log_mask & TLS_LOG_CACHE)
+ msg_info("%s: Decrypting session ticket, key expiration: %ld",
+ TLScontext->namaddr, (long) key->tout);
+ }
+ TLScontext->ticketed = 1;
+ return (TLS_TKT_ACCEPT);
+}
+
/* tls_server_init - initialize the server-side TLS engine */
TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
long off = 0;
int verify_flags = SSL_VERIFY_NONE;
int cachable;
+ int scache_timeout;
+ int ticketable = 0;
int protomask;
TLS_APPL_STATE *app_ctx;
int log_mask;
*/
SSL_CTX_set_verify_depth(server_ctx, props->verifydepth + 1);
+ /*
+ * The session cache is implemented by the tlsmgr(8) server.
+ *
+ * XXX 200502 Surprise: when OpenSSL purges an entry from the in-memory
+ * cache, it also attempts to purge the entry from the on-disk cache.
+ * This is undesirable, especially when we set the in-memory cache size
+ * to 1. For this reason we don't allow OpenSSL to purge on-disk cache
+ * entries, and leave it up to the tlsmgr process instead. Found by
+ * Victor Duchovni.
+ */
+ if (tls_mgr_policy(props->cache_type, &cachable,
+ &scache_timeout) != TLS_MGR_STAT_OK)
+ scache_timeout = 0;
+ if (scache_timeout <= 0)
+ cachable = 0;
+
/*
* Protocol work-arounds, OpenSSL version dependent.
*/
+ off |= tls_bug_bits();
+
+ /*
+ * Add SSL_OP_NO_TICKET when the timeout is zero or library support is
+ * incomplete. The SSL_CTX_set_tlsext_ticket_key_cb feature was added in
+ * OpenSSL 0.9.8h, while SSL_NO_TICKET was added in 0.9.8f.
+ */
#ifdef SSL_OP_NO_TICKET
- off |= SSL_OP_NO_TICKET;
+#if !defined(OPENSSL_NO_TLSEXT) && OPENSSL_VERSION_NUMBER >= 0x0090808fL
+ ticketable = (scache_timeout > 0 && !(off & SSL_OP_NO_TICKET));
+ if (ticketable)
+ SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_cb);
#endif
- off |= tls_bug_bits();
+ if (!ticketable)
+ off |= SSL_OP_NO_TICKET;
+#endif
+
SSL_CTX_set_options(server_ctx, off);
/*
*/
app_ctx = tls_alloc_app_context(server_ctx, log_mask);
- /*
- * The session cache is implemented by the tlsmgr(8) server.
- *
- * XXX 200502 Surprise: when OpenSSL purges an entry from the in-memory
- * cache, it also attempts to purge the entry from the on-disk cache.
- * This is undesirable, especially when we set the in-memory cache size
- * to 1. For this reason we don't allow OpenSSL to purge on-disk cache
- * entries, and leave it up to the tlsmgr process instead. Found by
- * Victor Duchovni.
- */
-
- if (tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK)
- cachable = 0;
-
- if (cachable || props->set_sessid) {
+ if (cachable || ticketable || props->set_sessid) {
/*
* Initialize the session cache.
/*
* OpenSSL ignores timed-out sessions. We need to set the internal
* cache timeout at least as high as the external cache timeout. This
- * applies even if no internal cache is used.
+ * applies even if no internal cache is used. We set the session
+ * lifetime to twice the cache lifetime, which is also the issuing
+ * and retired key validation lifetime of session tickets keys. This
+ * way a session always lasts longer than the server's ability to
+ * decrypt its session ticket. Otherwise, a bug in OpenSSL may fail
+ * to re-issue tickets when sessions decrypt, but are expired.
*/
- SSL_CTX_set_timeout(server_ctx, props->scache_timeout);
+ SSL_CTX_set_timeout(server_ctx, 2 * scache_timeout);
} else {
/*
*/
TLScontext->session_reused = SSL_session_reused(TLScontext->con);
if ((TLScontext->log_mask & TLS_LOG_CACHE) && TLScontext->session_reused)
- msg_info("%s: Reusing old session", TLScontext->namaddr);
+ msg_info("%s: Reusing old session%s", TLScontext->namaddr,
+ TLScontext->ticketed ? " (RFC 5077 session ticket)" : "");
/*
* Let's see whether a peer certificate is available and what is the
#include <mail_conf.h>
#include <mail_params.h>
#include <mail_version.h>
-#include <tls_mgr.h>
#include <mail_proto.h>
#include <data_redirect.h>
/* TLS library. */
#ifdef USE_TLS
+#include <tls_mgr.h>
#define TLS_INTERNAL
#include <tls.h> /* TLS_MGR_SCACHE_<type> */
#include <tls_prng.h>
int *cache_timeout; /* main.cf parameter value */
} TLSMGR_SCACHE;
-TLSMGR_SCACHE cache_table[] = {
+static TLSMGR_SCACHE cache_table[] = {
TLS_MGR_SCACHE_SMTPD, 0, 0, &var_smtpd_tls_scache_db,
VAR_SMTPD_TLS_LOGLEVEL,
&var_smtpd_tls_loglevel, &var_smtpd_tls_scache_timeout,
0,
};
+#define smtpd_cache (cache_table[0])
+
/*
* SLMs.
*/
cache->cache_info->timeout);
}
+/* tlsmgr_key - return matching or current RFC 5077 session ticket keys */
+
+static int tlsmgr_key(VSTRING *buffer, int timeout)
+{
+ TLS_TICKET_KEY *key;
+ TLS_TICKET_KEY tmp;
+ unsigned char *name;
+ time_t now = time((time_t *) 0);
+
+ /* In tlsmgr requests we encode null key names as empty strings. */
+ name = LEN(buffer) ? (unsigned char *) STR(buffer) : 0;
+
+ /*
+ * Each key's encrypt and subsequent decrypt-only timeout is half of the
+ * total session timeout.
+ */
+ timeout /= 2;
+
+ /* Attempt to locate existing key */
+ if ((key = tls_scache_key(name, now, timeout)) == 0) {
+ if (name == 0) {
+ /* Create new encryption key */
+ if (RAND_bytes(tmp.name, TLS_TICKET_NAMELEN) <= 0
+ || RAND_bytes(tmp.bits, TLS_TICKET_KEYLEN) <= 0
+ || RAND_bytes(tmp.hmac, TLS_TICKET_MACLEN) <= 0)
+ return (TLS_MGR_STAT_ERR);
+ tmp.tout = now + timeout - 1;
+ key = tls_scache_key_rotate(&tmp);
+ } else {
+ /* No matching decryption key found */
+ return (TLS_MGR_STAT_ERR);
+ }
+ }
+ /* Return value overrites name buffer */
+ vstring_memcpy(buffer, (char *) key, sizeof(*key));
+ return (TLS_MGR_STAT_OK);
+}
+
/* tlsmgr_loop - TLS manager main loop */
static int tlsmgr_loop(char *unused_name, char **unused_argv)
ATTR_TYPE_END);
}
+ /*
+ * RFC 5077 TLS session ticket keys
+ */
+ else if (STREQ(STR(request), TLS_MGR_REQ_TKTKEY)) {
+ if (attr_scan(client_stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_DATA, TLS_MGR_ATTR_KEYNAME, buffer,
+ ATTR_TYPE_END) == 1) {
+ if (LEN(buffer) != 0 && LEN(buffer) != TLS_TICKET_NAMELEN) {
+ msg_warn("invalid session ticket key name length: %ld",
+ (long) LEN(buffer));
+ VSTRING_RESET(buffer);
+ } else if (*smtpd_cache.cache_timeout <= 0) {
+ status = TLS_MGR_STAT_ERR;
+ VSTRING_RESET(buffer);
+ } else {
+ status = tlsmgr_key(buffer, *smtpd_cache.cache_timeout);
+ }
+ }
+ attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_DATA, TLS_MGR_ATTR_KEYBUF,
+ LEN(buffer), STR(buffer),
+ ATTR_TYPE_END);
+ }
+
/*
* Entropy request.
*/
*/
else if (STREQ(STR(request), TLS_MGR_REQ_POLICY)) {
int cachable = 0;
+ int timeout = 0;
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
STR(cache_type), TLS_MGR_REQ_POLICY);
} else {
cachable = (ent->cache_info != 0) ? 1 : 0;
+ timeout = *ent->cache_timeout;
status = TLS_MGR_STAT_OK;
}
}
attr_print(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_INT, TLS_MGR_ATTR_CACHABLE, cachable,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_SESSTOUT, timeout,
ATTR_TYPE_END);
}
*/
dup_filter = htable_create(sizeof(cache_table) / sizeof(cache_table[0]));
for (ent = cache_table; ent->cache_label; ++ent) {
- if (**ent->cache_db) {
+ /* Sanitize session timeout */
+ if (*ent->cache_timeout > 0) {
+ if (*ent->cache_timeout < TLS_SESSION_LIFEMIN)
+ *ent->cache_timeout = TLS_SESSION_LIFEMIN;
+ } else {
+ *ent->cache_timeout = 0;
+ }
+ /* External cache database disabled if timeout is non-positive */
+ if (*ent->cache_timeout > 0 && **ent->cache_db) {
if ((dup_label = htable_find(dup_filter, *ent->cache_db)) != 0)
msg_fatal("do not use the same TLS cache file %s for %s and %s",
*ent->cache_db, dup_label, ent->cache_label);
static const CONFIG_TIME_TABLE time_table[] = {
VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 1, 0,
VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_exch_period, 1, 0,
- VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, 0,
- VAR_SMTP_TLS_SCACHTIME, DEF_SMTP_TLS_SCACHTIME, &var_smtp_tls_scache_timeout, 0, 0,
- VAR_LMTP_TLS_SCACHTIME, DEF_LMTP_TLS_SCACHTIME, &var_lmtp_tls_scache_timeout, 0, 0,
+ VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, MAX_SMTPD_TLS_SCACHETIME,
+ VAR_SMTP_TLS_SCACHTIME, DEF_SMTP_TLS_SCACHTIME, &var_smtp_tls_scache_timeout, 0, MAX_SMTP_TLS_SCACHETIME,
+ VAR_LMTP_TLS_SCACHTIME, DEF_LMTP_TLS_SCACHTIME, &var_lmtp_tls_scache_timeout, 0, MAX_LMTP_TLS_SCACHETIME,
0,
};
static const CONFIG_INT_TABLE int_table[] = {
/* The SMTP TLS security level for the Postfix \fBtlsproxy\fR(8) server;
/* when a non-empty value is specified, this overrides the obsolete
/* parameters smtpd_use_tls and smtpd_enforce_tls.
-/* .IP "\fBtlsproxy_tls_session_cache_timeout ($smtpd_tls_session_cache_timeout)\fR"
-/* The expiration time of Postfix \fBtlsproxy\fR(8) server TLS session
-/* cache information.
/* .PP
/* Available in Postfix version 2.11 and later:
/* .IP "\fBtlsmgr_service_name (tlsmgr)\fR"
*/
int var_smtpd_tls_ccert_vd;
char *var_smtpd_tls_loglevel;
-int var_smtpd_tls_scache_timeout;
bool var_smtpd_use_tls;
bool var_smtpd_enforce_tls;
bool var_smtpd_tls_ask_ccert;
int var_tlsp_tls_ccert_vd;
char *var_tlsp_tls_loglevel;
-int var_tlsp_tls_scache_timeout;
bool var_tlsp_use_tls;
bool var_tlsp_enforce_tls;
bool var_tlsp_tls_ask_ccert;
log_level = var_tlsp_tls_loglevel,
verifydepth = var_tlsp_tls_ccert_vd,
cache_type = TLS_MGR_SCACHE_SMTPD,
- scache_timeout = var_tlsp_tls_scache_timeout,
set_sessid = var_tlsp_tls_set_sessid,
cert_file = cert_file,
key_file = var_tlsp_tls_key_file,
0,
};
static const CONFIG_TIME_TABLE time_table[] = {
- VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, 0,
VAR_TLSP_WATCHDOG, DEF_TLSP_WATCHDOG, &var_tlsp_watchdog, 10, 0,
- VAR_TLSP_TLS_SCACHTIME, DEF_TLSP_TLS_SCACHTIME, &var_tlsp_tls_scache_timeout, 0, 0,
0,
};
static const CONFIG_BOOL_TABLE bool_table[] = {