diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 8f3031c89..6488e500c 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -336,7 +336,6 @@ -TSTATE -TSTRING_LIST -TSTRING_TABLE --TSUMMARY_CLASS -TSYS_EXITS_DETAIL -TTLSMGR_SCACHE -TTLSP_STATE @@ -356,6 +355,7 @@ -TTLS_SESS_STATE -TTLS_TICKET_KEY -TTLS_TLSA +-TTLS_USAGE -TTLS_VINFO -TTLScontext_t -TTOK822 diff --git a/postfix/HISTORY b/postfix/HISTORY index 0ed7db882..ac502c1a5 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -23770,9 +23770,7 @@ Apologies for any names omitted. postmap/postmap.c. Cleanup: don't use ssize_t for boolean result. File: - global/smtp_stream.c. Memory leak: the Berkeley DB client - leaked a small amount of memory asfter failing to open a - table. File: util/dict_db.c. + global/smtp_stream.c. Cleanup: memory leak caused by missing dbenv->close() call after failing to open a Berkeley DB table. File: util/dict_db.c. @@ -23794,3 +23792,26 @@ Apologies for any names omitted. tls/tls_proxy_context_print.c, tls/tls_proxy_context_scan.c, tls/tls_client.c, tls/tls_server.c, smtpd/smtpd.c, posttls-finger/posttls-finger.c. + + Cleanup: vstream_memopen() flags handling. File: + util/vstream.c. + + Cleanup: the SMTP client now uses 'attr_print_plain' + serialization and 'attr_scan_plain' deserialization for + connection cache lookup keys, which now contain a serialized + version of the TLS context. File: smtp/smtp_session.c. + +20181117 + + The Postfix SMTP client now logs whether an SMTP-over-TLS + connection is newly established ("TLS connection established") + or whether the connection is reused ("TLS connection reused"). + Files: smtp/smtp.h, smtp/smtp_proto.c, smtp/smtp_session.c. + +20181118 + + Cleanup, no behavior change: updated comments concerning + connection reuse, and updated some identifiers to reflect + current reality. Files: smtp_reuse.c, smtp_key.c, smtp_proto.c, + smtp_tls_policy.c, smtp.h, smtp_connect.c. + diff --git a/postfix/README_FILES/AAAREADME b/postfix/README_FILES/AAAREADME index d4e10f070..7d72787cb 100644 --- a/postfix/README_FILES/AAAREADME +++ b/postfix/README_FILES/AAAREADME @@ -12,7 +12,6 @@ GGeenneerraall ccoonnffiigguurraattiioonn * TLS_README: TLS Encryption and authentication * FORWARD_SECRECY_README: TLS Forward Secrecy * IPV6_README: IP Version 6 Support - * IPV6_README: IP Version 6 Support * SMTPUTF8_README: SMTPUTF8 Support * COMPATIBILITY_README: Backwards-Compatibility Safety Net * INSTALL: Installation from source code diff --git a/postfix/README_FILES/FORWARD_SECRECY_README b/postfix/README_FILES/FORWARD_SECRECY_README index 2b58e4828..d59b99e92 100644 --- a/postfix/README_FILES/FORWARD_SECRECY_README +++ b/postfix/README_FILES/FORWARD_SECRECY_README @@ -323,7 +323,7 @@ verification status. (No client certificate requested) TLS 1.3 examples. Some of the new attributes may not appear when not - applicable or not available in an older versions of the OpenSSL library. + applicable or not available in older versions of the OpenSSL library. Received: from localhost (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 diff --git a/postfix/html/FORWARD_SECRECY_README.html b/postfix/html/FORWARD_SECRECY_README.html index 3fa0e78c5..18a83818b 100644 --- a/postfix/html/FORWARD_SECRECY_README.html +++ b/postfix/html/FORWARD_SECRECY_README.html @@ -434,7 +434,7 @@ Received: from host.example.com (host.example.com [192.168.0.2])
TLS 1.3 examples. Some of the new attributes may not appear when not -applicable or not available in an older versions of the OpenSSL library.
+applicable or not available in older versions of the OpenSSL library.diff --git a/postfix/html/index.html b/postfix/html/index.html index edf9019e7..2989177a6 100644 --- a/postfix/html/index.html +++ b/postfix/html/index.html @@ -46,8 +46,6 @@ configuration examplesIP Version 6 Support - IP Version 6 Support - SMTPUTF8 Support Backwards-Compatibility Safety Net diff --git a/postfix/proto/FORWARD_SECRECY_README.html b/postfix/proto/FORWARD_SECRECY_README.html index abeb31e0a..f549e4a1c 100644 --- a/postfix/proto/FORWARD_SECRECY_README.html +++ b/postfix/proto/FORWARD_SECRECY_README.html @@ -434,7 +434,7 @@ Received: from host.example.com (host.example.com [192.168.0.2])
TLS 1.3 examples. Some of the new attributes may not appear when not -applicable or not available in an older versions of the OpenSSL library.
+applicable or not available in older versions of the OpenSSL library.diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index cbb127459..ba90a1ddf 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20181117" +#define MAIL_RELEASE_DATE "20181118" #define MAIL_VERSION_NUMBER "3.4" #ifdef SNAPSHOT diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 778a3d524..effc658a1 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -192,17 +192,25 @@ typedef struct SMTP_STATE { } SMTP_STATE; /* - * TODO: use the new SMTP_ITER name space. + * Primitives to enable/disable/test connection caching and reuse based on + * the delivery request next-hop destination (i.e. not smtp_fallback_relay). + * + * Connection cache lookup by the request next-hop destination allows a reuse + * request to skip over bad hosts, and may result in a connection to a + * fall-back relay. Once we have found a 'good' host for a request next-hop, + * clear the request next-hop destination, to avoid caching less-preferred + * connections under that same request next-hop. */ -#define SET_NEXTHOP_STATE(state, nexthop) { \ +#define SET_SCACHE_REQUEST_NEXTHOP(state, nexthop) do { \ vstring_strcpy((state)->iterator->request_nexthop, nexthop); \ - } + } while (0) -#define FREE_NEXTHOP_STATE(state) { \ +#define CLEAR_SCACHE_REQUEST_NEXTHOP(state) do { \ STR((state)->iterator->request_nexthop)[0] = 0; \ - } + } while (0) -#define HAVE_NEXTHOP_STATE(state) (STR((state)->iterator->request_nexthop)[0] != 0) +#define HAVE_SCACHE_REQUEST_NEXTHOP(state) \ + (STR((state)->iterator->request_nexthop)[0] != 0) /* @@ -229,6 +237,7 @@ typedef struct SMTP_STATE { #define SMTP_FEATURE_EARLY_TLS_MAIL_REPLY (1<<19) /* CVE-2009-3555 */ #define SMTP_FEATURE_XFORWARD_IDENT (1<<20) #define SMTP_FEATURE_SMTPUTF8 (1<<21) /* RFC 6531 */ +#define SMTP_FEATURE_FROM_PROXY (1<<22) /* proxied connection */ /* * Features that passivate under the endpoint. @@ -617,7 +626,7 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); #define SMTP_KEY_FLAG_SERVICE (1<<0) /* service name */ #define SMTP_KEY_FLAG_SENDER (1<<1) /* sender address */ #define SMTP_KEY_FLAG_REQ_NEXTHOP (1<<2) /* request nexthop */ -#define SMTP_KEY_FLAG_NEXTHOP (1<<3) /* current nexthop */ +#define SMTP_KEY_FLAG_CUR_NEXTHOP (1<<3) /* current nexthop */ #define SMTP_KEY_FLAG_HOSTNAME (1<<4) /* remote host name */ #define SMTP_KEY_FLAG_ADDR (1<<5) /* remote address */ #define SMTP_KEY_FLAG_PORT (1<<6) /* remote port */ @@ -626,7 +635,7 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); #define SMTP_KEY_MASK_ALL \ (SMTP_KEY_FLAG_SERVICE | SMTP_KEY_FLAG_SENDER | \ SMTP_KEY_FLAG_REQ_NEXTHOP | \ - SMTP_KEY_FLAG_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \ + SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \ SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL) /* @@ -640,14 +649,14 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); ((var_smtp_sender_auth && *var_smtp_sasl_passwd) ? \ SMTP_KEY_FLAG_SENDER : 0) -#define COND_SASL_SMTP_KEY_FLAG_NEXTHOP \ - (*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_NEXTHOP : 0) +#define COND_SASL_SMTP_KEY_FLAG_CUR_NEXTHOP \ + (*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_CUR_NEXTHOP : 0) #ifdef USE_TLS -#define COND_TLS_SMTP_KEY_FLAG_NEXTHOP \ - (TLS_MUST_MATCH(state->tls->level) ? SMTP_KEY_FLAG_NEXTHOP : 0) +#define COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP \ + (TLS_MUST_MATCH(state->tls->level) ? SMTP_KEY_FLAG_CUR_NEXTHOP : 0) #else -#define COND_TLS_SMTP_KEY_FLAG_NEXTHOP \ +#define COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP \ (0) #endif @@ -655,10 +664,13 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); (*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_HOSTNAME : 0) /* - * Connection-cache destination lookup key. The SENDER attribute is a proxy - * for sender-dependent SASL credentials (or absence thereof), and prevents - * false connection sharing when different SASL credentials may be required - * for different deliveries to the same domain and port. The SERVICE + * Connection-cache destination lookup key, based on the delivery request + * nexthop. The SENDER attribute is a proxy for sender-dependent SASL + * credentials (or absence thereof), and prevents false connection sharing + * when different SASL credentials may be required for different deliveries + * to the same domain and port. Likewise, the delivery request nexthop + * (REQ_NEXTHOP) prevents false sharing of TLS identities (the destination + * key links only to appropriate endpoint lookup keys). The SERVICE * attribute is a proxy for all request-independent configuration details. */ #define SMTP_KEY_MASK_SCACHE_DEST_LABEL \ @@ -666,15 +678,18 @@ char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int); | SMTP_KEY_FLAG_REQ_NEXTHOP) /* - * Connection-cache endpoint lookup key. The SENDER, NEXTHOP, and HOSTNAME - * attributes are proxies for SASL credentials (or absence thereof), and - * prevent false connection sharing when different SASL credentials may be - * required for different deliveries to the same IP address and port. + * Connection-cache endpoint lookup key. The SENDER, CUR_NEXTHOP, HOSTNAME, + * PORT and TLS_LEVEL attributes are proxies for SASL credentials and TLS + * authentication (or absence thereof), and prevent false connection sharing + * when different SASL credentials or TLS identities may be required for + * different deliveries to the same IP address and port. The SERVICE + * attribute is a proxy for all request-independent configuration details. */ #define SMTP_KEY_MASK_SCACHE_ENDP_LABEL \ (SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \ - | COND_SASL_SMTP_KEY_FLAG_NEXTHOP | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \ - | COND_TLS_SMTP_KEY_FLAG_NEXTHOP | SMTP_KEY_FLAG_ADDR | \ + | COND_SASL_SMTP_KEY_FLAG_CUR_NEXTHOP \ + | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \ + | COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_ADDR | \ SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL) /* @@ -703,11 +718,6 @@ extern int smtp_mode; /* 111 8th Avenue /* New York, NY 10011, USA /* -/* Wietse Venema -/* Google, Inc. -/* 111 8th Avenue -/* New York, NY 10011, USA -/* /* TLS support originally by: /* Lutz Jaenicke /* BTU Cottbus diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index b218b2a01..d5693c7c8 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -417,13 +417,13 @@ static void smtp_cleanup_session(SMTP_STATE *state) state->session = 0; /* - * If this session was good, reset the logical next-hop state, so that we - * won't cache connections to alternate servers under the logical - * next-hop destination. Otherwise we could end up skipping over the - * available and more preferred servers. + * If this session was good, reset the logical next-hop destination, so + * that we won't cache connections to less-preferred servers under the + * logical next-hop destination. Otherwise we could end up skipping over + * the available and more-preferred servers. */ - if (HAVE_NEXTHOP_STATE(state) && !throttled) - FREE_NEXTHOP_STATE(state); + if (HAVE_SCACHE_REQUEST_NEXTHOP(state) && !throttled) + CLEAR_SCACHE_REQUEST_NEXTHOP(state); /* * Clean up the lists with todo and dropped recipients. @@ -678,7 +678,7 @@ static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list, #endif SMTP_ITER_SAVE_DEST(state->iterator); if (*addr_list && SMTP_RCPT_LEFT(state) > 0 - && HAVE_NEXTHOP_STATE(state) + && HAVE_SCACHE_REQUEST_NEXTHOP(state) && (session = smtp_reuse_nexthop(state, SMTP_KEY_MASK_SCACHE_DEST_LABEL)) != 0) { session_count = 1; smtp_update_addr_list(addr_list, STR(iter->addr), session_count); @@ -899,7 +899,7 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop, if (addr_list && (state->misc_flags & SMTP_MISC_FLAG_FIRST_NEXTHOP)) { smtp_cache_policy(state, domain); if (state->misc_flags & SMTP_MISC_FLAG_CONN_CACHE_MASK) - SET_NEXTHOP_STATE(state, dest); + SET_SCACHE_REQUEST_NEXTHOP(state, dest); } /* @@ -1124,8 +1124,8 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop, /* * Cleanup. */ - if (HAVE_NEXTHOP_STATE(state)) - FREE_NEXTHOP_STATE(state); + if (HAVE_SCACHE_REQUEST_NEXTHOP(state)) + CLEAR_SCACHE_REQUEST_NEXTHOP(state); argv_free(sites); } diff --git a/postfix/src/smtp/smtp_key.c b/postfix/src/smtp/smtp_key.c index 6f72b803e..8b5db76a2 100644 --- a/postfix/src/smtp/smtp_key.c +++ b/postfix/src/smtp/smtp_key.c @@ -53,7 +53,7 @@ /* .IP SMTP_KEY_FLAG_REQ_NEXTHOP /* The request nexthop destination. This is a proxy for /* destination-dependent, but host-independent context. -/* .IP SMTP_KEY_FLAG_NEXTHOP +/* .IP SMTP_KEY_FLAG_CUR_NEXTHOP /* The current iterator's nexthop destination (request nexthop /* or fallback nexthop, including optional [] and :port). This /* is the form that users specify in a SASL or TLS lookup @@ -183,7 +183,7 @@ char *smtp_key_prefix(VSTRING *buffer, const char *delim_na, */ if (flags & SMTP_KEY_FLAG_REQ_NEXTHOP) smtp_key_append_str(buffer, STR(iter->request_nexthop), delim_na); - if (flags & SMTP_KEY_FLAG_NEXTHOP) + if (flags & SMTP_KEY_FLAG_CUR_NEXTHOP) smtp_key_append_str(buffer, STR(iter->dest), delim_na); /* diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 0169f1716..0bac85aba 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -899,7 +899,7 @@ static int smtp_start_tls(SMTP_STATE *state) */ serverid = vstring_alloc(10); smtp_key_prefix(serverid, "&", state->iterator, SMTP_KEY_FLAG_SERVICE - | SMTP_KEY_FLAG_NEXTHOP /* With port */ + | SMTP_KEY_FLAG_CUR_NEXTHOP /* With port */ | SMTP_KEY_FLAG_HOSTNAME | SMTP_KEY_FLAG_ADDR); @@ -1018,6 +1018,11 @@ static int smtp_start_tls(SMTP_STATE *state) * context attributes. */ session->tls_context = tls_proxy_context_receive(session->stream); + if (session->tls_context) { + session->features |= SMTP_FEATURE_FROM_PROXY; + tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_NEW, + session->tls_context); + } } } else { /* state->tls->conn_reuse */ diff --git a/postfix/src/smtp/smtp_reuse.c b/postfix/src/smtp/smtp_reuse.c index f4b4996c5..f93ba296a 100644 --- a/postfix/src/smtp/smtp_reuse.c +++ b/postfix/src/smtp/smtp_reuse.c @@ -23,27 +23,26 @@ /* This module implements the SMTP client specific interface to /* the generic session cache infrastructure. /* -/* A cached connection is closed when the TLS policy requires -/* that TLS is enabled. +/* The caller needs to include additional state in _key_flags +/* to avoid false sharing of SASL-authenticated or TLS-authenticated +/* sessions. /* /* smtp_save_session() stores the current session under the -/* next-hop logical destination (if available) and under the -/* remote server address. The SMTP_SESSION object is destroyed. +/* delivery request next-hop logical destination (if applicable) +/* and under the remote server address. The SMTP_SESSION object +/* is destroyed. /* -/* smtp_reuse_nexthop() looks up a cached session by its logical -/* destination, and verifies that the session is still alive. -/* The restored session information includes the "best MX" bit -/* and overrides the iterator dest, host and addr fields. -/* The result is null in case of failure. +/* smtp_reuse_nexthop() looks up a cached session by its +/* delivery request next-hop destination, and verifies that +/* the session is still alive. The restored session information +/* includes the "best MX" bit and overrides the iterator dest, +/* host and addr fields. The result is null in case of failure. /* /* smtp_reuse_addr() looks up a cached session by its server /* address, and verifies that the session is still alive. /* The restored session information does not include the "best /* MX" bit, and does not override the iterator dest, host and -/* addr fields. -/* This function is a NOOP for TLS levels stronger than "encrypt", -/* because stronger levels require certificate checks, -/* The result is null in case of failure. +/* addr fields. The result is null in case of failure. /* /* Arguments: /* .IP state @@ -116,10 +115,16 @@ void smtp_save_session(SMTP_STATE *state, int name_key_flags, int fd; /* - * Encode the next-hop logical destination, if available. Reuse storage - * that is also used for cache lookup queries. + * Encode the delivery request next-hop destination, if applicable. Reuse + * storage that is also used for cache lookup queries. + * + * HAVE_SCACHE_REQUEST_NEXTHOP() controls whether or not to reuse or cache a + * connection by its delivery request next-hop destination. The idea is + * 1) to allow a reuse request to skip over bad hosts, and 2) to avoid + * caching a less-preferred connection when a more-preferred connection + * was possible. */ - if (HAVE_NEXTHOP_STATE(state)) + if (HAVE_SCACHE_REQUEST_NEXTHOP(state)) smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA, state->iterator, name_key_flags); @@ -138,16 +143,18 @@ void smtp_save_session(SMTP_STATE *state, int name_key_flags, state->session = 0; /* - * Save the session under the next-hop name, if available. + * Save the session under the delivery request next-hop name, if + * applicable. * * XXX The logical to physical binding can be kept for as long as the DNS * allows us to (but that could result in the caching of lots of unused * bindings). The session should be idle for no more than 30 seconds or * so. */ - if (HAVE_NEXTHOP_STATE(state)) - scache_save_dest(smtp_scache, var_smtp_cache_conn, STR(state->dest_label), - STR(state->dest_prop), STR(state->endp_label)); + if (HAVE_SCACHE_REQUEST_NEXTHOP(state)) + scache_save_dest(smtp_scache, var_smtp_cache_conn, + STR(state->dest_label), STR(state->dest_prop), + STR(state->endp_label)); /* * Save every good session under its physical endpoint address. @@ -165,15 +172,6 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd, SMTP_ITERATOR *iter = state->iterator; SMTP_SESSION *session; - /* - * Obsolete. - */ -#ifdef notdef - if (state->tls->level > TLS_LEV_NONE) - msg_panic("%s: unexpected plain-text cached session to %s", - myname, label); -#endif - /* * Re-activate the SMTP_SESSION object. */ @@ -216,15 +214,6 @@ SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags) SMTP_SESSION *session; int fd; - /* - * Obsolete: the TLS level and nexthop are part of the connection cache - * key. TODO(tlsproxy) is the port included in the nexthop? - */ -#ifdef notdef - if (state->tls->level > TLS_LEV_NONE) - return (0); -#endif - /* * Look up the session by its logical name. */ @@ -250,18 +239,13 @@ SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags) int fd; /* - * Allow address-based reuse only for security levels that don't require - * certificate checks. Not to be confused with a similar constraint in - * the destination label smtp_key pattern, which conditionally includes - * the nexthop to prevent the reuse of an authenticated connection to the - * same MX hostname and the same IP address, but for a different nexthop - * destination (just in case we start to send SNI with the nexthop, and - * forget to update connection cache lookup key patterns). + * Address-based reuse is safe for security levels that require TLS + * certificate checks, as long as the current nexhop is included in the + * cache lookup key (COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP). This is + * sufficient to prevent the reuse of a TLS-authenticated connection to + * the same MX hostname, IP address, and port, but for a different + * current nexthop destination with a different TLS policy. */ -#ifdef USE_TLS - if (TLS_MUST_MATCH(state->tls->level)) - return (0); -#endif /* * Look up the session by its IP address. This means that we have no diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 2b4ce8675..7ae9afd0c 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -113,11 +113,28 @@ #include#include +/* TLS Library. */ + +#include + /* Application-specific. */ #include "smtp.h" #include "smtp_sasl.h" + /* + * Local, because these are meaningful only for code in this file. + */ +#define SESS_ATTR_DEST "destination" +#define SESS_ATTR_HOST "host_name" +#define SESS_ATTR_ADDR "host_addr" +#define SESS_ATTR_DEST_FEATURES "destination_features" + +#define SESS_ATTR_TLS_LEVEL "tls_level" +#define SESS_ATTR_REUSE_COUNT "reuse_count" +#define SESS_ATTR_ENDP_FEATURES "endpoint_features" +#define SESS_ATTR_EXPIRE_TIME "expire_time" + /* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, SMTP_ITERATOR *iter, @@ -183,7 +200,8 @@ void smtp_session_free(SMTP_SESSION *session) vstream_fflush(session->stream); } if (session->tls_context) { - if (session->state->tls->conn_reuse) + if (session->features & + (SMTP_FEATURE_FROM_CACHE | SMTP_FEATURE_FROM_PROXY)) tls_proxy_context_free(session->tls_context); else tls_client_stop(smtp_tls_ctx, session->stream, @@ -220,6 +238,7 @@ int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, VSTRING *endp_prop) { SMTP_ITERATOR *iter = session->iterator; + VSTREAM *mp; int fd; /* @@ -228,55 +247,61 @@ int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, * destination (this information is needed for loop handling in * smtp_proto()). * - * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can - * serialize the properties with attr_print() instead of using ad-hoc, - * non-reusable, code and hard-coded format strings. - * - * TODO(tlsproxy): save TLS_SESS_STATE information so that we can restore - * TLS session properties. - * * TODO: save SASL username and password information so that we can * correctly save a reused authenticated connection. * - * Note: the TLS level field is always present. + * These memory writes should never fail. */ - vstring_sprintf(dest_prop, "%s\n%s\n%s\n%u\n%u", - STR(iter->dest), STR(iter->host), STR(iter->addr), -#ifdef USE_TLS - iter->parent->tls->level, -#else - 0, -#endif - session->features & SMTP_FEATURE_DESTINATION_MASK); + if ((mp = vstream_memopen(dest_prop, O_WRONLY)) == 0 + || attr_print_plain(mp, ATTR_FLAG_NONE, + SEND_ATTR_STR(SESS_ATTR_DEST, STR(iter->dest)), + SEND_ATTR_STR(SESS_ATTR_HOST, STR(iter->host)), + SEND_ATTR_STR(SESS_ATTR_ADDR, STR(iter->addr)), + SEND_ATTR_INT(SESS_ATTR_DEST_FEATURES, + session->features & SMTP_FEATURE_DESTINATION_MASK), + ATTR_TYPE_END) != 0 + || vstream_fclose(mp) != 0) + msg_fatal("smtp_session_passivate: can't save dest properties: %m"); /* * Encode the physical endpoint properties: all the session properties * except for "session from cache", "best MX", or "RSET failure". + * Plus the TLS level, reuse count, and connection expiration time. * - * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can - * serialize the properties with attr_print() instead of using obscure - * hard-coded format strings. + * XXX Should also record how many non-delivering mail transactions there + * were during this session, and perhaps other statistics, so that we + * don't reuse a session too much. * - * XXX Should also record an absolute time when a session must be closed, - * how many non-delivering mail transactions there were during this - * session, and perhaps other statistics, so that we don't reuse a - * session too much. + * TODO: passivate SASL username and password information so that we can + * correctly save a reused authenticated connection. * - * XXX Be sure to use unsigned types in the format string. Sign characters - * would be rejected by the alldig() test on the reading end. + * These memory writes should never fail. */ - vstring_sprintf(endp_prop, "%u\n%u\n%lu", - session->reuse_count, - session->features & SMTP_FEATURE_ENDPOINT_MASK, - (long) session->expire_time); + if ((mp = vstream_memopen(endp_prop, O_WRONLY)) == 0 + || attr_print_plain(mp, ATTR_FLAG_NONE, + SEND_ATTR_INT(SESS_ATTR_TLS_LEVEL, + session->state->tls->level), + SEND_ATTR_INT(SESS_ATTR_REUSE_COUNT, + session->reuse_count), + SEND_ATTR_INT(SESS_ATTR_ENDP_FEATURES, + session->features & SMTP_FEATURE_ENDPOINT_MASK), + SEND_ATTR_LONG(SESS_ATTR_EXPIRE_TIME, + (long) session->expire_time), + ATTR_TYPE_END) != 0 /* - * Append the passivated SASL attributes. + * Append the passivated TLS context. These memory writes should never + * fail. */ -#ifdef notdef - if (smtp_sasl_enable) - smtp_sasl_passivate(endp_prop, session); +#ifdef USE_TLS + || (session->tls_context + && attr_print_plain(mp, ATTR_FLAG_NONE, + SEND_ATTR_FUNC(tls_proxy_context_print, + (void *) session->tls_context), + ATTR_TYPE_END) != 0) #endif + || vstream_fclose(mp) != 0) + msg_fatal("smtp_session_passivate: cannot save TLS context: %m"); /* * Salvage the underlying file descriptor, and destroy the session @@ -297,50 +322,52 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, VSTRING *endp_prop) { const char *myname = "smtp_session_activate"; + VSTREAM *mp; SMTP_SESSION *session; - char *dest_props; - char *endp_props; - const char *prop; - const char *dest; - const char *host; - const char *addr; - unsigned features; /* server features */ - time_t expire_time; /* session re-use expiration time */ - unsigned reuse_count; /* # times reused */ + int endp_features; /* server features */ + int dest_features; /* server features */ + long expire_time; /* session re-use expiration time */ + int reuse_count; /* # times reused */ + TLS_SESS_STATE *tls_context = 0; #ifdef USE_TLS SMTP_TLS_POLICY *tls = iter->parent->tls; #endif +#define SMTP_SESSION_ACTIVATE_ERR_RETURN() do { \ + if (tls_context) \ + tls_proxy_context_free(tls_context); \ + return (0); \ + } while (0) + /* - * XXX it would be nice to have a VSTRING to VSTREAM adapter so that we - * can de-serialize the properties with attr_scan(), instead of using - * ad-hoc, non-reusable code. - * - * XXX As a preliminary solution we use mystrtok(), but that function is not - * suitable for zero-length fields. + * Sanity check: if TLS is required, the cached properties must contain a + * TLS context. */ - endp_props = STR(endp_prop); - if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) { - msg_warn("%s: bad cached session reuse count property", myname); - return (0); - } - reuse_count = atoi(prop); - if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) { - msg_warn("%s: bad cached session features property", myname); - return (0); - } - features = atoi(prop); - if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) { - msg_warn("%s: bad cached session expiration time property", myname); - return (0); - } -#ifdef MISSING_STRTOUL - expire_time = strtol(prop, 0, 10); -#else - expire_time = strtoul(prop, 0, 10); + if ((mp = vstream_memopen(endp_prop, O_RDONLY)) == 0 + || attr_scan_plain(mp, ATTR_FLAG_NONE, + RECV_ATTR_INT(SESS_ATTR_TLS_LEVEL, + &tls->level), + RECV_ATTR_INT(SESS_ATTR_REUSE_COUNT, + &reuse_count), + RECV_ATTR_INT(SESS_ATTR_ENDP_FEATURES, + &endp_features), + RECV_ATTR_LONG(SESS_ATTR_EXPIRE_TIME, + &expire_time), + ATTR_TYPE_END) != 4 +#ifdef USE_TLS + || ((tls->level > TLS_LEV_MAY + || (tls->level == TLS_LEV_MAY && vstream_peek(mp) > 0)) + && attr_scan_plain(mp, ATTR_FLAG_NONE, + RECV_ATTR_FUNC(tls_proxy_context_scan, + (void *) &tls_context), + ATTR_TYPE_END) != 1) #endif + || vstream_fclose(mp) != 0) { + msg_warn("smtp_session_activate: bad cached endp properties"); + SMTP_SESSION_ACTIVATE_ERR_RETURN(); + } /* * Clobber the iterator's current nexthop, host and address fields with @@ -355,36 +382,25 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, * correctly save a reused authenticated connection. */ if (dest_prop && VSTRING_LEN(dest_prop)) { - dest_props = STR(dest_prop); - if ((dest = mystrtok(&dest_props, "\n")) == 0) { - msg_warn("%s: missing cached session destination property", myname); - return (0); + if ((mp = vstream_memopen(dest_prop, O_RDONLY)) == 0 + || attr_scan_plain(mp, ATTR_FLAG_NONE, + RECV_ATTR_STR(SESS_ATTR_DEST, iter->dest), + RECV_ATTR_STR(SESS_ATTR_HOST, iter->host), + RECV_ATTR_STR(SESS_ATTR_ADDR, iter->addr), + RECV_ATTR_INT(SESS_ATTR_DEST_FEATURES, + &dest_features), + ATTR_TYPE_END) != 4 + || vstream_fclose(mp) != 0) { + msg_warn("smtp_session_passivate: bad cached dest properties"); + SMTP_SESSION_ACTIVATE_ERR_RETURN(); } - if ((host = mystrtok(&dest_props, "\n")) == 0) { - msg_warn("%s: missing cached session hostname property", myname); - return (0); - } - if ((addr = mystrtok(&dest_props, "\n")) == 0) { - msg_warn("%s: missing cached session address property", myname); - return (0); - } - /* Note: the TLS level field is always present. */ - if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) { - msg_warn("%s: bad cached destination TLS level property", myname); - return (0); - } -#ifdef USE_TLS - tls->level = atoi(prop); - if (msg_verbose) - msg_info("%s: tls_level=%d", myname, tls->level); -#endif - if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) { - msg_warn("%s: bad cached destination features property", myname); - return (0); - } - features |= atoi(prop); - SMTP_ITER_CLOBBER(iter, dest, host, addr); + } else { + dest_features = 0; } +#ifdef USE_TLS + if (msg_verbose) + msg_info("%s: tls_level=%d", myname, tls->level); +#endif /* * Allright, bundle up what we have sofar. @@ -393,7 +409,9 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), iter, (time_t) 0, NO_FLAGS); - session->features = (features | SMTP_FEATURE_FROM_CACHE); + session->features = + (endp_features | dest_features | SMTP_FEATURE_FROM_CACHE); + session->tls_context = tls_context; CACHE_THIS_SESSION_UNTIL(expire_time); session->reuse_count = ++reuse_count; @@ -401,20 +419,15 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, " "ttl=%ld, reuse=%d", myname, STR(iter->dest), STR(iter->host), - STR(iter->addr), ntohs(iter->port), features, + STR(iter->addr), ntohs(iter->port), + endp_features | dest_features, (long) (expire_time - time((time_t *) 0)), reuse_count); - /* - * Re-activate the SASL attributes. - */ -#ifdef notdef - if (smtp_sasl_enable && smtp_sasl_activate(session, endp_props) < 0) { - vstream_fdclose(session->stream); - session->stream = 0; - smtp_session_free(session); - return (0); - } +#if USE_TLS + if (tls_context) + tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_USED, + session->tls_context); #endif return (session); diff --git a/postfix/src/smtp/smtp_tls_policy.c b/postfix/src/smtp/smtp_tls_policy.c index 13735b210..6415e032e 100644 --- a/postfix/src/smtp/smtp_tls_policy.c +++ b/postfix/src/smtp/smtp_tls_policy.c @@ -668,7 +668,7 @@ int smtp_tls_policy_cache_query(DSN_BUF *why, SMTP_TLS_POLICY *tls, * values that also appear in other cache and table search keys. */ key = vstring_alloc(100); - smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_NEXTHOP + smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | SMTP_KEY_FLAG_PORT); ctable_newcontext(policy_cache, (void *) iter); diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index e49567562..0f3c5be12 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -115,12 +115,12 @@ extern const char *str_tls_level(int); #endif /*- - * Backwards compatibility with OpenSSL < 1.1.1a (or some later version). + * Backwards compatibility with OpenSSL < 1.1.1a. * - * The client-only interface SSL_get_server_tmp_key() is slated to be made to - * work on both client and server, and renamed to SSL_get_peer_tmp_key(), with - * the original name left behind as an alias. We use the new name when - * available. + * In OpenSSL 1.1.1a the client-only interface SSL_get_server_tmp_key() was + * updated to work on both the client and the server, and was renamed to + * SSL_get_peer_tmp_key(), with the original name left behind as an alias. We + * use the new name when available. */ #if OPENSSL_VERSION_NUMBER < 0x1010101fUL #undef SSL_get_signature_nid @@ -159,9 +159,13 @@ extern const char *str_tls_level(int); /* * TLS role, presently for logging. */ -typedef enum { TLS_ROLE_CLIENT, TLS_ROLE_SERVER, } TLS_ROLE; +typedef enum { + TLS_ROLE_CLIENT, TLS_ROLE_SERVER, +} TLS_ROLE; -typedef enum { TLS_USAGE_NEW, TLS_USAGE_USED, } TLS_USAGE; +typedef enum { + TLS_USAGE_NEW, TLS_USAGE_USED, +} TLS_USAGE; /* * Names of valid tlsmgr(8) session caches. diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index f48538973..3d771a494 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -1191,6 +1191,9 @@ TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext, && !TLS_NEVER_SECURED(props->tls_level)) TLScontext->peer_status |= TLS_CERT_FLAG_SECURED; + /* + * With the handshake done, extract TLS 1.3 signature metadata. + */ tls_get_signature_params(TLScontext); if (TLScontext->log_mask & TLS_LOG_SUMMARY) diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c index 0ca919f52..9460d9fd6 100644 --- a/postfix/src/tls/tls_misc.c +++ b/postfix/src/tls/tls_misc.c @@ -14,6 +14,12 @@ /* TLS_USAGE usage; /* TLS_SESS_STATE *TLScontext; /* +/* const char *tls_compile_version(void) +/* +/* const char *tls_run_version(void) +/* +/* const char **tls_pkey_algorithms(void) +/* /* .SH Internal functions /* .nf /* .na @@ -103,12 +109,6 @@ /* /* int tls_validate_digest(dgst) /* const char *dgst; -/* -/* const char *tls_compile_version(void) -/* -/* const char *tls_run_version(void) -/* -/* const char **tls_pkey_algorithms(void) /* DESCRIPTION /* This module implements public and internal routines that /* support the TLS client and server. @@ -118,6 +118,16 @@ /* connections, or TLS_ROLE_SERVER for incoming server connections, /* and the "usage" must be TLS_USAGE_NEW or TLS_USAGE_USED. /* +/* tls_compile_version() returns a text string description of +/* the compile-time TLS library. +/* +/* tls_run_version() is just tls_compile_version() but with the runtime +/* version instead of the compile-time version. +/* +/* tls_pkey_algorithms() returns a pointer to null-terminated +/* array of string constants with the names of the supported +/* public-key algorithms. +/* /* tls_alloc_app_context() creates an application context that /* holds the SSL context for the application and related cached state. /* @@ -190,16 +200,6 @@ /* /* tls_validate_digest() returns non-zero if the named digest /* is usable and zero otherwise. -/* -/* tls_compile_version() returns a text string description of -/* the compile-time TLS library. -/* -/* tls_run_version() is just tls_compile_version() but with the runtime -/* version instead of the compile-time version. -/* -/* tls_pkey_algorithms() returns a pointer to null-terminated -/* array of string constants with the names of the supported -/* public-key algorithms. /* LICENSE /* .ad /* .fi diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index 674e79604..7af288271 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -1714,7 +1714,7 @@ VSTREAM *vstream_memreopen(VSTREAM *stream, VSTRING *string, int flags) stream->write_fn = 0; stream->vstring = string; memcpy(&stream->buf, &stream->vstring->vbuf, sizeof(stream->buf)); - stream->buf.flags |= (flags | VSTREAM_FLAG_MEMORY); + stream->buf.flags |= VSTREAM_FLAG_MEMORY; switch (VSTREAM_ACC_MASK(flags)) { case O_RDONLY: stream->buf.flags |= VSTREAM_FLAG_READ;