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 <Gilles.Peskine@arm.com>
diff --git a/tests/suites/test_suite_base64.data b/tests/suites/test_suite_base64.data
index 3999e73..9488df3 100644
--- a/tests/suites/test_suite_base64.data
+++ b/tests/suites/test_suite_base64.data
@@ -76,6 +76,110 @@
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 1797049..182be29 100644
--- a/tests/suites/test_suite_base64.function
+++ b/tests/suites/test_suite_base64.function
@@ -99,7 +99,18 @@
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,