summaryrefslogtreecommitdiffstats
path: root/net/der/parser.h
blob: d18728e1858acfbb1af093a116dd8d401f6a45f6 (plain)
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
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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 "base/compiler_specific.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
#include "net/der/input.h"
#include "net/der/tag.h"

namespace net {

namespace 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);

  // 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|.
  bool ReadTagAndValue(Tag* tag, Input* out) WARN_UNUSED_RESULT;

  // 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|.
  bool ReadRawTLV(Input* out) WARN_UNUSED_RESULT;

  // 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|, 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.
  bool ReadOptionalTag(Tag tag,
                       Input* out,
                       bool* was_present) WARN_UNUSED_RESULT;

  // Like ReadOptionalTag, but the value is discarded.
  bool SkipOptionalTag(Tag tag, bool* was_present) WARN_UNUSED_RESULT;

  // If the current tag matches |tag|, it puts the current value in |out|,
  // advances the input, and returns true. Otherwise, it returns false.
  bool ReadTag(Tag tag, Input* out) WARN_UNUSED_RESULT;

  // Advances the input and returns true if the current tag matches |tag|;
  // otherwise it returns false.
  bool SkipTag(Tag tag) WARN_UNUSED_RESULT;

  // 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.
  bool ReadConstructed(Tag tag, Parser* out) WARN_UNUSED_RESULT;

  // A more specific form of ReadConstructed that expects the current tag
  // to be 0x30 (SEQUENCE).
  bool ReadSequence(Parser* out) WARN_UNUSED_RESULT;

  // 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).
  bool ReadUint8(uint8_t* out) WARN_UNUSED_RESULT;

  // 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).
  bool ReadUint64(uint64_t* out) WARN_UNUSED_RESULT;

  // Reads a BIT STRING. 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).
  bool ReadBitString(BitString* out) WARN_UNUSED_RESULT;

  // 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).
  bool ReadGeneralizedTime(GeneralizedTime* out) WARN_UNUSED_RESULT;

  // 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.
  bool PeekTagAndValue(Tag* tag, Input* out) WARN_UNUSED_RESULT;

  // 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:
  ByteReader input_;
  Mark advance_mark_;

  DISALLOW_COPY(Parser);
};

}  // namespace der

}  // namespace net

#endif  // NET_DER_PARSER_H_