summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-txt/ChangeLog5
-rw-r--r--doc/doc-txt/NewStuff71
-rw-r--r--doc/doc-txt/OptionLists.txt10
-rw-r--r--src/src/functions.h7
-rw-r--r--src/src/globals.c5
-rw-r--r--src/src/globals.h5
-rw-r--r--src/src/readconf.c7
-rw-r--r--src/src/smtp_in.c9
-rw-r--r--src/src/tls-gnu.c273
-rw-r--r--src/src/tls-openssl.c20
-rw-r--r--src/src/transports/smtp.c20
-rw-r--r--src/src/transports/smtp.h5
-rw-r--r--test/confs/201111
-rw-r--r--test/log/201143
-rw-r--r--test/scripts/2000-GnuTLS/201130
15 files changed, 422 insertions, 99 deletions
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 240c815eb..238621e9b 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.454 2007/01/17 11:17:58 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.455 2007/01/18 15:35:42 ph10 Exp $
Change log file for Exim from version 4.21
-------------------------------------------
@@ -26,6 +26,9 @@ PH/02 In an ACL statement such as
PH/03 Added additional dnslists conditions == and =& which are different from
= and & when the dns lookup returns more than one IP address.
+PH/04 Added gnutls_require_{kx,mac,protocols} to give more control over the
+ cipher suites used by GnuTLS. These options are ignored by OpenSSL.
+
Exim version 4.66
-----------------
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 960f93ce8..9cc8f81cc 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/NewStuff,v 1.127 2007/01/17 11:17:58 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/NewStuff,v 1.128 2007/01/18 15:35:42 ph10 Exp $
New Features in Exim
--------------------
@@ -106,6 +106,75 @@ Version 4.67
When the DNS lookup yields only a single IP address, there is no difference
between = and == and between & and =&.
+ 3. Up till now, the only control over which cipher suites GnuTLS uses has been
+ for the cipher algorithms. New options have been added to allow some of the
+ other parameters to be varied. Here is complete documentation for the
+ available features:
+
+ GnuTLS allows the caller to specify separate lists of permitted key
+ exchange methods, main cipher algorithms, and MAC algorithms. These may be
+ used in any combination to form a specific cipher suite. This is unlike
+ OpenSSL, where complete cipher names can be passed to its control function.
+ GnuTLS also allows a list of acceptable protocols to be supplied.
+
+ For compatibility with OpenSSL, the tls_require_ciphers option can be set
+ to complete cipher suite names such as RSA_ARCFOUR_SHA, but for GnuTLS this
+ option controls only the cipher algorithms. Exim searches each item in the
+ list for the name of an available algorithm. For example, if the list
+ contains RSA_AES_SHA, then AES is recognized, and the behaviour is exactly
+ the same as if just AES were given.
+
+ There are additional options called gnutls_require_kx, gnutls_require_mac,
+ and gnutls_require_protocols that can be used to restrict the key exchange
+ methods, MAC algorithms, and protocols, respectively. These options are
+ ignored if OpenSSL is in use.
+
+ All four options are available as global options, controlling how Exim
+ behaves as a server, and also as options of the smtp transport, controlling
+ how Exim behaves as a client. All the values are string expanded. After
+ expansion, the values must be colon-separated lists, though the separator
+ can be changed in the usual way.
+
+ Each of the four lists starts out with a default set of algorithms. If the
+ first item in one of the "require" options does _not_ start with an
+ exclamation mark, all the default items are deleted. In this case, only
+ those that are explicitly specified can be used. If the first item in one
+ of the "require" items _does_ start with an exclamation mark, the defaults
+ are left on the list.
+
+ Then, any item that starts with an exclamation mark causes the relevant
+ entry to be removed from the list, and any item that does not start with an
+ exclamation mark causes a new entry to be added to the list. Unrecognized
+ items in the list are ignored. Thus:
+
+ tls_require_ciphers = !ARCFOUR
+
+ allows all the defaults except ARCFOUR, whereas
+
+ tls_require_ciphers = AES : 3DES
+
+ allows only cipher suites that use AES or 3DES. For tls_require_ciphers
+ the recognized names are AES_256, AES_128, AES (both of the preceding),
+ 3DES, ARCFOUR_128, ARCFOUR_40, and ARCFOUR (both of the preceding). The
+ default list does not contain all of these; it just has AES_256, AES_128,
+ 3DES, and ARCFOUR_128.
+
+ For gnutls_require_kx, the recognized names are DHE_RSA, RSA (which
+ includes DHE_RSA), DHE_DSS, and DHE (which includes both DHE_RSA and
+ DHE_DSS). The default list contains RSA, DHE_DSS, DHE_RSA.
+
+ For gnutls_require_mac, the recognized names are SHA (synonym SHA1), and
+ MD5. The default list contains SHA, MD5.
+
+ For gnutls_require_protocols, the recognized names are TLS1 and SSL3.
+ The default list contains TLS1, SSL3.
+
+ In a server, the order of items in these lists is unimportant. The server
+ will advertise the availability of all the relevant cipher suites. However,
+ in a client, the order in the tls_require_ciphers list specifies a
+ preference order for the cipher algorithms. The first one in the client's
+ list that is also advertised by the server is tried first.
+
Version 4.66
------------
diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt
index e484f98e9..67b03c793 100644
--- a/doc/doc-txt/OptionLists.txt
+++ b/doc/doc-txt/OptionLists.txt
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/OptionLists.txt,v 1.28 2006/12/05 11:35:28 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/OptionLists.txt,v 1.29 2007/01/18 15:35:42 ph10 Exp $
LISTS OF EXIM OPTIONS
---------------------
@@ -11,7 +11,7 @@ This file contains complete lists of four kinds of Exim option:
4. Those that can appear in the build time configuration for the Exim monitor
(Local/eximon.conf).
-This file was last updated for Exim release 4.64.
+This file was last updated for Exim release 4.67.
1. RUN TIME OPTIONS
@@ -231,6 +231,12 @@ from string* unset autoreply
gecos_name string* unset main
gecos_pattern string unset main
gethostbyname boolean false smtp
+gnutls_require_kx string* unset main 4.67
+ string* unset smtp 4.67
+gnutls_require_mac string* unset main 4.67
+ string* unset smtp 4.67
+gnutls_require_protocols string* unset main 4.67
+ string* unset smtp 4.67
group string + routers 4.00
unset transports 4.00 replaces local option in some transports
header_line_maxsize integer 0 (unset) main 4.14
diff --git a/src/src/functions.h b/src/src/functions.h
index f15142336..5e3f9d580 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/functions.h,v 1.33 2007/01/15 15:59:22 ph10 Exp $ */
+/* $Cambridge: exim/src/src/functions.h,v 1.34 2007/01/18 15:35:42 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -24,13 +24,14 @@ extern uschar *init_perl(uschar *);
#ifdef SUPPORT_TLS
extern int tls_client_start(int, host_item *, address_item *, uschar *,
- uschar *, uschar *, uschar *, uschar *, uschar *, int);
+ uschar *, uschar *, uschar *, uschar *, uschar *, uschar *,
+ uschar *, uschar *, int);
extern void tls_close(BOOL);
extern int tls_feof(void);
extern int tls_ferror(void);
extern int tls_getc(void);
extern int tls_read(uschar *, size_t);
-extern int tls_server_start(uschar *);
+extern int tls_server_start(uschar *, uschar *, uschar *, uschar *);
extern int tls_ungetc(int);
extern int tls_write(const uschar *, size_t);
#endif
diff --git a/src/src/globals.c b/src/src/globals.c
index 796104bc0..c60ef864f 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.c,v 1.62 2007/01/15 15:59:22 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.c,v 1.63 2007/01/18 15:35:42 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -109,6 +109,9 @@ uschar *tls_on_connect_ports = NULL;
uschar *tls_peerdn = NULL;
#ifdef SUPPORT_TLS
+uschar *gnutls_require_mac = NULL;
+uschar *gnutls_require_kx = NULL;
+uschar *gnutls_require_proto = NULL;
const pcre *regex_STARTTLS = NULL;
uschar *tls_advertise_hosts = NULL; /* This is deliberate */
uschar *tls_certificate = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index 2ea06dad9..090e1b483 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.h,v 1.43 2007/01/15 15:59:22 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.h,v 1.44 2007/01/18 15:35:42 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -71,6 +71,9 @@ extern uschar *tls_on_connect_ports; /* Ports always tls-on-connect */
extern uschar *tls_peerdn; /* DN from peer */
#ifdef SUPPORT_TLS
+extern uschar *gnutls_require_mac; /* So some can be avoided */
+extern uschar *gnutls_require_kx; /* So some can be avoided */
+extern uschar *gnutls_require_proto; /* So some can be avoided */
extern const pcre *regex_STARTTLS; /* For recognizing STARTTLS settings */
extern uschar *tls_advertise_hosts; /* host for which TLS is advertised */
extern uschar *tls_certificate; /* Certificate file */
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 593da8a57..c3514aba5 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/readconf.c,v 1.26 2007/01/08 10:50:18 ph10 Exp $ */
+/* $Cambridge: exim/src/src/readconf.c,v 1.27 2007/01/18 15:35:42 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -218,6 +218,11 @@ static optionlist optionlist_config[] = {
{ "freeze_tell", opt_stringptr, &freeze_tell },
{ "gecos_name", opt_stringptr, &gecos_name },
{ "gecos_pattern", opt_stringptr, &gecos_pattern },
+#ifdef SUPPORT_TLS
+ { "gnutls_require_kx", opt_stringptr, &gnutls_require_kx },
+ { "gnutls_require_mac", opt_stringptr, &gnutls_require_mac },
+ { "gnutls_require_protocols", opt_stringptr, &gnutls_require_proto },
+#endif
{ "header_line_maxsize", opt_int, &header_line_maxsize },
{ "header_maxsize", opt_int, &header_maxsize },
{ "headers_charset", opt_stringptr, &headers_charset },
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index b1a1eba3d..ea7039935 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/smtp_in.c,v 1.50 2007/01/15 15:59:22 ph10 Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.51 2007/01/18 15:35:42 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -1540,7 +1540,9 @@ if (!sender_host_unknown)
smtps port for use with older style SSL MTAs. */
#ifdef SUPPORT_TLS
- if (tls_on_connect && tls_server_start(tls_require_ciphers) != OK)
+ if (tls_on_connect &&
+ tls_server_start(tls_require_ciphers,
+ gnutls_require_mac, gnutls_require_kx, gnutls_require_proto) != OK)
return FALSE;
#endif
@@ -3593,7 +3595,8 @@ while (done <= 0)
We must allow for an extra EHLO command and an extra AUTH command after
STARTTLS that don't add to the nonmail command count. */
- if ((rc = tls_server_start(tls_require_ciphers)) == OK)
+ if ((rc = tls_server_start(tls_require_ciphers, gnutls_require_mac,
+ gnutls_require_kx, gnutls_require_proto)) == OK)
{
if (!tls_remember_esmtp)
helo_seen = esmtp = auth_advertised = pipelining_advertised = FALSE;
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 891d1ea00..ee57659fa 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/tls-gnu.c,v 1.17 2007/01/08 10:50:18 ph10 Exp $ */
+/* $Cambridge: exim/src/src/tls-gnu.c,v 1.18 2007/01/18 15:35:42 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -46,17 +46,24 @@ static char ssl_errstring[256];
static int ssl_session_timeout = 200;
static int verify_requirement;
-/* Priorities for TLS algorithms to use. At present, only the cipher priority
-vector can be altered. */
+/* Priorities for TLS algorithms to use. In each case there's a default table,
+and space into which it can be copied and altered. */
-static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
+static const int default_proto_priority[16] = {
+ GNUTLS_TLS1,
+ GNUTLS_SSL3,
+ 0 };
+
+static int proto_priority[16];
-static const int kx_priority[16] = {
+static const int default_kx_priority[16] = {
GNUTLS_KX_RSA,
GNUTLS_KX_DHE_DSS,
GNUTLS_KX_DHE_RSA,
0 };
+static int kx_priority[16];
+
static int default_cipher_priority[16] = {
GNUTLS_CIPHER_AES_256_CBC,
GNUTLS_CIPHER_AES_128_CBC,
@@ -66,21 +73,50 @@ static int default_cipher_priority[16] = {
static int cipher_priority[16];
-static const int mac_priority[16] = {
+static const int default_mac_priority[16] = {
GNUTLS_MAC_SHA,
GNUTLS_MAC_MD5,
0 };
+static int mac_priority[16];
+
+/* These two are currently not changeable. */
+
static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
-/* Tables of cipher names and equivalent numbers */
+/* Tables of priority names and equivalent numbers */
typedef struct pri_item {
uschar *name;
int *values;
} pri_item;
+
+static int tls1_codes[] = { GNUTLS_TLS1, 0 };
+static int ssl3_codes[] = { GNUTLS_SSL3, 0 };
+
+static pri_item proto_index[] = {
+ { US"TLS1", tls1_codes },
+ { US"SSL3", ssl3_codes }
+};
+
+
+static int kx_rsa_codes[] = { GNUTLS_KX_RSA,
+ GNUTLS_KX_DHE_RSA, 0 };
+static int kx_dhe_codes[] = { GNUTLS_KX_DHE_DSS,
+ GNUTLS_KX_DHE_RSA, 0 };
+static int kx_dhe_dss_codes[] = { GNUTLS_KX_DHE_DSS, 0 };
+static int kx_dhe_rsa_codes[] = { GNUTLS_KX_DHE_RSA, 0 };
+
+static pri_item kx_index[] = {
+ { US"DHE_DSS", kx_dhe_dss_codes },
+ { US"DHE_RSA", kx_dhe_rsa_codes },
+ { US"RSA", kx_rsa_codes },
+ { US"DHE", kx_dhe_codes }
+};
+
+
static int arcfour_128_codes[] = { GNUTLS_CIPHER_ARCFOUR_128, 0 };
static int arcfour_40_codes[] = { GNUTLS_CIPHER_ARCFOUR_40, 0 };
static int arcfour_codes[] = { GNUTLS_CIPHER_ARCFOUR_128,
@@ -102,6 +138,16 @@ static pri_item cipher_index[] = {
};
+static int mac_sha_codes[] = { GNUTLS_MAC_SHA, 0 };
+static int mac_md5_codes[] = { GNUTLS_MAC_MD5, 0 };
+
+static pri_item mac_index[] = {
+ { US"SHA", mac_sha_codes },
+ { US"SHA1", mac_sha_codes },
+ { US"MD5", mac_md5_codes }
+};
+
+
/*************************************************
* Handle TLS error *
@@ -512,7 +558,7 @@ return OK;
/*************************************************
-* Remove ciphers from priority list *
+* Remove from a priority list *
*************************************************/
/* Cautiously written so that it will remove duplicates if present.
@@ -525,7 +571,7 @@ Returns: nothing
*/
static void
-remove_ciphers(int *list, int *remove_list)
+remove_priority(int *list, int *remove_list)
{
for (; *remove_list != 0; remove_list++)
{
@@ -545,7 +591,7 @@ for (; *remove_list != 0; remove_list++)
/*************************************************
-* Add ciphers to priority list *
+* Add to a priority list *
*************************************************/
/* Cautiously written to check the list size
@@ -559,7 +605,7 @@ Returns: TRUE if OK; FALSE if list overflows
*/
static BOOL
-add_ciphers(int *list, int list_max, int *add_list)
+add_priority(int *list, int list_max, int *add_list)
{
int next = 0;
while (list[next] != 0) next++;
@@ -575,6 +621,78 @@ return TRUE;
/*************************************************
+* Adjust a priority list *
+*************************************************/
+
+/* This function is called to adjust the lists of cipher algorithms, MAC
+algorithms, key-exchange methods, and protocols.
+
+Arguments:
+ plist the appropriate priority list
+ psize the length of the list
+ s the configuation string
+ index the index of recognized strings
+ isize the length of the index
+
+
+ which text for an error message
+
+Returns: FALSE if the table overflows, else TRUE
+*/
+
+static BOOL
+set_priority(int *plist, int psize, uschar *s, pri_item *index, int isize,
+ uschar *which)
+{
+int sep = 0;
+BOOL first = TRUE;
+uschar *t;
+
+while ((t = string_nextinlist(&s, &sep, big_buffer, big_buffer_size)) != NULL)
+ {
+ int i;
+ BOOL exclude = t[0] == '!';
+ if (first && !exclude) plist[0] = 0;
+ first = FALSE;
+ for (i = 0; i < isize; i++)
+ {
+ uschar *ss = strstric(t, index[i].name, FALSE);
+ if (ss != NULL)
+ {
+ uschar *endss = ss + Ustrlen(index[i].name);
+ if ((ss == t || !isalnum(ss[-1])) && !isalnum(*endss))
+ {
+ if (exclude)
+ remove_priority(plist, index[i].values);
+ else
+ {
+ if (!add_priority(plist, psize, index[i].values))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "GnuTLS init failed: %s "
+ "priority table overflow", which);
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+DEBUG(D_tls)
+ {
+ int *ptr = plist;
+ debug_printf("adjusted %s priorities:", which);
+ while (*ptr != 0) debug_printf(" %d", *ptr++);
+ debug_printf("\n");
+ }
+
+return TRUE;
+}
+
+
+
+
+/*************************************************
* Initialize a single GNUTLS session *
*************************************************/
@@ -591,78 +709,60 @@ cipher.
Arguments:
side one of GNUTLS_SERVER, GNUTLS_CLIENT
- expciphers expanded ciphers list
+ expciphers expanded ciphers list or NULL
+ expmac expanded MAC list or NULL
+ expkx expanded key-exchange list or NULL
+ expproto expanded protocol list or NULL
Returns: a gnutls_session, or NULL if there is a problem
*/
static gnutls_session
-tls_session_init(int side, uschar *expciphers)
+tls_session_init(int side, uschar *expciphers, uschar *expmac, uschar *expkx,
+ uschar *expproto)
{
gnutls_session session;
gnutls_init(&session, side);
-/* Handle the list of permitted ciphers */
+/* Initialize the lists of permitted protocols, key-exchange methods, ciphers,
+and MACs. */
memcpy(cipher_priority, default_cipher_priority, sizeof(cipher_priority));
+memcpy(mac_priority, default_mac_priority, sizeof(mac_priority));
+memcpy(kx_priority, default_kx_priority, sizeof(kx_priority));
+memcpy(proto_priority, default_proto_priority, sizeof(proto_priority));
+
+/* The names OpenSSL uses in tls_require_ciphers are of the form DES-CBC3-SHA,
+using hyphen separators. GnuTLS uses underscore separators. So that I can use
+either form for tls_require_ciphers in my tests, and also for general
+convenience, we turn hyphens into underscores before scanning the list. */
if (expciphers != NULL)
{
- int sep = 0;
- BOOL first = TRUE;
- uschar *cipher;
-
- /* The names OpenSSL uses are of the form DES-CBC3-SHA, using hyphen
- separators. GnuTLS uses underscore separators. So that I can use either form
- in my tests, and also for general convenience, we turn hyphens into
- underscores before scanning the list. */
-
uschar *s = expciphers;
while (*s != 0) { if (*s == '-') *s = '_'; s++; }
+ }
- while ((cipher = string_nextinlist(&expciphers, &sep, big_buffer,
- big_buffer_size)) != NULL)
- {
- int i;
- BOOL exclude = cipher[0] == '!';
- if (first && !exclude) cipher_priority[0] = 0;
- first = FALSE;
-
- for (i = 0; i < sizeof(cipher_index)/sizeof(pri_item); i++)
- {
- uschar *ss = strstric(cipher, cipher_index[i].name, FALSE);
- if (ss != NULL)
- {
- uschar *endss = ss + Ustrlen(cipher_index[i].name);
- if ((ss == cipher || !isalnum(ss[-1])) && !isalnum(*endss))
- {
- if (exclude)
- remove_ciphers(cipher_priority, cipher_index[i].values);
- else
- {
- if (!add_ciphers(cipher_priority,
- sizeof(cipher_priority)/sizeof(pri_item),
- cipher_index[i].values))
- {
- log_write(0, LOG_MAIN|LOG_PANIC, "GnuTLS init failed: cipher "
- "priority table overflow");
- gnutls_deinit(session);
- return NULL;
- }
- }
- }
- }
- }
- }
-
- DEBUG(D_tls)
- {
- int *ptr = cipher_priority;
- debug_printf("adjusted cipher priorities:");
- while (*ptr != 0) debug_printf(" %d", *ptr++);
- debug_printf("\n");
- }
+if ((expciphers != NULL &&
+ !set_priority(cipher_priority, sizeof(cipher_priority)/sizeof(int),
+ expciphers, cipher_index, sizeof(cipher_index)/sizeof(pri_item),
+ US"cipher")) ||
+ (expmac != NULL &&
+ !set_priority(mac_priority, sizeof(mac_priority)/sizeof(int),
+ expmac, mac_index, sizeof(mac_index)/sizeof(pri_item),
+ US"MAC")) ||
+ (expkx != NULL &&
+ !set_priority(kx_priority, sizeof(kx_priority)/sizeof(int),
+ expkx, kx_index, sizeof(kx_index)/sizeof(pri_item),
+ US"key-exchange")) ||
+ (expproto != NULL &&
+ !set_priority(proto_priority, sizeof(proto_priority)/sizeof(int),
+ expproto, proto_index, sizeof(proto_index)/sizeof(pri_item),
+ US"protocol")))
+ {
+ gnutls_deinit(session);
+ return NULL;
}
/* Define the various priorities */
@@ -670,7 +770,7 @@ if (expciphers != NULL)
gnutls_cipher_set_priority(session, cipher_priority);
gnutls_compression_set_priority(session, comp_priority);
gnutls_kx_set_priority(session, kx_priority);
-gnutls_protocol_set_priority(session, protocol_priority);
+gnutls_protocol_set_priority(session, proto_priority);
gnutls_mac_set_priority(session, mac_priority);
gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
@@ -739,7 +839,10 @@ the STARTTLS command. It must respond to that command, and then negotiate
a TLS session.
Arguments:
- require_ciphers list of allowed ciphers
+ require_ciphers list of allowed ciphers or NULL
+ require_mac list of allowed MACs or NULL
+ require_kx list of allowed key_exchange methods or NULL
+ require_proto list of allowed protocols or NULL
Returns: OK on success
DEFER for errors before the start of the negotiation
@@ -748,11 +851,15 @@ Returns: OK on success
*/
int
-tls_server_start(uschar *require_ciphers)
+tls_server_start(uschar *require_ciphers, uschar *require_mac,
+ uschar *require_kx, uschar *require_proto)
{
int rc;
uschar *error;
uschar *expciphers = NULL;
+uschar *expmac = NULL;
+uschar *expkx = NULL;
+uschar *expproto = NULL;
/* Check for previous activation */
@@ -774,7 +881,10 @@ rc = tls_init(NULL, tls_certificate, tls_privatekey, tls_verify_certificates,
tls_crl);
if (rc != OK) return rc;
-if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
+if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers) ||
+ !expand_check(require_mac, US"gnutls_require_mac", &expmac) ||
+ !expand_check(require_kx, US"gnutls_require_kx", &expkx) ||
+ !expand_check(require_proto, US"gnutls_require_proto", &expproto))
return FAIL;
/* If this is a host for which certificate verification is mandatory or
@@ -790,7 +900,8 @@ else if (verify_check_host(&tls_try_verify_hosts) == OK)
/* Prepare for new connection */
-tls_session = tls_session_init(GNUTLS_SERVER, expciphers);
+tls_session = tls_session_init(GNUTLS_SERVER, expciphers, expmac, expkx,
+ expproto);
if (tls_session == NULL)
return tls_error(US"tls_session_init", NULL, GNUTLS_E_MEMORY_ERROR);
@@ -883,13 +994,16 @@ return OK;
Arguments:
fd the fd of the connection
host connected host (for messages)
- addr
+ addr the first address (not used)
dhparam DH parameter file
certificate certificate file
privatekey private key file
verify_certs file for certificate verify
verify_crl CRL for verify
- require_ciphers list of allowed ciphers
+ require_ciphers list of allowed ciphers or NULL
+ require_mac list of allowed MACs or NULL
+ require_kx list of allowed key_exchange methods or NULL
+ require_proto list of allowed protocols or NULL
timeout startup timeout
Returns: OK/DEFER/FAIL (because using common functions),
@@ -899,10 +1013,14 @@ Returns: OK/DEFER/FAIL (because using common functions),
int
tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam,
uschar *certificate, uschar *privatekey, uschar *verify_certs,
- uschar *verify_crl, uschar *require_ciphers, int timeout)
+ uschar *verify_crl, uschar *require_ciphers, uschar *require_mac,
+ uschar *require_kx, uschar *require_proto, int timeout)
{
const gnutls_datum *server_certs;
uschar *expciphers = NULL;
+uschar *expmac = NULL;
+uschar *expkx = NULL;
+uschar *expproto = NULL;
uschar *error;
unsigned int server_certs_size;
int rc;
@@ -914,10 +1032,15 @@ verify_requirement = (verify_certs == NULL)? VERIFY_NONE : VERIFY_REQUIRED;
rc = tls_init(host, certificate, privatekey, verify_certs, verify_crl);
if (rc != OK) return rc;
-if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers))
+if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers) ||
+ !expand_check(require_mac, US"gnutls_require_mac", &expmac) ||
+ !expand_check(require_kx, US"gnutls_require_kx", &expkx) ||
+ !expand_check(require_proto, US"gnutls_require_proto", &expproto))
return FAIL;
-tls_session = tls_session_init(GNUTLS_CLIENT, expciphers);
+tls_session = tls_session_init(GNUTLS_CLIENT, expciphers, expmac, expkx,
+ expproto);
+
if (tls_session == NULL)
return tls_error(US "tls_session_init", host, GNUTLS_E_MEMORY_ERROR);
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 297b68b0d..1ae725b86 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/tls-openssl.c,v 1.9 2007/01/08 10:50:18 ph10 Exp $ */
+/* $Cambridge: exim/src/src/tls-openssl.c,v 1.10 2007/01/18 15:35:42 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -598,6 +598,11 @@ a TLS session.
Arguments:
require_ciphers allowed ciphers
+ ------------------------------------------------------
+ require_mac list of allowed MACs ) Not used
+ require_kx list of allowed key_exchange methods ) for
+ require_proto list of allowed protocols ) OpenSSL
+ ------------------------------------------------------
Returns: OK on success
DEFER for errors before the start of the negotiation
@@ -606,7 +611,8 @@ Returns: OK on success
*/
int
-tls_server_start(uschar *require_ciphers)
+tls_server_start(uschar *require_ciphers, uschar *require_mac,
+ uschar *require_kx, uschar *require_proto)
{
int rc;
uschar *expciphers;
@@ -746,12 +752,19 @@ return OK;
Argument:
fd the fd of the connection
host connected host (for messages)
+ addr the first address
dhparam DH parameter file
certificate certificate file
privatekey private key file
verify_certs file for certificate verify
crl file containing CRL
require_ciphers list of allowed ciphers
+ ------------------------------------------------------
+ require_mac list of allowed MACs ) Not used
+ require_kx list of allowed key_exchange methods ) for
+ require_proto list of allowed protocols ) OpenSSL
+ ------------------------------------------------------
+ timeout startup timeout
Returns: OK on success
FAIL otherwise - note that tls_error() will not give DEFER
@@ -761,7 +774,8 @@ Returns: OK on success
int
tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam,
uschar *certificate, uschar *privatekey, uschar *verify_certs, uschar *crl,
- uschar *require_ciphers, int timeout)
+ uschar *require_ciphers, uschar *require_mac, uschar *require_kx,
+ uschar *require_proto, int timeout)
{
static uschar txt[256];
uschar *expciphers;
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index a5a96aeed..887b1ff82 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.30 2007/01/08 10:50:20 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.31 2007/01/18 15:35:43 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -63,6 +63,14 @@ optionlist smtp_transport_options[] = {
(void *)offsetof(smtp_transport_options_block, final_timeout) },
{ "gethostbyname", opt_bool,
(void *)offsetof(smtp_transport_options_block, gethostbyname) },
+ #ifdef SUPPORT_TLS
+ { "gnutls_require_kx", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, gnutls_require_kx) },
+ { "gnutls_require_mac", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, gnutls_require_mac) },
+ { "gnutls_require_protocols", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, gnutls_require_proto) },
+ #endif
{ "helo_data", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, helo_data) },
{ "hosts", opt_stringptr,
@@ -178,6 +186,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
NULL, /* tls_crl */
NULL, /* tls_privatekey */
NULL, /* tls_require_ciphers */
+ NULL, /* gnutls_require_kx */
+ NULL, /* gnutls_require_mac */
+ NULL, /* gnutls_require_proto */
NULL, /* tls_verify_certificates */
TRUE /* tls_tempfail_tryclear */
#endif
@@ -1053,13 +1064,18 @@ if (tls_offered && !suppress_tls &&
else
{
- int rc = tls_client_start(inblock.sock, host, addrlist,
+ int rc = tls_client_start(inblock.sock,
+ host,
+ addrlist,
NULL, /* No DH param */
ob->tls_certificate,
ob->tls_privatekey,
ob->tls_verify_certificates,
ob->tls_crl,
ob->tls_require_ciphers,
+ ob->gnutls_require_mac,
+ ob->gnutls_require_kx,
+ ob->gnutls_require_proto,
ob->command_timeout);
/* TLS negotiation failed; give an error. From outside, this function may
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index e759286bc..4f5dec707 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.h,v 1.10 2007/01/08 10:50:20 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.h,v 1.11 2007/01/18 15:35:43 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -50,6 +50,9 @@ typedef struct {
uschar *tls_crl;
uschar *tls_privatekey;
uschar *tls_require_ciphers;
+ uschar *gnutls_require_kx;
+ uschar *gnutls_require_mac;
+ uschar *gnutls_require_proto;
uschar *tls_verify_certificates;
BOOL tls_tempfail_tryclear;
#endif
diff --git a/test/confs/2011 b/test/confs/2011
index f5f707eb1..334ca894f 100644
--- a/test/confs/2011
+++ b/test/confs/2011
@@ -1,6 +1,10 @@
# Exim test configuration 2011
SERVER =
+CREQCIP =
+CREQMAC =
+SREQCIP =
+SREQMAC =
exim_path = EXIM_PATH
host_lookup_order = bydns
@@ -28,6 +32,9 @@ tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
tls_verify_hosts = *
tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
+SREQCIP
+SREQMAC
+
# ----- Routers -----
@@ -52,7 +59,7 @@ send_to_server:
port = PORT_D
tls_certificate = DIR/aux-fixed/cert2
tls_privatekey = DIR/aux-fixed/cert2
- tls_require_ciphers = IDEA-CBC-MD5 \
- ${if eq{$host_address}{127.0.0.1}{:DES-CBC3-SHA:RSA_ARCFOUR_SHA}}
+ CREQCIP
+ CREQMAC
# End
diff --git a/test/log/2011 b/test/log/2011
index 477754e37..7fc966b95 100644
--- a/test/log/2011
+++ b/test/log/2011
@@ -1,11 +1,50 @@
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
1999-03-02 09:44:33 Start queue run: pid=pppp -qf
1999-03-02 09:44:33 10HmaX-0005vi-00 TLS error on connection to ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] (gnutls_handshake): No supported cipher suites have been found.
-1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS-1.0:RSA_ARCFOUR_SHA1:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmaX-0005vi-00 TLS error on connection to 127.0.0.1 [127.0.0.1] (gnutls_handshake): No supported cipher suites have been found.
+1999-03-02 09:44:33 10HmaX-0005vi-00 TLS session failure: delivering unencrypted to 127.0.0.1 [127.0.0.1] (not in hosts_require_tls)
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]
1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userx@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS-1.0:RSA_ARCFOUR_SHA1:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userx@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS-1.0:RSA_ARCFOUR_MD5:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userx@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS-1.0:RSA_ARCFOUR_MD5:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userx@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS-1.0:RSA_AES_256_CBC_SHA1:32 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbC-0005vi-00 => userx@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS-1.0:RSA_AES_256_CBC_SHA1:32 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userx@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=SSL 3.0:RSA_AES_256_CBC_SHA1:32 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbE-0005vi-00 => userx@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLS-1.0:RSA_ARCFOUR_MD5:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
******** SERVER ********
1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
1999-03-02 09:44:33 TLS error on connection from the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] (gnutls_handshake): A TLS packet with unexpected length was received.
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLS-1.0:RSA_ARCFOUR_SHA1:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 TLS error on connection from localhost (myhost.test.ex) [127.0.0.1] (gnutls_handshake): A TLS packet with unexpected length was received.
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS-1.0:RSA_ARCFOUR_SHA1:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS-1.0:RSA_ARCFOUR_MD5:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS-1.0:RSA_ARCFOUR_MD5:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS-1.0:RSA_AES_256_CBC_SHA1:32 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS-1.0:RSA_AES_256_CBC_SHA1:32 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=SSL 3.0:RSA_AES_256_CBC_SHA1:32 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS-1.0:RSA_ARCFOUR_MD5:16 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
diff --git a/test/scripts/2000-GnuTLS/2011 b/test/scripts/2000-GnuTLS/2011
index 4e48ebce6..6f72fba80 100644
--- a/test/scripts/2000-GnuTLS/2011
+++ b/test/scripts/2000-GnuTLS/2011
@@ -1,10 +1,38 @@
-# TLS client: require_ciphers
+# TLS client & server: (gnu)tls_require_xxx
gnutls
+# Start up the server
exim -DSERVER=server -bd -oX PORT_D
****
+# This puts a message on the queue (queue_only is set).
exim userx@test.ex
Testing
****
+# This will fail to deliver encrypted because there are no acceptable
+# ciphers, so it will deliver in clear.
+exim -qf -DCREQCIP=tls_require_ciphers=IDEA-CBC-MD5
+****
+# This delivers the message to the server, where it will remain
+# on the queue because queue_only is set.
+exim -qf -DCREQCIP=tls_require_ciphers=IDEA-CBC-MD5:DES-CBC3-SHA:RSA_ARCFOUR_SHA
+****
+# So we can deliver it again and again, with different parameters.
+exim -qf -DCREQMAC=gnutls_require_mac=MD5
+****
+exim -qf -DCREQMAC=gnutls_require_mac=!SHA1
+****
+exim -qf -DCREQMAC=gnutls_require_mac=MD5:SHA
+****
+exim -qf -DCREQMAC=gnutls_require_kx=!DHE
+****
+exim -qf -DCREQMAC=gnutls_require_protocols=SSL3
+****
+# Restart the server with a cipher restriction
+killdaemon
+exim -DSERVER=server \
+ -DSREQCIP=tls_require_ciphers=ARCFOUR \
+ -DSREQMAC=gnutls_require_mac=MD5 \
+ -bd -oX PORT_D
+****
exim -qf
****
killdaemon