diff --git a/postfix/.indent.pro b/postfix/.indent.pro index d5c9972c1..bc5fa9c63 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -257,6 +257,7 @@ -TXSASL_SERVER -TXSASL_SERVER_IMPL -TXSASL_SERVER_IMPL_INFO +-Tcipher_probe -Toff_t -Tregex_t -Tregmatch_t diff --git a/postfix/HISTORY b/postfix/HISTORY index 8881cfe7b..5ba0c8253 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -13149,6 +13149,12 @@ Apologies for any names omitted. all other recipients are in the initial segment). File: global/rec_types.h. +20070123 + + Workaround: OpenSSL falsely concludes that AES256 support + is present when only AES128 is available. Code by Victor + Duchovni. File: tls/tls_misc.c. + Wish list: Update message content length when adding/removing headers. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 82b46d828..cce3395d8 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 "20070122" +#define MAIL_RELEASE_DATE "20070123" #define MAIL_VERSION_NUMBER "2.4" #ifdef SNAPSHOT diff --git a/postfix/src/tls/Makefile.in b/postfix/src/tls/Makefile.in index 2c48df724..d3e21510a 100644 --- a/postfix/src/tls/Makefile.in +++ b/postfix/src/tls/Makefile.in @@ -151,6 +151,7 @@ tls_mgr.o: ../../include/vstream.h tls_mgr.o: ../../include/vstring.h tls_mgr.o: tls_mgr.c tls_mgr.o: tls_mgr.h +tls_misc.o: ../../include/argv.h tls_misc.o: ../../include/msg.h tls_misc.o: ../../include/mymalloc.h tls_misc.o: ../../include/name_code.h diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c index f87389819..ac5f25507 100644 --- a/postfix/src/tls/tls_misc.c +++ b/postfix/src/tls/tls_misc.c @@ -104,6 +104,7 @@ #include #include #include +#include /* TLS library. */ @@ -151,6 +152,41 @@ NAME_CODE tls_cipher_level_table[] = { 0, TLS_CIPHER_NONE, }; +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, +}; + /* * Parsed OpenSSL version number. */ @@ -168,6 +204,9 @@ const char *tls_cipher_list(int cipher_level,...) { const char *myname = "tls_cipher_list"; static VSTRING *buf; + static ARGV *exclude_unavailable; + cipher_probe *probe; + int i; va_list ap; const char *exclude; char *tok; @@ -202,6 +241,18 @@ const char *tls_cipher_list(int cipher_level,...) if (VSTRING_LEN(buf) == 0) msg_panic("%s: empty cipherlist", myname); + /* + * Exclude ciphers that clueless distributions leave out of libcrypto. + */ + 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]); + va_start(ap, cipher_level); while ((exclude = va_arg(ap, char *)) != 0) { if (*exclude == '\0')