Gitweb:
https://git.exim.org/exim.git/commitdiff/b1a32a3ce673130f4b2f49a341b11c3567081637
Commit: b1a32a3ce673130f4b2f49a341b11c3567081637
Parent: 6a2c32cb705e73820c29e965394333f2874ba770
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Sun Nov 17 19:30:42 2019 +0000
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Sun Nov 17 21:23:05 2019 +0000
OpenSSL: support authenticator channel-binding. Bug 2467
---
doc/doc-txt/NewStuff | 3 +++
src/src/auths/gsasl_exim.c | 4 ++--
src/src/base64.c | 10 ++++++++--
src/src/functions.h | 1 +
src/src/globals.h | 2 +-
src/src/tls-gnu.c | 18 +++++++++++-------
src/src/tls-openssl.c | 28 ++++++++++++++++++++++++++++
src/src/tls.c | 2 --
8 files changed, 54 insertions(+), 14 deletions(-)
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index fbd1a5e..18c3d30 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -14,6 +14,9 @@ Version 4.next
2. Variables $tls_in_ver, $tls_out_ver.
+ 3. Channel-binding for authenticators is now supported under OpenSSL.
+ Previously it was GnuTLS-only.
+
Version 4.93
------------
diff --git a/src/src/auths/gsasl_exim.c b/src/src/auths/gsasl_exim.c
index 06c91ea..78a63cd 100644
--- a/src/src/auths/gsasl_exim.c
+++ b/src/src/auths/gsasl_exim.c
@@ -292,7 +292,7 @@ if (ob->server_realm)
gsasl_property_set(sctx, GSASL_QOPS, "qop-auth");
#ifndef DISABLE_TLS
-if (tls_channelbinding_b64)
+if (tls_in.channelbinding)
{
/* Some auth mechanisms can ensure that both sides are talking withing the
same security context; for TLS, this means that even if a bad certificate
@@ -317,7 +317,7 @@ if (tls_channelbinding_b64)
HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n",
ablock->name);
gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE,
- CCS tls_channelbinding_b64);
+ CCS tls_in.channelbinding);
}
else
HDEBUG(D_auth)
diff --git a/src/src/base64.c b/src/src/base64.c
index 6c81914..aa46c2b 100644
--- a/src/src/base64.c
+++ b/src/src/base64.c
@@ -242,9 +242,9 @@ static uschar *enc64table =
US"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
uschar *
-b64encode(const uschar * clear, int len)
+b64encode_taint(const uschar * clear, int len, BOOL tainted)
{
-uschar *code = store_get(4*((len+2)/3) + 1, is_tainted(clear));
+uschar *code = store_get(4*((len+2)/3) + 1, tainted);
uschar *p = code;
while (len-- >0)
@@ -283,6 +283,12 @@ while (len-- >0)
return code;
}
+uschar *
+b64encode(const uschar * clear, int len)
+{
+return b64encode_taint(clear, len, is_tainted(clear));
+}
+
/* End of base64.c */
/* vi: sw ai sw=2
diff --git a/src/src/functions.h b/src/src/functions.h
index 187bdaf..da21b87 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -136,6 +136,7 @@ extern gstring *authres_spf(gstring *);
#endif
extern uschar *b64encode(const uschar *, int);
+extern uschar *b64encode_taint(const uschar *, int, BOOL);
extern int b64decode(const uschar *, uschar **);
extern int bdat_getc(unsigned);
extern uschar *bdat_getbuf(unsigned *);
diff --git a/src/src/globals.h b/src/src/globals.h
index 1754d3e..8a3d4c5 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -97,6 +97,7 @@ typedef struct {
void *peercert; /* Certificate of peer, binary */
uschar *peerdn; /* DN from peer */
uschar *sni; /* Server Name Indication */
+ uschar *channelbinding; /* b64'd data identifying channel, for authenticators */
enum {
OCSP_NOT_REQ=0, /* not requested */
OCSP_NOT_RESP, /* no response to request */
@@ -120,7 +121,6 @@ extern BOOL gnutls_allow_auto_pkcs11; /* Let GnuTLS autoload PKCS11 modules *
extern uschar *openssl_options; /* OpenSSL compatibility options */
extern const pcre *regex_STARTTLS; /* For recognizing STARTTLS settings */
extern uschar *tls_certificate; /* Certificate file */
-extern uschar *tls_channelbinding_b64; /* string of base64 channel binding */
extern uschar *tls_crl; /* CRL File */
extern int tls_dh_max_bits; /* don't accept higher lib suggestions */
extern uschar *tls_dhparam; /* DH param file */
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 7d7f61d..f3c3835 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -155,7 +155,7 @@ Some of these correspond to variables in globals.c; those variables will
be set to point to content in one of these instances, as appropriate for
the stage of the process lifetime.
-Not handled here: global tls_channelbinding_b64.
+Not handled here: global tlsp->tls_channelbinding.
*/
typedef struct exim_gnutls_state {
@@ -467,7 +467,7 @@ Sets:
tls_active fd
tls_bits strength indicator
tls_certificate_verified bool indicator
- tls_channelbinding_b64 for some SASL mechanisms
+ tls_channelbinding for some SASL mechanisms
tls_ver a string
tls_cipher a string
tls_peercert pointer to library internal
@@ -499,10 +499,10 @@ tlsp->certificate_verified = state->peer_cert_verified;
tlsp->dane_verified = state->peer_dane_verified;
#endif
-/* note that tls_channelbinding_b64 is not saved to the spool file, since it's
+/* note that tls_channelbinding is not saved to the spool file, since it's
only available for use for authenticators while this TLS session is running. */
-tls_channelbinding_b64 = NULL;
+tlsp->channelbinding = NULL;
#ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
channel.data = NULL;
channel.size = 0;
@@ -510,11 +510,15 @@ if ((rc = gnutls_session_channel_binding(state->session, GNUTLS_CB_TLS_UNIQUE, &
{ DEBUG(D_tls) debug_printf("Channel binding error: %s\n", gnutls_strerror(rc)); }
else
{
+ /* Declare the taintedness of the binding info. On server, untainted; on
+ client, tainted - being the Finish msg from the server. */
+
old_pool = store_pool;
store_pool = POOL_PERM;
- tls_channelbinding_b64 = b64encode(CUS channel.data, (int)channel.size);
+ tlsp->channelbinding = b64encode_taint(CUS channel.data, (int)channel.size,
+ !!state->host);
store_pool = old_pool;
- DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage.\n");
+ DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage\n");
}
#endif
@@ -3093,7 +3097,7 @@ gnutls_certificate_free_credentials(state->x509_cred);
tlsp->active.sock = -1;
tlsp->active.tls_ctx = NULL;
/* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
-tls_channelbinding_b64 = NULL;
+tlsp->channelbinding = NULL;
if (state->xfer_buffer) store_free(state->xfer_buffer);
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 7a82e1d..5ea4d96 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -2741,6 +2741,20 @@ DEBUG(D_tls)
tls_in.ourcert = crt ? X509_dup(crt) : NULL;
}
+/* Channel-binding info for authenticators
+See description in https://paquier.xyz/postgresql-2/channel-binding-openssl/ */
+ {
+ uschar c, * s;
+ size_t len = SSL_get_peer_finished(server_ssl, &c, 0);
+ int old_pool = store_pool;
+
+ SSL_get_peer_finished(server_ssl, s = store_get((int)len, FALSE), len);
+ store_pool = POOL_PERM;
+ tls_in.channelbinding = b64encode_taint(CUS s, (int)len, FALSE);
+ store_pool = old_pool;
+ DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage\n");
+ }
+
/* Only used by the server-side tls (tls_in), including tls_getc.
Client-side (tls_out) reads (seem to?) go via
smtp_read_response()/ip_recv().
@@ -3303,6 +3317,20 @@ tlsp->cipher_stdname = cipher_stdname_ssl(exim_client_ctx->ssl);
tlsp->ourcert = crt ? X509_dup(crt) : NULL;
}
+/*XXX will this work with continued-TLS? */
+/* Channel-binding info for authenticators */
+ {
+ uschar c, * s;
+ size_t len = SSL_get_finished(exim_client_ctx->ssl, &c, 0);
+ int old_pool = store_pool;
+
+ SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, TRUE), len);
+ store_pool = POOL_PERM;
+ tlsp->channelbinding = b64encode_taint(CUS s, (int)len, TRUE);
+ store_pool = old_pool;
+ DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage\n");
+ }
+
tlsp->active.sock = cctx->sock;
tlsp->active.tls_ctx = exim_client_ctx;
cctx->tls_ctx = exim_client_ctx;
diff --git a/src/src/tls.c b/src/src/tls.c
index 531d679..d47156c 100644
--- a/src/src/tls.c
+++ b/src/src/tls.c
@@ -61,8 +61,6 @@ static int ssl_xfer_eof = FALSE;
static BOOL ssl_xfer_error = FALSE;
#endif
-uschar *tls_channelbinding_b64 = NULL;
-
/*************************************************
* Expand string; give error on failure *