[exim-cvs] OpenSSL: support authenticator channel-binding. B…

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] OpenSSL: support authenticator channel-binding. Bug 2467
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     *