1 // Copyright 2011 The Chromium Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef BSSL_PKI_PEM_H_ 16 #define BSSL_PKI_PEM_H_ 17 18 #include <stddef.h> 19 20 #include <optional> 21 #include <string> 22 #include <string_view> 23 #include <vector> 24 25 #include <openssl/base.h> 26 #include <openssl/span.h> 27 28 BSSL_NAMESPACE_BEGIN 29 30 // PEMTokenizer is a utility class for the parsing of data encapsulated 31 // using RFC 1421, Privacy Enhancement for Internet Electronic Mail. It 32 // does not implement the full specification, most notably it does not 33 // support the Encapsulated Header Portion described in Section 4.4. 34 class OPENSSL_EXPORT PEMTokenizer { 35 public: 36 // Create a new PEMTokenizer that iterates through |str| searching for 37 // instances of PEM encoded blocks that are of the |allowed_block_types|. 38 // |str| must remain valid for the duration of the PEMTokenizer. 39 PEMTokenizer(std::string_view str, 40 const std::vector<std::string> &allowed_block_types); 41 PEMTokenizer(std::string_view str, 42 bssl::Span<const std::string_view> allowed_block_types); 43 44 PEMTokenizer(const PEMTokenizer &) = delete; 45 PEMTokenizer &operator=(const PEMTokenizer &) = delete; 46 47 ~PEMTokenizer(); 48 49 // Attempts to decode the next PEM block in the string. Returns false if no 50 // PEM blocks can be decoded. The decoded PEM block will be available via 51 // data(). 52 bool GetNext(); 53 54 // Returns the PEM block type (eg: CERTIFICATE) of the last successfully 55 // decoded PEM block. 56 // GetNext() must have returned true before calling this method. block_type()57 const std::string &block_type() const { return block_type_; } 58 59 // Returns the raw, Base64-decoded data of the last successfully decoded 60 // PEM block. 61 // GetNext() must have returned true before calling this method. data()62 const std::string &data() const { return data_; } 63 64 private: 65 void Init(std::string_view str, 66 bssl::Span<const std::string_view> allowed_block_types); 67 68 // A simple cache of the allowed PEM header and footer for a given PEM 69 // block type, so that it is only computed once. 70 struct PEMType; 71 72 // The string to search, which must remain valid for as long as this class 73 // is around. 74 std::string_view str_; 75 76 // The current position within |str_| that searching should begin from, 77 // or std::string_view::npos if iteration is complete 78 std::string_view::size_type pos_; 79 80 // The type of data that was encoded, as indicated in the PEM 81 // Pre-Encapsulation Boundary (eg: CERTIFICATE, PKCS7, or 82 // PRIVACY-ENHANCED MESSAGE). 83 std::string block_type_; 84 85 // The types of PEM blocks that are allowed. PEM blocks that are not of 86 // one of these types will be skipped. 87 std::vector<PEMType> block_types_; 88 89 // The raw (Base64-decoded) data of the last successfully decoded block. 90 std::string data_; 91 }; 92 93 // PEMToken represents a single PEM token. Headers are not stored or supported. 94 struct PEMToken { 95 std::string type; 96 std::string data; 97 }; 98 99 // PEMDecode decodes |data| into a sequence of PEM tokens. Only tokens whose 100 // type appears in |allowed_types| are included in the resulting vector. The 101 // resulting vector may be empty if either there are no valid PEM tokens in the 102 // input, or there are valid tokens but none of them match any of the allowed 103 // types. 104 OPENSSL_EXPORT std::vector<PEMToken> PEMDecode( 105 std::string_view data, bssl::Span<const std::string_view> allowed_types); 106 107 // PEMDecodeSingle decodes |data| into a single PEM token, which must be of the 108 // specified |allowed_type|, and returns that token's base64-decoded body. 109 // Returns nullopt if there is not exactly one token of the allowed type in the 110 // input for any reason. 111 OPENSSL_EXPORT std::optional<std::string> PEMDecodeSingle( 112 std::string_view data, std::string_view allowed_type); 113 114 // PEMEncode encodes |data| in the encapsulated message format described in RFC 115 // 1421, with |type| as the PEM block type (eg: CERTIFICATE). 116 OPENSSL_EXPORT std::string PEMEncode(std::string_view data, 117 const std::string &type); 118 119 BSSL_NAMESPACE_END 120 121 #endif // BSSL_PKI_PEM_H_ 122