1*fb52cf35Schristos /*	$NetBSD: smtp_tls_policy.c,v 1.4 2022/10/08 16:12:49 christos Exp $	*/
22e5cb688Stron 
32e5cb688Stron /*++
42e5cb688Stron /* NAME
52e5cb688Stron /*	smtp_tls_policy 3
62e5cb688Stron /* SUMMARY
72e5cb688Stron /*	SMTP_TLS_POLICY structure management
82e5cb688Stron /* SYNOPSIS
92e5cb688Stron /*	#include "smtp.h"
102e5cb688Stron /*
112e5cb688Stron /*	void    smtp_tls_list_init()
122e5cb688Stron /*
132e5cb688Stron /*	int	smtp_tls_policy_cache_query(why, tls, iter)
142e5cb688Stron /*	DSN_BUF	*why;
152e5cb688Stron /*	SMTP_TLS_POLICY *tls;
162e5cb688Stron /*	SMTP_ITERATOR *iter;
172e5cb688Stron /*
182e5cb688Stron /*	void	smtp_tls_policy_dummy(tls)
192e5cb688Stron /*	SMTP_TLS_POLICY *tls;
202e5cb688Stron /*
212e5cb688Stron /*	void	smtp_tls_policy_cache_flush()
222e5cb688Stron /* DESCRIPTION
232e5cb688Stron /*	smtp_tls_list_init() initializes lookup tables used by the TLS
242e5cb688Stron /*	policy engine.
252e5cb688Stron /*
262e5cb688Stron /*	smtp_tls_policy_cache_query() returns a shallow copy of the
272e5cb688Stron /*	cached SMTP_TLS_POLICY structure for the iterator's
282e5cb688Stron /*	destination, host, port and DNSSEC validation status.
292e5cb688Stron /*	This copy is guaranteed to be valid until the next
302e5cb688Stron /*	smtp_tls_policy_cache_query() or smtp_tls_policy_cache_flush()
312e5cb688Stron /*	call.  The caller can override the TLS security level without
322e5cb688Stron /*	corrupting the policy cache.
332e5cb688Stron /*	When any required table or DNS lookups fail, the TLS level
342e5cb688Stron /*	is set to TLS_LEV_INVALID, the "why" argument is updated
352e5cb688Stron /*	with the error reason and the result value is zero (false).
362e5cb688Stron /*
372e5cb688Stron /*	smtp_tls_policy_dummy() initializes a trivial, non-cached,
382e5cb688Stron /*	policy with TLS disabled.
392e5cb688Stron /*
402e5cb688Stron /*	smtp_tls_policy_cache_flush() destroys the TLS policy cache
412e5cb688Stron /*	and contents.
422e5cb688Stron /*
432e5cb688Stron /*	Arguments:
442e5cb688Stron /* .IP why
452e5cb688Stron /*	A pointer to a DSN_BUF which holds error status information when
462e5cb688Stron /*	the TLS policy lookup fails.
472e5cb688Stron /* .IP tls
482e5cb688Stron /*	Pointer to TLS policy storage.
492e5cb688Stron /* .IP iter
502e5cb688Stron /*	The literal next-hop or fall-back destination including
512e5cb688Stron /*	the optional [] and including the :port or :service;
522e5cb688Stron /*	the name of the remote host after MX and CNAME expansions
532e5cb688Stron /*	(see smtp_cname_overrides_servername for the handling
542e5cb688Stron /*	of hostnames that resolve to a CNAME record);
552e5cb688Stron /*	the printable address of the remote host;
562e5cb688Stron /*	the remote port in network byte order;
572e5cb688Stron /*	the DNSSEC validation status of the host name lookup after
582e5cb688Stron /*	MX and CNAME expansions.
592e5cb688Stron /* LICENSE
602e5cb688Stron /* .ad
612e5cb688Stron /* .fi
622e5cb688Stron /*	This software is free. You can do with it whatever you want.
632e5cb688Stron /*	The original author kindly requests that you acknowledge
642e5cb688Stron /*	the use of his software.
652e5cb688Stron /* AUTHOR(S)
662e5cb688Stron /*	TLS support originally by:
672e5cb688Stron /*	Lutz Jaenicke
682e5cb688Stron /*	BTU Cottbus
692e5cb688Stron /*	Allgemeine Elektrotechnik
702e5cb688Stron /*	Universitaetsplatz 3-4
712e5cb688Stron /*	D-03044 Cottbus, Germany
722e5cb688Stron /*
732e5cb688Stron /*	Updated by:
742e5cb688Stron /*	Wietse Venema
752e5cb688Stron /*	IBM T.J. Watson Research
762e5cb688Stron /*	P.O. Box 704
772e5cb688Stron /*	Yorktown Heights, NY 10598, USA
782e5cb688Stron /*
793c275423Schristos /*	Wietse Venema
803c275423Schristos /*	Google, Inc.
813c275423Schristos /*	111 8th Avenue
823c275423Schristos /*	New York, NY 10011, USA
833c275423Schristos /*
842e5cb688Stron /*	Viktor Dukhovni
852e5cb688Stron /*--*/
862e5cb688Stron 
872e5cb688Stron /* System library. */
882e5cb688Stron 
892e5cb688Stron #include <sys_defs.h>
902e5cb688Stron 
912e5cb688Stron #ifdef USE_TLS
922e5cb688Stron 
932e5cb688Stron #include <netinet/in.h>			/* ntohs() for Solaris or BSD */
942e5cb688Stron #include <arpa/inet.h>			/* ntohs() for Linux or BSD */
952e5cb688Stron #include <stdlib.h>
962e5cb688Stron #include <string.h>
972e5cb688Stron 
982e5cb688Stron #ifdef STRCASECMP_IN_STRINGS_H
992e5cb688Stron #include <strings.h>
1002e5cb688Stron #endif
1012e5cb688Stron 
1022e5cb688Stron /* Utility library. */
1032e5cb688Stron 
1042e5cb688Stron #include <msg.h>
1052e5cb688Stron #include <mymalloc.h>
1062e5cb688Stron #include <vstring.h>
1072e5cb688Stron #include <stringops.h>
1083c275423Schristos #include <valid_hostname.h>
109837e7c1aSchristos #include <valid_utf8_hostname.h>
1102e5cb688Stron #include <ctable.h>
1112e5cb688Stron 
1122e5cb688Stron /* Global library. */
1132e5cb688Stron 
1142e5cb688Stron #include <mail_params.h>
1152e5cb688Stron #include <maps.h>
1162e5cb688Stron #include <dsn_buf.h>
1172e5cb688Stron 
1182e5cb688Stron /* DNS library. */
1192e5cb688Stron 
1202e5cb688Stron #include <dns.h>
1212e5cb688Stron 
1222e5cb688Stron /* Application-specific. */
1232e5cb688Stron 
1242e5cb688Stron #include "smtp.h"
1252e5cb688Stron 
1262e5cb688Stron /* XXX Cache size should scale with [sl]mtp_mx_address_limit. */
1272e5cb688Stron #define CACHE_SIZE 20
1282e5cb688Stron static CTABLE *policy_cache;
1292e5cb688Stron 
1302e5cb688Stron static int global_tls_level(void);
1312e5cb688Stron static void dane_init(SMTP_TLS_POLICY *, SMTP_ITERATOR *);
1322e5cb688Stron 
1332e5cb688Stron static MAPS *tls_policy;		/* lookup table(s) */
1342e5cb688Stron static MAPS *tls_per_site;		/* lookup table(s) */
1352e5cb688Stron 
1362e5cb688Stron /* smtp_tls_list_init - initialize per-site policy lists */
1372e5cb688Stron 
smtp_tls_list_init(void)1382e5cb688Stron void    smtp_tls_list_init(void)
1392e5cb688Stron {
1402e5cb688Stron     if (*var_smtp_tls_policy) {
141837e7c1aSchristos 	tls_policy = maps_create(VAR_LMTP_SMTP(TLS_POLICY),
142837e7c1aSchristos 				 var_smtp_tls_policy,
143837e7c1aSchristos 				 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
144837e7c1aSchristos 				 | DICT_FLAG_UTF8_REQUEST);
1452e5cb688Stron 	if (*var_smtp_tls_per_site)
1462e5cb688Stron 	    msg_warn("%s ignored when %s is not empty.",
147837e7c1aSchristos 		     VAR_LMTP_SMTP(TLS_PER_SITE), VAR_LMTP_SMTP(TLS_POLICY));
1482e5cb688Stron 	return;
1492e5cb688Stron     }
1502e5cb688Stron     if (*var_smtp_tls_per_site) {
151837e7c1aSchristos 	tls_per_site = maps_create(VAR_LMTP_SMTP(TLS_PER_SITE),
152837e7c1aSchristos 				   var_smtp_tls_per_site,
153837e7c1aSchristos 				   DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
154837e7c1aSchristos 				   | DICT_FLAG_UTF8_REQUEST);
1552e5cb688Stron     }
1562e5cb688Stron }
1572e5cb688Stron 
1582e5cb688Stron /* policy_name - printable tls policy level */
1592e5cb688Stron 
policy_name(int tls_level)1602e5cb688Stron static const char *policy_name(int tls_level)
1612e5cb688Stron {
1622e5cb688Stron     const char *name = str_tls_level(tls_level);
1632e5cb688Stron 
1642e5cb688Stron     if (name == 0)
1652e5cb688Stron 	name = "unknown";
1662e5cb688Stron     return name;
1672e5cb688Stron }
1682e5cb688Stron 
1692e5cb688Stron #define MARK_INVALID(why, levelp) do { \
1702e5cb688Stron 	    dsb_simple((why), "4.7.5", "client TLS configuration problem"); \
1712e5cb688Stron 	    *(levelp) = TLS_LEV_INVALID; } while (0)
1722e5cb688Stron 
1732e5cb688Stron /* tls_site_lookup - look up per-site TLS security level */
1742e5cb688Stron 
tls_site_lookup(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)1752e5cb688Stron static void tls_site_lookup(SMTP_TLS_POLICY *tls, int *site_level,
1762e5cb688Stron 		              const char *site_name, const char *site_class)
1772e5cb688Stron {
1782e5cb688Stron     const char *lookup;
1792e5cb688Stron 
1802e5cb688Stron     /*
1812e5cb688Stron      * Look up a non-default policy. In case of multiple lookup results, the
1822e5cb688Stron      * precedence order is a permutation of the TLS enforcement level order:
1832e5cb688Stron      * VERIFY, ENCRYPT, NONE, MAY, NOTFOUND. I.e. we override MAY with a more
1842e5cb688Stron      * specific policy including NONE, otherwise we choose the stronger
1852e5cb688Stron      * enforcement level.
1862e5cb688Stron      */
1872e5cb688Stron     if ((lookup = maps_find(tls_per_site, site_name, 0)) != 0) {
1882e5cb688Stron 	if (!strcasecmp(lookup, "NONE")) {
1892e5cb688Stron 	    /* NONE overrides MAY or NOTFOUND. */
1902e5cb688Stron 	    if (*site_level <= TLS_LEV_MAY)
1912e5cb688Stron 		*site_level = TLS_LEV_NONE;
1922e5cb688Stron 	} else if (!strcasecmp(lookup, "MAY")) {
1932e5cb688Stron 	    /* MAY overrides NOTFOUND but not NONE. */
1942e5cb688Stron 	    if (*site_level < TLS_LEV_NONE)
1952e5cb688Stron 		*site_level = TLS_LEV_MAY;
1962e5cb688Stron 	} else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) {
1972e5cb688Stron 	    if (*site_level < TLS_LEV_ENCRYPT)
1982e5cb688Stron 		*site_level = TLS_LEV_ENCRYPT;
1992e5cb688Stron 	} else if (!strcasecmp(lookup, "MUST")) {
2002e5cb688Stron 	    if (*site_level < TLS_LEV_VERIFY)
2012e5cb688Stron 		*site_level = TLS_LEV_VERIFY;
2022e5cb688Stron 	} else {
2032e5cb688Stron 	    msg_warn("%s: unknown TLS policy '%s' for %s %s",
2042e5cb688Stron 		     tls_per_site->title, lookup, site_class, site_name);
2052e5cb688Stron 	    MARK_INVALID(tls->why, site_level);
2062e5cb688Stron 	    return;
2072e5cb688Stron 	}
2082e5cb688Stron     } else if (tls_per_site->error) {
2092e5cb688Stron 	msg_warn("%s: %s \"%s\": per-site table lookup error",
2102e5cb688Stron 		 tls_per_site->title, site_class, site_name);
2112e5cb688Stron 	dsb_simple(tls->why, "4.3.0", "Temporary lookup error");
2122e5cb688Stron 	*site_level = TLS_LEV_INVALID;
2132e5cb688Stron 	return;
2142e5cb688Stron     }
2152e5cb688Stron     return;
2162e5cb688Stron }
2172e5cb688Stron 
2182e5cb688Stron /* tls_policy_lookup_one - look up destination TLS policy */
2192e5cb688Stron 
tls_policy_lookup_one(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)2202e5cb688Stron static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
2212e5cb688Stron 				          const char *site_name,
2222e5cb688Stron 				          const char *site_class)
2232e5cb688Stron {
2242e5cb688Stron     const char *lookup;
2252e5cb688Stron     char   *policy;
2262e5cb688Stron     char   *saved_policy;
2272e5cb688Stron     char   *tok;
2282e5cb688Stron     const char *err;
2292e5cb688Stron     char   *name;
2302e5cb688Stron     char   *val;
2312e5cb688Stron     static VSTRING *cbuf;
2322e5cb688Stron 
2332e5cb688Stron #undef FREE_RETURN
2342e5cb688Stron #define FREE_RETURN do { myfree(saved_policy); return; } while (0)
2352e5cb688Stron 
2362e5cb688Stron #define INVALID_RETURN(why, levelp) do { \
2372e5cb688Stron 	    MARK_INVALID((why), (levelp)); FREE_RETURN; } while (0)
2382e5cb688Stron 
2392e5cb688Stron #define WHERE \
2402e5cb688Stron     STR(vstring_sprintf(cbuf, "%s, %s \"%s\"", \
2412e5cb688Stron 		tls_policy->title, site_class, site_name))
2422e5cb688Stron 
2432e5cb688Stron     if (cbuf == 0)
2442e5cb688Stron 	cbuf = vstring_alloc(10);
2452e5cb688Stron 
2462e5cb688Stron     if ((lookup = maps_find(tls_policy, site_name, 0)) == 0) {
2472e5cb688Stron 	if (tls_policy->error) {
2482e5cb688Stron 	    msg_warn("%s: policy table lookup error", WHERE);
2492e5cb688Stron 	    MARK_INVALID(tls->why, site_level);
2502e5cb688Stron 	}
2512e5cb688Stron 	return;
2522e5cb688Stron     }
2532e5cb688Stron     saved_policy = policy = mystrdup(lookup);
2542e5cb688Stron 
255837e7c1aSchristos     if ((tok = mystrtok(&policy, CHARS_COMMA_SP)) == 0) {
2562e5cb688Stron 	msg_warn("%s: invalid empty policy", WHERE);
2572e5cb688Stron 	INVALID_RETURN(tls->why, site_level);
2582e5cb688Stron     }
2592e5cb688Stron     *site_level = tls_level_lookup(tok);
2602e5cb688Stron     if (*site_level == TLS_LEV_INVALID) {
2612e5cb688Stron 	/* tls_level_lookup() logs no warning. */
2622e5cb688Stron 	msg_warn("%s: invalid security level \"%s\"", WHERE, tok);
2632e5cb688Stron 	INVALID_RETURN(tls->why, site_level);
2642e5cb688Stron     }
2652e5cb688Stron 
2662e5cb688Stron     /*
2672e5cb688Stron      * Warn about ignored attributes when TLS is disabled.
2682e5cb688Stron      */
2692e5cb688Stron     if (*site_level < TLS_LEV_MAY) {
270837e7c1aSchristos 	while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0)
2712e5cb688Stron 	    msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
2722e5cb688Stron 		     WHERE, tok);
2732e5cb688Stron 	FREE_RETURN;
2742e5cb688Stron     }
2752e5cb688Stron 
2762e5cb688Stron     /*
2772e5cb688Stron      * Errors in attributes may have security consequences, don't ignore
2782e5cb688Stron      * errors that can degrade security.
2792e5cb688Stron      */
280837e7c1aSchristos     while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0) {
2812e5cb688Stron 	if ((err = split_nameval(tok, &name, &val)) != 0) {
2822e5cb688Stron 	    msg_warn("%s: malformed attribute/value pair \"%s\": %s",
2832e5cb688Stron 		     WHERE, tok, err);
2842e5cb688Stron 	    INVALID_RETURN(tls->why, site_level);
2852e5cb688Stron 	}
2862e5cb688Stron 	/* Only one instance per policy. */
2872e5cb688Stron 	if (!strcasecmp(name, "ciphers")) {
2882e5cb688Stron 	    if (*val == 0) {
2892e5cb688Stron 		msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
2902e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
2912e5cb688Stron 	    }
2922e5cb688Stron 	    if (tls->grade) {
2932e5cb688Stron 		msg_warn("%s: attribute \"%s\" is specified multiple times",
2942e5cb688Stron 			 WHERE, name);
2952e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
2962e5cb688Stron 	    }
2972e5cb688Stron 	    tls->grade = mystrdup(val);
2982e5cb688Stron 	    continue;
2992e5cb688Stron 	}
3002e5cb688Stron 	/* Only one instance per policy. */
3012e5cb688Stron 	if (!strcasecmp(name, "protocols")) {
3022e5cb688Stron 	    if (tls->protocols) {
3032e5cb688Stron 		msg_warn("%s: attribute \"%s\" is specified multiple times",
3042e5cb688Stron 			 WHERE, name);
3052e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
3062e5cb688Stron 	    }
3072e5cb688Stron 	    tls->protocols = mystrdup(val);
3082e5cb688Stron 	    continue;
3092e5cb688Stron 	}
3103c275423Schristos 	/* Only one instance per policy. */
3113c275423Schristos 	if (!strcasecmp(name, "servername")) {
3123c275423Schristos 	    if (tls->sni) {
3133c275423Schristos 		msg_warn("%s: attribute \"%s\" is specified multiple times",
3143c275423Schristos 			 WHERE, name);
3153c275423Schristos 		INVALID_RETURN(tls->why, site_level);
3163c275423Schristos 	    }
3173c275423Schristos 	    if (valid_hostname(val, DONT_GRIPE))
3183c275423Schristos 		tls->sni = mystrdup(val);
3193c275423Schristos 	    else {
3203c275423Schristos 		msg_warn("%s: \"%s=%s\" specifies an invalid hostname",
3213c275423Schristos 			 WHERE, name, val);
3223c275423Schristos 		INVALID_RETURN(tls->why, site_level);
3233c275423Schristos 	    }
3243c275423Schristos 	    continue;
3253c275423Schristos 	}
3262e5cb688Stron 	/* Multiple instances per policy. */
3272e5cb688Stron 	if (!strcasecmp(name, "match")) {
3282e5cb688Stron 	    if (*val == 0) {
3292e5cb688Stron 		msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
3302e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
3312e5cb688Stron 	    }
3322e5cb688Stron 	    switch (*site_level) {
3332e5cb688Stron 	    default:
3342e5cb688Stron 		msg_warn("%s: attribute \"%s\" invalid at security level "
3352e5cb688Stron 			 "\"%s\"", WHERE, name, policy_name(*site_level));
3362e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
3372e5cb688Stron 		break;
3382e5cb688Stron 	    case TLS_LEV_FPRINT:
3392e5cb688Stron 		if (!tls->dane)
3402e5cb688Stron 		    tls->dane = tls_dane_alloc();
341*fb52cf35Schristos 		tls_dane_add_fpt_digests(tls->dane, val, "|", smtp_mode);
3422e5cb688Stron 		break;
3432e5cb688Stron 	    case TLS_LEV_VERIFY:
3442e5cb688Stron 	    case TLS_LEV_SECURE:
3452e5cb688Stron 		if (tls->matchargv == 0)
3462e5cb688Stron 		    tls->matchargv = argv_split(val, ":");
3472e5cb688Stron 		else
3482e5cb688Stron 		    argv_split_append(tls->matchargv, val, ":");
3492e5cb688Stron 		break;
3502e5cb688Stron 	    }
3512e5cb688Stron 	    continue;
3522e5cb688Stron 	}
3532e5cb688Stron 	/* Only one instance per policy. */
3542e5cb688Stron 	if (!strcasecmp(name, "exclude")) {
3552e5cb688Stron 	    if (tls->exclusions) {
3562e5cb688Stron 		msg_warn("%s: attribute \"%s\" is specified multiple times",
3572e5cb688Stron 			 WHERE, name);
3582e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
3592e5cb688Stron 	    }
3602e5cb688Stron 	    tls->exclusions = vstring_strcpy(vstring_alloc(10), val);
3612e5cb688Stron 	    continue;
3622e5cb688Stron 	}
3632e5cb688Stron 	/* Multiple instances per policy. */
3642e5cb688Stron 	if (!strcasecmp(name, "tafile")) {
3652e5cb688Stron 	    /* Only makes sense if we're using CA-based trust */
3662e5cb688Stron 	    if (!TLS_MUST_PKIX(*site_level)) {
3672e5cb688Stron 		msg_warn("%s: attribute \"%s\" invalid at security level"
3682e5cb688Stron 			 " \"%s\"", WHERE, name, policy_name(*site_level));
3692e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
3702e5cb688Stron 	    }
3712e5cb688Stron 	    if (*val == 0) {
3722e5cb688Stron 		msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
3732e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
3742e5cb688Stron 	    }
3752e5cb688Stron 	    if (!tls->dane)
3762e5cb688Stron 		tls->dane = tls_dane_alloc();
3772e5cb688Stron 	    if (!tls_dane_load_trustfile(tls->dane, val)) {
3782e5cb688Stron 		INVALID_RETURN(tls->why, site_level);
3792e5cb688Stron 	    }
3802e5cb688Stron 	    continue;
3812e5cb688Stron 	}
3823c275423Schristos 	/* Last one wins. */
3833c275423Schristos 	if (!strcasecmp(name, "connection_reuse")) {
3843c275423Schristos 	    if (strcasecmp(val, "yes") == 0) {
3853c275423Schristos 		tls->conn_reuse = 1;
3863c275423Schristos 	    } else if (strcasecmp(val, "no") == 0) {
3873c275423Schristos 		tls->conn_reuse = 0;
3883c275423Schristos 	    } else {
3893c275423Schristos 		msg_warn("%s: attribute \"%s\" has bad value: \"%s\"",
3903c275423Schristos 			 WHERE, name, val);
3913c275423Schristos 		INVALID_RETURN(tls->why, site_level);
3923c275423Schristos 	    }
393*fb52cf35Schristos 	    continue;
3943c275423Schristos 	}
3952e5cb688Stron 	msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
3962e5cb688Stron 	INVALID_RETURN(tls->why, site_level);
3972e5cb688Stron     }
3982e5cb688Stron 
3992e5cb688Stron     FREE_RETURN;
4002e5cb688Stron }
4012e5cb688Stron 
4022e5cb688Stron /* tls_policy_lookup - look up destination TLS policy */
4032e5cb688Stron 
tls_policy_lookup(SMTP_TLS_POLICY * tls,int * site_level,const char * site_name,const char * site_class)4042e5cb688Stron static void tls_policy_lookup(SMTP_TLS_POLICY *tls, int *site_level,
4052e5cb688Stron 			              const char *site_name,
4062e5cb688Stron 			              const char *site_class)
4072e5cb688Stron {
4082e5cb688Stron 
4092e5cb688Stron     /*
4102e5cb688Stron      * Only one lookup with [nexthop]:port, [nexthop] or nexthop:port These
4112e5cb688Stron      * are never the domain part of localpart@domain, rather they are
4122e5cb688Stron      * explicit nexthops from transport:nexthop, and match only the
4132e5cb688Stron      * corresponding policy. Parent domain matching (below) applies only to
4142e5cb688Stron      * sub-domains of the recipient domain.
4152e5cb688Stron      *
4162e5cb688Stron      * XXX UNIX-domain connections query with the pathname as destination.
4172e5cb688Stron      */
418837e7c1aSchristos     if (!valid_utf8_hostname(var_smtputf8_enable, site_name, DONT_GRIPE)) {
4192e5cb688Stron 	tls_policy_lookup_one(tls, site_level, site_name, site_class);
4202e5cb688Stron 	return;
4212e5cb688Stron     }
4222e5cb688Stron     do {
4232e5cb688Stron 	tls_policy_lookup_one(tls, site_level, site_name, site_class);
4242e5cb688Stron     } while (*site_level == TLS_LEV_NOTFOUND
4252e5cb688Stron 	     && (site_name = strchr(site_name + 1, '.')) != 0);
4262e5cb688Stron }
4272e5cb688Stron 
4282e5cb688Stron /* load_tas - load one or more ta files */
4292e5cb688Stron 
load_tas(TLS_DANE * dane,const char * files)4302e5cb688Stron static int load_tas(TLS_DANE *dane, const char *files)
4312e5cb688Stron {
4322e5cb688Stron     int     ret = 0;
4332e5cb688Stron     char   *save = mystrdup(files);
4342e5cb688Stron     char   *buf = save;
4352e5cb688Stron     char   *file;
4362e5cb688Stron 
4372e5cb688Stron     do {
438837e7c1aSchristos 	if ((file = mystrtok(&buf, CHARS_COMMA_SP)) != 0)
4392e5cb688Stron 	    ret = tls_dane_load_trustfile(dane, file);
4402e5cb688Stron     } while (file && ret);
4412e5cb688Stron 
4422e5cb688Stron     myfree(save);
4432e5cb688Stron     return (ret);
4442e5cb688Stron }
4452e5cb688Stron 
4462e5cb688Stron /* set_cipher_grade - Set cipher grade and exclusions */
4472e5cb688Stron 
set_cipher_grade(SMTP_TLS_POLICY * tls)4482e5cb688Stron static void set_cipher_grade(SMTP_TLS_POLICY *tls)
4492e5cb688Stron {
4502e5cb688Stron     const char *mand_exclude = "";
4512e5cb688Stron     const char *also_exclude = "";
4522e5cb688Stron 
4532e5cb688Stron     /*
4542e5cb688Stron      * Use main.cf cipher level if no per-destination value specified. With
4552e5cb688Stron      * mandatory encryption at least encrypt, and with mandatory verification
4562e5cb688Stron      * at least authenticate!
4572e5cb688Stron      */
4582e5cb688Stron     switch (tls->level) {
4592e5cb688Stron     case TLS_LEV_INVALID:
4602e5cb688Stron     case TLS_LEV_NONE:
4612e5cb688Stron 	return;
4622e5cb688Stron 
4632e5cb688Stron     case TLS_LEV_MAY:
4642e5cb688Stron 	if (tls->grade == 0)
4652e5cb688Stron 	    tls->grade = mystrdup(var_smtp_tls_ciph);
4662e5cb688Stron 	break;
4672e5cb688Stron 
4682e5cb688Stron     case TLS_LEV_ENCRYPT:
4692e5cb688Stron 	if (tls->grade == 0)
4702e5cb688Stron 	    tls->grade = mystrdup(var_smtp_tls_mand_ciph);
4712e5cb688Stron 	mand_exclude = var_smtp_tls_mand_excl;
4722e5cb688Stron 	also_exclude = "eNULL";
4732e5cb688Stron 	break;
4742e5cb688Stron 
475837e7c1aSchristos     case TLS_LEV_HALF_DANE:
4762e5cb688Stron     case TLS_LEV_DANE:
477837e7c1aSchristos     case TLS_LEV_DANE_ONLY:
4782e5cb688Stron     case TLS_LEV_FPRINT:
4792e5cb688Stron     case TLS_LEV_VERIFY:
4802e5cb688Stron     case TLS_LEV_SECURE:
4812e5cb688Stron 	if (tls->grade == 0)
4822e5cb688Stron 	    tls->grade = mystrdup(var_smtp_tls_mand_ciph);
4832e5cb688Stron 	mand_exclude = var_smtp_tls_mand_excl;
4842e5cb688Stron 	also_exclude = "aNULL";
4852e5cb688Stron 	break;
4862e5cb688Stron     }
4872e5cb688Stron 
4882e5cb688Stron #define ADD_EXCLUDE(vstr, str) \
4892e5cb688Stron     do { \
4902e5cb688Stron 	if (*(str)) \
4912e5cb688Stron 	    vstring_sprintf_append((vstr), "%s%s", \
4922e5cb688Stron 				   VSTRING_LEN(vstr) ? " " : "", (str)); \
4932e5cb688Stron     } while (0)
4942e5cb688Stron 
4952e5cb688Stron     /*
4962e5cb688Stron      * The "exclude" policy table attribute overrides main.cf exclusion
4972e5cb688Stron      * lists.
4982e5cb688Stron      */
4992e5cb688Stron     if (tls->exclusions == 0) {
5002e5cb688Stron 	tls->exclusions = vstring_alloc(10);
5012e5cb688Stron 	ADD_EXCLUDE(tls->exclusions, var_smtp_tls_excl_ciph);
5022e5cb688Stron 	ADD_EXCLUDE(tls->exclusions, mand_exclude);
5032e5cb688Stron     }
5042e5cb688Stron     ADD_EXCLUDE(tls->exclusions, also_exclude);
5052e5cb688Stron }
5062e5cb688Stron 
5072e5cb688Stron /* policy_create - create SMTP TLS policy cache object (ctable call-back) */
5082e5cb688Stron 
policy_create(const char * unused_key,void * context)5092e5cb688Stron static void *policy_create(const char *unused_key, void *context)
5102e5cb688Stron {
5112e5cb688Stron     SMTP_ITERATOR *iter = (SMTP_ITERATOR *) context;
5122e5cb688Stron     int     site_level;
5132e5cb688Stron     const char *dest = STR(iter->dest);
5142e5cb688Stron     const char *host = STR(iter->host);
5152e5cb688Stron 
5162e5cb688Stron     /*
5172e5cb688Stron      * Prepare a pristine policy object.
5182e5cb688Stron      */
5192e5cb688Stron     SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) mymalloc(sizeof(*tls));
5202e5cb688Stron 
5212e5cb688Stron     smtp_tls_policy_init(tls, dsb_create());
5223c275423Schristos     tls->conn_reuse = var_smtp_tls_conn_reuse;
5232e5cb688Stron 
5242e5cb688Stron     /*
5252e5cb688Stron      * Compute the per-site TLS enforcement level. For compatibility with the
5262e5cb688Stron      * original TLS patch, this algorithm is gives equal precedence to host
5272e5cb688Stron      * and next-hop policies.
5282e5cb688Stron      */
5292e5cb688Stron     tls->level = global_tls_level();
5302e5cb688Stron     site_level = TLS_LEV_NOTFOUND;
5312e5cb688Stron 
5322e5cb688Stron     if (tls_policy) {
5332e5cb688Stron 	tls_policy_lookup(tls, &site_level, dest, "next-hop destination");
5342e5cb688Stron     } else if (tls_per_site) {
5352e5cb688Stron 	tls_site_lookup(tls, &site_level, dest, "next-hop destination");
5362e5cb688Stron 	if (site_level != TLS_LEV_INVALID
537837e7c1aSchristos 	    && strcasecmp_utf8(dest, host) != 0)
5382e5cb688Stron 	    tls_site_lookup(tls, &site_level, host, "server hostname");
5392e5cb688Stron 
5402e5cb688Stron 	/*
5412e5cb688Stron 	 * Override a wild-card per-site policy with a more specific global
5422e5cb688Stron 	 * policy.
5432e5cb688Stron 	 *
5442e5cb688Stron 	 * With the original TLS patch, 1) a per-site ENCRYPT could not override
5452e5cb688Stron 	 * a global VERIFY, and 2) a combined per-site (NONE+MAY) policy
5462e5cb688Stron 	 * produced inconsistent results: it changed a global VERIFY into
5472e5cb688Stron 	 * NONE, while producing MAY with all weaker global policy settings.
5482e5cb688Stron 	 *
5492e5cb688Stron 	 * With the current implementation, a combined per-site (NONE+MAY)
5502e5cb688Stron 	 * consistently overrides global policy with NONE, and global policy
5512e5cb688Stron 	 * can override only a per-site MAY wildcard. That is, specific
5522e5cb688Stron 	 * policies consistently override wildcard policies, and
5532e5cb688Stron 	 * (non-wildcard) per-site policies consistently override global
5542e5cb688Stron 	 * policies.
5552e5cb688Stron 	 */
5562e5cb688Stron 	if (site_level == TLS_LEV_MAY && tls->level > TLS_LEV_MAY)
5572e5cb688Stron 	    site_level = tls->level;
5582e5cb688Stron     }
5592e5cb688Stron     switch (site_level) {
5602e5cb688Stron     default:
5612e5cb688Stron 	tls->level = site_level;
56241c0b7abStron 	/* FALLTHROUGH */
5632e5cb688Stron     case TLS_LEV_NOTFOUND:
5642e5cb688Stron 	break;
5652e5cb688Stron     case TLS_LEV_INVALID:
56641c0b7abStron 	tls->level = site_level;
5672e5cb688Stron 	return ((void *) tls);
5682e5cb688Stron     }
5692e5cb688Stron 
5702e5cb688Stron     /*
5712e5cb688Stron      * DANE initialization may change the security level to something else,
5722e5cb688Stron      * so do this early, so that we use the right level below.  Note that
5732e5cb688Stron      * "dane-only" changes to "dane" once we obtain the requisite TLSA
5742e5cb688Stron      * records.
5752e5cb688Stron      */
576837e7c1aSchristos     if (TLS_DANE_BASED(tls->level))
5772e5cb688Stron 	dane_init(tls, iter);
5782e5cb688Stron     if (tls->level == TLS_LEV_INVALID)
5792e5cb688Stron 	return ((void *) tls);
5802e5cb688Stron 
5812e5cb688Stron     /*
5823c275423Schristos      * Use main.cf protocols and SNI settings if not set in per-destination
5833c275423Schristos      * table.
5842e5cb688Stron      */
5852e5cb688Stron     if (tls->level > TLS_LEV_NONE && tls->protocols == 0)
5862e5cb688Stron 	tls->protocols =
5872e5cb688Stron 	    mystrdup((tls->level == TLS_LEV_MAY) ?
5882e5cb688Stron 		     var_smtp_tls_proto : var_smtp_tls_mand_proto);
5893c275423Schristos     if (tls->level > TLS_LEV_NONE && tls->sni == 0) {
5903c275423Schristos 	if (!*var_smtp_tls_sni || valid_hostname(var_smtp_tls_sni, DONT_GRIPE))
5913c275423Schristos 	    tls->sni = mystrdup(var_smtp_tls_sni);
5923c275423Schristos 	else {
5933c275423Schristos 	    msg_warn("\"%s = %s\" specifies an invalid hostname",
5943c275423Schristos 		     VAR_LMTP_SMTP(TLS_SNI), var_smtp_tls_sni);
5953c275423Schristos 	    MARK_INVALID(tls->why, &tls->level);
5963c275423Schristos 	    return ((void *) tls);
5973c275423Schristos 	}
5983c275423Schristos     }
5992e5cb688Stron 
6002e5cb688Stron     /*
6012e5cb688Stron      * Compute cipher grade (if set in per-destination table, else
6022e5cb688Stron      * set_cipher() uses main.cf settings) and security level dependent
6032e5cb688Stron      * cipher exclusion list.
6042e5cb688Stron      */
6052e5cb688Stron     set_cipher_grade(tls);
6062e5cb688Stron 
6072e5cb688Stron     /*
6082e5cb688Stron      * Use main.cf cert_match setting if not set in per-destination table.
6092e5cb688Stron      */
6102e5cb688Stron     switch (tls->level) {
6112e5cb688Stron     case TLS_LEV_INVALID:
6122e5cb688Stron     case TLS_LEV_NONE:
6132e5cb688Stron     case TLS_LEV_MAY:
6142e5cb688Stron     case TLS_LEV_ENCRYPT:
615837e7c1aSchristos     case TLS_LEV_HALF_DANE:
6162e5cb688Stron     case TLS_LEV_DANE:
617837e7c1aSchristos     case TLS_LEV_DANE_ONLY:
6182e5cb688Stron 	break;
6192e5cb688Stron     case TLS_LEV_FPRINT:
6202e5cb688Stron 	if (tls->dane == 0)
6212e5cb688Stron 	    tls->dane = tls_dane_alloc();
622*fb52cf35Schristos 	if (tls->dane->tlsa == 0) {
623*fb52cf35Schristos 	    tls_dane_add_fpt_digests(tls->dane, var_smtp_tls_fpt_cmatch,
624*fb52cf35Schristos 				     CHARS_COMMA_SP, smtp_mode);
625*fb52cf35Schristos 	    if (tls->dane->tlsa == 0) {
6262e5cb688Stron 		msg_warn("nexthop domain %s: configured at fingerprint "
6272e5cb688Stron 		       "security level, but with no fingerprints to match.",
6282e5cb688Stron 			 dest);
6292e5cb688Stron 		MARK_INVALID(tls->why, &tls->level);
6302e5cb688Stron 		return ((void *) tls);
6312e5cb688Stron 	    }
6322e5cb688Stron 	}
6332e5cb688Stron 	break;
6342e5cb688Stron     case TLS_LEV_VERIFY:
6352e5cb688Stron     case TLS_LEV_SECURE:
6362e5cb688Stron 	if (tls->matchargv == 0)
6372e5cb688Stron 	    tls->matchargv =
6382e5cb688Stron 		argv_split(tls->level == TLS_LEV_VERIFY ?
6392e5cb688Stron 			   var_smtp_tls_vfy_cmatch : var_smtp_tls_sec_cmatch,
640837e7c1aSchristos 			   CHARS_COMMA_SP ":");
6412e5cb688Stron 	if (*var_smtp_tls_tafile) {
6422e5cb688Stron 	    if (tls->dane == 0)
6432e5cb688Stron 		tls->dane = tls_dane_alloc();
644*fb52cf35Schristos 	    if (tls->dane->tlsa == 0
6452e5cb688Stron 		&& !load_tas(tls->dane, var_smtp_tls_tafile)) {
6462e5cb688Stron 		MARK_INVALID(tls->why, &tls->level);
6472e5cb688Stron 		return ((void *) tls);
6482e5cb688Stron 	    }
6492e5cb688Stron 	}
6502e5cb688Stron 	break;
6512e5cb688Stron     default:
6522e5cb688Stron 	msg_panic("unexpected TLS security level: %d", tls->level);
6532e5cb688Stron     }
6542e5cb688Stron 
6552e5cb688Stron     if (msg_verbose && tls->level != global_tls_level())
6562e5cb688Stron 	msg_info("%s TLS level: %s", "effective", policy_name(tls->level));
6572e5cb688Stron 
6582e5cb688Stron     return ((void *) tls);
6592e5cb688Stron }
6602e5cb688Stron 
6612e5cb688Stron /* policy_delete - free no longer cached policy (ctable call-back) */
6622e5cb688Stron 
policy_delete(void * item,void * unused_context)6632e5cb688Stron static void policy_delete(void *item, void *unused_context)
6642e5cb688Stron {
6652e5cb688Stron     SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) item;
6662e5cb688Stron 
6672e5cb688Stron     if (tls->protocols)
6682e5cb688Stron 	myfree(tls->protocols);
6693c275423Schristos     if (tls->sni)
6703c275423Schristos 	myfree(tls->sni);
6712e5cb688Stron     if (tls->grade)
6722e5cb688Stron 	myfree(tls->grade);
6732e5cb688Stron     if (tls->exclusions)
6742e5cb688Stron 	vstring_free(tls->exclusions);
6752e5cb688Stron     if (tls->matchargv)
6762e5cb688Stron 	argv_free(tls->matchargv);
6772e5cb688Stron     if (tls->dane)
6782e5cb688Stron 	tls_dane_free(tls->dane);
6792e5cb688Stron     dsb_free(tls->why);
6802e5cb688Stron 
681837e7c1aSchristos     myfree((void *) tls);
6822e5cb688Stron }
6832e5cb688Stron 
6842e5cb688Stron /* smtp_tls_policy_cache_query - cached lookup of TLS policy */
6852e5cb688Stron 
smtp_tls_policy_cache_query(DSN_BUF * why,SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter)6862e5cb688Stron int     smtp_tls_policy_cache_query(DSN_BUF *why, SMTP_TLS_POLICY *tls,
6872e5cb688Stron 				            SMTP_ITERATOR *iter)
6882e5cb688Stron {
6892e5cb688Stron     VSTRING *key;
6902e5cb688Stron 
6912e5cb688Stron     /*
6922e5cb688Stron      * Create an empty TLS Policy cache on the fly.
6932e5cb688Stron      */
6942e5cb688Stron     if (policy_cache == 0)
6952e5cb688Stron 	policy_cache =
6962e5cb688Stron 	    ctable_create(CACHE_SIZE, policy_create, policy_delete, (void *) 0);
6972e5cb688Stron 
6982e5cb688Stron     /*
6992e5cb688Stron      * Query the TLS Policy cache, with a search key that reflects our shared
7002e5cb688Stron      * values that also appear in other cache and table search keys.
7012e5cb688Stron      */
7022e5cb688Stron     key = vstring_alloc(100);
7033c275423Schristos     smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_CUR_NEXTHOP
7042e5cb688Stron 		    | SMTP_KEY_FLAG_HOSTNAME
7052e5cb688Stron 		    | SMTP_KEY_FLAG_PORT);
7062e5cb688Stron     ctable_newcontext(policy_cache, (void *) iter);
7072e5cb688Stron     *tls = *(SMTP_TLS_POLICY *) ctable_locate(policy_cache, STR(key));
7082e5cb688Stron     vstring_free(key);
7092e5cb688Stron 
7102e5cb688Stron     /*
7112e5cb688Stron      * Report errors. Both error and non-error results are cached. We must
7122e5cb688Stron      * therefore copy the cached DSN buffer content to the caller's buffer.
7132e5cb688Stron      */
7142e5cb688Stron     if (tls->level == TLS_LEV_INVALID) {
7152e5cb688Stron 	/* XXX Simplify this by implementing a "copy" primitive. */
7162e5cb688Stron 	dsb_update(why,
7172e5cb688Stron 		   STR(tls->why->status), STR(tls->why->action),
7182e5cb688Stron 		   STR(tls->why->mtype), STR(tls->why->mname),
7192e5cb688Stron 		   STR(tls->why->dtype), STR(tls->why->dtext),
7202e5cb688Stron 		   "%s", STR(tls->why->reason));
7212e5cb688Stron 	return (0);
7222e5cb688Stron     } else {
7232e5cb688Stron 	return (1);
7242e5cb688Stron     }
7252e5cb688Stron }
7262e5cb688Stron 
7272e5cb688Stron /* smtp_tls_policy_cache_flush - flush TLS policy cache */
7282e5cb688Stron 
smtp_tls_policy_cache_flush(void)7292e5cb688Stron void    smtp_tls_policy_cache_flush(void)
7302e5cb688Stron {
7312e5cb688Stron     if (policy_cache != 0) {
7322e5cb688Stron 	ctable_free(policy_cache);
7332e5cb688Stron 	policy_cache = 0;
7342e5cb688Stron     }
7352e5cb688Stron }
7362e5cb688Stron 
7372e5cb688Stron /* global_tls_level - parse and cache var_smtp_tls_level */
7382e5cb688Stron 
global_tls_level(void)7392e5cb688Stron static int global_tls_level(void)
7402e5cb688Stron {
7412e5cb688Stron     static int l = TLS_LEV_NOTFOUND;
7422e5cb688Stron 
7432e5cb688Stron     if (l != TLS_LEV_NOTFOUND)
7442e5cb688Stron 	return l;
7452e5cb688Stron 
7462e5cb688Stron     /*
7472e5cb688Stron      * Compute the global TLS policy. This is the default policy level when
7482e5cb688Stron      * no per-site policy exists. It also is used to override a wild-card
7492e5cb688Stron      * per-site policy.
7502e5cb688Stron      *
7512e5cb688Stron      * We require that the global level is valid on startup.
7522e5cb688Stron      */
7532e5cb688Stron     if (*var_smtp_tls_level) {
7542e5cb688Stron 	if ((l = tls_level_lookup(var_smtp_tls_level)) == TLS_LEV_INVALID)
7552e5cb688Stron 	    msg_fatal("invalid tls security level: \"%s\"", var_smtp_tls_level);
7562e5cb688Stron     } else if (var_smtp_enforce_tls)
7572e5cb688Stron 	l = var_smtp_tls_enforce_peername ? TLS_LEV_VERIFY : TLS_LEV_ENCRYPT;
7582e5cb688Stron     else
7592e5cb688Stron 	l = var_smtp_use_tls ? TLS_LEV_MAY : TLS_LEV_NONE;
7602e5cb688Stron 
7612e5cb688Stron     if (msg_verbose)
7622e5cb688Stron 	msg_info("%s TLS level: %s", "global", policy_name(l));
7632e5cb688Stron 
7642e5cb688Stron     return l;
7652e5cb688Stron }
7662e5cb688Stron 
7672e5cb688Stron #define NONDANE_CONFIG	0		/* Administrator's fault */
7682e5cb688Stron #define NONDANE_DEST	1		/* Remote server's fault */
769837e7c1aSchristos #define DANE_CANTAUTH	2		/* Remote server's fault */
7702e5cb688Stron 
dane_incompat(SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter,int errtype,const char * fmt,...)7712e5cb688Stron static void PRINTFLIKE(4, 5) dane_incompat(SMTP_TLS_POLICY *tls,
7722e5cb688Stron 					           SMTP_ITERATOR *iter,
7732e5cb688Stron 					           int errtype,
7742e5cb688Stron 					           const char *fmt,...)
7752e5cb688Stron {
7762e5cb688Stron     va_list ap;
7772e5cb688Stron 
7782e5cb688Stron     va_start(ap, fmt);
7792e5cb688Stron     if (tls->level == TLS_LEV_DANE) {
780837e7c1aSchristos 	tls->level = (errtype == DANE_CANTAUTH) ? TLS_LEV_ENCRYPT : TLS_LEV_MAY;
7812e5cb688Stron 	if (errtype == NONDANE_CONFIG)
7822e5cb688Stron 	    vmsg_warn(fmt, ap);
7832e5cb688Stron 	else if (msg_verbose)
7842e5cb688Stron 	    vmsg_info(fmt, ap);
7852e5cb688Stron     } else {					/* dane-only */
7862e5cb688Stron 	if (errtype == NONDANE_CONFIG) {
7872e5cb688Stron 	    vmsg_warn(fmt, ap);
7882e5cb688Stron 	    MARK_INVALID(tls->why, &tls->level);
7892e5cb688Stron 	} else {
7902e5cb688Stron 	    tls->level = TLS_LEV_INVALID;
7912e5cb688Stron 	    vdsb_simple(tls->why, "4.7.5", fmt, ap);
7922e5cb688Stron 	}
7932e5cb688Stron     }
7942e5cb688Stron     va_end(ap);
7952e5cb688Stron }
7962e5cb688Stron 
7972e5cb688Stron /* dane_init - special initialization for "dane" security level */
7982e5cb688Stron 
dane_init(SMTP_TLS_POLICY * tls,SMTP_ITERATOR * iter)7992e5cb688Stron static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter)
8002e5cb688Stron {
8012e5cb688Stron     TLS_DANE *dane;
8022e5cb688Stron 
8032e5cb688Stron     if (!iter->port) {
8042e5cb688Stron 	msg_warn("%s: the \"dane\" security level is invalid for delivery via"
8052e5cb688Stron 		 " unix-domain sockets", STR(iter->dest));
8062e5cb688Stron 	MARK_INVALID(tls->why, &tls->level);
8072e5cb688Stron 	return;
8082e5cb688Stron     }
8092e5cb688Stron     if (!tls_dane_avail()) {
8102e5cb688Stron 	dane_incompat(tls, iter, NONDANE_CONFIG,
8112e5cb688Stron 		      "%s: %s configured, but no requisite library support",
8122e5cb688Stron 		      STR(iter->dest), policy_name(tls->level));
8132e5cb688Stron 	return;
8142e5cb688Stron     }
8152e5cb688Stron     if (!(smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS)
8162e5cb688Stron 	|| smtp_dns_support != SMTP_DNS_DNSSEC) {
8172e5cb688Stron 	dane_incompat(tls, iter, NONDANE_CONFIG,
8182e5cb688Stron 		      "%s: %s configured with dnssec lookups disabled",
8192e5cb688Stron 		      STR(iter->dest), policy_name(tls->level));
8202e5cb688Stron 	return;
8212e5cb688Stron     }
8222e5cb688Stron 
8232e5cb688Stron     /*
8242e5cb688Stron      * If we ignore MX lookup errors, we also ignore DNSSEC security problems
8252e5cb688Stron      * and thus avoid any reasonable expectation that we get the right DANE
8262e5cb688Stron      * key material.
8272e5cb688Stron      */
8282e5cb688Stron     if (smtp_mode && var_ign_mx_lookup_err) {
8292e5cb688Stron 	dane_incompat(tls, iter, NONDANE_CONFIG,
8302e5cb688Stron 		      "%s: %s configured with MX lookup errors ignored",
8312e5cb688Stron 		      STR(iter->dest), policy_name(tls->level));
8322e5cb688Stron 	return;
8332e5cb688Stron     }
8342e5cb688Stron 
8352e5cb688Stron     /*
8362e5cb688Stron      * This is not optional, code in tls_dane.c assumes that the nexthop
8372e5cb688Stron      * qname is already an fqdn.  If we're using these flags to go from qname
8382e5cb688Stron      * to rname, the assumption is invalid.  Likewise we cannot add the qname
8392e5cb688Stron      * to certificate name checks, ...
8402e5cb688Stron      */
8412e5cb688Stron     if (smtp_dns_res_opt & (RES_DEFNAMES | RES_DNSRCH)) {
8422e5cb688Stron 	dane_incompat(tls, iter, NONDANE_CONFIG,
8432e5cb688Stron 		      "%s: dns resolver options incompatible with %s TLS",
8442e5cb688Stron 		      STR(iter->dest), policy_name(tls->level));
8452e5cb688Stron 	return;
8462e5cb688Stron     }
847837e7c1aSchristos 
848837e7c1aSchristos     /*
849837e7c1aSchristos      * When the MX name is present and insecure, DANE may not apply, we then
850837e7c1aSchristos      * either fail if DANE is mandatory or use regular opportunistic TLS if
851837e7c1aSchristos      * the insecure MX level is "may".
852837e7c1aSchristos      */
853837e7c1aSchristos     if (iter->mx && !iter->mx->dnssec_valid
854837e7c1aSchristos 	&& (tls->level == TLS_LEV_DANE_ONLY ||
855837e7c1aSchristos 	    smtp_tls_insecure_mx_policy <= TLS_LEV_MAY)) {
8562e5cb688Stron 	dane_incompat(tls, iter, NONDANE_DEST, "non DNSSEC destination");
8572e5cb688Stron 	return;
8582e5cb688Stron     }
8592e5cb688Stron     /* When TLSA lookups fail, we defer the message */
8602e5cb688Stron     if ((dane = tls_dane_resolve(iter->port, "tcp", iter->rr,
8612e5cb688Stron 				 var_smtp_tls_force_tlsa)) == 0) {
8622e5cb688Stron 	tls->level = TLS_LEV_INVALID;
8632e5cb688Stron 	dsb_simple(tls->why, "4.7.5", "TLSA lookup error for %s:%u",
8642e5cb688Stron 		   STR(iter->host), ntohs(iter->port));
8652e5cb688Stron 	return;
8662e5cb688Stron     }
8672e5cb688Stron     if (tls_dane_notfound(dane)) {
8682e5cb688Stron 	dane_incompat(tls, iter, NONDANE_DEST, "no TLSA records found");
8692e5cb688Stron 	tls_dane_free(dane);
8702e5cb688Stron 	return;
8712e5cb688Stron     }
8722e5cb688Stron 
8732e5cb688Stron     /*
8742e5cb688Stron      * Some TLSA records found, but none usable, per
8752e5cb688Stron      *
8762e5cb688Stron      * https://tools.ietf.org/html/draft-ietf-dane-srv-02#section-4
8772e5cb688Stron      *
8782e5cb688Stron      * we MUST use TLS, and SHALL use full PKIX certificate checks.  The latter
8792e5cb688Stron      * would be unwise for SMTP: no human present to "click ok" and risk of
8802e5cb688Stron      * non-delivery in most cases exceeds risk of interception.
8812e5cb688Stron      *
8822e5cb688Stron      * We also have a form of Goedel's incompleteness theorem in play: any list
8832e5cb688Stron      * of public root CA certs is either incomplete or inconsistent (for any
8842e5cb688Stron      * given verifier some of the CAs are surely not trustworthy).
8852e5cb688Stron      */
8862e5cb688Stron     if (tls_dane_unusable(dane)) {
887837e7c1aSchristos 	dane_incompat(tls, iter, DANE_CANTAUTH, "TLSA records unusable");
8882e5cb688Stron 	tls_dane_free(dane);
8892e5cb688Stron 	return;
8902e5cb688Stron     }
8912e5cb688Stron 
8922e5cb688Stron     /*
893837e7c1aSchristos      * Perhaps downgrade to "encrypt" if MX is insecure.
894837e7c1aSchristos      */
895837e7c1aSchristos     if (iter->mx && !iter->mx->dnssec_valid) {
896837e7c1aSchristos 	if (smtp_tls_insecure_mx_policy == TLS_LEV_ENCRYPT) {
897837e7c1aSchristos 	    dane_incompat(tls, iter, DANE_CANTAUTH,
898837e7c1aSchristos 			  "Verification not possible, MX RRset is insecure");
899837e7c1aSchristos 	    tls_dane_free(dane);
900837e7c1aSchristos 	    return;
901837e7c1aSchristos 	}
902837e7c1aSchristos 	if (tls->level != TLS_LEV_DANE
903837e7c1aSchristos 	    || smtp_tls_insecure_mx_policy != TLS_LEV_DANE)
904837e7c1aSchristos 	    msg_panic("wrong state for insecure MX host DANE policy");
905837e7c1aSchristos 
906837e7c1aSchristos 	/* For correct logging in tls_client_start() */
907837e7c1aSchristos 	tls->level = TLS_LEV_HALF_DANE;
908837e7c1aSchristos     }
909837e7c1aSchristos 
910837e7c1aSchristos     /*
9112e5cb688Stron      * With DANE trust anchors, peername matching is not configurable.
9122e5cb688Stron      */
913*fb52cf35Schristos     if (dane->tlsa != 0) {
9142e5cb688Stron 	tls->matchargv = argv_alloc(2);
9152e5cb688Stron 	argv_add(tls->matchargv, dane->base_domain, ARGV_END);
9162e5cb688Stron 	if (iter->mx) {
9172e5cb688Stron 	    if (strcmp(iter->mx->qname, iter->mx->rname) == 0)
9182e5cb688Stron 		argv_add(tls->matchargv, iter->mx->qname, ARGV_END);
9192e5cb688Stron 	    else
9202e5cb688Stron 		argv_add(tls->matchargv, iter->mx->rname,
9212e5cb688Stron 			 iter->mx->qname, ARGV_END);
9222e5cb688Stron 	}
923*fb52cf35Schristos     } else
9242e5cb688Stron 	msg_panic("empty DANE match list");
9252e5cb688Stron     tls->dane = dane;
9262e5cb688Stron     return;
9272e5cb688Stron }
9282e5cb688Stron 
9292e5cb688Stron #endif
930