From: Wietse Venema Date: Mon, 29 Jan 2007 05:00:00 +0000 (-0500) Subject: postfix-2.3.7-RC3 X-Git-Tag: v2.3.7-RC3^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c6d2e6a37fac6509f86bbe853a22a462ad9a3873;p=thirdparty%2Fpostfix.git postfix-2.3.7-RC3 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 86d18924c..dd38a0277 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -254,6 +254,7 @@ -TXSASL_SERVER -TXSASL_SERVER_IMPL -TXSASL_SERVER_IMPL_INFO +-Tcipher_probe -Tregex_t -Tregmatch_t -Tsasl_conn_t diff --git a/postfix/HISTORY b/postfix/HISTORY index f0d473879..4aee528f3 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -12927,8 +12927,16 @@ Apologies for any names omitted. Duchovni. Files: smtpd/smtpd_check.c. Workaround: don't insert header/body blank line separator - in malformed attachments, to avoid breaking digital signatures. - Switch from header to body state, for robust MIME parsing. - People concerned about MIME evasion can use a MIME normalizer - to corrupt their user's legitimate email. File: - global/mime_state.c. + into malformed MIME attachments, to avoid breaking digital + signatures. File: global/mime_state.c. + +20070118 + + Bugfix: match lists didn't implement ![ipv6address]. Problem + reported by Paulo Pacheco. File: util/match_list.c. + +200070129 + + Workaround: OpenSSL falsely concludes that AES256 support + is present when only AES128 is available. Code by Victor + Duchovni. File: tls/tls_misc.c. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 181546478..887cc48be 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "20070113" -#define MAIL_VERSION_NUMBER "2.3.7-RC2" +#define MAIL_RELEASE_DATE "20070129" +#define MAIL_VERSION_NUMBER "2.3.7-RC3" #ifdef SNAPSHOT # define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff --git a/postfix/src/global/mime_state.c b/postfix/src/global/mime_state.c index b81fc1f90..4b4bf69f9 100644 --- a/postfix/src/global/mime_state.c +++ b/postfix/src/global/mime_state.c @@ -499,6 +499,7 @@ MIME_STATE *mime_state_alloc(int flags, /* Volatile members. */ state->err_flags = 0; + state->body_offset = 0; /* XXX */ SET_MIME_STATE(state, MIME_STATE_PRIMARY, MIME_CTYPE_TEXT, MIME_STYPE_PLAIN, MIME_ENC_7BIT, MIME_ENC_7BIT); @@ -938,6 +939,15 @@ int mime_state_update(MIME_STATE *state, int rec_type, * messages. Otherwise, treat such headers as part of the "body". Set * the proper encoding information for the multipart prolog. * + * XXX We parse headers inside message/* content even when the encoding + * is invalid (encoding != domain). With base64 we won't recognize + * any headers, and with quoted-printable we won't recognize MIME + * boundary strings, but the MIME processor will still resynchronize + * when it runs into the higher-level boundary string at the end of + * the message/* content. Although we will treat some headers as body + * text, we will still do a better job than if we were treating the + * entire message/* content as body text. + * * XXX This changes state to MIME_STATE_NESTED and then outputs a body * line, so that the body offset is not properly reset. * @@ -973,13 +983,14 @@ int mime_state_update(MIME_STATE *state, int rec_type, * separator, nor does the Milter protocol pass it on to Milter * applications. * - * XXX We don't insert a blank line separator with attachments, as - * this breaks digital signatures. Postfix shall not do a worse - * mail delivery job than crappy MTAs that can't even parse MIME. - * But we switch to the body state anyway. + * XXX We don't insert a blank line separator into attachments, to + * avoid breaking digital signatures. Postfix shall not do a + * worse mail delivery job than MTAs that can't even parse MIME. + * We switch to body state anyway, to avoid treating body text as + * header text, and mis-interpreting or truncating it. The code + * below for initial From_ lines is for educational purposes. * - * People who worry about MIME evasion can use a MIME normalizer, - * and knowlingly corrupt legitimate email for their users. + * Sites concerned about MIME evasion can use a MIME normalizer. * Postfix has a different mission. */ else { @@ -989,9 +1000,25 @@ int mime_state_update(MIME_STATE *state, int rec_type, state->curr_state == MIME_STATE_PRIMARY ? "primary" : state->curr_state == MIME_STATE_NESTED ? "nested" : "other"); - if (state->curr_state == MIME_STATE_PRIMARY) + switch (state->curr_state) { + case MIME_STATE_PRIMARY: BODY_OUT(state, REC_TYPE_NORM, "", 0); - SET_CURR_STATE(state, MIME_STATE_BODY); + SET_CURR_STATE(state, MIME_STATE_BODY); + break; +#if 0 + case MIME_STATE_NESTED: + if (state->body_offset <= 1 + && rec_type == REC_TYPE_NORM + && len > 7 + && (strncmp(text + (*text == '>'), "From ", 5) == 0 + || strncmp(text, "=46rom ", 7) == 0)) + break; + /* FALLTHROUGH */ +#endif + default: + SET_CURR_STATE(state, MIME_STATE_BODY); + break; + } } } diff --git a/postfix/src/global/record.c b/postfix/src/global/record.c index 3ef7ca7b5..96233f426 100644 --- a/postfix/src/global/record.c +++ b/postfix/src/global/record.c @@ -77,8 +77,8 @@ /* and REC_FLAG_DEFAULT for normal use. /* /* rec_get() is a wrapper around rec_get_raw() that always -/* enables the REC_FLAG_FOLLOW_PTR and REC_FLAG_SKIP_DTXT -/* features. +/* enables the REC_FLAG_FOLLOW_PTR, REC_FLAG_SKIP_DTXT +/* and REC_FLAG_SEEK_END features. /* /* rec_put() stores the specified record and returns the record /* type, or REC_TYPE_ERROR in case of problems. diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index dad89aae9..8f6a00f14 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -210,6 +210,7 @@ smtp_chat.o: ../../include/dsn.h smtp_chat.o: ../../include/dsn_buf.h smtp_chat.o: ../../include/dsn_util.h smtp_chat.o: ../../include/htable.h +smtp_chat.o: ../../include/int_filt.h smtp_chat.o: ../../include/line_wrap.h smtp_chat.o: ../../include/mail_addr.h smtp_chat.o: ../../include/mail_error.h diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 5c5d63470..1f8dab64c 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -716,6 +716,7 @@ int smtp_ext_prop_mask; * OpenSSL client state. */ SSL_CTX *smtp_tls_ctx; +int smtp_tls_mand_level; #endif @@ -879,6 +880,18 @@ static void pre_init(char *unused_name, char **unused_argv) props.CAfile = var_smtp_tls_CAfile; props.CApath = var_smtp_tls_CApath; + /* + * If the administrator set an invalid grade, use "medium" instead. + * The TLS library requires a valid setting. + */ + smtp_tls_mand_level = tls_cipher_level(var_smtp_tls_mand_ciph); + if (smtp_tls_mand_level == TLS_CIPHER_NONE) { + smtp_tls_mand_level = TLS_CIPHER_MEDIUM; + msg_warn("invalid '%s' value '%s', using 'medium'", + strcmp(var_procname, "smtp") == 0 ? + VAR_SMTP_TLS_MAND_CIPH : VAR_LMTP_TLS_MAND_CIPH, + var_smtp_tls_mand_ciph); + } smtp_tls_ctx = tls_client_init(&props); smtp_tls_list_init(); #else diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index af397d711..98989805c 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -168,6 +168,7 @@ extern int smtp_ext_prop_mask; /* address externsion propagation */ #ifdef USE_TLS extern SSL_CTX *smtp_tls_ctx; /* client-side TLS engine */ +extern int smtp_tls_mand_level; /* TLS_CIPHER_EXPORT, ... */ #endif diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index abb32789b..d042840e5 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -355,7 +355,7 @@ static void set_cipherlist(SMTP_SESSION *session, int cipher_level, int lmtp) case TLS_LEV_ENCRYPT: also_exclude = "eNULL"; if (cipher_level == TLS_CIPHER_NONE) - cipher_level = tls_cipher_level(var_smtp_tls_mand_ciph); + cipher_level = smtp_tls_mand_level; mand_exclude = var_smtp_tls_mand_excl; break; @@ -363,22 +363,14 @@ static void set_cipherlist(SMTP_SESSION *session, int cipher_level, int lmtp) case TLS_LEV_SECURE: also_exclude = "aNULL"; if (cipher_level == TLS_CIPHER_NONE) - cipher_level = tls_cipher_level(var_smtp_tls_mand_ciph); + cipher_level = smtp_tls_mand_level; mand_exclude = var_smtp_tls_mand_excl; break; } - cipherlist = tls_cipher_list(cipher_level, exclude, mand_exclude, - also_exclude, TLS_END_EXCLUDE); - if (cipherlist == 0) { - msg_warn("unknown '%s' value '%s' ignored, using 'medium'", - lmtp ? VAR_LMTP_TLS_MAND_CIPH : VAR_SMTP_TLS_MAND_CIPH, - var_smtp_tls_mand_ciph); - cipherlist = tls_cipher_list(TLS_CIPHER_MEDIUM, exclude, mand_exclude, - also_exclude, TLS_END_EXCLUDE); - if (cipherlist == 0) - msg_panic("NULL medium cipherlist"); - } + cipherlist = tls_cipher_list(cipher_level, TLS_CIPH_EXCL_LIST, + exclude, mand_exclude, also_exclude, + TLS_CIPH_EXCL_END); session->tls_cipherlist = mystrdup(cipherlist); } diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 16f71294b..9fa60e9ef 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -4226,6 +4226,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) if (use_tls) { #ifdef USE_TLS tls_server_props props; + ARGV *cipher_exclusions; int havecert; int oknocert; int wantcert; @@ -4271,32 +4272,44 @@ static void pre_jail_init(char *unused_name, char **unused_argv) if (!enforce_tls && var_smtpd_tls_req_ccert) msg_warn("Can't require client certs unless TLS is required"); - props.cipherlist = - tls_cipher_list(enforce_tls ? - tls_cipher_level(var_smtpd_tls_mand_ciph) : - TLS_CIPHER_EXPORT, - var_smtpd_tls_excl_ciph, - havecert ? "" : "aRSA aDSS", - wantcert ? "aNULL" : "", - enforce_tls ? var_smtpd_tls_mand_excl : - TLS_END_EXCLUDE, - TLS_END_EXCLUDE); - - if (props.cipherlist == 0) { - msg_warn("unknown '%s' value '%s' ignored, using 'export'", - VAR_SMTPD_TLS_MAND_CIPH, var_smtpd_tls_mand_ciph); - props.cipherlist = - tls_cipher_list(TLS_CIPHER_EXPORT, - var_smtpd_tls_excl_ciph, - havecert ? "" : "aRSA aDSS", - wantcert ? "aNULL" : "", - enforce_tls ? var_smtpd_tls_mand_excl : - TLS_END_EXCLUDE, - TLS_END_EXCLUDE); - } - if (havecert || oknocert) + if (havecert || oknocert) { + cipher_exclusions = argv_alloc(3); + argv_add(cipher_exclusions, var_smtpd_tls_excl_ciph, ARGV_END); + if (wantcert) + argv_add(cipher_exclusions, "aNULL", ARGV_END); + + /* + * Detect problem configurations early, a certificate-less + * handshake can't use ciphers that need server certificates, + * so we want to fail now while setting up the cipherlist, + * not later. Also this detects any conflict between wantcert + * and !havecert. + */ + if (!havecert) + argv_add(cipher_exclusions, "aRSA", "aDSS", ARGV_END); + if (enforce_tls) { + argv_add(cipher_exclusions, + var_smtpd_tls_mand_excl, ARGV_END); + + /* + * If the administrator set an invalid grade, use + * "medium" instead. The TLS library requires a valid + * setting. + */ + props.cipher_level = + tls_cipher_level(var_smtpd_tls_mand_ciph); + if (props.cipher_level == TLS_CIPHER_NONE) { + props.cipher_level = TLS_CIPHER_MEDIUM; + msg_warn("invalid '%s' value '%s', using 'medium'", + VAR_SMTPD_TLS_MAND_CIPH, + var_smtpd_tls_mand_ciph); + } + } else + props.cipher_level = TLS_CIPHER_EXPORT; + props.cipher_exclusions = cipher_exclusions->argv; smtpd_tls_ctx = tls_server_init(&props); - else if (enforce_tls) + argv_free(cipher_exclusions); + } else if (enforce_tls) msg_fatal("No server certs available. TLS can't be enabled"); else msg_warn("No server certs available. TLS won't be enabled"); diff --git a/postfix/src/smtpd/smtpd_exp.ref b/postfix/src/smtpd/smtpd_exp.ref index 75b6c84f3..c04381ba8 100644 --- a/postfix/src/smtpd/smtpd_exp.ref +++ b/postfix/src/smtpd/smtpd_exp.ref @@ -107,8 +107,8 @@ OK >>> mail sname@sdomain OK >>> rcpt rname@rdomain -./smtpd_check: : reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@example.tld; from= to= proto=SMTP helo= -554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@example.tld +./smtpd_check: : reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain; from= to= proto=SMTP helo= +554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain >>> # >>> # Check MX access >>> # diff --git a/postfix/src/tls/Makefile.in b/postfix/src/tls/Makefile.in index 8b8d254bf..f0bc15572 100644 --- a/postfix/src/tls/Makefile.in +++ b/postfix/src/tls/Makefile.in @@ -89,6 +89,7 @@ depend: $(MAKES) @$(EXPORT) make -f Makefile.in Makefile 1>&2 # do not edit below this line - it is generated by 'make depend' +tls_bio_ops.o: ../../include/argv.h tls_bio_ops.o: ../../include/iostuff.h tls_bio_ops.o: ../../include/msg.h tls_bio_ops.o: ../../include/name_code.h @@ -99,6 +100,7 @@ tls_bio_ops.o: ../../include/vstream.h tls_bio_ops.o: ../../include/vstring.h tls_bio_ops.o: tls.h tls_bio_ops.o: tls_bio_ops.c +tls_certkey.o: ../../include/argv.h tls_certkey.o: ../../include/msg.h tls_certkey.o: ../../include/name_code.h tls_certkey.o: ../../include/name_mask.h @@ -122,6 +124,7 @@ tls_client.o: ../../include/vstring.h tls_client.o: tls.h tls_client.o: tls_client.c tls_client.o: tls_mgr.h +tls_dh.o: ../../include/argv.h tls_dh.o: ../../include/msg.h tls_dh.o: ../../include/name_code.h tls_dh.o: ../../include/name_mask.h @@ -131,6 +134,7 @@ tls_dh.o: ../../include/vstream.h tls_dh.o: ../../include/vstring.h tls_dh.o: tls.h tls_dh.o: tls_dh.c +tls_level.o: ../../include/argv.h tls_level.o: ../../include/name_code.h tls_level.o: ../../include/name_mask.h tls_level.o: ../../include/sys_defs.h @@ -151,6 +155,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 @@ -190,6 +195,7 @@ tls_prng_file.o: ../../include/mymalloc.h tls_prng_file.o: ../../include/sys_defs.h tls_prng_file.o: tls_prng.h tls_prng_file.o: tls_prng_file.c +tls_rsa.o: ../../include/argv.h tls_rsa.o: ../../include/name_code.h tls_rsa.o: ../../include/name_mask.h tls_rsa.o: ../../include/sys_defs.h @@ -211,6 +217,7 @@ tls_scache.o: ../../include/vstream.h tls_scache.o: ../../include/vstring.h tls_scache.o: tls_scache.c tls_scache.o: tls_scache.h +tls_seed.o: ../../include/argv.h tls_seed.o: ../../include/msg.h tls_seed.o: ../../include/name_code.h tls_seed.o: ../../include/name_mask.h @@ -237,6 +244,7 @@ tls_server.o: ../../include/vstring.h tls_server.o: tls.h tls_server.o: tls_mgr.h tls_server.o: tls_server.c +tls_session.o: ../../include/argv.h tls_session.o: ../../include/msg.h tls_session.o: ../../include/mymalloc.h tls_session.o: ../../include/name_code.h @@ -247,6 +255,7 @@ tls_session.o: ../../include/vstream.h tls_session.o: ../../include/vstring.h tls_session.o: tls.h tls_session.o: tls_session.c +tls_stream.o: ../../include/argv.h tls_stream.o: ../../include/iostuff.h tls_stream.o: ../../include/msg.h tls_stream.o: ../../include/name_code.h @@ -257,6 +266,7 @@ tls_stream.o: ../../include/vstream.h tls_stream.o: ../../include/vstring.h tls_stream.o: tls.h tls_stream.o: tls_stream.c +tls_verify.o: ../../include/argv.h tls_verify.o: ../../include/msg.h tls_verify.o: ../../include/mymalloc.h tls_verify.o: ../../include/name_code.h diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index f13702327..ef6799712 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -56,6 +56,7 @@ extern NAME_CODE tls_level_table[]; #include #include #include +#include #define TLS_BIO_BUFSIZE 8192 @@ -128,8 +129,10 @@ extern NAME_CODE tls_cipher_level_table[]; #define tls_cipher_level(str) \ name_code(tls_cipher_level_table, NAME_CODE_FLAG_NONE, (str)) -#define TLS_END_EXCLUDE ((char *)0) -extern const char *tls_cipher_list(int,...); +#define TLS_CIPH_EXCL_ARRAY 1 +#define TLS_CIPH_EXCL_LIST 2 +#define TLS_CIPH_EXCL_END ((char *) 0) +extern const char *tls_cipher_list(int, int,...); /* * tls_client.c @@ -181,7 +184,8 @@ typedef struct { const char *dkey_file; const char *CAfile; const char *CApath; - const char *cipherlist; + int cipher_level; /* TLS_CIPHER_EXPORT, ... */ + char **cipher_exclusions; int protocols; /* protocols, 0 => all */ const char *dh1024_param_file; const char *dh512_param_file; diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index 0680ee0cd..6ecac330b 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -718,13 +718,12 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props) * 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); - } + 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. diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c index f87389819..e0a1d832b 100644 --- a/postfix/src/tls/tls_misc.c +++ b/postfix/src/tls/tls_misc.c @@ -18,8 +18,9 @@ /* /* long tls_bug_bits() /* -/* const char *tls_cipher_list(cipher_level, ...) +/* const char *tls_cipher_list(cipher_level, options, ...) /* int cipher_level; +/* int options; /* /* void tls_print_errors() /* @@ -56,7 +57,10 @@ /* 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 -/* upon each call. +/* upon each call. The options argument specifies how exceptions +/* are specified: TLS_CIPH_EXCL_ARRAY (null-terminated character +/* pointer array) or TLS_CIPH_EXCL_LIST (variadic parameter +/* list terminated with TLS_CIPH_EXCL_END). /* /* tls_print_errors() queries the OpenSSL error stack, /* logs the error messages, and clears the error stack. @@ -151,6 +155,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. */ @@ -164,15 +203,19 @@ typedef struct { /* tls_cipher_list - Cipherlist for given grade, less exclusions */ -const char *tls_cipher_list(int cipher_level,...) +const char *tls_cipher_list(int cipher_level, int options,...) { 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; char *save; char *cp; + char **ex_array = 0; buf = buf ? buf : vstring_alloc(10); VSTRING_RESET(buf); @@ -193,17 +236,30 @@ const char *tls_cipher_list(int cipher_level,...) case TLS_CIPHER_NULL: vstring_strcpy(buf, var_tls_null_clist); break; - case TLS_CIPHER_NONE: - return 0; default: msg_panic("%s: invalid cipher grade: %d", myname, cipher_level); } - if (VSTRING_LEN(buf) == 0) msg_panic("%s: empty cipherlist", myname); - va_start(ap, cipher_level); - while ((exclude = va_arg(ap, char *)) != 0) { + /* + * 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, options); + if (options == TLS_CIPH_EXCL_ARRAY) + ex_array = va_arg(ap, char **); + else if (options != TLS_CIPH_EXCL_LIST) + msg_panic("%s: bad argument list option: %d", myname, options); + while ((exclude = ex_array ? *ex_array++ : va_arg(ap, char *)) != 0) { if (*exclude == '\0') continue; save = cp = mystrdup(exclude); diff --git a/postfix/src/tls/tls_server.c b/postfix/src/tls/tls_server.c index 3c6dac341..720cbcfcd 100644 --- a/postfix/src/tls/tls_server.c +++ b/postfix/src/tls/tls_server.c @@ -249,6 +249,7 @@ SSL_CTX *tls_server_init(const tls_server_props *props) int verify_flags = SSL_VERIFY_NONE; SSL_CTX *server_ctx; int cachable; + const char *cipher_list; /* See skeleton at OpenSSL apps/s_server.c. */ @@ -328,12 +329,14 @@ 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); - } + cipher_list = tls_cipher_list(props->cipher_level, TLS_CIPH_EXCL_ARRAY, + props->cipher_exclusions); + if (SSL_CTX_set_cipher_list(server_ctx, cipher_list) == 0) { + tls_print_errors(); + msg_warn("Invalid cipherlist: %s", cipher_list); + SSL_CTX_free(server_ctx); /* 200411 */ + return (0); + } /* * Load the CA public key certificates for both the server cert and for diff --git a/postfix/src/util/match_list.c b/postfix/src/util/match_list.c index efeebd939..1dfa2fcf5 100644 --- a/postfix/src/util/match_list.c +++ b/postfix/src/util/match_list.c @@ -96,7 +96,7 @@ struct MATCH_LIST { }; #define MATCH_DICTIONARY(pattern) \ - ((pattern)[0] != '[' && strchr((pattern), ':') != 0) + ((pattern + strspn(pattern, "!"))[0] != '[' && strchr((pattern), ':') != 0) /* match_list_parse - parse buffer, destroy buffer */