smtp_tls_exclude_ciphers
diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html
index ba706a170..e116f43aa 100644
--- a/postfix/html/smtp.8.html
+++ b/postfix/html/smtp.8.html
@@ -762,45 +762,54 @@ SMTP(8) SMTP(8)
When set to "yes", report the TLSRPT status only for "new" TLS
sessions.
+ Available in Postfix version 3.10.5 and later:
+
+ smtp_tls_enforce_sts_mx_patterns (yes)
+ Transform the TLS policy from an STS policy plugin: connect to
+ an MX host only if its name matches the STS policy MX host pat-
+ tern, and match the server certificate against the MX hostname.
+
+ Available in Postfix version 3.11 and later:
+
tls_required_enable (yes)
Enable support for the "TLS-Required: no" message header,
defined in RFC 8689.
OBSOLETE STARTTLS CONTROLS
- The following configuration parameters exist for compatibility with
- Postfix versions before 2.3. Support for these will be removed in a
+ The following configuration parameters exist for compatibility with
+ Postfix versions before 2.3. Support for these will be removed in a
future release.
smtp_use_tls (no)
- Opportunistic mode: use TLS when a remote SMTP server announces
+ Opportunistic mode: use TLS when a remote SMTP server announces
STARTTLS support, otherwise send the mail in the clear.
smtp_enforce_tls (no)
- Enforcement mode: require that remote SMTP servers use TLS
+ Enforcement mode: require that remote SMTP servers use TLS
encryption, and never send mail in the clear.
smtp_tls_enforce_peername (yes)
- With mandatory TLS encryption, require that the remote SMTP
- server hostname matches the information in the remote SMTP
+ With mandatory TLS encryption, require that the remote SMTP
+ server hostname matches the information in the remote SMTP
server certificate.
smtp_tls_per_site (empty)
- Optional lookup tables with the Postfix SMTP client TLS usage
- policy by next-hop destination and by remote SMTP server host-
+ Optional lookup tables with the Postfix SMTP client TLS usage
+ policy by next-hop destination and by remote SMTP server host-
name.
smtp_tls_cipherlist (empty)
- Obsolete Postfix < 2.3 control for the Postfix SMTP client TLS
+ Obsolete Postfix < 2.3 control for the Postfix SMTP client TLS
cipher list.
RESOURCE AND RATE CONTROLS
smtp_connect_timeout (30s)
- The Postfix SMTP client time limit for completing a TCP connec-
+ The Postfix SMTP client time limit for completing a TCP connec-
tion, or zero (use the operating system built-in time limit).
smtp_helo_timeout (300s)
- The Postfix SMTP client time limit for sending the HELO or EHLO
- command, and for receiving the initial remote SMTP server
+ The Postfix SMTP client time limit for sending the HELO or EHLO
+ command, and for receiving the initial remote SMTP server
response.
lmtp_lhlo_timeout (300s)
@@ -812,19 +821,19 @@ SMTP(8) SMTP(8)
mand, and for receiving the remote SMTP server response.
smtp_mail_timeout (300s)
- The Postfix SMTP client time limit for sending the MAIL FROM
+ The Postfix SMTP client time limit for sending the MAIL FROM
command, and for receiving the remote SMTP server response.
smtp_rcpt_timeout (300s)
- The Postfix SMTP client time limit for sending the SMTP RCPT TO
+ The Postfix SMTP client time limit for sending the SMTP RCPT TO
command, and for receiving the remote SMTP server response.
smtp_data_init_timeout (120s)
- The Postfix SMTP client time limit for sending the SMTP DATA
+ The Postfix SMTP client time limit for sending the SMTP DATA
command, and for receiving the remote SMTP server response.
smtp_data_xfer_timeout (180s)
- The Postfix SMTP client time limit for sending the SMTP message
+ The Postfix SMTP client time limit for sending the SMTP message
content.
smtp_data_done_timeout (600s)
@@ -838,13 +847,13 @@ SMTP(8) SMTP(8)
Available in Postfix version 2.1 and later:
smtp_mx_address_limit (5)
- The maximal number of MX (mail exchanger) IP addresses that can
- result from Postfix SMTP client mail exchanger lookups, or zero
+ The maximal number of MX (mail exchanger) IP addresses that can
+ result from Postfix SMTP client mail exchanger lookups, or zero
(no limit).
smtp_mx_session_limit (2)
- The maximal number of SMTP sessions per delivery request before
- the Postfix SMTP client gives up or delivers to a fall-back
+ The maximal number of SMTP sessions per delivery request before
+ the Postfix SMTP client gives up or delivers to a fall-back
relay host, or zero (no limit).
smtp_rset_timeout (20s)
@@ -854,17 +863,17 @@ SMTP(8) SMTP(8)
Available in Postfix version 2.2 and earlier:
lmtp_cache_connection (yes)
- Keep Postfix LMTP client connections open for up to $max_idle
+ Keep Postfix LMTP client connections open for up to $max_idle
seconds.
Available in Postfix version 2.2 and later:
smtp_connection_cache_destinations (empty)
- Permanently enable SMTP connection caching for the specified
+ Permanently enable SMTP connection caching for the specified
destinations.
smtp_connection_cache_on_demand (yes)
- Temporarily enable SMTP connection caching while a destination
+ Temporarily enable SMTP connection caching while a destination
has a high volume of mail in the active queue.
smtp_connection_reuse_time_limit (300s)
@@ -878,23 +887,23 @@ SMTP(8) SMTP(8)
Available in Postfix version 2.3 and later:
connection_cache_protocol_timeout (5s)
- Time limit for connection cache connect, send or receive opera-
+ Time limit for connection cache connect, send or receive opera-
tions.
Available in Postfix version 2.9 - 3.6:
smtp_per_record_deadline (no)
- Change the behavior of the smtp_*_timeout time limits, from a
- time limit per read or write system call, to a time limit to
- send or receive a complete record (an SMTP command line, SMTP
- response line, SMTP message content line, or TLS protocol mes-
+ Change the behavior of the smtp_*_timeout time limits, from a
+ time limit per read or write system call, to a time limit to
+ send or receive a complete record (an SMTP command line, SMTP
+ response line, SMTP message content line, or TLS protocol mes-
sage).
Available in Postfix version 2.11 and later:
smtp_connection_reuse_count_limit (0)
- When SMTP connection caching is enabled, the number of times
- that an SMTP session may be reused before it is closed, or zero
+ 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).
Available in Postfix version 3.4 and later:
@@ -905,13 +914,13 @@ SMTP(8) SMTP(8)
Available in Postfix version 3.7 and later:
smtp_per_request_deadline (no)
- Change the behavior of the smtp_*_timeout time limits, from a
- time limit per plaintext or TLS read or write call, to a com-
- bined time limit for sending a complete SMTP request and for
+ Change the behavior of the smtp_*_timeout time limits, from a
+ time limit per plaintext or TLS read or write call, to a com-
+ bined time limit for sending a complete SMTP request and for
receiving a complete SMTP response.
smtp_min_data_rate (500)
- The minimum plaintext data transfer rate in bytes/second for
+ The minimum plaintext data transfer rate in bytes/second for
DATA requests, when deadlines are enabled with
smtp_per_request_deadline.
@@ -919,54 +928,54 @@ SMTP(8) SMTP(8)
transport_destination_concurrency_limit ($default_destination_concur-
rency_limit)
- A transport-specific override for the default_destination_con-
+ A transport-specific override for the default_destination_con-
currency_limit parameter value, where transport is the master.cf
name of the message delivery transport.
transport_destination_recipient_limit ($default_destination_recipi-
ent_limit)
A transport-specific override for the default_destination_recip-
- ient_limit parameter value, where transport is the master.cf
+ ient_limit parameter value, where transport is the master.cf
name of the message delivery transport.
SMTPUTF8 CONTROLS
Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
smtputf8_enable (yes)
- Enable preliminary SMTPUTF8 support for the protocols described
+ Enable preliminary SMTPUTF8 support for the protocols described
in RFC 6531, RFC 6532, and RFC 6533.
smtputf8_autodetect_classes (sendmail, verify)
- Detect that a message requires SMTPUTF8 support for the speci-
+ Detect that a message requires SMTPUTF8 support for the speci-
fied mail origin classes.
Available in Postfix version 3.2 and later:
enable_idna2003_compatibility (no)
- Enable 'transitional' compatibility between IDNA2003 and
- IDNA2008, when converting UTF-8 domain names to/from the ASCII
+ Enable 'transitional' compatibility between IDNA2003 and
+ IDNA2008, when converting UTF-8 domain names to/from the ASCII
form that is used for DNS lookups.
TROUBLE SHOOTING CONTROLS
debug_peer_level (2)
- The increment in verbose logging level when a nexthop destina-
- tion, remote client or server name or network address matches a
+ The increment in verbose logging level when a nexthop destina-
+ tion, remote client or server name or network address matches a
pattern given with the debug_peer_list parameter.
debug_peer_list (empty)
- Optional list of nexthop destination, remote client or server
- name or network address patterns that, if matched, cause the
- verbose logging level to increase by the amount specified in
+ Optional list of nexthop destination, remote client or server
+ name or network address patterns that, if matched, cause the
+ verbose logging level to increase by the amount specified in
$debug_peer_level.
error_notice_recipient (postmaster)
- The recipient of postmaster notifications about mail delivery
+ The recipient of postmaster notifications about mail delivery
problems that are caused by policy, resource, software or proto-
col errors.
internal_mail_filter_classes (empty)
- What categories of Postfix-generated mail are subject to
- before-queue content inspection by non_smtpd_milters,
+ What categories of Postfix-generated mail are subject to
+ before-queue content inspection by non_smtpd_milters,
header_checks and body_checks.
notify_classes (resource, software)
@@ -974,46 +983,46 @@ SMTP(8) SMTP(8)
MISCELLANEOUS CONTROLS
best_mx_transport (empty)
- Where the Postfix SMTP client should deliver mail when it
+ Where the Postfix SMTP client should deliver mail when it
detects a "mail loops back to myself" error condition.
config_directory (see 'postconf -d' output)
- The default location of the Postfix main.cf and master.cf con-
+ The default location of the Postfix main.cf and master.cf con-
figuration files.
daemon_timeout (18000s)
- How much time a Postfix daemon process may take to handle a
+ How much time a Postfix daemon process may take to handle a
request before it is terminated by a built-in watchdog timer.
delay_logging_resolution_limit (2)
- The maximal number of digits after the decimal point when log-
+ The maximal number of digits after the decimal point when log-
ging delay values.
disable_dns_lookups (no)
Disable DNS lookups in the Postfix SMTP and LMTP clients.
inet_interfaces (all)
- The local network interface addresses that this mail system
+ The local network interface addresses that this mail system
receives mail on.
inet_protocols (see 'postconf -d' output)
- The Internet protocols Postfix will attempt to use when making
+ The Internet protocols Postfix will attempt to use when making
or accepting connections.
ipc_timeout (3600s)
- The time limit for sending or receiving information over an
+ The time limit for sending or receiving information over an
internal communication channel.
lmtp_assume_final (no)
- When a remote LMTP server announces no DSN support, assume that
- the server performs final delivery, and send "delivered" deliv-
+ When a remote LMTP server announces no DSN support, assume that
+ the server performs final delivery, and send "delivered" deliv-
ery status notifications instead of "relayed".
lmtp_tcp_port (24)
The default TCP port that the Postfix LMTP client connects to.
max_idle (100s)
- The maximum amount of time that an idle Postfix daemon process
+ The maximum amount of time that an idle Postfix daemon process
waits for an incoming connection before terminating voluntarily.
max_use (100)
@@ -1027,21 +1036,21 @@ SMTP(8) SMTP(8)
The process name of a Postfix command or daemon process.
proxy_interfaces (empty)
- The remote network interface addresses that this mail system
- receives mail on by way of a proxy or network address transla-
+ The remote network interface addresses that this mail system
+ receives mail on by way of a proxy or network address transla-
tion unit.
smtp_address_preference (any)
The address type ("ipv6", "ipv4" or "any") that the Postfix SMTP
- client will try first, when a destination has IPv6 and IPv4
+ client will try first, when a destination has IPv6 and IPv4
addresses with equal MX preference.
smtp_bind_address (empty)
- An optional numerical network address that the Postfix SMTP
+ An optional numerical network address that the Postfix SMTP
client should bind to when making an IPv4 connection.
smtp_bind_address6 (empty)
- An optional numerical network address that the Postfix SMTP
+ An optional numerical network address that the Postfix SMTP
client should bind to when making an IPv6 connection.
smtp_helo_name ($myhostname)
@@ -1061,7 +1070,7 @@ SMTP(8) SMTP(8)
The syslog facility of Postfix logging.
syslog_name (see 'postconf -d' output)
- A prefix that is prepended to the process name in syslog
+ A prefix that is prepended to the process name in syslog
records, so that, for example, "smtpd" becomes "prefix/smtpd".
Available with Postfix 2.2 and earlier:
@@ -1073,14 +1082,14 @@ SMTP(8) SMTP(8)
Available with Postfix 2.3 and later:
smtp_fallback_relay ($fallback_relay)
- Optional list of relay destinations that will be used when an
- SMTP destination is not found, or when delivery fails due to a
+ Optional list of relay destinations that will be used when an
+ SMTP destination is not found, or when delivery fails due to a
non-permanent error.
Available with Postfix 3.0 and later:
smtp_address_verify_target (rcpt)
- In the context of email address verification, the SMTP protocol
+ In the context of email address verification, the SMTP protocol
stage that determines whether an email address is deliverable.
Available with Postfix 3.1 and later:
@@ -1102,7 +1111,7 @@ SMTP(8) SMTP(8)
Available in Postfix 3.7 and later:
smtp_bind_address_enforce (no)
- Defer delivery when the Postfix SMTP client cannot apply the
+ Defer delivery when the Postfix SMTP client cannot apply the
smtp_bind_address or smtp_bind_address6 setting.
SEE ALSO
diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5
index 22757a2e1..31bfc0375 100644
--- a/postfix/man/man5/postconf.5
+++ b/postfix/man/man5/postconf.5
@@ -3499,6 +3499,10 @@ The LMTP\-specific version of the smtp_tls_enforce_peername
configuration parameter. See there for details.
.PP
This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_enforce_sts_mx_patterns (default: yes)
+See smtp_tls_enforce_sts_mx_patterns.
+.PP
+This feature is available in Postfix >= 3.10.5.
.SH lmtp_tls_exclude_ciphers (default: empty)
The LMTP\-specific version of the smtp_tls_exclude_ciphers
configuration parameter. See there for details.
@@ -8697,6 +8701,12 @@ CommonName of this attacker will be logged).
.PP
This feature is available in Postfix 2.2 and later. With
Postfix 2.3 and later use smtp_tls_security_level instead.
+.SH smtp_tls_enforce_sts_mx_patterns (default: yes)
+Transform the TLS policy from an STS policy plugin: connect to
+an MX host only if its name matches the STS policy MX host pattern,
+and match the server certificate against the MX hostname.
+.PP
+This feature is available in Postfix >= 3.10.5.
.SH smtp_tls_exclude_ciphers (default: empty)
List of ciphers or cipher types to exclude from the Postfix
SMTP client cipher
diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8
index ff7921bd8..dde3d5c7d 100644
--- a/postfix/man/man8/smtp.8
+++ b/postfix/man/man8/smtp.8
@@ -684,6 +684,14 @@ by a local TLSRPT reporting service.
.IP "\fBsmtp_tlsrpt_skip_reused_handshakes (Postfix >= 3.11: no, Postfix 3.10: yes)\fR"
When set to "yes", report the TLSRPT status only for "new" TLS
sessions.
+.PP
+Available in Postfix version 3.10.5 and later:
+.IP "\fBsmtp_tls_enforce_sts_mx_patterns (yes)\fR"
+Transform the TLS policy from an STS policy plugin: connect to
+an MX host only if its name matches the STS policy MX host pattern,
+and match the server certificate against the MX hostname.
+.PP
+Available in Postfix version 3.11 and later:
.IP "\fBtls_required_enable (yes)\fR"
Enable support for the "TLS\-Required: no" message header, defined
in RFC 8689.
diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink
index 061e0aef1..2b174bcac 100755
--- a/postfix/mantools/postlink
+++ b/postfix/mantools/postlink
@@ -729,6 +729,8 @@ while (<>) {
s;\blmtp_tlsrpt_enable\b;$&;g;
s;\blmtp_tlsrpt_socket_name\b;$&;g;
s;\blmtp_tlsrpt_skip_reused_handshakes\b;$&;g;
+ s;\blmtp_tls_enforce_sts_mx_patterns\b;$&;g;
+ s;\bsmtp_tls_enforce_sts_mx_patterns\b;$&;g;
s;\bsmtpd_enforce_tls\b;$&;g;
s;\bsmtpd_sasl_tls_security_options\b;$&;g;
s;\bsmtpd_sasl_type\b;$&;g;
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 4b0ca1212..cbaf202ec 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -19566,6 +19566,20 @@ second etc. TLS handshake to report.
This feature is available in Postfix ≥ 3.10.
+%PARAM lmtp_tls_enforce_sts_mx_patterns yes
+
+ See smtp_tls_enforce_sts_mx_patterns.
+
+ This feature is available in Postfix ≥ 3.10.5.
+
+%PARAM smtp_tls_enforce_sts_mx_patterns yes
+
+ Transform the TLS policy from an STS policy plugin: connect to
+an MX host only if its name matches the STS policy MX host pattern,
+and match the server certificate against the MX hostname.
+
+ This feature is available in Postfix ≥ 3.10.5.
+
%PARAM full_name_encoding_charset utf-8
The character set name (also called "charset") that Postfix
diff --git a/postfix/proto/stop.spell-cc b/postfix/proto/stop.spell-cc
index ff0517210..4313fb9d7 100644
--- a/postfix/proto/stop.spell-cc
+++ b/postfix/proto/stop.spell-cc
@@ -1868,3 +1868,5 @@ deduplicates
intmax
lflag
REPLYCODE
+PTEST
+finalizer
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 551020a86..28a879f1c 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -4514,6 +4514,12 @@ extern char *var_smtp_tlsrpt_sockname;
#define DEF_LMTP_TLSRPT_SKIP_REUSED_HS DEF_SMTP_TLSRPT_SKIP_REUSED_HS
extern int var_smtp_tlsrpt_skip_reused_hs;
+#define VAR_SMTP_TLS_ENF_STS_MX_PAT "smtp_tls_enforce_sts_mx_patterns"
+#define DEF_SMTP_TLS_ENF_STS_MX_PAT "yes"
+#define VAR_LMTP_TLS_ENF_STS_MX_PAT "lmtp_tls_enforce_sts_mx_patterns"
+#define DEF_LMTP_TLS_ENF_STS_MX_PAT "yes"
+extern bool var_smtp_tls_enf_sts_mx_pat;
+
/*
* RFC 2047 encoding of full name info.
*/
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 85e924775..564e97222 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20250825"
+#define MAIL_RELEASE_DATE "20250906"
#define MAIL_VERSION_NUMBER "3.11"
#ifdef SNAPSHOT
diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in
index f8cde6978..25002c658 100644
--- a/postfix/src/smtp/Makefile.in
+++ b/postfix/src/smtp/Makefile.in
@@ -8,10 +8,10 @@ OBJS = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \
smtp_sasl_proto.o smtp_sasl_glue.o smtp_reuse.o smtp_map11.o \
smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o smtp_tlsrpt.o
HDRS = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h smtp_sasl_auth_cache.h
-TESTSRC =
+TESTSRC = smtp_policy_test.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
-TESTPROG= smtp_unalias smtp_map11
+TESTPROG= smtp_unalias smtp_map11 smtp_tls_policy_test
PROG = smtp
INC_DIR = ../../include
LIBS = ../../lib/lib$(LIB_PREFIX)master$(LIB_SUFFIX) \
@@ -33,7 +33,7 @@ Makefile: Makefile.in
test: $(TESTPROG)
-tests: smtp_map11_test
+tests: smtp_map11_test test_smtp_tls_policy
root_tests:
@@ -64,6 +64,14 @@ smtp_map11_test: smtp_map11 smtp_map11.ref
diff smtp_map11.ref smtp_map11.tmp
rm -f smtp_map11.tmp
+SMTP_POLICY_TEST_OBJ = smtp_tls_policy_test.o smtp_tls_policy.o smtp_state.o smtp_key.o
+
+smtp_tls_policy_test: $(SMTP_POLICY_TEST_OBJ) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $(SMTP_POLICY_TEST_OBJ) $(LIBS) $(SYSLIBS)
+
+test_smtp_tls_policy: smtp_tls_policy_test
+ $(SHLIB_ENV) $(VALGRIND) ./smtp_tls_policy_test
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
@@ -777,6 +785,7 @@ smtp_tls_policy.o: ../../include/htable.h
smtp_tls_policy.o: ../../include/mail_params.h
smtp_tls_policy.o: ../../include/maps.h
smtp_tls_policy.o: ../../include/match_list.h
+smtp_tls_policy.o: ../../include/midna_domain.h
smtp_tls_policy.o: ../../include/mime_state.h
smtp_tls_policy.o: ../../include/msg.h
smtp_tls_policy.o: ../../include/msg_stats.h
@@ -806,6 +815,46 @@ smtp_tls_policy.o: ../../include/vstream.h
smtp_tls_policy.o: ../../include/vstring.h
smtp_tls_policy.o: smtp.h
smtp_tls_policy.o: smtp_tls_policy.c
+smtp_tls_policy_test.o: ../../include/argv.h
+smtp_tls_policy_test.o: ../../include/attr.h
+smtp_tls_policy_test.o: ../../include/check_arg.h
+smtp_tls_policy_test.o: ../../include/deliver_request.h
+smtp_tls_policy_test.o: ../../include/dict.h
+smtp_tls_policy_test.o: ../../include/dns.h
+smtp_tls_policy_test.o: ../../include/dsn.h
+smtp_tls_policy_test.o: ../../include/dsn_buf.h
+smtp_tls_policy_test.o: ../../include/header_body_checks.h
+smtp_tls_policy_test.o: ../../include/header_opts.h
+smtp_tls_policy_test.o: ../../include/htable.h
+smtp_tls_policy_test.o: ../../include/mail_params.h
+smtp_tls_policy_test.o: ../../include/maps.h
+smtp_tls_policy_test.o: ../../include/match_list.h
+smtp_tls_policy_test.o: ../../include/mime_state.h
+smtp_tls_policy_test.o: ../../include/msg.h
+smtp_tls_policy_test.o: ../../include/msg_stats.h
+smtp_tls_policy_test.o: ../../include/msg_vstream.h
+smtp_tls_policy_test.o: ../../include/myaddrinfo.h
+smtp_tls_policy_test.o: ../../include/myflock.h
+smtp_tls_policy_test.o: ../../include/mymalloc.h
+smtp_tls_policy_test.o: ../../include/name_code.h
+smtp_tls_policy_test.o: ../../include/name_mask.h
+smtp_tls_policy_test.o: ../../include/nvtable.h
+smtp_tls_policy_test.o: ../../include/recipient_list.h
+smtp_tls_policy_test.o: ../../include/resolve_clnt.h
+smtp_tls_policy_test.o: ../../include/scache.h
+smtp_tls_policy_test.o: ../../include/sendopts.h
+smtp_tls_policy_test.o: ../../include/sock_addr.h
+smtp_tls_policy_test.o: ../../include/string_list.h
+smtp_tls_policy_test.o: ../../include/stringops.h
+smtp_tls_policy_test.o: ../../include/sys_defs.h
+smtp_tls_policy_test.o: ../../include/tls.h
+smtp_tls_policy_test.o: ../../include/tls_proxy.h
+smtp_tls_policy_test.o: ../../include/tok822.h
+smtp_tls_policy_test.o: ../../include/vbuf.h
+smtp_tls_policy_test.o: ../../include/vstream.h
+smtp_tls_policy_test.o: ../../include/vstring.h
+smtp_tls_policy_test.o: smtp.h
+smtp_tls_policy_test.o: smtp_tls_policy_test.c
smtp_tlsrpt.o: ../../include/argv.h
smtp_tlsrpt.o: ../../include/attr.h
smtp_tlsrpt.o: ../../include/check_arg.h
diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c
index b77500326..963081b54 100644
--- a/postfix/src/smtp/lmtp_params.c
+++ b/postfix/src/smtp/lmtp_params.c
@@ -140,5 +140,6 @@
VAR_LMTP_REQ_DEADLINE, DEF_LMTP_REQ_DEADLINE, &var_smtp_req_deadline,
VAR_LMTP_TLSRPT_ENABLE, DEF_LMTP_TLSRPT_ENABLE, &var_smtp_tlsrpt_enable,
VAR_LMTP_TLSRPT_SKIP_REUSED_HS, DEF_LMTP_TLSRPT_SKIP_REUSED_HS, &var_smtp_tlsrpt_skip_reused_hs,
+ VAR_LMTP_TLS_ENF_STS_MX_PAT, DEF_LMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat,
0,
};
diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c
index 76e1a3801..beb46033c 100644
--- a/postfix/src/smtp/smtp.c
+++ b/postfix/src/smtp/smtp.c
@@ -650,6 +650,14 @@
/* .IP "\fBsmtp_tlsrpt_skip_reused_handshakes (Postfix >= 3.11: no, Postfix 3.10: yes)\fR"
/* When set to "yes", report the TLSRPT status only for "new" TLS
/* sessions.
+/* .PP
+/* Available in Postfix version 3.10.5 and later:
+/* .IP "\fBsmtp_tls_enforce_sts_mx_patterns (yes)\fR"
+/* Transform the TLS policy from an STS policy plugin: connect to
+/* an MX host only if its name matches the STS policy MX host pattern,
+/* and match the server certificate against the MX hostname.
+/* .PP
+/* Available in Postfix version 3.11 and later:
/* .IP "\fBtls_required_enable (yes)\fR"
/* Enable support for the "TLS-Required: no" message header, defined
/* in RFC 8689.
@@ -1132,6 +1140,7 @@ bool var_smtp_tls_blk_early_mail_reply;
bool var_smtp_tls_force_tlsa;
char *var_smtp_tls_insecure_mx_policy;
bool var_smtp_tls_enable_rpk;
+bool var_smtp_tls_enf_sts_mx_pat;
#endif
diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h
index 874f9481c..28cca83a4 100644
--- a/postfix/src/smtp/smtp.h
+++ b/postfix/src/smtp/smtp.h
@@ -137,6 +137,7 @@ typedef struct SMTP_TLS_POLICY {
extern void smtp_tls_list_init(void);
extern int smtp_tls_policy_cache_query(DSN_BUF *, SMTP_TLS_POLICY *, SMTP_ITERATOR *);
extern void smtp_tls_policy_cache_flush(void);
+extern int smtp_tls_authorize_mx_hostname(SMTP_TLS_POLICY *, const char *);
/*
* Macros must use distinct names for local temporary variables, otherwise
diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c
index fb3494523..7a93e638c 100644
--- a/postfix/src/smtp/smtp_connect.c
+++ b/postfix/src/smtp/smtp_connect.c
@@ -1124,6 +1124,11 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
continue;
/* XXX Assume there is no code at the end of this loop. */
}
+ /* Skip MX hosts that lack authorization. */
+ if (!smtp_tls_authorize_mx_hostname(state->tls, addr->qname)) {
+ continue;
+ /* XXX Assume there is no code at the end of this loop. */
+ }
/* Disable TLS when retrying after a handshake failure */
if (retry_plain) {
state->tls->level = TLS_LEV_NONE;
diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c
index 6d80ef105..8569cb9f5 100644
--- a/postfix/src/smtp/smtp_params.c
+++ b/postfix/src/smtp/smtp_params.c
@@ -144,5 +144,6 @@
VAR_SMTP_REQ_DEADLINE, DEF_SMTP_REQ_DEADLINE, &var_smtp_req_deadline,
VAR_SMTP_TLSRPT_ENABLE, DEF_SMTP_TLSRPT_ENABLE, &var_smtp_tlsrpt_enable,
VAR_SMTP_TLSRPT_SKIP_REUSED_HS, DEF_SMTP_TLSRPT_SKIP_REUSED_HS, &var_smtp_tlsrpt_skip_reused_hs,
+ VAR_SMTP_TLS_ENF_STS_MX_PAT, DEF_SMTP_TLS_ENF_STS_MX_PAT, &var_smtp_tls_enf_sts_mx_pat,
0,
};
diff --git a/postfix/src/smtp/smtp_tls_policy.c b/postfix/src/smtp/smtp_tls_policy.c
index 809ffea05..76f38aa3e 100644
--- a/postfix/src/smtp/smtp_tls_policy.c
+++ b/postfix/src/smtp/smtp_tls_policy.c
@@ -17,6 +17,10 @@
/* SMTP_TLS_POLICY *tls;
/*
/* void smtp_tls_policy_cache_flush()
+/*
+/* int smtp_tls_authorize_mx_hostname(tls, qname)
+/* SMTP_TLS_POLICY *tls;
+/* const char *qname;
/* DESCRIPTION
/* smtp_tls_list_init() initializes lookup tables used by the TLS
/* policy engine.
@@ -38,6 +42,11 @@
/* smtp_tls_policy_cache_flush() destroys the TLS policy cache
/* and contents.
/*
+/* smtp_tls_authorize_mx_hostname() authorizes an MX host if the
+/* name used for host lookup satisfies a TLS policy MX name
+/* constraint (for example, an STS policy MX pattern), or if the
+/* TLS policy has no name constraint.
+/*
/* Arguments:
/* .IP why
/* A pointer to a DSN_BUF which holds error status information when
@@ -107,6 +116,7 @@
#include
#include
#include
+#include
/* Global library. */
@@ -136,6 +146,51 @@ static void dane_init(SMTP_TLS_POLICY *, SMTP_ITERATOR *);
static MAPS *tls_policy; /* lookup table(s) */
static MAPS *tls_per_site; /* lookup table(s) */
+/* match_sts_mx_host_pattern - match hostname against STS policy MX pattern */
+
+static int match_sts_mx_host_pattern(const char *pattern, const char *qname)
+{
+ const char *first_dot_in_qname;
+
+ /* Caller guarantees that inputs are in ASCII form. */
+ return (strcasecmp(qname, pattern) == 0
+ || (pattern[0] == '*' && pattern[1] == '.' && pattern[2] != 0
+ && (first_dot_in_qname = strchr(qname, '.')) != 0
+ && first_dot_in_qname > qname
+ && strcasecmp(first_dot_in_qname + 1, pattern + 2) == 0));
+}
+
+/* smtp_tls_authorize_mx_hostname - enforce applicable MX hostname policy */
+
+int smtp_tls_authorize_mx_hostname(SMTP_TLS_POLICY *tls, const char *name)
+{
+
+#define SAFE_FOR_SMTP_TLS_ENF_STS_MX_PAT(tls) (var_smtp_tls_enf_sts_mx_pat \
+ && (tls)->ext_policy_type != 0 \
+ && strcasecmp((tls)->ext_policy_type, "sts") == 0 \
+ && (tls)->matchargv != 0 && (tls)->ext_mx_host_patterns != 0)
+
+ /* Enforce STS policy MX patterns. */
+ if (SAFE_FOR_SMTP_TLS_ENF_STS_MX_PAT(tls)) {
+ const char *aname;
+ char **pattp;
+
+#ifndef NO_EAI
+ if (!allascii(name) && (aname = midna_domain_to_ascii(name)) != 0) {
+ if (msg_verbose)
+ msg_info("%s asciified to %s", name, aname);
+ } else
+#endif
+ aname = name;
+ for (pattp = tls->ext_mx_host_patterns->argv; *pattp; pattp++)
+ if (match_sts_mx_host_pattern(*pattp, aname))
+ return (1);
+ return (0);
+ }
+ /* No applicable policy name patterns. */
+ return (1);
+}
+
/* smtp_tls_list_init - initialize per-site policy lists */
void smtp_tls_list_init(void)
@@ -517,6 +572,10 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
INVALID_RETURN(tls->why, site_level);
}
}
+ if (SAFE_FOR_SMTP_TLS_ENF_STS_MX_PAT(tls)) {
+ argv_truncate(tls->matchargv, 0);
+ argv_add(tls->matchargv, "hostname", (char *) 0);
+ }
FREE_RETURN;
}
diff --git a/postfix/src/smtp/smtp_tls_policy_test.c b/postfix/src/smtp/smtp_tls_policy_test.c
new file mode 100644
index 000000000..f37ac9875
--- /dev/null
+++ b/postfix/src/smtp/smtp_tls_policy_test.c
@@ -0,0 +1,503 @@
+/*++
+/* NAME
+/* smtp_tls_policy_test 1t
+/* SUMMARY
+/* smtp_tls_policy unit tests
+/* SYNOPSIS
+/* ./smtp_tls_policy_test
+/* DESCRIPTION
+/* smtp_tls_policy_test runs and logs each configured test, reports
+/* if a test is a PASS or FAIL, and returns an exit status of zero
+/* if all tests are a PASS.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* porcupine.org
+/*--*/
+
+ /*
+ * System library.
+ */
+#include
+#include
+
+ /*
+ * Utility library.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef USE_TLS
+
+#define PASS (0)
+#define FAIL (1)
+
+ /*
+ * Global library.
+ */
+#include
+
+ /*
+ * TLS library.
+ */
+
+ /*
+ * SMTP client.
+ */
+#include
+
+ /*
+ * Surrogate dependencies. Parameters are initialized without $name
+ * expansion, and can be changed by tests.
+ */
+char *var_smtp_tls_policy;
+char *var_smtp_tls_per_site;
+char *var_smtp_tls_ciph;
+bool var_smtp_tls_conn_reuse;
+bool var_smtp_tls_enable_rpk;
+char *var_smtp_tls_level;
+int smtp_host_lookup_mask;
+int var_smtp_cache_conn;
+char *var_smtp_tls_mand_ciph;
+char *var_smtp_tls_mand_excl;
+char *var_smtp_dns_res_opt;
+char *var_smtp_dns_support;
+char *var_smtp_tls_insecure_mx_policy;
+int var_ign_mx_lookup_err;
+bool var_smtp_enforce_tls;
+bool var_smtp_tls_enforce_peername;
+bool var_smtp_tls_force_tlsa;
+char *var_smtp_tls_fpt_cmatch;
+char *var_smtp_tls_mand_proto;
+char *var_smtp_tls_proto;
+char *var_smtp_tls_sec_cmatch;
+char *var_smtp_tls_sni;
+char *var_smtp_tls_tafile;
+char *var_smtp_tls_vfy_cmatch;
+bool var_smtp_use_tls;
+char *var_smtp_tls_excl_ciph;
+bool var_smtp_tls_enf_sts_mx_pat;
+
+ /*
+ * Other globals.
+ */
+int smtp_mode;
+int smtp_tls_insecure_mx_policy;
+unsigned smtp_dns_res_opt;
+int smtp_dns_support;
+int smtp_host_lookup_mask;
+
+ /*
+ * Pre-test initializer to make tests independent.
+ */
+static void test_setup(void)
+{
+ var_smtp_tls_policy = DEF_SMTP_TLS_POLICY;
+ var_smtp_tls_per_site = DEF_SMTP_TLS_PER_SITE;
+ var_smtp_tls_ciph = DEF_SMTP_TLS_CIPH;
+ var_smtp_tls_conn_reuse = DEF_SMTP_TLS_CONN_REUSE;
+ var_smtp_tls_enable_rpk = DEF_SMTP_TLS_ENABLE_RPK;
+ var_smtp_tls_level = "may";
+ var_smtp_cache_conn = 2;
+ var_smtp_tls_mand_ciph = DEF_SMTP_TLS_MAND_CIPH;
+ var_smtp_tls_mand_excl = DEF_SMTP_TLS_MAND_EXCL;
+ var_smtp_dns_res_opt = DEF_SMTP_DNS_RES_OPT;
+ var_smtp_dns_support = DEF_SMTP_DNS_SUPPORT;
+ var_smtp_tls_insecure_mx_policy = DEF_SMTP_TLS_INSECURE_MX_POLICY;
+ var_ign_mx_lookup_err = DEF_IGN_MX_LOOKUP_ERR;
+ var_smtp_enforce_tls = DEF_SMTP_ENFORCE_TLS;
+ var_smtp_tls_enforce_peername = DEF_SMTP_TLS_ENFORCE_PN;
+ var_smtp_tls_force_tlsa = DEF_SMTP_TLS_FORCE_TLSA;
+ var_smtp_tls_fpt_cmatch = DEF_SMTP_TLS_FPT_CMATCH;
+ var_smtp_tls_mand_proto = DEF_SMTP_TLS_MAND_PROTO;
+ var_smtp_tls_proto = DEF_SMTP_TLS_PROTO;
+ var_smtp_tls_sec_cmatch = DEF_SMTP_TLS_SEC_CMATCH;
+ var_smtp_tls_sni = DEF_SMTP_TLS_SNI;
+ var_smtp_tls_tafile = DEF_SMTP_TLS_TAFILE;
+ var_smtp_tls_vfy_cmatch = DEF_SMTP_TLS_VFY_CMATCH;
+ var_smtp_use_tls = DEF_SMTP_USE_TLS;
+ var_smtp_tls_excl_ciph = DEF_SMTP_TLS_EXCL_CIPH;
+ var_smtp_tls_enf_sts_mx_pat = 1;
+
+ smtp_mode = 1;
+
+ smtp_tls_policy_cache_flush();
+}
+
+ /*
+ * Post-test finalizer to help memory leak tests.
+ */
+static void test_teardown(void)
+{
+ smtp_tls_policy_cache_flush();
+}
+
+ /*
+ * Test helpers. TODO(wietse) adopt PTEST which does a nicer job.
+ */
+static int match_int(const char *what, int want, int got)
+{
+ if (want != got) {
+ msg_warn("%s: got %d, want %d", what, got, want);
+ return (0);
+ }
+ return (1);
+}
+
+#define STR_OR_NULL(s) ((s)? (s) : "NULL")
+
+static int match_cstr(const char *what, const char *want, const char *got)
+{
+ if (!want != !got) {
+ msg_warn("%s: got '%s', want '%s'", what, STR_OR_NULL(got),
+ STR_OR_NULL(want));
+ return (0);
+ }
+ if (want != 0 && strcmp(got, want) != 0) {
+ msg_warn("%s: got '%s', want '%s'", what, got, want);
+ return (0);
+ }
+ return (1);
+}
+
+#define WANT_ARGV_MAX 5
+
+struct WANT_ARGV {
+ ssize_t argc;
+ char *argv[WANT_ARGV_MAX];
+};
+
+#define ARGV_OR_NULL(a) ((a)? ("argv") : "NULL")
+
+static int match_argv(const char *what, const struct WANT_ARGV * want,
+ const ARGV *got)
+{
+ if (!want != !got) {
+ msg_warn("%s: got '%s', want '%s'", what, ARGV_OR_NULL(got),
+ ARGV_OR_NULL(want));
+ return (0);
+ }
+ if (match_int("argc", want->argc, got->argc) == 0) {
+ return (0);
+ } else {
+ VSTRING *buf;
+ int idx;
+ int equal;
+
+ buf = vstring_alloc(100);
+ for (equal = 1, idx = 0; idx < want->argc; idx++) {
+ vstring_sprintf(buf, "%s->argv[%d]", what, idx);
+ if (match_cstr(STR(buf), want->argv[idx], got->argv[idx]) == 0)
+ equal = 0;
+ }
+ vstring_free(buf);
+ return (equal);
+ }
+}
+
+ /*
+ * Limited policy for STS tests.
+ */
+struct WANT_SMTP_TLS_POLICY {
+ int level; /* TLS enforcement level */
+#if 0
+ char *protocols; /* Acceptable SSL protocols */
+ char *grade; /* Cipher grade: "export", ... */
+ VSTRING *exclusions; /* Excluded SSL ciphers */
+ char *protocols; /* Acceptable SSL protocols */
+ char *grade; /* Cipher grade: "export", ... */
+ VSTRING *exclusions; /* Excluded SSL ciphers */
+#endif
+ struct WANT_ARGV matchargv; /* Cert match patterns */
+#if 0
+ DSN_BUF *why; /* Lookup error status */
+ TLS_DANE *dane; /* DANE TLSA digests */
+#endif
+ char *sni; /* Optional SNI name when not DANE */
+#if 0
+ int conn_reuse; /* enable connection reuse */
+ int enable_rpk; /* Enable server->client RPK */
+#endif
+ int ext_policy_ttl; /* TTL from DNS etc. */
+ char *ext_policy_type; /* (sts) */
+ struct WANT_ARGV ext_policy_strings;/* policy strings from DNS etc. */
+ char *ext_policy_domain; /* policy scope */
+ struct WANT_ARGV ext_mx_host_patterns; /* (sts) MX host patterns */
+ char *ext_policy_failure; /* (sts) policy failure */
+};
+
+#define POLICY_OR_NULL(p) ((p)? ("policy") : "NULL")
+
+static int match_smtp_tls_policy(const char *what,
+ const struct WANT_SMTP_TLS_POLICY * want,
+ const SMTP_TLS_POLICY *got)
+{
+ int equal = 1;
+
+ if (!want != !got) {
+ msg_warn("%s: got '%s', want '%s'", what, POLICY_OR_NULL(got),
+ POLICY_OR_NULL(want));
+ return (0);
+ }
+ if (match_int("level", want->level, got->level) == 0) {
+ msg_warn("%s->level mismatch", what);
+ equal = 0;
+ }
+ if (match_argv("matchargv", &want->matchargv, got->matchargv) == 0) {
+ msg_warn("%s->matchargv mismatch", what);
+ equal = 0;
+ }
+ if (match_cstr("sni", want->sni, got->sni) == 0) {
+ msg_warn("%s->sni mismatch", what);
+ equal = 0;
+ }
+ if (match_int("ext_policy_ttl", want->ext_policy_ttl, got->ext_policy_ttl) == 0) {
+ msg_warn("%s->ext_policy_ttl mismatch", what);
+ equal = 0;
+ }
+ if (match_cstr("ext_policy_type", want->ext_policy_type,
+ got->ext_policy_type) == 0) {
+ msg_warn("%s->ext_policy_type mismatch", what);
+ equal = 0;
+ }
+ if (match_argv("ext_policy_strings", &want->ext_policy_strings,
+ got->ext_policy_strings) == 0) {
+ msg_warn("%s->ext_policy_strings mismatch", what);
+ equal = 0;
+ }
+ if (match_cstr("ext_policy_domain", want->ext_policy_domain,
+ got->ext_policy_domain) == 0) {
+ msg_warn("%s->ext_policy_domain mismatch", what);
+ equal = 0;
+ }
+ if (match_argv("ext_mx_host_patterns", &want->ext_mx_host_patterns,
+ got->ext_mx_host_patterns) == 0) {
+ msg_warn("%s->ext_mx_host_patterns mismatch", what);
+ equal = 0;
+ }
+ if (match_cstr("ext_policy_failure", want->ext_policy_failure,
+ got->ext_policy_failure) == 0) {
+ msg_warn("%s->ext_policy_failure mismatch", what);
+ equal = 0;
+ }
+ return (equal);
+}
+
+ /*
+ * Test structure. Some tests may bring their own.
+ */
+typedef struct TEST_CASE {
+ const char *label;
+ int (*action) (const struct TEST_CASE *);
+} TEST_CASE;
+
+ /*
+ * Verify that policies from an STS plugin are converted into Postfix TLS
+ * policies that match a certificate against the server hostname, and that
+ * other policy attributes are stored appropriately. A later test will
+ * verify that MX hostnames are matched against the STS policy MX hostname
+ * patterns.
+ */
+static int sts_policy_smoke_test(const struct TEST_CASE *tp)
+{
+ var_smtp_tls_policy =
+ "static:{secure match=example:.example "
+ "servername=example policy_ttl=123 "
+ "policy_type=sts policy_string=one "
+ "policy_string=two policy_domain=example "
+ "mx_host_pattern=example mx_host_pattern=*.example}";
+ static const struct WANT_SMTP_TLS_POLICY want_policy = {
+ .level = TLS_LEV_SECURE,
+ .matchargv = {.argc = 1,.argv = {"hostname"}},
+ .sni = "example",
+ .ext_policy_ttl = 123,
+ .ext_policy_type = "sts",
+ .ext_policy_strings = {.argc = 2,.argv = {"one", "two"}},
+ .ext_policy_domain = "example",
+ .ext_mx_host_patterns = {.argc = 2,.argv = {"example", "*.example"}}
+ };
+ SMTP_STATE *state = smtp_state_alloc();
+ const char *domain = "example";
+ const char *host = "mail.example";
+ const char *addr = "10.0.1.1";
+ int port = 25;
+ int match;
+
+ var_smtp_tls_enf_sts_mx_pat = 1;
+ var_smtp_tls_level = "secure";
+ smtp_tls_list_init();
+ SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
+ if ((match = smtp_tls_policy_cache_query(state->why, state->tls,
+ state->iterator)) == 0) {
+ msg_warn("smtp_tls_policy_cache_query failed: %s",
+ STR(state->why->reason));
+ } else {
+ match = match_smtp_tls_policy("policy", &want_policy, state->tls);
+ }
+ smtp_state_free(state);
+ smtp_tls_policy_cache_flush();
+ return (match ? PASS : FAIL);
+}
+
+ /*
+ * Verify that the historical support for policies from STS plugins is still
+ * available. STS plugins generate a policy that will match a certificate
+ * against all MX patterns, after converting a pattern "*.domain" to
+ * ".domain", and do not constrain the allowed MX hostnames.
+ */
+static int obs_sts_policy_smoke_test(const struct TEST_CASE *tp)
+{
+ var_smtp_tls_policy =
+ "static:{secure match=example:.example "
+ "servername=example policy_ttl=123 "
+ "policy_type=sts policy_string=one "
+ "policy_string=two policy_domain=example "
+ "mx_host_pattern=example mx_host_pattern=*.example}";
+ static const struct WANT_SMTP_TLS_POLICY want_policy = {
+ .level = TLS_LEV_SECURE,
+ .matchargv = {.argc = 2,.argv = {"example", ".example"}},
+ .sni = "example",
+ .ext_policy_ttl = 123,
+ .ext_policy_type = "sts",
+ .ext_policy_strings = {.argc = 2,.argv = {"one", "two"}},
+ .ext_policy_domain = "example",
+ .ext_mx_host_patterns = {.argc = 2,.argv = {"example", "*.example"}}
+ };
+ SMTP_STATE *state = smtp_state_alloc();
+ const char *domain = "example";
+ const char *host = "mail.example";
+ const char *addr = "10.0.1.1";
+ int port = 25;
+ int match;
+
+ var_smtp_tls_enf_sts_mx_pat = 0;
+ var_smtp_tls_level = "secure";
+ smtp_tls_list_init();
+ SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
+ if ((match = smtp_tls_policy_cache_query(state->why, state->tls,
+ state->iterator)) == 0) {
+ msg_warn("smtp_tls_policy_cache_query failed: %s",
+ STR(state->why->reason));
+ } else {
+ match = match_smtp_tls_policy("policy", &want_policy, state->tls);
+ }
+ smtp_state_free(state);
+ smtp_tls_policy_cache_flush();
+ return (match ? PASS : FAIL);
+}
+
+ /*
+ * Test the MX host authorization constraints.
+ */
+static int test_hostname_authorization(const struct TEST_CASE *tp)
+{
+ var_smtp_tls_policy =
+ "static:{secure match=example.com:.example.com "
+ "servername=example.com policy_ttl=123 "
+ "policy_type=sts policy_string=one "
+ "policy_string=two policy_domain=example.com "
+ "mx_host_pattern=example.com mx_host_pattern=*.example.com}";
+ static const struct WANT_SMTP_TLS_POLICY want_policy = {
+ .level = TLS_LEV_SECURE,
+ .matchargv = {.argc = 1,.argv = {"hostname"}},
+ .sni = "example.com",
+ .ext_policy_ttl = 123,
+ .ext_policy_type = "sts",
+ .ext_policy_strings = {.argc = 2,.argv = {"one", "two"}},
+ .ext_policy_domain = "example.com",
+ .ext_mx_host_patterns = {.argc = 2,.argv = {"example.com", "*.example.com"}}
+ };
+ SMTP_STATE *state = smtp_state_alloc();
+ const char *domain = "example.com";
+ const char *host = "mail.example.com";
+ const char *addr = "10.0.1.1";
+ int port = 25;
+ int match;
+ static const char *permit_domains[] = {
+ "example.com", "mail.example.com", 0,
+ };
+ static const char *reject_domains[] = {
+ ".example.com", "foo.bar.example.com", 0,
+ };
+ const char *const * cpp;
+
+ var_smtp_tls_enf_sts_mx_pat = 1;
+ var_smtp_tls_level = "secure";
+ smtp_tls_list_init();
+ SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
+ if ((match = smtp_tls_policy_cache_query(state->why, state->tls,
+ state->iterator)) == 0) {
+ msg_warn("smtp_tls_policy_cache_query failed: %s",
+ STR(state->why->reason));
+ } else {
+ match = match_smtp_tls_policy("policy", &want_policy, state->tls);
+ }
+ if (match == 0)
+ return (FAIL);
+
+ /* Verify that 'good' MX host names are authorized. */
+ for (cpp = permit_domains; *cpp; cpp++) {
+ if (!smtp_tls_authorize_mx_hostname(state->tls, *cpp)) {
+ msg_warn("hostname '%s' is not authorized", *cpp);
+ match = 0;
+ }
+ }
+ /* Verify that 'wrong' MX host names are not authorized. */
+ for (cpp = reject_domains; *cpp; cpp++) {
+ if (smtp_tls_authorize_mx_hostname(state->tls, *cpp)) {
+ msg_warn("hostname '%s' is authorized", *cpp);
+ match = 0;
+ }
+ }
+
+ smtp_state_free(state);
+ smtp_tls_policy_cache_flush();
+ return (match ? PASS : FAIL);
+}
+
+static const struct TEST_CASE test_cases[] = {
+ {"sts_policy_smoke_test", sts_policy_smoke_test,},
+ {"obs_sts_policy_smoke_test", obs_sts_policy_smoke_test,},
+ {"test_hostname_authorization", test_hostname_authorization},
+ {0},
+};
+
+int main(int argc, char **argv)
+{
+ static int tests_passed = 0;
+ static int tests_failed = 0;
+ const struct TEST_CASE *tp;
+
+ msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+ for (tp = test_cases; tp->label; tp++) {
+ msg_info("RUN %s", tp->label);
+ test_setup();
+ if (tp->action(tp) == PASS) {
+ msg_info("PASS %s", tp->label);
+ tests_passed += 1;
+ } else {
+ msg_info("FAIL %s", tp->label);
+ tests_failed += 1;
+ }
+ test_teardown();
+ }
+ msg_info("PASS=%d FAIL=%d", tests_passed, tests_failed);
+ exit(tests_failed != 0);
+}
+
+#else
+
+int main(int argc, char **argv)
+{
+ msg_fatal("this program requires `#define USE_TLS'");
+}
+
+#endif