summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhil Pennock <pdp@exim.org>2012-05-04 08:27:09 -0700
committerPhil Pennock <pdp@exim.org>2012-05-04 08:27:09 -0700
commit3f0945ffae8acee547d11ae53d38fbdf9a2cc81f (patch)
tree2e726521f7a030478238a0dab3841fdaafde1e26 /src
parent7be682ca5ebd9571a01b762195b11c34cd231830 (diff)
More tls_sni support: outbound, logging.
tls_sni as SMTP transport option. Use correct storage pool for copying tls_sni, so survives for life of process. Add +tls_sni log-selector, for inbound tls_sni. Update exipick to handle -tls_sni in spool files. Also reset tls_bits at start of outbound connection (was missing).
Diffstat (limited to 'src')
-rw-r--r--src/src/exipick.src6
-rw-r--r--src/src/functions.h2
-rw-r--r--src/src/globals.c3
-rw-r--r--src/src/local_scan.h2
-rw-r--r--src/src/macros.h3
-rw-r--r--src/src/receive.c5
-rw-r--r--src/src/smtp_in.c5
-rw-r--r--src/src/string.c2
-rw-r--r--src/src/tls-gnu.c6
-rw-r--r--src/src/tls-openssl.c37
-rw-r--r--src/src/transports/smtp.c10
-rw-r--r--src/src/transports/smtp.h1
12 files changed, 66 insertions, 16 deletions
diff --git a/src/src/exipick.src b/src/src/exipick.src
index 811092dc1..ed3b66154 100644
--- a/src/src/exipick.src
+++ b/src/src/exipick.src
@@ -955,6 +955,8 @@ sub _parse_header {
$self->{_vars}{tls_cipher} = $arg;
} elsif ($tag eq '-tls_peerdn') {
$self->{_vars}{tls_peerdn} = $arg;
+ } elsif ($tag eq '-tls_sni') {
+ $self->{_vars}{tls_sni} = $arg;
} elsif ($tag eq '-host_address') {
$self->{_vars}{sender_host_port} = $self->_get_host_and_port(\$arg);
$self->{_vars}{sender_host_address} = $arg;
@@ -1793,6 +1795,10 @@ The cipher suite that was negotiated for encrypted SMTP connections.
The value of the Distinguished Name of the certificate if Exim is configured to request one
+=item S . $tls_sni
+
+The value of the Server Name Indication TLS extension sent by a client, if one was sent.
+
=item N + $warning_count
The number of delay warnings which have been sent for this message.
diff --git a/src/src/functions.h b/src/src/functions.h
index f1af42ee5..220235235 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -23,7 +23,7 @@ extern uschar *init_perl(uschar *);
#ifdef SUPPORT_TLS
extern int tls_client_start(int, host_item *, address_item *, uschar *,
uschar *, uschar *, uschar *, uschar *, uschar *, uschar *,
- uschar *, uschar *, int);
+ uschar *, uschar *, uschar *, int);
extern void tls_close(BOOL);
extern int tls_feof(void);
extern int tls_ferror(void);
diff --git a/src/src/globals.c b/src/src/globals.c
index 7985cd3f0..f11c7c2db 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -697,7 +697,7 @@ uschar *log_file_path = US LOG_FILE_PATH
/* Those log options with L_xxx identifiers have values less than 0x800000 and
are the ones that get put into log_write_selector. They can be used in calls to
log_write() to test for the bit. The options with LX_xxx identifiers have
-values greater than 0x80000000 and are put int log_extra_selector (without the
+values greater than 0x80000000 and are put into log_extra_selector (without the
top bit). They are never used in calls to log_write(), but are tested
independently. This separation became necessary when the number of log
selectors was getting close to filling a 32-bit word. */
@@ -746,6 +746,7 @@ bit_table log_options[] = {
{ US"tls_certificate_verified", LX_tls_certificate_verified },
{ US"tls_cipher", LX_tls_cipher },
{ US"tls_peerdn", LX_tls_peerdn },
+ { US"tls_sni", LX_tls_sni },
{ US"unknown_in_list", LX_unknown_in_list }
};
diff --git a/src/src/local_scan.h b/src/src/local_scan.h
index 25b194407..aedfc9f92 100644
--- a/src/src/local_scan.h
+++ b/src/src/local_scan.h
@@ -186,7 +186,7 @@ extern uschar *rfc2047_decode(uschar *, BOOL, uschar *, int, int *, uschar **);
extern int smtp_fflush(void);
extern void smtp_printf(const char *, ...) PRINTF_FUNCTION(1,2);
extern void smtp_vprintf(const char *, va_list);
-extern uschar *string_copy(uschar *);
+extern uschar *string_copy(const uschar *);
extern uschar *string_copyn(uschar *, int);
extern uschar *string_sprintf(const char *, ...) PRINTF_FUNCTION(1,2);
diff --git a/src/src/macros.h b/src/src/macros.h
index c1c4cc33f..9b41226e5 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -407,7 +407,8 @@ set all the bits in a multi-word selector. */
#define LX_tls_certificate_verified 0x80100000
#define LX_tls_cipher 0x80200000
#define LX_tls_peerdn 0x80400000
-#define LX_unknown_in_list 0x80800000
+#define LX_tls_sni 0x80800000
+#define LX_unknown_in_list 0x81000000
#define L_default (L_connection_reject | \
L_delay_delivery | \
diff --git a/src/src/receive.c b/src/src/receive.c
index 71052657c..aaaf64ce6 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -3488,6 +3488,11 @@ if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
if ((log_extra_selector & LX_tls_peerdn) != 0 && tls_peerdn != NULL)
s = string_append(s, &size, &sptr, 3, US" DN=\"",
string_printing(tls_peerdn), US"\"");
+#ifndef USE_GNUTLS
+if ((log_extra_selector & LX_tls_sni) != 0 && tls_sni != NULL)
+ s = string_append(s, &size, &sptr, 3, US" SNI=\"",
+ string_printing(tls_sni), US"\"");
+#endif
#endif
if (sender_host_authenticated != NULL)
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 23bc5315e..d1c10f00f 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -841,6 +841,11 @@ if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
if ((log_extra_selector & LX_tls_peerdn) != 0 && tls_peerdn != NULL)
s = string_append(s, &size, &ptr, 3, US" DN=\"",
string_printing(tls_peerdn), US"\"");
+#ifndef USE_GNUTLS
+if ((log_extra_selector & LX_tls_sni) != 0 && tls_sni != NULL)
+ s = string_append(s, &size, &ptr, 3, US" SNI=\"",
+ string_printing(tls_sni), US"\"");
+#endif
#endif
sep = (smtp_connection_had[SMTP_HBUFF_SIZE-1] != SCH_NONE)?
diff --git a/src/src/string.c b/src/src/string.c
index 0a321ee1f..3fea7c048 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -415,7 +415,7 @@ Returns: copy of string in new store
*/
uschar *
-string_copy(uschar *s)
+string_copy(const uschar *s)
{
int len = Ustrlen(s) + 1;
uschar *ss = store_get(len);
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 2f952e47b..7e87dded0 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -1055,6 +1055,7 @@ Arguments:
dhparam DH parameter file
certificate certificate file
privatekey private key file
+ sni TLS SNI to send to remote host
verify_certs file for certificate verify
verify_crl CRL for verify
require_ciphers list of allowed ciphers or NULL
@@ -1069,8 +1070,9 @@ 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, uschar *require_mac,
+ uschar *certificate, uschar *privatekey, uschar *sni ARG_UNUSED,
+ uschar *verify_certs, uschar *verify_crl,
+ uschar *require_ciphers, uschar *require_mac,
uschar *require_kx, uschar *require_proto, int timeout)
{
const gnutls_datum *server_certs;
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 8cc2457e5..e609670ee 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -385,15 +385,18 @@ tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
const tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
int rc;
+int old_pool = store_pool;
if (!servername)
return SSL_TLSEXT_ERR_OK;
-DEBUG(D_tls) debug_printf("TLS SNI: %s%s\n", servername,
+DEBUG(D_tls) debug_printf("Received TLS SNI \"%s\"%s\n", servername,
reexpand_tls_files_for_sni ? "" : " (unused for certificate selection)");
/* Make the extension value available for expansion */
-tls_sni = servername;
+store_pool = POOL_PERM;
+tls_sni = string_copy(US servername);
+store_pool = old_pool;
if (!reexpand_tls_files_for_sni)
return SSL_TLSEXT_ERR_OK;
@@ -550,10 +553,13 @@ if (rc != OK) return rc;
/* If we need to handle SNI, do so */
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
-/* We always do this, so that $tls_sni is available even if not used in
-tls_certificate */
-SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
-SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo);
+if (host == NULL)
+ {
+ /* We always do this, so that $tls_sni is available even if not used in
+ tls_certificate */
+ SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
+ SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo);
+ }
#endif
/* Set up the RSA callback */
@@ -944,6 +950,7 @@ Argument:
dhparam DH parameter file
certificate certificate file
privatekey private key file
+ sni TLS SNI to send to remote host
verify_certs file for certificate verify
crl file containing CRL
require_ciphers list of allowed ciphers
@@ -961,7 +968,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 *certificate, uschar *privatekey, uschar *sni,
+ uschar *verify_certs, uschar *crl,
uschar *require_ciphers, uschar *require_mac, uschar *require_kx,
uschar *require_proto, int timeout)
{
@@ -1000,6 +1008,19 @@ SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx));
SSL_set_fd(ssl, fd);
SSL_set_connect_state(ssl);
+if (sni)
+ {
+ if (!expand_check(sni, US"tls_sni", &tls_sni))
+ return FAIL;
+ if (!Ustrlen(tls_sni))
+ tls_sni = NULL;
+ else
+ {
+ DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tls_sni);
+ SSL_set_tlsext_host_name(ssl, tls_sni);
+ }
+ }
+
/* There doesn't seem to be a built-in timeout on connection. */
DEBUG(D_tls) debug_printf("Calling SSL_connect\n");
@@ -1078,8 +1099,10 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
SSL_free(ssl);
ssl = NULL;
tls_active = -1;
+ tls_bits = 0;
tls_cipher = NULL;
tls_peerdn = NULL;
+ tls_sni = NULL;
return smtp_getc();
}
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index c571d874c..b1fedd2d4 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -128,8 +128,10 @@ optionlist smtp_transport_options[] = {
(void *)offsetof(smtp_transport_options_block, tls_crl) },
{ "tls_privatekey", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, tls_privatekey) },
- { "tls_require_ciphers", opt_stringptr,
+ { "tls_require_ciphers", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, tls_require_ciphers) },
+ { "tls_sni", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, tls_sni) },
{ "tls_tempfail_tryclear", opt_bool,
(void *)offsetof(smtp_transport_options_block, tls_tempfail_tryclear) },
{ "tls_verify_certificates", opt_stringptr,
@@ -191,7 +193,8 @@ smtp_transport_options_block smtp_transport_option_defaults = {
NULL, /* gnutls_require_mac */
NULL, /* gnutls_require_proto */
NULL, /* tls_verify_certificates */
- TRUE /* tls_tempfail_tryclear */
+ TRUE, /* tls_tempfail_tryclear */
+ NULL /* tls_sni */
#endif
#ifndef DISABLE_DKIM
,NULL, /* dkim_canon */
@@ -889,8 +892,10 @@ outblock.authenticating = FALSE;
/* Reset the parameters of a TLS session. */
+tls_bits = 0;
tls_cipher = NULL;
tls_peerdn = NULL;
+tls_sni = NULL;
/* If an authenticated_sender override has been specified for this transport
instance, expand it. If the expansion is forced to fail, and there was already
@@ -1122,6 +1127,7 @@ if (tls_offered && !suppress_tls &&
NULL, /* No DH param */
ob->tls_certificate,
ob->tls_privatekey,
+ ob->tls_sni,
ob->tls_verify_certificates,
ob->tls_crl,
ob->tls_require_ciphers,
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index a2ea4ff0a..605be4800 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -54,6 +54,7 @@ typedef struct {
uschar *gnutls_require_proto;
uschar *tls_verify_certificates;
BOOL tls_tempfail_tryclear;
+ uschar *tls_sni;
#endif
#ifndef DISABLE_DKIM
uschar *dkim_domain;