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;