Gitweb:
https://git.exim.org/exim.git/commitdiff/1c519e07b908a314ce7bdfceb6baa9e18e302dfc
Commit: 1c519e07b908a314ce7bdfceb6baa9e18e302dfc
Parent: 9540bcf2addf37f08505454247f5687b68d340c7
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Sat Dec 28 17:00:30 2019 +0000
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Sat Dec 28 17:04:18 2019 +0000
GSASL channel-binding: TLS resumption checks
---
doc/doc-docbook/spec.xfpt | 2 +-
src/src/auths/gsasl_exim.c | 43 ++++++++++++++++++++++++++++++++-----------
src/src/auths/gsasl_exim.h | 2 +-
src/src/globals.h | 1 +
src/src/tls-gnu.c | 6 ++++++
src/src/tls-openssl.c | 2 ++
6 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 9043685..1d4c39c 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -27447,7 +27447,7 @@ without code changes in Exim.
.option client_authz gsasl string&!! unset
This option can be used to supply an &'authorization id'&
which is different to the &'authentication_id'& provided
-by $%client_username%& option.
+by &%client_username%& option.
If unset or (after expansion) empty it is not used,
which is the common case.
diff --git a/src/src/auths/gsasl_exim.c b/src/src/auths/gsasl_exim.c
index db14a40..f527e13 100644
--- a/src/src/auths/gsasl_exim.c
+++ b/src/src/auths/gsasl_exim.c
@@ -96,7 +96,7 @@ auth_gsasl_options_block auth_gsasl_option_defaults = {
/* Dummy values */
void auth_gsasl_init(auth_instance *ablock) {}
int auth_gsasl_server(auth_instance *ablock, uschar *data) {return 0;}
-int auth_gsasl_client(auth_instance *ablock, smtp_inblock * sx,
+int auth_gsasl_client(auth_instance *ablock, void * sx,
int timeout, uschar *buffer, int buffsize) {return 0;}
void auth_gsasl_version_report(FILE *f) {}
@@ -301,14 +301,24 @@ HDEBUG(D_auth)
ablock->name, ob->server_mech);
#ifndef DISABLE_TLS
+if (tls_in.channelbinding && ob->server_channelbinding)
+ {
+# ifdef EXPERIMENTAL_TLS_RESUME
+ if (!tls_in.ext_master_secret && tls_in.resumption == RESUME_USED)
+ { /* per RFC 7677 section 4 */
+ HDEBUG(D_auth) debug_printf(
+ "channel binding not usable on resumed TLS without extended-master-secret");
+ return FAIL;
+ }
+# endif
# ifdef CHANNELBIND_HACK
/* This is a gross hack to get around the library a) requiring that
c-b was already set, at the _start() call, and b) caching a b64'd
version of the binding then which it never updates. */
-if (tls_in.channelbinding && ob->server_channelbinding)
gsasl_callback_hook_set(gsasl_ctx, tls_in.channelbinding);
# endif
+ }
#endif
if ((rc = gsasl_server_start(gsasl_ctx, CCS ob->server_mech, &sctx)) != GSASL_OK)
@@ -362,7 +372,7 @@ if (tls_in.channelbinding)
{
HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n",
ablock->name);
-# ifdef CHANNELBIND_HACK
+# ifndef CHANNELBIND_HACK
gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_in.channelbinding);
# endif
}
@@ -720,7 +730,7 @@ return TRUE;
int
auth_gsasl_client(
auth_instance *ablock, /* authenticator block */
- smtp_inblock * sx, /* connection */
+ void * sx, /* connection */
int timeout, /* command timeout */
uschar *buffer, /* buffer for reading response */
int buffsize) /* size of buffer */
@@ -740,13 +750,24 @@ HDEBUG(D_auth)
*buffer = 0;
#ifndef DISABLE_TLS
-/* This is a gross hack to get around the library a) requiring that
-c-b was already set, at the _start() call, and b) caching a b64'd
-version of the binding then which it never updates. */
+if (tls_out.channelbinding && ob->client_channelbinding)
+ {
+# ifdef EXPERIMENTAL_TLS_RESUME
+ if (!tls_out.ext_master_secret && tls_out.resumption == RESUME_USED)
+ { /* per RFC 7677 section 4 */
+ string_format(buffer, buffsize, "%s",
+ "channel binding not usable on resumed TLS without extended-master-secret");
+ return FAIL;
+ }
+# endif
+# ifdef CHANNELBIND_HACK
+ /* This is a gross hack to get around the library a) requiring that
+ c-b was already set, at the _start() call, and b) caching a b64'd
+ version of the binding then which it never updates. */
-if (tls_out.channelbinding)
- if (ob->client_channelbinding)
- gsasl_callback_hook_set(gsasl_ctx, tls_out.channelbinding);
+ gsasl_callback_hook_set(gsasl_ctx, tls_out.channelbinding);
+# endif
+ }
#endif
if ((rc = gsasl_client_start(gsasl_ctx, CCS ob->server_mech, &sctx)) != GSASL_OK)
@@ -780,7 +801,7 @@ if (tls_out.channelbinding)
{
HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n",
ablock->name);
-# ifdef CHANNELBIND_HACK
+# ifndef CHANNELBIND_HACK
gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_out.channelbinding);
# endif
}
diff --git a/src/src/auths/gsasl_exim.h b/src/src/auths/gsasl_exim.h
index 93d2078..7afec70 100644
--- a/src/src/auths/gsasl_exim.h
+++ b/src/src/auths/gsasl_exim.h
@@ -42,7 +42,7 @@ extern auth_gsasl_options_block auth_gsasl_option_defaults;
extern void auth_gsasl_init(auth_instance *);
extern int auth_gsasl_server(auth_instance *, uschar *);
-extern int auth_gsasl_client(auth_instance *, smtp_inblock *,
+extern int auth_gsasl_client(auth_instance *, void *,
int, uschar *, int);
extern void auth_gsasl_version_report(FILE *f);
diff --git a/src/src/globals.h b/src/src/globals.h
index 03a56f0..bb66cb2 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -111,6 +111,7 @@ typedef struct {
BOOL ticket_received:1;
#endif
BOOL verify_override:1; /* certificate_verified only due to tls_try_verify_hosts */
+ BOOL ext_master_secret:1; /* extended-master-secret was used */
} tls_support;
extern tls_support tls_in;
extern tls_support tls_out;
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 837b991..69a8bd6 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -2529,6 +2529,9 @@ if (rc != GNUTLS_E_SUCCESS)
return FAIL;
}
+if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET)
+ tls_in.ext_master_secret = TRUE;
+
#ifdef EXPERIMENTAL_TLS_RESUME
tls_server_resume_posthandshake(state);
#endif
@@ -2998,6 +3001,9 @@ if (!verify_certificate(state, errstr))
return FALSE;
}
+if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET)
+ tlsp->ext_master_secret = TRUE;
+
#ifndef DISABLE_OCSP
if (request_ocsp)
{
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index bee5a42..d16479e 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -2784,6 +2784,7 @@ if (SSL_session_reused(server_ssl))
/* TLS has been set up. Record data for the connection,
adjust the input functions to read via TLS, and initialize things. */
+tls_in.ext_master_secret = SSL_get_extms_support(server_ssl) == 1;
peer_cert(server_ssl, &tls_in, peerdn, sizeof(peerdn));
tls_in.ver = tlsver_name(server_ssl);
@@ -3384,6 +3385,7 @@ DEBUG(D_tls)
tls_client_resume_posthandshake(exim_client_ctx, tlsp);
#endif
+tlsp->ext_master_secret = SSL_get_extms_support(exim_client_ctx->ssl) == 1;
peer_cert(exim_client_ctx->ssl, tlsp, peerdn, sizeof(peerdn));
tlsp->ver = tlsver_name(exim_client_ctx->ssl);