diff --git a/libluna/src/Base64.cpp b/libluna/src/Base64.cpp index 7af1b0e5..a40add49 100644 --- a/libluna/src/Base64.cpp +++ b/libluna/src/Base64.cpp @@ -97,11 +97,23 @@ namespace Base64 char* padding = strchr(data.chars(), '='); if (padding) { + padding++; // If the string ends with padding, it must be either one or two equals signs. - if (padding[1] != '=' && padding[1] != '\0') return err(EINVAL); - if (padding[1]) + if (*padding != '=' && *padding != '\0') return err(EINVAL); + + if (*padding) padding++; + + // After that, only thing allowed is newline (and garbage characters if those are permitted) + while (*padding) { - if (padding[strspn(&padding[2], "\n") + 2]) return err(EINVAL); + char c = *padding; + padding++; + + if (c == '\n') continue; + + if (_isalnum(c) || c == '+' || c == '/' || c == '=') return err(EINVAL); + + if (!allow_garbage_chars) return err(EINVAL); } } diff --git a/tests/libluna/TestBase64.cpp b/tests/libluna/TestBase64.cpp index 3cea7307..e9b526af 100644 --- a/tests/libluna/TestBase64.cpp +++ b/tests/libluna/TestBase64.cpp @@ -130,6 +130,22 @@ TestResult test_base64_skip_garbage_chars_if_allowed() test_success; } +TestResult test_base64_skip_garbage_chars_if_allowed_after_padding() +{ + auto rc = Base64::decode_string("YWJjZA==\n?-"_sv, true); + if (rc.has_error()) + { + validate(rc.error() != EINVAL); + return rc.release_error(); + } + + auto decoded = rc.release_value(); + + validate(decoded.view() == "abcd"_sv); + + test_success; +} + Result test_main() { test_prelude; @@ -144,6 +160,7 @@ Result test_main() run_test(test_base64_disallow_characters_after_padding); run_test(test_base64_disallow_garbage_chars_by_default); run_test(test_base64_skip_garbage_chars_if_allowed); + run_test(test_base64_skip_garbage_chars_if_allowed_after_padding); return {}; }