1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Copyright (c) 2014, Google Inc. 2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Permission to use, copy, modify, and/or distribute this software for any 4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * purpose with or without fee is hereby granted, provided that the above 5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * copyright notice and this permission notice appear in all copies. 6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <stdio.h> 16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <string.h> 17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 18d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin#include <string> 19d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin#include <vector> 20d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 21572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan#include <gtest/gtest.h> 22572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 23d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/base64.h> 24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/crypto.h> 25d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/err.h> 26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 27f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include "../internal.h" 28572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan#include "../test/test_util.h" 29f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin 30d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 31d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjaminenum encoding_relation { 32d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // canonical indicates that the encoding is the expected encoding of the 33d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // input. 34d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin canonical, 35d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // valid indicates that the encoding is /a/ valid encoding of the input, but 36d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // need not be the canonical one. 37d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin valid, 38d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // invalid indicates that the encoded data is valid. 39d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin invalid, 40d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin}; 41d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 42e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystruct TestVector { 43d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin enum encoding_relation relation; 44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const char *decoded; 45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const char *encoded; 46e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley}; 47d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 48e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// Test vectors from RFC 4648. 49e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic const TestVector kTestVectors[] = { 50d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "", ""}, 51d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "f", "Zg==\n"}, 52d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "fo", "Zm8=\n"}, 53d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "foo", "Zm9v\n"}, 54d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "foob", "Zm9vYg==\n"}, 55d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "fooba", "Zm9vYmE=\n"}, 56d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "foobar", "Zm9vYmFy\n"}, 57d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {valid, "foobar", "Zm9vYmFy\n\n"}, 58d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {valid, "foobar", " Zm9vYmFy\n\n"}, 59d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {valid, "foobar", " Z m 9 v Y m F y\n\n"}, 60d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "Zm9vYmFy=\n"}, 61d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "Zm9vYmFy==\n"}, 62d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "Zm9vYmFy===\n"}, 63d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "Z"}, 64d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "Z\n"}, 65d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "ab!c"}, 66d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "ab=c"}, 67d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "abc"}, 68d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 69d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 70d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n"}, 71d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 72d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n"}, 73d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 74d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n"}, 75d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", 76d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n==\n"}, 77d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 78d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh" 79d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "4eHh4eHh4\n"}, 80d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {canonical, 81d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 82d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh" 83d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "4eHh4eHh4eHh4eA==\n"}, 84d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 85d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh" 86d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "4eHh4eHh4eHh4eA==\n"}, 87d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 88d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e" 89d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "Hh4eHh4eHh4eA==\n"}, 90d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", 91d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==" 92d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "\neHh4eHh4eHh4eHh4eHh4eHh4\n"}, 93d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 94d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // A '-' has traditionally been treated as the end of the data by OpenSSL 95d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // and anything following would be ignored. BoringSSL does not accept this 96d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // non-standard extension. 97d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "Zm9vYmFy-anythinggoes"}, 98d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", "Zm9vYmFy\n-anythinggoes"}, 99d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 100d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin // CVE-2015-0292 101d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin {invalid, "", 102d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "ZW5jb2RlIG1lCg===========================================================" 103d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin "=======\n"}, 104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}; 105d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 106572a4e2e687520da9e518528d7371b794b1decc0Robert Sloanclass Base64Test : public testing::TestWithParam<TestVector> {}; 107572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 108572a4e2e687520da9e518528d7371b794b1decc0Robert SloanINSTANTIATE_TEST_CASE_P(, Base64Test, testing::ValuesIn(kTestVectors)); 109d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 110d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin// RemoveNewlines returns a copy of |in| with all '\n' characters removed. 111d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjaminstatic std::string RemoveNewlines(const char *in) { 112d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin std::string ret; 113d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin const size_t in_len = strlen(in); 114d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 1157c0d06c221ce9edf44bbf978b909b38a0aee2084David Benjamin for (size_t i = 0; i < in_len; i++) { 116d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin if (in[i] != '\n') { 117d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin ret.push_back(in[i]); 118d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin } 119d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin } 120d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 121d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin return ret; 122d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin} 123d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 124572a4e2e687520da9e518528d7371b794b1decc0Robert SloanTEST_P(Base64Test, EncodeBlock) { 125572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const TestVector &t = GetParam(); 126572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (t.relation != canonical) { 127572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan return; 128d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 129d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 130572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const size_t decoded_len = strlen(t.decoded); 131572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t max_encoded_len; 132572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len)); 133d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 134572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::vector<uint8_t> out_vec(max_encoded_len); 135572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan uint8_t *out = out_vec.data(); 136572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t len = EVP_EncodeBlock(out, (const uint8_t *)t.decoded, decoded_len); 137d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 138572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::string encoded(RemoveNewlines(t.encoded)); 139572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_EQ(Bytes(encoded), Bytes(out, len)); 140572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan} 141d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 142572a4e2e687520da9e518528d7371b794b1decc0Robert SloanTEST_P(Base64Test, DecodeBase64) { 143572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const TestVector &t = GetParam(); 144572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (t.relation == valid) { 145572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan // The non-canonical encodings will generally have odd whitespace etc 146572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan // that |EVP_DecodeBase64| will reject. 147572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan return; 148572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan } 149d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 150572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const std::string encoded(RemoveNewlines(t.encoded)); 151572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::vector<uint8_t> out_vec(encoded.size()); 152572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan uint8_t *out = out_vec.data(); 153d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 154572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t len; 155572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int ok = EVP_DecodeBase64(out, &len, out_vec.size(), 156572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan (const uint8_t *)encoded.data(), encoded.size()); 157572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 158572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (t.relation == invalid) { 159572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_FALSE(ok); 160572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan } else if (t.relation == canonical) { 161572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ASSERT_TRUE(ok); 162572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_EQ(Bytes(t.decoded), Bytes(out, len)); 163d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin } 164d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin} 165d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 166572a4e2e687520da9e518528d7371b794b1decc0Robert SloanTEST_P(Base64Test, DecodeBlock) { 167572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const TestVector &t = GetParam(); 168572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (t.relation != canonical) { 169572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan return; 170572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan } 171d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 172572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::string encoded(RemoveNewlines(t.encoded)); 173d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 174572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::vector<uint8_t> out_vec(encoded.size()); 175572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan uint8_t *out = out_vec.data(); 176d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 177572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan // Test that the padding behavior of the deprecated API is preserved. 178572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int ret = 179572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_DecodeBlock(out, (const uint8_t *)encoded.data(), encoded.size()); 180572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ASSERT_GE(ret, 0); 181572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan // EVP_DecodeBlock should ignore padding. 182572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ASSERT_EQ(0, ret % 3); 183572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t expected_len = strlen(t.decoded); 184572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (expected_len % 3 != 0) { 185572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ret -= 3 - (expected_len % 3); 186d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 187572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_EQ(Bytes(t.decoded), Bytes(out, static_cast<size_t>(ret))); 188d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin} 189d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 190572a4e2e687520da9e518528d7371b794b1decc0Robert SloanTEST_P(Base64Test, EncodeDecode) { 191572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const TestVector &t = GetParam(); 192d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 193572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_ENCODE_CTX ctx; 194572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const size_t decoded_len = strlen(t.decoded); 195d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 196572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (t.relation == canonical) { 197572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t max_encoded_len; 198572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len)); 199d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 200572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan // EVP_EncodeUpdate will output new lines every 64 bytes of output so we 201572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan // need slightly more than |EVP_EncodedLength| returns. */ 202572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan max_encoded_len += (max_encoded_len + 63) >> 6; 203572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::vector<uint8_t> out_vec(max_encoded_len); 204572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan uint8_t *out = out_vec.data(); 205d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 206572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_EncodeInit(&ctx); 207d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 208572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int out_len; 209572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_EncodeUpdate(&ctx, out, &out_len, 210572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan reinterpret_cast<const uint8_t *>(t.decoded), 211572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan decoded_len); 212572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t total = out_len; 213d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 214572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_EncodeFinal(&ctx, out + total, &out_len); 215572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan total += out_len; 216d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 217572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_EQ(Bytes(t.encoded), Bytes(out, total)); 218572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan } 219d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 220572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::vector<uint8_t> out_vec(strlen(t.encoded)); 221572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan uint8_t *out = out_vec.data(); 222572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 223572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_DecodeInit(&ctx); 224572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int out_len; 225572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t total = 0; 226572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int ret = EVP_DecodeUpdate(&ctx, out, &out_len, 227572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan reinterpret_cast<const uint8_t *>(t.encoded), 228572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan strlen(t.encoded)); 229572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (ret != -1) { 230572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan total = out_len; 231572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ret = EVP_DecodeFinal(&ctx, out + total, &out_len); 232572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan total += out_len; 233572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan } 234d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 235572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan switch (t.relation) { 236572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan case canonical: 237572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan case valid: 238572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ASSERT_NE(-1, ret); 239572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_EQ(Bytes(t.decoded), Bytes(out, total)); 240572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan break; 241d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 242572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan case invalid: 243572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_EQ(-1, ret); 244572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan break; 245d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 246d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin} 247d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 248572a4e2e687520da9e518528d7371b794b1decc0Robert SloanTEST_P(Base64Test, DecodeUpdateStreaming) { 249572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const TestVector &t = GetParam(); 250572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (t.relation == invalid) { 251572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan return; 252572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan } 253d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 254572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan const size_t encoded_len = strlen(t.encoded); 255d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 256572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan std::vector<uint8_t> out(encoded_len); 257572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 258572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan for (size_t chunk_size = 1; chunk_size <= encoded_len; chunk_size++) { 259572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan SCOPED_TRACE(chunk_size); 260572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t out_len = 0; 261572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_ENCODE_CTX ctx; 262572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EVP_DecodeInit(&ctx); 263572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 264572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan for (size_t i = 0; i < encoded_len;) { 265572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan size_t todo = encoded_len - i; 266572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (todo > chunk_size) { 267572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan todo = chunk_size; 268d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin } 269d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin 270572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int bytes_written; 271572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int ret = EVP_DecodeUpdate( 272572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan &ctx, out.data() + out_len, &bytes_written, 273572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan reinterpret_cast<const uint8_t *>(t.encoded + i), todo); 274572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan i += todo; 275572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 276572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan switch (ret) { 277572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan case -1: 278572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan FAIL() << "EVP_DecodeUpdate failed"; 279572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan case 0: 280572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan out_len += bytes_written; 281572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan if (i == encoded_len || 282572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan (i + 1 == encoded_len && t.encoded[i] == '\n') || 283572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan /* If there was an '-' in the input (which means “EOF”) then 284572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan * this loop will continue to test that |EVP_DecodeUpdate| will 285572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan * ignore the remainder of the input. */ 286572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan strchr(t.encoded, '-') != nullptr) { 287572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan break; 288572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan } 289572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan 290572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan FAIL() 291572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan << "EVP_DecodeUpdate returned zero before end of encoded data."; 292572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan case 1: 293572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan out_len += bytes_written; 294572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan break; 295572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan default: 296572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan FAIL() << "Invalid return value " << ret; 297d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin } 298d316cba52b5aeac660e03068e65dd873669ce1dbDavid Benjamin } 299d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 300572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int bytes_written; 301572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written); 302572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan ASSERT_NE(ret, -1); 303572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan out_len += bytes_written; 304d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 305572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan EXPECT_EQ(Bytes(t.decoded), Bytes(out.data(), out_len)); 306d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 307d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 308