Re: [PATCH 0/2] Use base64 URL safe alphabet for message id generation.
On Sat, Mar 04, 2023 at 06:33:33PM +0100, Sebastian Andrzej Siewior wrote: #2 of this mini series uses the safe dictionary for base64 encoding to use for message-id generation. This bothered me for a while and then I stumbled uppon issie #400 so it appears to not be just me. #1 is rather unimportant but allows to decode this safe URL base64 encoded strings if ever needed. Thank you Sebastian, and again my apologies to everyone for basically ignoring #400. These patches look okay to me. I've made a couple small indentation and spacing fixes to be in line with Mutt code, but otherwise they seem fine. I'll take another look tomorrow and if I still don't see any issues will push to stable for a (well overdue) 2.2.10 release in the next week or so. -- Kevin J. McCarthy GPG Fingerprint: 8975 A9B3 3AA3 7910 385C 5308 ADEF 7684 8031 6BDA signature.asc Description: PGP signature
[PATCH 2/2] Use base64 URL safe alphabet for message id generation.
The character '/' from base64 alphabet breaks web redirectors if the message-id from an email is used as part of the URL for redirectors and/ or automatic pointers to an email. Use the URL safe alphabet from RFC4648 section 5 for message id generation. Signed-off-by: Sebastian Andrzej Siewior --- base64.c| 33 +++-- messageid.c | 4 ++-- mime.h | 1 + protos.h| 1 + sendlib.c | 9 + 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/base64.c b/base64.c index 290f384e16957..cc7106f4358b2 100644 --- a/base64.c +++ b/base64.c @@ -56,16 +56,15 @@ void mutt_buffer_to_base64 (BUFFER *out, const unsigned char *in, size_t len) mutt_buffer_fix_dptr (out); } -/* raw bytes to null-terminated base 64 string */ -void mutt_to_base64 (unsigned char *out, const unsigned char *in, size_t len, -size_t olen) +static void to_base64 (unsigned char *out, const unsigned char *in, size_t len, +size_t olen, const char *dict) { while (len >= 3 && olen > 4) { -*out++ = B64Chars[in[0] >> 2]; -*out++ = B64Chars[((in[0] << 4) & 0x30) | (in[1] >> 4)]; -*out++ = B64Chars[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; -*out++ = B64Chars[in[2] & 0x3f]; +*out++ = dict[in[0] >> 2]; +*out++ = dict[((in[0] << 4) & 0x30) | (in[1] >> 4)]; +*out++ = dict[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; +*out++ = dict[in[2] & 0x3f]; olen -= 4; len -= 3; in+= 3; @@ -76,15 +75,29 @@ void mutt_to_base64 (unsigned char *out, const unsigned char *in, size_t len, { unsigned char fragment; -*out++ = B64Chars[in[0] >> 2]; +*out++ = dict[in[0] >> 2]; fragment = (in[0] << 4) & 0x30; if (len > 1) fragment |= in[1] >> 4; -*out++ = B64Chars[fragment]; -*out++ = (len < 2) ? '=' : B64Chars[(in[1] << 2) & 0x3c]; +*out++ = dict[fragment]; +*out++ = (len < 2) ? '=' : dict[(in[1] << 2) & 0x3c]; *out++ = '='; } *out = '\0'; + +} + +/* raw bytes to null-terminated base 64 string */ +void mutt_to_base64 (unsigned char *out, const unsigned char *in, size_t len, +size_t olen) +{ + to_base64(out, in, len, olen, B64Chars); +} + +void mutt_to_base64_safeurl (unsigned char *out, const unsigned char *in, +size_t len, size_t olen) +{ + to_base64(out, in, len, olen, B64Chars_urlsafe); } int mutt_buffer_from_base64 (BUFFER *out, const char *in) diff --git a/messageid.c b/messageid.c index e4ac441002626..d96a5d4467102 100644 --- a/messageid.c +++ b/messageid.c @@ -49,7 +49,7 @@ static const char *id_format_str (char *dest, size_t destlen, size_t col, { case 'r': mutt_random_bytes ((char *)r_raw, sizeof(r_raw)); - mutt_to_base64 (r_out, r_raw, sizeof(r_raw), sizeof(r_out)); + mutt_to_base64_safeurl (r_out, r_raw, sizeof(r_raw), sizeof(r_out)); mutt_format_s (dest, destlen, fmt, (const char *)r_out); break; @@ -65,7 +65,7 @@ static const char *id_format_str (char *dest, size_t destlen, size_t col, for (int i = 0; i < 4; i++) z_raw[i] = (uint8_t) (id_data->now >> (3-i)*8u); mutt_random_bytes ((char *)z_raw + 4, sizeof(z_raw) - 4); - mutt_to_base64 (z_out, z_raw, sizeof(z_raw), sizeof(z_out)); + mutt_to_base64_safeurl (z_out, z_raw, sizeof(z_raw), sizeof(z_out)); mutt_format_s (dest, destlen, fmt, (const char *)z_out); break; diff --git a/mime.h b/mime.h index c162ee2b5a2b6..1a876ae27749c 100644 --- a/mime.h +++ b/mime.h @@ -63,6 +63,7 @@ enum extern const int Index_hex[]; extern const int Index_64[]; extern const char B64Chars[]; +extern const char B64Chars_urlsafe[]; #endif #define hexval(c) Index_hex[(unsigned int)(c)] diff --git a/protos.h b/protos.h index a055d1a2ca266..d760c7d137ed5 100644 --- a/protos.h +++ b/protos.h @@ -432,6 +432,7 @@ int safe_symlink (const char *, const char *); /* base64.c */ void mutt_to_base64 (unsigned char*, const unsigned char*, size_t, size_t); +void mutt_to_base64_safeurl (unsigned char*, const unsigned char*, size_t, size_t); int mutt_from_base64 (char*, const char*, size_t); void mutt_buffer_to_base64 (BUFFER *, const unsigned char *, size_t); int mutt_buffer_from_base64 (BUFFER *, const char *); diff --git a/sendlib.c b/sendlib.c index d9429c2e62629..c2283972f1d33 100644 --- a/sendlib.c +++ b/sendlib.c @@ -84,6 +84,15 @@ const char B64Chars[64] = { '8', '9', '+', '/' }; +/* RFC4648 section 5 Base 64 Encoding with URL and Filename Safe Alphabet */ +const char B64Chars_urlsafe[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '-', '_' +}; + static void transform_to_7bit
[PATCH 1/2] base64val: Add support to decode base64 safe URL.
In the base64 safe URL dictionary the characters '+' and '/' are replaced by '-' and '_'. Add the characters to Index_64 to allow decoding if needed. Signed-off-by: Sebastian Andrzej Siewior --- handler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handler.c b/handler.c index 697c87e2b0992..cedf352ae1e5b 100644 --- a/handler.c +++ b/handler.c @@ -58,10 +58,10 @@ const int Index_hex[128] = { const int Index_64[128] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,62,-1,63, 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, - 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,63, -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; -- 2.39.2
[PATCH 0/2] Use base64 URL safe alphabet for message id generation.
Hi, #2 of this mini series uses the safe dictionary for base64 encoding to use for message-id generation. This bothered me for a while and then I stumbled uppon issie #400 so it appears to not be just me. #1 is rather unimportant but allows to decode this safe URL base64 encoded strings if ever needed. Sebastian