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