smtpd: tls ciphers and protocols on listeners

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

smtpd: tls ciphers and protocols on listeners

Eric Faurot-2
Hi,

This diff allows to specify tls ciphers and protocols on listen rules,
as it's been done already for relay actions. While there, sanitize
error checking on protocols config in the mta.

Eric.

Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/config.c,v
retrieving revision 1.54
diff -u -p -r1.54 config.c
--- config.c 5 Mar 2021 12:37:32 -0000 1.54
+++ config.c 6 Apr 2021 10:24:18 -0000
@@ -252,6 +252,8 @@ purge_config(uint8_t what)
  if (what & PURGE_LISTENERS) {
  while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
  TAILQ_REMOVE(env->sc_listeners, l, entry);
+ free(l->tls_ciphers);
+ free(l->tls_protocols);
  free(l->pki);
  free(l);
  }
Index: mta.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/mta.c,v
retrieving revision 1.237
diff -u -p -r1.237 mta.c
--- mta.c 2 Apr 2021 06:30:55 -0000 1.237
+++ mta.c 6 Apr 2021 10:39:52 -0000
@@ -508,10 +508,14 @@ mta_setup_dispatcher(struct dispatcher *
  if (ciphers && tls_config_set_ciphers(config, ciphers) == -1)
  err(1, "%s", tls_config_error(config));
 
- if (remote->tls_protocols &&
-    (tls_config_parse_protocols(&protos, remote->tls_protocols) == -1
-    || tls_config_set_protocols(config, protos) == -1))
- err(1, "%s", tls_config_error(config));
+ if (remote->tls_protocols) {
+ if (tls_config_parse_protocols(&protos,
+    remote->tls_protocols) == -1)
+ err(1, "failed to parse protocols \"%s\"",
+    remote->tls_protocols);
+ if (tls_config_set_protocols(config, protos) == -1)
+ err(1, "%s", tls_config_error(config));
+ }
 
  if (remote->pki) {
  pki = dict_get(env->sc_pki_dict, remote->pki);
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.286
diff -u -p -r1.286 parse.y
--- parse.y 31 Mar 2021 17:47:16 -0000 1.286
+++ parse.y 6 Apr 2021 10:19:33 -0000
@@ -137,6 +137,8 @@ static struct listen_opts {
  char       *filtername;
  char       *pki[PKI_MAX];
  int pkicount;
+ char       *tls_ciphers;
+ char       *tls_protocols;
  char       *ca;
  uint16_t       auth;
  struct table   *authtable;
@@ -2333,6 +2335,20 @@ opt_if_listen : INET4 {
  listen_opts.options |= LO_SSL;
  listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY;
  }
+ | CIPHERS STRING {
+ if (listen_opts.tls_ciphers) {
+ yyerror("ciphers already specified");
+ YYERROR;
+ }
+ listen_opts.tls_ciphers = $2;
+ }
+ | PROTOCOLS STRING {
+ if (listen_opts.tls_protocols) {
+ yyerror("protocols already specified");
+ YYERROR;
+ }
+ listen_opts.tls_protocols = $2;
+ }
  | PKI STRING {
  if (listen_opts.pkicount == PKI_MAX) {
  yyerror("too many pki specified");
@@ -2516,7 +2532,11 @@ listen : LISTEN {
  memset(&listen_opts, 0, sizeof listen_opts);
  listen_opts.family = AF_UNSPEC;
  listen_opts.flags |= F_EXT_DSN;
- } ON listener_type
+ } ON listener_type {
+ free(listen_opts.tls_protocols);
+ free(listen_opts.tls_ciphers);
+ memset(&listen_opts, 0, sizeof listen_opts);
+ }
  ;
 
 table : TABLE STRING STRING {
@@ -3310,6 +3330,16 @@ config_listener(struct listener *h,  str
  log_warnx("pki name not found: %s", lo->pki[i]);
  fatalx(NULL);
  }
+ }
+
+ if (lo->tls_ciphers != NULL &&
+    (h->tls_ciphers = strdup(lo->tls_ciphers)) == NULL) {
+ fatal("strdup");
+ }
+
+ if (lo->tls_protocols != NULL &&
+    (h->tls_protocols = strdup(lo->tls_protocols)) == NULL) {
+ fatal("strdup");
  }
 
  if (lo->ca != NULL) {
Index: smtp.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtp.c,v
retrieving revision 1.168
diff -u -p -r1.168 smtp.c
--- smtp.c 10 Mar 2021 17:25:59 -0000 1.168
+++ smtp.c 6 Apr 2021 10:39:34 -0000
@@ -169,6 +169,8 @@ smtp_setup_listener_tls(struct listener
 {
  static const char *dheparams[] = { "none", "auto", "legacy" };
  struct tls_config *config;
+ const char *ciphers;
+ uint32_t protos;
  struct pki *pki;
  struct ca *ca;
  int i;
@@ -176,9 +178,19 @@ smtp_setup_listener_tls(struct listener
  if ((config = tls_config_new()) == NULL)
  fatal("smtpd: tls_config_new");
 
- if (env->sc_tls_ciphers &&
-    tls_config_set_ciphers(config, env->sc_tls_ciphers) == -1)
+ ciphers = env->sc_tls_ciphers;
+ if (l->tls_ciphers)
+ ciphers = l->tls_ciphers;
+ if (ciphers && tls_config_set_ciphers(config, ciphers) == -1)
+ err(1, "%s", tls_config_error(config));
+
+ if (l->tls_protocols) {
+ if (tls_config_parse_protocols(&protos, l->tls_protocols) == -1)
+ err(1, "failed to parse protocols \"%s\"",
+    l->tls_protocols);
+ if (tls_config_set_protocols(config, protos) == -1)
  err(1, "%s", tls_config_error(config));
+ }
 
  pki = l->pki[0];
  if (pki == NULL)
Index: smtpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.conf.5,v
retrieving revision 1.259
diff -u -p -r1.259 smtpd.conf.5
--- smtpd.conf.5 31 Mar 2021 17:47:16 -0000 1.259
+++ smtpd.conf.5 6 Apr 2021 10:31:20 -0000
@@ -527,6 +527,18 @@ With the
 .Cm verify
 option, clients must also provide a valid certificate
 to establish an SMTP session.
+.It Cm protocols Ar protostr
+Define the protocol versions to be used for TLS sessions.
+Refer to the
+.Xr tls_config_parse_protocols 3
+manpage for the format of
+.Ar protostr .
+.It Cm ciphers Ar cipherstr
+Define the list of ciphers that may be used for TLS sessions.
+Refer to the
+.Xr tls_config_set_ciphers 3
+manpage for the format of
+.Ar cipherstr .
 .El
 .It Ic listen on Cm socket Op Ar options
 Listen for incoming SMTP connections on the Unix domain socket
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.664
diff -u -p -r1.664 smtpd.h
--- smtpd.h 31 Mar 2021 19:09:19 -0000 1.664
+++ smtpd.h 6 Apr 2021 10:02:28 -0000
@@ -543,6 +543,8 @@ struct listener {
 
  int local; /* there must be a better way */
 
+ char *tls_protocols;
+ char *tls_ciphers;
  struct tls *tls;
  struct pki **pki;
  int pkicount;