2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

postfix-2.4-20070221

This commit is contained in:
Wietse Venema 2007-02-21 00:00:00 -05:00 committed by Viktor Dukhovni
parent aaed482ca0
commit 761ae533bd
17 changed files with 189 additions and 96 deletions

View File

@ -13255,6 +13255,18 @@ Apologies for any names omitted.
multi-valued macro. Files: util/sys_defs.h, util/events.c,
master/multi_server.c, *qmgr/qmgr_transport.c.
20070220
Work-around: Disable SSL/TLS ciphers when the underlying
symmetric algorithm is not available in the OpenSSL crypto
library at the required bit strength. Problem observed with
SunOS 5.10's bundled OpenSSL 0.9.7 and AES 256. Also possible
with OpenSSL 0.9.8 and CAMELLIA 256. Root cause fixed in
upcoming OpenSSL 0.9.7m, 0.9.8e and 0.9.9 releases. Victor
Duchovni, Morgan Stanley. Files: src/smtp/smtp_proto.c,
src/smtpd/smtpd.c, src/tls/tls.h, src/tls/tls_client.c,
src/tls/tls_misc.c and src/tls/tls_server.c.
Wish list:
Update message content length when adding/removing headers.

View File

@ -11772,7 +11772,7 @@ setting. </p>
</DD>
<DT><b><a name="tls_null_cipherlist">tls_null_cipherlist</a>
(default: !aNULL:eNULL+kRSA)</b></DT><DD>
(default: eNULL:!aNULL)</b></DT><DD>
<p> The OpenSSL cipherlist for "NULL" grade ciphers that provide
authentication without encryption. This defines the meaning of the "null"

View File

@ -441,7 +441,7 @@ SMTP(8) SMTP(8)
The OpenSSL cipherlist for "EXPORT" or higher grade
ciphers.
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (!aNULL:eNULL+kRSA)</b>
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (eNULL:!aNULL)</b>
The OpenSSL cipherlist for "NULL" grade ciphers
that provide authentication without encryption.

View File

@ -471,7 +471,7 @@ SMTPD(8) SMTPD(8)
The OpenSSL cipherlist for "EXPORT" or higher grade
ciphers.
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (!aNULL:eNULL+kRSA)</b>
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (eNULL:!aNULL)</b>
The OpenSSL cipherlist for "NULL" grade ciphers
that provide authentication without encryption.

View File

@ -7148,7 +7148,7 @@ certificates). You are strongly encouraged to not change this
setting.
.PP
This feature is available in Postfix 2.3 and later.
.SH tls_null_cipherlist (default: !aNULL:eNULL+kRSA)
.SH tls_null_cipherlist (default: eNULL:!aNULL)
The OpenSSL cipherlist for "NULL" grade ciphers that provide
authentication without encryption. This defines the meaning of the "null"
setting in smtpd_mandatory_tls_ciphers, smtp_tls_mandatory_ciphers and

View File

@ -362,7 +362,7 @@ The OpenSSL cipherlist for "MEDIUM" or higher grade ciphers.
The OpenSSL cipherlist for "LOW" or higher grade ciphers.
.IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
.IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
.IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
The OpenSSL cipherlist for "NULL" grade ciphers that provide
authentication without encryption.
.PP

View File

@ -386,7 +386,7 @@ The OpenSSL cipherlist for "MEDIUM" or higher grade ciphers.
The OpenSSL cipherlist for "LOW" or higher grade ciphers.
.IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
.IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
.IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
The OpenSSL cipherlist for "NULL" grade ciphers that provide
authentication without encryption.
.SH "OBSOLETE STARTTLS CONTROLS"

View File

@ -10399,7 +10399,7 @@ strongly encouraged to not change this setting. </p>
<p> This feature is available in Postfix 2.3 and later. </p>
%PARAM tls_null_cipherlist !aNULL:eNULL+kRSA
%PARAM tls_null_cipherlist eNULL:!aNULL
<p> The OpenSSL cipherlist for "NULL" grade ciphers that provide
authentication without encryption. This defines the meaning of the "null"

View File

