summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2023-08-10 01:10:33 +0200
committermanuel <manuel@mausz.at>2023-08-10 01:10:33 +0200
commitf3696facb188bda5b9995bb8cf50e9bac37e4f29 (patch)
tree0f467424bd8628d6e29aa9a688b14e29bd26dfda
parent29b6e8b053d21f0a1e722e1c3be38371e7efaf10 (diff)
downloadqmail-f3696facb188bda5b9995bb8cf50e9bac37e4f29.tar.gz
qmail-f3696facb188bda5b9995bb8cf50e9bac37e4f29.tar.bz2
qmail-f3696facb188bda5b9995bb8cf50e9bac37e4f29.zip
DANE: only enabled if MX lookup has been validated
additionally require TLSA RRs to be validated as well
-rw-r--r--qmail-remote.c51
1 files changed, 23 insertions, 28 deletions
diff --git a/qmail-remote.c b/qmail-remote.c
index c353bec..edfdb60 100644
--- a/qmail-remote.c
+++ b/qmail-remote.c
@@ -67,7 +67,6 @@ struct ip_address partner;
67# define EHLO 1 67# define EHLO 1
68# define CLIENTCERT "control/clientcert.pem" 68# define CLIENTCERT "control/clientcert.pem"
69 69
70int tls_init();
71const char *ssl_err_str = 0; 70const char *ssl_err_str = 0;
72char **myargv; 71char **myargv;
73#endif 72#endif
@@ -368,8 +367,6 @@ void blast()
368} 367}
369 368
370#ifdef TLS 369#ifdef TLS
371char *partner_fqdn = 0;
372
373# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", NULL) 370# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", NULL)
374void tls_quit(const char *s1, const char *s2) 371void tls_quit(const char *s1, const char *s2)
375{ 372{
@@ -377,12 +374,12 @@ void tls_quit(const char *s1, const char *s2)
377} 374}
378# define tls_quit_error(s) tls_quit(s, ssl_error()) 375# define tls_quit_error(s) tls_quit(s, ssl_error())
379 376
380int match_partner(const char *s, int len) 377int match_mx_host(const char *mx_host, const char *s, int len)
381{ 378{
382 if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1; 379 if (!case_diffb(mx_host, len, s) && !mx_host[len]) return 1;
383 /* we also match if the name is *.domainname */ 380 /* we also match if the name is *.domainname */
384 if (*s == '*') { 381 if (*s == '*') {
385 const char *domain = partner_fqdn + str_chr(partner_fqdn, '.'); 382 const char *domain = mx_host + str_chr(mx_host, '.');
386 if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1; 383 if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1;
387 } 384 }
388 return 0; 385 return 0;
@@ -396,25 +393,26 @@ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
396 * @return 0 ...TLS failed, continue plaintext 393 * @return 0 ...TLS failed, continue plaintext
397 * @return -1 ...skip to next MX 394 * @return -1 ...skip to next MX
398 */ 395 */
399int tls_init() 396static int tls_init(struct ip_mx *current_mx)
400{ 397{
401 int i; 398 int i;
402 SSL *myssl; 399 SSL *myssl;
403 SSL_CTX *ctx; 400 SSL_CTX *ctx;
404 stralloc saciphers = {0}; 401 stralloc saciphers = {0};
405 const char *ciphers, *servercert = 0; 402 const char *ciphers, *servercert = 0;
403 const char *mx_host = current_mx->fqdn;
406 404
407 if (partner_fqdn) { 405 if (mx_host) {
408 struct stat st; 406 struct stat st;
409 stralloc tmp = {0}; 407 stralloc tmp = {0};
410 if (!stralloc_copys(&tmp, "control/tlshosts/") 408 if (!stralloc_copys(&tmp, "control/tlshosts/")
411 || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)) 409 || !stralloc_catb(&tmp, mx_host, str_len(mx_host))
412 || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem(); 410 || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem();
413 if (stat(tmp.s, &st) == 0) 411 if (stat(tmp.s, &st) == 0)
414 servercert = tmp.s; 412 servercert = tmp.s;
415 else { 413 else {
416 if (!stralloc_copys(&tmp, "control/notlshosts/") 414 if (!stralloc_copys(&tmp, "control/notlshosts/")
417 || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1)) 415 || !stralloc_catb(&tmp, mx_host, str_len(mx_host)+1))
418 temp_nomem(); 416 temp_nomem();
419 if ((stat("control/tlshosts/exhaustivelist", &st) == 0) || 417 if ((stat("control/tlshosts/exhaustivelist", &st) == 0) ||
420 (stat(tmp.s, &st) == 0)) { 418 (stat(tmp.s, &st) == 0)) {
@@ -431,7 +429,7 @@ int tls_init()
431 int tls_required = (smtps || servercert != NULL); 429 int tls_required = (smtps || servercert != NULL);
432 stralloc tlsa_rr = { 0 }; 430 stralloc tlsa_rr = { 0 };
433 431
434 if (partner_fqdn && !servercert) { 432 if (mx_host && !servercert && current_mx->validated) {
435 stralloc tlsa_label = { 0 }; 433 stralloc tlsa_label = { 0 };
436 char port[FMT_ULONG]; 434 char port[FMT_ULONG];
437 435
@@ -439,7 +437,7 @@ int tls_init()
439 port[fmt_ulong(port, smtp_port)] = 0; 437 port[fmt_ulong(port, smtp_port)] = 0;
440 if (!stralloc_cats(&tlsa_label, port)) temp_nomem(); 438 if (!stralloc_cats(&tlsa_label, port)) temp_nomem();
441 if (!stralloc_cats(&tlsa_label, "._tcp.")) temp_nomem(); 439 if (!stralloc_cats(&tlsa_label, "._tcp.")) temp_nomem();
442 if (!stralloc_cats(&tlsa_label, partner_fqdn)) temp_nomem(); 440 if (!stralloc_cats(&tlsa_label, mx_host)) temp_nomem();
443 441
444 switch (dns_tlsa(&tlsa_rr, &tlsa_label)) { 442 switch (dns_tlsa(&tlsa_rr, &tlsa_label)) {
445 case DNS_MEM: temp_nomem(); 443 case DNS_MEM: temp_nomem();
@@ -447,7 +445,7 @@ int tls_init()
447 case DNS_HARD: tlsa_rr.len = 0; // no record found 445 case DNS_HARD: tlsa_rr.len = 0; // no record found
448 } 446 }
449 447
450 if (tlsa_rr.len) 448 if (tlsa_rr.len && dns_last_query_validated())
451 tls_required = 1; 449 tls_required = 1;
452 } 450 }
453 451
@@ -549,12 +547,12 @@ int tls_init()
549 } 547 }
550 548
551 /* set SNI hostname */ 549 /* set SNI hostname */
552 if (partner_fqdn) 550 if (mx_host)
553 SSL_set_tlsext_host_name(myssl, partner_fqdn); 551 SSL_set_tlsext_host_name(myssl, mx_host);
554 552
555 /* DANE: enable + add records */ 553 /* DANE: enable + add records */
556 if (tlsa_rr.len) { 554 if (tlsa_rr.len) {
557 if (SSL_dane_enable(myssl, partner_fqdn) <= 0) { 555 if (SSL_dane_enable(myssl, mx_host) <= 0) {
558 smtptext.len = 0; 556 smtptext.len = 0;
559 tls_quit_error("ZTLS error enabling dane"); 557 tls_quit_error("ZTLS error enabling dane");
560 } 558 }
@@ -657,7 +655,7 @@ int tls_init()
657 peercert = SSL_get_peer_certificate(myssl); 655 peercert = SSL_get_peer_certificate(myssl);
658 if (!peercert) { 656 if (!peercert) {
659 out("ZTLS unable to verify server "); 657 out("ZTLS unable to verify server ");
660 tls_quit(partner_fqdn, "no certificate provided"); 658 tls_quit(mx_host, "no certificate provided");
661 } 659 }
662 660
663 /* RFC 2595 section 2.4: find a matching name 661 /* RFC 2595 section 2.4: find a matching name
@@ -668,7 +666,7 @@ int tls_init()
668 { 666 {
669 const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i); 667 const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
670 if (gn->type == GEN_DNS) 668 if (gn->type == GEN_DNS)
671 if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break; 669 if (match_mx_host(mx_host, gn->d.ia5->data, gn->d.ia5->length)) break;
672 } 670 }
673 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 671 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
674 } 672 }
@@ -685,10 +683,10 @@ int tls_init()
685 } 683 }
686 if (peer.len <= 0) { 684 if (peer.len <= 0) {
687 out("ZTLS unable to verify server "); 685 out("ZTLS unable to verify server ");
688 tls_quit(partner_fqdn, "certificate contains no valid commonName"); 686 tls_quit(mx_host, "certificate contains no valid commonName");
689 } 687 }
690 if (!match_partner(peer.s, peer.len)) { 688 if (!match_mx_host(mx_host, peer.s, peer.len)) {
691 out("ZTLS unable to verify server "); out(partner_fqdn); 689 out("ZTLS unable to verify server "); out(mx_host);
692 out(": received certificate for "); outsafe(&peer); TLS_QUIT; 690 out(": received certificate for "); outsafe(&peer); TLS_QUIT;
693 } 691 }
694 } 692 }
@@ -699,7 +697,7 @@ int tls_init()
699 else if (tlsa_rr.len) { 697 else if (tlsa_rr.len) {
700 if (!SSL_get_peer_certificate(myssl) || SSL_get_verify_result(myssl) != X509_V_OK) { 698 if (!SSL_get_peer_certificate(myssl) || SSL_get_verify_result(myssl) != X509_V_OK) {
701 out("lNo TLSA record matched: "); 699 out("lNo TLSA record matched: ");
702 out(partner_fqdn); 700 out(mx_host);
703 quit2("/", NULL, 0); 701 quit2("/", NULL, 0);
704 return -1; 702 return -1;
705 } 703 }
@@ -771,7 +769,7 @@ void mail_without_auth()
771 substdio_flush(&smtpto); 769 substdio_flush(&smtpto);
772} 770}
773 771
774void smtp() 772static void smtp(struct ip_mx *current_mx)
775{ 773{
776 unsigned long code = 0; 774 unsigned long code = 0;
777 int flagbother; 775 int flagbother;
@@ -791,7 +789,7 @@ void smtp()
791#endif 789#endif
792 790
793#ifdef TLS 791#ifdef TLS
794 int tls = tls_init(); 792 int tls = tls_init(current_mx);
795 if (tls == -1) { 793 if (tls == -1) {
796 if (ssl) 794 if (ssl)
797 ssl_free(ssl); 795 ssl_free(ssl);
@@ -1194,10 +1192,7 @@ char **argv;
1194 if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) smtp_port,timeoutconnect) == 0) { 1192 if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) smtp_port,timeoutconnect) == 0) {
1195 tcpto_err(&ip.ix[i].ip,0); 1193 tcpto_err(&ip.ix[i].ip,0);
1196 partner = ip.ix[i].ip; 1194 partner = ip.ix[i].ip;
1197#ifdef TLS 1195 smtp(&ip.ix[i]); /* only returns when the next MX is to be tried */
1198 partner_fqdn = ip.ix[i].fqdn;
1199#endif
1200 smtp(); /* only returns when the next MX is to be tried */
1201 } 1196 }
1202 tcpto_err(&ip.ix[i].ip,errno == error_timeout || errno == error_refused); 1197 tcpto_err(&ip.ix[i].ip,errno == error_timeout || errno == error_refused);
1203 close(smtpfd); 1198 close(smtpfd);