summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
eae0036)
gnutls_sec_param_to_pk_bits() and gnutls_rnd() are both new as of
GnuTLS 2.12.x. Guard their usage on 2.12.0+ at compile time.
In older versions, the vaguely_random_number() function just immediately
calls the fallback, so it's the same as before this change (just one
extra indirection in the code-path).
Define a constant of 1024 for dh-bits for use in those old releases
where GnuTLS won't tell us how many we should use.
Change the on-disk filename for generated D-H params again, replacing
the -normal with -<bitcount>, so that it's 1024 or whatever, and as
the value changes, Exim will automatically start using the new value.
on how Exim was built; the values are not suitable for keying material.
If Exim is linked against OpenSSL then RAND_pseudo_bytes() is used.
.new
on how Exim was built; the values are not suitable for keying material.
If Exim is linked against OpenSSL then RAND_pseudo_bytes() is used.
.new
-if Exim is linked against GnuTLS then gnutls_rnd(GNUTLS_RND_NONCE) is used.
+If Exim is linked against GnuTLS then gnutls_rnd(GNUTLS_RND_NONCE) is used,
+for versions of GnuTLS with that function.
.wen
Otherwise, the implementation may be arc4random(), random() seeded by
srandomdev() or srandom(), or a custom implementation even weaker than
.wen
Otherwise, the implementation may be arc4random(), random() seeded by
srandomdev() or srandom(), or a custom implementation even weaker than
GnuTLS uses D-H parameters that may take a substantial amount of time
to compute. It is unreasonable to re-compute them for every TLS session.
Therefore, Exim keeps this data in a file in its spool directory, called
GnuTLS uses D-H parameters that may take a substantial amount of time
to compute. It is unreasonable to re-compute them for every TLS session.
Therefore, Exim keeps this data in a file in its spool directory, called
-&_gnutls-params-normal_&.
+&_gnutls-params-NNNN_& for some value of NNNN, corresponding to the number
+of bits requested.
The file is owned by the Exim user and is readable only by
its owner. Every Exim process that start up GnuTLS reads the D-H
parameters from this file. If the file does not exist, the first Exim process
The file is owned by the Exim user and is readable only by
its owner. Every Exim process that start up GnuTLS reads the D-H
parameters from this file. If the file does not exist, the first Exim process
a substantial amount of time, causing timeouts on incoming connections.
The solution is to generate the parameters externally to Exim. They are stored
a substantial amount of time, causing timeouts on incoming connections.
The solution is to generate the parameters externally to Exim. They are stored
-in &_gnutls-params-normal_& in PEM format, which means that they can be
+in &_gnutls-params-N_& in PEM format, which means that they can be
generated externally using the &(certtool)& command that is part of GnuTLS.
To replace the parameters with new ones, instead of deleting the file
generated externally using the &(certtool)& command that is part of GnuTLS.
To replace the parameters with new ones, instead of deleting the file
&(certtool)& and, when this has been done, replace Exim's cache file by
renaming. The relevant commands are something like this:
.code
&(certtool)& and, when this has been done, replace Exim's cache file by
renaming. The relevant commands are something like this:
.code
+# ls
+[ look for file; assume gnutls-params-1024 is the most recent ]
# rm -f new-params
# touch new-params
# chown exim:exim new-params
# chmod 0600 new-params
# rm -f new-params
# touch new-params
# chown exim:exim new-params
# chmod 0600 new-params
-# certtool --generate-dh-params >>new-params
+# certtool --generate-dh-params --bits 1024 >>new-params
-# mv new-params gnutls-params-normal
+# mv new-params gnutls-params-1024
.endd
If Exim never has to generate the parameters itself, the possibility of
stalling is removed.
.endd
If Exim never has to generate the parameters itself, the possibility of
stalling is removed.
-The filename changed in Exim 4.78, to gain the -normal suffix, corresponding
-to the GnuTLS constant &`GNUTLS_SEC_PARAM_NORMAL`&, defining the number of
-bits to include. At time of writing, NORMAL corresponds to 2432 bits for D-H.
+The filename changed in Exim 4.78, to gain the -bits suffix. The value which
+Exim will choose depends upon the version of GnuTLS in use. For older GnuTLS,
+the value remains hard-coded in Exim as 1024. As of GnuTLS 2.12.x, there is
+a way for Exim to ask for the "normal" number of bits for D-H public-key usage,
+and Exim does so. Exim thus removes itself from the policy decision, and the
+filename and bits used change as the GnuTLS maintainers change the value for
+their parameter &`GNUTLS_SEC_PARAM_NORMAL`&. At the time of writing, this
+gives 2432 bits.
gnutls_priority_init, ignoring Exim options gnutls_require_kx,
gnutls_require_mac & gnutls_require_protocols (no longer supported).
Added SNI support via GnuTLS too.
gnutls_priority_init, ignoring Exim options gnutls_require_kx,
gnutls_require_mac & gnutls_require_protocols (no longer supported).
Added SNI support via GnuTLS too.
+ Made ${randint:..} supplier available, if using not-too-old GnuTLS.
PP/26 Added EXPERIMENTAL_OCSP for OpenSSL.
PP/26 Added EXPERIMENTAL_OCSP for OpenSSL.
SNI support has been added to Exim's GnuTLS integration too.
SNI support has been added to Exim's GnuTLS integration too.
+ For sufficiently recent GnuTLS libraries, ${randint:..} will now use
+ gnutls_rnd(), asking for GNUTLS_RND_NONCE level randomness.
+
12. With OpenSSL, if built with EXPERIMENTAL_OCSP, a new option tls_ocsp_file
is now available. If the contents of the file are valid, then Exim will
send that back in response to a TLS status request; this is OCSP Stapling.
12. With OpenSSL, if built with EXPERIMENTAL_OCSP, a new option tls_ocsp_file
is now available. If the contents of the file are valid, then Exim will
send that back in response to a TLS status request; this is OCSP Stapling.
static BOOL exim_gnutls_base_init_done = FALSE;
static BOOL exim_gnutls_base_init_done = FALSE;
-/* ------------------------------------------------------------------------ */
-/* Callback declarations */
-
-static void exim_gnutls_logger_cb(int level, const char *message);
-static int exim_sni_handling_cb(gnutls_session_t session);
-
/* ------------------------------------------------------------------------ */
/* macros */
/* ------------------------------------------------------------------------ */
/* macros */
#define EXIM_CLIENT_DH_MIN_BITS 1024
#define EXIM_CLIENT_DH_MIN_BITS 1024
+/* With GnuTLS 2.12.x+ we have gnutls_sec_param_to_pk_bits() with which we
+can ask for a bit-strength. Without that, we stick to the constant we had
+before, for now. */
+#define EXIM_SERVER_DH_BITS_PRE2_12 1024
+
#define exim_gnutls_err_check(Label) do { \
if (rc != GNUTLS_E_SUCCESS) { return tls_error((Label), gnutls_strerror(rc), host); } } while (0)
#define exim_gnutls_err_check(Label) do { \
if (rc != GNUTLS_E_SUCCESS) { return tls_error((Label), gnutls_strerror(rc), host); } } while (0)
#if GNUTLS_VERSION_NUMBER >= 0x020c00
#define HAVE_GNUTLS_SESSION_CHANNEL_BINDING
#if GNUTLS_VERSION_NUMBER >= 0x020c00
#define HAVE_GNUTLS_SESSION_CHANNEL_BINDING
+#define HAVE_GNUTLS_SEC_PARAM_CONSTANTS
+#define HAVE_GNUTLS_RND
+
+
+
+/* ------------------------------------------------------------------------ */
+/* Callback declarations */
+
+#if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0
+static void exim_gnutls_logger_cb(int level, const char *message);
+#endif
+
+static int exim_sni_handling_cb(gnutls_session_t session);
+
+
+
+
/* ------------------------------------------------------------------------ */
/* Static functions */
/* ------------------------------------------------------------------------ */
/* Static functions */
uschar filename[PATH_MAX];
size_t sz;
host_item *host = NULL; /* dummy for macros */
uschar filename[PATH_MAX];
size_t sz;
host_item *host = NULL; /* dummy for macros */
-const char * const dh_param_fn_ext = "normal"; /* change as dh_bits changes */
DEBUG(D_tls) debug_printf("Initialising GnuTLS server params.\n");
rc = gnutls_dh_params_init(&dh_server_params);
exim_gnutls_err_check(US"gnutls_dh_params_init");
DEBUG(D_tls) debug_printf("Initialising GnuTLS server params.\n");
rc = gnutls_dh_params_init(&dh_server_params);
exim_gnutls_err_check(US"gnutls_dh_params_init");
-/* If you change this, also change dh_param_fn_ext so that we can use a
+#ifdef HAVE_GNUTLS_SEC_PARAM_CONSTANTS
+/* If you change this constant, also change dh_param_fn_ext so that we can use a
different filename and ensure we have sufficient bits. */
dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL);
if (!dh_bits)
return tls_error(US"gnutls_sec_param_to_pk_bits() failed", NULL, NULL);
different filename and ensure we have sufficient bits. */
dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL);
if (!dh_bits)
return tls_error(US"gnutls_sec_param_to_pk_bits() failed", NULL, NULL);
+DEBUG(D_tls)
+ debug_printf("GnuTLS tells us that for D-H PL, NORMAL is %d bits.\n",
+ dh_bits);
+#else
+dh_bits = EXIM_SERVER_DH_BITS_PRE2_12;
+DEBUG(D_tls)
+ debug_printf("GnuTLS lacks gnutls_sec_param_to_pk_bits(), using %d bits.\n",
+ dh_bits);
+#endif
if (!string_format(filename, sizeof(filename),
if (!string_format(filename, sizeof(filename),
- "%s/gnutls-params-%s", spool_directory, dh_param_fn_ext))
+ "%s/gnutls-params-%d", spool_directory, dh_bits))
return tls_error(US"overlong filename", NULL, NULL);
/* Open the cache file for reading and if successful, read it and set up the
return tls_error(US"overlong filename", NULL, NULL);
/* Open the cache file for reading and if successful, read it and set up the
* gnutls_global_set_log_function()
* gnutls_global_set_log_level() 0..9
*/
* gnutls_global_set_log_function()
* gnutls_global_set_log_level() 0..9
*/
+#if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0
static void
exim_gnutls_logger_cb(int level, const char *message)
{
DEBUG(D_tls) debug_printf("GnuTLS<%d>: %s\n", level, message);
}
static void
exim_gnutls_logger_cb(int level, const char *message)
{
DEBUG(D_tls) debug_printf("GnuTLS<%d>: %s\n", level, message);
}
/* Called after client hello, should handle SNI work.
/* Called after client hello, should handle SNI work.
Returns a random number in range [0, max-1]
*/
Returns a random number in range [0, max-1]
*/
int
vaguely_random_number(int max)
{
int
vaguely_random_number(int max)
{
* smooth distribution and cares enough then they should submit a patch then. */
return r % max;
}
* smooth distribution and cares enough then they should submit a patch then. */
return r % max;
}
+#else /* HAVE_GNUTLS_RND */
+int
+vaguely_random_number(int max)
+{
+ return vaguely_random_number_fallback(max);
+}
+#endif /* HAVE_GNUTLS_RND */