]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/tls-gnu.c
Fix error logging for dynamically-loaded modules. Bug 2507
[user/henk/code/exim.git] / src / src / tls-gnu.c
index 13bf905a0153a836f5be183c8986ff43abd0165b..34ebc0903114a5414ac8c0c48bc2a8b46cdf2a6c 100644 (file)
@@ -70,6 +70,16 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
 #if GNUTLS_VERSION_NUMBER >= 0x03010a
 # define SUPPORT_GNUTLS_SESS_DESC
 #endif
 #if GNUTLS_VERSION_NUMBER >= 0x03010a
 # define SUPPORT_GNUTLS_SESS_DESC
 #endif
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+# define GNUTLS_AUTO_GLOBAL_INIT
+# define GNUTLS_AUTO_PKCS11_MANUAL
+#endif
+#if (GNUTLS_VERSION_NUMBER >= 0x030404) \
+  || (GNUTLS_VERSION_NUMBER >= 0x030311) && (GNUTLS_VERSION_NUMBER & 0xffff00 == 0x030300)
+# ifndef DISABLE_OCSP
+#  define EXIM_HAVE_OCSP
+# endif
+#endif
 #if GNUTLS_VERSION_NUMBER >= 0x030500
 # define SUPPORT_GNUTLS_KEYLOG
 #endif
 #if GNUTLS_VERSION_NUMBER >= 0x030500
 # define SUPPORT_GNUTLS_KEYLOG
 #endif
@@ -123,6 +133,12 @@ builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
 # ifdef EXIM_HAVE_TLS1_3
 builtin_macro_create(US"_HAVE_TLS1_3");
 # endif
 # ifdef EXIM_HAVE_TLS1_3
 builtin_macro_create(US"_HAVE_TLS1_3");
 # endif
+# ifdef EXIM_HAVE_OCSP
+builtin_macro_create(US"_HAVE_TLS_OCSP");
+# endif
+# ifdef SUPPORT_SRV_OCSP_STACK
+builtin_macro_create(US"_HAVE_TLS_OCSP_LIST");
+# endif
 }
 #else
 
 }
 #else
 
