Hi,

On Wed, Apr 22, 2020 at 09:05:28PM -0400, re...@webconquest.com wrote:
> On Mon, Apr 20, 2020 at 11:18:55AM +0200, Oswald wrote in
[...]
> Thanks, I will incorporate this in the patch!

Here is another patch calling the openssl/gnutls random functions if
compiled with any of those, otherwise or on error resort to random().

The openssl/gnutls functions apparently are quite old, so I don't see
indication for version or configure checking. Nowadays they are
connected to /dev/urandom, wich advertises to "return at most 32 MB" in
the manual. Overall one can assume that entropy is not an issue, as I
didn't hear about making many TLS connections might block because
running out of entropy.

The MessageId still starts with the time, but is now included in the
base64 part, joined with the random section before encoding. A signed
date will fit in 4 bytes until 2106, which leads to a smooth length
without trailing '=' (but the whole thing can be made dynamic if
someone might have concerns).

Within Mutt randomness is also used for email boundaries and names for
temp files, with probably different demands regarding strength - LRAND
resp. lrand64 with fallback to random looks like the performance
choice, but could use fewer calls when aware of RAND_MAX...
Merging with the new code and existing base64.c could be nice.


Gero
diff --git a/mutt_ssl.c b/mutt_ssl.c
index 6978e4e4..89f6a077 100644
--- a/mutt_ssl.c
+++ b/mutt_ssl.c
@@ -1417,3 +1417,15 @@ static int ssl_passwd_cb(char *buf, int size, int 
rwflag, void *userdata)
 
   return snprintf(buf, size, "%s", account->pass);
 }
+
+int mutt_ssl_random(void *buf, size_t buflen)
+{
+  if (ssl_init() == 0)
+  {
+    if (RAND_bytes((unsigned char *)buf, (int)buflen) == 1)
+      return 0;
+    dprint (1, (debugfile, "mutt_ssl_random: Error getting random data, code 
%ld\n",
+                ERR_get_error()));
+  }
+  return -1;
+}
diff --git a/mutt_ssl.h b/mutt_ssl.h
index ad0e74c9..8c8a2e1d 100644
--- a/mutt_ssl.h
+++ b/mutt_ssl.h
@@ -24,6 +24,13 @@
 #if defined(USE_SSL)
 int mutt_ssl_starttls (CONNECTION* conn);
 int mutt_ssl_socket_setup (CONNECTION *conn);
+int mutt_ssl_random (void *buf, size_t buflen);
+#if defined(USE_SSL_OPENSSL)
+#define MUTT_SSL_RANDOM_SUCCESS 1
+#endif
+#if defined(USE_SSL_GNUTLS)
+#define MUTT_SSL_RANDOM_SUCCESS 0
+#endif
 #endif
 
 #endif /* _MUTT_SSL_H_ */
diff --git a/mutt_ssl_gnutls.c b/mutt_ssl_gnutls.c
index 25c6778a..c1f94d4e 100644
--- a/mutt_ssl_gnutls.c
+++ b/mutt_ssl_gnutls.c
@@ -22,6 +22,7 @@
 
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
+#include <gnutls/crypto.h>
 #ifdef HAVE_GNUTLS_OPENSSL_H
 #include <gnutls/openssl.h>
 #endif
@@ -1221,3 +1222,8 @@ static int tls_check_certificate (CONNECTION* conn)
 
   return rc;
 }
+
+int mutt_ssl_random (void *buf, size_t buflen)
+{
+  return gnutls_rnd (GNUTLS_RND_NONCE, buf, buflen);
+}
diff --git a/sendlib.c b/sendlib.c
index cdec5beb..f04cbdff 100644
--- a/sendlib.c
+++ b/sendlib.c
@@ -41,6 +41,9 @@
 #ifdef USE_AUTOCRYPT
 #include "autocrypt.h"
 #endif
+#ifdef USE_SSL
+#include "mutt_ssl.h"
+#endif
 
 #include <string.h>
 #include <stdlib.h>
@@ -79,8 +82,6 @@ const char B64Chars[64] = {
   '8', '9', '+', '/'
 };
 
-static char MsgIdPfx = 'A';
-
 static void transform_to_7bit (BODY *a, FILE *fpin);
 
 static void encode_quoted (FGETCONV * fc, FILE *fout, int istext)
@@ -2398,22 +2399,78 @@ const char *mutt_fqdn(short may_hide_host)
   return p;
 }
 
+#if RAND_MAX/256 >= 0x7FFFFFFFFFFFFF
+  #define RAND_LEN 8
+  #if RAND_MAX/256 < 0xFFFFFFFFFFFFFF
+    #define RAND_SIGNED_BITS 63
+  #endif
+#elif RAND_MAX/256 >= 0x7FFFFF
+  #define RAND_LEN 4
+  #if RAND_MAX/256 <  0xFFFFFF
+    #define RAND_SIGNED_BITS 31
+  #endif
+#else
+  #define RAND_LEN 2
+  #if RAND_MAX/256 <  0xFF
+    #define RAND_SIGNED_BITS 15
+  #endif
+#endif
+
+void mutt_strong_random (unsigned char *buf, size_t len)
+{
+#ifdef USE_SSL
+  if (mutt_ssl_random (buf, len) == MUTT_SSL_RANDOM_SUCCESS)
+    return;
+#endif
+
+  long int rnd;
+#ifdef RAND_SIGNED_BITS
+  long int extra;
+  int extra_len = 0;
+#endif
+
+  assert (len % RAND_LEN == 0);
+
+  while (len >= RAND_LEN)
+  {
+#ifdef RAND_SIGNED_BITS
+    if (extra_len == 0)
+    {
+      extra = random();
+      extra_len = RAND_SIGNED_BITS;
+    }
+
+    rnd = random() ^ (extra & 1 ? ((long int)1 << RAND_SIGNED_BITS) : 0);
+    extra >>= 1;
+    --extra_len;
+#else
+    rnd = random();
+#endif
+
+    len -= RAND_LEN;
+    memcpy (&buf[len], &rnd, RAND_LEN);
+  }
+}
+
+#define MSGID_RANDOM_SIZE 8
+
 char *mutt_gen_msgid (void)
 {
   char buf[SHORT_STRING];
+  unsigned char buf_b64[2 * (sizeof(time_t) + MSGID_RANDOM_SIZE)];
   time_t now;
-  struct tm *tm;
   const char *fqdn;
+  int i;
 
   now = time (NULL);
-  tm = gmtime (&now);
+  for (i = 3; i >= 0; --i, now >>= 8) /* revisit in time before overflow in 
year 2106 */
+    buf[i] = now & 0xff;
+  mutt_strong_random ((unsigned char *) &buf[4], MSGID_RANDOM_SIZE);
+  mutt_to_base64(buf_b64, (unsigned char *) buf, MSGID_RANDOM_SIZE + 4, 
sizeof(buf_b64));
   if (!(fqdn = mutt_fqdn(0)))
     fqdn = NONULL(Hostname);
 
-  snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.G%c%u@%s>",
-           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
-           tm->tm_min, tm->tm_sec, MsgIdPfx, (unsigned int)getpid (), fqdn);
-  MsgIdPfx = (MsgIdPfx == 'Z') ? 'A' : MsgIdPfx + 1;
+  snprintf (buf, sizeof (buf), "<%s@%s>", buf_b64, fqdn);
   return (safe_strdup (buf));
 }
 

Reply via email to