Hi Vincent,

On Sun, Apr 26, 2020 at 10:51:51PM +0200, Vincent Lefevre wrote:
> On 2020-04-26 02:33:00 +0200, Gero Treuner wrote:
> > The MessageId still starts with the time, but is now included in the
> > base64 part, joined with the random section before encoding.
> 
> Why is the time needed? Since you use a CSPRNG, you can just use
> random data for the full local part of the Message-Id.

As no acceptance criterias are defined, "need" still is under
discussion.

With which option do you feel more comfortable (so obviously I made the
choice for myself):

(1) Probability that the same MessageId will be generated is practically
    zero, but a very very small amount above zero.

(2) Probability that the same MessageId will be generated is practically
    zero, but a very very small amount above zero, and starting with the
    next second really is zero (unless somebody intentionally
    replicates a MessageId, which is easy as we know).

Is this the time to start a poll, and also about the length of the
random part?

Also (only) PRNG will still be used where the CSPRNG fails or is not
chosen at compile time. I only can imagine very extraordinary conditions
making the CSPRNG fail - it is a valid question whether it is better to
stop sending a message at this point then.


As I'm writing an email anyway: Attached is a slightly polished version
of the patch.


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..878a487e 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,76 @@ 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_EXTRA_BITS 63
+  #endif
+#elif RAND_MAX/256 >= 0x7FFFFF
+  #define RAND_LEN 4
+  #if RAND_MAX/256 < 0xFFFFFF
+    #define RAND_EXTRA_BITS 31
+  #endif
+#else
+  #define RAND_LEN 2
+  #if RAND_MAX/256 < 0xFF
+    #define RAND_EXTRA_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_EXTRA_BITS
+  long int extra, extra_mask = 0;
+#endif
+
+  assert (len % RAND_LEN == 0);
+
+  while (len >= RAND_LEN)
+  {
+#ifdef RAND_EXTRA_BITS
+    if (extra_mask == 0)
+    {
+      extra = random();
+      extra_mask = 1L << (RAND_EXTRA_BITS - 1);
+    }
+
+    rnd = random() ^ (extra & extra_mask ? (1L << RAND_EXTRA_BITS) : 0);
+    extra_mask >>= 1;
+#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