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));
}