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