@@ -151,7 +167,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.
 
 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 {
 */
 
 typedef struct exim_gnutls_state {
@@ -463,7 +479,8 @@ Sets:
   tls_active                fd
   tls_bits                  strength indicator
   tls_certificate_verified  bool indicator
   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
   tls_peerdn                a string
   tls_cipher                a string
   tls_peercert              pointer to library internal
   tls_peerdn                a string
@@ -494,10 +511,10 @@ tlsp->certificate_verified = state->peer_cert_verified;
 tlsp->dane_verified = state->peer_dane_verified;
 #endif
 
 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. */
 
 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;
 #ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
 channel.data = NULL;
 channel.size = 0;
@@ -505,11 +522,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
   {
   { 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;
   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;
   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
 
   }
 #endif
 
@@ -1497,7 +1518,7 @@ if (!exim_gnutls_base_init_done)
   {
   DEBUG(D_tls) debug_printf("GnuTLS global init required.\n");
 
   {
   DEBUG(D_tls) debug_printf("GnuTLS global init required.\n");
 
-#ifdef HAVE_GNUTLS_PKCS11
+#if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL)
   /* By default, gnutls_global_init will init PKCS11 support in auto mode,
   which loads modules from a config file, which sounds good and may be wanted
   by some sysadmin, but also means in common configurations that GNOME keyring
   /* By default, gnutls_global_init will init PKCS11 support in auto mode,
   which loads modules from a config file, which sounds good and may be wanted
   by some sysadmin, but also means in common configurations that GNOME keyring
@@ -1508,8 +1529,10 @@ if (!exim_gnutls_base_init_done)
       return tls_error_gnu(US"gnutls_pkcs11_init", rc, host, errstr);
 #endif
 
       return tls_error_gnu(US"gnutls_pkcs11_init", rc, host, errstr);
 #endif
 
+#ifndef GNUTLS_AUTO_GLOBAL_INIT
   if ((rc = gnutls_global_init()))
     return tls_error_gnu(US"gnutls_global_init", rc, host, errstr);
   if ((rc = gnutls_global_init()))
     return tls_error_gnu(US"gnutls_global_init", rc, host, errstr);
+#endif
 
 #if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0
   DEBUG(D_tls)
 
 #if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0
   DEBUG(D_tls)
@@ -1748,11 +1771,17 @@ old_pool = store_pool;
     /* debug_printf("peer_status: gnutls_session_get_desc %s\n", s); */
 
     for (s++; (c = *s) && c != ')'; s++) g = string_catn(g, s, 1);
     /* debug_printf("peer_status: gnutls_session_get_desc %s\n", s); */
 
     for (s++; (c = *s) && c != ')'; s++) g = string_catn(g, s, 1);
+
+    tlsp->ver = string_copyn(g->s, g->ptr);
+    for (uschar * p = US tlsp->ver; *p; p++)
+      if (*p == '-') { *p = '\0'; break; }     /* TLS1.0-PKIX -> TLS1.0 */
+
     g = string_catn(g, US":", 1);
     if (*s) s++;               /* now on _ between groups */
     while ((c = *s))
       {
     g = string_catn(g, US":", 1);
     if (*s) s++;               /* now on _ between groups */
     while ((c = *s))
       {
-      for (*++s && ++s; (c = *s) && c != ')'; s++) g = string_catn(g, c == '-' ? US"_" : s, 1);
+      for (*++s && ++s; (c = *s) && c != ')'; s++)
+       g = string_catn(g, c == '-' ? US"_" : s, 1);
       /* now on ) closing group */
       if ((c = *s) && *++s == '-') g = string_catn(g, US"__", 2);
       /* now on _ between groups */
       /* now on ) closing group */
       if ((c = *s) && *++s == '-') g = string_catn(g, US"__", 2);
       /* now on _ between groups */
@@ -1772,6 +1801,8 @@ old_pool = store_pool;
   releases did return "TLS 1.0"; play it safe, just in case. */
 
   for (uschar * p = state->ciphersuite; *p; p++) if (isspace(*p)) *p = '-';
   releases did return "TLS 1.0"; play it safe, just in case. */
 
   for (uschar * p = state->ciphersuite; *p; p++) if (isspace(*p)) *p = '-';
+  tlsp->ver = string_copyn(state->ciphersuite,
+                       Ustrchr(state->ciphersuite, ':') - state->ciphersuite);
 #endif
 
 /* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */
 #endif
 
 /* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */
@@ -2252,17 +2283,17 @@ post_handshake_debug(exim_gnutls_state_st * state)
 #ifdef SUPPORT_GNUTLS_SESS_DESC
 debug_printf("%s\n", gnutls_session_get_desc(state->session));
 #endif
 #ifdef SUPPORT_GNUTLS_SESS_DESC
 debug_printf("%s\n", gnutls_session_get_desc(state->session));
 #endif
-#ifdef SUPPORT_GNUTLS_KEYLOG
 
 
+#ifdef SUPPORT_GNUTLS_KEYLOG
 # ifdef EXIM_HAVE_TLS1_3
 if (gnutls_protocol_get_version(state->session) < GNUTLS_TLS1_3)
 # ifdef EXIM_HAVE_TLS1_3
 if (gnutls_protocol_get_version(state->session) < GNUTLS_TLS1_3)
-#else
+# else
 if (TRUE)
 if (TRUE)
-#endif
+# endif
   {
   gnutls_datum_t c, s;
   gstring * gc, * gs;
   {
   gnutls_datum_t c, s;
   gstring * gc, * gs;
-  /* we only want the client random and the master secret */
+  /* For TLS1.2 we only want the client random and the master secret */
   gnutls_session_get_random(state->session, &c, &s);
   gnutls_session_get_master_secret(state->session, &s);
   gc = ddump(&c);
   gnutls_session_get_random(state->session, &c, &s);
   gnutls_session_get_master_secret(state->session, &s);
   gc = ddump(&c);
@@ -2275,7 +2306,8 @@ else
     " add SSLKEYLOGFILE to keep_environment in the exim config\n"
     " run exim as root\n"
     " if using sudo, add SSLKEYLOGFILE to env_keep in /etc/sudoers\n"
     " add SSLKEYLOGFILE to keep_environment in the exim config\n"
     " run exim as root\n"
     " if using sudo, add SSLKEYLOGFILE to env_keep in /etc/sudoers\n"
-    " (works for TLS1.2 also, and saves cut-paste into file)\n");
+    " (works for TLS1.2 also, and saves cut-paste into file)"
+    " Trying to use add_environment for this will not work\n");
 #endif
 }
 
 #endif
 }
 
@@ -2379,9 +2411,20 @@ and sent an SMTP response. */
 
 DEBUG(D_tls) debug_printf("initialising GnuTLS as a server\n");
 
 
 DEBUG(D_tls) debug_printf("initialising GnuTLS as a server\n");
 
-if ((rc = tls_init(NULL, tls_certificate, tls_privatekey,
-    NULL, tls_verify_certificates, tls_crl,
-    require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
+  {
+#ifdef MEASURE_TIMING
+  struct timeval t0;
+  gettimeofday(&t0, NULL);
+#endif
+
+  if ((rc = tls_init(NULL, tls_certificate, tls_privatekey,
+      NULL, tls_verify_certificates, tls_crl,
+      require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
+
+#ifdef MEASURE_TIMING
+  report_time_since(&t0, US"server tls_init (delta)");
+#endif
+  }
 
 #ifdef EXPERIMENTAL_TLS_RESUME
 tls_server_resume_prehandshake(state);
 
 #ifdef EXPERIMENTAL_TLS_RESUME
 tls_server_resume_prehandshake(state);
@@ -2486,6 +2529,11 @@ if (rc != GNUTLS_E_SUCCESS)
   return FAIL;
   }
 
   return FAIL;
   }
 
+#ifdef GNUTLS_SFLAGS_EXT_MASTER_SECRET
+if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET)
+  tls_in.ext_master_secret = TRUE;
+#endif
+
 #ifdef EXPERIMENTAL_TLS_RESUME
 tls_server_resume_posthandshake(state);
 #endif
 #ifdef EXPERIMENTAL_TLS_RESUME
 tls_server_resume_posthandshake(state);
 #endif
@@ -2815,10 +2863,21 @@ if (conn_args->dane && ob->dane_require_tls_ciphers)
 if (!cipher_list)
   cipher_list = ob->tls_require_ciphers;
 
 if (!cipher_list)
   cipher_list = ob->tls_require_ciphers;
 
-if (tls_init(host, ob->tls_certificate, ob->tls_privatekey,
-    ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl,
-    cipher_list, &state, tlsp, errstr) != OK)
-  return FALSE;
+  {
+#ifdef MEASURE_TIMING
+  struct timeval t0;
+  gettimeofday(&t0, NULL);
+#endif
+
+  if (tls_init(host, ob->tls_certificate, ob->tls_privatekey,
+      ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl,
+      cipher_list, &state, tlsp, errstr) != OK)
+    return FALSE;
+
+#ifdef MEASURE_TIMING
+  report_time_since(&t0, US"client tls_init (delta)");
+#endif
+  }
 
   {
   int dh_min_bits = ob->tls_dh_min_bits;
 
   {
   int dh_min_bits = ob->tls_dh_min_bits;
@@ -2944,6 +3003,11 @@ if (!verify_certificate(state, errstr))
   return FALSE;
   }
 
   return FALSE;
   }
 
+#ifdef GNUTLS_SFLAGS_EXT_MASTER_SECRET
+if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET)
+  tlsp->ext_master_secret = TRUE;
+#endif
+
 #ifndef DISABLE_OCSP
 if (request_ocsp)
   {
 #ifndef DISABLE_OCSP
 if (request_ocsp)
   {
@@ -3056,7 +3120,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 */
 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);
 
 
 if (state->xfer_buffer) store_free(state->xfer_buffer);
@@ -3270,6 +3334,9 @@ Arguments:
   len       number of bytes
   more     more data expected soon
 
   len       number of bytes
   more     more data expected soon
 
+Calling with len zero and more unset will flush buffered writes.  The buff
+argument can be null for that case.
+
 Returns:    the number of bytes after a successful write,
             -1 after a failed write
 */
 Returns:    the number of bytes after a successful write,
             -1 after a failed write
 */
@@ -3417,24 +3484,33 @@ gnutls_priority_t priority_cache;
 const char *errpos;
 uschar * dummy_errstr;
 
 const char *errpos;
 uschar * dummy_errstr;
 
-#define validate_check_rc(Label) do { \
+#ifdef GNUTLS_AUTO_GLOBAL_INIT
+# define validate_check_rc(Label) do { \
+  if (rc != GNUTLS_E_SUCCESS) { if (exim_gnutls_base_init_done) \
+    return string_sprintf("%s failed: %s", (Label), gnutls_strerror(rc)); } } while (0)
+# define return_deinit(Label) do { return (Label); } while (0)
+#else
+# define validate_check_rc(Label) do { \
   if (rc != GNUTLS_E_SUCCESS) { if (exim_gnutls_base_init_done) gnutls_global_deinit(); \
   if (rc != GNUTLS_E_SUCCESS) { if (exim_gnutls_base_init_done) gnutls_global_deinit(); \
-  return string_sprintf("%s failed: %s", (Label), gnutls_strerror(rc)); } } while (0)
-#define return_deinit(Label) do { gnutls_global_deinit(); return (Label); } while (0)
+    return string_sprintf("%s failed: %s", (Label), gnutls_strerror(rc)); } } while (0)
+# define return_deinit(Label) do { gnutls_global_deinit(); return (Label); } while (0)
+#endif
 
 if (exim_gnutls_base_init_done)
   log_write(0, LOG_MAIN|LOG_PANIC,
       "already initialised GnuTLS, Exim developer bug");
 
 
 if (exim_gnutls_base_init_done)
   log_write(0, LOG_MAIN|LOG_PANIC,
       "already initialised GnuTLS, Exim developer bug");
 
-#ifdef HAVE_GNUTLS_PKCS11
+#if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL)
 if (!gnutls_allow_auto_pkcs11)
   {
   rc = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
   validate_check_rc(US"gnutls_pkcs11_init");
   }
 #endif
 if (!gnutls_allow_auto_pkcs11)
   {
   rc = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
   validate_check_rc(US"gnutls_pkcs11_init");
   }
 #endif
+#ifndef GNUTLS_AUTO_GLOBAL_INIT
 rc = gnutls_global_init();
 validate_check_rc(US"gnutls_global_init()");
 rc = gnutls_global_init();
 validate_check_rc(US"gnutls_global_init()");
+#endif
 exim_gnutls_base_init_done = TRUE;
 
 if (!(tls_require_ciphers && *tls_require_ciphers))
 exim_gnutls_base_init_done = TRUE;
 
 if (!(tls_require_ciphers && *tls_require_ciphers))
@@ -3457,7 +3533,9 @@ validate_check_rc(string_sprintf(
 
 #undef return_deinit
 #undef validate_check_rc
 
 #undef return_deinit
 #undef validate_check_rc
+#ifndef GNUTLS_AUTO_GLOBAL_INIT
 gnutls_global_deinit();
 gnutls_global_deinit();
+#endif
 
 return NULL;
 }
 
 return NULL;
 }