-TTEST_CASE
-TTLSMGR_SCACHE
-TTLSP_STATE
+-TTLSRPT_WRAPPER
-TTLS_APPL_STATE
-TTLS_CERTS
-TTLS_CLIENT_INIT_PROPS
Minor feature: "postcat -f" option to prepend the filename
to each output line. This simplifies test data development.
File: postcat/postcat.c.
+
+20240919
+
+ Bitrot: With OpenSSL 3.0 additional key exchange algorithms
+ can be runtime loaded via "providers", and these don't have
+ short internal numeric ids (nids). We've been using numeric
+ ids to configure key exchange groups, and for logging the
+ negotiated group. We now need to switch to APIs that work
+ directly with string names. OpenSSL 3.0 supports not only
+ (EC)DH key exchange groups but also more general KEMs (Key
+ Encapsulation Mechanisms), in which the response from the
+ server to the client contains no server public key. So we
+ can no longer reliably deduce the negotiated group from a
+ "peer" key, and may need to fall back on the (new with
+ OpenSSL 3.2) SSL_get0_group_name() function. Viktor Dukhovni.
+ Files: src/tls/tls.h, src/tls/tls_dh.c, src/tls/tls_misc.c.
+
+20240923
+
+ Cleanup: No user-visible change. Updated TLSRPT related
+ internal comments and internal identifiers; updated error
+ logging after changes in libtlsrpt error-to-string conversion
+ functions; minor changes to improve robustness.
* SASL_README: SASL Authentication
* TLS_README: TLS Encryption and authentication
* FORWARD_SECRECY_README: TLS Forward Secrecy
+ * TLSRPT_README: TLSRPT Protocol Support
* IPV6_README: IP Version 6 Support
* SMTPUTF8_README: SMTPUTF8 Support
* MAILLOG_README: Postfix logging to file or stdout
successful and failed TLS connections to that domain. Support for TLSRPT was
added in Postfix 3.10.
-When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable = yes"), the
-Postfix SMTP and TLS clients engines will generate "success" and "failure"
-events, and will pass those events to a TLSRPT client library and report
-generator that are maintained by sys4. The Postfix implementation supports both
-DANE (Postfix built-in) and MTA-STS (through an smtp_tls_policy_maps plug-in).
+A policy example looks like this:
-The high-level diagram shows how Postfix events are reported to domains that
+ _smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-
+ report@example.com"
+
+Translation: email sending systems are requested to generate daily summaries of
+successful and failed SMTP over TLS connections to domain example.com, and to
+report those summaries via email to the specified address. Instead of mailto:,
+a policy may specify an https: destination.
+
+The high-level diagram shows how Postfix reports summaries to domains that
publish a TLSRPT policy.
Postfix SMTP and --> TLSRPT client --> TLSRPT report --> Email or HTTP
TLS client engines library generator summary
+When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable = yes"), the
+Postfix SMTP and TLS clients engines will generate "success" and "failure"
+events, and will pass those events to a TLSRPT client library and report
+generator that are maintained by sys4. The Postfix implementation supports both
+DANE (Postfix built-in) and MTA-STS (through an smtp_tls_policy_maps plug-in).
+
The Postfix smtp(8) client process implements the SMTP client engine. With
"smtp_tls_connection_reuse = no", the smtp(8) client process also implements
the TLS client engine. With "smtp_tls_connection_reuse = yes", the smtp(8)
The smtp_tlsrpt_socket_name parameter specifies an absolute pathname, or a
pathname that is relative to $queue_directory.
-A good socket location would be under $queue_directory/run/tlsrpt or
-$queue_directory/var/run/tlsrpt. These can then be configured in Postfix as a
-relative pathname (run/tlsrpt/tlsrpt.sock or var/run/tlsrpt/tlsrpt.sock) so
-that the same name will work with and without Postfix chroot support. Do not
-specify a location under directory that is already used by Postfix programs.
-Only Postfix programs should create sockets there.
+ Note: the socket location is still to be determined. A good socket location
+ would be under $queue_directory, for example: (smtp_tlsrpt_socket_name =
+ run/tlsrpt/tlsrpt.sock or smtp_tlsrpt_socket_name = var/run/tlsrpt/
+ tlsrpt.sock). Such names will work with and without Postfix chroot support.
+ Do not specify a location under a directory (private, public, ...) that is
+ already used by Postfix programs. Only Postfix programs should create
+ sockets there.
+
+For obvious reasons, RFC 8460 suggests not to enforce strict TLS security when
+sending daily success/failure summaries via email. Postfix currently does not
+have a mechanism to request this when submitting an email message. For initial
+tests a transport map may take care of this.
+
+ /etc/postfix/main.cf:
+ transport_maps = hash:/etc/postfix/transport
+
+ /etc/postfix/transport:
+ /^\Qsts-reports@gmail.com\E$/ allow-plaintext
+ /^\Qsmtp-tls-report@sys4.de\E$/ allow-plaintext
+ ...
+
+ /etc/postfix/master.cf:
+ allow-plaintext .. .. .. .. .. .. .. smtp
+ -o smtp_tls_security_level=may
+ -o smtp_tls_policy_maps=
+
+The ^ and $ prevent false matches, and the \Q and \E disable special
+characters.
M\bMT\bTA\bA-\b-S\bST\bTS\bS S\bSu\bup\bpp\bpo\bor\brt\bt v\bvi\bia\ba s\bsm\bmt\btp\bp_\b_t\btl\bls\bs_\b_p\bpo\bol\bli\bic\bcy\by_\b_m\bma\bap\bps\bs
Postfix supports MTA-STS though an smtp_tls_policy_maps policy plugin. Postfix
-TLSRPT support expects a response with the usual security level and matching
-requirements, plus any applicable name=value attributes described below.
-Specify { name = value } when a value may contain whitespace.
+expects a response with the usual security level and matching requirements,
+plus any applicable name=value attributes described below. Specify { name =
+value } when a value may contain whitespace.
Note 1: Postfix 3.10 and later will accept these attributes in an MTA-STS
- response even if TLSRPT support is disabled (at build time or run time),
- but it will not use most attributes except ttl and policy_failure.
+ response even if TLSRPT support is disabled (at build time or run time).
+ With TLSRPT support turned off, Postfix will use the ttl and policy_failure
+ attributes, and will ignore the attributes that are used only for TLSRPT.
Note 2: It is an error to specify these attributes for a non-STS policy.
L\bLi\bim\bmi\bit\bta\bat\bti\bio\bon\bns\bs
-The following limitations exist primarily because some errors may be reported
-by a Postfix smtp(8) client process, and some errors by a Postfix tlsproxy(8)
-process. It is too difficult to propagate TLSRPT client library state between
-processes.
-
-The Postfix TLSRPT client reports one final status (either 'success' or
-'failure') for each MTA that it is able to connect to. It cannot report a final
-status 'success' with some recoverable 'failure'. Specifically:
-
- * The Postfix TLSRPT client can report either successful TLS policy
- compliance, or an unrecoverable failure that prevents TLS policy compliance
- (examples: all TLSA records are unusable, or some PKI error during
- certificate verification).
+The Postfix TLSRPT implementation reports at most one final TLS handshake
+status (either 'success' or 'failure') per connection. Postfix TLSRPT cannot
+report a failure and then later report a final status of 'success' for that
+same connection. The reason is that it's too complicated to filter TLS errors
+and to report error details from the TLS engine back to the SMTP protocol
+engine. It just is not how Postfix works internally.
- * The Postfix TLSRPT client must not be used to report a potentially
- recoverable failure such as a non-parsable TLSA record, because some other
- TLSA record for the same host may still allow successful TLS policy
- compliance.
+The Postfix TLSRPT implementation reports only TLS handshake success or
+failure. It does not report failure to connect, or connections that break after
+a successful TLS handshake.
C\bCr\bre\bed\bdi\bit\bts\bs
--- /dev/null
+Functionality
+=============
+
+There needs to be a way to force "smtp_tls_security_level=may"
+for rmail deliveries of daily TLSRPT summaries.
+
+Paranoia
+=========
+
+Should there be a check that the TLSRPT policy for domain FOO
+has an 'rua' field that contains FOO?
+
+Paranoia: in IPC protocols base64 encode data that is not fully vetted.
+TLSRPT_WRAPPER.rpt_policy
+TLSRPT_WRAPPER.policy strings
+TLSRPT_WRAPPER.ehlo_cmd string.
+
+Code health
+===========
+Remove the trw_report_failure() additional_info argument. This is
+always null.
+
+Need to add a hex_code test for HEX_ENCODE_FLAG_APPEND.
+
+Deduplicate the code in sane_sockaddr_to_hostaddr(). It also appears in
+haproxy_srvr.c, normalize_mailhost_addr.c, and in postscreen_endpt.c.
+
+Need unit tests for smtp_tlsrpt.c and tlstrpd_wrapper.c. This
+requires infrastructure.
Add tests for Message-ID extraction in the cleanup daemon.
+ When debug logging is enabled, dict_db_open() logs a newline
+ character after the version info.
+
+ postsuper fails to write the maillog file while Postfix is down
+ (the fallback to 'direct write' happens after an irreversible
+ set_ugid() call).
+
The postdrop code should be more explicit about what
attrributes it will pass through. rec_attr_map() is not
supposed to be an approver.
reports for successful and failed TLS connections to that domain.
Support for TLSRPT was added in Postfix 3.10. </p>
-<p> When Postfix TLSRPT support is enabled (with "<a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a>
-= yes"), the Postfix SMTP and TLS clients engines will generate
-"success" and "failure" events, and will pass those events to a
-TLSRPT client library and report generator that are maintained by
-sys4. The Postfix implementation supports both DANE (Postfix built-in)
-and MTA-STS (through an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> plug-in). </p>
+<p> A policy example looks like this: </p>
-<p> The high-level diagram shows how Postfix events are reported
-to domains that publish a TLSRPT policy.
+<blockquote>
+<pre>
+_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-report@example.com"
+</pre>
+</blockquote>
+
+<p> Translation: email sending systems are requested to generate daily
+summaries of successful and failed SMTP over TLS connections to domain
+<tt>example.com</tt>, and to report those summaries via email to the
+specified address. Instead of <tt>mailto:</tt>, a policy may specify an
+<tt>https:</tt> destination. </p>
+
+<p> The high-level diagram shows how Postfix reports summaries to
+domains that publish a TLSRPT policy.
<blockquote>
</blockquote>
+<p> When Postfix TLSRPT support is enabled (with "<a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a>
+= yes"), the Postfix SMTP and TLS clients engines will generate
+"success" and "failure" events, and will pass those events to a
+TLSRPT client library and report generator that are maintained by
+sys4. The Postfix implementation supports both DANE (Postfix built-in)
+and MTA-STS (through an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> plug-in). </p>
+
<p> The Postfix <a href="smtp.8.html">smtp(8)</a> client process implements the SMTP client
-engine. With "<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = no", the <a href="smtp.8.html">smtp(8)</a> client
+engine. With "<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = no", the <a href="smtp.8.html">smtp(8)</a> client
process also implements the TLS client engine. With
"<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = yes", the <a href="smtp.8.html">smtp(8)</a> client process
delegates TLS processing to a Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> process. Either
</pre>
</blockquote>
-<p> The <a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> parameter specifies an absolute
-pathname, or a pathname that is relative to $<a href="postconf.5.html#queue_directory">queue_directory</a>. </p>
+<p> The <tt><a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a></tt> parameter specifies an
+absolute pathname, or a pathname that is relative to
+<tt>$<a href="postconf.5.html#queue_directory">queue_directory</a></tt>. </p>
-<p> A good socket location would be under $<a href="postconf.5.html#queue_directory">queue_directory</a>/run/tlsrpt
-or $<a href="postconf.5.html#queue_directory">queue_directory</a>/var/run/tlsrpt. These can then be configured
-in Postfix as a relative pathname (run/tlsrpt/tlsrpt.sock or
-var/run/tlsrpt/tlsrpt.sock) so that the same name will work with
-and without Postfix chroot support. Do not specify a location under
-directory that is already used by Postfix programs. Only Postfix
+<blockquote>
+
+<p> Note: the socket location is still to be determined. A good
+socket location would be under <tt>$<a href="postconf.5.html#queue_directory">queue_directory</a></tt>, for
+example: (<tt><a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> = run/tlsrpt/tlsrpt.sock</tt>
+or <tt><a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> = var/run/tlsrpt/tlsrpt.sock</tt>).
+Such names will work with and without Postfix chroot support. Do
+not specify a location under a directory (<tt>private, public,
+...</tt>) that is already used by Postfix programs. Only Postfix
programs should create sockets there. </p>
+</blockquote>
+
+<p> For obvious reasons, <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> suggests not to enforce strict
+TLS security when sending daily success/failure summaries via email. Postfix
+currently does not have a mechanism to request this when submitting
+an email message. For initial tests a transport map may take care
+of this. </p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ <a href="postconf.5.html#transport_maps">transport_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/transport
+ 
+/etc/postfix/transport:
+ /^\Qsts-reports@gmail.com\E$/ allow-plaintext
+ /^\Qsmtp-tls-report@sys4.de\E$/ allow-plaintext
+ ...
+ 
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+ allow-plaintext .. .. .. .. .. .. .. smtp
+ -o <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a>=may
+ -o <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a>=
+</pre>
+</blockquote>
+
+<p> The <tt>^</tt> and <tt>$</tt> prevent false matches, and the
+<tt>\Q</tt> and <tt>\E</tt> disable special characters. </p>
+
<h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps
</a></h2>
<p> Postfix supports MTA-STS though an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> policy
-plugin. Postfix TLSRPT support expects a response with the usual
-security level and matching requirements, plus any applicable
-name=value attributes described below. Specify { name = value }
-when a value may contain whitespace. </p>
+plugin. Postfix expects a response with the usual security level and
+matching requirements, plus any applicable name=value attributes described
+below. Specify { name = value } when a value may contain whitespace. </p>
<blockquote>
<p> Note 1: Postfix 3.10 and later will accept these attributes in
an MTA-STS response even if TLSRPT support is disabled (at build
-time or run time), but it will not use most attributes except
-<tt>ttl</tt> and <tt>policy_failure</tt>. </p>
+time or run time). With TLSRPT support turned off, Postfix
+will use the <tt>ttl</tt> and <tt>policy_failure</tt> attributes,
+and will ignore the attributes that are used only for TLSRPT. </p>
<p> Note 2: It is an error to specify these attributes for a non-STS
policy. </p>
<li> <p> <tt> policy_ttl=<i>time</i> </tt> </p>
<p> How long (in seconds) a Postfix SMTP client process will cache
-the MTA-STS plugin response. </p> </li>
+the MTA-STS plugin response. </p> </li>
<li> <p> <tt> { policy_string = <i>value</i> } </tt> </p>
<h2> <a name="limitations"> Limitations </a></h2>
-<p> The following limitations exist primarily because some errors
-may be reported by a Postfix <a href="smtp.8.html">smtp(8)</a> client process, and some errors
-by a Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> process. It is too difficult to propagate
-TLSRPT client library state between processes.</p>
-
-<p> The Postfix TLSRPT client reports one final status (either
-'success' or 'failure') for each MTA that it is able to connect to.
-It cannot report a final status 'success' with some recoverable
-'failure'. Specifically: </p>
-
-<ul>
-
-<li> <p> The Postfix TLSRPT client can report either successful TLS
-policy compliance, or an unrecoverable failure that prevents TLS
-policy compliance (examples: all TLSA records are unusable, or some
-PKI error during certificate verification). <p> </li>
-
-<li> <p> The Postfix TLSRPT client must not be used to report a
-potentially recoverable failure such as a non-parsable TLSA record,
-because some other TLSA record for the same host may still allow
-successful TLS policy compliance. </p> </li>
-
-</ul>
+<p> The Postfix TLSRPT implementation reports at most one final TLS
+handshake status (either 'success' or 'failure') per connection.
+Postfix TLSRPT cannot report a failure and then later report a final
+status of 'success' for that same connection. The reason is that
+it's too complicated to filter TLS errors and to report error details
+from the TLS engine back to the SMTP protocol engine. It just is
+not how Postfix works internally. </p>
+
+<p> The Postfix TLSRPT implementation reports only TLS handshake
+success or failure. It does not report failure to connect, or
+connections that break after a successful TLS handshake. </p>
<h2> <a name="credits"> Credits </a> </h2>
<li> <a href="FORWARD_SECRECY_README.html"> TLS Forward Secrecy </a>
+<li> <a href="TLSRPT_README.html"> TLSRPT Protocol Support </a>
+
<li> <a href="IPV6_README.html"> IP Version 6 Support </a>
<li> <a href="SMTPUTF8_README.html"> SMTPUTF8 Support </a>
<DT><b><a name="tls_eecdh_auto_curves">tls_eecdh_auto_curves</a>
(default: see "postconf -d" output)</b></DT><DD>
-<p> The prioritized list of elliptic curves supported by the Postfix
-SMTP client and server. These curves are used by the Postfix SMTP
-server when "<a href="postconf.5.html#smtpd_tls_eecdh_grade">smtpd_tls_eecdh_grade</a> = auto". The selected curves must be
-implemented by OpenSSL and be standardized for use in TLS (<a href="https://tools.ietf.org/html/rfc8422">RFC 8422</a>).
-It is unwise to list only "bleeding-edge" curves supported by a small
-subset of clients. The default list is suitable for most users. </p>
-
-<p> Postfix skips curve names that are unknown to OpenSSL, or that
-are known but not yet implemented. This makes it possible to
-"anticipate" support for curves that should be used once they become
-available. In particular, in some OpenSSL versions, the new <a href="https://tools.ietf.org/html/rfc8031">RFC</a>
-<a href="https://tools.ietf.org/html/rfc8031">8031</a> curves "X25519" and "X448" may be known by name, but ECDH
-support for either or both may be missing. These curves may appear
-in the default value of this parameter, even though they'll only
-be usable with later versions of OpenSSL. </p>
+<p> The prioritized list of elliptic curves, that should be enabled in the
+Postfix SMTP client and server. These are used by the Postfix SMTP server when
+"<a href="postconf.5.html#smtpd_tls_eecdh_grade">smtpd_tls_eecdh_grade</a> = auto". The selected curves should be implemented
+by OpenSSL and be standardized for use in the TLS "supported groups" extension
+(<a href="https://tools.ietf.org/html/rfc8422">RFC8422</a>, <a href="https://tools.ietf.org/html/rfc8446">RFC8446</a> and <a href="https://tools.ietf.org/html/rfc8447">RFC8447</a>). Be sure to include at least "x25519" and
+"prime256v1" (the OpenSSL name for "secp256r1", a.k.a. "P-256"). The default
+list is suitable for most users. </p>
+
+<p> On the client side, the first curve listed will be used to construct the
+client's initial TLS 1.3 "keyshare". If this is not supported by the server,
+the TLS handshake may require an additional round-trip after the server issues
+a HelloRetryRequest (HRR) indicating a suitable mutually supported curve. </p>
+
+<p> Postfix skips curve names that are unknown to OpenSSL, or that are known
+but not yet implemented. This makes it possible to "anticipate" support for
+curves that should be used once they become available, or to deploy the same
+setting on a server "farm" where not all servers support the same curves. </p>
+
+<p> As of Postfix 3.10, when compiled with OpenSSL 3.0 or later, the "curve"
+names can be more general key encapsulation mechanisms (KEMs), and/or may be
+loaded from an external "provider" (via a suitable <a href="postconf.5.html#tls_config_file">tls_config_file</a>). </p>
<p> See also the "<a href="postconf.5.html#tls_ffdhe_auto_groups">tls_ffdhe_auto_groups</a>" parameter, which supports
customizing the list of FFDHE groups enabled with TLS 1.3. That setting
this is required by OpenSSL 3.0. If both are inadvertently set empty,
Postfix will fall back to the compiled-in defaults. </p>
-<p> All the default groups and EC curves should sufficiently strong
-to make "pruning" the defaults unwise. At a minimum, "X25519" and
-"P-256" (a.k.a. "prime256v1") should be among the enabled EC curves,
-while "dhe2048" and "dhe3072" should be among the FFDHE groups. </p>
+<p> All the default groups and EC curves should sufficiently strong to make
+"pruning" the defaults unwise. At a minimum, "x25519" and "prime256v1" (the
+OpenSSL name for "secp256r1", a.k.a. "P-256") should be among the enabled EC
+curves, while "dhe2048" and "dhe3072" should be among the FFDHE groups. </p>
<p> This feature is available in Postfix 3.8 and later, when it is
compiled and linked with OpenSSL 3.0 or later. </p>
.PP
This feature is available in Postfix 2.8 and later.
.SH tls_eecdh_auto_curves (default: see "postconf \-d" output)
-The prioritized list of elliptic curves supported by the Postfix
-SMTP client and server. These curves are used by the Postfix SMTP
-server when "smtpd_tls_eecdh_grade = auto". The selected curves must be
-implemented by OpenSSL and be standardized for use in TLS (RFC 8422).
-It is unwise to list only "bleeding\-edge" curves supported by a small
-subset of clients. The default list is suitable for most users.
-.PP
-Postfix skips curve names that are unknown to OpenSSL, or that
-are known but not yet implemented. This makes it possible to
-"anticipate" support for curves that should be used once they become
-available. In particular, in some OpenSSL versions, the new RFC
-8031 curves "X25519" and "X448" may be known by name, but ECDH
-support for either or both may be missing. These curves may appear
-in the default value of this parameter, even though they'll only
-be usable with later versions of OpenSSL.
+The prioritized list of elliptic curves, that should be enabled in the
+Postfix SMTP client and server. These are used by the Postfix SMTP server when
+"smtpd_tls_eecdh_grade = auto". The selected curves should be implemented
+by OpenSSL and be standardized for use in the TLS "supported groups" extension
+(RFC8422, RFC8446 and RFC8447). Be sure to include at least "x25519" and
+"prime256v1" (the OpenSSL name for "secp256r1", a.k.a. "P\-256"). The default
+list is suitable for most users.
+.PP
+On the client side, the first curve listed will be used to construct the
+client's initial TLS 1.3 "keyshare". If this is not supported by the server,
+the TLS handshake may require an additional round\-trip after the server issues
+a HelloRetryRequest (HRR) indicating a suitable mutually supported curve.
+.PP
+Postfix skips curve names that are unknown to OpenSSL, or that are known
+but not yet implemented. This makes it possible to "anticipate" support for
+curves that should be used once they become available, or to deploy the same
+setting on a server "farm" where not all servers support the same curves.
+.PP
+As of Postfix 3.10, when compiled with OpenSSL 3.0 or later, the "curve"
+names can be more general key encapsulation mechanisms (KEMs), and/or may be
+loaded from an external "provider" (via a suitable tls_config_file).
.PP
See also the "tls_ffdhe_auto_groups" parameter, which supports
customizing the list of FFDHE groups enabled with TLS 1.3. That setting
this is required by OpenSSL 3.0. If both are inadvertently set empty,
Postfix will fall back to the compiled\-in defaults.
.PP
-All the default groups and EC curves should sufficiently strong
-to make "pruning" the defaults unwise. At a minimum, "X25519" and
-"P\-256" (a.k.a. "prime256v1") should be among the enabled EC curves,
-while "dhe2048" and "dhe3072" should be among the FFDHE groups.
+All the default groups and EC curves should sufficiently strong to make
+"pruning" the defaults unwise. At a minimum, "x25519" and "prime256v1" (the
+OpenSSL name for "secp256r1", a.k.a. "P\-256") should be among the enabled EC
+curves, while "dhe2048" and "dhe3072" should be among the FFDHE groups.
.PP
This feature is available in Postfix 3.8 and later, when it is
compiled and linked with OpenSSL 3.0 or later.
reports for successful and failed TLS connections to that domain.
Support for TLSRPT was added in Postfix 3.10. </p>
-<p> When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable
-= yes"), the Postfix SMTP and TLS clients engines will generate
-"success" and "failure" events, and will pass those events to a
-TLSRPT client library and report generator that are maintained by
-sys4. The Postfix implementation supports both DANE (Postfix built-in)
-and MTA-STS (through an smtp_tls_policy_maps plug-in). </p>
+<p> A policy example looks like this: </p>
-<p> The high-level diagram shows how Postfix events are reported
-to domains that publish a TLSRPT policy.
+<blockquote>
+<pre>
+_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-report@example.com"
+</pre>
+</blockquote>
+
+<p> Translation: email sending systems are requested to generate daily
+summaries of successful and failed SMTP over TLS connections to domain
+<tt>example.com</tt>, and to report those summaries via email to the
+specified address. Instead of <tt>mailto:</tt>, a policy may specify an
+<tt>https:</tt> destination. </p>
+
+<p> The high-level diagram shows how Postfix reports summaries to
+domains that publish a TLSRPT policy.
<blockquote>
</blockquote>
+<p> When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable
+= yes"), the Postfix SMTP and TLS clients engines will generate
+"success" and "failure" events, and will pass those events to a
+TLSRPT client library and report generator that are maintained by
+sys4. The Postfix implementation supports both DANE (Postfix built-in)
+and MTA-STS (through an smtp_tls_policy_maps plug-in). </p>
+
<p> The Postfix smtp(8) client process implements the SMTP client
-engine. With "smtp_tls_connection_reuse = no", the smtp(8) client
+engine. With "smtp_tls_connection_reuse = no", the smtp(8) client
process also implements the TLS client engine. With
"smtp_tls_connection_reuse = yes", the smtp(8) client process
delegates TLS processing to a Postfix tlsproxy(8) process. Either
</pre>
</blockquote>
-<p> The smtp_tlsrpt_socket_name parameter specifies an absolute
-pathname, or a pathname that is relative to $queue_directory. </p>
+<p> The <tt>smtp_tlsrpt_socket_name</tt> parameter specifies an
+absolute pathname, or a pathname that is relative to
+<tt>$queue_directory</tt>. </p>
-<p> A good socket location would be under $queue_directory/run/tlsrpt
-or $queue_directory/var/run/tlsrpt. These can then be configured
-in Postfix as a relative pathname (run/tlsrpt/tlsrpt.sock or
-var/run/tlsrpt/tlsrpt.sock) so that the same name will work with
-and without Postfix chroot support. Do not specify a location under
-directory that is already used by Postfix programs. Only Postfix
+<blockquote>
+
+<p> Note: the socket location is still to be determined. A good
+socket location would be under <tt>$queue_directory</tt>, for
+example: (<tt>smtp_tlsrpt_socket_name = run/tlsrpt/tlsrpt.sock</tt>
+or <tt>smtp_tlsrpt_socket_name = var/run/tlsrpt/tlsrpt.sock</tt>).
+Such names will work with and without Postfix chroot support. Do
+not specify a location under a directory (<tt>private, public,
+...</tt>) that is already used by Postfix programs. Only Postfix
programs should create sockets there. </p>
+</blockquote>
+
+<p> For obvious reasons, RFC 8460 suggests not to enforce strict
+TLS security when sending daily success/failure summaries via email. Postfix
+currently does not have a mechanism to request this when submitting
+an email message. For initial tests a transport map may take care
+of this. </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ transport_maps = hash:/etc/postfix/transport
+ 
+/etc/postfix/transport:
+ /^\Qsts-reports@gmail.com\E$/ allow-plaintext
+ /^\Qsmtp-tls-report@sys4.de\E$/ allow-plaintext
+ ...
+ 
+/etc/postfix/master.cf:
+ allow-plaintext .. .. .. .. .. .. .. smtp
+ -o smtp_tls_security_level=may
+ -o smtp_tls_policy_maps=
+</pre>
+</blockquote>
+
+<p> The <tt>^</tt> and <tt>$</tt> prevent false matches, and the
+<tt>\Q</tt> and <tt>\E</tt> disable special characters. </p>
+
<h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps
</a></h2>
<p> Postfix supports MTA-STS though an smtp_tls_policy_maps policy
-plugin. Postfix TLSRPT support expects a response with the usual
-security level and matching requirements, plus any applicable
-name=value attributes described below. Specify { name = value }
-when a value may contain whitespace. </p>
+plugin. Postfix expects a response with the usual security level and
+matching requirements, plus any applicable name=value attributes described
+below. Specify { name = value } when a value may contain whitespace. </p>
<blockquote>
<p> Note 1: Postfix 3.10 and later will accept these attributes in
an MTA-STS response even if TLSRPT support is disabled (at build
-time or run time), but it will not use most attributes except
-<tt>ttl</tt> and <tt>policy_failure</tt>. </p>
+time or run time). With TLSRPT support turned off, Postfix
+will use the <tt>ttl</tt> and <tt>policy_failure</tt> attributes,
+and will ignore the attributes that are used only for TLSRPT. </p>
<p> Note 2: It is an error to specify these attributes for a non-STS
policy. </p>
<li> <p> <tt> policy_ttl=<i>time</i> </tt> </p>
<p> How long (in seconds) a Postfix SMTP client process will cache
-the MTA-STS plugin response. </p> </li>
+the MTA-STS plugin response. </p> </li>
<li> <p> <tt> { policy_string = <i>value</i> } </tt> </p>
<h2> <a name="limitations"> Limitations </a></h2>
-<p> The following limitations exist primarily because some errors
-may be reported by a Postfix smtp(8) client process, and some errors
-by a Postfix tlsproxy(8) process. It is too difficult to propagate
-TLSRPT client library state between processes.</p>
-
-<p> The Postfix TLSRPT client reports one final status (either
-'success' or 'failure') for each MTA that it is able to connect to.
-It cannot report a final status 'success' with some recoverable
-'failure'. Specifically: </p>
-
-<ul>
-
-<li> <p> The Postfix TLSRPT client can report either successful TLS
-policy compliance, or an unrecoverable failure that prevents TLS
-policy compliance (examples: all TLSA records are unusable, or some
-PKI error during certificate verification). <p> </li>
-
-<li> <p> The Postfix TLSRPT client must not be used to report a
-potentially recoverable failure such as a non-parsable TLSA record,
-because some other TLSA record for the same host may still allow
-successful TLS policy compliance. </p> </li>
-
-</ul>
+<p> The Postfix TLSRPT implementation reports at most one final TLS
+handshake status (either 'success' or 'failure') per connection.
+Postfix TLSRPT cannot report a failure and then later report a final
+status of 'success' for that same connection. The reason is that
+it's too complicated to filter TLS errors and to report error details
+from the TLS engine back to the SMTP protocol engine. It just is
+not how Postfix works internally. </p>
+
+<p> The Postfix TLSRPT implementation reports only TLS handshake
+success or failure. It does not report failure to connect, or
+connections that break after a successful TLS handshake. </p>
<h2> <a name="credits"> Credits </a> </h2>
%PARAM tls_eecdh_auto_curves see "postconf -d" output
-<p> The prioritized list of elliptic curves supported by the Postfix
-SMTP client and server. These curves are used by the Postfix SMTP
-server when "smtpd_tls_eecdh_grade = auto". The selected curves must be
-implemented by OpenSSL and be standardized for use in TLS (RFC 8422).
-It is unwise to list only "bleeding-edge" curves supported by a small
-subset of clients. The default list is suitable for most users. </p>
-
-<p> Postfix skips curve names that are unknown to OpenSSL, or that
-are known but not yet implemented. This makes it possible to
-"anticipate" support for curves that should be used once they become
-available. In particular, in some OpenSSL versions, the new RFC
-8031 curves "X25519" and "X448" may be known by name, but ECDH
-support for either or both may be missing. These curves may appear
-in the default value of this parameter, even though they'll only
-be usable with later versions of OpenSSL. </p>
+<p> The prioritized list of elliptic curves, that should be enabled in the
+Postfix SMTP client and server. These are used by the Postfix SMTP server when
+"smtpd_tls_eecdh_grade = auto". The selected curves should be implemented
+by OpenSSL and be standardized for use in the TLS "supported groups" extension
+(RFC8422, RFC8446 and RFC8447). Be sure to include at least "x25519" and
+"prime256v1" (the OpenSSL name for "secp256r1", a.k.a. "P-256"). The default
+list is suitable for most users. </p>
+
+<p> On the client side, the first curve listed will be used to construct the
+client's initial TLS 1.3 "keyshare". If this is not supported by the server,
+the TLS handshake may require an additional round-trip after the server issues
+a HelloRetryRequest (HRR) indicating a suitable mutually supported curve. </p>
+
+<p> Postfix skips curve names that are unknown to OpenSSL, or that are known
+but not yet implemented. This makes it possible to "anticipate" support for
+curves that should be used once they become available, or to deploy the same
+setting on a server "farm" where not all servers support the same curves. </p>
+
+<p> As of Postfix 3.10, when compiled with OpenSSL 3.0 or later, the "curve"
+names can be more general key encapsulation mechanisms (KEMs), and/or may be
+loaded from an external "provider" (via a suitable tls_config_file). </p>
<p> See also the "tls_ffdhe_auto_groups" parameter, which supports
customizing the list of FFDHE groups enabled with TLS 1.3. That setting
this is required by OpenSSL 3.0. If both are inadvertently set empty,
Postfix will fall back to the compiled-in defaults. </p>
-<p> All the default groups and EC curves should sufficiently strong
-to make "pruning" the defaults unwise. At a minimum, "X25519" and
-"P-256" (a.k.a. "prime256v1") should be among the enabled EC curves,
-while "dhe2048" and "dhe3072" should be among the FFDHE groups. </p>
+<p> All the default groups and EC curves should sufficiently strong to make
+"pruning" the defaults unwise. At a minimum, "x25519" and "prime256v1" (the
+OpenSSL name for "secp256r1", a.k.a. "P-256") should be among the enabled EC
+curves, while "dhe2048" and "dhe3072" should be among the FFDHE groups. </p>
<p> This feature is available in Postfix 3.8 and later, when it is
compiled and linked with OpenSSL 3.0 or later. </p>
canonicalization
Orlitzky
Typofix
+Deduplicate
+KEM
+HelloRetryRequest
+HRR
+KEMs
+kex
+keyshare
+pkg
RPT
TLSRPT
TLSRPTv
datatracker
webpki
parsable
+mailto
policies policy policy type
policies policy policy string Ignored if the tls_policy_type
policies policy policy domain
-additional_detail additional_detail
+additional_info additional_info
ignored ignored
USE_TLSRPT USE_TLSRPT
unimplemented commands in the SMTP server File smtpd smtpd c
cleanup cleanup h cleanup cleanup_extracted c
File postcat postcat c
+ Files src tls tls h src tls tls_dh c src tls tls_misc c
CCARGS CCARGS DHAS_MONGODB I usr include libmongoc 1 0
dt dt dd 2 Also enable verbose logging in the Postfix TLS
Postfix Postfix legacy TLS Support
- A good socket location would be under queue_directory run tlsrpt or queue_directory var run tlsrpt These can then be configured in Postfix as a relative pathname run tlsrpt tlsrpt sock or var run tlsrpt tlsrpt sock so that the same name will
+ Note the socket location is still to be determined A good socket location would be under queue_directory for example smtp_tlsrpt_socket_name run tlsrpt tlsrpt sock or smtp_tlsrpt_socket_name var run tlsrpt tlsrpt sock Such names
STS
STSv
Sys
+Qsmtp
+Qsts
+gmail
#else
#define DEF_TLS_EECDH_AUTO_3 ""
#endif
-#if defined(SN_secp521r1) && defined(NID_secp521r1)
-#define DEF_TLS_EECDH_AUTO_4 SN_secp521r1 " "
+#if defined(SN_secp384r1) && defined(NID_secp384r1)
+#define DEF_TLS_EECDH_AUTO_4 SN_secp384r1
#else
#define DEF_TLS_EECDH_AUTO_4 ""
#endif
-#if defined(SN_secp384r1) && defined(NID_secp384r1)
-#define DEF_TLS_EECDH_AUTO_5 SN_secp384r1
+#if defined(SN_secp521r1) && defined(NID_secp521r1)
+#define DEF_TLS_EECDH_AUTO_5 SN_secp521r1 " "
#else
#define DEF_TLS_EECDH_AUTO_5 ""
#endif
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20240917"
+#define MAIL_RELEASE_DATE "20240923"
#define MAIL_VERSION_NUMBER "3.10"
#ifdef SNAPSHOT
matchargv = state->match,
mdalg = state->mdalg,
tlsrpt = 0,
- fail_type = 0,
+ ffail_type = 0,
dane = state->ddane ?
state->ddane : state->dane);
matchargv = state->match,
mdalg = state->mdalg,
tlsrpt = 0,
- fail_type = 0,
+ ffail_type = 0,
dane = state->ddane ? state->ddane : state->dane);
} /* tlsproxy_mode */
vstring_free(cipher_exclusions);
session->state = state;
#ifdef USE_TLS
session->tls_nexthop = domain;
+
+ /*
+ * Update TLSRPT state even if this is a reused SMTP
+ * connection. If for some unlikely reason we must report a
+ * problem, then we must report correct information.
+ */
#ifdef USE_TLSRPT
if (state->tlsrpt && state->tls->level > TLS_LEV_NONE) {
smtp_tlsrpt_set_tls_policy(state);
/* 111 8th Avenue
/* New York, NY 10011, USA
/*
+/* Wietse Venema
+/* porcupine.org
+/*
/* Pipelining code in cooperation with:
/* Jon Ribbens
/* Oaktree Internet Solutions Ltd.,
#ifdef USE_TLSRPT
if (state->tlsrpt
&& (state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0)
- trw_set_ehlo_resp(state->tlsrpt, resp->str);
+ smtp_tlsrpt_set_ehlo_resp(state, resp->str);
#endif
}
if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
if (state->tlsrpt)
trw_report_failure(state->tlsrpt,
TLSRPT_STARTTLS_NOT_SUPPORTED,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
/* failure_reason= */ (char *) 0);
#endif
return (smtp_site_fail(state, STR(iter->host), resp,
if (state->tlsrpt)
trw_report_failure(state->tlsrpt,
TLSRPT_STARTTLS_NOT_SUPPORTED,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
/* failure_reason= */ (char *) 0);
#endif
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
#else
tlsrpt = 0,
#endif
- fail_type = 0,
+ ffail_type = 0,
dane = state->tls->dane);
/*
#else
tlsrpt = 0,
#endif
- fail_type = state->tls->ext_policy_failure,
+ ffail_type = state->tls->ext_policy_failure,
dane = state->tls->dane);
/*
if (!TLS_CERT_IS_TRUSTED(session->tls_context)) {
(void) trw_report_failure(state->tlsrpt,
TLSRPT_CERTIFICATE_NOT_TRUSTED,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
/* failure_reason= */ (char *) 0);
} else {
(void) trw_report_failure(state->tlsrpt,
TLSRPT_CERTIFICATE_HOST_MISMATCH,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
/* failure_reason= */ (char *) 0);
}
}
* Create a TLSRPT success report only if the TLS engine has not reported
* a failure (For example, the TLS handshake may be successful, but the
* security level was downgraded from opportunistic or half "dane" to
- * "encrypt").
+ * "encrypt"), and only if the TLS session and SMTP connection are new.
*/
#ifdef USE_TLSRPT
- if (state->tlsrpt && session->tls_context->rpt_reported == 0)
+ if (state->tlsrpt && session->tls_context->rpt_reported == 0
+ && session->tls_context->session_reused == 0 /* New TLS */
+ && session->reuse_count == 0) /* New SMTP */
(void) trw_report_success(state->tlsrpt);
#endif
tls->ext_policy_type = mystrdup(val);
continue;
}
+ /* Only one instance per policy. */
if (!strcasecmp(name, EXT_POLICY_DOMAIN)) {
if (tls->ext_policy_domain) {
msg_warn("%s: attribute \"%s\" is specified multiple times",
/* SMTP_STATE *state,
/* const char *ehlo_resp)
/* DESCRIPTION
-/* This module collects TLSRPT policy information and selected SMTP
-/* protocol engine state in a TLSRPT_WRAPPER object. This will be
-/* passed to (possibly remote) TLS protocol engine, so that it
-/* can report a TLS error to a TLSRPT library. The SMTP protocol
-/* engine uses the information to report a TLS error or success.
+/* This module populates a TLSRPT_WRAPPER object with a)
+/* remote TLSRPT policy information, b) remote TLSA or STS policy
+/* information, and c) selected SMTP connection information. This
+/* object is passed to a TLS protocol engine, which may run in a
+/* different process than the SMTP protocol engine. The TLS protocol
+/* engine uses the TLSRPT_WRAPPER object to report a TLS handshake
+/* error to a TLSRPT library. The SMTP protocol engine uses the
+/* object to report a TLS handshake error or success.
/*
-/* smtp_tls_post_jail() does configuration sanity checks and
-/* returns 0 if successful, i.e. TLSRPT support is properly
+/* smtp_tls_post_jail() does configuration sanity checks and returns
+/* 0 if successful, i.e. TLSRPT support is properly
/* configured. Otherwise it returns -1 and logs a warning. Arguments:
/* .IP sockname_pname
-/* The name of a configuration parameter for the endpoint that is
-/* managed by TLSRPT infrastructure. This is used in a diagnostic
-/* message.
+/* The name of a configuration parameter for the endpoint that
+/* is managed by TLSRPT infrastructure. This name is used in a
+/* diagnostic message.
/* .IP sockname_pval
/* The value of said parameter.
/* .PP
-/* smtp_tlsrpt_create_wrapper() destroys any TLSRPT_WRAPPER
-/* referenced by state->tlsrpt, and looks for a TLSRPT
-/* policy for the specified domain. If one policy exists,
-/* smtp_tlsrpt_create_wrapper() attaches a TLSRPT_WRAPPER instance
-/* to state->tlsrpt. Otherwise, state->tlsrpt will be null, and
-/* other smtp_tlsrpt_* calls must not be made. The TLSRPT_WRAPPER
-/* instance may be reused for different SMTP connections with the
-/* same TLSRPT policy domain. Arguments:
+/* smtp_tlsrpt_create_wrapper() destroys a TLSRPT_WRAPPER referenced
+/* by state->tlsrpt, and looks for a TLSRPT policy for the specified
+/* domain. If one policy exists, smtp_tlsrpt_create_wrapper()
+/* attaches a TLSRPT_WRAPPER instance to state->tlsrpt. Otherwise,
+/* state->tlsrpt will be null, and other smtp_tlsrpt_* calls must not
+/* be made. The TLSRPT_WRAPPER instance may be reused for different
+/* SMTP connections for the same TLSRPT policy domain. Arguments:
/* .IP domain
/* The name of a domain that may publish a TLSRPT policy. An
/* internationalized domain name may be in U-label or A-label form
-/* (it will be converted to A-label internally).
+/* (the U-label form will be converted to A-label internally).
/* .PP
-/* smtp_tlsrpt_set_tls_policy() updates the TLSRPT_WRAPPER with
-/* DANE or STS TLS policy information, and clears information
-/* that was added with smtp_tlsrpt_set_tcp_connection() or
-/* smtp_tlsrpt_set_ehlo_resp().
+/* smtp_tlsrpt_set_tls_policy() updates the TLSRPT_WRAPPER
+/* object with DANE or STS TLS policy information, and clears
+/* information that was added with smtp_tlsrpt_set_tcp_connection()
+/* or smtp_tlsrpt_set_ehlo_resp().
/* .PP
-/* smtp_tlsrpt_set_tcp_connection() updates the TLSRPT_WRAPPER with
-/* TCP connection properties.
+/* smtp_tlsrpt_set_tcp_connection() updates the TLSRPT_WRAPPER
+/* object with TCP connection properties.
/* .PP
-/* smtp_tlsrpt_set_ehlo_resp() updates the TLSRPT_WRAPPER with the
-/* SMTP server's EHLO response.
+/* smtp_tlsrpt_set_ehlo_resp() updates the TLSRPT_WRAPPER object
+/* with the SMTP server's EHLO response.
/* BUGS
/* This module inherits all limitations from tlsrpt_wrapper(3).
/* SEE ALSO
const char *sockname_pval)
{
if (smtp_dns_support == SMTP_DNS_DISABLED) {
- msg_warn("Cannot enable TLRPT support: DNS is disabled");
+ msg_warn("Cannot enable %s: DNS is disabled", smtp_tlsrpt_support);
return (-1);
}
if (*sockname_pval == 0) {
* Lexical features: As specified in RFC 8460, a TLSRPT policy record
* must start with a version field ("v=TLSRPTv1") followed by *WSP;*WSP
* and at least one other field (we must not assume that the second field
- * will be "rua"). We leave further validation to the TLSRPT library,
- * where it belongs.
+ * will be "rua"). We leave further validation to the code that actually
+ * needs it.
*/
#define TLSRPTv1_MAGIC "v=TLSRPTv1"
#define TLSRPTv1_MAGIC_LEN (sizeof(TLSRPTv1_MAGIC) - 1)
next = rr->next;
if (strncmp(rr->data, TLSRPTv1_MAGIC, TLSRPTv1_MAGIC_LEN) != 0)
- /* Ignore non-TLSRPT info. */
+ /* Ignore non-TLSRPTv1 info. */
continue;
cp = rr->data + TLSRPTv1_MAGIC_LEN;
continue;
}
if (rr_result) {
- msg_warn("%s: Too many policies for %s",
+ msg_warn("%s: Too many TLSRPT policies for %s",
smtp_tlsrpt_support, adomain);
dns_rr_free(rr_result);
+ rr_result = 0;
break;
}
rr_result = rr;
/*
* Get the IP client address string. The Postfix SMTP_ITERATOR already
- * contains strings with other connection information.
+ * contains strings with server-side connection information.
*/
if (getsockname(vstream_fileno(session->stream),
(struct sockaddr *) &addr_storage,
tls_dane.o: tls.h
tls_dane.o: tls_dane.c
tls_dh.o: ../../include/argv.h
+tls_dh.o: ../../include/been_here.h
tls_dh.o: ../../include/check_arg.h
tls_dh.o: ../../include/dns.h
tls_dh.o: ../../include/mail_params.h
#define TLS_PEEK_PEER_CERT(ssl) SSL_get_peer_certificate(ssl)
#define TLS_FREE_PEER_CERT(x) X509_free(x)
#define tls_set_bio_callback BIO_set_callback
+#endif
+
+#if OPENSSL_VERSION_PREREQ(3,2)
+#define TLS_GROUP_NAME(ssl) SSL_get0_group_name(ssl)
+#elif OPENSSL_VERSION_PREREQ(3,0)
+#define TLS_GROUP_NAME(ssl) \
+ SSL_group_to_name((ssl), SSL_get_negotiated_group(ssl))
+#else
+#define TLS_GROUP_NAME(ssl) ((const char *)0)
#endif
/*
int errorcode; /* First error at error depth */
int must_fail; /* Failed to load trust settings */
int rpt_reported; /* Failure was reported with TLSRPT */
- char *fail_type; /* Doomed by policy */
+ char *ffail_type; /* Forced verification failure */
} TLS_SESS_STATE;
/*
const char *mdalg; /* default message digest algorithm */
const TLS_DANE *dane; /* DANE TLSA verification */
struct TLSRPT_WRAPPER *tlsrpt; /* RFC 8460 reporting */
- char *fail_type; /* verification must fail by policy */
+ char *ffail_type; /* Forced verification failure */
} TLS_CLIENT_START_PROPS;
extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *);
/*
/* Victor Duchovni
/* Morgan Stanley
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System library. */
msg_info("%s: re-using session with untrusted peer credential, "
"look for details earlier in the log", props->namaddr);
}
- /* TODO(wietse) In the non-reuse case, tlsrprt the root cause? */
+ /* TODO(wietse) Don't log TLSRPT success/failure for reused session. */
}
/* verify_rpk - process RFC7250 raw public key verification status */
msg_info("%s: re-using session with untrusted certificate, "
"look for details earlier in the log", props->namaddr);
}
- /* TODO(wietse) In the non-reuse case, tlsrprt the root cause? */
+ /* TODO(wietse) Don't log TLSRPT success/failure for reused session. */
}
/* add_namechecks - tell OpenSSL what names to check */
#ifdef USE_TLSRPT
if (props->tlsrpt) {
trw_report_failure(props->tlsrpt, TLSRPT_TLSA_INVALID,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
"all-TLSA-records-unusable");
}
#endif
#ifdef USE_TLSRPT
if (props->tlsrpt) {
trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
"all-fingerprints-unusable");
}
#endif
#ifdef USE_TLSRPT
if (props->tlsrpt) {
trw_report_failure(props->tlsrpt, TLSRPT_TLSA_INVALID,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
"all-TLSA-records-unusable");
}
#endif
#ifdef USE_TLSRPT
if (props->tlsrpt) {
trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
"all-trust-anchors-unusable");
}
#endif
* certificate matches in tls_verify.c. TODO(wietse) how was this handled
* historically?
*/
- if (props->fail_type) {
- TLScontext->fail_type = mystrdup(props->fail_type);
+ if (props->ffail_type) {
+ TLScontext->ffail_type = mystrdup(props->ffail_type);
TLScontext->must_fail = 1;
}
#ifdef USE_TLSRPT
if (props->tlsrpt)
trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
"tls-handshake-failure");
#endif
uncache_session(app_ctx->ssl_ctx, TLScontext);
/*
* Global library
*/
+#include <been_here.h>
#include <mail_params.h>
/* TLS library. */
{
#ifndef OPENSSL_NO_ECDH
SSL_CTX *tmpctx;
- int *nids;
- int space = 10;
- int n = 0;
+ BH_TABLE *seen;
char *save;
char *groups;
char *group;
+ static VSTRING *names;
if ((tmpctx = SSL_CTX_new(TLS_method())) == 0) {
msg_warn("cannot allocate temp SSL_CTX");
tls_print_errors();
return (AG_STAT_NO_RETRY);
}
- nids = mymalloc(space * sizeof(int));
+ if (!names)
+ names = vstring_alloc(sizeof DEF_TLS_EECDH_AUTO +
+ sizeof DEF_TLS_FFDHE_AUTO);
+ VSTRING_RESET(names);
+ /*
+ * OpenSSL does not tolerate duplicate groups in the requested list.
+ * Deduplicate case-insensitively, just in case OpenSSL some day supports
+ * case-insensitive group lookup. Users who specify the group name twice
+ * and get the case wrong the first time deserve to be unhappy. :-)
+ *
+ * OpenSSL 3.3 supports "?<name>" as a syntax for optionally ignoring
+ * unsupported groups, so we could skip checking against the throw-away
+ * CTX when linked against 3.3 or higher, but the cost savings don't
+ * justify the #ifdef overhead for now.
+ */
+ seen = been_here_init(0, BH_FLAG_FOLD);
+
+#define GROUPS_SEP CHARS_COMMA_SP ":"
#define SETUP_AG_RETURN(val) do { \
+ been_here_free(seen); \
myfree(save); \
- myfree(nids); \
SSL_CTX_free(tmpctx); \
return (val); \
} while (0)
groups = save = concatenate(eecdh, " ", ffdhe, NULL);
- if ((group = mystrtok(&groups, CHARS_COMMA_SP)) == 0) {
+ if ((group = mystrtok(&groups, GROUPS_SEP)) == 0) {
msg_warn("no %s key exchange group - OpenSSL requires at least one",
origin);
SETUP_AG_RETURN(AG_STAT_NO_GROUP);
}
- for (; group != 0; group = mystrtok(&groups, CHARS_COMMA_SP)) {
- int nid = EC_curve_nist2nid(group);
-
- if (nid == NID_undef)
- nid = OBJ_sn2nid(group);
- if (nid == NID_undef)
- nid = OBJ_ln2nid(group);
- if (nid == NID_undef) {
- msg_warn("ignoring unknown key exchange group \"%s\"", group);
+ for (; group != 0; group = mystrtok(&groups, GROUPS_SEP)) {
+ if (been_here_fixed(seen, group))
continue;
- }
-
/*
- * Validate the NID by trying it as the group for a throw-away SSL
- * context. Silently skip unsupported code points. This way, we can
- * list X25519 and X448 as soon as the nids are assigned, and before
- * the supporting code is implemented. They'll be silently skipped
- * when not yet supported.
+ * Validate the group name by trying it as the group for a throw-away
+ * SSL context. This way, we can ask for new groups that may not yet be
+ * supported by the underlying OpenSSL runtime. Unsupported groups are
+ * silently ignored.
*/
- if (SSL_CTX_set1_curves(tmpctx, &nid, 1) <= 0) {
- continue;
+ ERR_set_mark();
+ if (SSL_CTX_set1_curves_list(tmpctx, group) > 0) {
+ if (VSTRING_LEN(names) > 0)
+ VSTRING_ADDCH(names, ':');
+ vstring_strcat(names, group);
}
- if (++n > space) {
- space *= 2;
- nids = myrealloc(nids, space * sizeof(int));
- }
- nids[n - 1] = nid;
+ ERR_pop_to_mark();
}
- if (n == 0) {
+ if (VSTRING_LEN(names) == 0) {
/* The names may be case-sensitive */
msg_warn("none of the %s key exchange groups are supported", origin);
SETUP_AG_RETURN(AG_STAT_NO_GROUP);
}
- if (SSL_CTX_set1_curves(ctx, nids, n) <= 0) {
+ VSTRING_TERMINATE(names);
+
+ if (SSL_CTX_set1_curves_list(ctx, vstring_str(names)) <= 0) {
msg_warn("failed to set up the %s key exchange groups", origin);
tls_print_errors();
SETUP_AG_RETURN(AG_STAT_NO_RETRY);
kex_name = OBJ_nid2sn(EVP_PKEY_type(nid));
break;
+#if defined(EVP_PKEY_KEYMGMT)
+ case EVP_PKEY_KEYMGMT:
+ kex_name = EVP_PKEY_get0_type_name(dh_pkey);
+ TLScontext->kex_bits = 0;
+ break;
+#endif
+
case EVP_PKEY_DH:
kex_name = "DHE";
TLScontext->kex_bits = EVP_PKEY_bits(dh_pkey);
EVP_PKEY_free(dh_pkey);
}
+ /*
+ * On the client side, a TLS 1.3 KEM has no server key, just ciphertext to
+ * decapsulate, but, as of OpenSSL 3.0, the client can still obtain the
+ * negotiated group name directly. We nevertheless still try to get the
+ * group details from the peer key first, which works with OpenSSL 1.1.1
+ * and retains the original output format for the (EC)DH groups.
+ */
+ if (!kex_name)
+ kex_name = TLS_GROUP_NAME(ssl);
+
/*
* On the client end, the certificate may be present, but not used, so we
* check via SSL_get_signature_nid(). This means that local signature
TLScontext->errorcode = X509_V_OK;
TLScontext->errorcert = 0;
TLScontext->rpt_reported = 0;
- TLScontext->fail_type = 0;
+ TLScontext->ffail_type = 0;
return (TLScontext);
}
myfree((void *) TLScontext->srvr_sig_dgst);
if (TLScontext->errorcert)
X509_free(TLScontext->errorcert);
- if (TLScontext->fail_type)
- myfree(TLScontext->fail_type);
+ if (TLScontext->ffail_type)
+ myfree(TLScontext->ffail_type);
myfree((void *) TLScontext);
}
#define TLS_ATTR_MDALG "mdalg"
#define TLS_ATTR_DANE "dane"
#define TLS_ATTR_TLSRPT "tlsrpt"
-#define FAIL_TYPE "fail_type"
+#define TLS_ATTR_FFAIL_TYPE "forced_failure_type"
/*
* TLS_TLSA attributes.
SEND_ATTR_FUNC(tls_proxy_client_tlsrpt_print,
(const void *) props->tlsrpt),
#endif
- SEND_ATTR_STR(FAIL_TYPE,
- STRING_OR_EMPTY(props->fail_type)),
+ SEND_ATTR_STR(TLS_ATTR_FFAIL_TYPE,
+ STRING_OR_EMPTY(props->ffail_type)),
ATTR_TYPE_END);
/* Do not flush the stream. */
if (msg_verbose)
if (props->tlsrpt)
trw_free(props->tlsrpt);
#endif
- if (props->fail_type)
- myfree(props->fail_type);
+ if (props->ffail_type)
+ myfree(props->ffail_type);
myfree((void *) props);
}
VSTRING *cipher_grade = vstring_alloc(25);
VSTRING *cipher_exclusions = vstring_alloc(25);
VSTRING *mdalg = vstring_alloc(25);
- VSTRING *fail_type = vstring_alloc(25);
+ VSTRING *ffail_type = vstring_alloc(25);
#ifdef USE_TLSRPT
#define EXPECT_START_SCAN_RETURN 17
RECV_ATTR_FUNC(tls_proxy_client_tlsrpt_scan,
&props->tlsrpt),
#endif
- RECV_ATTR_STR(FAIL_TYPE, fail_type),
+ RECV_ATTR_STR(TLS_ATTR_FFAIL_TYPE, ffail_type),
ATTR_TYPE_END);
/* Always construct a well-formed structure. */
props->nexthop = vstring_export(nexthop);
props->cipher_grade = vstring_export(cipher_grade);
props->cipher_exclusions = vstring_export(cipher_exclusions);
props->mdalg = vstring_export(mdalg);
- EXPORT_OR_NULL(props->fail_type, fail_type);
+ EXPORT_OR_NULL(props->ffail_type, ffail_type);
ret = (ret == EXPECT_START_SCAN_RETURN ? 1 : -1);
if (ret != 1) {
tls_proxy_client_start_free(props);
/*
/* Victor Duchovni
/* Morgan Stanley
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System library. */
/*
* If an external policy flagged an error, report that instead.
*/
- if (TLScontext->fail_type) {
+ if (TLScontext->ffail_type) {
msg_info("certificate verification failed for %s: "
- "external policy failure (%s)",
- TLScontext->namaddr, TLScontext->fail_type);
+ "external policy failure (%s)",
+ TLScontext->namaddr, TLScontext->ffail_type);
#ifdef USE_TLSRPT
if (tlsrpt) {
tlsrpt_failure_t failure_type;
- if ((failure_type = convert_tlsrpt_policy_failure(TLScontext->fail_type)) < 0)
+ if ((failure_type = convert_tlsrpt_policy_failure(TLScontext->ffail_type)) < 0)
msg_panic("tls_log_verify_error: unexpected failure_reason: %s",
- TLScontext->fail_type);
+ TLScontext->ffail_type);
trw_report_failure(tlsrpt, failure_type,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
/* failure_reason= */ (char *) 0);
}
#endif
#ifdef USE_TLSRPT
if (tlsrpt)
trw_report_failure(tlsrpt, TLSRPT_CERTIFICATE_NOT_TRUSTED,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
/* failure_code= */ (char *) 0);
#endif
break;
#ifdef USE_TLSRPT
if (tlsrpt)
trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
CERT_ERROR_TO_STRING(err));
#endif
break;
#ifdef USE_TLSRPT
if (tlsrpt)
trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
CERT_ERROR_TO_STRING(err));
#endif
break;
#ifdef USE_TLSRPT
if (tlsrpt)
trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
CERT_ERROR_TO_STRING(err));
#endif
break;
#ifdef USE_TLSRPT
if (tlsrpt)
trw_report_failure(tlsrpt, TLSRPT_CERTIFICATE_EXPIRED,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
/* failure_code= */ (char *) 8);
#endif
break;
#ifdef USE_TLSRPT
if (tlsrpt)
trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
CERT_ERROR_TO_STRING(err));
#endif
break;
#ifdef USE_TLSRPT
if (tlsrpt)
trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
CERT_ERROR_TO_STRING(err));
#endif
break;
/* NAME
/* tlsrpt_wrapper 3
/* SUMMARY
-/* TLSRPT support for the TLS protocol engine
+/* TLSRPT support for the SMTP and TLS protocol engines
/* SYNOPSIS
/* #include <tlsrpt_wrapper.h>
/*
/* void trw_report_failure(
/* TLSRPT_WRAPPER *trw,
/* tlsrpt_failure_t failure_type,
-/* const char *additional_detail,
+/* const char *additional_info,
/* const char *failure_reason)
/*
/* void trw_report_success(
/* int valid_tlsrpt_policy_failure(
/* const char *failure_name)
/* #endif /* USE_TLS */
-/* ARCHITECTURE, BOTTOM-UP VIEW
-/* Postfix TLSRPT support uses the TLSRPT client library from
-/* sys4.de. That library makes the reasonable assumption that
+/* POSTFIX ARCHITECTURE, BOTTOM-UP VIEW
+/* .ad
+/* .fi
+/* This module encapsulates TLSRPT support for Postfix's
+/* multi-process and multi-layer architecture. The text that follows
+/* explains the purpose of this software layer.
+/*
+/* First, Postfix TLSRPT support uses the TLSRPT client library
+/* from sys4.de. That library makes the reasonable assumption that
/* all calls concerning one SMTP session will be made from within
/* one process.
/*
-/* With Postfix, the TLS protocol engine may be located in a
-/* different process than the SMTP protocol engine, and both
-/* processes need the ability to report a TLS error.
+/* Second, some TLS errors are detected in the SMTP protocol
+/* engine (example: a remote SMTP server does not announce STARTTLS
+/* support), while other TLS errors are detected in the TLS protocol
+/* engine (example: certificate verification error).
/*
-/* To bridge this gap, the SMTP protocol engine forwards SMTP
-/* session and TLS policy information to the TLS protocol engine in
-/* the form of a TLSRPT_WRAPPER object that contains SMTP and other
-/* information that the TLSRPT client library needs. The TLS engine
-/* can pass that information to the TLSRPT client library to report
-/* a TLS error. The SMTP protocol engine can use that same
-/* information to report a TLS error or success.
-/* IMPLEMENTATION
+/* Third, the Postfix TLS protocol engine may be located in a
+/* different process than the SMTP protocol engine. And even if the
+/* two are located in the same process, the TLS protocol engine knows
+/* nothing about SMTP. Hence, there needs to be an abstraction that
+/* isolates the TLS protocol engine from the SMTP-specific details
+/* of TLSRPT.
+/*
+/* Fourth, Postfix has a pipelined and layered architecture where
+/* each process (or architectural layer) handles a problem as it
+/* runs into it, instead of reporting problem details back to its
+/* pipeline predecessor (or back to a higher architectural layer).
+/* TLSRPT_WRAPPER IMPLEMENTATION
/* .ad
/* .fi
-/* The Postfix SMTP protocol engine (smtp_proto.c) reports TLS
-/* errors when TLS support is required but unavailable, or requests
-/* the Postfix TLS protocol engine to perform a TLS protocol
-/* handshake over an open SMTP connection. The SMTP protocol engine
-/* either calls the TLS protocol engine directly, or calls it over
-/* RPC in a tlsproxy(8) process.
+/* At a high level, the SMTP protocol engine encapsulates SMTP
+/* session and TLS policy information in an opaque TLSRPT_WRAPPER
+/* object, and passes that object to the TLS protocol engine. The
+/* TLS protocol engine can invoke TLSRPT_WRAPPER methods to report a
+/* TLS error through the sys4.de TLSRPT client library. In a similar
+/* manner, the SMTP protocol engine can invoke TLSRPT_WRAPPER object
+/* methods to report a TLS error or success.
+/*
+/* At a low level, The Postfix SMTP protocol engine (smtp_proto.c)
+/* reports TLS errors when TLS support is required but unavailable,
+/* or requests the Postfix TLS protocol engine to perform a TLS
+/* protocol handshake over an open SMTP connection. The SMTP
+/* protocol engine either calls the TLS protocol engine directly,
+/* or calls it over local IPC in a tlsproxy(8) process.
/*
-/* The TLS protocol engine may report a TLS error through the
-/* tlsrpt_wrapper library, and either returns no TLS session object,
-/* or a TLS session object for a completed handshake. The TLS
-/* session object will indicate if the TLS protocol engine reported
-/* any TLS error through TLSRPT.
+/* The TLS protocol engine may report a TLS error by invoking
+/* TLSRPT_WRAPPER methods, and either returns no TLS session object,
+/* or a TLS session object for a completed handshake. The TLS session
+/* object will indicate if the TLS protocol engine reported any
+/* TLS error through TLSRPT (for example an error that resulted in
+/* a successful TLS handshake with a downgraded TLS security level).
/*
/* The Postfix SMTP protocol engine reports success or failure
-/* through the tlsrpt_wrapper library, depending on whether all
-/* matching requirements were satisfied. SMTP protocol engine
-/* does not report success or failure through the tlsrpt_wrapper
-/* library if the TLS protocol engine already reported a failure.
-/* WRAPPER API
+/* by invoking TLSRPT_WRAPPER methods, depending on whether all
+/* matching requirements were satisfied. The SMTP protocol engine
+/* does not report success or failure by invoking TLSRPT_WRAPPER
+/* methods if the TLS protocol engine already reported a failure.
+/* TLSRPT_WRAPPER API
/* .ad
/* .fi
/* The functions below must be called in a specific order. All
/* string inputs are copied. If a required call is missing then
-/* the request will be ignored, and a warning will be logged.
+/* the request will be ignored, and a warning will be logged,
+/* but this not affect email deliveries.
/* .PP
/* trw_create() must be called before other trw_xxx() requests can
/* be made. Arguments:
/* trw_free() destroys storage allocated with other trw_xxx()
/* requests.
/* .PP
-/* trw_set_tls_policy() must be called by the SMTP protocol
-/* engine after it found a DANE, STS, or no policy, and before it
-/* tries to establish a new SMTP connection. This function clears
-/* information that was specified earlier with trw_set_tls_policy()
-/* or trw_set_tcp_connection(), and whether trw_report_failure()
+/* trw_set_tls_policy() must be called by the SMTP protocol engine
+/* after it found a DANE, STS, or no policy, and before it tries to
+/* establish a new SMTP connection. This function clears information
+/* that was specified earlier with trw_set_tls_policy() or
+/* trw_set_tcp_connection(), and resets whether trw_report_failure()
/* or trw_report_success() were called. Mapping from arguments to
/* TLSRPT report fields:
/* .IP tls_policy_type
/* policies[].policy.policy-type.
-/* .IP tls_policy_strings
+/* .IP tls_policy_strings (may be null)
/* policies[].policy.policy-string[]. Ignored if the tls_policy_type
/* value is TLSRPT_NO_POLICY_FOUND.
-/* .IP tls_policy_domain
+/* .IP tls_policy_domain (may be null)
/* policies[].policy.policy-domain.
/* .IP mx_host_patterns (may be null)
/* policies[].policy.mx-host[]. Ignored if the tls_policy_type
/* connection. Mapping from arguments to TLSRPT report fields:
/* .IP failure_type
/* policies[].failure-details[].result-type.
-/* .IP additional_detail (may be null)
+/* .IP additional_info (may be null)
/* policies[].failure-details[].additional-information.
/* .IP failure_reason (may be null)
/* policies[].failure-details[].failure-reason-code
/* module is built with TLSRPT support. This allows the names to
/* be used even if TLSRPT is disabled.
/* DIAGNOSTICS
-/* Some functions will log a a warning when information is missing,
-/* but such warnings will not affect the SMTP or TLS protocol engine.
+/* Some functions will log a warning when information is missing.
+/* Such warnings will not affect the operation of the SMTP or TLS
+/* protocol engine.
/* BUGS
/* This implementation is suitable to report successful TLS policy
/* compliance, and to report a failure that prevents TLS policy
}
/*
- * Report a libc error. Do not report success if errno was zero.
+ * Report a libc error. Do not report success if errno was zero. When
+ * debug logging is enabled, also log some library-internal info.
*/
else {
err = tlsrpt_errno_from_error_code(libtlsrpt_errorcode);
msg_warn("Could not report TLS handshake result to tlsrpt library:"
" %s (errno %d)", mystrerror(err), err);
+ if (msg_verbose)
+ msg_warn("Error location in tlsrpt library: %s (error %d)",
+ tlsrpt_strerror(libtlsrpt_errorcode),
+ libtlsrpt_errorcode);
errno = err;
return (-1);
}
int trw_report_failure(TLSRPT_WRAPPER *trw,
tlsrpt_failure_t failure_type,
- const char *additional_detail,
+ const char *additional_info,
const char *failure_reason)
{
const char myname[] = "trw_report_failure";
/* receiving_mx_hostname= */ trw->rcv_mta_name,
/* receiving_mx_helo= */ trw->rcv_mta_ehlo,
/* receiving_ip= */ trw->rcv_mta_addr,
- /* additional_information= */ additional_detail,
+ /* additional_information= */ additional_info,
/* failure_reason_code= */ failure_reason);
if (res == 0)
res = tlsrpt_finish_policy(dr, TLSRPT_FINAL_FAILURE);
/* NAME
/* tlsrpt_wrapper 3h
/* SUMMARY
-/* TLSRPT support for the TLS protocol engine
+/* TLSRPT support for the SMTP and TLS protocol engines
/* SYNOPSIS
/* #include <tlsrpt_wrapper.h>
/* DESCRIPTION
const char *rcv_mta_ehlo);
extern int trw_report_failure(TLSRPT_WRAPPER *trw,
tlsrpt_failure_t policy_failure,
- const char *additional_detail,
+ const char *additional_info,
const char *failure_reason);
extern int trw_report_success(TLSRPT_WRAPPER *trw);
extern int trw_is_reported(const TLSRPT_WRAPPER *trw);
&& state->is_server_role == 0)
trw_report_failure(state->client_start_props->tlsrpt,
TLSRPT_VALIDATION_FAILURE,
- /* additional_detail= */ (char *) 0,
+ /* additional_info= */ (char *) 0,
"tls-handshake-failure");
#endif
tlsp_state_free(state);
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System libraries. */