diff --git a/src/crypto/base64/base64.c b/src/crypto/base64/base64.c index 666f83269..26ad9749a 100644 --- a/src/crypto/base64/base64.c +++ b/src/crypto/base64/base64.c @@ -307,6 +307,10 @@ static int base64_decode_quad(uint8_t *out, size_t *out_num_bytes, (in[2] == '=') << 1 | (in[3] == '='); + // In presence of padding, the lowest bits of v are unused. Canonical encoding + // (RFC 4648, section 3.5) requires that these bits all be set to zero. Common + // PEM parsers accept noncanonical base64, adding to the malleability of the + // format. This decoder follows OpenSSL's and Go's PEM parsers and accepts it. switch (padding_pattern) { case 0: // The common case of no padding. diff --git a/src/crypto/base64/base64_test.cc b/src/crypto/base64/base64_test.cc index 6484dc6a8..f24660566 100644 --- a/src/crypto/base64/base64_test.cc +++ b/src/crypto/base64/base64_test.cc @@ -45,8 +45,8 @@ struct Base64TestVector { const char *encoded; }; -// Test vectors from RFC 4648. static const Base64TestVector kTestVectors[] = { + // Test vectors from RFC 4648, section 10. {canonical, "", ""}, {canonical, "f", "Zg==\n"}, {canonical, "fo", "Zm8=\n"}, @@ -54,12 +54,31 @@ static const Base64TestVector kTestVectors[] = { {canonical, "foob", "Zm9vYg==\n"}, {canonical, "fooba", "Zm9vYmE=\n"}, {canonical, "foobar", "Zm9vYmFy\n"}, - {valid, "foobar", "Zm9vYmFy\n\n"}, - {valid, "foobar", " Zm9vYmFy\n\n"}, - {valid, "foobar", " Z m 9 v Y m F y\n\n"}, + {invalid, "", "Zm9vYmFy=\n"}, {invalid, "", "Zm9vYmFy==\n"}, {invalid, "", "Zm9vYmFy===\n"}, + + // valid non-canonical encodings due to arbitrary whitespace + {valid, "foobar", "Zm9vYmFy\n\n"}, + {valid, "foobar", " Zm9vYmFy\n\n"}, + {valid, "foobar", " Z m 9 v Y m F y\n\n"}, + {valid, "foobar", "Zm9vYmFy\r\n"}, + + // The following "valid" encodings are arguably invalid, but they are + // commonly accepted by parsers, in particular by OpenSSL. + {valid, "v", "dv==\n"}, + {canonical, "w", "dw==\n"}, + {valid, "w", "dx==\n"}, + {valid, "w", "d+==\n"}, + {valid, "w", "d/==\n"}, + {invalid, "", "d===\n"}, + {canonical, "w`", "d2A=\n"}, + {valid, "w`", "d2B=\n"}, + {valid, "w`", "d2C=\n"}, + {valid, "w`", "d2D=\n"}, + {canonical, "wa", "d2E=\n"}, + {invalid, "", "Z"}, {invalid, "", "Z\n"}, {invalid, "", "ab!c"},