From: Wietse Venema Date: Thu, 21 Feb 2019 05:00:00 +0000 (-0500) Subject: postfix-3.4.0-RC3 X-Git-Tag: v3.4.0-RC3^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b12b6ab4e71b45b27ea574bfa4947792116cd9d;p=thirdparty%2Fpostfix.git postfix-3.4.0-RC3 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index a23dcad81..4540a81da 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -24128,3 +24128,37 @@ Apologies for any names omitted. Cleanup: missing #ifdef USE_TLS. Files: smtp/smtp_session.c, posttls-finger/posttls-finger.c. + +20190217 + + Cleanup: when the master daemon runs with PID=1 (init mode), + reap orhpan processes from non-Postfix code running in the + same container, instead of terminating with a panic. File: + master/master_spawn.c. + +20190218 + + Bugfix: tlsproxy did not enable DANE-style PKI because + libtls seems to have to accreted multiple init functions + instead of reusing the tls_client_init() and tls_client_start() + API. And some functions that do initialization don't even + have init in their name! Problem report by Andreas Schulze. + Viktor Dukhovni. Files: tls/tls_misc.c, tlsproxy/tlsproxy.c. + + Workaround: Postfix libtls makes DANE-specific changes to + the shared SSL_CTX. To avoid false sharing, tlsproxy needs + to label the SSL_CTX cache with DANE bits until we can + remove the code that modifies SSL_CTX. File: tlsproxy/tlsproxy.c. + + Cleanup: Postfix libtls changed the shared SSL_CTX to + override ciphers. instead of changing the SSL handle. To + avoid false sharing in tlsproxy, the changes are now made + to the SSL handle. Viktor Dukhovni. Files: tls/tls.h, + tls/tls_client.c, tls/tls_misc.c, tls/tls_server.c. + +20190219 + + Bugfix: in the Postfix SMTP client, TLS wrappermode was not + tested in tlsproxy mode. It needed some setup for buffering + and timeouts. Problem report by Andreas Schulze. File: + smtp/smtp_proto.c. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index bdd12ac2a..87ee978c0 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,8 +20,8 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20190212" -#define MAIL_VERSION_NUMBER "3.4.0-RC2" +#define MAIL_RELEASE_DATE "20190221" +#define MAIL_VERSION_NUMBER "3.4.0-RC3" #ifdef SNAPSHOT #define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff --git a/postfix/src/master/master_spawn.c b/postfix/src/master/master_spawn.c index 06bfa6715..c3b70f2b4 100644 --- a/postfix/src/master/master_spawn.c +++ b/postfix/src/master/master_spawn.c @@ -301,8 +301,11 @@ void master_reap_child(void) if (msg_verbose) msg_info("master_reap_child: pid %d", pid); if ((proc = (MASTER_PROC *) binhash_find(master_child_table, - (void *) &pid, sizeof(pid))) == 0) + (void *) &pid, sizeof(pid))) == 0) { + if (init_mode) + continue; /* non-Postfix process */ msg_panic("master_reap: unknown pid: %d", pid); + } serv = proc->serv; #define MASTER_KILL_SIGNAL SIGTERM diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index ce2352bc9..a43a326af 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -337,6 +337,8 @@ int smtp_helo(SMTP_STATE *state) && (state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0) { /* XXX Mix-up of per-session and per-request flags. */ state->misc_flags |= SMTP_MISC_FLAG_IN_STARTTLS; + smtp_stream_setup(state->session->stream, var_smtp_starttls_tmout, + var_smtp_rec_deadline); tls_helo_status = smtp_start_tls(state); state->misc_flags &= ~SMTP_MISC_FLAG_IN_STARTTLS; return (tls_helo_status); diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index 6c10d4ad7..2a8cc1199 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -338,10 +338,6 @@ struct TLS_APPL_STATE { SSL_CTX *sni_ctx; int log_mask; char *cache_type; - char *cipher_exclusions; /* Last cipher selection state */ - char *cipher_list; /* Last cipher selection state */ - int cipher_grade; /* Last cipher selection state */ - VSTRING *why; }; /* @@ -459,8 +455,8 @@ extern const NAME_CODE tls_cipher_grade_table[]; /* * Cipher lists with exclusions. */ -extern const char *tls_set_ciphers(TLS_APPL_STATE *, const char *, - const char *, const char *); +extern const char *tls_set_ciphers(TLS_SESS_STATE *, const char *, + const char *); /* * Populate TLS context with TLS 1.3-related signature parameters. diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index cfc0aca47..4d5143eaf 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -907,6 +907,24 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) if (TLS_DANE_BASED(props->tls_level)) protomask |= TLS_PROTOCOL_SSLv2; + /* + * Allocate a new TLScontext for the new connection and get an SSL + * structure. Add the location of TLScontext to the SSL to later retrieve + * the information inside the tls_verify_certificate_callback(). + * + * If session caching was enabled when TLS was initialized, the cache type + * is stored in the client SSL context. + */ + TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); + TLScontext->cache_type = app_ctx->cache_type; + + if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { + msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + /* * Per session cipher selection for sessions with mandatory encryption * @@ -914,11 +932,11 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) * to stay the same between connections, so we make use of a 1-element * cache to return the same result for identical inputs. */ - cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, + cipher_list = tls_set_ciphers(TLScontext, props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { - msg_warn("%s: %s: aborting TLS session", - props->namaddr, vstring_str(app_ctx->why)); + /* already warned */ + tls_free_context(TLScontext); return (0); } if (log_mask & TLS_LOG_VERBOSE) @@ -949,17 +967,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) */ myserverid = tls_serverid_digest(props, protomask, cipher_list); - /* - * Allocate a new TLScontext for the new connection and get an SSL - * structure. Add the location of TLScontext to the SSL to later retrieve - * the information inside the tls_verify_certificate_callback(). - * - * If session caching was enabled when TLS was initialized, the cache type - * is stored in the client SSL context. - */ - TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); - TLScontext->cache_type = app_ctx->cache_type; - TLScontext->serverid = myserverid; TLScontext->stream = props->stream; TLScontext->mdalg = props->mdalg; @@ -967,12 +974,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) /* Alias DANE digest info from props */ TLScontext->dane = props->dane; - if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { - msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); - tls_print_errors(); - tls_free_context(TLScontext); - return (0); - } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c index 01dda8a97..a28623af5 100644 --- a/postfix/src/tls/tls_misc.c +++ b/postfix/src/tls/tls_misc.c @@ -76,9 +76,8 @@ /* const char *str_tls_cipher_grade(grade) /* int grade; /* -/* const char *tls_set_ciphers(app_ctx, context, grade, exclusions) -/* TLS_APPL_STATE *app_ctx; -/* const char *context; +/* const char *tls_set_ciphers(TLScontext, grade, exclusions) +/* TLS_SESS_STATE *TLScontext; /* int grade; /* const char *exclusions; /* @@ -171,13 +170,11 @@ /* When the input specifies an undefined grade, str_tls_cipher_grade() /* logs no warning, returns a null pointer. /* -/* tls_set_ciphers() generates a cipher list from the specified -/* grade, minus any ciphers specified via a list of exclusions. -/* The cipherlist is applied to the supplied SSL context if it -/* is different from the most recently applied value. The return -/* value is the cipherlist used and is overwritten upon each call. -/* When the input is invalid, tls_set_ciphers() logs a warning with -/* the specified context, and returns a null pointer result. +/* tls_set_ciphers() applies the requested cipher grade and exclusions +/* to the provided TLS session context, returning the resulting cipher +/* list string. The return value is the cipherlist used and is +/* overwritten upon each call. When the input is invalid, +/* tls_set_ciphers() logs a warning, and returns a null result. /* /* tls_get_signature_params() updates the "TLScontext" with handshake /* signature parameters pertaining to TLS 1.3, where the ciphersuite @@ -536,22 +533,6 @@ typedef struct { int status; } TLS_VINFO; - /* - * OpenSSL adopted the cipher selection patch, so we don't expect any more - * broken ciphers other than AES and CAMELLIA. - */ -typedef struct { - const char *ssl_name; - const int alg_bits; - const char *evp_name; -} cipher_probe_t; - -static const cipher_probe_t cipher_probes[] = { - "AES", 256, "AES-256-CBC", - "CAMELLIA", 256, "CAMELLIA-256-CBC", - 0, 0, 0, -}; - /* tls_log_mask - Convert user TLS loglevel to internal log feature mask */ int tls_log_mask(const char *log_param, const char *log_level) @@ -570,113 +551,6 @@ void tls_update_app_logmask(TLS_APPL_STATE *app_ctx, int log_mask) app_ctx->log_mask = log_mask; } -/* tls_exclude_missing - Append exclusions for missing ciphers */ - -static const char *tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf) -{ - const char *myname = "tls_exclude_missing"; - static ARGV *exclude; /* Cached */ - SSL *s = 0; - ssl_cipher_stack_t *ciphers; - const SSL_CIPHER *c; - const cipher_probe_t *probe; - int alg_bits; - int num; - int i; - - /* - * Process a list of probes which specify: - * - * An SSL cipher-suite name for a family of ciphers that use the same - * symmetric algorithm at two or more key sizes, typically 128/256 bits. - * - * The key size (typically 256) that OpenSSL fails to check, and assumes - * available when another key size (typically 128) is usable. - * - * The OpenSSL name of the symmetric algorithm associated with the SSL - * cipher-suite. Typically, this is MUMBLE-256-CBC, where "MUMBLE" is the - * name of the SSL cipher-suite that use the MUMBLE symmetric algorithm. - * On systems that support the required encryption algorithm, the name is - * listed in the output of "openssl list-cipher-algorithms". - * - * When an encryption algorithm is not available at the given key size but - * the corresponding OpenSSL cipher-suite contains ciphers that have have - * this key size, the problem ciphers are explicitly disabled in Postfix. - * The list is cached in the static "exclude" array. - */ - if (exclude == 0) { - exclude = argv_alloc(1); - - /* - * Iterate over the probe list - */ - for (probe = cipher_probes; probe->ssl_name; ++probe) { - /* No exclusions if evp_name is a valid algorithm */ - if (EVP_get_cipherbyname(probe->evp_name)) - continue; - - /* - * Sadly there is no SSL_CTX_get_ciphers() interface, so we are - * forced to allocate and free an SSL object. Fatal error if we - * can't allocate the SSL object. - */ - ERR_clear_error(); - if (s == 0 && (s = SSL_new(ctx)) == 0) { - tls_print_errors(); - msg_fatal("%s: error allocating SSL object", myname); - } - - /* - * Cipher is not supported by libcrypto, nothing to do if also - * not supported by libssl. Flush the OpenSSL error stack. - * - * XXX: There may be additional places in pre-existing code where - * SSL errors are generated and ignored, that require a similar - * "flush". Better yet, is to always flush before calls that run - * tls_print_errors() on failure. - * - * Contrary to documentation, on SunOS 5.10 SSL_set_cipher_list() - * returns success with no ciphers selected, when this happens - * SSL_get_ciphers() produces a stack with 0 elements! - */ - if (SSL_set_cipher_list(s, probe->ssl_name) == 0 - || (ciphers = SSL_get_ciphers(s)) == 0 - || (num = sk_SSL_CIPHER_num(ciphers)) == 0) { - ERR_clear_error(); /* flush any generated errors */ - continue; - } - for (i = 0; i < num; ++i) { - c = sk_SSL_CIPHER_value(ciphers, i); - (void) SSL_CIPHER_get_bits(c, &alg_bits); - if (alg_bits == probe->alg_bits) - argv_add(exclude, SSL_CIPHER_get_name(c), ARGV_END); - } - } - if (s != 0) - SSL_free(s); - } - for (i = 0; i < exclude->argc; ++i) - vstring_sprintf_append(buf, ":!%s", exclude->argv[i]); - return (vstring_str(buf)); -} - -/* tls_apply_cipher_list - update SSL_CTX cipher list */ - -static const char *tls_apply_cipher_list(TLS_APPL_STATE *app_ctx, - const char *context, VSTRING *spec) -{ - const char *new = tls_exclude_missing(app_ctx->ssl_ctx, spec); - - ERR_clear_error(); - if (SSL_CTX_set_cipher_list(app_ctx->ssl_ctx, new) == 0) { - tls_print_errors(); - vstring_sprintf(app_ctx->why, "invalid %s cipher list: \"%s\"", - context, new); - return (0); - } - return (new); -} - /* tls_protocol_mask - Bitmask of protocols to exclude */ int tls_protocol_mask(const char *plist) @@ -738,11 +612,13 @@ void tls_param_init(void) VAR_OPENSSL_PATH, DEF_OPENSSL_PATH, &var_openssl_path, 1, 0, 0, }; + /* If this changes, update TLS_CLIENT_PARAMS in tls_proxy.h. */ static const CONFIG_INT_TABLE int_table[] = { VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 1, 0, 0, }; + /* If this changes, update TLS_CLIENT_PARAMS in tls_proxy.h. */ static const CONFIG_BOOL_TABLE bool_table[] = { VAR_TLS_APPEND_DEF_CA, DEF_TLS_APPEND_DEF_CA, &var_tls_append_def_CA, @@ -772,6 +648,8 @@ void tls_pre_jail_init(TLS_ROLE role) }; int flags; + tls_param_init(); + /* Nothing for clients at this time */ if (role != TLS_ROLE_SERVER) return; @@ -804,7 +682,6 @@ static int server_sni_callback(SSL *ssl, int *alert, void *arg) TLScontext->namaddr, sni); return SSL_TLSEXT_ERR_NOACK; } - do { /* Don't silently skip maps opened with the wrong flags. */ pem = maps_file_find(tls_server_sni_maps, cp, 0); @@ -821,11 +698,12 @@ static int server_sni_callback(SSL *ssl, int *alert, void *arg) } msg_info("TLS SNI %s from %s not matched, using default chain", sni, TLScontext->namaddr); + /* * XXX: We could lie and pretend to accept the name, but since we've - * previously not impemented the callback (with OpenSSL then declining - * the extension), and nothing bad happened, declining it explicitly - * should be safe. + * previously not implemented the callback (with OpenSSL then + * declining the extension), and nothing bad happened, declining it + * explicitly should be safe. */ return SSL_TLSEXT_ERR_NOACK; } @@ -841,45 +719,24 @@ static int server_sni_callback(SSL *ssl, int *alert, void *arg) /* tls_set_ciphers - Set SSL context cipher list */ -const char *tls_set_ciphers(TLS_APPL_STATE *app_ctx, const char *context, - const char *grade, const char *exclusions) +const char *tls_set_ciphers(TLS_SESS_STATE *TLScontext, const char *grade, + const char *exclusions) { const char *myname = "tls_set_ciphers"; static VSTRING *buf; - int new_grade; char *save; char *cp; char *tok; - const char *new_list; - new_grade = tls_cipher_grade(grade); - if (new_grade == TLS_CIPHER_NONE) { - vstring_sprintf(app_ctx->why, "invalid %s cipher grade: \"%s\"", - context, grade); - return (0); - } if (buf == 0) buf = vstring_alloc(10); VSTRING_RESET(buf); - /* - * Given cached state and identical input, we return the same result. - */ - if (app_ctx->cipher_list) { - if (new_grade == app_ctx->cipher_grade - && strcmp(app_ctx->cipher_exclusions, exclusions) == 0) - return (app_ctx->cipher_list); - - /* Change required, flush cached state */ - app_ctx->cipher_grade = TLS_CIPHER_NONE; - - myfree(app_ctx->cipher_exclusions); - app_ctx->cipher_exclusions = 0; - - myfree(app_ctx->cipher_list); - app_ctx->cipher_list = 0; - } - switch (new_grade) { + switch (tls_cipher_grade(grade)) { + case TLS_CIPHER_NONE: + msg_warn("%s: invalid cipher grade: \"%s\"", + TLScontext->namaddr, grade); + return (0); case TLS_CIPHER_HIGH: vstring_strcpy(buf, var_tls_high_clist); break; @@ -896,11 +753,8 @@ const char *tls_set_ciphers(TLS_APPL_STATE *app_ctx, const char *context, vstring_strcpy(buf, var_tls_null_clist); break; default: - - /* - * The caller MUST provide a valid cipher grade - */ - msg_panic("invalid %s cipher grade: %d", context, new_grade); + /* Internal error, valid grade, but missing case label. */ + msg_panic("%s: unexpected cipher grade: %s", myname, grade); } /* @@ -921,23 +775,22 @@ const char *tls_set_ciphers(TLS_APPL_STATE *app_ctx, const char *context, * Can't exclude ciphers that start with modifiers. */ if (strchr("!+-@", *tok)) { - vstring_sprintf(app_ctx->why, - "invalid unary '!+-@' in %s cipher " - "exclusion: \"%s\"", context, tok); + msg_warn("%s: invalid unary '!+-@' in cipher exclusion: %s", + TLScontext->namaddr, tok); return (0); } vstring_sprintf_append(buf, ":!%s", tok); } myfree(save); } - if ((new_list = tls_apply_cipher_list(app_ctx, context, buf)) == 0) + ERR_clear_error(); + if (SSL_set_cipher_list(TLScontext->con, vstring_str(buf)) == 0) { + msg_warn("%s: error setting cipher grade: \"%s\"", + TLScontext->namaddr, grade); + tls_print_errors(); return (0); - - /* Cache new state */ - app_ctx->cipher_grade = new_grade; - app_ctx->cipher_exclusions = mystrdup(exclusions); - - return (app_ctx->cipher_list = mystrdup(new_list)); + } + return (vstring_str(buf)); } /* tls_get_signature_params - TLS 1.3 signature details */ @@ -1118,10 +971,10 @@ void tls_log_summary(TLS_ROLE role, TLS_USAGE usage, TLS_SESS_STATE *ctx) const char *sni = (role == TLS_ROLE_CLIENT) ? 0 : ctx->peer_sni; /* - * When SNI was sent and accepted, the server-side log message now includes - * a "to " detail after the "from " detail identifying - * the remote client. We don't presently log (purportedly) accepted SNI on - * the client side. + * When SNI was sent and accepted, the server-side log message now + * includes a "to " detail after the "from " detail + * identifying the remote client. We don't presently log (purportedly) + * accepted SNI on the client side. */ vstring_sprintf(msg, "%s TLS connection %s %s %s%s%s: %s" " with cipher %s (%d/%d bits)", @@ -1129,7 +982,7 @@ void tls_log_summary(TLS_ROLE role, TLS_USAGE usage, TLS_SESS_STATE *ctx) TLS_CERT_IS_SECURED(ctx) ? "Verified" : TLS_CERT_IS_TRUSTED(ctx) ? "Trusted" : "Untrusted", usage == TLS_USAGE_NEW ? "established" : "reused", - direction, ctx->namaddr, sni ? " to " : "", sni ? sni : "", + direction, ctx->namaddr, sni ? " to " : "", sni ? sni : "", ctx->protocol, ctx->cipher_name, ctx->cipher_usebits, ctx->cipher_algbits); @@ -1182,11 +1035,7 @@ TLS_APPL_STATE *tls_alloc_app_context(SSL_CTX *ssl_ctx, SSL_CTX *sni_ctx, app_ctx->log_mask = log_mask; /* See also: cache purging code in tls_set_ciphers(). */ - app_ctx->cipher_grade = TLS_CIPHER_NONE; - app_ctx->cipher_exclusions = 0; - app_ctx->cipher_list = 0; app_ctx->cache_type = 0; - app_ctx->why = vstring_alloc(1); if (tls_server_sni_maps) { SSL_CTX_set_tlsext_servername_callback(ssl_ctx, server_sni_callback); @@ -1205,13 +1054,6 @@ void tls_free_app_context(TLS_APPL_STATE *app_ctx) SSL_CTX_free(app_ctx->sni_ctx); if (app_ctx->cache_type) myfree(app_ctx->cache_type); - /* See also: cache purging code in tls_set_ciphers(). */ - if (app_ctx->cipher_exclusions) - myfree(app_ctx->cipher_exclusions); - if (app_ctx->cipher_list) - myfree(app_ctx->cipher_list); - if (app_ctx->why) - vstring_free(app_ctx->why); myfree((void *) app_ctx); } diff --git a/postfix/src/tls/tls_server.c b/postfix/src/tls/tls_server.c index 9d4760022..6c0328de6 100644 --- a/postfix/src/tls/tls_server.c +++ b/postfix/src/tls/tls_server.c @@ -779,16 +779,6 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props) if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection from %s", props->namaddr); - cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, - props->cipher_exclusions); - if (cipher_list == 0) { - msg_warn("%s: %s: aborting TLS session", props->namaddr, - vstring_str(app_ctx->why)); - return (0); - } - if (log_mask & TLS_LOG_VERBOSE) - msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); - /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve @@ -797,11 +787,6 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props) TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; - TLScontext->serverid = mystrdup(props->serverid); - TLScontext->am_server = 1; - TLScontext->stream = props->stream; - TLScontext->mdalg = props->mdalg; - ERR_clear_error(); if ((TLScontext->con = (SSL *) SSL_new(app_ctx->ssl_ctx)) == 0) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); @@ -809,6 +794,21 @@ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props) tls_free_context(TLScontext); return (0); } + cipher_list = tls_set_ciphers(TLScontext, props->cipher_grade, + props->cipher_exclusions); + if (cipher_list == 0) { + /* already warned */ + tls_free_context(TLScontext); + return (0); + } + if (log_mask & TLS_LOG_VERBOSE) + msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); + + TLScontext->serverid = mystrdup(props->serverid); + TLScontext->am_server = 1; + TLScontext->stream = props->stream; + TLScontext->mdalg = props->mdalg; + if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); diff --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c index 2c8714cb4..7339da6b9 100644 --- a/postfix/src/tlsproxy/tlsproxy.c +++ b/postfix/src/tlsproxy/tlsproxy.c @@ -498,7 +498,6 @@ char *var_tlsp_clnt_policy; * TLS per-process status. */ static TLS_APPL_STATE *tlsp_server_ctx; -static TLS_APPL_STATE *tlsp_client_ctx; static bool tlsp_pre_jail_done; static int ask_client_cert; static char *tlsp_pre_jail_client_param_key; /* pre-jail global params */ @@ -947,7 +946,13 @@ static int tlsp_client_start_pre_handshake(TLSP_STATE *state) { state->client_start_props->ctx = state->appl_state; state->client_start_props->fd = state->ciphertext_fd; - state->tls_context = tls_client_start(state->client_start_props); + /* These predicates and warning belong inside tls_client_start(). */ + if (!TLS_DANE_BASED(state->client_start_props->tls_level) + || tls_dane_avail()) + state->tls_context = tls_client_start(state->client_start_props); + else + msg_warn("%s: DANE requested, but not available", + state->client_start_props->namaddr); if (state->tls_context != 0) return (TLSP_STAT_OK); @@ -1136,24 +1141,19 @@ static void tlsp_log_config_diff(const char *server_cfg, const char *client_cfg) myfree(saved_server); } - /* - * Macro for readability. - */ -#define TLSP_CLIENT_INIT(params, props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ - a10, a11, a12, a13, a14) \ - tlsp_client_init((params), TLS_CLIENT_INIT_ARGS((props), a1, a2, a3, a4, \ - a5, a6, a7, a8, a9, a10, a11, a12, a13, a14)) - /* tlsp_client_init - initialize a TLS client engine */ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, - TLS_CLIENT_INIT_PROPS *init_props) + TLS_CLIENT_INIT_PROPS *init_props, + int dane_based) { TLS_APPL_STATE *appl_state; VSTRING *param_buf; char *param_key; VSTRING *init_buf; char *init_key; + VSTRING *init_buf_for_hashing; + char *init_key_for_hashing; int log_hints = 0; /* @@ -1165,6 +1165,11 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, * First, compute the TLS_APPL_STATE cache lookup key. Save a copy of the * pre-jail request TLS_CLIENT_PARAMS and TLSPROXY_CLIENT_INIT_PROPS * settings, so that we can detect post-jail requests that do not match. + * + * Workaround: salt the hash-table key with DANE on/off info. This avoids + * cross-talk between DANE and non-DANE sessions. Postfix DANE support + * modifies SSL_CTX to override certificate verification because there is + * no other way to do this before OpenSSL 1.1.0. */ param_buf = vstring_alloc(100); param_key = tls_proxy_client_param_with_names_to_string( @@ -1172,12 +1177,18 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, init_buf = vstring_alloc(100); init_key = tls_proxy_client_init_with_names_to_string( init_buf, init_props); + init_buf_for_hashing = vstring_alloc(100); + init_key_for_hashing = STR(vstring_sprintf(init_buf_for_hashing, "%s%d\n", + init_key, dane_based)); if (tlsp_pre_jail_done == 0) { - if (tlsp_pre_jail_client_param_key != 0 - || tlsp_pre_jail_client_init_key != 0) - msg_panic("tlsp_client_init: multiple pre-jail calls"); - tlsp_pre_jail_client_param_key = mystrdup(param_key); - tlsp_pre_jail_client_init_key = mystrdup(init_key); + if (tlsp_pre_jail_client_param_key == 0 + || tlsp_pre_jail_client_init_key == 0) { + tlsp_pre_jail_client_param_key = mystrdup(param_key); + tlsp_pre_jail_client_init_key = mystrdup(init_key); + } else if (strcmp(tlsp_pre_jail_client_param_key, param_key) != 0 + || strcmp(tlsp_pre_jail_client_init_key, init_key) != 0) { + msg_panic("tlsp_client_init: too many pre-jail calls"); + } } /* @@ -1198,7 +1209,7 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, * Look up the cached TLS_APPL_STATE for this tls_client_init request. */ if ((appl_state = (TLS_APPL_STATE *) - htable_find(tlsp_client_app_cache, init_key)) == 0) { + htable_find(tlsp_client_app_cache, init_key_for_hashing)) == 0) { /* * Before creating a TLS_APPL_STATE instance, log a warning if a @@ -1249,7 +1260,7 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, */ if (appl_state == 0 && (appl_state = tls_client_init(init_props)) != 0) { - (void) htable_enter(tlsp_client_app_cache, init_key, + (void) htable_enter(tlsp_client_app_cache, init_key_for_hashing, (void *) appl_state); /* @@ -1263,6 +1274,7 @@ static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_PARAMS *tls_params, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); } + vstring_free(init_buf_for_hashing); vstring_free(init_buf); vstring_free(param_buf); return (appl_state); @@ -1364,7 +1376,8 @@ static void tlsp_get_request_event(int event, void *context) return; } state->appl_state = tlsp_client_init(state->tls_params, - state->client_init_props); + state->client_init_props, + TLS_DANE_BASED(state->client_start_props->tls_level)); ready = state->appl_state != 0; break; case TLS_PROXY_FLAG_ROLE_SERVER: @@ -1645,6 +1658,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) if (clnt_use_tls || var_tlsp_clnt_per_site[0] || var_tlsp_clnt_policy[0]) { TLS_CLIENT_PARAMS tls_params; TLS_CLIENT_INIT_PROPS init_props; + int dane_based_mode; tls_pre_jail_init(TLS_ROLE_CLIENT); @@ -1655,25 +1669,27 @@ static void pre_jail_init(char *unused_name, char **unused_argv) * Large parameter lists are error-prone, so we emulate a language * feature that C does not have natively: named parameter lists. */ - tlsp_client_ctx = - TLSP_CLIENT_INIT(tls_proxy_client_param_from_config(&tls_params), - &init_props, - log_param = var_tlsp_clnt_logparam, - log_level = var_tlsp_clnt_loglevel, - verifydepth = var_tlsp_clnt_scert_vd, - cache_type = TLS_MGR_SCACHE_SMTP, - chain_files = var_tlsp_clnt_chain_files, - cert_file = var_tlsp_clnt_cert_file, - key_file = var_tlsp_clnt_key_file, - dcert_file = var_tlsp_clnt_dcert_file, - dkey_file = var_tlsp_clnt_dkey_file, - eccert_file = var_tlsp_clnt_eccert_file, - eckey_file = var_tlsp_clnt_eckey_file, - CAfile = var_tlsp_clnt_CAfile, - CApath = var_tlsp_clnt_CApath, - mdalg = var_tlsp_clnt_fpt_dgst); - if (tlsp_client_ctx == 0) - msg_warn("TLS client initialization failed"); + (void) tls_proxy_client_param_from_config(&tls_params); + (void) TLS_CLIENT_INIT_ARGS(&init_props, + log_param = var_tlsp_clnt_logparam, + log_level = var_tlsp_clnt_loglevel, + verifydepth = var_tlsp_clnt_scert_vd, + cache_type = TLS_MGR_SCACHE_SMTP, + chain_files = var_tlsp_clnt_chain_files, + cert_file = var_tlsp_clnt_cert_file, + key_file = var_tlsp_clnt_key_file, + dcert_file = var_tlsp_clnt_dcert_file, + dkey_file = var_tlsp_clnt_dkey_file, + eccert_file = var_tlsp_clnt_eccert_file, + eckey_file = var_tlsp_clnt_eckey_file, + CAfile = var_tlsp_clnt_CAfile, + CApath = var_tlsp_clnt_CApath, + mdalg = var_tlsp_clnt_fpt_dgst); + for (dane_based_mode = 0; dane_based_mode < 2; dane_based_mode++) { + if (tlsp_client_init(&tls_params, &init_props, + dane_based_mode) == 0) + msg_warn("TLS client initialization failed"); + } } /*