Skip to content

Commit

Permalink
postfix-3.4.28
Browse files Browse the repository at this point in the history
  • Loading branch information
wietse-postfix authored and Viktor Dukhovni committed Jan 22, 2023
1 parent 83348e6 commit 29302a2
Show file tree
Hide file tree
Showing 15 changed files with 179 additions and 40 deletions.
59 changes: 59 additions & 0 deletions postfix/HISTORY
Original file line number Diff line number Diff line change
Expand Up @@ -24818,3 +24818,62 @@ Apologies for any names omitted.
Cleanup: Postfix 3.4.26 introduced a missing msg_panic()
argument (in code that never executes). File:
cleanup/cleanup_milter.c.

20221128

Bugfix (introduced: Postfix 2.2): the smtpd_proxy_client
code mis-parsed the last XFORWARD attribute name in the
SMTP server's EHLO response. The result was that the
smtpd_proxy_client code failed to forward the IDENT attribute.
Fix by Andreas Weigel. File: smtpd/smtpd_proxy.c.

20221201

Portability: LINUX6 support. Files: makedefs, util/sys_defs.h.

20221207

Workaround: OpenSSL 3.x EVP_get_digestbyname() can return
lazily bound handles that may fail to work when one attempts
to use them, because no provider search happens until one
constructs an actual operation context. In sufficiently
hostile configurations, Postfix could mistakenly believe
that an algorithm is available, when in fact it is not. A
similar workaround may be needed for EVP_get_cipherbyname().
Fix by Viktor Dukhovni. Files: tls/tls.h, tls/tls_dane.c,
tls/tls_fprint.c, tls/tls_misc.c.

Bugfix (introduced: Postfix 2.11): the checkok() macro in
tls/tls_fprint.c evaluated its argument unconditionally;
it should evaluate the argument only if there was no prior
error. Found during code review. File: tls/tls_fprint.c.

20221215

Foolproofing: postscreen segfault with postscreen_dnsbl_threshold
< 1. It should reject such input with a fatal error instead.
Discovered by Benny Pedersen. File: postscreen/postscreen.c.

20230103

Bugfix (introduced: Postfix 2.7): the verify daemon logged
a garbled cache name when terminating a cache scan in
progress. Reported by Phil Biggs, fix by Viktor Dukhovni.
File: util/dict_cache.c.

Bitrot: fixes for linker warnings from newer Darwin (MacOS)
versions. Viktor Dukhovni. File: makedefs.

20230115

Workaround: STRREF() macro to shut up compiler warnings for
legitimate string comparison expressions. Back-ported from
Postfix 3.6 and later. Files: util/stringops.h, flush/flush.c.

Workaround for a breaking change in OpenSSL 3: always turn
on SSL_OP_IGNORE_UNEXPECTED_EOF, to avoid warning messages
and missed opportunities for TLS session reuse. This is
safe because the SMTP protocol implements application-level
framing, and is therefore not affected by TLS truncation
attacks. Fix by Viktor Dukhovni. Files: tls/tls.h, tls_client.c,
tls/tls_server.c.
12 changes: 9 additions & 3 deletions postfix/makedefs
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ EOF
: ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"}
: ${PLUGIN_LD="${CC-gcc} -shared"}
;;
Linux.[345].*) SYSTYPE=LINUX$RELEASE_MAJOR
Linux.[3456].*) SYSTYPE=LINUX$RELEASE_MAJOR
case "$CCARGS" in
*-DNO_DB*) ;;
*-DHAS_DB*) ;;
Expand Down Expand Up @@ -699,19 +699,25 @@ ReliantUNIX-?.5.43) SYSTYPE=ReliantUnix543
?.*|10.*) ;;
*) SYSLIBS="$SYSLIBS -lresolv";;
esac
# Darwin 21 linker without additional coaxing complains about
# -Wl,-undefined,dynamic_lookup
case $RELEASE in
2[1-9].*|[3-9]?.*) NOFIXUP="-Wl,-no_fixup_chains ";;
*) NOFIXUP="";;
esac
# kqueue and/or poll are broken in MacOS X 10.5 (Darwin 9).
# kqueue works in Mac OS X 10.8 (Darwin 12).
case $RELEASE in
?.*|1[0-1].*) CCARGS="$CCARGS -DNO_KQUEUE";;
esac
: ${SHLIB_CFLAGS=-fPIC}
: ${SHLIB_SUFFIX=.dylib}
: ${SHLIB_LD='cc -shared -Wl,-flat_namespace -Wl,-undefined,dynamic_lookup -Wl,-install_name,@rpath/${LIB}'}
: ${SHLIB_LD="cc -shared -Wl,-flat_namespace ${NOFIXUP}-Wl,-undefined,dynamic_lookup "'-Wl,-install_name,@rpath/${LIB}'}
: ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'}
# In MacOS/X 10.11.x /bin/sh unsets DYLD_LIBRARY_PATH, so we
# have export it into postfix-install indirectly!
: ${SHLIB_ENV="DYLD_LIBRARY_PATH=`pwd`/lib SHLIB_ENV_VAR=DYLD_LIBRARY_PATH SHLIB_ENV_VAL=`pwd`/lib"}
: ${PLUGIN_LD='cc -shared -Wl,-flat_namespace -Wl,-undefined,dynamic_lookup'}
: ${PLUGIN_LD="cc -shared -Wl,-flat_namespace ${NOFIXUP}-Wl,-undefined,dynamic_lookup"}
;;
dcosx.1*) SYSTYPE=DCOSX1
RANLIB=echo
Expand Down
2 changes: 1 addition & 1 deletion postfix/src/flush/flush.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ static DOMAIN_LIST *flush_domains;
* Silly little macros.
*/
#define STR(x) vstring_str(x)
#define STREQ(x,y) ((x) == (y) || strcmp(x,y) == 0)
#define STREQ(x,y) (STRREF(x) == STRREF(y) || strcmp(x,y) == 0)

