xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtp/smtp_tls_policy.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: smtp_tls_policy.c,v 1.4 2022/10/08 16:12: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 <stringops.h>
108 #include <valid_hostname.h>
109 #include <valid_utf8_hostname.h>
110 #include <ctable.h>
111 
112 /* Global library. */
113 
114 #include <mail_params.h>
115 #include <maps.h>
116 #include <dsn_buf.h>
117 
118 /* DNS library. */
119 
120 #include <dns.h>
121 
122 /* Application-specific. */
123 
124 #include "smtp.h"
125 
126 /* XXX Cache size should scale with [sl]mtp_mx_address_limit. */
127 #define CACHE_SIZE 20
128 static CTABLE *policy_cache;
129 
130 static int global_tls_level(void);
131 static void dane_init(SMTP_TLS_POLICY *, SMTP_ITERATOR *);
132 
133 static MAPS *tls_policy;		/* lookup table(s) */
134 static MAPS *tls_per_site;		/* lookup table(s) */
135 
136 /* smtp_tls_list_init - initialize per-site policy lists */
137 
smtp_tls_list_init(void)138 void    smtp_tls_list_init(void)
139 {
140     if (*var_smtp_tls_policy) {
141 	tls_policy = maps_create(VAR_LMTP_SMTP(TLS_POLICY),
142 				 var_smtp_tls_policy,
143 				 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
144 				 | DICT_FLAG_UTF8_REQUEST);
145 	if (*var_smtp_tls_per_site)
146 	    msg_warn("%s ignored when %s is not empty.",
147 		     VAR_LMTP_SMTP(TLS_PER_SITE), VAR_LMTP_SMTP(TLS_POLICY));
148 	return;
149     }
150     if (*var_smtp_tls_per_site) {
151 	tls_per_site = maps_create(VAR_LMTP_SMTP(TLS_PER_SITE),
152 				   var_smtp_tls_per_site,
153 				   DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
154 				   | DICT_FLAG_UTF8_REQUEST);
155     }
156 }
157 
158 /* policy_name - printable tls policy level */
159 
policy_name(int tls_level)160 static const char *policy_name(int tls_level)
161 {
162     const char *name = str_tls_level(tls_level);
163 
164     if (name == 0)
165 	name = "unknown";
166     return name;
167 }
168 
169 #define MARK_INVALID(why, levelp) do { \
170 	    dsb_simple((why), "4.7.5", "client TLS configuration problem"); \
171 	    *(levelp) = TLS_LEV_INVALID; } while (0)
172 
173 /* tls_site_lookup - look up per-site TLS security level */
174 
tls_site_lookup(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)175 static void tls_site_lookup(SMTP_TLS_POLICY *tls, int *site_level,
176 		              const char *site_name, const char *site_class)
177 {
178     const char *lookup;
179 
180     /*
181      * Look up a non-default policy. In case of multiple lookup results, the
182      * precedence order is a permutation of the TLS enforcement level order:
183      * VERIFY, ENCRYPT, NONE, MAY, NOTFOUND. I.e. we override MAY with a more
184      * specific policy including NONE, otherwise we choose the stronger
185      * enforcement level.
186      */
187     if ((lookup = maps_find(tls_per_site, site_name, 0)) != 0) {
188 	if (!strcasecmp(lookup, "NONE")) {
189 	    /* NONE overrides MAY or NOTFOUND. */
190 	    if (*site_level <= TLS_LEV_MAY)
191 		*site_level = TLS_LEV_NONE;
192 	} else if (!strcasecmp(lookup, "MAY")) {
193 	    /* MAY overrides NOTFOUND but not NONE. */
194 	    if (*site_level < TLS_LEV_NONE)
195 		*site_level = TLS_LEV_MAY;
196 	} else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) {
197 	    if (*site_level < TLS_LEV_ENCRYPT)
198 		*site_level = TLS_LEV_ENCRYPT;
199 	} else if (!strcasecmp(lookup, "MUST")) {
200 	    if (*site_level < TLS_LEV_VERIFY)
201 		*site_level = TLS_LEV_VERIFY;
202 	} else {
203 	    msg_warn("%s: unknown TLS policy '%s' for %s %s",
204 		     tls_per_site->title, lookup, site_class, site_name);
205 	    MARK_INVALID(tls->why, site_level);
206 	    return;
207 	}
208     } else if (tls_per_site->error) {
209 	msg_warn("%s: %s \"%s\": per-site table lookup error",
210 		 tls_per_site->title, site_class, site_name);
211 	dsb_simple(tls->why, "4.3.0", "Temporary lookup error");
212 	*site_level = TLS_LEV_INVALID;
213 	return;
214     }
215     return;
216 }
217 
218 /* tls_policy_lookup_one - look up destination TLS policy */
219 
tls_policy_lookup_one(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)220 static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
221 				          const char *site_name,
222 				          const char *site_class)
223 {
224     const char *lookup;
225     char   *policy;
226     char   *saved_policy;
227     char   *tok;
228     const char *err;
229     char   *name;
230     char   *val;
231     static VSTRING *cbuf;
232 
233 #undef FREE_RETURN
234 #define FREE_RETURN do { myfree(saved_policy); return; } while (0)
235 
236 #define INVALID_RETURN(why, levelp) do { \
237 	    MARK_INVALID((why), (levelp)); FREE_RETURN; } while (0)
238 
239 #define WHERE \
240     STR(vstring_sprintf(cbuf, "%s, %s \"%s\"", \
241 		tls_policy->title, site_class, site_name))
242 
243     if (cbuf == 0)
244 	cbuf = vstring_alloc(10);
245 
246     if ((lookup = maps_find(tls_policy, site_name, 0)) == 0) {
247 	if (tls_policy->error) {
248 	    msg_warn("%s: policy table lookup error", WHERE);
249 	    MARK_INVALID(tls->why, site_level);
250 	}
251 	return;
252     }
253     saved_policy = policy = mystrdup(lookup);
254 
255     if ((tok = mystrtok(&policy, CHARS_COMMA_SP)) == 0) {
256 	msg_warn("%s: invalid empty policy", WHERE);
257 	INVALID_RETURN(tls->why, site_level);
258     }
259     *site_level = tls_level_lookup(tok);
260     if (*site_level == TLS_LEV_INVALID) {
261 	/* tls_level_lookup() logs no warning. */
262 	msg_warn("%s: invalid security level \"%s\"", WHERE, tok);
263 	INVALID_RETURN(tls->why, site_level);
264     }
265 
266     /*
267      * Warn about ignored attributes when TLS is disabled.
268      */
269     if (*site_level < TLS_LEV_MAY) {
270 	while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0)
271 	    msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
272 		     WHERE, tok);
273 	FREE_RETURN;
274     }
275 
276     /*
277      * Errors in attributes may have security consequences, don't ignore
278      * errors that can degrade security.
279      */
280     while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0) {
281 	if ((err = split_nameval(tok, &name, &val)) != 0) {
282 	    msg_warn("%s: malformed attribute/value pair \"%s\": %s",
283 		     WHERE, tok, err);
284 	    INVALID_RETURN(tls->why, site_level);
285 	}
286 	/* Only one instance per policy. */
287 	if (!strcasecmp(name, "ciphers")) {
288 	    if (*val == 0) {
289 		msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
290 		INVALID_RETURN(tls->why, site_level);
291 	    }
292 	    if (tls->grade) {
293 		msg_warn("%s: attribute \"%s\" is specified multiple times",
294 			 WHERE, name);
295 		INVALID_RETURN(tls->why, site_level);
296 	    }
297 	    tls->grade = mystrdup(val);
298 	    continue;
299 	}
300 	/* Only one instance per policy. */
301 	if (!strcasecmp(name, "protocols")) {
302 	    if (tls->protocols) {
303 		msg_warn("%s: attribute \"%s\" is specified multiple times",
304 			 WHERE, name);
305 		INVALID_RETURN(tls->why, site_level);
306 	    }
307 	    tls->protocols = mystrdup(val);
308 	    continue;
309 	}
310 	/* Only one instance per policy. */
311 	if (!strcasecmp(name, "servername")) {
312 	    if (tls->sni) {
313 		msg_warn("%s: attribute \"%s\" is specified multiple times",
314 			 WHERE, name);
315 		INVALID_RETURN(tls->why, site_level);
316 	    }
317 	    if (valid_hostname(val, DONT_GRIPE))
318 		tls->sni = mystrdup(val);
319 	    else {
320 		msg_warn("%s: \"%s=%s\" specifies an invalid hostname",
321 			 WHERE, name, val);
322 		INVALID_RETURN(tls->why, site_level);
323 	    }
324 	    continue;
325 	}
326 	/* Multiple instances per policy. */
327 	if (!strcasecmp(name, "match")) {
328 	    if (*val == 0) {
329 		msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
330 		INVALID_RETURN(tls->why, site_level);
331 	    }
332 	    switch (*site_level) {
333 	    default:
334 		msg_warn("%s: attribute \"%s\" invalid at security level "
335 			 "\"%s\"", WHERE, name, policy_name(*site_level));
336 		INVALID_RETURN(tls->why, site_level);
337 		break;
338 	    case TLS_LEV_FPRINT:
339 		if (!tls->dane)
340 		    tls->dane = tls_dane_alloc();
341 		tls_dane_add_fpt_digests(tls->dane, val, "|", smtp_mode);
342 		break;
343 	    case TLS_LEV_VERIFY:
344 	    case TLS_LEV_SECURE:
345 		if (tls->matchargv == 0)
346 		    tls->matchargv = argv_split(val, ":");
347 		else
348 		    argv_split_append(tls->matchargv, val, ":");
349 		break;
350 	    }
351 	    continue;
352 	}
353 	/* Only one instance per policy. */
354 	if (!strcasecmp(name, "exclude")) {
355 	    if (tls->exclusions) {
356 		msg_warn("%s: attribute \"%s\" is specified multiple times",
357 			 WHERE, name);
358 		INVALID_RETURN(tls->why, site_level);
359 	    }
360 	    tls->exclusions = vstring_strcpy(vstring_alloc(10), val);
361 	    continue;
362 	}
363 	/* Multiple instances per policy. */
364 	if (!strcasecmp(name, "tafile")) {
365 	    /* Only makes sense if we're using CA-based trust */
366 	    if (!TLS_MUST_PKIX(*site_level)) {
367 		msg_warn("%s: attribute \"%s\" invalid at security level"
368 			 " \"%s\"", WHERE, name, policy_name(*site_level));
369 		INVALID_RETURN(tls->why, site_level);
370 	    }
371 	    if (*val == 0) {
372 		msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
373 		INVALID_RETURN(tls->why, site_level);
374 	    }
375 	    if (!tls->dane)
376 		tls->dane = tls_dane_alloc();
377 	    if (!tls_dane_load_trustfile(tls->dane, val)) {
378 		INVALID_RETURN(tls->why, site_level);
379 	    }
380 	    continue;
381 	}
382 	/* Last one wins. */
383 	if (!strcasecmp(name, "connection_reuse")) {
384 	    if (strcasecmp(val, "yes") == 0) {
385 		tls->conn_reuse = 1;
386 	    } else if (strcasecmp(val, "no") == 0) {
387 		tls->conn_reuse = 0;
388 	    } else {
389 		msg_warn("%s: attribute \"%s\" has bad value: \"%s\"",
390 			 WHERE, name, val);
391 		INVALID_RETURN(tls->why, site_level);
392 	    }
393 	    continue;
394 	}
395 	msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
396 	INVALID_RETURN(tls->why, site_level);
397     }
398 
399     FREE_RETURN;
400 }
401 
402 /* tls_policy_lookup - look up destination TLS policy */
403 
tls_policy_lookup(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)404 static void tls_policy_lookup(SMTP_TLS_POLICY *tls, int *site_level,
405 			              const char *site_name,
406 			              const char *site_class)
407 {
408 
409     /*
410      * Only one lookup with [nexthop]:port, [nexthop] or nexthop:port These
411      * are never the domain part of localpart@domain, rather they are
412      * explicit nexthops from transport:nexthop, and match only the
413      * corresponding policy. Parent domain matching (below) applies only to
414      * sub-domains of the recipient domain.
415      *
416      * XXX UNIX-domain connections query with the pathname as destination.
417      */
418     if (!valid_utf8_hostname(var_smtputf8_enable, site_name, DONT_GRIPE)) {
419 	tls_policy_lookup_one(tls, site_level, site_name, site_class);
420 	return;
421     }
422     do {
423 	tls_policy_lookup_one(tls, site_level, site_name, site_class);
424     } while (*site_level == TLS_LEV_NOTFOUND
425 	     && (site_name = strchr(site_name + 1, '.')) != 0);
426 }
427 
428 /* load_tas - load one or more ta files */
429 
load_tas(TLS_DANE * dane,const char * files)430 static int load_tas(TLS_DANE *dane, const char *files)
431 {
432     int     ret = 0;
433     char   *save = mystrdup(files);
434     char   *buf = save;
435     char   *file;
436 
437     do {
438 	if ((file = mystrtok(&buf, CHARS_COMMA_SP)) != 0)
439 	    ret = tls_dane_load_trustfile(dane, file);
440     } while (file && ret);
441 
442     myfree(save);
443     return (ret);
444 }
445 
446 /* set_cipher_grade - Set cipher grade and exclusions */
447 
set_cipher_grade(SMTP_TLS_POLICY * tls)448 static void set_cipher_grade(SMTP_TLS_POLICY *tls)
449 {
450     const char *mand_exclude = "";
451     const char *also_exclude = "";
452 
453     /*
454      * Use main.cf cipher level if no per-destination value specified. With
455      * mandatory encryption at least encrypt, and with mandatory verification
456      * at least authenticate!
457      */
458     switch (tls->level) {
459     case TLS_LEV_INVALID:
460     case TLS_LEV_NONE:
461 	return;
462 
463     case TLS_LEV_MAY:
464 	if (tls->grade == 0)
465 	    tls->grade = mystrdup(var_smtp_tls_ciph);
466 	break;
467 
468     case TLS_LEV_ENCRYPT:
469 	if (tls->grade == 0)
470 	    tls->grade = mystrdup(var_smtp_tls_mand_ciph);
471 	mand_exclude = var_smtp_tls_mand_excl;
472 	also_exclude = "eNULL";
473 	break;
474 
475     case TLS_LEV_HALF_DANE:
476     case TLS_LEV_DANE:
477     case TLS_LEV_DANE_ONLY:
478     case TLS_LEV_FPRINT:
479     case TLS_LEV_VERIFY:
480     case TLS_LEV_SECURE:
481 	if (tls->grade == 0)
482 	    tls->grade = mystrdup(var_smtp_tls_mand_ciph);
483 	mand_exclude = var_smtp_tls_mand_excl;
484 	also_exclude = "aNULL";
485 	break;
486     }
487 
488 #define ADD_EXCLUDE(vstr, str) \
489     do { \
490 	if (*(str)) \
491 	    vstring_sprintf_append((vstr), "%s%s", \
492 				   VSTRING_LEN(vstr) ? " " : "", (str)); \
493     } while (0)
494 
495     /*
496      * The "exclude" policy table attribute overrides main.cf exclusion
497      * lists.
498      */
499     if (tls->exclusions == 0) {
500 	tls->exclusions = vstring_alloc(10);
501 	ADD_EXCLUDE(tls->exclusions, var_smtp_tls_excl_ciph);
502 	ADD_EXCLUDE(tls->exclusions, mand_exclude);
503     }
504     ADD_EXCLUDE(tls->exclusions, also_exclude);
505 }
506 
507 /* policy_create - create SMTP TLS policy cache object (ctable call-back) */
508 
policy_create(const char * unused_key,void * context)509 static void *policy_create(const char *unused_key, void *context)
510 {
511     SMTP_ITERATOR *iter = (SMTP_ITERATOR *) context;
512     int     site_level;
513     const char *dest = STR(iter->dest);
514     const char *host = STR(iter->host);
515 
516     /*
517      * Prepare a pristine policy object.
518      */
519     SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) mymalloc(sizeof(*tls));
520 
521     smtp_tls_policy_init(tls, dsb_create());
522     tls->conn_reuse = var_smtp_tls_conn_reuse;
523 
524     /*
525      * Compute the per-site TLS enforcement level. For compatibility with the
526      * original TLS patch, this algorithm is gives equal precedence to host
527      * and next-hop policies.
528      */
529     tls->level = global_tls_level();
530     site_level = TLS_LEV_NOTFOUND;
531 
532     if (tls_policy) {
533 	tls_policy_lookup(tls, &site_level, dest, "next-hop destination");
534     } else if (tls_per_site) {
535 	tls_site_lookup(tls, &site_level, dest, "next-hop destination");
536 	if (site_level != TLS_LEV_INVALID
537 	    && strcasecmp_utf8(dest, host) != 0)
538 	    tls_site_lookup(tls, &site_level, host, "server hostname");
539 
540 	/*
541 	 * Override a wild-card per-site policy with a more specific global
542 	 * policy.
543 	 *
544 	 * With the original TLS patch, 1) a per-site ENCRYPT could not override
545 	 * a global VERIFY, and 2) a combined per-site (NONE+MAY) policy
546 	 * produced inconsistent results: it changed a global VERIFY into
547 	 * NONE, while producing MAY with all weaker global policy settings.
548 	 *
549 	 * With the current implementation, a combined per-site (NONE+MAY)
550 	 * consistently overrides global policy with NONE, and global policy
551 	 * can override only a per-site MAY wildcard. That is, specific
552 	 * policies consistently override wildcard policies, and
553 	 * (non-wildcard) per-site policies consistently override global
554 	 * policies.
555 	 */
556 	if (site_level == TLS_LEV_MAY && tls->level > TLS_LEV_MAY)
557 	    site_level = tls->level;
558     }
559     switch (site_level) {
560     default:
561 	tls->level = site_level;
562 	/* FALLTHROUGH */
563     case TLS_LEV_NOTFOUND:
564 	break;
565     case TLS_LEV_INVALID:
566 	tls->level = site_level;
567 	return ((void *) tls);
568     }
569 
570     /*
571      * DANE initialization may change the security level to something else,
572      * so do this early, so that we use the right level below.  Note that
573      * "dane-only" changes to "dane" once we obtain the requisite TLSA
574      * records.
575      */
576     if (TLS_DANE_BASED(tls->level))
577 	dane_init(tls, iter);
578     if (tls->level == TLS_LEV_INVALID)
579 	return ((void *) tls);
580 
581     /*
582      * Use main.cf protocols and SNI settings if not set in per-destination
583      * table.
584      */
585     if (tls->level > TLS_LEV_NONE && tls->protocols == 0)
586 	tls->protocols =
587 	    mystrdup((tls->level == TLS_LEV_MAY) ?
588 		     var_smtp_tls_proto : var_smtp_tls_mand_proto);
589     if (tls->level > TLS_LEV_NONE && tls->sni == 0) {
590 	if (!*var_smtp_tls_sni || valid_hostname(var_smtp_tls_sni, DONT_GRIPE))
591 	    tls->sni = mystrdup(var_smtp_tls_sni);
592 	else {
593 	    msg_warn("\"%s = %s\" specifies an invalid hostname",
594 		     VAR_LMTP_SMTP(TLS_SNI), var_smtp_tls_sni);
595 	    MARK_INVALID(tls->why, &tls->level);
596 	    return ((void *) tls);
597 	}
598     }
599 
600     /*
601      * Compute cipher grade (if set in per-destination table, else
602      * set_cipher() uses main.cf settings) and security level dependent
603      * cipher exclusion list.
604      */
605     set_cipher_grade(tls);
606 
607     /*
608      * Use main.cf cert_match setting if not set in per-destination table.
609      */
610     switch (tls->level) {
611     case TLS_LEV_INVALID:
612     case TLS_LEV_NONE:
613     case TLS_LEV_MAY:
614     case TLS_LEV_ENCRYPT:
615     case TLS_LEV_HALF_DANE:
616     case TLS_LEV_DANE:
617     case TLS_LEV_DANE_ONLY:
618 	break;
619     case TLS_LEV_FPRINT:
620 	if (tls->dane == 0)
621 	    tls->dane = tls_dane_alloc();
622 	if (tls->dane->tlsa == 0) {
623 	    tls_dane_add_fpt_digests(tls->dane, var_smtp_tls_fpt_cmatch,
624 				     CHARS_COMMA_SP, smtp_mode);
625 	    if (tls->dane->tlsa == 0) {
626 		msg_warn("nexthop domain %s: configured at fingerprint "
627 		       "security level, but with no fingerprints to match.",
628 			 dest);
629 		MARK_INVALID(tls->why, &tls->level);
630 		return ((void *) tls);
631 	    }
632 	}
633 	break;
634     case TLS_LEV_VERIFY:
635     case TLS_LEV_SECURE:
636 	if (tls->matchargv == 0)
637 	    tls->matchargv =
638 		argv_split(tls->level == TLS_LEV_VERIFY ?
639 			   var_smtp_tls_vfy_cmatch : var_smtp_tls_sec_cmatch,
640 			   CHARS_COMMA_SP ":");
641 	if (*var_smtp_tls_tafile) {
642 	    if (tls->dane == 0)
643 		tls->dane = tls_dane_alloc();
644 	    if (tls->dane->tlsa == 0
645 		&& !load_tas(tls->dane, var_smtp_tls_tafile)) {
646 		MARK_INVALID(tls->why, &tls->level);
647 		return ((void *) tls);
648 	    }
649 	}
650 	break;
651     default:
652 	msg_panic("unexpected TLS security level: %d", tls->level);
653     }
654 
655     if (msg_verbose && tls->level != global_tls_level())
656 	msg_info("%s TLS level: %s", "effective", policy_name(tls->level));
657 
658     return ((void *) tls);
659 }
660 
661 /* policy_delete - free no longer cached policy (ctable call-back) */
662 
policy_delete(void * item,void * unused_context)663 static void policy_delete(void *item, void *unused_context)
664 {
665     SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) item;
666 
667     if (tls->protocols)
668 	myfree(tls->protocols);
669     if (tls->sni)
670 	myfree(tls->sni);
671     if (tls->grade)
672 	myfree(tls->grade);
673     if (tls->exclusions)
674 	vstring_free(tls->exclusions);
675     if (tls->matchargv)
676 	argv_free(tls->matchargv);
677     if (tls->dane)
678 	tls_dane_free(tls->dane);
679     dsb_free(tls->why);
680 
681     myfree((void *) tls);
682 }
683 
684 /* smtp_tls_policy_cache_query - cached lookup of TLS policy */
685 
smtp_tls_policy_cache_query(DSN_BUF * why,SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter)686 int     smtp_tls_policy_cache_query(DSN_BUF *why, SMTP_TLS_POLICY *tls,
687 				            SMTP_ITERATOR *iter)
688 {
689     VSTRING *key;
690 
691     /*
692      * Create an empty TLS Policy cache on the fly.
693      */
694     if (policy_cache == 0)
695 	policy_cache =
696 	    ctable_create(CACHE_SIZE, policy_create, policy_delete, (void *) 0);
697 
698     /*
699      * Query the TLS Policy cache, with a search key that reflects our shared
700      * values that also appear in other cache and table search keys.
701      */
702     key = vstring_alloc(100);
703     smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_CUR_NEXTHOP
704 		    | SMTP_KEY_FLAG_HOSTNAME
705 		    | SMTP_KEY_FLAG_PORT);
706     ctable_newcontext(policy_cache, (void *) iter);
707     *tls = *(SMTP_TLS_POLICY *) ctable_locate(policy_cache, STR(key));
708     vstring_free(key);
709 
710     /*
711      * Report errors. Both error and non-error results are cached. We must
712      * therefore copy the cached DSN buffer content to the caller's buffer.
713      */
714     if (tls->level == TLS_LEV_INVALID) {
715 	/* XXX Simplify this by implementing a "copy" primitive. */
716 	dsb_update(why,
717 		   STR(tls->why->status), STR(tls->why->action),
718 		   STR(tls->why->mtype), STR(tls->why->mname),
719 		   STR(tls->why->dtype), STR(tls->why->dtext),
720 		   "%s", STR(tls->why->reason));
721 	return (0);
722     } else {
723 	return (1);
724     }
725 }
726 
727 /* smtp_tls_policy_cache_flush - flush TLS policy cache */
728 
smtp_tls_policy_cache_flush(void)729 void    smtp_tls_policy_cache_flush(void)
730 {
731     if (policy_cache != 0) {
732 	ctable_free(policy_cache);
733 	policy_cache = 0;
734     }
735 }
736 
737 /* global_tls_level - parse and cache var_smtp_tls_level */
738 
global_tls_level(void)739 static int global_tls_level(void)
740 {
741     static int l = TLS_LEV_NOTFOUND;
742 
743     if (l != TLS_LEV_NOTFOUND)
744 	return l;
745 
746     /*
747      * Compute the global TLS policy. This is the default policy level when
748      * no per-site policy exists. It also is used to override a wild-card
749      * per-site policy.
750      *
751      * We require that the global level is valid on startup.
752      */
753     if (*var_smtp_tls_level) {
754 	if ((l = tls_level_lookup(var_smtp_tls_level)) == TLS_LEV_INVALID)
755 	    msg_fatal("invalid tls security level: \"%s\"", var_smtp_tls_level);
756     } else if (var_smtp_enforce_tls)
757 	l = var_smtp_tls_enforce_peername ? TLS_LEV_VERIFY : TLS_LEV_ENCRYPT;
758     else
759 	l = var_smtp_use_tls ? TLS_LEV_MAY : TLS_LEV_NONE;
760 
761     if (msg_verbose)
762 	msg_info("%s TLS level: %s", "global", policy_name(l));
763 
764     return l;
765 }
766 
767 #define NONDANE_CONFIG	0		/* Administrator's fault */
768 #define NONDANE_DEST	1		/* Remote server's fault */
769 #define DANE_CANTAUTH	2		/* Remote server's fault */
770 
dane_incompat(SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter,int errtype,const char * fmt,...)771 static void PRINTFLIKE(4, 5) dane_incompat(SMTP_TLS_POLICY *tls,
772 					           SMTP_ITERATOR *iter,
773 					           int errtype,
774 					           const char *fmt,...)
775 {
776     va_list ap;
777 
778     va_start(ap, fmt);
779     if (tls->level == TLS_LEV_DANE) {
780 	tls->level = (errtype == DANE_CANTAUTH) ? TLS_LEV_ENCRYPT : TLS_LEV_MAY;
781 	if (errtype == NONDANE_CONFIG)
782 	    vmsg_warn(fmt, ap);
783 	else if (msg_verbose)
784 	    vmsg_info(fmt, ap);
785     } else {					/* dane-only */
786 	if (errtype == NONDANE_CONFIG) {
787 	    vmsg_warn(fmt, ap);
788 	    MARK_INVALID(tls->why, &tls->level);
789 	} else {
790 	    tls->level = TLS_LEV_INVALID;
791 	    vdsb_simple(tls->why, "4.7.5", fmt, ap);
792 	}
793     }
794     va_end(ap);
795 }
796 
797 /* dane_init - special initialization for "dane" security level */
798 
dane_init(SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter)799 static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter)
800 {
801     TLS_DANE *dane;
802 
803     if (!iter->port) {
804 	msg_warn("%s: the \"dane\" security level is invalid for delivery via"
805 		 " unix-domain sockets", STR(iter->dest));
806 	MARK_INVALID(tls->why, &tls->level);
807 	return;
808     }
809     if (!tls_dane_avail()) {
810 	dane_incompat(tls, iter, NONDANE_CONFIG,
811 		      "%s: %s configured, but no requisite library support",
812 		      STR(iter->dest), policy_name(tls->level));
813 	return;
814     }
815     if (!(smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS)
816 	|| smtp_dns_support != SMTP_DNS_DNSSEC) {
817 	dane_incompat(tls, iter, NONDANE_CONFIG,
818 		      "%s: %s configured with dnssec lookups disabled",
819 		      STR(iter->dest), policy_name(tls->level));
820 	return;
821     }
822 
823     /*
824      * If we ignore MX lookup errors, we also ignore DNSSEC security problems
825      * and thus avoid any reasonable expectation that we get the right DANE
826      * key material.
827      */
828     if (smtp_mode && var_ign_mx_lookup_err) {
829 	dane_incompat(tls, iter, NONDANE_CONFIG,
830 		      "%s: %s configured with MX lookup errors ignored",
831 		      STR(iter->dest), policy_name(tls->level));
832 	return;
833     }
834 
835     /*
836      * This is not optional, code in tls_dane.c assumes that the nexthop
837      * qname is already an fqdn.  If we're using these flags to go from qname
838      * to rname, the assumption is invalid.  Likewise we cannot add the qname
839      * to certificate name checks, ...
840      */
841     if (smtp_dns_res_opt & (RES_DEFNAMES | RES_DNSRCH)) {
842 	dane_incompat(tls, iter, NONDANE_CONFIG,
843 		      "%s: dns resolver options incompatible with %s TLS",
844 		      STR(iter->dest), policy_name(tls->level));
845 	return;
846     }
847 
848     /*
849      * When the MX name is present and insecure, DANE may not apply, we then
850      * either fail if DANE is mandatory or use regular opportunistic TLS if
851      * the insecure MX level is "may".
852      */
853     if (iter->mx && !iter->mx->dnssec_valid
854 	&& (tls->level == TLS_LEV_DANE_ONLY ||
855 	    smtp_tls_insecure_mx_policy <= TLS_LEV_MAY)) {
856 	dane_incompat(tls, iter, NONDANE_DEST, "non DNSSEC destination");
857 	return;
858     }
859     /* When TLSA lookups fail, we defer the message */
860     if ((dane = tls_dane_resolve(iter->port, "tcp", iter->rr,
861 				 var_smtp_tls_force_tlsa)) == 0) {
862 	tls->level = TLS_LEV_INVALID;
863 	dsb_simple(tls->why, "4.7.5", "TLSA lookup error for %s:%u",
864 		   STR(iter->host), ntohs(iter->port));
865 	return;
866     }
867     if (tls_dane_notfound(dane)) {
868 	dane_incompat(tls, iter, NONDANE_DEST, "no TLSA records found");
869 	tls_dane_free(dane);
870 	return;
871     }
872 
873     /*
874      * Some TLSA records found, but none usable, per
875      *
876      * https://tools.ietf.org/html/draft-ietf-dane-srv-02#section-4
877      *
878      * we MUST use TLS, and SHALL use full PKIX certificate checks.  The latter
879      * would be unwise for SMTP: no human present to "click ok" and risk of
880      * non-delivery in most cases exceeds risk of interception.
881      *
882      * We also have a form of Goedel's incompleteness theorem in play: any list
883      * of public root CA certs is either incomplete or inconsistent (for any
884      * given verifier some of the CAs are surely not trustworthy).
885      */
886     if (tls_dane_unusable(dane)) {
887 	dane_incompat(tls, iter, DANE_CANTAUTH, "TLSA records unusable");
888 	tls_dane_free(dane);
889 	return;
890     }
891 
892     /*
893      * Perhaps downgrade to "encrypt" if MX is insecure.
894      */
895     if (iter->mx && !iter->mx->dnssec_valid) {
896 	if (smtp_tls_insecure_mx_policy == TLS_LEV_ENCRYPT) {
897 	    dane_incompat(tls, iter, DANE_CANTAUTH,
898 			  "Verification not possible, MX RRset is insecure");
899 	    tls_dane_free(dane);
900 	    return;
901 	}
902 	if (tls->level != TLS_LEV_DANE
903 	    || smtp_tls_insecure_mx_policy != TLS_LEV_DANE)
904 	    msg_panic("wrong state for insecure MX host DANE policy");
905 
906 	/* For correct logging in tls_client_start() */
907 	tls->level = TLS_LEV_HALF_DANE;
908     }
909 
910     /*
911      * With DANE trust anchors, peername matching is not configurable.
912      */
913     if (dane->tlsa != 0) {
914 	tls->matchargv = argv_alloc(2);
915 	argv_add(tls->matchargv, dane->base_domain, ARGV_END);
916 	if (iter->mx) {
917 	    if (strcmp(iter->mx->qname, iter->mx->rname) == 0)
918 		argv_add(tls->matchargv, iter->mx->qname, ARGV_END);
919 	    else
920 		argv_add(tls->matchargv, iter->mx->rname,
921 			 iter->mx->qname, ARGV_END);
922 	}
923     } else
924 	msg_panic("empty DANE match list");
925     tls->dane = dane;
926     return;
927 }
928 
929 #endif
930