From 683a46e6c1265e2028212c03d2e4c47602b3297f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 3 Jun 2025 22:01:33 +0200 Subject: [PATCH] mbedtls_base64_decode: assert sloppy behavior with bad number of = Add unit tests covering cases where the number of digits plus equal signs is not a multiple of 4. These are invalid inputs, but they are currently accepted as long as the number of equal signs is at most 2. The tests assert the current behavior, not behavior that is desirable. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_base64.data | 104 ++++++++++++++++++++++++ tests/suites/test_suite_base64.function | 11 +++ 2 files changed, 115 insertions(+) diff --git a/tests/suites/test_suite_base64.data b/tests/suites/test_suite_base64.data index 3999e73bf9..9488df3a21 100644 --- a/tests/suites/test_suite_base64.data +++ b/tests/suites/test_suite_base64.data @@ -76,6 +76,110 @@ mbedtls_base64_decode:"zm=masd":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER Base64 decode (Space inside string) mbedtls_base64_decode:"zm masd":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER +# Validate the weird behavior of mbedtls_base64_decode() on some +# invalid inputs (number of digts + equals not a multiple of 4). +# In the reference output, "!" characters at the end are needed to +# pad the output buffer, but the actual output omits those. E.g. if +# dst_string is "ab!" then mbedtls_base64_decode() reports a 3-byte +# output when dlen < 3, but actually outputs 2 bytes if given a +# buffer of 3 bytes or more. + +Base64 decode: 1 digit, 0 equals (sloppily accepted) +mbedtls_base64_decode:"Y":"!":0 + +Base64 decode: 1 digit, 1 equals (sloppily accepted) +mbedtls_base64_decode:"Y":"!":0 + +Base64 decode: 1 digit, 2 equals (sloppily accepted) +mbedtls_base64_decode:"Y==":"!":0 + +Base64 decode: 1 digit, 3 equals (bad) +mbedtls_base64_decode:"Y===":"!":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 2 digits, 0 equals (sloppily accepted) +mbedtls_base64_decode:"Yw":"!!":0 + +Base64 decode: 2 digits, 1 equals (sloppily accepted) +mbedtls_base64_decode:"Yw=":"!!":0 + +Base64 decode: 2 digits, 2 equals (good) +mbedtls_base64_decode:"Yw==":"c":0 + +Base64 decode: 2 digits, 3 equals (bad) +mbedtls_base64_decode:"Yw===":"c":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 3 digits, 0 equals (sloppily accepted) +mbedtls_base64_decode:"Y28":"!!!":0 + +Base64 decode: 3 digits, 1 equals (good) +mbedtls_base64_decode:"Y28=":"co":0 + +Base64 decode: 3 digits, 2 equals (sloppily accepted) +mbedtls_base64_decode:"Y28==":"co":0 + +Base64 decode: 3 digits, 3 equals (bad) +mbedtls_base64_decode:"Y28===":"co":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 4 digits, 0 equals (good) +mbedtls_base64_decode:"Y29t":"com":0 + +Base64 decode: 4 digits, 1 equals (sloppily accepted) +mbedtls_base64_decode:"Y29t=":"com":0 + +Base64 decode: 4 digits, 2 equals (sloppily accepted) +mbedtls_base64_decode:"Y29t==":"com":0 + +Base64 decode: 4 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29t===":"com":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 5 digits, 0 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tc":"com!":0 + +Base64 decode: 5 digits, 1 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tc=":"com!":0 + +Base64 decode: 5 digits, 2 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tc==":"com!":0 + +Base64 decode: 5 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tc===":"com!":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 6 digits, 0 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tcA":"com!!":0 + +Base64 decode: 6 digits, 1 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tcA=":"com!!":0 + +Base64 decode: 6 digits, 2 equals (good) +mbedtls_base64_decode:"Y29tcA==":"comp":0 + +Base64 decode: 6 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tcA===":"comp":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 7 digits, 0 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tcG8":"com!!!":0 + +Base64 decode: 7 digits, 1 equals (good) +mbedtls_base64_decode:"Y29tcG8=":"compo":0 + +Base64 decode: 7 digits, 2 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tcG8==":"compo":0 + +Base64 decode: 7 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tcG8===":"compo":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 8 digits, 0 equals (good) +mbedtls_base64_decode:"Y29tcG9z":"compos":0 + +Base64 decode: 8 digits, 1 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tcG9z=":"compos":0 + +Base64 decode: 8 digits, 2 equals (sloppily accepted) +mbedtls_base64_decode:"Y29tcG9z==":"compos":0 + +Base64 decode: 8 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tcG9z===":"compos":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + Base64 decode "Zm9vYmFy" (no newline nor '\0' at end) base64_decode_hex_src:"5a6d3976596d4679":"foobar":0 diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function index 1797049a08..182be2916f 100644 --- a/tests/suites/test_suite_base64.function +++ b/tests/suites/test_suite_base64.function @@ -99,7 +99,18 @@ void mbedtls_base64_decode(char *src_string, char *dst_string, int result) TEST_CALLOC(dst, dst_size); + /* Validate broken behavior observed on Mbed TLS 3.6.3: + * some invalid inputs are accepted, and asking for the decoded length + * gives a figure that's longer than the decoded output. + * In the test data, trailing "!" characters in dst_string indicate + * padding that must be present in the output buffer length, but + * will not be present in the actual output when the output buffer + * is large enough. + */ size_t expected_dst_len = correct_dst_len; + while (expected_dst_len > 0 && dst_string[expected_dst_len - 1] == '!') { + --expected_dst_len; + } /* Test normal operation */ TEST_EQUAL(mbedtls_base64_decode(dst, dst_size, &len,