There is currently no way to force TLS on a relay rule in general, and
force certificate checking. Typical use case: a secondary MX needing
to relay safely to lower preference MXs.
This diff below allows the "tls" option to be used alone, including on
non-smarthost relay rules, to specify that the relay must be using
TLS. The "no-verify" keyword becomes optional.
Currently, the different cases are as follows:
- action <name> relay
Standard relaying, using smtp with opportunistic STARTTLS.
When using TLS, certificates are not checked.
- action <name> relay host <smarthost>
Relay through smarthost, using TLS or not, depending on the protocol.
When using TLS, certificates are checked.
- action <name> relay host <smarthost> tls no-verify
Same as above, but certificates are not checked.
With the proposed change, we get:
- action <name> relay
Standard relaying, using smtp with opportunistic STARTTLS.
When using TLS, certificates are not checked.
- action <name> relay tls
Standard relaying, using smtp with mandatory STARTTLS.
Certificates are checked.
- action <name> relay tls no-verify
Same as above, but certificates are not checked.
- action <name> relay host <smarthost>
Relay through smarthost, using TLS or not, depending on the protocol.
For "smtp+tls://" and "smtps://" certificates are checked.
For "smtp://" (opportunistic TLS) certificates are not checked.
- action <name> relay host <smarthost> tls
Relay through smarthost with mandatory TLS.
Certificates are checked.
The "smtp://" protocol is updated to "smtp+tls://" internally.
The "smtp+notls://" protocol is rejected, and no relaying happens.
- action <name> relay host <smarthost> tls no-verify
Same as above, but certificates are not checked.
The differences with the currently allowed syntax are:
1) the "tls no-verify" option on smarthost relay actually forces TLS,
2) a relay with a "smtp://" smarthost and no "tls no-verify" does not
require a valid certificate anymore.
It is more constistent altogether, and in practice it should not be
a problem because most smarthost configurations uses strict TLS.
Now, for the secondary MX example, the rule would look like:
action "do-backup" relay backup tls
Comments?
Eric.
Index: mta.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/mta.c,v
retrieving revision 1.225
diff -u -p -r1.225 mta.c
--- mta.c 19 Sep 2018 05:31:12 -0000 1.225
+++ mta.c 21 Sep 2018 08:09:14 -0000
@@ -657,6 +657,23 @@ mta_handle_envelope(struct envelope *evp
return;
}
+ if (dispatcher->u.remote.tls_required) {
+ /* Reject relay if smtp+notls:// is requested */
+ if (relayh.tls == RELAY_TLS_NO) {
+ log_warnx("warn: TLS required for action \"%s\"",
+ evp->dispatcher);
+ m_create(p_queue, IMSG_MTA_DELIVERY_TEMPFAIL, 0, 0, -1);
+ m_add_evpid(p_queue, evp->id);
+ m_add_string(p_queue, "TLS required for relaying");
+ m_add_int(p_queue, ESC_OTHER_STATUS);
+ m_close(p_queue);
+ return;
+ }
+ /* Update smtp:// to smtp+tls:// */
+ if (relayh.tls == RELAY_TLS_OPPORTUNISTIC)
+ relayh.tls = RELAY_TLS_STARTTLS;
+ }
+
relay = mta_relay(evp, &relayh);
/* ignore if we don't know the limits yet */
if (relay->limits &&
@@ -1739,7 +1756,7 @@ mta_relay(struct envelope *e, struct rel
if (!key.authlabel[0])
key.authlabel = NULL;
- if (dispatcher->u.remote.smarthost &&
+ if ((key.tls == RELAY_TLS_STARTTLS || key.tls == RELAY_TLS_SMTPS) &&
dispatcher->u.remote.tls_noverify == 0)
key.flags |= RELAY_TLS_VERIFY;
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.221
diff -u -p -r1.221 parse.y
--- parse.y 7 Sep 2018 07:35:31 -0000 1.221
+++ parse.y 21 Sep 2018 08:09:14 -0000
@@ -739,17 +739,21 @@ HELO STRING {
dispatcher->u.remote.smarthost = strdup(t->t_name);
}
-| TLS NO_VERIFY {
- if (dispatcher->u.remote.smarthost == NULL) {
- yyerror("tls no-verify may not be specified without host on a
dispatcher");
+| TLS {
+ if (dispatcher->u.remote.tls_required == 1) {
+ yyerror("tls already specified for this dispatcher");
YYERROR;
}
- if (dispatcher->u.remote.tls_noverify == 1) {
- yyerror("tls no-verify already specified for this dispatcher");
+ dispatcher->u.remote.tls_required = 1;
+}
+| TLS NO_VERIFY {
+ if (dispatcher->u.remote.tls_required == 1) {
+ yyerror("tls already specified for this dispatcher");
YYERROR;
}
+ dispatcher->u.remote.tls_required = 1;
dispatcher->u.remote.tls_noverify = 1;
}
| AUTH tables {
Index: smtpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.conf.5,v
retrieving revision 1.204
diff -u -p -r1.204 smtpd.conf.5
--- smtpd.conf.5 10 Sep 2018 12:42:17 -0000 1.204
+++ smtpd.conf.5 21 Sep 2018 08:09:15 -0000
@@ -265,8 +265,13 @@ and
.Dq smtps
protocols for authentication.
Server certificates for those protocols are verified by default.
-.It Cm tls no-verify
-Do not require a valid certificate for the specified host.
+.It Cm tls Op no-verify
+Require TLS to be used when relaying, using mandatory STARTTLS by default.
+When used with a smarthost, the protocol must not be
+.Dq smtp+notls:// .
+If
+.Op no-verify
+is specified, do not require a valid certificate.
.It Cm auth Pf < Ar table Ns >
Use the mapping
.Ar table
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.561
diff -u -p -r1.561 smtpd.h
--- smtpd.h 19 Sep 2018 05:31:12 -0000 1.561
+++ smtpd.h 21 Sep 2018 08:09:15 -0000
@@ -1063,6 +1063,7 @@ struct dispatcher_remote {
char *smarthost;
char *auth;
+ int tls_required;
int tls_noverify;
int backup;