/*
* Forward declarations resulting from breaking up routines according to
Expand Down
4 changes: 2 additions & 2 deletions postfix/src/global/mail_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 "20221007"
#define MAIL_VERSION_NUMBER "3.4.27"
#define MAIL_RELEASE_DATE "20230121"
#define MAIL_VERSION_NUMBER "3.4.28"

#ifdef SNAPSHOT
#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
Expand Down
2 changes: 1 addition & 1 deletion postfix/src/postscreen/postscreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@ int main(int argc, char **argv)
0,
};
static const CONFIG_INT_TABLE int_table[] = {
VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 0, 0,
VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 1, 0,
VAR_PSC_DNSBL_WTHRESH, DEF_PSC_DNSBL_WTHRESH, &var_psc_dnsbl_wthresh, 0, 0,
VAR_PSC_CMD_COUNT, DEF_PSC_CMD_COUNT, &var_psc_cmd_count, 1, 0,
VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
Expand Down
2 changes: 1 addition & 1 deletion postfix/src/smtpd/smtpd_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ static int smtpd_proxy_connect(SMTPD_STATE *state)
*/
server_xforward_features = 0;
lines = STR(proxy->reply);
while ((words = mystrtok(&lines, "\n")) != 0) {
while ((words = mystrtok(&lines, "\r\n")) != 0) {
if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
if (strcasecmp(word, XFORWARD_CMD) == 0)
while ((word = mystrtok(&words, " \t")) != 0)
Expand Down
11 changes: 10 additions & 1 deletion postfix/src/tls/tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,13 @@ extern void tls_param_init(void);
#define SSL_OP_NO_TLSv1_3 0L /* Noop */
#endif

/*
* Always used when defined, SMTP has no truncation attacks.
*/
#ifndef SSL_OP_IGNORE_UNEXPECTED_EOF
#define SSL_OP_IGNORE_UNEXPECTED_EOF 0L
#endif

#define TLS_KNOWN_PROTOCOLS \
( TLS_PROTOCOL_SSLv2 | TLS_PROTOCOL_SSLv3 | TLS_PROTOCOL_TLSv1 \
| TLS_PROTOCOL_TLSv1_1 | TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3 )
Expand All @@ -431,7 +438,8 @@ extern void tls_param_init(void);
* just exposed via hex codes or named elements of tls_ssl_options.
*/
#define TLS_SSL_OP_MANAGED_BITS \
(SSL_OP_CIPHER_SERVER_PREFERENCE | TLS_SSL_OP_PROTOMASK(~0))
(SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_IGNORE_UNEXPECTED_EOF | \
TLS_SSL_OP_PROTOMASK(~0))

extern int tls_protocol_mask(const char *);

Expand Down Expand Up @@ -679,6 +687,7 @@ extern void tls_dane_set_callback(SSL_CTX *, TLS_SESS_STATE *);
/*
* tls_fprint.c
*/
extern const EVP_MD *tls_digest_byname(const char *, EVP_MD_CTX **);
extern char *tls_digest_encode(const unsigned char *, int);
extern char *tls_data_fprint(const char *, int, const char *);
extern char *tls_cert_fprint(X509 *, const char *);
Expand Down
9 changes: 9 additions & 0 deletions postfix/src/tls/tls_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,15 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
*/
SSL_CTX_set_verify_depth(client_ctx, props->verifydepth + 1);

/*
* Presently we use TLS only with SMTP where truncation attacks are not
* possible as a result of application framing. If we ever use TLS in
* some other application protocol where truncation could be relevant,
* we'd need to disable truncation detection conditionally, or explicitly
* clear the option in that code path.
*/
off |= SSL_OP_IGNORE_UNEXPECTED_EOF;

/*
* Protocol selection is destination dependent, so we delay the protocol
* selection options to the per-session SSL object.
Expand Down
2 changes: 1 addition & 1 deletion postfix/src/tls/tls_dane.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ static dane_digest *add_digest(char *mdalg, int pref)
}

if (*dane_mdalg
&& ((md = EVP_get_digestbyname(dane_mdalg)) == 0
&& ((md = tls_digest_byname(dane_mdalg, NULL)) == 0
|| (mdlen = EVP_MD_size(md)) <= 0
|| mdlen > EVP_MAX_MD_SIZE)) {
msg_warn("Unimplemented digest algorithm in %s: %s%s%s",
Expand Down
76 changes: 63 additions & 13 deletions postfix/src/tls/tls_fprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
/* SYNOPSIS
/* #include <tls.h>
/*
/* EVP_MD *tls_digest_byname(const char *mdalg, EVP_MD_CTX **mdctxPtr)
/* const char *mdalg;
/* EVP_MD_CTX **mdctxPtr;
/*
/* char *tls_serverid_digest(props, protomask, ciphers)
/* const TLS_CLIENT_START_PROPS *props;
/* long protomask;
Expand All @@ -28,6 +32,13 @@
/* X509 *peercert;
/* const char *mdalg;
/* DESCRIPTION
/* tls_digest_byname() constructs, and optionally returns, an EVP_MD_CTX
/* handle for performing digest operations with the algorithm named by the
/* mdalg parameter. The return value is non-null on success, and holds a
/* digest algorithm handle. If the mdctxPtr argument is non-null the
/* created context is returned to the caller, who is then responsible for
/* deleting it by calling EVP_MD_ctx_free() once it is no longer needed.
/*
/* tls_digest_encode() converts a binary message digest to a hex ASCII
/* format with ':' separators between each pair of hex digits.
/* The return value is dynamically allocated with mymalloc(),
Expand Down Expand Up @@ -61,6 +72,8 @@
/* and the caller must eventually free it with myfree().
/*
/* Arguments:
/* .IP mdalg
/* A digest algorithm name, such as "sha256".
/* .IP peercert
/* Server or client X.509 certificate.
/* .IP md_buf
Expand All @@ -71,6 +84,9 @@
/* Name of a message digest algorithm suitable for computing secure
/* (1st pre-image resistant) message digests of certificates. For now,
/* md5, sha1, or member of SHA-2 family if supported by OpenSSL.
/* .IP mdctxPtr
/* Pointer to an (EVP_MD_CTX *) handle, or NULL if only probing for
/* algorithm support without immediate use in mind.
/* .IP buf
/* Input data for the message digest algorithm mdalg.
/* .IP len
Expand Down Expand Up @@ -125,7 +141,7 @@

static const char hexcodes[] = "0123456789ABCDEF";

#define checkok(ret) (ok &= ((ret) ? 1 : 0))
#define checkok(stillok) (ok = ok && (stillok))
#define digest_data(p, l) checkok(EVP_DigestUpdate(mdctx, (char *)(p), (l)))
#define digest_object(p) digest_data((p), sizeof(*(p)))
#define digest_string(s) digest_data((s), strlen(s)+1)
Expand Down Expand Up @@ -159,13 +175,50 @@ static int digest_tlsa_usage(EVP_MD_CTX * mdctx, TLS_TLSA *tlsa,
return (ok);
}

/* tls_digest_byname - test availability or prepare to use digest */

const EVP_MD *tls_digest_byname(const char *mdalg, EVP_MD_CTX **mdctxPtr)
{
const EVP_MD *md;
EVP_MD_CTX *mdctx = NULL;
int ok = 1;

/*
* In OpenSSL 3.0, because of dynamically variable algorithm providers,
* there is a time-of-check/time-of-use issue that means that abstract
* algorithm handles returned by EVP_get_digestbyname() can (and not
* infrequently do) return ultimately unusable algorithms, to check for
* actual availability, one needs to use the new EVP_MD_fetch() API, or
* indirectly check usability by creating a concrete context. We take the
* latter approach here (works for 1.1.1 without #ifdef).
*
* Note that EVP_MD_CTX_{create,destroy} were renamed to, respectively,
* EVP_MD_CTX_{new,free} in OpenSSL 1.1.0.
*/
checkok(md = EVP_get_digestbyname(mdalg));

/*
* Sanity check: Newer shared libraries could (hypothetical ABI break)
* allow larger digests, we avoid such poison algorithms.
*/
checkok(EVP_MD_size(md) <= EVP_MAX_MD_SIZE);
checkok(mdctx = EVP_MD_CTX_new());
checkok(EVP_DigestInit_ex(mdctx, md, NULL));


if (ok && mdctxPtr != 0)
*mdctxPtr = mdctx;
else
EVP_MD_CTX_free(mdctx);
return (ok ? md : 0);
}

/* tls_serverid_digest - suffix props->serverid with parameter digest */

char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
const char *ciphers)
{
EVP_MD_CTX *mdctx;
const EVP_MD *md;
const char *mdalg;
unsigned char md_buf[EVP_MAX_MD_SIZE];
unsigned int md_len;
Expand All @@ -181,17 +234,17 @@ char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
* default digest, but DANE requires sha256 and sha512, so if we must
* fall back to our default digest, DANE support won't be available. We
* panic if the fallback algorithm is not available, as it was verified
* available in tls_client_init() and must not simply vanish.
* available in tls_client_init() and must not simply vanish. Our
* provider set is not expected to change once the OpenSSL library is
* initialized.
*/
if ((md = EVP_get_digestbyname(mdalg = "sha256")) == 0
&& (md = EVP_get_digestbyname(mdalg = props->mdalg)) == 0)
msg_panic("digest algorithm \"%s\" not found", mdalg);
if (tls_digest_byname(mdalg = LN_sha256, &mdctx) == 0
&& tls_digest_byname(mdalg = props->mdalg, &mdctx) == 0)
msg_panic("digest algorithm \"%s\" not found", props->mdalg);

/* Salt the session lookup key with the OpenSSL runtime version. */
sslversion = OpenSSL_version_num();

mdctx = EVP_MD_CTX_create();
checkok(EVP_DigestInit_ex(mdctx, md, NULL));
digest_string(props->helo ? props->helo : "");
digest_object(&sslversion);
digest_object(&protomask);
Expand Down Expand Up @@ -284,18 +337,15 @@ char *tls_digest_encode(const unsigned char *md_buf, int md_len)

char *tls_data_fprint(const char *buf, int len, const char *mdalg)
{
EVP_MD_CTX *mdctx;
const EVP_MD *md;
EVP_MD_CTX *mdctx = NULL;
unsigned char md_buf[EVP_MAX_MD_SIZE];
unsigned int md_len;
int ok = 1;

/* Previously available in "init" routine. */
if ((md = EVP_get_digestbyname(mdalg)) == 0)
if (tls_digest_byname(mdalg, &mdctx) == 0)
msg_panic("digest algorithm \"%s\" not found", mdalg);

mdctx = EVP_MD_CTX_create();
checkok(EVP_DigestInit_ex(mdctx, md, NULL));
digest_data(buf, len);
checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
EVP_MD_CTX_destroy(mdctx);
Expand Down
20 changes: 5 additions & 15 deletions postfix/src/tls/tls_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1516,43 +1516,33 @@ long tls_bio_dump_cb(BIO *bio, int cmd, const char *argp, int argi,
int tls_validate_digest(const char *dgst)
{
const EVP_MD *md_alg;
unsigned int md_len;

/*
* Register SHA-2 digests, if implemented and not already registered.
* Improves interoperability with clients and servers that prematurely
* deploy SHA-2 certificates. Also facilitates DANE and TA support.
*/
#if defined(LN_sha256) && defined(NID_sha256) && !defined(OPENSSL_NO_SHA256)
if (!EVP_get_digestbyname(LN_sha224))
if (!tls_digest_byname(LN_sha224, NULL))
EVP_add_digest(EVP_sha224());
if (!EVP_get_digestbyname(LN_sha256))
if (!tls_digest_byname(LN_sha256, NULL))
EVP_add_digest(EVP_sha256());
#endif
#if defined(LN_sha512) && defined(NID_sha512) && !defined(OPENSSL_NO_SHA512)
if (!EVP_get_digestbyname(LN_sha384))
if (!tls_digest_byname(LN_sha384, NULL))
EVP_add_digest(EVP_sha384());
if (!EVP_get_digestbyname(LN_sha512))
if (!tls_digest_byname(LN_sha512, NULL))
EVP_add_digest(EVP_sha512());
#endif

/*
* If the administrator specifies an unsupported digest algorithm, fail
* now, rather than in the middle of a TLS handshake.
*/
if ((md_alg = EVP_get_digestbyname(dgst)) == 0) {
if ((md_alg = tls_digest_byname(dgst, NULL)) == 0) {
msg_warn("Digest algorithm \"%s\" not found", dgst);
return (0);
}

/*
* Sanity check: Newer shared libraries may use larger digests.
*/
if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) {
msg_warn("Digest algorithm \"%s\" output size %u too large",
dgst, md_len);
return (0);
}
return (1);
}

Expand Down
Loading

0 comments on commit 29302a2

Please sign in to comment.