1 /*        $NetBSD: smtp_tls_policy.c,v 1.5 2025/02/25 19:15:49 christos Exp $   */
2 
3 /*++
4 /* NAME
5 /*        smtp_tls_policy 3
6 /* SUMMARY
7 /*        SMTP_TLS_POLICY structure management
8 /* SYNOPSIS
9 /*        #include "smtp.h"
10 /*
11 /*        void    smtp_tls_list_init()
12 /*
13 /*        int       smtp_tls_policy_cache_query(why, tls, iter)
14 /*        DSN_BUF   *why;
15 /*        SMTP_TLS_POLICY *tls;
16 /*        SMTP_ITERATOR *iter;
17 /*
18 /*        void      smtp_tls_policy_dummy(tls)
19 /*        SMTP_TLS_POLICY *tls;
20 /*
21 /*        void      smtp_tls_policy_cache_flush()
22 /* DESCRIPTION
23 /*        smtp_tls_list_init() initializes lookup tables used by the TLS
24 /*        policy engine.
25 /*
26 /*        smtp_tls_policy_cache_query() returns a shallow copy of the
27 /*        cached SMTP_TLS_POLICY structure for the iterator's
28 /*        destination, host, port and DNSSEC validation status.
29 /*        This copy is guaranteed to be valid until the next
30 /*        smtp_tls_policy_cache_query() or smtp_tls_policy_cache_flush()
31 /*        call.  The caller can override the TLS security level without
32 /*        corrupting the policy cache.
33 /*        When any required table or DNS lookups fail, the TLS level
34 /*        is set to TLS_LEV_INVALID, the "why" argument is updated
35 /*        with the error reason and the result value is zero (false).
36 /*
37 /*        smtp_tls_policy_dummy() initializes a trivial, non-cached,
38 /*        policy with TLS disabled.
39 /*
40 /*        smtp_tls_policy_cache_flush() destroys the TLS policy cache
41 /*        and contents.
42 /*
43 /*        Arguments:
44 /* .IP why
45 /*        A pointer to a DSN_BUF which holds error status information when
46 /*        the TLS policy lookup fails.
47 /* .IP tls
48 /*        Pointer to TLS policy storage.
49 /* .IP iter
50 /*        The literal next-hop or fall-back destination including
51 /*        the optional [] and including the :port or :service;
52 /*        the name of the remote host after MX and CNAME expansions
53 /*        (see smtp_cname_overrides_servername for the handling
54 /*        of hostnames that resolve to a CNAME record);
55 /*        the printable address of the remote host;
56 /*        the remote port in network byte order;
57 /*        the DNSSEC validation status of the host name lookup after
58 /*        MX and CNAME expansions.
59 /* LICENSE
60 /* .ad
61 /* .fi
62 /*        This software is free. You can do with it whatever you want.
63 /*        The original author kindly requests that you acknowledge
64 /*        the use of his software.
65 /* AUTHOR(S)
66 /*        TLS support originally by:
67 /*        Lutz Jaenicke
68 /*        BTU Cottbus
69 /*        Allgemeine Elektrotechnik
70 /*        Universitaetsplatz 3-4
71 /*        D-03044 Cottbus, Germany
72 /*
73 /*        Updated by:
74 /*        Wietse Venema
75 /*        IBM T.J. Watson Research
76 /*        P.O. Box 704
77 /*        Yorktown Heights, NY 10598, USA
78 /*
79 /*        Wietse Venema
80 /*        Google, Inc.
81 /*        111 8th Avenue
82 /*        New York, NY 10011, USA
83 /*
84 /*        Viktor Dukhovni
85 /*--*/
86 
87 /* System library. */
88 
89 #include <sys_defs.h>
90 
91 #ifdef USE_TLS
92 
93 #include <netinet/in.h>                           /* ntohs() for Solaris or BSD */
94 #include <arpa/inet.h>                            /* ntohs() for Linux or BSD */
95 #include <stdlib.h>
96 #include <string.h>
97 
98 #ifdef STRCASECMP_IN_STRINGS_H
99 #include <strings.h>
100 #endif
101 
102 /* Utility library. */
103 
104 #include <msg.h>
105 #include <mymalloc.h>
106 #include <vstring.h>
107 #include <sane_strtol.h>
108 #include <stringops.h>
109 #include <valid_hostname.h>
110 #include <valid_utf8_hostname.h>
111 #include <ctable.h>
112 
113 /* Global library. */
114 
115 #include <mail_params.h>
116 #include <maps.h>
117 #include <dsn_buf.h>
118 
119 /* TLS library. */
120 
121 #include <tlsrpt_wrapper.h>
122 
123 /* DNS library. */
124 
125 #include <dns.h>
126 
127 /* Application-specific. */
128 
129 #include "smtp.h"
130 
131 /* XXX Cache size should scale with [sl]mtp_mx_address_limit. */
132 #define CACHE_SIZE 20
133 static CTABLE *policy_cache;
134 
135 static int global_tls_level(void);
136 static void dane_init(SMTP_TLS_POLICY *, SMTP_ITERATOR *);
137 
138 static MAPS *tls_policy;                /* lookup table(s) */
139 static MAPS *tls_per_site;              /* lookup table(s) */
140 
141 /* smtp_tls_list_init - initialize per-site policy lists */
142 
smtp_tls_list_init(void)143 void    smtp_tls_list_init(void)
144 {
145     if (*var_smtp_tls_policy) {
146           tls_policy = maps_create(VAR_LMTP_SMTP(TLS_POLICY),
147                                          var_smtp_tls_policy,
148                                          DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
149                                          | DICT_FLAG_UTF8_REQUEST);
150           if (*var_smtp_tls_per_site)
151               msg_warn("%s ignored when %s is not empty.",
152                          VAR_LMTP_SMTP(TLS_PER_SITE), VAR_LMTP_SMTP(TLS_POLICY));
153           return;
154     }
155     if (*var_smtp_tls_per_site) {
156           tls_per_site = maps_create(VAR_LMTP_SMTP(TLS_PER_SITE),
157                                            var_smtp_tls_per_site,
158                                            DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
159                                            | DICT_FLAG_UTF8_REQUEST);
160     }
161 }
162 
163 /* policy_name - printable tls policy level */
164 
policy_name(int tls_level)165 static const char *policy_name(int tls_level)
166 {
167     const char *name = str_tls_level(tls_level);
168 
169     if (name == 0)
170           name = "unknown";
171     return name;
172 }
173 
174 #define MARK_INVALID(why, levelp) do { \
175               dsb_simple((why), "4.7.5", "client TLS configuration problem"); \
176               *(levelp) = TLS_LEV_INVALID; } while (0)
177 
178 /* tls_site_lookup - look up per-site TLS security level */
179 
tls_site_lookup(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)180 static void tls_site_lookup(SMTP_TLS_POLICY *tls, int *site_level,
181                                   const char *site_name, const char *site_class)
182 {
183     const char *lookup;
184 
185     /*
186      * Look up a non-default policy. In case of multiple lookup results, the
187      * precedence order is a permutation of the TLS enforcement level order:
188      * VERIFY, ENCRYPT, NONE, MAY, NOTFOUND. I.e. we override MAY with a more
189      * specific policy including NONE, otherwise we choose the stronger
190      * enforcement level.
191      */
192     if ((lookup = maps_find(tls_per_site, site_name, 0)) != 0) {
193           if (!strcasecmp(lookup, "NONE")) {
194               /* NONE overrides MAY or NOTFOUND. */
195               if (*site_level <= TLS_LEV_MAY)
196                     *site_level = TLS_LEV_NONE;
197           } else if (!strcasecmp(lookup, "MAY")) {
198               /* MAY overrides NOTFOUND but not NONE. */
199               if (*site_level < TLS_LEV_NONE)
200                     *site_level = TLS_LEV_MAY;
201           } else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) {
202               if (*site_level < TLS_LEV_ENCRYPT)
203                     *site_level = TLS_LEV_ENCRYPT;
204           } else if (!strcasecmp(lookup, "MUST")) {
205               if (*site_level < TLS_LEV_VERIFY)
206                     *site_level = TLS_LEV_VERIFY;
207           } else {
208               msg_warn("%s: unknown TLS policy '%s' for %s %s",
209                          tls_per_site->title, lookup, site_class, site_name);
210               MARK_INVALID(tls->why, site_level);
211               return;
212           }
213     } else if (tls_per_site->error) {
214           msg_warn("%s: %s \"%s\": per-site table lookup error",
215                      tls_per_site->title, site_class, site_name);
216           dsb_simple(tls->why, "4.3.0", "Temporary lookup error");
217           *site_level = TLS_LEV_INVALID;
218           return;
219     }
220     return;
221 }
222 
223 /* tls_policy_lookup_one - look up destination TLS policy */
224 
tls_policy_lookup_one(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)225 static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
226                                                   const char *site_name,
227                                                   const char *site_class)
228 {
229     const char *lookup;
230     char   *policy;
231     char   *saved_policy = 0;
232     char   *tok;
233     char   *name;
234     char   *val;
235     static VSTRING *cbuf;
236     char   *free_me = 0;
237 
238 #undef FREE_RETURN
239 #define FREE_RETURN do { \
240           if (saved_policy) \
241               myfree(saved_policy); \
242           if (free_me) \
243               myfree(free_me); \
244           return; \
245     } while (0)
246 
247 #define INVALID_RETURN(why, levelp) do { \
248               MARK_INVALID((why), (levelp)); FREE_RETURN; } while (0)
249 
250 #define WHERE \
251     STR(vstring_sprintf(cbuf, "%s, %s \"%s\"", \
252                     tls_policy->title, site_class, site_name))
253 
254     if (cbuf == 0)
255           cbuf = vstring_alloc(10);
256 
257     if ((lookup = maps_find(tls_policy, site_name, 0)) == 0) {
258           if (tls_policy->error) {
259               msg_warn("%s: policy table lookup error", WHERE);
260               MARK_INVALID(tls->why, site_level);
261           }
262           return;
263     }
264     saved_policy = policy = mystrdup(lookup);
265 
266     if ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) == 0) {
267           msg_warn("%s: invalid empty policy", WHERE);
268           INVALID_RETURN(tls->why, site_level);
269     }
270     *site_level = tls_level_lookup(tok);
271     if (*site_level == TLS_LEV_INVALID) {
272           /* tls_level_lookup() logs no warning. */
273           msg_warn("%s: invalid security level \"%s\"", WHERE, tok);
274           INVALID_RETURN(tls->why, site_level);
275     }
276 
277     /*
278      * Warn about ignored attributes when TLS is disabled.
279      */
280     if (*site_level < TLS_LEV_MAY) {
281           while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0)
282               msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
283                          WHERE, tok);
284           FREE_RETURN;
285     }
286 
287     /*
288      * Errors in attributes may have security consequences, don't ignore
289      * errors that can degrade security.
290      *
291      * Caution: normalize whitespace, to neutralize line break etc. characters
292      * inside the value portion of { name = value }.
293      */
294     while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
295           const char *err;
296 
297 #define EXTPAR_OPT  (EXTPAR_FLAG_STRIP | EXTPAR_FLAG_NORMAL_WS)
298 
299           if ((tok[0] == CHARS_BRACE[0]
300                && (err = free_me = extpar(&tok, CHARS_BRACE, EXTPAR_OPT)) != 0)
301               || (err = split_nameval(tok, &name, &val)) != 0) {
302               msg_warn("%s: malformed attribute/value pair \"%s\": %s",
303                          WHERE, tok, err);
304               INVALID_RETURN(tls->why, site_level);
305           }
306           /* Only one instance per policy. */
307           if (!strcasecmp(name, "ciphers")) {
308               if (*val == 0) {
309                     msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
310                     INVALID_RETURN(tls->why, site_level);
311               }
312               if (tls->grade) {
313                     msg_warn("%s: attribute \"%s\" is specified multiple times",
314                                WHERE, name);
315                     INVALID_RETURN(tls->why, site_level);
316               }
317               tls->grade = mystrdup(val);
318               continue;
319           }
320           /* Only one instance per policy. */
321           if (!strcasecmp(name, "protocols")) {
322               if (tls->protocols) {
323                     msg_warn("%s: attribute \"%s\" is specified multiple times",
324                                WHERE, name);
325                     INVALID_RETURN(tls->why, site_level);
326               }
327               tls->protocols = mystrdup(val);
328               continue;
329           }
330           /* Only one instance per policy. */
331           if (!strcasecmp(name, "servername")) {
332               if (tls->sni) {
333                     msg_warn("%s: attribute \"%s\" is specified multiple times",
334                                WHERE, name);
335                     INVALID_RETURN(tls->why, site_level);
336               }
337               if (valid_hostname(val, DONT_GRIPE))
338                     tls->sni = mystrdup(val);
339               else {
340                     msg_warn("%s: \"%s=%s\" specifies an invalid hostname",
341                                WHERE, name, val);
342                     INVALID_RETURN(tls->why, site_level);
343               }
344               continue;
345           }
346           /* Multiple instances per policy. */
347           if (!strcasecmp(name, "match")) {
348               if (*val == 0) {
349                     msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
350                     INVALID_RETURN(tls->why, site_level);
351               }
352               switch (*site_level) {
353               default:
354                     msg_warn("%s: attribute \"%s\" invalid at security level "
355                                "\"%s\"", WHERE, name, policy_name(*site_level));
356                     INVALID_RETURN(tls->why, site_level);
357                     break;
358               case TLS_LEV_FPRINT:
359                     if (tls->matchargv == 0)
360                         tls->matchargv = argv_split(val, "|");
361                     else
362                         argv_split_append(tls->matchargv, val, "|");
363                     break;
364               case TLS_LEV_VERIFY:
365               case TLS_LEV_SECURE:
366                     if (tls->matchargv == 0)
367                         tls->matchargv = argv_split(val, ":");
368                     else
369                         argv_split_append(tls->matchargv, val, ":");
370                     break;
371               }
372               continue;
373           }
374           /* Only one instance per policy. */
375           if (!strcasecmp(name, "exclude")) {
376               if (tls->exclusions) {
377                     msg_warn("%s: attribute \"%s\" is specified multiple times",
378                                WHERE, name);
379                     INVALID_RETURN(tls->why, site_level);
380               }
381               tls->exclusions = vstring_strcpy(vstring_alloc(10), val);
382               continue;
383           }
384           /* Multiple instances per policy. */
385           if (!strcasecmp(name, "tafile")) {
386               /* Only makes sense if we're using CA-based trust */
387               if (!TLS_MUST_PKIX(*site_level)) {
388                     msg_warn("%s: attribute \"%s\" invalid at security level"
389                                " \"%s\"", WHERE, name, policy_name(*site_level));
390                     INVALID_RETURN(tls->why, site_level);
391               }
392               if (*val == 0) {
393                     msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
394                     INVALID_RETURN(tls->why, site_level);
395               }
396               if (!tls->dane)
397                     tls->dane = tls_dane_alloc();
398               if (!tls_dane_load_trustfile(tls->dane, val)) {
399                     INVALID_RETURN(tls->why, site_level);
400               }
401               continue;
402           }
403           /* Last one wins. */
404           if (!strcasecmp(name, "connection_reuse")) {
405               if (strcasecmp(val, "yes") == 0) {
406                     tls->conn_reuse = 1;
407               } else if (strcasecmp(val, "no") == 0) {
408                     tls->conn_reuse = 0;
409               } else {
410                     msg_warn("%s: attribute \"%s\" has bad value: \"%s\"",
411                                WHERE, name, val);
412                     INVALID_RETURN(tls->why, site_level);
413               }
414               continue;
415           }
416           /* Last one wins. */
417           if (!strcasecmp(name, "enable_rpk")) {
418               /* Ultimately ignored at some security levels */
419               if (strcasecmp(val, "yes") == 0) {
420                     tls->enable_rpk = 1;
421               } else if (strcasecmp(val, "no") == 0) {
422                     tls->enable_rpk = 0;
423               } else {
424                     msg_warn("%s: attribute \"%s\" has bad value: \"%s\"",
425                                WHERE, name, val);
426                     INVALID_RETURN(tls->why, site_level);
427               }
428               continue;
429           }
430           /* Only one instance per policy. */
431           if (!strcasecmp(name, EXT_POLICY_TTL)) {
432               char   *end;
433               long    lval;
434 
435               if (tls->ext_policy_ttl != EXT_POLICY_TTL_UNSET) {
436                     msg_warn("%s: attribute \"%s\" is specified multiple times",
437                                WHERE, name);
438                     INVALID_RETURN(tls->why, site_level);
439               }
440               if (!alldig(val) || ((lval = sane_strtol(val, &end, 10)),
441                                          ((tls->ext_policy_ttl = lval) != lval))
442                     || *end != 0) {
443                     msg_warn("%s: attribute \"%s\" has a malformed value: \"%s\"",
444                                WHERE, name, val);
445                     INVALID_RETURN(tls->why, site_level);
446               }
447               continue;
448           }
449           /* Only one instance per policy. */
450           if (!strcasecmp(name, EXT_POLICY_TYPE)) {
451               if (tls->ext_policy_type) {
452                     msg_warn("%s: attribute \"%s\" is specified multiple times",
453                                WHERE, name);
454                     INVALID_RETURN(tls->why, site_level);
455               }
456               if (!valid_tlsrpt_policy_type(val)) {
457                     msg_warn("%s: attribute \"%s\" has an unexpected value: \"%s\"",
458                                WHERE, name, val);
459                     INVALID_RETURN(tls->why, site_level);
460               }
461               tls->ext_policy_type = mystrdup(val);
462               continue;
463           }
464           /* Only one instance per policy. */
465           if (!strcasecmp(name, EXT_POLICY_DOMAIN)) {
466               if (tls->ext_policy_domain) {
467                     msg_warn("%s: attribute \"%s\" is specified multiple times",
468                                WHERE, name);
469                     INVALID_RETURN(tls->why, site_level);
470               }
471               if (!valid_hostname(val, DO_GRIPE)) {
472                     msg_warn("%s: attribute \"%s\" has a malformed value: \"%s\"",
473                                WHERE, name, val);
474                     INVALID_RETURN(tls->why, site_level);
475               }
476               tls->ext_policy_domain = mystrdup(val);
477               continue;
478           }
479           /* Multiple instances per policy are allowed. */
480           if (!strcasecmp(name, EXT_POLICY_STRING)) {
481               if (tls->ext_policy_strings == 0)
482                     tls->ext_policy_strings = argv_alloc(1);
483               argv_add(tls->ext_policy_strings, val, (char *) 0);
484               continue;
485           }
486           /* Multiple instances per policy are allowed. */
487           if (!strcasecmp(name, EXT_MX_HOST_PATTERN)) {
488               if (tls->ext_mx_host_patterns == 0)
489                     tls->ext_mx_host_patterns = argv_alloc(1);
490               argv_add(tls->ext_mx_host_patterns, val, (char *) 0);
491               continue;
492           }
493           /* Only one instance per policy. */
494           if (!strcasecmp(name, EXT_POLICY_FAILURE)) {
495               if (tls->ext_policy_failure != 0) {
496                     msg_warn("%s: attribute \"%s\" is specified multiple times",
497                                WHERE, name);
498                     INVALID_RETURN(tls->why, site_level);
499               }
500               if (!valid_tlsrpt_policy_failure(val)) {
501                     msg_warn("%s: attribute \"%s\" has an unexpected value: \"%s\"",
502                                WHERE, name, val);
503                     INVALID_RETURN(tls->why, site_level);
504               }
505               tls->ext_policy_failure = mystrdup(val);
506               continue;
507           }
508           msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
509           INVALID_RETURN(tls->why, site_level);
510     }
511     if (tls->ext_policy_type == 0) {
512           if (tls->ext_policy_ttl != EXT_POLICY_TTL_UNSET
513               || tls->ext_policy_strings
514               || tls->ext_policy_domain || tls->ext_mx_host_patterns
515               || tls->ext_policy_failure) {
516               msg_warn("%s: built-in policy has unexpected attribute "
517                          "policy_ttl, policy_domain, policy_string, "
518                          "mx_host_pattern or policy_failure", WHERE);
519               INVALID_RETURN(tls->why, site_level);
520           }
521     }
522     FREE_RETURN;
523 }
524 
525 /* tls_policy_lookup - look up destination TLS policy */
526 
tls_policy_lookup(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)527 static void tls_policy_lookup(SMTP_TLS_POLICY *tls, int *site_level,
528                                             const char *site_name,
529                                             const char *site_class)
530 {
531 
532     /*
533      * Only one lookup with [nexthop]:port, [nexthop] or nexthop:port These
534      * are never the domain part of localpart@domain, rather they are
535      * explicit nexthops from transport:nexthop, and match only the
536      * corresponding policy. Parent domain matching (below) applies only to
537      * sub-domains of the recipient domain.
538      *
539      * XXX UNIX-domain connections query with the pathname as destination.
540      */
541     if (!valid_utf8_hostname(var_smtputf8_enable, site_name, DONT_GRIPE)) {
542           tls_policy_lookup_one(tls, site_level, site_name, site_class);
543           return;
544     }
545     do {
546           tls_policy_lookup_one(tls, site_level, site_name, site_class);
547     } while (*site_level == TLS_LEV_NOTFOUND
548                && (site_name = strchr(site_name + 1, '.')) != 0);
549 }
550 
551 /* load_tas - load one or more ta files */
552 
load_tas(TLS_DANE * dane,const char * files)553 static int load_tas(TLS_DANE *dane, const char *files)
554 {
555     int     ret = 0;
556     char   *save = mystrdup(files);
557     char   *buf = save;
558     char   *file;
559 
560     do {
561           if ((file = mystrtok(&buf, CHARS_COMMA_SP)) != 0)
562               ret = tls_dane_load_trustfile(dane, file);
563     } while (file && ret);
564 
565     myfree(save);
566     return (ret);
567 }
568 
569 /* set_cipher_grade - Set cipher grade and exclusions */
570 
set_cipher_grade(SMTP_TLS_POLICY * tls)571 static void set_cipher_grade(SMTP_TLS_POLICY *tls)
572 {
573     const char *mand_exclude = "";
574     const char *also_exclude = "";
575 
576     /*
577      * Use main.cf cipher level if no per-destination value specified. With
578      * mandatory encryption at least encrypt, and with mandatory verification
579      * at least authenticate!
580      */
581     switch (tls->level) {
582     case TLS_LEV_INVALID:
583     case TLS_LEV_NONE:
584           return;
585 
586     case TLS_LEV_MAY:
587           if (tls->grade == 0)
588               tls->grade = mystrdup(var_smtp_tls_ciph);
589           break;
590 
591     case TLS_LEV_ENCRYPT:
592           if (tls->grade == 0)
593               tls->grade = mystrdup(var_smtp_tls_mand_ciph);
594           mand_exclude = var_smtp_tls_mand_excl;
595           also_exclude = "eNULL";
596           break;
597 
598     case TLS_LEV_HALF_DANE:
599     case TLS_LEV_DANE:
600     case TLS_LEV_DANE_ONLY:
601     case TLS_LEV_FPRINT:
602     case TLS_LEV_VERIFY:
603     case TLS_LEV_SECURE:
604           if (tls->grade == 0)
605               tls->grade = mystrdup(var_smtp_tls_mand_ciph);
606           mand_exclude = var_smtp_tls_mand_excl;
607           also_exclude = "aNULL";
608           break;
609     }
610 
611 #define ADD_EXCLUDE(vstr, str) \
612     do { \
613           if (*(str)) \
614               vstring_sprintf_append((vstr), "%s%s", \
615                                            VSTRING_LEN(vstr) ? " " : "", (str)); \
616     } while (0)
617 
618     /*
619      * The "exclude" policy table attribute overrides main.cf exclusion
620      * lists.
621      */
622     if (tls->exclusions == 0) {
623           tls->exclusions = vstring_alloc(10);
624           ADD_EXCLUDE(tls->exclusions, var_smtp_tls_excl_ciph);
625           ADD_EXCLUDE(tls->exclusions, mand_exclude);
626     }
627     ADD_EXCLUDE(tls->exclusions, also_exclude);
628 }
629 
630 /* policy_create - create SMTP TLS policy cache object (ctable call-back) */
631 
policy_create(const char * unused_key,void * context)632 static void *policy_create(const char *unused_key, void *context)
633 {
634     SMTP_ITERATOR *iter = (SMTP_ITERATOR *) context;
635     int     site_level;
636     const char *dest = STR(iter->dest);
637     const char *host = STR(iter->host);
638 
639     /*
640      * Prepare a pristine policy object.
641      */
642     SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) mymalloc(sizeof(*tls));
643 
644     smtp_tls_policy_init(tls, dsb_create());
645     tls->conn_reuse = var_smtp_tls_conn_reuse;
646     tls->enable_rpk = var_smtp_tls_enable_rpk;
647 
648     /*
649      * Compute the per-site TLS enforcement level. For compatibility with the
650      * original TLS patch, this algorithm is gives equal precedence to host
651      * and next-hop policies.
652      */
653     tls->level = global_tls_level();
654     site_level = TLS_LEV_NOTFOUND;
655 
656     if (tls_policy) {
657           tls_policy_lookup(tls, &site_level, dest, "next-hop destination");
658     } else if (tls_per_site) {
659           tls_site_lookup(tls, &site_level, dest, "next-hop destination");
660           if (site_level != TLS_LEV_INVALID
661               && strcasecmp_utf8(dest, host) != 0)
662               tls_site_lookup(tls, &site_level, host, "server hostname");
663 
664           /*
665            * Override a wild-card per-site policy with a more specific global
666            * policy.
667            *
668            * With the original TLS patch, 1) a per-site ENCRYPT could not override
669            * a global VERIFY, and 2) a combined per-site (NONE+MAY) policy
670            * produced inconsistent results: it changed a global VERIFY into
671            * NONE, while producing MAY with all weaker global policy settings.
672            *
673            * With the current implementation, a combined per-site (NONE+MAY)
674            * consistently overrides global policy with NONE, and global policy
675            * can override only a per-site MAY wildcard. That is, specific
676            * policies consistently override wildcard policies, and
677            * (non-wildcard) per-site policies consistently override global
678            * policies.
679            */
680           if (site_level == TLS_LEV_MAY && tls->level > TLS_LEV_MAY)
681               site_level = tls->level;
682     }
683     switch (site_level) {
684     default:
685           tls->level = site_level;
686           /* FALLTHROUGH */
687     case TLS_LEV_NOTFOUND:
688           break;
689     case TLS_LEV_INVALID:
690           tls->level = site_level;
691           return ((void *) tls);
692     }
693 
694     /*
695      * DANE initialization may change the security level to something else,
696      * so do this early, so that we use the right level below.  Note that
697      * "dane-only" changes to "dane" once we obtain the requisite TLSA
698      * records.
699      */
700     if (TLS_DANE_BASED(tls->level))
701           dane_init(tls, iter);
702     if (tls->level == TLS_LEV_INVALID)
703           return ((void *) tls);
704 
705     /*
706      * Use main.cf protocols and SNI settings if not set in per-destination
707      * table.
708      */
709     if (tls->level > TLS_LEV_NONE && tls->protocols == 0)
710           tls->protocols =
711               mystrdup((tls->level == TLS_LEV_MAY) ?
712                          var_smtp_tls_proto : var_smtp_tls_mand_proto);
713     if (tls->level > TLS_LEV_NONE && tls->sni == 0) {
714           if (!*var_smtp_tls_sni || valid_hostname(var_smtp_tls_sni, DONT_GRIPE))
715               tls->sni = mystrdup(var_smtp_tls_sni);
716           else {
717               msg_warn("\"%s = %s\" specifies an invalid hostname",
718                          VAR_LMTP_SMTP(TLS_SNI), var_smtp_tls_sni);
719               MARK_INVALID(tls->why, &tls->level);
720               return ((void *) tls);
721           }
722     }
723 
724     /*
725      * Compute cipher grade (if set in per-destination table, else
726      * set_cipher() uses main.cf settings) and security level dependent
727      * cipher exclusion list.
728      */
729     set_cipher_grade(tls);
730 
731 /*
732  * Even when soliciting raw public keys, synthesize TLSA RRs that also match
733  * certificates.  Though this is fragile, it maintains compatibility with
734  * servers that never return RPKs.
735  */
736 #define DONT_SUPPRESS_CERT_MATCH        0
737 
738     /*
739      * Use main.cf cert_match setting if not set in per-destination table.
740      */
741     switch (tls->level) {
742     case TLS_LEV_INVALID:
743     case TLS_LEV_NONE:
744     case TLS_LEV_MAY:
745     case TLS_LEV_ENCRYPT:
746     case TLS_LEV_HALF_DANE:
747     case TLS_LEV_DANE:
748     case TLS_LEV_DANE_ONLY:
749           break;
750     case TLS_LEV_FPRINT:
751           if (tls->dane == 0)
752               tls->dane = tls_dane_alloc();
753           /* Process the specified fingerprint match patterns */
754           if (tls->matchargv) {
755               int     i;
756 
757               for (i = 0; i < tls->matchargv->argc; ++i) {
758                     tls_dane_add_fpt_digests(tls->dane, DONT_SUPPRESS_CERT_MATCH,
759                                                    tls->matchargv->argv[i], "",
760                                                    smtp_mode);
761               }
762           } else {
763               tls_dane_add_fpt_digests(tls->dane, DONT_SUPPRESS_CERT_MATCH,
764                                              var_smtp_tls_fpt_cmatch, CHARS_COMMA_SP,
765                                              smtp_mode);
766           }
767           if (tls->dane->tlsa == 0) {
768               msg_warn("nexthop domain %s: configured at fingerprint "
769                          "security level, but with no fingerprints to match.",
770                          dest);
771               MARK_INVALID(tls->why, &tls->level);
772               return ((void *) tls);
773           }
774           break;
775     case TLS_LEV_VERIFY:
776     case TLS_LEV_SECURE:
777           if (tls->matchargv == 0)
778               tls->matchargv =
779                     argv_split(tls->level == TLS_LEV_VERIFY ?
780                                  var_smtp_tls_vfy_cmatch : var_smtp_tls_sec_cmatch,
781                                  CHARS_COMMA_SP ":");
782           if (*var_smtp_tls_tafile) {
783               if (tls->dane == 0)
784                     tls->dane = tls_dane_alloc();
785               if (tls->dane->tlsa == 0
786                     && !load_tas(tls->dane, var_smtp_tls_tafile)) {
787                     MARK_INVALID(tls->why, &tls->level);
788                     return ((void *) tls);
789               }
790           }
791           break;
792     default:
793           msg_panic("unexpected TLS security level: %d", tls->level);
794     }
795 
796     if (msg_verbose && tls->level != global_tls_level())
797           msg_info("%s TLS level: %s", "effective", policy_name(tls->level));
798 
799     return ((void *) tls);
800 }
801 
802 /* policy_delete - free no longer cached policy (ctable call-back) */
803 
policy_delete(void * item,void * unused_context)804 static void policy_delete(void *item, void *unused_context)
805 {
806     SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) item;
807 
808     if (tls->protocols)
809           myfree(tls->protocols);
810     if (tls->sni)
811           myfree(tls->sni);
812     if (tls->grade)
813           myfree(tls->grade);
814     if (tls->exclusions)
815           vstring_free(tls->exclusions);
816     if (tls->matchargv)
817           argv_free(tls->matchargv);
818     if (tls->dane)
819           tls_dane_free(tls->dane);
820     dsb_free(tls->why);
821     if (tls->ext_policy_type)
822           myfree(tls->ext_policy_type);
823     if (tls->ext_policy_domain)
824           myfree(tls->ext_policy_domain);
825     if (tls->ext_policy_strings)
826           argv_free(tls->ext_policy_strings);
827     if (tls->ext_mx_host_patterns)
828           argv_free(tls->ext_mx_host_patterns);
829     if (tls->ext_policy_failure)
830           myfree(tls->ext_policy_failure);
831 
832     myfree((void *) tls);
833 }
834 
835 /* smtp_tls_policy_cache_query - cached lookup of TLS policy */
836 
smtp_tls_policy_cache_query(DSN_BUF * why,SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter)837 int     smtp_tls_policy_cache_query(DSN_BUF *why, SMTP_TLS_POLICY *tls,
838                                                     SMTP_ITERATOR *iter)
839 {
840     VSTRING *key;
841 
842     /*
843      * Create an empty TLS Policy cache on the fly.
844      */
845     if (policy_cache == 0)
846           policy_cache =
847               ctable_create(CACHE_SIZE, policy_create, policy_delete, (void *) 0);
848 
849     /*
850      * Query the TLS Policy cache, with a search key that reflects our shared
851      * values that also appear in other cache and table search keys.
852      */
853     key = vstring_alloc(100);
854     smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_CUR_NEXTHOP
855                         | SMTP_KEY_FLAG_HOSTNAME
856                         | SMTP_KEY_FLAG_PORT);
857     ctable_newcontext(policy_cache, (void *) iter);
858     *tls = *(SMTP_TLS_POLICY *) ctable_locate(policy_cache, STR(key));
859     vstring_free(key);
860 
861     /*
862      * Report errors. Both error and non-error results are cached. We must
863      * therefore copy the cached DSN buffer content to the caller's buffer.
864      */
865     if (tls->level == TLS_LEV_INVALID) {
866           /* XXX Simplify this by implementing a "copy" primitive. */
867           dsb_update(why,
868                        STR(tls->why->status), STR(tls->why->action),
869                        STR(tls->why->mtype), STR(tls->why->mname),
870                        STR(tls->why->dtype), STR(tls->why->dtext),
871                        "%s", STR(tls->why->reason));
872           return (0);
873     } else {
874           return (1);
875     }
876 }
877 
878 /* smtp_tls_policy_cache_flush - flush TLS policy cache */
879 
smtp_tls_policy_cache_flush(void)880 void    smtp_tls_policy_cache_flush(void)
881 {
882     if (policy_cache != 0) {
883           ctable_free(policy_cache);
884           policy_cache = 0;
885     }
886 }
887 
888 /* global_tls_level - parse and cache var_smtp_tls_level */
889 
global_tls_level(void)890 static int global_tls_level(void)
891 {
892     static int l = TLS_LEV_NOTFOUND;
893 
894     if (l != TLS_LEV_NOTFOUND)
895           return l;
896 
897     /*
898      * Compute the global TLS policy. This is the default policy level when
899      * no per-site policy exists. It also is used to override a wild-card
900      * per-site policy.
901      *
902      * We require that the global level is valid on startup.
903      */
904     if (*var_smtp_tls_level) {
905           if ((l = tls_level_lookup(var_smtp_tls_level)) == TLS_LEV_INVALID)
906               msg_fatal("invalid tls security level: \"%s\"", var_smtp_tls_level);
907     } else if (var_smtp_enforce_tls)
908           l = var_smtp_tls_enforce_peername ? TLS_LEV_VERIFY : TLS_LEV_ENCRYPT;
909     else
910           l = var_smtp_use_tls ? TLS_LEV_MAY : TLS_LEV_NONE;
911 
912     if (msg_verbose)
913           msg_info("%s TLS level: %s", "global", policy_name(l));
914 
915     return l;
916 }
917 
918 #define NONDANE_CONFIG        0                   /* Administrator's fault */
919 #define NONDANE_DEST          1                   /* Remote server's fault */
920 #define DANE_CANTAUTH         2                   /* Remote server's fault */
921 
dane_incompat(SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter,int errtype,const char * fmt,...)922 static void PRINTFLIKE(4, 5) dane_incompat(SMTP_TLS_POLICY *tls,
923                                                              SMTP_ITERATOR *iter,
924                                                              int errtype,
925                                                              const char *fmt,...)
926 {
927     va_list ap;
928 
929     va_start(ap, fmt);
930     if (tls->level == TLS_LEV_DANE) {
931           tls->level = (errtype == DANE_CANTAUTH) ? TLS_LEV_ENCRYPT : TLS_LEV_MAY;
932           if (errtype == NONDANE_CONFIG)
933               vmsg_warn(fmt, ap);
934           else if (msg_verbose)
935               vmsg_info(fmt, ap);
936     } else {                                                /* dane-only */
937           if (errtype == NONDANE_CONFIG) {
938               vmsg_warn(fmt, ap);
939               MARK_INVALID(tls->why, &tls->level);
940           } else {
941               tls->level = TLS_LEV_INVALID;
942               vdsb_simple(tls->why, "4.7.5", fmt, ap);
943           }
944     }
945     va_end(ap);
946 }
947 
948 /* dane_init - special initialization for "dane" security level */
949 
dane_init(SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter)950 static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter)
951 {
952     TLS_DANE *dane;
953 
954     if (!iter->port) {
955           msg_warn("%s: the \"dane\" security level is invalid for delivery via"
956                      " unix-domain sockets", STR(iter->dest));
957           MARK_INVALID(tls->why, &tls->level);
958           return;
959     }
960     if (!tls_dane_avail()) {
961           dane_incompat(tls, iter, NONDANE_CONFIG,
962                           "%s: %s configured, but no requisite library support",
963                           STR(iter->dest), policy_name(tls->level));
964           return;
965     }
966     if (!(smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS)
967           || smtp_dns_support != SMTP_DNS_DNSSEC) {
968           dane_incompat(tls, iter, NONDANE_CONFIG,
969                           "%s: %s configured with dnssec lookups disabled",
970                           STR(iter->dest), policy_name(tls->level));
971           return;
972     }
973 
974     /*
975      * If we ignore MX lookup errors, we also ignore DNSSEC security problems
976      * and thus avoid any reasonable expectation that we get the right DANE
977      * key material.
978      */
979     if (smtp_mode && var_ign_mx_lookup_err) {
980           dane_incompat(tls, iter, NONDANE_CONFIG,
981                           "%s: %s configured with MX lookup errors ignored",
982                           STR(iter->dest), policy_name(tls->level));
983           return;
984     }
985 
986     /*
987      * This is not optional, code in tls_dane.c assumes that the nexthop
988      * qname is already an fqdn.  If we're using these flags to go from qname
989      * to rname, the assumption is invalid.  Likewise we cannot add the qname
990      * to certificate name checks, ...
991      */
992     if (smtp_dns_res_opt & (RES_DEFNAMES | RES_DNSRCH)) {
993           dane_incompat(tls, iter, NONDANE_CONFIG,
994                           "%s: dns resolver options incompatible with %s TLS",
995                           STR(iter->dest), policy_name(tls->level));
996           return;
997     }
998 
999     /*
1000      * When the MX name is present and insecure, DANE may not apply, we then
1001      * either fail if DANE is mandatory or use regular opportunistic TLS if
1002      * the insecure MX level is "may".
1003      */
1004     if (iter->mx && !iter->mx->dnssec_valid
1005           && (tls->level == TLS_LEV_DANE_ONLY ||
1006               smtp_tls_insecure_mx_policy <= TLS_LEV_MAY)) {
1007           dane_incompat(tls, iter, NONDANE_DEST, "non DNSSEC destination");
1008           return;
1009     }
1010     /* When TLSA lookups fail, we defer the message */
1011     if ((dane = tls_dane_resolve(iter->port, "tcp", iter->rr,
1012                                          var_smtp_tls_force_tlsa)) == 0) {
1013           tls->level = TLS_LEV_INVALID;
1014           dsb_simple(tls->why, "4.7.5", "TLSA lookup error for %s:%u",
1015                        STR(iter->host), ntohs(iter->port));
1016           return;
1017     }
1018     if (tls_dane_notfound(dane)) {
1019           dane_incompat(tls, iter, NONDANE_DEST, "no TLSA records found");
1020           tls_dane_free(dane);
1021           return;
1022     }
1023 
1024     /*
1025      * Some TLSA records found, but none usable, per
1026      *
1027      * https://tools.ietf.org/html/draft-ietf-dane-srv-02#section-4
1028      *
1029      * we MUST use TLS, and SHALL use full PKIX certificate checks.  The latter
1030      * would be unwise for SMTP: no human present to "click ok" and risk of
1031      * non-delivery in most cases exceeds risk of interception.
1032      *
1033      * We also have a form of Goedel's incompleteness theorem in play: any list
1034      * of public root CA certs is either incomplete or inconsistent (for any
1035      * given verifier some of the CAs are surely not trustworthy).
1036      */
1037     if (tls_dane_unusable(dane)) {
1038           dane_incompat(tls, iter, DANE_CANTAUTH, "TLSA records unusable");
1039           tls_dane_free(dane);
1040           return;
1041     }
1042 
1043     /*
1044      * Perhaps downgrade to "encrypt" if MX is insecure.
1045      */
1046     if (iter->mx && !iter->mx->dnssec_valid) {
1047           if (smtp_tls_insecure_mx_policy == TLS_LEV_ENCRYPT) {
1048               dane_incompat(tls, iter, DANE_CANTAUTH,
1049                                 "Verification not possible, MX RRset is insecure");
1050               tls_dane_free(dane);
1051               return;
1052           }
1053           if (tls->level != TLS_LEV_DANE
1054               || smtp_tls_insecure_mx_policy != TLS_LEV_DANE)
1055               msg_panic("wrong state for insecure MX host DANE policy");
1056 
1057           /* For correct logging in tls_client_start() */
1058           tls->level = TLS_LEV_HALF_DANE;
1059     }
1060 
1061     /*
1062      * With DANE trust anchors, peername matching is not configurable.
1063      */
1064     if (dane->tlsa != 0) {
1065           tls->matchargv = argv_alloc(2);
1066           argv_add(tls->matchargv, dane->base_domain, ARGV_END);
1067           if (iter->mx) {
1068               if (strcmp(iter->mx->qname, iter->mx->rname) == 0)
1069                     argv_add(tls->matchargv, iter->mx->qname, ARGV_END);
1070               else
1071                     argv_add(tls->matchargv, iter->mx->rname,
1072                                iter->mx->qname, ARGV_END);
1073           }
1074     } else
1075           msg_panic("empty DANE match list");
1076     tls->dane = dane;
1077     return;
1078 }
1079 
1080 #endif
1081