diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | qmail-remote.c | 197 | ||||
| -rw-r--r-- | qmail-smtpd.c | 213 |
3 files changed, 130 insertions, 282 deletions
| @@ -1533,7 +1533,7 @@ dns.lib socket.lib | |||
| 1533 | ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ | 1533 | ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ |
| 1534 | lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ | 1534 | lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ |
| 1535 | env.a str.a fs.a auto_qmail.o base64.o \ | 1535 | env.a str.a fs.a auto_qmail.o base64.o \ |
| 1536 | `cat dns.lib` `cat socket.lib` -lval -lsres -lidn2 | 1536 | `cat dns.lib` `cat socket.lib` -lidn2 |
| 1537 | 1537 | ||
| 1538 | qmail-remote.0: \ | 1538 | qmail-remote.0: \ |
| 1539 | qmail-remote.8 | 1539 | qmail-remote.8 |
diff --git a/qmail-remote.c b/qmail-remote.c index 0e2377e..1a09df9 100644 --- a/qmail-remote.c +++ b/qmail-remote.c | |||
| @@ -63,8 +63,6 @@ struct ip_address partner; | |||
| 63 | # include "tls.h" | 63 | # include "tls.h" |
| 64 | # include "ssl_timeoutio.h" | 64 | # include "ssl_timeoutio.h" |
| 65 | # include <openssl/x509v3.h> | 65 | # include <openssl/x509v3.h> |
| 66 | # include <validator/validator.h> | ||
| 67 | # include <validator/val_dane.h> | ||
| 68 | 66 | ||
| 69 | # define EHLO 1 | 67 | # define EHLO 1 |
| 70 | # define CLIENTCERT "control/clientcert.pem" | 68 | # define CLIENTCERT "control/clientcert.pem" |
| @@ -72,10 +70,6 @@ struct ip_address partner; | |||
| 72 | int tls_init(); | 70 | int tls_init(); |
| 73 | const char *ssl_err_str = 0; | 71 | const char *ssl_err_str = 0; |
| 74 | char **myargv; | 72 | char **myargv; |
| 75 | val_context_t *dane_context = NULL; | ||
| 76 | int dane_context_failed = 0; | ||
| 77 | struct val_danestatus *dane_status = NULL; | ||
| 78 | struct val_ssl_data *dane_ssl_data = NULL; | ||
| 79 | #endif | 73 | #endif |
| 80 | 74 | ||
| 81 | #ifdef SMTPUTF8 | 75 | #ifdef SMTPUTF8 |
| @@ -241,10 +235,6 @@ unsigned long ehlo() | |||
| 241 | if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len; | 235 | if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len; |
| 242 | ehlokw.len = 0; | 236 | ehlokw.len = 0; |
| 243 | 237 | ||
| 244 | # ifdef MXPS | ||
| 245 | if (type == 's') return 0; | ||
| 246 | # endif | ||
| 247 | |||
| 248 | substdio_puts(&smtpto, "EHLO "); | 238 | substdio_puts(&smtpto, "EHLO "); |
| 249 | substdio_put(&smtpto, helohost.s, helohost.len); | 239 | substdio_put(&smtpto, helohost.s, helohost.len); |
| 250 | substdio_puts(&smtpto, "\r\n"); | 240 | substdio_puts(&smtpto, "\r\n"); |
| @@ -437,34 +427,28 @@ int tls_init() | |||
| 437 | } | 427 | } |
| 438 | } | 428 | } |
| 439 | 429 | ||
| 440 | /* DANE: starts here */ | 430 | /* DANE: lookup TLSA records */ |
| 441 | int dane_retval = VAL_DANE_INTERNAL_ERROR; | ||
| 442 | int tls_required = (smtps || servercert != NULL); | 431 | int tls_required = (smtps || servercert != NULL); |
| 443 | 432 | stralloc tlsa_rr = { 0 }; | |
| 444 | if (partner_fqdn && !servercert && !dane_context_failed) { | 433 | |
| 445 | if (dane_context == NULL && val_create_context(NULL, &dane_context) | 434 | if (partner_fqdn && !servercert) { |
| 446 | != VAL_NO_ERROR) { | 435 | stralloc tlsa_label = { 0 }; |
| 447 | dane_context_failed = 1; | 436 | char port[FMT_ULONG]; |
| 448 | out("lUnable to initialize libval context\n"); | 437 | |
| 449 | zeroflush(); | 438 | if (!stralloc_copyb(&tlsa_label, "_", 1)) temp_nomem(); |
| 439 | port[fmt_ulong(port, smtp_port)] = 0; | ||
| 440 | if (!stralloc_cats(&tlsa_label, port)) temp_nomem(); | ||
| 441 | if (!stralloc_cats(&tlsa_label, "._tcp.")) temp_nomem(); | ||
| 442 | if (!stralloc_cats(&tlsa_label, partner_fqdn)) temp_nomem(); | ||
| 443 | |||
| 444 | switch (dns_tlsa(&tlsa_rr, &tlsa_label)) { | ||
| 445 | case DNS_MEM: temp_nomem(); | ||
| 446 | case DNS_SOFT: temp_dns(); | ||
| 447 | case DNS_HARD: tlsa_rr.len = 0; // no record found | ||
| 450 | } | 448 | } |
| 451 | 449 | ||
| 452 | if (dane_context) { | 450 | if (tlsa_rr.len) |
| 453 | val_free_dane(dane_status); | 451 | tls_required = 1; |
| 454 | val_free_dane_ssl(dane_ssl_data); | ||
| 455 | |||
| 456 | /* DANE: lookup TLSA records */ | ||
| 457 | struct val_daneparams dane_params = { | ||
| 458 | .port = smtp_port, | ||
| 459 | .proto = DANE_PARAM_PROTO_TCP | ||
| 460 | }; | ||
| 461 | dane_retval = val_getdaneinfo(dane_context, partner_fqdn, &dane_params, &dane_status); | ||
| 462 | /* work around a bug if no error but no also no records */ | ||
| 463 | if (dane_retval == VAL_DANE_NOERROR && dane_status == NULL) | ||
| 464 | dane_retval = VAL_DANE_IGNORE_TLSA; | ||
| 465 | if (dane_retval == VAL_DANE_NOERROR) | ||
| 466 | tls_required = 1; | ||
| 467 | } | ||
| 468 | } | 452 | } |
| 469 | 453 | ||
| 470 | if (!smtps) { | 454 | if (!smtps) { |
| @@ -480,13 +464,20 @@ int tls_init() | |||
| 480 | } | 464 | } |
| 481 | 465 | ||
| 482 | SSL_library_init(); | 466 | SSL_library_init(); |
| 483 | ctx = SSL_CTX_new(SSLv23_client_method()); | 467 | ctx = SSL_CTX_new(TLS_client_method()); |
| 484 | if (!ctx) { | 468 | if (!ctx) { |
| 485 | if (!tls_required) return 0; | ||
| 486 | smtptext.len = 0; | 469 | smtptext.len = 0; |
| 487 | tls_quit_error("ZTLS error initializing ctx"); | 470 | tls_quit_error("ZTLS error initializing ctx"); |
| 488 | } | 471 | } |
| 489 | SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); | 472 | SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); |
| 473 | |||
| 474 | /* we verify ourself below. see SSL_get_verify_result */ | ||
| 475 | SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); | ||
| 476 | |||
| 477 | if (SSL_CTX_dane_enable(ctx) <= 0) { | ||
| 478 | smtptext.len = 0; | ||
| 479 | tls_quit_error("ZTLS error initializing dane ctx"); | ||
| 480 | } | ||
| 490 | 481 | ||
| 491 | if (servercert) { | 482 | if (servercert) { |
| 492 | if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) { | 483 | if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) { |
| @@ -497,19 +488,6 @@ int tls_init() | |||
| 497 | /* set the callback here; SSL_set_verify didn't work before 0.9.6c */ | 488 | /* set the callback here; SSL_set_verify didn't work before 0.9.6c */ |
| 498 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); | 489 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); |
| 499 | } | 490 | } |
| 500 | else if (dane_retval == VAL_DANE_NOERROR) { | ||
| 501 | /* DANE: treat PKIX-EE as it were DANE-EE */ | ||
| 502 | struct val_danestatus *dane_cur; | ||
| 503 | for (dane_cur = dane_status; dane_cur; dane_cur = dane_cur->next) { | ||
| 504 | if (dane_cur->usage == DANE_USE_SVC_CONSTRAINT) | ||
| 505 | dane_cur->usage = DANE_USE_DOMAIN_ISSUED; | ||
| 506 | } | ||
| 507 | /* DANE: set verify callback */ | ||
| 508 | int err = val_enable_dane_ssl(dane_context, ctx, partner_fqdn, dane_status, | ||
| 509 | &dane_ssl_data); | ||
| 510 | if (err != VAL_NO_ERROR) | ||
| 511 | tls_quit("ZCould not enable dane verification", p_val_error(err)); | ||
| 512 | } | ||
| 513 | 491 | ||
| 514 | /* let the other side complain if it needs a cert and we don't have one */ | 492 | /* let the other side complain if it needs a cert and we don't have one */ |
| 515 | if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT)) | 493 | if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT)) |
| @@ -518,14 +496,10 @@ int tls_init() | |||
| 518 | myssl = SSL_new(ctx); | 496 | myssl = SSL_new(ctx); |
| 519 | SSL_CTX_free(ctx); | 497 | SSL_CTX_free(ctx); |
| 520 | if (!myssl) { | 498 | if (!myssl) { |
| 521 | if (!tls_required) return 0; | ||
| 522 | smtptext.len = 0; | 499 | smtptext.len = 0; |
| 523 | tls_quit_error("ZTLS error initializing ssl"); | 500 | tls_quit_error("ZTLS error initializing ssl"); |
| 524 | } | 501 | } |
| 525 | 502 | ||
| 526 | if (!smtps) | ||
| 527 | substdio_putsflush(&smtpto, "STARTTLS\r\n"); | ||
| 528 | |||
| 529 | /* while the server is preparing a responce, do something else */ | 503 | /* while the server is preparing a responce, do something else */ |
| 530 | if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1) | 504 | if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1) |
| 531 | { SSL_free(myssl); temp_control(); } | 505 | { SSL_free(myssl); temp_control(); } |
| @@ -539,14 +513,15 @@ int tls_init() | |||
| 539 | SSL_set_cipher_list(myssl, ciphers); | 513 | SSL_set_cipher_list(myssl, ciphers); |
| 540 | alloc_free(saciphers.s); | 514 | alloc_free(saciphers.s); |
| 541 | 515 | ||
| 542 | #if OPENSSL_VERSION_NUMBER >= 0x10100005L | ||
| 543 | stralloc opensslconf = {0}; | 516 | stralloc opensslconf = {0}; |
| 544 | if (control_readfile(&opensslconf, "control/opensslconf", 0) == -1) | 517 | if (control_readfile(&opensslconf, "control/opensslconf", 0) == -1) |
| 545 | { SSL_free(myssl); temp_control(); } | 518 | { SSL_free(myssl); temp_control(); } |
| 546 | if (opensslconf.len) { | 519 | if (opensslconf.len) { |
| 547 | SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); | 520 | SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); |
| 548 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); | 521 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); |
| 522 | /* client + server so we can share one single file */ | ||
| 549 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); | 523 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); |
| 524 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); | ||
| 550 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); | 525 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); |
| 551 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); | 526 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); |
| 552 | SSL_CONF_CTX_set_ssl(cctx, myssl); | 527 | SSL_CONF_CTX_set_ssl(cctx, myssl); |
| @@ -572,13 +547,68 @@ int tls_init() | |||
| 572 | 547 | ||
| 573 | (void)SSL_CONF_CTX_finish(cctx); | 548 | (void)SSL_CONF_CTX_finish(cctx); |
| 574 | } | 549 | } |
| 575 | #endif | ||
| 576 | 550 | ||
| 577 | /* set SNI hostname */ | 551 | /* set SNI hostname */ |
| 578 | if (partner_fqdn) | 552 | if (partner_fqdn) |
| 579 | SSL_set_tlsext_host_name(myssl, partner_fqdn); | 553 | SSL_set_tlsext_host_name(myssl, partner_fqdn); |
| 580 | 554 | ||
| 581 | /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */ | 555 | /* DANE: enable + add records */ |
| 556 | if (tlsa_rr.len) { | ||
| 557 | if (SSL_dane_enable(myssl, partner_fqdn) <= 0) { | ||
| 558 | smtptext.len = 0; | ||
| 559 | tls_quit_error("ZTLS error enabling dane"); | ||
| 560 | } | ||
| 561 | SSL_dane_set_flags(myssl, DANE_FLAG_NO_DANE_EE_NAMECHECKS); | ||
| 562 | |||
| 563 | // loop through TLSA rr | ||
| 564 | int pos = 0, num_usable = 0; | ||
| 565 | unsigned char *rr_data = (unsigned char *)tlsa_rr.s; | ||
| 566 | while (pos < tlsa_rr.len && tlsa_rr.len - pos > 2 + 4) // sizeof(rrlen) + min(rrdata) | ||
| 567 | { | ||
| 568 | unsigned short rrlen = (rr_data[pos] << 8) + rr_data[pos + 1]; | ||
| 569 | pos += 2; | ||
| 570 | uint8_t usage = rr_data[pos]; | ||
| 571 | uint8_t selector = rr_data[pos + 1]; | ||
| 572 | uint8_t mtype = rr_data[pos + 2]; | ||
| 573 | |||
| 574 | /* | ||
| 575 | * Opportunistic DANE TLS clients support only DANE-TA(2) or DANE-EE(3). | ||
| 576 | * They treat all other certificate usages, and in particular PKIX-TA(0) | ||
| 577 | * and PKIX-EE(1), as unusable. | ||
| 578 | */ | ||
| 579 | switch (usage) { | ||
| 580 | default: | ||
| 581 | case 0: /* PKIX-TA(0) */ | ||
| 582 | case 1: /* PKIX-EE(1) */ | ||
| 583 | pos += rrlen; | ||
| 584 | continue; | ||
| 585 | case 2: /* DANE-TA(2) */ | ||
| 586 | case 3: /* DANE-EE(3) */ | ||
| 587 | break; | ||
| 588 | } | ||
| 589 | |||
| 590 | // rrlen includes usage+selector+mtype (3) byte. remove | ||
| 591 | unsigned const char *cdata = rr_data + pos + 3; | ||
| 592 | size_t cdlen = rrlen - 3; | ||
| 593 | int tlsa_added = SSL_dane_tlsa_add(myssl, usage, selector, mtype, cdata, cdlen); | ||
| 594 | if (tlsa_added < 0) { | ||
| 595 | smtptext.len = 0; | ||
| 596 | tls_quit_error("ZTLS error adding DANE TLSA record"); | ||
| 597 | } | ||
| 598 | else if (tlsa_added > 0) | ||
| 599 | ++num_usable; | ||
| 600 | |||
| 601 | pos += rrlen; | ||
| 602 | } | ||
| 603 | |||
| 604 | // no records usable. fallback to unauthenticated TLS | ||
| 605 | if (num_usable == 0) | ||
| 606 | tlsa_rr.len = 0; | ||
| 607 | } | ||
| 608 | |||
| 609 | if (!smtps) | ||
| 610 | substdio_putsflush(&smtpto, "STARTTLS\r\n"); | ||
| 611 | |||
| 582 | SSL_set_fd(myssl, smtpfd); | 612 | SSL_set_fd(myssl, smtpfd); |
| 583 | 613 | ||
| 584 | /* read the responce to STARTTLS */ | 614 | /* read the responce to STARTTLS */ |
| @@ -593,7 +623,7 @@ int tls_init() | |||
| 593 | } | 623 | } |
| 594 | 624 | ||
| 595 | ssl = myssl; | 625 | ssl = myssl; |
| 596 | if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0) { | 626 | if (ssl_timeoutconn(timeout, smtpfd, smtpfd, myssl) <= 0) { |
| 597 | if (tls_required) | 627 | if (tls_required) |
| 598 | tls_quit("ZTLS connect failed", ssl_error_str()); | 628 | tls_quit("ZTLS connect failed", ssl_error_str()); |
| 599 | else { | 629 | else { |
| @@ -617,14 +647,14 @@ int tls_init() | |||
| 617 | X509 *peercert; | 647 | X509 *peercert; |
| 618 | STACK_OF(GENERAL_NAME) *gens; | 648 | STACK_OF(GENERAL_NAME) *gens; |
| 619 | 649 | ||
| 620 | int r = SSL_get_verify_result(ssl); | 650 | int r = SSL_get_verify_result(myssl); |
| 621 | if (r != X509_V_OK) { | 651 | if (r != X509_V_OK) { |
| 622 | out("ZTLS unable to verify server with "); | 652 | out("ZTLS unable to verify server with "); |
| 623 | tls_quit(servercert, X509_verify_cert_error_string(r)); | 653 | tls_quit(servercert, X509_verify_cert_error_string(r)); |
| 624 | } | 654 | } |
| 625 | alloc_free(servercert); | 655 | alloc_free(servercert); |
| 626 | 656 | ||
| 627 | peercert = SSL_get_peer_certificate(ssl); | 657 | peercert = SSL_get_peer_certificate(myssl); |
| 628 | if (!peercert) { | 658 | if (!peercert) { |
| 629 | out("ZTLS unable to verify server "); | 659 | out("ZTLS unable to verify server "); |
| 630 | tls_quit(partner_fqdn, "no certificate provided"); | 660 | tls_quit(partner_fqdn, "no certificate provided"); |
| @@ -651,10 +681,7 @@ int tls_init() | |||
| 651 | if (i >= 0) { | 681 | if (i >= 0) { |
| 652 | X509_NAME_ENTRY *entry = X509_NAME_get_entry(subj, i); | 682 | X509_NAME_ENTRY *entry = X509_NAME_get_entry(subj, i); |
| 653 | ASN1_STRING *s = X509_NAME_ENTRY_get_data(entry); | 683 | ASN1_STRING *s = X509_NAME_ENTRY_get_data(entry); |
| 654 | #if OPENSSL_VERSION_NUMBER < 0x10100005L | 684 | if (s) { peer.len = ASN1_STRING_length(s); peer.s = (char *)ASN1_STRING_get0_data(s); } |
| 655 | #define ASN1_STRING_get0_data ASN1_STRING_data | ||
| 656 | #endif | ||
| 657 | if (s) { peer.len = ASN1_STRING_length(s); peer.s = (unsigned char *)ASN1_STRING_get0_data(s); } | ||
| 658 | } | 685 | } |
| 659 | if (peer.len <= 0) { | 686 | if (peer.len <= 0) { |
| 660 | out("ZTLS unable to verify server "); | 687 | out("ZTLS unable to verify server "); |
| @@ -669,8 +696,8 @@ int tls_init() | |||
| 669 | X509_free(peercert); | 696 | X509_free(peercert); |
| 670 | } | 697 | } |
| 671 | /* DANE: verify result */ | 698 | /* DANE: verify result */ |
| 672 | else if (dane_retval == VAL_DANE_NOERROR) { | 699 | else if (tlsa_rr.len) { |
| 673 | if (!SSL_get_peer_certificate(ssl) || SSL_get_verify_result(ssl) != X509_V_OK) { | 700 | if (!SSL_get_peer_certificate(myssl) || SSL_get_verify_result(myssl) != X509_V_OK) { |
| 674 | out("lNo TLSA record matched: "); | 701 | out("lNo TLSA record matched: "); |
| 675 | out(partner_fqdn); | 702 | out(partner_fqdn); |
| 676 | quit2("/", NULL, 0); | 703 | quit2("/", NULL, 0); |
| @@ -746,33 +773,22 @@ void mail_without_auth() | |||
| 746 | 773 | ||
| 747 | void smtp() | 774 | void smtp() |
| 748 | { | 775 | { |
| 749 | unsigned long code; | 776 | unsigned long code = 0; |
| 750 | int flagbother; | 777 | int flagbother; |
| 751 | int i, j; | ||
| 752 | |||
| 753 | #ifndef PORT_SMTP | ||
| 754 | /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */ | ||
| 755 | # define port smtp_port | ||
| 756 | #endif | ||
| 757 | 778 | ||
| 758 | #ifdef TLS | 779 | #ifdef TLS |
| 759 | # ifdef MXPS | 780 | if (smtp_port == 465) smtps = 1; |
| 760 | if (type == 'S') smtps = 1; | 781 | if (!smtps) { |
| 761 | else if (type != 's') | ||
| 762 | # endif | ||
| 763 | if (port == 465) smtps = 1; | ||
| 764 | if (!smtps) | ||
| 765 | #endif | 782 | #endif |
| 766 | |||
| 767 | code = smtpcode(); | 783 | code = smtpcode(); |
| 768 | if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed"); | 784 | if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed"); |
| 769 | if (code >= 400 && code < 500) return; /* try next MX, see RFC-2821 */ | 785 | if (code >= 400 && code < 500) return; /* try next MX, see RFC-2821 */ |
| 770 | if (code != 220) quit("ZConnected to "," but greeting failed"); | 786 | if (code != 220) quit("ZConnected to "," but greeting failed"); |
| 771 | 787 | ||
| 788 | code = ehlo(); | ||
| 772 | #ifdef TLS | 789 | #ifdef TLS |
| 773 | if (!smtps) | 790 | } |
| 774 | #endif | 791 | #endif |
| 775 | code = ehlo(); | ||
| 776 | 792 | ||
| 777 | #ifdef TLS | 793 | #ifdef TLS |
| 778 | int tls = tls_init(); | 794 | int tls = tls_init(); |
| @@ -782,7 +798,7 @@ void smtp() | |||
| 782 | ssl = NULL; | 798 | ssl = NULL; |
| 783 | return; /* try next MX */ | 799 | return; /* try next MX */ |
| 784 | } | 800 | } |
| 785 | else if (tls) | 801 | else if (tls > 0) |
| 786 | /* RFC2487 says we should issue EHLO (even if we might not need | 802 | /* RFC2487 says we should issue EHLO (even if we might not need |
| 787 | * extensions); at the same time, it does not prohibit a server | 803 | * extensions); at the same time, it does not prohibit a server |
| 788 | * to reject the EHLO and make us fallback to HELO */ | 804 | * to reject the EHLO and make us fallback to HELO */ |
| @@ -803,7 +819,7 @@ void smtp() | |||
| 803 | if (code != 250) quit("ZConnected to "," but my name was rejected"); | 819 | if (code != 250) quit("ZConnected to "," but my name was rejected"); |
| 804 | } | 820 | } |
| 805 | 821 | ||
| 806 | i = 0; | 822 | int i = 0; |
| 807 | if (auth_smtp_user.len && auth_smtp_pass.len) { | 823 | if (auth_smtp_user.len && auth_smtp_pass.len) { |
| 808 | while((i += str_chr(smtptext.s+i,'\n') + 1) && | 824 | while((i += str_chr(smtptext.s+i,'\n') + 1) && |
| 809 | (i+8 < smtptext.len) && | 825 | (i+8 < smtptext.len) && |
| @@ -854,7 +870,7 @@ void smtp() | |||
| 854 | if (code >= 400) quit("ZConnected to "," but sender was rejected"); | 870 | if (code >= 400) quit("ZConnected to "," but sender was rejected"); |
| 855 | 871 | ||
| 856 | flagbother = 0; | 872 | flagbother = 0; |
| 857 | for (i = 0;i < reciplist.len;++i) { | 873 | for (int i = 0;i < reciplist.len;++i) { |
| 858 | substdio_puts(&smtpto,"RCPT TO:<"); | 874 | substdio_puts(&smtpto,"RCPT TO:<"); |
| 859 | substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); | 875 | substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); |
| 860 | substdio_puts(&smtpto,">\r\n"); | 876 | substdio_puts(&smtpto,">\r\n"); |
| @@ -907,7 +923,6 @@ void qmtp() | |||
| 907 | { | 923 | { |
| 908 | struct stat st; | 924 | struct stat st; |
| 909 | unsigned long len; | 925 | unsigned long len; |
| 910 | int len2; | ||
| 911 | char *x; | 926 | char *x; |
| 912 | int i; | 927 | int i; |
| 913 | int n; | 928 | int n; |
| @@ -1039,9 +1054,11 @@ void getcontrols() | |||
| 1039 | case -1: | 1054 | case -1: |
| 1040 | temp_control(); | 1055 | temp_control(); |
| 1041 | case 0: | 1056 | case 0: |
| 1042 | if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break; | 1057 | if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); |
| 1058 | break; | ||
| 1043 | case 1: | 1059 | case 1: |
| 1044 | if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; | 1060 | if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); |
| 1061 | break; | ||
| 1045 | } | 1062 | } |
| 1046 | } | 1063 | } |
| 1047 | 1064 | ||
| @@ -1074,7 +1091,7 @@ char **argv; | |||
| 1074 | relayhost = 0; | 1091 | relayhost = 0; |
| 1075 | for (i = 0;i <= host.len;++i) | 1092 | for (i = 0;i <= host.len;++i) |
| 1076 | if ((i == 0) || (i == host.len) || (host.s[i] == '.')) | 1093 | if ((i == 0) || (i == host.len) || (host.s[i] == '.')) |
| 1077 | if (relayhost = constmap(&maproutes,host.s + i,host.len - i)) | 1094 | if ((relayhost = constmap(&maproutes,host.s + i,host.len - i))) |
| 1078 | break; | 1095 | break; |
| 1079 | if (relayhost && !*relayhost) relayhost = 0; | 1096 | if (relayhost && !*relayhost) relayhost = 0; |
| 1080 | 1097 | ||
diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 5ea23dc..0d3b16d 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c | |||
| @@ -67,8 +67,6 @@ static const stralloc *client_get_session_id(); | |||
| 67 | 67 | ||
| 68 | #ifdef TLS | 68 | #ifdef TLS |
| 69 | # include <sys/stat.h> | 69 | # include <sys/stat.h> |
| 70 | # include <openssl/bn.h> | ||
| 71 | # include <openssl/dh.h> | ||
| 72 | # include "tls.h" | 70 | # include "tls.h" |
| 73 | # include "ssl_timeoutio.h" | 71 | # include "ssl_timeoutio.h" |
| 74 | 72 | ||
| @@ -208,7 +206,7 @@ int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\ | |||
| 208 | void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); } | 206 | void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); } |
| 209 | void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); do_hard_errors(); } | 207 | void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); do_hard_errors(); } |
| 210 | int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); do_hard_errors(); return -1; } | 208 | int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); do_hard_errors(); return -1; } |
| 211 | int err_noauth2() { out("503 auth not available (#5.3.3)\r\n"); do_hard_errors(); } | 209 | int err_noauth2() { out("503 auth not available (#5.3.3)\r\n"); do_hard_errors(); return -1; } |
| 212 | int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; } | 210 | int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; } |
| 213 | int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; } | 211 | int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; } |
| 214 | int err_wantstarttls() { out("530 Must issue a STARTTLS command first (#5.7.0)\r\n"); return -1; }; | 212 | int err_wantstarttls() { out("530 Must issue a STARTTLS command first (#5.7.0)\r\n"); return -1; }; |
| @@ -386,7 +384,7 @@ char *arg; | |||
| 386 | if (!stralloc_copys(&addr,"")) die_nomem(); | 384 | if (!stralloc_copys(&addr,"")) die_nomem(); |
| 387 | flagesc = 0; | 385 | flagesc = 0; |
| 388 | flagquoted = 0; | 386 | flagquoted = 0; |
| 389 | for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */ | 387 | for (i = 0; (ch = arg[i]); ++i) { /* copy arg to addr, stripping quotes */ |
| 390 | if (flagesc) { | 388 | if (flagesc) { |
| 391 | if (!stralloc_append(&addr,&ch)) die_nomem(); | 389 | if (!stralloc_append(&addr,&ch)) die_nomem(); |
| 392 | flagesc = 0; | 390 | flagesc = 0; |
| @@ -485,7 +483,7 @@ int bmcheck(which) int which; | |||
| 485 | } | 483 | } |
| 486 | if ((negate) && (x == 0)) { | 484 | if ((negate) && (x == 0)) { |
| 487 | if (!stralloc_copyb(&matchedregex,bmb.s + j - 1,(i - j + 1))) die_nomem(); | 485 | if (!stralloc_copyb(&matchedregex,bmb.s + j - 1,(i - j + 1))) die_nomem(); |
| 488 | if (!stralloc_0(&matchedregex)) die_nomem(); | 486 | if (!stralloc_0(&matchedregex)) die_nomem(); |
| 489 | return 1; | 487 | return 1; |
| 490 | } | 488 | } |
| 491 | if (!(negate) && (x > 0)) { | 489 | if (!(negate) && (x > 0)) { |
| @@ -582,8 +580,6 @@ void mailfrom_auth(arg,len) | |||
| 582 | char *arg; | 580 | char *arg; |
| 583 | int len; | 581 | int len; |
| 584 | { | 582 | { |
| 585 | int j; | ||
| 586 | |||
| 587 | if (!stralloc_copys(&fuser,"")) die_nomem(); | 583 | if (!stralloc_copys(&fuser,"")) die_nomem(); |
| 588 | if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); } | 584 | if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); } |
| 589 | else | 585 | else |
| @@ -610,7 +606,7 @@ void mailfrom_parms(arg) char *arg; | |||
| 610 | int len; | 606 | int len; |
| 611 | 607 | ||
| 612 | len = str_len(arg); | 608 | len = str_len(arg); |
| 613 | if (!stralloc_copys(&mfparms,"")) die_nomem; | 609 | if (!stralloc_copys(&mfparms,"")) die_nomem(); |
| 614 | i = byte_chr(arg,len,'>'); | 610 | i = byte_chr(arg,len,'>'); |
| 615 | if (i > 4 && i < len) { | 611 | if (i > 4 && i < len) { |
| 616 | while (len) { | 612 | while (len) { |
| @@ -622,10 +618,10 @@ void mailfrom_parms(arg) char *arg; | |||
| 622 | if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; } | 618 | if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; } |
| 623 | /* we do not support this */ | 619 | /* we do not support this */ |
| 624 | //if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5); | 620 | //if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5); |
| 625 | if (!stralloc_copys(&mfparms,"")) die_nomem; | 621 | if (!stralloc_copys(&mfparms,"")) die_nomem(); |
| 626 | } | 622 | } |
| 627 | else | 623 | else |
| 628 | if (!stralloc_catb(&mfparms,arg,1)) die_nomem; | 624 | if (!stralloc_catb(&mfparms,arg,1)) die_nomem(); |
| 629 | } | 625 | } |
| 630 | } | 626 | } |
| 631 | } | 627 | } |
| @@ -1094,17 +1090,17 @@ int authenticate(void) | |||
| 1094 | if (authout.len > 0) { | 1090 | if (authout.len > 0) { |
| 1095 | len = authout.len; | 1091 | len = authout.len; |
| 1096 | arg = authout.s; | 1092 | arg = authout.s; |
| 1097 | if (!stralloc_copys(&authparams, "")) die_nomem; | 1093 | if (!stralloc_copys(&authparams, "")) die_nomem(); |
| 1098 | while (len) { | 1094 | while (len) { |
| 1099 | if (*arg == '\0') { | 1095 | if (*arg == '\0') { |
| 1100 | if (case_starts(authparams.s, "USER=") && (authparams.len - 5) > 0) { | 1096 | if (case_starts(authparams.s, "USER=") && (authparams.len - 5) > 0) { |
| 1101 | if (!stralloc_copyb(&user, authparams.s + 5, authparams.len - 5)) die_nomem(); | 1097 | if (!stralloc_copyb(&user, authparams.s + 5, authparams.len - 5)) die_nomem(); |
| 1102 | if (!stralloc_0(&user)) die_nomem(); | 1098 | if (!stralloc_0(&user)) die_nomem(); |
| 1103 | } | 1099 | } |
| 1104 | if (!stralloc_copys(&authparams, "")) die_nomem; | 1100 | if (!stralloc_copys(&authparams, "")) die_nomem(); |
| 1105 | } | 1101 | } |
| 1106 | else | 1102 | else |
| 1107 | if (!stralloc_catb(&authparams, arg, 1)) die_nomem; | 1103 | if (!stralloc_catb(&authparams, arg, 1)) die_nomem(); |
| 1108 | arg++; | 1104 | arg++; |
| 1109 | len--; | 1105 | len--; |
| 1110 | } | 1106 | } |
| @@ -1130,19 +1126,19 @@ int auth_login(arg) char *arg; | |||
| 1130 | if (tls_before_auth && !ssl) return err_wantstarttls(); | 1126 | if (tls_before_auth && !ssl) return err_wantstarttls(); |
| 1131 | #endif | 1127 | #endif |
| 1132 | if (*arg) { | 1128 | if (*arg) { |
| 1133 | if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input(); | 1129 | if ((r = b64decode(arg,str_len(arg),&user)) == 1) return err_input(); |
| 1134 | } | 1130 | } |
| 1135 | else { | 1131 | else { |
| 1136 | out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */ | 1132 | out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */ |
| 1137 | if (authgetl() < 0) return -1; | 1133 | if (authgetl() < 0) return -1; |
| 1138 | if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input(); | 1134 | if ((r = b64decode(authin.s,authin.len,&user)) == 1) return err_input(); |
| 1139 | } | 1135 | } |
| 1140 | if (r == -1) die_nomem(); | 1136 | if (r == -1) die_nomem(); |
| 1141 | 1137 | ||
| 1142 | out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */ | 1138 | out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */ |
| 1143 | 1139 | ||
| 1144 | if (authgetl() < 0) return -1; | 1140 | if (authgetl() < 0) return -1; |
| 1145 | if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input(); | 1141 | if ((r = b64decode(authin.s,authin.len,&pass)) == 1) return err_input(); |
| 1146 | if (r == -1) die_nomem(); | 1142 | if (r == -1) die_nomem(); |
| 1147 | 1143 | ||
| 1148 | if (!user.len || !pass.len) return err_input(); | 1144 | if (!user.len || !pass.len) return err_input(); |
| @@ -1157,12 +1153,12 @@ int auth_plain(arg) char *arg; | |||
| 1157 | if (tls_before_auth && !ssl) return err_wantstarttls(); | 1153 | if (tls_before_auth && !ssl) return err_wantstarttls(); |
| 1158 | #endif | 1154 | #endif |
| 1159 | if (*arg) { | 1155 | if (*arg) { |
| 1160 | if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input(); | 1156 | if ((r = b64decode(arg,str_len(arg),&resp)) == 1) return err_input(); |
| 1161 | } | 1157 | } |
| 1162 | else { | 1158 | else { |
| 1163 | out("334 \r\n"); flush(); | 1159 | out("334 \r\n"); flush(); |
| 1164 | if (authgetl() < 0) return -1; | 1160 | if (authgetl() < 0) return -1; |
| 1165 | if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input(); | 1161 | if ((r = b64decode(authin.s,authin.len,&resp)) == 1) return err_input(); |
| 1166 | } | 1162 | } |
| 1167 | if (r == -1 || !stralloc_0(&resp)) die_nomem(); | 1163 | if (r == -1 || !stralloc_0(&resp)) die_nomem(); |
| 1168 | while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */ | 1164 | while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */ |
| @@ -1297,140 +1293,6 @@ void smtp_tls(char *arg) | |||
| 1297 | else tls_init(); | 1293 | else tls_init(); |
| 1298 | } | 1294 | } |
| 1299 | 1295 | ||
| 1300 | /* | ||
| 1301 | * Grab well-defined DH parameters from OpenSSL, see the get_rfc* | ||
| 1302 | * functions in <openssl/bn.h> for all available primes. | ||
| 1303 | */ | ||
| 1304 | #if OPENSSL_VERSION_NUMBER < 0x10100005L | ||
| 1305 | static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) | ||
| 1306 | { | ||
| 1307 | /* q is optional */ | ||
| 1308 | if (p == NULL || g == NULL) | ||
| 1309 | return 0; | ||
| 1310 | BN_free(dh->p); | ||
| 1311 | BN_free(dh->q); | ||
| 1312 | BN_free(dh->g); | ||
| 1313 | dh->p = p; | ||
| 1314 | dh->q = q; | ||
| 1315 | dh->g = g; | ||
| 1316 | |||
| 1317 | if (q != NULL) | ||
| 1318 | dh->length = BN_num_bits(q); | ||
| 1319 | |||
| 1320 | return 1; | ||
| 1321 | } | ||
| 1322 | #endif | ||
| 1323 | |||
| 1324 | static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *)) | ||
| 1325 | { | ||
| 1326 | BIGNUM *p, *g; | ||
| 1327 | DH *dh = DH_new(); | ||
| 1328 | if (!dh) | ||
| 1329 | return NULL; | ||
| 1330 | |||
| 1331 | p = prime(NULL); | ||
| 1332 | g = BN_new(); | ||
| 1333 | if (g != NULL) | ||
| 1334 | BN_set_word(g, 2); | ||
| 1335 | if (!p || !g || !DH_set0_pqg(dh, p, NULL, g)) { | ||
| 1336 | DH_free(dh); | ||
| 1337 | BN_free(p); | ||
| 1338 | BN_free(g); | ||
| 1339 | return NULL; | ||
| 1340 | } | ||
| 1341 | return dh; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | /* Storage and initialization for DH parameters. */ | ||
| 1345 | static struct dhparam { | ||
| 1346 | BIGNUM *(*const prime)(BIGNUM *); /* function to generate... */ | ||
| 1347 | DH *dh; /* ...this, used for keys.... */ | ||
| 1348 | const unsigned int min; /* ...of length >= this. */ | ||
| 1349 | } dhparams[] = { | ||
| 1350 | { get_rfc3526_prime_8192, NULL, 6145 }, | ||
| 1351 | { get_rfc3526_prime_6144, NULL, 4097 }, | ||
| 1352 | { get_rfc3526_prime_4096, NULL, 3073 }, | ||
| 1353 | { get_rfc3526_prime_3072, NULL, 2049 }, | ||
| 1354 | { get_rfc3526_prime_2048, NULL, 1025 }, | ||
| 1355 | { get_rfc2409_prime_1024, NULL, 0 } | ||
| 1356 | }; | ||
| 1357 | |||
| 1358 | /* Hand out the same DH structure though once generated as we leak | ||
| 1359 | * memory otherwise and freeing the structure up after use would be | ||
| 1360 | * hard to track and in fact is not needed at all as it is safe to | ||
| 1361 | * use the same parameters over and over again security wise (in | ||
| 1362 | * contrast to the keys itself) and code safe as the returned structure | ||
| 1363 | * is duplicated by OpenSSL anyway. Hence no modification happens | ||
| 1364 | * to our copy. */ | ||
| 1365 | static DH *tmp_dh_cb(SSL *ssl, int export, int keylen) | ||
| 1366 | { | ||
| 1367 | EVP_PKEY *pkey = SSL_get_privatekey(ssl); | ||
| 1368 | int type = pkey ? EVP_PKEY_base_id(pkey) : EVP_PKEY_NONE; | ||
| 1369 | unsigned n; | ||
| 1370 | |||
| 1371 | /* | ||
| 1372 | * OpenSSL will call us with either keylen == 512 or keylen == 1024 | ||
| 1373 | * (see the definition of SSL_EXPORT_PKEYLENGTH in ssl_locl.h). | ||
| 1374 | * Adjust the DH parameter length according to the size of the | ||
| 1375 | * RSA/DSA private key used for the current connection, and always | ||
| 1376 | * use at least 1024-bit parameters. | ||
| 1377 | * Note: This may cause interoperability issues with implementations | ||
| 1378 | * which limit their DH support to 1024 bit - e.g. Java 7 and earlier. | ||
| 1379 | * In this case, SSLCertificateFile can be used to specify fixed | ||
| 1380 | * 1024-bit DH parameters (with the effect that OpenSSL skips this | ||
| 1381 | * callback). | ||
| 1382 | */ | ||
| 1383 | if (type == EVP_PKEY_RSA || type == EVP_PKEY_DSA) | ||
| 1384 | keylen = EVP_PKEY_bits(pkey); | ||
| 1385 | |||
| 1386 | for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) { | ||
| 1387 | if (keylen >= dhparams[n].min) { | ||
| 1388 | if (dhparams[n].dh == NULL) | ||
| 1389 | dhparams[n].dh = make_dh_params(dhparams[n].prime); | ||
| 1390 | return dhparams[n].dh; | ||
| 1391 | } | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | return NULL; /* impossible to reach. */ | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | static DH *ssl_dh_GetParamFromFile(const char *file) | ||
| 1398 | { | ||
| 1399 | DH *dh = NULL; | ||
| 1400 | BIO *bio; | ||
| 1401 | |||
| 1402 | if ((bio = BIO_new_file(file, "r")) == NULL) | ||
| 1403 | return NULL; | ||
| 1404 | dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); | ||
| 1405 | BIO_free(bio); | ||
| 1406 | if (!dh) | ||
| 1407 | (void)ERR_get_error(); | ||
| 1408 | return dh; | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | #ifdef HAVE_ECC | ||
| 1412 | static EC_GROUP *ssl_ec_GetParamFromFile(const char *file) | ||
| 1413 | { | ||
| 1414 | EC_GROUP *group = NULL; | ||
| 1415 | BIO *bio; | ||
| 1416 | |||
| 1417 | if ((bio = BIO_new_file(file, "r")) == NULL) | ||
| 1418 | return NULL; | ||
| 1419 | group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); | ||
| 1420 | BIO_free(bio); | ||
| 1421 | if (!group) | ||
| 1422 | (void)ERR_get_error(); | ||
| 1423 | return group; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | #if !defined(SSL_set_ecdh_auto) | ||
| 1427 | static EC_KEY *tmp_ecdh_cb(SSL *ssl, int export, int keylen) | ||
| 1428 | { | ||
| 1429 | return EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); | ||
| 1430 | } | ||
| 1431 | #endif | ||
| 1432 | #endif | ||
| 1433 | |||
| 1434 | /* don't want to fail handshake if cert isn't verifiable */ | 1296 | /* don't want to fail handshake if cert isn't verifiable */ |
| 1435 | int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } | 1297 | int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } |
| 1436 | 1298 | ||
| @@ -1455,15 +1317,7 @@ void tls_init() | |||
| 1455 | SSL_CTX *ctx; | 1317 | SSL_CTX *ctx; |
| 1456 | const char *ciphers; | 1318 | const char *ciphers; |
| 1457 | stralloc saciphers = {0}; | 1319 | stralloc saciphers = {0}; |
| 1458 | X509_STORE *store; | ||
| 1459 | X509_LOOKUP *lookup; | ||
| 1460 | const char *servercert, *servercert2; | 1320 | const char *servercert, *servercert2; |
| 1461 | DH *dhparams; | ||
| 1462 | #ifdef HAVE_ECC | ||
| 1463 | EC_GROUP *ecparams; | ||
| 1464 | int nid; | ||
| 1465 | EC_KEY *eckey = NULL; | ||
| 1466 | #endif | ||
| 1467 | struct stat st; | 1321 | struct stat st; |
| 1468 | 1322 | ||
| 1469 | /* if set, use servercert selected through SMTP_SERVERCERT env var */ | 1323 | /* if set, use servercert selected through SMTP_SERVERCERT env var */ |
| @@ -1475,7 +1329,7 @@ void tls_init() | |||
| 1475 | SSL_library_init(); | 1329 | SSL_library_init(); |
| 1476 | 1330 | ||
| 1477 | /* a new SSL context with the bare minimum of options */ | 1331 | /* a new SSL context with the bare minimum of options */ |
| 1478 | ctx = SSL_CTX_new(SSLv23_server_method()); | 1332 | ctx = SSL_CTX_new(TLS_server_method()); |
| 1479 | if (!ctx) { tls_err("unable to initialize ctx"); return; } | 1333 | if (!ctx) { tls_err("unable to initialize ctx"); return; } |
| 1480 | int min_ssl_version = (*childargs) ? TLS1_2_VERSION : TLS1_VERSION; | 1334 | int min_ssl_version = (*childargs) ? TLS1_2_VERSION : TLS1_VERSION; |
| 1481 | SSL_CTX_set_min_proto_version(ctx, min_ssl_version); | 1335 | SSL_CTX_set_min_proto_version(ctx, min_ssl_version); |
| @@ -1490,13 +1344,13 @@ void tls_init() | |||
| 1490 | 1344 | ||
| 1491 | /* this will also check whether public and private keys match */ | 1345 | /* this will also check whether public and private keys match */ |
| 1492 | if (!SSL_CTX_use_PrivateKey_file(ctx, servercert, SSL_FILETYPE_PEM)) | 1346 | if (!SSL_CTX_use_PrivateKey_file(ctx, servercert, SSL_FILETYPE_PEM)) |
| 1493 | { SSL_free(myssl); tls_err("no valid private key"); return; } | 1347 | { SSL_CTX_free(ctx); tls_err("no valid private key"); return; } |
| 1494 | 1348 | ||
| 1495 | if (stat(servercert2, &st) == 0) { | 1349 | if (stat(servercert2, &st) == 0) { |
| 1496 | if (!SSL_CTX_use_certificate_chain_file(ctx, servercert2)) | 1350 | if (!SSL_CTX_use_certificate_chain_file(ctx, servercert2)) |
| 1497 | { SSL_CTX_free(ctx); tls_err("missing alternate certificate"); return; } | 1351 | { SSL_CTX_free(ctx); tls_err("invalid alternate certificate"); return; } |
| 1498 | if (!SSL_CTX_use_PrivateKey_file(ctx, servercert2, SSL_FILETYPE_PEM)) | 1352 | if (!SSL_CTX_use_PrivateKey_file(ctx, servercert2, SSL_FILETYPE_PEM)) |
| 1499 | { SSL_free(myssl); tls_err("no valid alternate private key"); return; } | 1353 | { SSL_CTX_free(ctx); tls_err("no valid alternate private key"); return; } |
| 1500 | } | 1354 | } |
| 1501 | 1355 | ||
| 1502 | /* a new SSL object, with the rest added to it directly to avoid copying */ | 1356 | /* a new SSL object, with the rest added to it directly to avoid copying */ |
| @@ -1519,39 +1373,17 @@ void tls_init() | |||
| 1519 | SSL_set_cipher_list(myssl, ciphers); | 1373 | SSL_set_cipher_list(myssl, ciphers); |
| 1520 | alloc_free(saciphers.s); | 1374 | alloc_free(saciphers.s); |
| 1521 | 1375 | ||
| 1522 | //TODO: we shouldn't use hardcoded DH: see https://weakdh.org/ | 1376 | SSL_set_dh_auto(myssl, 1); |
| 1523 | SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); | 1377 | SSL_set_ecdh_auto(myssl, 1); |
| 1524 | |||
| 1525 | /* try to read DH parameters from certificate */ | ||
| 1526 | if ((dhparams = ssl_dh_GetParamFromFile(servercert))) | ||
| 1527 | SSL_set_tmp_dh(myssl, dhparams); | ||
| 1528 | |||
| 1529 | #ifdef HAVE_ECC | ||
| 1530 | /* similarly, try to read the ECDH curve name from certificate... */ | ||
| 1531 | if ((ecparams = ssl_ec_GetParamFromFile(servercert)) && | ||
| 1532 | (nid = EC_GROUP_get_curve_name(ecparams)) && | ||
| 1533 | (eckey = EC_KEY_new_by_curve_name(nid))) { | ||
| 1534 | SSL_set_tmp_ecdh(myssl, eckey); | ||
| 1535 | } | ||
| 1536 | else { | ||
| 1537 | #if defined(SSL_set_ecdh_auto) | ||
| 1538 | /* ...otherwise, enable auto curve selection (OpenSSL 1.0.2 and later) */ | ||
| 1539 | SSL_set_ecdh_auto(myssl, 1); | ||
| 1540 | #else | ||
| 1541 | /* or set callback, which will configure NIST P-256 */ | ||
| 1542 | SSL_set_tmp_ecdh_callback(myssl, tmp_ecdh_cb); | ||
| 1543 | #endif | ||
| 1544 | } | ||
| 1545 | EC_KEY_free(eckey); | ||
| 1546 | #endif | ||
| 1547 | 1378 | ||
| 1548 | #if OPENSSL_VERSION_NUMBER >= 0x10100005L | ||
| 1549 | stralloc opensslconf = {0}; | 1379 | stralloc opensslconf = {0}; |
| 1550 | if (control_readfile(&opensslconf, "control/opensslconf", 0) == -1) | 1380 | if (control_readfile(&opensslconf, "control/opensslconf", 0) == -1) |
| 1551 | { SSL_free(myssl); die_control(); } | 1381 | { SSL_free(myssl); die_control(); } |
| 1552 | if (opensslconf.len) { | 1382 | if (opensslconf.len) { |
| 1553 | SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); | 1383 | SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); |
| 1554 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); | 1384 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); |
| 1385 | /* client + server so we can share one single file */ | ||
| 1386 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); | ||
| 1555 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); | 1387 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); |
| 1556 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); | 1388 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); |
| 1557 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); | 1389 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); |
| @@ -1579,7 +1411,6 @@ void tls_init() | |||
| 1579 | 1411 | ||
| 1580 | (void)SSL_CONF_CTX_finish(cctx); | 1412 | (void)SSL_CONF_CTX_finish(cctx); |
| 1581 | } | 1413 | } |
| 1582 | #endif | ||
| 1583 | 1414 | ||
| 1584 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); | 1415 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); |
| 1585 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); | 1416 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); |
