| // Copyright 2010 The Chromium Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "pem.h" |
| |
| #include <array> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| BSSL_NAMESPACE_BEGIN |
| |
| TEST(PEMTokenizerTest, BasicParsing) { |
| const char data[] = |
| "-----BEGIN EXPECTED-BLOCK-----\n" |
| "TWF0Y2hlc0FjY2VwdGVkQmxvY2tUeXBl\n" |
| "-----END EXPECTED-BLOCK-----\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| accepted_types.push_back("EXPECTED-BLOCK"); |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_TRUE(tokenizer.GetNext()); |
| |
| EXPECT_EQ("EXPECTED-BLOCK", tokenizer.block_type()); |
| EXPECT_EQ("MatchesAcceptedBlockType", tokenizer.data()); |
| |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, CarriageReturnLineFeeds) { |
| const char data[] = |
| "-----BEGIN EXPECTED-BLOCK-----\r\n" |
| "TWF0Y2hlc0FjY2VwdGVkQmxvY2tUeXBl\r\n" |
| "-----END EXPECTED-BLOCK-----\r\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| accepted_types.push_back("EXPECTED-BLOCK"); |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_TRUE(tokenizer.GetNext()); |
| |
| EXPECT_EQ("EXPECTED-BLOCK", tokenizer.block_type()); |
| EXPECT_EQ("MatchesAcceptedBlockType", tokenizer.data()); |
| |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, NoAcceptedBlockTypes) { |
| const char data[] = |
| "-----BEGIN UNEXPECTED-BLOCK-----\n" |
| "SWdub3Jlc1JlamVjdGVkQmxvY2tUeXBl\n" |
| "-----END UNEXPECTED-BLOCK-----\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| accepted_types.push_back("EXPECTED-BLOCK"); |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, MultipleAcceptedBlockTypes) { |
| const char data[] = |
| "-----BEGIN BLOCK-ONE-----\n" |
| "RW5jb2RlZERhdGFPbmU=\n" |
| "-----END BLOCK-ONE-----\n" |
| "-----BEGIN BLOCK-TWO-----\n" |
| "RW5jb2RlZERhdGFUd28=\n" |
| "-----END BLOCK-TWO-----\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| accepted_types.push_back("BLOCK-ONE"); |
| accepted_types.push_back("BLOCK-TWO"); |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_TRUE(tokenizer.GetNext()); |
| |
| EXPECT_EQ("BLOCK-ONE", tokenizer.block_type()); |
| EXPECT_EQ("EncodedDataOne", tokenizer.data()); |
| |
| EXPECT_TRUE(tokenizer.GetNext()); |
| |
| EXPECT_EQ("BLOCK-TWO", tokenizer.block_type()); |
| EXPECT_EQ("EncodedDataTwo", tokenizer.data()); |
| |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, MissingFooter) { |
| const char data[] = |
| "-----BEGIN MISSING-FOOTER-----\n" |
| "RW5jb2RlZERhdGFPbmU=\n" |
| "-----END MISSING-FOOTER-----\n" |
| "-----BEGIN MISSING-FOOTER-----\n" |
| "RW5jb2RlZERhdGFUd28=\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| accepted_types.push_back("MISSING-FOOTER"); |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_TRUE(tokenizer.GetNext()); |
| |
| EXPECT_EQ("MISSING-FOOTER", tokenizer.block_type()); |
| EXPECT_EQ("EncodedDataOne", tokenizer.data()); |
| |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, NestedEncoding) { |
| const char data[] = |
| "-----BEGIN BLOCK-ONE-----\n" |
| "RW5jb2RlZERhdGFPbmU=\n" |
| "-----BEGIN BLOCK-TWO-----\n" |
| "RW5jb2RlZERhdGFUd28=\n" |
| "-----END BLOCK-TWO-----\n" |
| "-----END BLOCK-ONE-----\n" |
| "-----BEGIN BLOCK-ONE-----\n" |
| "RW5jb2RlZERhdGFUaHJlZQ==\n" |
| "-----END BLOCK-ONE-----\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| accepted_types.push_back("BLOCK-ONE"); |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_TRUE(tokenizer.GetNext()); |
| |
| EXPECT_EQ("BLOCK-ONE", tokenizer.block_type()); |
| EXPECT_EQ("EncodedDataThree", tokenizer.data()); |
| |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, EmptyAcceptedTypes) { |
| const char data[] = |
| "-----BEGIN BLOCK-ONE-----\n" |
| "RW5jb2RlZERhdGFPbmU=\n" |
| "-----END BLOCK-ONE-----\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, BlockWithHeader) { |
| const char data[] = |
| "-----BEGIN BLOCK-ONE-----\n" |
| "Header-One: Data data data\n" |
| "Header-Two: \n" |
| " continuation\n" |
| "Header-Three: Mix-And,Match\n" |
| "\n" |
| "RW5jb2RlZERhdGFPbmU=\n" |
| "-----END BLOCK-ONE-----\n" |
| "-----BEGIN BLOCK-ONE-----\n" |
| "RW5jb2RlZERhdGFUd28=\n" |
| "-----END BLOCK-ONE-----\n"; |
| std::string_view string_piece(data); |
| std::vector<std::string> accepted_types; |
| accepted_types.push_back("BLOCK-ONE"); |
| |
| PEMTokenizer tokenizer(string_piece, accepted_types); |
| EXPECT_TRUE(tokenizer.GetNext()); |
| |
| EXPECT_EQ("BLOCK-ONE", tokenizer.block_type()); |
| EXPECT_EQ("EncodedDataTwo", tokenizer.data()); |
| |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMTokenizerTest, SpanConstructor) { |
| const std::string_view data = |
| "-----BEGIN EXPECTED-BLOCK-----\n" |
| "U3BhbkNvbnN0cnVjdG9y\n" |
| "-----END EXPECTED-BLOCK-----\n"; |
| const std::array<std::string_view, 1> accepted_types = { "EXPECTED-BLOCK" }; |
| PEMTokenizer tokenizer(data, bssl::Span(accepted_types)); |
| EXPECT_TRUE(tokenizer.GetNext()); |
| EXPECT_EQ("EXPECTED-BLOCK", tokenizer.block_type()); |
| EXPECT_EQ("SpanConstructor", tokenizer.data()); |
| |
| EXPECT_FALSE(tokenizer.GetNext()); |
| } |
| |
| TEST(PEMDecodeTest, BasicSingle) { |
| const std::string_view data = |
| "-----BEGIN SINGLE-----\n" |
| "YmxvY2sgYm9keQ==" |
| "-----END SINGLE-----\n" |
| "-----BEGIN WRONG-----\n" |
| "d3JvbmcgYmxvY2sgYm9keQ==" |
| "-----END WRONG-----\n"; |
| std::optional<std::string> result = PEMDecodeSingle(data, "SINGLE"); |
| ASSERT_TRUE(result); |
| EXPECT_EQ(*result, "block body"); |
| } |
| |
| TEST(PEMDecodeTest, BasicMulti) { |
| const std::string_view data = |
| "-----BEGIN MULTI-1-----\n" |
| "YmxvY2sgYm9keSAx" |
| "-----END MULTI-1-----\n" |
| "-----BEGIN WRONG-----\n" |
| "d3JvbmcgYmxvY2sgYm9keQ==" |
| "-----END WRONG-----\n" |
| "-----BEGIN MULTI-2-----\n" |
| "YmxvY2sgYm9keSAy" |
| "-----END MULTI-2-----\n"; |
| const std::array<std::string_view, 2> accepted_types = {"MULTI-1", "MULTI-2"}; |
| std::vector<PEMToken> result = PEMDecode(data, accepted_types); |
| EXPECT_EQ(result.size(), 2u); |
| EXPECT_EQ(result[0].type, "MULTI-1"); |
| EXPECT_EQ(result[0].data, "block body 1"); |
| EXPECT_EQ(result[1].type, "MULTI-2"); |
| EXPECT_EQ(result[1].data, "block body 2"); |
| } |
| |
| TEST(PEMDecodeTest, TypeMismatchSingle) { |
| const std::string_view data = |
| "-----BEGIN WRONG-----\n" |
| "d3JvbmcgYmxvY2sgYm9keQ==" |
| "-----END WRONG-----\n"; |
| std::optional<std::string> result = PEMDecodeSingle(data, "SINGLE"); |
| EXPECT_FALSE(result); |
| } |
| |
| TEST(PEMDecodeTest, TooManySingle) { |
| const std::string_view data = |
| "-----BEGIN SINGLE-----\n" |
| "YmV0dGVyIG5vdCBzZWUgdGhpcw==" |
| "-----END SINGLE-----\n" |
| "-----BEGIN SINGLE-----\n" |
| "b3IgdGhpcw==" |
| "-----END SINGLE-----\n"; |
| std::optional<std::string> result = PEMDecodeSingle(data, "SINGLE"); |
| EXPECT_FALSE(result); |
| } |
| |
| TEST(PEMEncodeTest, Basic) { |
| EXPECT_EQ( |
| "-----BEGIN BLOCK-ONE-----\n" |
| "RW5jb2RlZERhdGFPbmU=\n" |
| "-----END BLOCK-ONE-----\n", |
| PEMEncode("EncodedDataOne", "BLOCK-ONE")); |
| EXPECT_EQ( |
| "-----BEGIN BLOCK-TWO-----\n" |
| "RW5jb2RlZERhdGFUd28=\n" |
| "-----END BLOCK-TWO-----\n", |
| PEMEncode("EncodedDataTwo", "BLOCK-TWO")); |
| } |
| |
| TEST(PEMEncodeTest, Empty) { |
| EXPECT_EQ( |
| "-----BEGIN EMPTY-----\n" |
| "-----END EMPTY-----\n", |
| PEMEncode("", "EMPTY")); |
| } |
| |
| TEST(PEMEncodeTest, Wrapping) { |
| EXPECT_EQ( |
| "-----BEGIN SINGLE LINE-----\n" |
| "MTIzNDU2Nzg5MGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM\n" |
| "-----END SINGLE LINE-----\n", |
| PEMEncode("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL", |
| "SINGLE LINE")); |
| |
| EXPECT_EQ( |
| "-----BEGIN WRAPPED LINE-----\n" |
| "MTIzNDU2Nzg5MGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM\nTQ==\n" |
| "-----END WRAPPED LINE-----\n", |
| PEMEncode("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM", |
| "WRAPPED LINE")); |
| } |
| |
| BSSL_NAMESPACE_END |