From a34efb8d7d5d5a54e622015f4f71fb5646a47afa Mon Sep 17 00:00:00 2001
From: Wietse Z Venema
Date: Mon, 23 Sep 2024 00:00:00 -0500
Subject: [PATCH] postfix-3.10-20240923
---
postfix/HISTORY | 16 +++++++
postfix/WISHLIST | 7 ++++
postfix/html/postconf.5.html | 42 +++++++++++--------
postfix/man/man5/postconf.5 | 42 +++++++++++--------
postfix/proto/postconf.proto | 42 +++++++++++--------
postfix/proto/stop | 8 ++++
postfix/proto/stop.double-history | 1 +
postfix/proto/stop.spell-history | 1 +
postfix/src/global/mail_params.h | 8 ++--
postfix/src/global/mail_version.h | 2 +-
postfix/src/tls/Makefile.in | 1 +
postfix/src/tls/tls.h | 9 ++++
postfix/src/tls/tls_dh.c | 70 +++++++++++++++++--------------
postfix/src/tls/tls_misc.c | 17 ++++++++
14 files changed, 176 insertions(+), 90 deletions(-)
diff --git a/postfix/HISTORY b/postfix/HISTORY
index d2b98f48c..616323f8b 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -28220,3 +28220,19 @@ Apologies for any names omitted.
Minor feature: "postcat -f" option to prepend the filename
to each output line. This simplifies test data development.
File: postcat/postcat.c.
+
+20240919
+
+ Bitrot: With OpenSSL 3.0 additional key exchange algorithms
+ can be runtime loaded via "providers", and these don't have
+ short internal numeric ids (nids). We've been using numeric
+ ids to configure key exchange groups, and for logging the
+ negotiated group. We now need to switch to APIs that work
+ directly with string names. OpenSSL 3.0 supports not only
+ (EC)DH key exchange groups but also more general KEMs (Key
+ Encapsulation Mechanisms), in which the response from the
+ server to the client contains no server public key. So we
+ can no longer reliably deduce the negotiated group from a
+ "peer" key, and may need to fall back on the (new with
+ OpenSSL 3.2) SSL_get0_group_name() function. Viktor Dukhovni.
+ Files: src/tls/tls.h, src/tls/tls_dh.c, src/tls/tls_misc.c.
diff --git a/postfix/WISHLIST b/postfix/WISHLIST
index f2112a779..baa23fdd1 100644
--- a/postfix/WISHLIST
+++ b/postfix/WISHLIST
@@ -8,6 +8,13 @@ Wish list:
Add tests for Message-ID extraction in the cleanup daemon.
+ When debug logging is enabled, dict_db_open() logs a newline
+ character after the version info.
+
+ postsuper fails to write the maillog file while Postfix is down
+ (the fallback to 'direct write' happens after an irreversible
+ set_ugid() call).
+
The postdrop code should be more explicit about what
attrributes it will pass through. rec_attr_map() is not
supposed to be an approver.
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html
index 57b9b1390..988b6f4d9 100644
--- a/postfix/html/postconf.5.html
+++ b/postfix/html/postconf.5.html
@@ -20124,21 +20124,27 @@ be using 0.9.6!
tls_eecdh_auto_curves
(default: see "postconf -d" output)
- The prioritized list of elliptic curves supported by the Postfix
-SMTP client and server. These curves are used by the Postfix SMTP
-server when "smtpd_tls_eecdh_grade = auto". The selected curves must be
-implemented by OpenSSL and be standardized for use in TLS (RFC 8422).
-It is unwise to list only "bleeding-edge" curves supported by a small
-subset of clients. The default list is suitable for most users.
+ The prioritized list of elliptic curves, that should be enabled in the
+Postfix SMTP client and server. These are used by the Postfix SMTP server when
+"smtpd_tls_eecdh_grade = auto". The selected curves should be implemented
+by OpenSSL and be standardized for use in the TLS "supported groups" extension
+(RFC8422, RFC8446 and RFC8447). Be sure to include at least "x25519" and
+"prime256v1" (the OpenSSL name for "secp256r1", a.k.a. "P-256"). The default
+list is suitable for most users.
- Postfix skips curve names that are unknown to OpenSSL, or that
-are known but not yet implemented. This makes it possible to
-"anticipate" support for curves that should be used once they become
-available. In particular, in some OpenSSL versions, the new RFC
-8031 curves "X25519" and "X448" may be known by name, but ECDH
-support for either or both may be missing. These curves may appear
-in the default value of this parameter, even though they'll only
-be usable with later versions of OpenSSL.
+ On the client side, the first curve listed will be used to construct the
+client's initial TLS 1.3 "keyshare". If this is not supported by the server,
+the TLS handshake may require an additional round-trip after the server issues
+a HelloRetryRequest (HRR) indicating a suitable mutually supported curve.
+
+ Postfix skips curve names that are unknown to OpenSSL, or that are known
+but not yet implemented. This makes it possible to "anticipate" support for
+curves that should be used once they become available, or to deploy the same
+setting on a server "farm" where not all servers support the same curves.
+
+ As of Postfix 3.10, when compiled with OpenSSL 3.0 or later, the "curve"
+names can be more general key encapsulation mechanisms (KEMs), and/or may be
+loaded from an external "provider" (via a suitable tls_config_file).
See also the "tls_ffdhe_auto_groups" parameter, which supports
customizing the list of FFDHE groups enabled with TLS 1.3. That setting
@@ -20293,10 +20299,10 @@ EC key agreement in OpenSSL 3.0 and later. Note that at least one of
this is required by OpenSSL 3.0. If both are inadvertently set empty,
Postfix will fall back to the compiled-in defaults.
- All the default groups and EC curves should sufficiently strong
-to make "pruning" the defaults unwise. At a minimum, "X25519" and
-"P-256" (a.k.a. "prime256v1") should be among the enabled EC curves,
-while "dhe2048" and "dhe3072" should be among the FFDHE groups.
+ All the default groups and EC curves should sufficiently strong to make
+"pruning" the defaults unwise. At a minimum, "x25519" and "prime256v1" (the
+OpenSSL name for "secp256r1", a.k.a. "P-256") should be among the enabled EC
+curves, while "dhe2048" and "dhe3072" should be among the FFDHE groups.
This feature is available in Postfix 3.8 and later, when it is
compiled and linked with OpenSSL 3.0 or later.
diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5
index 91beac06d..7e367f164 100644
--- a/postfix/man/man5/postconf.5
+++ b/postfix/man/man5/postconf.5
@@ -13984,21 +13984,27 @@ Postfix >= 3.4. See \fBSSL_CTX_set_options\fR(3).
.PP
This feature is available in Postfix 2.8 and later.
.SH tls_eecdh_auto_curves (default: see "postconf \-d" output)
-The prioritized list of elliptic curves supported by the Postfix
-SMTP client and server. These curves are used by the Postfix SMTP
-server when "smtpd_tls_eecdh_grade = auto". The selected curves must be
-implemented by OpenSSL and be standardized for use in TLS (RFC 8422).
-It is unwise to list only "bleeding\-edge" curves supported by a small
-subset of clients. The default list is suitable for most users.
+The prioritized list of elliptic curves, that should be enabled in the
+Postfix SMTP client and server. These are used by the Postfix SMTP server when
+"smtpd_tls_eecdh_grade = auto". The selected curves should be implemented
+by OpenSSL and be standardized for use in the TLS "supported groups" extension
+(RFC8422, RFC8446 and RFC8447). Be sure to include at least "x25519" and
+"prime256v1" (the OpenSSL name for "secp256r1", a.k.a. "P\-256"). The default
+list is suitable for most users.
.PP
-Postfix skips curve names that are unknown to OpenSSL, or that
-are known but not yet implemented. This makes it possible to
-"anticipate" support for curves that should be used once they become
-available. In particular, in some OpenSSL versions, the new RFC
-8031 curves "X25519" and "X448" may be known by name, but ECDH
-support for either or both may be missing. These curves may appear
-in the default value of this parameter, even though they'll only
-be usable with later versions of OpenSSL.
+On the client side, the first curve listed will be used to construct the
+client's initial TLS 1.3 "keyshare". If this is not supported by the server,
+the TLS handshake may require an additional round\-trip after the server issues
+a HelloRetryRequest (HRR) indicating a suitable mutually supported curve.
+.PP
+Postfix skips curve names that are unknown to OpenSSL, or that are known
+but not yet implemented. This makes it possible to "anticipate" support for
+curves that should be used once they become available, or to deploy the same
+setting on a server "farm" where not all servers support the same curves.
+.PP
+As of Postfix 3.10, when compiled with OpenSSL 3.0 or later, the "curve"
+names can be more general key encapsulation mechanisms (KEMs), and/or may be
+loaded from an external "provider" (via a suitable tls_config_file).
.PP
See also the "tls_ffdhe_auto_groups" parameter, which supports
customizing the list of FFDHE groups enabled with TLS 1.3. That setting
@@ -14115,10 +14121,10 @@ EC key agreement in OpenSSL 3.0 and later. Note that at least one of
this is required by OpenSSL 3.0. If both are inadvertently set empty,
Postfix will fall back to the compiled\-in defaults.
.PP
-All the default groups and EC curves should sufficiently strong
-to make "pruning" the defaults unwise. At a minimum, "X25519" and
-"P\-256" (a.k.a. "prime256v1") should be among the enabled EC curves,
-while "dhe2048" and "dhe3072" should be among the FFDHE groups.
+All the default groups and EC curves should sufficiently strong to make
+"pruning" the defaults unwise. At a minimum, "x25519" and "prime256v1" (the
+OpenSSL name for "secp256r1", a.k.a. "P\-256") should be among the enabled EC
+curves, while "dhe2048" and "dhe3072" should be among the FFDHE groups.
.PP
This feature is available in Postfix 3.8 and later, when it is
compiled and linked with OpenSSL 3.0 or later.
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 24b8295f2..d0f3bd145 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -13364,21 +13364,27 @@ parameter. See there for details.
%PARAM tls_eecdh_auto_curves see "postconf -d" output
- The prioritized list of elliptic curves supported by the Postfix
-SMTP client and server. These curves are used by the Postfix SMTP
-server when "smtpd_tls_eecdh_grade = auto". The selected curves must be
-implemented by OpenSSL and be standardized for use in TLS (RFC 8422).
-It is unwise to list only "bleeding-edge" curves supported by a small
-subset of clients. The default list is suitable for most users.
+ The prioritized list of elliptic curves, that should be enabled in the
+Postfix SMTP client and server. These are used by the Postfix SMTP server when
+"smtpd_tls_eecdh_grade = auto". The selected curves should be implemented
+by OpenSSL and be standardized for use in the TLS "supported groups" extension
+(RFC8422, RFC8446 and RFC8447). Be sure to include at least "x25519" and
+"prime256v1" (the OpenSSL name for "secp256r1", a.k.a. "P-256"). The default
+list is suitable for most users.
- Postfix skips curve names that are unknown to OpenSSL, or that
-are known but not yet implemented. This makes it possible to
-"anticipate" support for curves that should be used once they become
-available. In particular, in some OpenSSL versions, the new RFC
-8031 curves "X25519" and "X448" may be known by name, but ECDH
-support for either or both may be missing. These curves may appear
-in the default value of this parameter, even though they'll only
-be usable with later versions of OpenSSL.
+ On the client side, the first curve listed will be used to construct the
+client's initial TLS 1.3 "keyshare". If this is not supported by the server,
+the TLS handshake may require an additional round-trip after the server issues
+a HelloRetryRequest (HRR) indicating a suitable mutually supported curve.
+
+ Postfix skips curve names that are unknown to OpenSSL, or that are known
+but not yet implemented. This makes it possible to "anticipate" support for
+curves that should be used once they become available, or to deploy the same
+setting on a server "farm" where not all servers support the same curves.
+
+ As of Postfix 3.10, when compiled with OpenSSL 3.0 or later, the "curve"
+names can be more general key encapsulation mechanisms (KEMs), and/or may be
+loaded from an external "provider" (via a suitable tls_config_file).
See also the "tls_ffdhe_auto_groups" parameter, which supports
customizing the list of FFDHE groups enabled with TLS 1.3. That setting
@@ -13420,10 +13426,10 @@ EC key agreement in OpenSSL 3.0 and later. Note that at least one of
this is required by OpenSSL 3.0. If both are inadvertently set empty,
Postfix will fall back to the compiled-in defaults.
- All the default groups and EC curves should sufficiently strong
-to make "pruning" the defaults unwise. At a minimum, "X25519" and
-"P-256" (a.k.a. "prime256v1") should be among the enabled EC curves,
-while "dhe2048" and "dhe3072" should be among the FFDHE groups.
+ All the default groups and EC curves should sufficiently strong to make
+"pruning" the defaults unwise. At a minimum, "x25519" and "prime256v1" (the
+OpenSSL name for "secp256r1", a.k.a. "P-256") should be among the enabled EC
+curves, while "dhe2048" and "dhe3072" should be among the FFDHE groups.
This feature is available in Postfix 3.8 and later, when it is
compiled and linked with OpenSSL 3.0 or later.
diff --git a/postfix/proto/stop b/postfix/proto/stop
index ec9542f1c..03c799cfa 100644
--- a/postfix/proto/stop
+++ b/postfix/proto/stop
@@ -1615,3 +1615,11 @@ milterfrom
canonicalization
Orlitzky
Typofix
+Deduplicate
+KEM
+HelloRetryRequest
+HRR
+KEMs
+kex
+keyshare
+pkg
diff --git a/postfix/proto/stop.double-history b/postfix/proto/stop.double-history
index 3e1bff20c..70a09313a 100644
--- a/postfix/proto/stop.double-history
+++ b/postfix/proto/stop.double-history
@@ -130,3 +130,4 @@ proto proto mysql_table proto pgsql_table proto ldap_table
unimplemented commands in the SMTP server File smtpd smtpd c
cleanup cleanup h cleanup cleanup_extracted c
File postcat postcat c
+ Files src tls tls h src tls tls_dh c src tls tls_misc c
diff --git a/postfix/proto/stop.spell-history b/postfix/proto/stop.spell-history
index e28ab4175..0b5f5be48 100644
--- a/postfix/proto/stop.spell-history
+++ b/postfix/proto/stop.spell-history
@@ -82,3 +82,4 @@ mozilla
Dilyan
Palauzov
pkgconf
+testfiles
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 1f03b0b34..1d61fde53 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -3409,13 +3409,13 @@ extern char *var_tls_null_clist;
#else
#define DEF_TLS_EECDH_AUTO_3 ""
#endif
-#if defined(SN_secp521r1) && defined(NID_secp521r1)
-#define DEF_TLS_EECDH_AUTO_4 SN_secp521r1 " "
+#if defined(SN_secp384r1) && defined(NID_secp384r1)
+#define DEF_TLS_EECDH_AUTO_4 SN_secp384r1
#else
#define DEF_TLS_EECDH_AUTO_4 ""
#endif
-#if defined(SN_secp384r1) && defined(NID_secp384r1)
-#define DEF_TLS_EECDH_AUTO_5 SN_secp384r1
+#if defined(SN_secp521r1) && defined(NID_secp521r1)
+#define DEF_TLS_EECDH_AUTO_5 SN_secp521r1 " "
#else
#define DEF_TLS_EECDH_AUTO_5 ""
#endif
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 52a5cc1ad..95fbd9bfd 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 "20240917"
+#define MAIL_RELEASE_DATE "20240923"
#define MAIL_VERSION_NUMBER "3.10"
#ifdef SNAPSHOT
diff --git a/postfix/src/tls/Makefile.in b/postfix/src/tls/Makefile.in
index 4b562b3fb..2e5bbd3d8 100644
--- a/postfix/src/tls/Makefile.in
+++ b/postfix/src/tls/Makefile.in
@@ -207,6 +207,7 @@ tls_dane.o: ../../include/vstring.h
tls_dane.o: tls.h
tls_dane.o: tls_dane.c
tls_dh.o: ../../include/argv.h
+tls_dh.o: ../../include/been_here.h
tls_dh.o: ../../include/check_arg.h
tls_dh.o: ../../include/dns.h
tls_dh.o: ../../include/mail_params.h
diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h
index 3ec41ba36..406246fd5 100644
--- a/postfix/src/tls/tls.h
+++ b/postfix/src/tls/tls.h
@@ -123,6 +123,15 @@ extern const char *str_tls_level(int);
#define TLS_PEEK_PEER_CERT(ssl) SSL_get_peer_certificate(ssl)
#define TLS_FREE_PEER_CERT(x) X509_free(x)
#define tls_set_bio_callback BIO_set_callback
+#endif
+
+#if OPENSSL_VERSION_PREREQ(3,2)
+#define TLS_GROUP_NAME(ssl) SSL_get0_group_name(ssl)
+#elif OPENSSL_VERSION_PREREQ(3,0)
+#define TLS_GROUP_NAME(ssl) \
+ SSL_group_to_name((ssl), SSL_get_negotiated_group(ssl))
+#else
+#define TLS_GROUP_NAME(ssl) ((const char *)0)
#endif
/*
diff --git a/postfix/src/tls/tls_dh.c b/postfix/src/tls/tls_dh.c
index f47b95461..6165b9390 100644
--- a/postfix/src/tls/tls_dh.c
+++ b/postfix/src/tls/tls_dh.c
@@ -75,6 +75,7 @@
/*
* Global library
*/
+#include
#include
/* TLS library. */
@@ -313,68 +314,75 @@ static int setup_auto_groups(SSL_CTX *ctx, const char *origin,
{
#ifndef OPENSSL_NO_ECDH
SSL_CTX *tmpctx;
- int *nids;
- int space = 10;
- int n = 0;
+ BH_TABLE *seen;
char *save;
char *groups;
char *group;
+ static VSTRING *names;
if ((tmpctx = SSL_CTX_new(TLS_method())) == 0) {
msg_warn("cannot allocate temp SSL_CTX");
tls_print_errors();
return (AG_STAT_NO_RETRY);
}
- nids = mymalloc(space * sizeof(int));
+ if (!names)
+ names = vstring_alloc(sizeof DEF_TLS_EECDH_AUTO +
+ sizeof DEF_TLS_FFDHE_AUTO);
+ VSTRING_RESET(names);
+ /*
+ * OpenSSL does not tolerate duplicate groups in the requested list.
+ * Deduplicate case-insensitively, just in case OpenSSL some day supports
+ * case-insensitive group lookup. Users who specify the group name twice
+ * and get the case wrong the first time deserve to be unhappy. :-)
+ *
+ * OpenSSL 3.3 supports "?" as a syntax for optionally ignoring
+ * unsupported groups, so we could skip checking against the throw-away
+ * CTX when linked against 3.3 or higher, but the cost savings don't
+ * justify the #ifdef overhead for now.
+ */
+ seen = been_here_init(0, BH_FLAG_FOLD);
+
+#define GROUPS_SEP CHARS_COMMA_SP ":"
#define SETUP_AG_RETURN(val) do { \
+ been_here_free(seen); \
myfree(save); \
- myfree(nids); \
SSL_CTX_free(tmpctx); \
return (val); \
} while (0)
groups = save = concatenate(eecdh, " ", ffdhe, NULL);
- if ((group = mystrtok(&groups, CHARS_COMMA_SP)) == 0) {
+ if ((group = mystrtok(&groups, GROUPS_SEP)) == 0) {
msg_warn("no %s key exchange group - OpenSSL requires at least one",
origin);
SETUP_AG_RETURN(AG_STAT_NO_GROUP);
}
- for (; group != 0; group = mystrtok(&groups, CHARS_COMMA_SP)) {
- int nid = EC_curve_nist2nid(group);
-
- if (nid == NID_undef)
- nid = OBJ_sn2nid(group);
- if (nid == NID_undef)
- nid = OBJ_ln2nid(group);
- if (nid == NID_undef) {
- msg_warn("ignoring unknown key exchange group \"%s\"", group);
+ for (; group != 0; group = mystrtok(&groups, GROUPS_SEP)) {
+ if (been_here_fixed(seen, group))
continue;
- }
-
/*
- * Validate the NID by trying it as the group for a throw-away SSL
- * context. Silently skip unsupported code points. This way, we can
- * list X25519 and X448 as soon as the nids are assigned, and before
- * the supporting code is implemented. They'll be silently skipped
- * when not yet supported.
+ * Validate the group name by trying it as the group for a throw-away
+ * SSL context. This way, we can ask for new groups that may not yet be
+ * supported by the underlying OpenSSL runtime. Unsupported groups are
+ * silently ignored.
*/
- if (SSL_CTX_set1_curves(tmpctx, &nid, 1) <= 0) {
- continue;
+ ERR_set_mark();
+ if (SSL_CTX_set1_curves_list(tmpctx, group) > 0) {
+ if (VSTRING_LEN(names) > 0)
+ VSTRING_ADDCH(names, ':');
+ vstring_strcat(names, group);
}
- if (++n > space) {
- space *= 2;
- nids = myrealloc(nids, space * sizeof(int));
- }
- nids[n - 1] = nid;
+ ERR_pop_to_mark();
}
- if (n == 0) {
+ if (VSTRING_LEN(names) == 0) {
/* The names may be case-sensitive */
msg_warn("none of the %s key exchange groups are supported", origin);
SETUP_AG_RETURN(AG_STAT_NO_GROUP);
}
- if (SSL_CTX_set1_curves(ctx, nids, n) <= 0) {
+ VSTRING_TERMINATE(names);
+
+ if (SSL_CTX_set1_curves_list(ctx, vstring_str(names)) <= 0) {
msg_warn("failed to set up the %s key exchange groups", origin);
tls_print_errors();
SETUP_AG_RETURN(AG_STAT_NO_RETRY);
diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c
index f77d778ac..5e34f7a24 100644
--- a/postfix/src/tls/tls_misc.c
+++ b/postfix/src/tls/tls_misc.c
@@ -1057,6 +1057,13 @@ void tls_get_signature_params(TLS_SESS_STATE *TLScontext)
kex_name = OBJ_nid2sn(EVP_PKEY_type(nid));
break;
+#if defined(EVP_PKEY_KEYMGMT)
+ case EVP_PKEY_KEYMGMT:
+ kex_name = EVP_PKEY_get0_type_name(dh_pkey);
+ TLScontext->kex_bits = 0;
+ break;
+#endif
+
case EVP_PKEY_DH:
kex_name = "DHE";
TLScontext->kex_bits = EVP_PKEY_bits(dh_pkey);
@@ -1072,6 +1079,16 @@ void tls_get_signature_params(TLS_SESS_STATE *TLScontext)
EVP_PKEY_free(dh_pkey);
}
+ /*
+ * On the client side, a TLS 1.3 KEM has no server key, just ciphertext to
+ * decapsulate, but, as of OpenSSL 3.0, the client can still obtain the
+ * negotiated group name directly. We nevertheless still try to get the
+ * group details from the peer key first, which works with OpenSSL 1.1.1
+ * and retains the original output format for the (EC)DH groups.
+ */
+ if (!kex_name)
+ kex_name = TLS_GROUP_NAME(ssl);
+
/*
* On the client end, the certificate may be present, but not used, so we
* check via SSL_get_signature_nid(). This means that local signature