@ -2692,7 +2692,7 @@ extern char *var_tls_low_clist;
extern char *var_tls_export_clist;
#define VAR_TLS_NULL_CLIST "tls_null_cipherlist"
#define DEF_TLS_NULL_CLIST "!aNULL:eNULL+kRSA"
#define DEF_TLS_NULL_CLIST "eNULL:!aNULL"
extern char *var_tls_null_clist;
/*

View File

@ -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 "20070218"
#define MAIL_RELEASE_DATE "20070221"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT

View File

@ -332,7 +332,7 @@
/* The OpenSSL cipherlist for "LOW" or higher grade ciphers.
/* .IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
/* The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
/* .IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
/* .IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
/* The OpenSSL cipherlist for "NULL" grade ciphers that provide
/* authentication without encryption.
/* .PP

View File

@ -753,7 +753,7 @@ static int smtp_start_tls(SMTP_STATE *state)
vstring_sprintf_append(serverid, "&p=%s",
tls_protocol_names(VAR_SMTP_TLS_MAND_PROTO,
session->tls_protocols));
if (session->tls_level >= TLS_LEV_ENCRYPT && session->tls_cipherlist)
if (session->tls_level >= TLS_LEV_ENCRYPT)
vstring_sprintf_append(serverid, "&c=%s", session->tls_cipherlist);
tls_props.ctx = smtp_tls_ctx;

View File

@ -354,7 +354,7 @@
/* The OpenSSL cipherlist for "LOW" or higher grade ciphers.
/* .IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
/* The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
/* .IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
/* .IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
/* The OpenSSL cipherlist for "NULL" grade ciphers that provide
/* authentication without encryption.
/* OBSOLETE STARTTLS CONTROLS
@ -4311,6 +4311,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
enforce_tls ? var_smtpd_tls_mand_excl :
TLS_END_EXCLUDE,
TLS_END_EXCLUDE);
if (props.cipherlist == 0)
msg_panic("NULL export cipherlist");
}
if (havecert || oknocert)
smtpd_tls_ctx = tls_server_init(&props);

View File

@ -130,6 +130,7 @@ extern NAME_CODE tls_cipher_level_table[];
#define TLS_END_EXCLUDE ((char *)0)
extern const char *tls_cipher_list(int,...);
extern const char *tls_set_cipher_list(SSL_CTX *, const char *);
/*
* tls_client.c

View File

@ -626,6 +626,15 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
if (props->log_level >= 1)
msg_info("setting up TLS connection to %s", props->host);
/*
* Before we create an SSL, update the SSL_CTX cipherlist if necessary.
*/
if (tls_set_cipher_list(props->ctx, props->cipherlist) == 0) {
msg_warn("Invalid cipherlist \"%s\": aborting TLS session",
props->cipherlist);
return (0);
}
/*
* Allocate a new TLScontext for the new connection and get an SSL
* structure. Add the location of TLScontext to the SSL to later retrieve
@ -710,24 +719,13 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
}
/*
* Per session cipher selection for sessions with mandatory encryption
* Try to load an existing session from the TLS session cache.
*
* By the time a TLS client is negotiating ciphers it has already offered to
* re-use a session, it is too late to renege on the offer. So we must
* not attempt to re-use sessions whose ciphers are too weak. We expect
* the caller to salt the session lookup key with the cipher list, so
* that sessions found in the cache are always acceptable.
*/
if (props->cipherlist != 0)
if (SSL_set_cipher_list(TLScontext->con, props->cipherlist) == 0) {
msg_warn("Could not set cipherlist: %s", props->cipherlist);
tls_print_errors();
tls_free_context(TLScontext);
return (0);
}
/*
* Try to load an existing session from the TLS session cache.
*
* XXX To avoid memory leaks we must always call SSL_SESSION_free() after
* calling SSL_set_session(), regardless of whether or not the session

View File

@ -18,6 +18,10 @@
/*
/* long tls_bug_bits()
/*
/* const char *tls_set_cipher_list(ssl_ctx, cipher_list)
/* SSL_CTX *ssl_ctx;
/* char *cipher_list;
/*
/* const char *tls_cipher_list(cipher_level, ...)
/* int cipher_level;
/*
@ -53,6 +57,11 @@
/* for the run-time library. Some of the bug work-arounds are
/* not appropriate for some library versions.
/*
/* tls_set_cipher_list() updates the cipher list of the specified SSL
/* context. Returns the new cipherlist on success, otherwise logs a
/* suitable warning and returns 0. The storage for the return value
/* is overwritted with each call.
/*
/* tls_cipher_list() generates a cipher list from the specified
/* grade, minus any ciphers specified via a null-terminated
/* list of string-valued exclusions. The result is overwritten
@ -152,45 +161,6 @@ NAME_CODE tls_cipher_level_table[] = {
0, TLS_CIPHER_NONE,
};
#if 0
typedef struct {
char *algorithm;
char *exclusion;
} cipher_probe;
static cipher_probe cipher_probe_list[] = {
/*
* Check for missing AES256, OpenSSL only checks for AES128, and then
* enables both, because they only have one "is AES" boolean flag in the
* cipher property mask. The implementation cannot distinguish between
* AES128 and AES256. When some O/S distributions play games with
* libcrypto and exclude just the AES256 ciphers, they break the OpenSSL
* cipherlist construction code, with clients and servers potentially
* negotiating unimplemented ciphers.
*
* This problem is peculiar to AES, which is not a single cipher, but a
* family of related ciphers. The other OpenSSL symmetric ciphers are
* atomic, either implemented or not. We expect that future ciphers will
* either also be atomic, or will have one property bit per family member
* and will be filtered accurately by OpenSSL.
*
* If all else fails, this table can be expanded :-(
*
* XXX: the probe for AES256 is enclosed in #ifdef. OpenSSL 0.9.6 and and
* earlier don't have AES 256, this requires 0.9.7 or later. We recommend
* against use of 0.9.6, it has open issues solved in 0.9.7l and 0.9.8d,
* but we are not yet prepared to drop support for 0.9.6.
*/
#ifdef SN_aes_256_cbc
SN_aes_256_cbc, SSL_TXT_AES "+HIGH",
#endif
0, 0,
};
#endif
/*
* Parsed OpenSSL version number.
*/
@ -202,17 +172,140 @@ 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 {
char *ssl_name;
int alg_bits;
char *evp_name;
} cipher_probe_t;
static cipher_probe_t cipher_probes[] = {
"AES", 256, "AES-256-CBC",
"CAMELLIA", 256, "CAMELLIA-256-CBC",
0, 0, 0,
};
/* tls_exclude_missing - Append exclusions for missing ciphers */
static void tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
{
const char *myname = "tls_exclude_missing";
static ARGV *exclude; /* Cached */
SSL *s = 0;
STACK_OF(SSL_CIPHER) * ciphers;
SSL_CIPHER *c;
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 check, and assumes is
* 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]);
}
/* tls_set_cipher_list - Set SSL_CTX cipher list */
const char *tls_set_cipher_list(SSL_CTX *ssl_ctx, const char *spec)
{
static VSTRING *buf;
const char *ex_spec;
if (buf == 0)
buf = vstring_alloc(10);
vstring_strcpy(buf, spec);
tls_exclude_missing(ssl_ctx, buf);
ex_spec = vstring_str(buf);
ERR_clear_error();
if (SSL_CTX_set_cipher_list(ssl_ctx, ex_spec) != 0)
return (ex_spec);
tls_print_errors();
return (0);
}
/* tls_cipher_list - Cipherlist for given grade, less exclusions */
const char *tls_cipher_list(int cipher_level,...)
{
const char *myname = "tls_cipher_list";
static VSTRING *buf;
#if 0
static ARGV *exclude_unavailable;
cipher_probe *probe;
int i;
#endif
va_list ap;
const char *exclude;
char *tok;
@ -241,47 +334,34 @@ const char *tls_cipher_list(int cipher_level,...)
case TLS_CIPHER_NONE:
return 0;
default:
/*
* The caller MUST provide a valid cipher grade
*/
msg_panic("%s: invalid cipher grade: %d", myname, cipher_level);
}
/*
* The base lists for each grade can't be empty.
*/
if (VSTRING_LEN(buf) == 0)
msg_panic("%s: empty cipherlist", myname);
/*
* Exclude ciphers that clueless distributions leave out of libcrypto.
*/
#if 0
if (exclude_unavailable == 0) {
exclude_unavailable = argv_alloc(1);
for (probe = cipher_probe_list; probe->algorithm; ++probe)
if (!EVP_get_cipherbyname(probe->algorithm))
argv_add(exclude_unavailable, probe->exclusion, (char *) 0);
}
for (i = 0; i < exclude_unavailable->argc; ++i)
vstring_sprintf_append(buf, ":!%s", exclude_unavailable->argv[i]);
#endif
va_start(ap, cipher_level);
while ((exclude = va_arg(ap, char *)) != 0) {
if (*exclude == '\0')
continue;
save = cp = mystrdup(exclude);
while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
while ((tok = mystrtok(&cp, "\t\n\r ,:")) != 0) {
/*
* Can't exclude ciphers that start with modifiers, or
* multi-element (":" separated) ciphers.
* Can't exclude ciphers that start with modifiers.
*/
if (strchr("!+-@", *tok)) {
msg_warn("%s: can't exclude '!+-@' modifiers, '%s' ignored",
myname, tok);
continue;
}
if (strchr(tok, ':')) {
msg_warn("%s: can't exclude compound ciphers, '%s' ignored",
myname, tok);
continue;
}
vstring_sprintf_append(buf, ":!%s", tok);
}
myfree(save);

View File

@ -329,12 +329,12 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
/*
* Override the default cipher list with our own list.
*/
if (*props->cipherlist != 0)
if (SSL_CTX_set_cipher_list(server_ctx, props->cipherlist) == 0) {
tls_print_errors();
SSL_CTX_free(server_ctx); /* 200411 */
return (0);
}
if (tls_set_cipher_list(server_ctx, props->cipherlist) == 0) {
SSL_CTX_free(server_ctx);
msg_warn("Invalid cipherlist \"%s\": disabling TLS support",
props->cipherlist);
return (0); /* Already logged */
}
/*
* Load the CA public key certificates for both the server cert and for