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