diff -urN -bw sendmail-8.16.0.original/sendmail/conf.c sendmail-8.16.0.new/sendmail/conf.c --- sendmail-8.16.0.original/sendmail/conf.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/conf.c 2018-10-13 13:14:57.573138086 -0700 @@ -6693,6 +6693,10 @@ "_FFR_TLSA_DANE", #endif +#if _FFR_TLSA_DANE2 + /* experimental DANE support using openssl */ + "_FFR_TLSA_DANE2", +#endif #if _FFR_TLSFB2CLEAR /* set default for TLSFallbacktoClear to true */ "_FFR_TLSFB2CLEAR", diff -urN -bw sendmail-8.16.0.original/sendmail/deliver.c sendmail-8.16.0.new/sendmail/deliver.c --- sendmail-8.16.0.original/sendmail/deliver.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/deliver.c 2018-10-13 13:14:57.600139065 -0700 @@ -2918,7 +2918,7 @@ macid("{server_addr}"), "0"); } -# if _FFR_TLSA_DANE +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 SM_FREE(Dane_vrfy_ctx.dane_vrfy_host); Dane_vrfy_ctx.dane_vrfy_host = sm_strdup(srvname); # endif @@ -2936,6 +2936,13 @@ Dane_vrfy_ctx.dane_vrfy_res = 0; } # endif +# if _FFR_TLSA_DANE2 + if (DONE_STARTTLS(mci->mci_flags)) + { + /* use a "reset" function? */ + SM_FREE(Dane_vrfy_ctx.dane_vrfy_host); + } +# endif # endif /* STARTTLS || SASL */ @@ -2987,6 +2994,29 @@ bool saveSuprErrs = SuprErrs; char *host = NULL; +# if _FFR_TLSA_DANE2 + host = macvalue(macid("{server_name}"), e); + rcode = EX_OK; + usetls = bitset(MCIF_TLS, mci->mci_flags); + if (usetls) + { + /* starttls advertised, but we might want to ignore it */ + usetls = !iscltflgset(e, D_NOTLS); + if (!usetls) sm_syslog(LOG_ERR, e->e_id, "!!starttls advertised by %s, but we ignore it", host); + } + else + { + /* starttls not advertised by the connected server */ + STAB *s; + s = stab(host, ST_TLSA_RR, ST_FIND); + if (s && s->s_tlsa && (s->s_tlsa->dane_tlsa_n > 0)) + { + /* but we have tlsa records, kill it */ + sm_syslog(LOG_ERR, e->e_id, "!!have tlsa records, but starttls not advertised by %s", host); + rcode = EX_SOFTWARE; + } + } +# else rcode = EX_OK; usetls = bitset(MCIF_TLS, mci->mci_flags); if (usetls) @@ -2995,6 +3025,7 @@ usetls = tlsstate == 0; host = macvalue(macid("{server_name}"), e); +# endif /* _FFR_TLSA_DANE2 */ if (usetls) { olderrors = Errors; @@ -3145,6 +3176,9 @@ && Dane_vrfy_ctx.dane_vrfy_chk != DANE_SECURE #endif +#if _FFR_TLSA_DANE2 + && Dane_vrfy_ctx.dane_vrfy_chk != DANE_NEVER +#endif ) { ++tlsstate; @@ -6281,6 +6315,9 @@ SSL *clt_ssl = NULL; time_t tlsstart; extern int TLSsslidx; +#if _FFR_TLSA_DANE2 + STAB *s; +#endif if (clt_ctx == NULL && !initclttls(true)) return EX_TEMPFAIL; @@ -6316,6 +6353,45 @@ if (LogLevel > 13) sm_syslog(LOG_INFO, NOQID, "STARTTLS=client, start=ok"); +# if _FFR_TLSA_DANE2 + Dane_vrfy_ctx.dane_vrfy_chk = DANE_NEVER; + + /* get tls_clt_features to see if we disable dane for this server */ + if (get_tls_se_options(e, NULL, &mci->mci_tlsi, false) != 0) + { + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=client, get_tls_se_options=fail"); + return EX_SOFTWARE; + } + + /* we are not disabling dane for this server, and want dane in general */ + if (!SM_TLSI_IS(&(mci->mci_tlsi), TLSI_FL_NODANE) && Dane) + { + s = stab(Dane_vrfy_ctx.dane_vrfy_host, ST_TLSA_RR, ST_FIND); + if (tTd(96, 4)) + sm_dprintf("dane_verify, host=%s, s=%p\n", + Dane_vrfy_ctx.dane_vrfy_host, s); + if (s && s->s_tlsa && (s->s_tlsa->dane_tlsa_n > 0)) + { + /* + ** and we have tlsa records - ok, do dane, disable the certificate + ** callback, and let openssl/dane do the right thing. + */ + Dane_vrfy_ctx.dane_vrfy_chk = Dane; + SSL_CTX_set_cert_verify_callback(clt_ctx, NULL, NULL); + SSL_CTX_set_verify(clt_ctx, SSL_VERIFY_NONE, dane_verify_cb); + if (SSL_CTX_dane_enable(clt_ctx) <= 0) + { + if (LogLevel > 7) + sm_syslog(LOG_ERR, NOQID, "STARTTLS=client, error: SSL_CTX_dane_enable() failed"); + tlslogerr(LOG_WARNING, 9, "client"); + return EX_SOFTWARE; + } + SSL_CTX_dane_set_flags(clt_ctx, DANE_FLAG_NO_DANE_EE_NAMECHECKS); + } + } +# endif /* _FFR_TLSA_DANE2 */ + /* start connection */ if ((clt_ssl = SSL_new(clt_ctx)) == NULL) { @@ -6329,6 +6405,84 @@ } /* SSL_clear(clt_ssl); ? */ +# if _FFR_TLSA_DANE2 + { + if (Dane_vrfy_ctx.dane_vrfy_chk) + { + int i; + dane_tlsa_P dane_tlsa; + dane_tlsa = s->s_tlsa; + if (SSL_dane_enable(clt_ssl, Dane_vrfy_ctx.dane_vrfy_host) <= 0) + { + if (LogLevel > 5) + { + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=client, error: SSL_dane_enable() failed"); + tlslogerr(LOG_WARNING, 9, "client"); + } + return EX_SOFTWARE; + } + Dane_vrfy_ctx.dane_vrfy_usable = 0; + if (dane_tlsa->dane_tlsa_ignoremx) + { + unsigned char digest[32]; + unsigned char hexbuf[512]; + memset(digest, '\0', sizeof(digest)); + if (LogLevel > 5) + { + data2hex(digest, sizeof(digest), hexbuf, sizeof(hexbuf)); + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=tlsa created 3 0 1 for %s, len %d %s", + Dane_vrfy_ctx.dane_vrfy_host, sizeof(digest), hexbuf); + } + if (SSL_dane_tlsa_add(clt_ssl, 3, 0, 1, digest, sizeof(digest)) <= 0) + { + if (LogLevel > 13) + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=tlsa mxignore record not added to context"); + } + else + { + Dane_vrfy_ctx.dane_vrfy_usable++; + } + } + else + for (i = 0; i < dane_tlsa->dane_tlsa_n; i++) + { + char *p; + int l; + unsigned char hexbuf[512]; + uint8_t usage, selector, match; + p = dane_tlsa->dane_tlsa_rr[i]; + l = dane_tlsa->dane_tlsa_len[i]; + usage = (uint8_t)(*p); + selector = (uint8_t)(*(p+1)); + match = (uint8_t)(*(p+2)); + if (LogLevel > 5) + { + data2hex((unsigned char *)(p+3), l-3, hexbuf, sizeof(hexbuf)); + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=tlsa found %d %d %d for %s, len %d %s", + usage, selector, match, Dane_vrfy_ctx.dane_vrfy_host, l-3, hexbuf); + } + if ((usage < 2) || (usage > 3) || + (SSL_dane_tlsa_add(clt_ssl, usage, selector, match, + (const unsigned char *)(p+3), l-3) <= 0)) + { + if (LogLevel > 13) + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=tlsa record not added to context"); + } + else + { + Dane_vrfy_ctx.dane_vrfy_usable++; + } + } + } + } + + /* get options again, this time setting clt_ssl options */ +# endif /* _FFR_TLSA_DANE2 */ if (get_tls_se_options(e, clt_ssl, &mci->mci_tlsi, false) != 0) { sm_syslog(LOG_ERR, NOQID, @@ -6353,7 +6507,6 @@ else Dane_vrfy_ctx.dane_vrfy_chk = Dane; #endif - rfd = sm_io_getinfo(mci->mci_in, SM_IO_WHAT_FD, NULL); wfd = sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD, NULL); diff -urN -bw sendmail-8.16.0.original/sendmail/domain.c sendmail-8.16.0.new/sendmail/domain.c --- sendmail-8.16.0.original/sendmail/domain.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/domain.c 2018-10-13 13:34:11.651960732 -0700 @@ -23,10 +23,10 @@ #if NAMED_BIND # include -# if _FFR_TLSA_DANE || DNSSEC_TEST +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 || DNSSEC_TEST # include # endif -# if _FFR_TLSA_DANE +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 # include # endif @@ -294,6 +294,307 @@ } #endif /* _FFR_TLSA_DANE */ +# if _FFR_TLSA_DANE2 + +/* +** TLSAADD -- add TLSA records to dane_tlsa entry +** +** Parameters: +** host -- host name used in TLSA lookup +** r -- DNS data for TLSA lookup of _25._tcp.host +** dane_tlsa -- dane_tlsa entry +** n -- current number of TLSA records in dane_tlsa entry +** pttl -- (pointer to) TTL (in/out) +** level -- recursion level (CNAMEs) +** ad -- all the lookups that ended with finding this host were secure +** +** Returns: +** new number of TLSA records +*/ + +static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, + unsigned int *, int, bool)); + +static int +tlsaadd(host, r, dane_tlsa, n, pttl, level, ad) + const char *host; + DNS_REPLY_T *r; + dane_tlsa_P dane_tlsa; + int n; + unsigned int *pttl; + int level; + bool ad; +{ + RESOURCE_RECORD_T *rr; + unsigned int ttl; + + /* host lookup was secure, but tlsa query times out */ + if (ad && (r == NULL) && + ((h_errno == TRY_AGAIN) || (h_errno == NO_RECOVERY))) + { + DNS_REPLY_T *rc; + if ((rc = dns_lookup_int(host, C_IN, T_A, 0, 0, 0, RR_RAW)) != NULL) + { + /* A record lookup was also secure, so the TLSA timeout */ + /* cannot be ignored */ + if (rc->dns_r_h.ad || rc->dns_r_h.aa) + { + sm_syslog(LOG_WARNING, NOQID, "!!timeout getting tlsa for secure host %s", host); + dane_tlsa->dane_tlsa_ignoremx = 1; + } + dns_free_data(rc); + } + } + + /* tlsa query returned no data? */ + if (r == NULL) + return n; + + /* secure all the way if host lookup secure and tlsa lookup secure */ + ad = ad && (r->dns_r_h.ad || r->dns_r_h.aa); + + /* not secure all the way, but we require that? */ + if (!ad && Dane == DANE_SECURE) + return n; + + ttl = *pttl; + for (rr = r->dns_r_head; rr != NULL && n < MAX_TLSA_RR; + rr = rr->rr_next) + { + if (rr->rr_type == T_CNAME && level >= MAXCNAMEDEPTH) + { + if (tTd(8, 2)) + sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n", + host, rr->rr_u.rr_txt, level); + break; + } + + if (rr->rr_type == T_CNAME) + { + DNS_REPLY_T *rc; + rc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0, 0, RR_RAW); + if (tTd(8, 2)) + sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, r=%p, ad=%d\n", + host, rr->rr_u.rr_txt, level, + rc, rc != NULL ? rc->dns_r_h.ad : -1); + n = tlsaadd(rr->rr_u.rr_txt, rc, dane_tlsa, n, pttl, level + 1, ad); + dns_free_data(rc); + break; + } + + if (rr->rr_type != T_TLSA) + { + if (tTd(8, 8)) + sm_dprintf("tlsaadd(%s), type=%s\n", host, + dns_type_to_string(rr->rr_type)); + continue; + } + if (dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, host, true) + != TLSA_OK) + continue; + + /* to do: the RRs should be sorted */ + dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data; + dane_tlsa->dane_tlsa_len[n] = rr->rr_size; + if (tTd(8, 2)) + { + unsigned char *p; + + p = rr->rr_u.rr_data; + sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", host, + n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]); + } + + /* require some minimum TTL? */ + if (ttl > rr->rr_ttl && rr->rr_ttl > 0) + ttl = rr->rr_ttl; + + /* hack: instead of copying the data, just "take it over" */ + rr->rr_u.rr_data = NULL; + ++n; + } + *pttl = ttl; + return n; +} + +/* +** GETTLSA -- get TLSA records for named host using DNS +** +** Parameters: +** host -- host +** ad -- all lookups that ended with finding this host were secure +** +** Returns: +** The number of TLSA records found. +** <0 if there is an internal failure. +*/ + +/* +To Do: +- port as option +- existing entries +- TTL +- ? +*/ + +static bool gettlsa __P((char *, bool)); + +static bool +gettlsa(host, ad) + char *host; + bool ad; +{ + unsigned short port; + DNS_REPLY_T *r; + int n_rrs; + dane_tlsa_P dane_tlsa; + STAB *s; + time_t now; + unsigned int ttl; + int len; + char nbuf[MAXDNAME]; + bool want_start; + + SM_REQUIRE(host != NULL); + SM_REQUIRE(*host != '\0'); + + now = 0; + r = NULL; + dane_tlsa = NULL; + len = strlen(host); + if (len > 1 && host[len - 1] == '.') + { + len --; + host[len] = '\0'; + } + else + len = -1; + s = stab(host, ST_TLSA_RR, ST_FIND); + if (s != NULL) + { + /* + ** already exists... just reuse it for now.. + ** should be "renewed" (replaced) instead. + */ + + dane_tlsa = s->s_tlsa; + if (dane_tlsa != NULL) + { + now = curtime(); + + if (dane_tlsa->dane_tlsa_exp > now) + dane_tlsa_clr(dane_tlsa); + else + n_rrs = dane_tlsa->dane_tlsa_n; + goto end; + } + s = NULL; + } + + if (tTd(8, 2)) + sm_dprintf("gettlsa(%s)\n", host); + + if (dane_tlsa == NULL) + { + dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa)); + if (dane_tlsa == NULL) + { + n_rrs = -1; + goto end; + } + memset(dane_tlsa, '\0', sizeof(*dane_tlsa)); + } + + port = 25; + n_rrs = 0; + ttl = UINT_MAX; + want_start = 1; + + /* look for cnames */ + { + int level = 1; + int more = 1; + strncpy(nbuf, host, sizeof(nbuf)); + while (more && (level < MAXCNAMEDEPTH)) + { + more = 0; + if ((r = dns_lookup_int(nbuf, C_IN, T_CNAME, 0, 0, 0, RR_RAW)) != NULL) + { + RESOURCE_RECORD_T *rr; + for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next) + { + if (rr->rr_type == T_CNAME) + { + strncpy(nbuf, rr->rr_u.rr_txt, sizeof(nbuf)); + level++; + ad = ad && (r->dns_r_h.ad || r->dns_r_h.aa); + more = 1; + break; + } + } + dns_free_data(r); + } + } + if (level > 1) + { + char nbuf2[MAXDNAME]; + (void) sm_snprintf(nbuf2, sizeof(nbuf2), "_%hu._tcp.%s", port, nbuf); + if ((r = dns_lookup_int(nbuf2, C_IN, T_TLSA, 0, 0, 0, RR_RAW)) != NULL) + { + if (ad && (r->dns_r_h.ad || r->dns_r_h.aa)) + { + n_rrs = tlsaadd(nbuf, r, dane_tlsa, n_rrs, &ttl, 0, ad); + if (n_rrs > 0) + want_start = 0; + } + dns_free_data(r); + } + } + } + + if (want_start) + { + (void) sm_snprintf(nbuf, sizeof(nbuf), "_%hu._tcp.%s", port, host); + r = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0, 0, RR_RAW); + if (tTd(8, 2)) + sm_dprintf("gettlsa(%s), r=%p, ad=%d\n", host, r, + r != NULL ? r->dns_r_h.ad : -1); + n_rrs = tlsaadd(host, r, dane_tlsa, n_rrs, &ttl, 0, ad); + dns_free_data(r); + } + + /* still no usable entries found, but we are ignoring this mx? */ + if ((n_rrs == 0) && dane_tlsa->dane_tlsa_ignoremx) + { + /* make up a dummy record so our count is 1 */ + dane_tlsa->dane_tlsa_rr[n_rrs] = sm_malloc(10); + dane_tlsa->dane_tlsa_len[n_rrs] = 10; + n_rrs++; + } + + dane_tlsa->dane_tlsa_n = n_rrs; + s = stab(host, ST_TLSA_RR, ST_ENTER); + if (s == NULL) + goto error; + s->s_tlsa = dane_tlsa; + if (now == 0) + now = curtime(); + dane_tlsa->dane_tlsa_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL); + goto end; + + error: + if (tTd(8, 2)) + sm_dprintf("gettlsa(%s), status=error\n", host); + n_rrs = -1; + dane_tlsa_free(dane_tlsa); + + end: + if (len > 0) + host[len] = '.'; + return n_rrs; +} +#endif /* _FFR_TLSA_DANE2 */ + /* ** GETFALLBACKMXRR -- get MX resource records for fallback MX host. ** @@ -538,7 +839,11 @@ return -1; } +# if _FFR_TLSA_DANE2 + ad = ad && (hp->ad || hp->aa); +# else ad = ad && hp->ad; +# endif /* _FFR_TLSA_DANE2 */ if (tTd(8, 2)) sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, hp, ad); @@ -579,7 +884,7 @@ if (type != T_MX) { if ((tTd(8, 8) || _res.options & RES_DEBUG) -# if _FFR_TLSA_DANE +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 && type != T_RRSIG # endif ) @@ -612,10 +917,16 @@ weight[nmx] = mxrand(bp); prefs[nmx] = pref; mxhosts[nmx++] = bp; + if (n) { # if _FFR_TLSA_DANE if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane)) gettlsa(bp); # endif +# if _FFR_TLSA_DANE2 + if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane)) + gettlsa(bp, ad); +# endif + } /* ** Note: n can be 0 for something like: @@ -814,6 +1125,14 @@ (ad && n == HOST_SECURE && DANE_SECURE == Dane)) gettlsa(mxhosts[0]); # endif +# if _FFR_TLSA_DANE2 + if (tTd(8, 3)) + sm_dprintf("getmxrr=%s, getcanonname=%d\n", + mxhosts[0], n); + if (DANE_ALWAYS == Dane || + (ad && n == HOST_SECURE && DANE_SECURE == Dane)) + gettlsa(mxhosts[0], ad); +# endif } } @@ -1235,8 +1554,13 @@ ap = (unsigned char *) &answer + HFIXEDSZ; eom = (unsigned char *) &answer + ret; +# if _FFR_TLSA_DANE2 + if (!hp->ad && !hp->aa) + ad = false; +# else if (0 == hp->ad) ad = false; +# endif /* skip question part of response -- we know what we asked */ for (qdcount = ntohs((unsigned short) hp->qdcount); diff -urN -bw sendmail-8.16.0.original/sendmail/main.c sendmail-8.16.0.new/sendmail/main.c --- sendmail-8.16.0.original/sendmail/main.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/main.c 2018-10-13 13:14:57.639140477 -0700 @@ -1346,7 +1346,7 @@ (void) sm_signal(SIGINT, intsig); (void) sm_signal(SIGTERM, intsig); -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 /* Turn on necessary resolver options for DANE */ if (Dane != DANE_NEVER) _res.options |= RES_USE_EDNS0|RES_USE_DNSSEC; diff -urN -bw sendmail-8.16.0.original/sendmail/readcf.c sendmail-8.16.0.new/sendmail/readcf.c --- sendmail-8.16.0.original/sendmail/readcf.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/readcf.c 2018-10-13 13:14:57.651140912 -0700 @@ -2217,6 +2217,9 @@ #ifdef SSL_OP_NO_TLSv1_2 { "SSL_OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2 }, #endif +#ifdef SSL_OP_NO_TLSv1_3 + { "SSL_OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3 }, +#endif #ifdef SSL_OP_NO_TLSv1_1 { "SSL_OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1 }, #endif @@ -2487,7 +2490,7 @@ ssloptions = 0; ret = readssloptions(NULL, val, &ssloptions, ';'); - if (ret == 0) + if ((ssl != NULL) && (ret == 0)) (void) SSL_set_options(ssl, (long) ssloptions); else if (LogLevel > 8) { @@ -2502,7 +2505,7 @@ } else if (sm_strcasecmp(opt, "cipherlist") == 0) { - if (SSL_set_cipher_list(ssl, val) <= 0) + if ((ssl != NULL) && (SSL_set_cipher_list(ssl, val) <= 0)) { ret = 1; if (LogLevel > 7) @@ -2544,7 +2547,7 @@ /* need cert and key before we can use the options */ /* does not implement the "," hack for 2nd cert/key pair */ - if (keyfile != NULL && certfile != NULL) + if (keyfile != NULL && certfile != NULL && ssl != NULL) { load_certkey(ssl, srv, certfile, keyfile); keyfile = certfile = NULL; @@ -2946,7 +2949,7 @@ # define O_NSPORTIP 0xf0 { "NameServer", O_NSPORTIP, OI_NONE }, #endif -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 # define O_DANE 0xf1 { "DANE", O_DANE, OI_NONE }, #endif @@ -4605,7 +4608,7 @@ break; #endif -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 case O_DANE: if (sm_strcasecmp(val, "always") == 0) Dane = DANE_ALWAYS; diff -urN -bw sendmail-8.16.0.original/sendmail/sendmail.h sendmail-8.16.0.new/sendmail/sendmail.h --- sendmail-8.16.0.original/sendmail/sendmail.h 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/sendmail.h 2018-10-13 13:14:57.660141239 -0700 @@ -44,7 +44,12 @@ #include "sendmail/sendmail.h" #if STARTTLS +# if _FFR_TLSA_DANE2 +# define OPENSSL_USE_DEPRECATED # include +# else +# include +#endif #endif /* profiling? */ @@ -124,7 +129,7 @@ # endif /* HESIOD */ #if STARTTLS -# if _FFR_TLSA_DANE +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 typedef struct dane_tlsa_S dane_tlsa_T, *dane_tlsa_P; typedef struct dane_vrfy_ctx_S dane_vrfy_ctx_T, *dane_vrfy_ctx_P; # endif @@ -1583,7 +1588,7 @@ struct milter *sv_milter; /* milter filter name */ #endif /* MILTER */ QUEUEGRP *sv_queue; /* pointer to queue */ -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 dane_tlsa_P sv_tlsa; /* pointer to TLSA RRs */ #endif } s_value; @@ -1617,7 +1622,7 @@ # define ST_SOCKETMAP 16 /* List head of maps for SOCKET connection */ #endif /* SOCKETMAP */ -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 # define ST_TLSA_RR 17 /* cached TLSA RRs */ #endif @@ -1646,7 +1651,7 @@ # define s_milter s_value.sv_milter #endif /* MILTER */ #define s_quegrp s_value.sv_queue -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 # define s_tlsa s_value.sv_tlsa #endif @@ -2439,7 +2444,7 @@ EXTERN int ConnRateThrottle; /* throttle for SMTP connection rate */ EXTERN int volatile CurChildren; /* current number of daemonic children */ EXTERN int CurrentLA; /* current load average */ -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 EXTERN int Dane; /* DANE */ #endif EXTERN int DefaultNotify; /* default DSN notification flags */ diff -urN -bw sendmail-8.16.0.original/sendmail/stab.c sendmail-8.16.0.new/sendmail/stab.c --- sendmail-8.16.0.original/sendmail/stab.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/stab.c 2018-10-13 13:14:57.666141455 -0700 @@ -175,7 +175,7 @@ break; #endif /* SOCKETMAP */ -# if _FFR_TLSA_DANE +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 case ST_TLSA_RR: len = sizeof(s->s_tlsa); break; diff -urN -bw sendmail-8.16.0.original/sendmail/tls.c sendmail-8.16.0.new/sendmail/tls.c --- sendmail-8.16.0.original/sendmail/tls.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/tls.c 2018-10-13 13:14:57.682142036 -0700 @@ -29,6 +29,7 @@ # ERROR: OpenSSL version OPENSSL_VERSION_NUMBER is unsupported. # endif +# if !_FFR_TLSA_DANE2 # if OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x20000000L # define MTA_HAVE_DH_set0_pqg 1 # define MTA_HAVE_DSA_GENERATE_EX 1 @@ -47,10 +48,9 @@ static RSA *rsa_tmp = NULL; /* temporary RSA key */ static RSA *tmp_rsa_key __P((SSL *, int, int)); # endif /* !TLS_NO_RSA && MTA_RSA_TMP_CB */ +# endif /* !_FFR_TLSA_DANE2 */ static int tls_verify_cb __P((X509_STORE_CTX *, void *)); - static int x509_verify_cb __P((int, X509_STORE_CTX *)); - static void apps_ssl_info_cb __P((const SSL *, int , int)); static bool tls_ok_f __P((char *, char *, int)); static bool tls_safe_f __P((char *, long, bool)); @@ -58,6 +58,7 @@ int TLSsslidx = -1; +# if !_FFR_TLSA_DANE2 # if !NO_DH # include static DH *get_dh512 __P((void)); @@ -177,6 +178,7 @@ return(dh); } # endif /* !NO_DH */ +# endif /* !_FFR_TLSA_DANE2 */ /* @@ -834,7 +836,11 @@ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); +#if _FFR_TLSA_DANE2 + X509_STORE_set_verify_cb(store, x509_verify_cb); +#else X509_STORE_set_verify_cb_func(store, x509_verify_cb); +#endif return true; } @@ -889,7 +895,11 @@ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); +#if _FFR_TLSA_DANE2 + X509_STORE_set_verify_cb(store, x509_verify_cb); +#else X509_STORE_set_verify_cb_func(store, x509_verify_cb); +#endif return true; } @@ -1020,8 +1030,10 @@ /* ** valid values for dhparam are (only the first char is checked) ** none no parameters: don't use DH +# if !_FFR_TLSA_DANE2 ** i use precomputed 2048 bit parameters ** 512 use precomputed 512 bit parameters +# endif ** 1024 generate 1024 bit parameters ** 2048 generate 2048 bit parameters ** /file/name read parameters from /file/name @@ -1041,12 +1053,16 @@ if (c == '1') req |= TLS_I_DH1024; +# if !_FFR_TLSA_DANE2 else if (c == 'I' || c == 'i') req |= TLS_I_DHFIXED; +# endif /* !_FFR_TLSA_DANE2 */ else if (c == '2') req |= TLS_I_DH2048; +# if !_FFR_TLSA_DANE2 else if (c == '5') req |= TLS_I_DH512; +# endif /* !_FFR_TLSA_DANE2 */ else if (c == 'n' || c == 'N') req &= ~TLS_I_TRY_DH; else if (c != '/') @@ -1169,7 +1185,7 @@ SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2); # endif - +# if !_FFR_TLSA_DANE2 # if !TLS_NO_RSA && MTA_RSA_TMP_CB /* ** Create a temporary RSA key @@ -1199,6 +1215,7 @@ return false; } # endif /* !TLS_NO_RSA && MTA_RSA_TMP_CB */ +# endif /* !_FFR_TLSA_DANE2 */ /* ** load private key @@ -1396,6 +1413,7 @@ #endif DSA_free(dsa); } +# if !_FFR_TLSA_DANE2 else if (dh == NULL && bitset(TLS_I_DHFIXED, req)) { if (tTd(96, 2)) @@ -1408,6 +1426,7 @@ sm_dprintf("inittls: Using precomputed 512 bit DH parameters\n"); dh = get_dh512(); } +# endif /* !_FFR_TLSA_DANE2 */ if (dh == NULL) { @@ -1483,10 +1502,12 @@ if ((r = SSL_CTX_load_verify_locations(*ctx, cacertfile, cacertpath)) == 1) { +# if !_FFR_TLSA_DANE2 # if !TLS_NO_RSA && MTA_RSA_TMP_CB if (bitset(TLS_I_RSA_TMP, req)) SSL_CTX_set_tmp_rsa_callback(*ctx, tmp_rsa_key); # endif +# endif /* !_FFR_TLSA_DANE2 */ /* ** We have to install our own verify callback: @@ -1870,6 +1891,32 @@ } else # endif +# if _FFR_TLSA_DANE2 + if (Dane_vrfy_ctx.dane_vrfy_chk) + { + bool usable = (Dane_vrfy_ctx.dane_vrfy_usable > 0); + switch (verifyok) + { + case X509_V_OK: + if (cert != NULL) + { + s = "TRUSTED"; + r = TLS_AUTH_OK; + } + else + { + s = (usable) ? "DANE_FAIL" : "NOT"; + r = (usable) ? TLS_AUTH_FAIL : TLS_AUTH_NO; + } + break; + default: + s = (usable) ? "DANE_FAIL" : "FAIL"; + r = TLS_AUTH_FAIL; + break; + } + } + else +# endif switch (verifyok) { case X509_V_OK: @@ -2020,6 +2067,7 @@ return ret; } +# if !_FFR_TLSA_DANE2 # if !TLS_NO_RSA && MTA_RSA_TMP_CB /* ** TMP_RSA_KEY -- return temporary RSA key @@ -2085,6 +2133,7 @@ return rsa_tmp; } # endif /* !TLS_NO_RSA && MTA_RSA_TMP_CB */ +# endif /* !_FFR_TLSA_DANE2 */ /* ** APPS_SSL_INFO_CB -- info callback for TLS connections @@ -2184,10 +2233,13 @@ cert = X509_STORE_CTX_get_current_cert(ctx); reason = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); - X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + + if (cert) X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + else strcpy(buf, ""); + sm_syslog(LOG_INFO, NOQID, - "STARTTLS: %s cert verify: depth=%d %s, state=%d, reason=%s", - name, depth, buf, ok, X509_verify_cert_error_string(reason)); + "STARTTLS: %s cert verify: ok=%d, depth=%d %s, reason=%d %s", + name, ok, depth, buf, reason, X509_verify_cert_error_string(reason)); return 1; } @@ -2212,7 +2264,6 @@ } \ while (0) - # if _FFR_TLSA_DANE /* @@ -2308,6 +2359,42 @@ return ok; } # endif +# if _FFR_TLSA_DANE2 +/* +** DANE_VERIFY_CB -- verify callback for Dane TLSA records +** +** Parameters: +** ok -- did it verify +** ctx -- X509 store context +** +** Returns: +** accept connection? +*/ + +int +dane_verify_cb(ok, ctx) + int ok; + X509_STORE_CTX *ctx; +{ + char buf[512]; + X509 *cert; + int reason; + int depth; + + cert = X509_STORE_CTX_get_current_cert(ctx); + reason = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + if (cert) X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + else strcpy(buf, ""); + + sm_syslog(LOG_INFO, NOQID, + "STARTTLS: dane cert verify: ok=%d, depth=%d %s, reason=%d %s", + ok, depth, buf, reason, X509_verify_cert_error_string(reason)); + return 1; +} +# endif /* _FFR_TLSA_DANE2 */ + /* ** TLS_VERIFY_CB -- verify callback for TLS certificates @@ -2342,15 +2429,15 @@ if (ok != DANE_VRFY_NONE) return 1; # endif - ok = X509_verify_cert(ctx); if (ok <= 0) { if (LogLevel > 13) - return tls_verify_log(ok, ctx, "TLS"); + (void) tls_verify_log(ok, ctx, "TLS"); } else if (LogLevel > 14) (void) tls_verify_log(ok, ctx, "TLS"); + return 1; } diff -urN -bw sendmail-8.16.0.original/sendmail/tls.h sendmail-8.16.0.new/sendmail/tls.h --- sendmail-8.16.0.original/sendmail/tls.h 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/tls.h 2018-10-13 13:14:57.686142180 -0700 @@ -13,8 +13,9 @@ #if STARTTLS -# if _FFR_DANE -# include +# if _FFR_TLSA_DANE2 +# define OPENSSL_USE_DEPRECATED +# include # else # include # endif @@ -77,6 +78,35 @@ # define DANE_SECURE 2 # endif /* _FFR_TLSA_DANE */ +# if _FFR_TLSA_DANE2 +# define MAX_TLSA_RR 8 + +#define TLSA_BOGUS (-1) +#define TLSA_OK 0 +#define TLSA_UNSUPP 1 + +struct dane_tlsa_S +{ + time_t dane_tlsa_exp; + bool dane_tlsa_ignoremx; + int dane_tlsa_n; + void *dane_tlsa_rr[MAX_TLSA_RR]; + int dane_tlsa_len[MAX_TLSA_RR]; +}; + +struct dane_vrfy_ctx_S +{ + int dane_vrfy_chk; + int dane_vrfy_usable; + char *dane_vrfy_host; +}; + +/* values for DANE option and dane_vrfy_chk */ +# define DANE_NEVER 0 /* ignore tlsa records */ +# define DANE_ALWAYS 1 /* use all tlsa records */ +# define DANE_SECURE 2 /* only use tlsa records secured with dnssec */ +# endif /* _FFR_TLSA_DANE2 */ + /* ** TLS */ @@ -153,7 +183,10 @@ extern int tls_get_info __P((SSL *, bool, char *, MACROS_T *, bool)); extern void tlslogerr __P((int, int, const char *)); extern void tls_set_verify __P((SSL_CTX *, SSL *, bool)); -# if _FFR_TLSA_DANE +# if _FFR_TLSA_DANE2 +extern int dane_verify_cb __P((int, X509_STORE_CTX *)); +# endif +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 extern int dane_tlsa_chk __P((const char *, int, const char *, bool)); extern int dane_tlsa_clr __P((dane_tlsa_P)); extern int dane_tlsa_free __P((dane_tlsa_P)); @@ -180,7 +213,7 @@ EXTERN char *SSLEnginePath; EXTERN bool SSLEngineprefork; -# if _FFR_TLSA_DANE +# if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 EXTERN dane_vrfy_ctx_T Dane_vrfy_ctx; # endif @@ -188,10 +221,13 @@ #define TLS_set_engine(id, prefork) SSL_set_engine(id) # else int TLS_set_engine __P((const char *, bool)); + # endif extern int set_tls_rd_tmo __P((int)); +# if _FFR_TLSA_DANE extern int pubkey_fp __P((X509 *, const EVP_MD *, char **)); +# endif extern int data2hex __P((unsigned char *, int, unsigned char *, int)); #else /* STARTTLS */ diff -urN -bw sendmail-8.16.0.original/sendmail/tlsh.c sendmail-8.16.0.new/sendmail/tlsh.c --- sendmail-8.16.0.original/sendmail/tlsh.c 2018-08-23 05:52:20.000000000 -0700 +++ sendmail-8.16.0.new/sendmail/tlsh.c 2018-10-13 13:14:57.692142397 -0700 @@ -57,6 +57,7 @@ return h; } +# if _FFR_TLSA_DANE /* ** TLS_DATA_MD -- calculate MD for data ** @@ -146,8 +147,9 @@ *fp = (char *)buf; return r; } +# endif /* _FFR_TLSA_DANE */ -#if _FFR_TLSA_DANE +#if _FFR_TLSA_DANE || _FFR_TLSA_DANE2 /* ** DANE_TLSA_CHK -- check whether TLSA RRs are ok to use @@ -178,7 +180,7 @@ host, len); return TLSA_BOGUS; } - +# if _FFR_TLSA_DANE /* ignore TLSA RRs which we do not handle right now */ if ((int)rr[0] != 3 || (int)rr[1] != 1 || (int)rr[2] != 1) { @@ -190,6 +192,7 @@ (int)rr[3]); return TLSA_UNSUPP; } +# endif return TLSA_OK; } @@ -218,6 +221,9 @@ dane_tlsa->dane_tlsa_len[i] = 0; } dane_tlsa->dane_tlsa_exp = 0; +# if _FFR_TLSA_DANE2 + dane_tlsa->dane_tlsa_ignoremx = 0; +# endif dane_tlsa->dane_tlsa_n = 0; return 0; @@ -245,6 +251,6 @@ return 0; } -#endif /* _FFR_TLSA_DANE */ +#endif /* _FFR_TLSA_DANE || _FFR_TLSA_DANE2 */ #endif /* STARTTLS */