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