* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2019 */
+/* Copyright (c) The Exim Maintainers 2019-2020 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
*/
#include "../exim.h"
-#define CHANNELBIND_HACK
#ifndef AUTH_GSASL
/* dummy function to satisfy compilers when we link in an "empty" file. */
#include "gsasl_exim.h"
-#if GSASL_VERSION_MINOR >= 9
+#if GSASL_VERSION_MINOR >= 10
+# define EXIM_GSASL_HAVE_SCRAM_SHA_256
+# define EXIM_GSASL_SCRAM_S_KEY
+
+#elif GSASL_VERSION_MINOR == 9
# define EXIM_GSASL_HAVE_SCRAM_SHA_256
# if GSASL_VERSION_PATCH >= 1
# define EXIM_GSASL_SCRAM_S_KEY
# endif
+# if GSASL_VERSION_PATCH < 2
+# define CHANNELBIND_HACK
+# endif
+
+#else
+# define CHANNELBIND_HACK
#endif
we only ever handle one mechanism at a time, I didn't see the point in keeping
that. In case someone sees a point, I've left the condition_check() API
alone. */
+#define LOFF(field) OPT_OFF(auth_gsasl_options_block, field)
+
optionlist auth_gsasl_options[] = {
- { "client_authz", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, client_authz)) },
- { "client_channelbinding", opt_bool,
- (void *)(offsetof(auth_gsasl_options_block, client_channelbinding)) },
- { "client_password", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, client_password)) },
- { "client_spassword", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, client_spassword)) },
- { "client_username", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, client_username)) },
-
- { "server_channelbinding", opt_bool,
- (void *)(offsetof(auth_gsasl_options_block, server_channelbinding)) },
- { "server_hostname", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_hostname)) },
+ { "client_authz", opt_stringptr, LOFF(client_authz) },
+ { "client_channelbinding", opt_bool, LOFF(client_channelbinding) },
+ { "client_password", opt_stringptr, LOFF(client_password) },
+ { "client_spassword", opt_stringptr, LOFF(client_spassword) },
+ { "client_username", opt_stringptr, LOFF(client_username) },
+
+ { "server_channelbinding", opt_bool, LOFF(server_channelbinding) },
+ { "server_hostname", opt_stringptr, LOFF(server_hostname) },
#ifdef EXIM_GSASL_SCRAM_S_KEY
- { "server_key", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_key)) },
+ { "server_key", opt_stringptr, LOFF(server_key) },
#endif
- { "server_mech", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_mech)) },
- { "server_password", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_password)) },
- { "server_realm", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_realm)) },
- { "server_scram_iter", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_scram_iter)) },
- { "server_scram_salt", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_scram_salt)) },
+ { "server_mech", opt_stringptr, LOFF(server_mech) },
+ { "server_password", opt_stringptr, LOFF(server_password) },
+ { "server_realm", opt_stringptr, LOFF(server_realm) },
+ { "server_scram_iter", opt_stringptr, LOFF(server_scram_iter) },
+ { "server_scram_salt", opt_stringptr, LOFF(server_scram_salt) },
#ifdef EXIM_GSASL_SCRAM_S_KEY
- { "server_skey", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_s_key)) },
+ { "server_skey", opt_stringptr, LOFF(server_s_key) },
#endif
- { "server_service", opt_stringptr,
- (void *)(offsetof(auth_gsasl_options_block, server_service)) }
+ { "server_service", opt_stringptr, LOFF(server_service) }
};
int auth_gsasl_options_count =
#ifndef DISABLE_TLS
if (tls_in.channelbinding && ob->server_channelbinding)
{
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
if (!tls_in.ext_master_secret && tls_in.resumption == RESUME_USED)
{ /* per RFC 7677 section 4 */
HDEBUG(D_auth) debug_printf(
}
# 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. */
+/* This is a gross hack to get around the library before 1.9.2
+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. */
gsasl_callback_hook_set(gsasl_ctx, tls_in.channelbinding);
# endif
would then result in mechanism name changes on a library update, we
have little choice but to default it off and let the admin choose to
enable it. *sigh*
+
+ Earlier library versions need this set early, during the _start() call,
+ so we had to misuse gsasl_callback_hook_set/get() as a data transfer
+ mech for the callback done at that time to get the bind-data. More recently
+ the callback is done (if needed) during the first gsasl_stop(). We know
+ the bind-data here so can set it (and should not get a callback).
*/
if (ob->server_channelbinding)
{
#ifndef DISABLE_TLS
if (tls_out.channelbinding && ob->client_channelbinding)
{
-# ifdef EXPERIMENTAL_TLS_RESUME
+# ifndef DISABLE_TLS_RESUME
if (!tls_out.ext_master_secret && tls_out.resumption == RESUME_USED)
- { /* per RFC 7677 section 4 */
+ { /* Per RFC 7677 section 4. See also RFC 7627, "Triple Handshake"
+ vulnerability, and https://www.mitls.org/pages/attacks/3SHAKE */
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. */
+ /* This is a gross hack to get around the library before 1.9.2
+ 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. */
gsasl_callback_hook_set(gsasl_ctx, tls_out.channelbinding);
# endif
gsasl_prop_code_to_name(prop), ablock->name, ablock->public_name);
switch (prop)
{
- case GSASL_CB_TLS_UNIQUE:
+ case GSASL_CB_TLS_UNIQUE: /*XXX should never get called for this */
HDEBUG(D_auth)
debug_printf(" filling in\n");
gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_out.channelbinding);