1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_DER_PARSER_H_
#define NET_DER_PARSER_H_
#include <stdint.h>
#include "net/base/net_export.h"
#include "net/der/input.h"
#include "net/der/tag.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
namespace net::der {
class BitString;
struct GeneralizedTime;
// Parses a DER-encoded ASN.1 structure. DER (distinguished encoding rules)
// encodes each data value with a tag, length, and value (TLV). The tag
// indicates the type of the ASN.1 value. Depending on the type of the value,
// it could contain arbitrary bytes, so the length of the value is encoded
// after the tag and before the value to indicate how many bytes of value
// follow. DER also defines how the values are encoded for particular types.
//
// This Parser places a few restrictions on the DER encoding it can parse. The
// largest restriction is that it only supports tags which have a tag number
// no greater than 30 - these are the tags that fit in a single octet. The
// second restriction is that the maximum length for a value that can be parsed
// is 4GB. Both of these restrictions should be fine for any reasonable input.
//
// The Parser class is mainly focused on parsing the TLV structure of DER
// encoding, and does not directly handle parsing primitive values (other
// functions in the net::der namespace are provided for this.) When a Parser
// is created, it is passed in a reference to the encoded data. Because the
// encoded data is not owned by the Parser, the data cannot change during the
// lifespan of the Parser. The Parser functions by keeping a pointer to the
// current TLV which starts at the beginning of the input and advancing through
// the input as each TLV is read. As such, a Parser instance is thread-unsafe.
//
// Most methods for using the Parser write the current tag and/or value to
// the output parameters provided and then advance the input to the next TLV.
// None of the methods explicitly expose the length because it is part of the
// value. All methods return a boolean indicating whether there was a parsing
// error with the current TLV.
//
// Some methods are provided in the Parser class as convenience to both read
// the current TLV from the input and also parse the DER encoded value,
// converting it to a corresponding C++ type. These methods simply combine
// ReadTag() with the appropriate ParseType() free function.
//
// The design of DER encoding allows for nested data structures with
// constructed values, where the value is a series of TLVs. The Parser class
// is not designed to traverse through a nested encoding from a single object,
// but it does facilitate parsing nested data structures through the
// convenience methods ReadSequence() and the more general ReadConstructed(),
// which provide the user with another Parser object to traverse the next
// level of TLVs.
//
// For a brief example of how to use the Parser, suppose we have the following
// ASN.1 type definition:
//
// Foo ::= SEQUENCE {
// bar OCTET STRING OPTIONAL,
// quux OCTET STRING }
//
// If we have a DER-encoded Foo in an Input |encoded_value|, the
// following code shows an example of how to parse the quux field from the
// encoded data.
//
// bool ReadQuux(const Input& encoded_value, Input* quux_out) {
// Parser parser(encoded_value);
// Parser foo_parser;
// if (!parser.ReadSequence(&foo_parser))
// return false;
// if (!foo_parser->SkipOptionalTag(kOctetString))
// return false;
// if (!foo_parser->ReadTag(kOctetString, quux_out))
// return false;
// return true;
// }
class NET_EXPORT Parser {
public:
// Default constructor; equivalent to calling Parser(Input()). This only
// exists so that a Parser can be stack allocated and passed in to
// ReadConstructed() and similar methods.
Parser();
// Creates a parser to parse over the data represented by input. This class
// assumes that the underlying data will not change over the lifetime of
// the Parser object.
explicit Parser(const Input& input);
Parser(const Parser&) = default;
Parser& operator=(const Parser&) = default;
// Returns whether there is any more data left in the input to parse. This
// does not guarantee that the data is parseable.
bool HasMore();
// Reads the current TLV from the input and advances. If the tag or length
// encoding for the current value is invalid, this method returns false and
// does not advance the input. Otherwise, it returns true, putting the
// read tag in |tag| and the value in |out|.
[[nodiscard]] bool ReadTagAndValue(Tag* tag, Input* out);
// Reads the current TLV from the input and advances. Unlike ReadTagAndValue
// where only the value is put in |out|, this puts the raw bytes from the
// tag, length, and value in |out|.
[[nodiscard]] bool ReadRawTLV(Input* out);
// Basic methods for reading or skipping the current TLV, with an
// expectation of what the current tag should be. It should be possible
// to parse any structure with these 4 methods; convenience methods are also
// provided to make some cases easier.
// If the current tag in the input is |tag|, it puts the corresponding value
// in |out| and advances the input to the next TLV. If the current tag is
// something else, then |out| is set to nullopt and the input is not
// advanced. Like ReadTagAndValue, it returns false if the encoding is
// invalid and does not advance the input.
[[nodiscard]] bool ReadOptionalTag(Tag tag, absl::optional<Input>* out);
// If the current tag in the input is |tag|, it puts the corresponding value
// in |out|, sets |was_present| to true, and advances the input to the next
// TLV. If the current tag is something else, then |was_present| is set to
// false and the input is not advanced. Like ReadTagAndValue, it returns
// false if the encoding is invalid and does not advance the input.
// DEPRECATED: use the absl::optional version above in new code.
// TODO(mattm): convert the existing callers and remove this override.
[[nodiscard]] bool ReadOptionalTag(Tag tag, Input* out, bool* was_present);
// Like ReadOptionalTag, but the value is discarded.
[[nodiscard]] bool SkipOptionalTag(Tag tag, bool* was_present);
// If the current tag matches |tag|, it puts the current value in |out|,
// advances the input, and returns true. Otherwise, it returns false.
[[nodiscard]] bool ReadTag(Tag tag, Input* out);
// Advances the input and returns true if the current tag matches |tag|;
// otherwise it returns false.
[[nodiscard]] bool SkipTag(Tag tag);
// Convenience methods to combine parsing the TLV with parsing the DER
// encoding for a specific type.
// Reads the current TLV from the input, checks that the tag matches |tag|
// and is a constructed tag, and creates a new Parser from the value.
[[nodiscard]] bool ReadConstructed(Tag tag, Parser* out);
// A more specific form of ReadConstructed that expects the current tag
// to be 0x30 (SEQUENCE).
[[nodiscard]] bool ReadSequence(Parser* out);
// Expects the current tag to be kInteger, and calls ParseUint8 on the
// current value. Note that DER-encoded integers are arbitrary precision,
// so this method will fail for valid input that represents an integer
// outside the range of an uint8_t.
//
// Note that on failure the Parser is left in an undefined state (the
// input may or may not have been advanced).
[[nodiscard]] bool ReadUint8(uint8_t* out);
// Expects the current tag to be kInteger, and calls ParseUint64 on the
// current value. Note that DER-encoded integers are arbitrary precision,
// so this method will fail for valid input that represents an integer
// outside the range of an uint64_t.
//
// Note that on failure the Parser is left in an undefined state (the
// input may or may not have been advanced).
[[nodiscard]] bool ReadUint64(uint64_t* out);
// Reads a BIT STRING. On success returns BitString. On failure, returns
// absl::nullopt.
//
// Note that on failure the Parser is left in an undefined state (the
// input may or may not have been advanced).
[[nodiscard]] absl::optional<BitString> ReadBitString();
// Reads a GeneralizeTime. On success fills |out| and returns true.
//
// Note that on failure the Parser is left in an undefined state (the
// input may or may not have been advanced).
[[nodiscard]] bool ReadGeneralizedTime(GeneralizedTime* out);
// Lower level methods. The previous methods couple reading data from the
// input with advancing the Parser's internal pointer to the next TLV; these
// lower level methods decouple those two steps into methods that read from
// the current TLV and a method that advances the internal pointer to the
// next TLV.
// Reads the current TLV from the input, putting the tag in |tag| and the raw
// value in |out|, but does not advance the input. Returns true if the tag
// and length are successfully read and the output exists.
[[nodiscard]] bool PeekTagAndValue(Tag* tag, Input* out);
// Advances the input to the next TLV. This method only needs to be called
// after PeekTagAndValue; all other methods will advance the input if they
// read something.
bool Advance();
private:
CBS cbs_;
size_t advance_len_ = 0;
};
} // namespace net::der
#endif // NET_DER_PARSER_H_
|