]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.4.0-RC3 v3.4.0-RC3
authorWietse Venema <wietse@porcupine.org>
Thu, 21 Feb 2019 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Fri, 22 Feb 2019 07:44:03 +0000 (02:44 -0500)
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/master/master_spawn.c
postfix/src/smtp/smtp_proto.c
postfix/src/tls/tls.h
postfix/src/tls/tls_client.c
postfix/src/tls/tls_misc.c
postfix/src/tls/tls_server.c
postfix/src/tlsproxy/tlsproxy.c

index a23dcad81dd87e7e05a4076c77293cb3676f0a79..4540a81daf68606d16727a4977416a84623163df 100644 (file)
@@ -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.
index bdd12ac2aac435f35dde682b5bdaf81d6cd971e9..87ee978c0425ae2964f991da187d478633727c40 100644 (file)
@@ -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
index 06bfa6715c743d280b17bfaf325b28259036031d..c3b70f2b430671f9ee7f7d60a034cf0f0cf2ba90 100644 (file)
@@ -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
index ce2352bc94c38443b3abd4f8133faa2ea6df7f70..a43a326af347247e56e92ea44b1a9cca45127bd9 100644 (file)
@@ -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);
index 6c10d4ad78695349e3bf85edb78b92850cc36b63..2a8cc11999611c249c77233620af721b8791467f 100644 (file)
@@ -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.
index cfc0aca475284d63e4b79d11dbbb6d5208db9b65..4d5143eaf0df1ba9f7cda5f877ca50f0d7917160 100644 (file)
@@ -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();
index 01dda8a97978ec03f0148dc92f321170689696cd..a28623af5e282ca4fde3209f74927bb4ec643eaa 100644 (file)
@@ -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;
 /*
 /*     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 <sni-name>" detail after the "from <namaddr>" 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 <sni-name>" detail after the "from <namaddr>" 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);
 }
 
index 9d47600224b7924c857d720354535fbbb536a0c5..6c0328de61fac12058c264175e5b3d28ffd9d90a 100644 (file)
@@ -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();
index 2c8714cb4c09aebc1934eb169ebccfb44e6d7395..7339da6b9618832822cb2e55d23c6d53c18532fb 100644 (file)
@@ -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");
+       }
     }
 
     /*