Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / net / der / parser.cc
blob7263fbaeac18f28220c0626a11336df2a26438b2
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/logging.h"
6 #include "base/numerics/safe_math.h"
7 #include "net/der/parse_values.h"
8 #include "net/der/parser.h"
10 namespace net {
12 namespace der {
14 Parser::Parser() : input_(Input()), advance_mark_(Mark::NullMark()) {
16 Parser::Parser(const Input& input)
17 : input_(input), advance_mark_(Mark::NullMark()) {
20 // Reads the next TLV from the input and writes the tag and value to the
21 // output parameters |tag| and |out|.
22 bool Parser::PeekTagAndValue(Tag* tag, Input* out) {
23 ByteReader reader = input_;
25 // Don't support tags > 30.
26 uint8_t tag_byte;
27 if (!reader.ReadByte(&tag_byte))
28 return false;
30 // ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a
31 // tag number no greater than 30. This parser only supports tag numbers up
32 // to 30.
33 // If the tag number is 31 (0x1F, the largest value that fits in the allotted
34 // bytes), then the tag is more than one byte long and the continuation bytes
35 // contain the real tag number. We only support tag numbers < 31 (and thus
36 // single-byte tags).
37 if ((tag_byte & kTagNumberMask) == 31)
38 return false;
40 // Parse length. The format for the length encoding is specified in
41 // ITU-T X.690 section 8.1.3.
42 size_t value_len = 0; // Number of bytes used to encode just the value.
44 uint8_t length_first_byte;
45 if (!reader.ReadByte(&length_first_byte))
46 return false;
47 if ((length_first_byte & 0x80) == 0) {
48 // Short form for length - it's only one byte long.
49 value_len = length_first_byte & 0x7f;
50 } else {
51 // Long form for length - it's encoded across multiple bytes.
52 if (length_first_byte == 0xff) {
53 // ITU-T X.690 clause 8.1.3.5.c specifies the value 0xff shall not be
54 // used.
55 return false;
57 // The high bit indicated that this is the long form, while the next 7 bits
58 // encode the number of subsequent octets used to encode the length
59 // (ITU-T X.690 clause 8.1.3.5.b).
60 size_t length_len = length_first_byte & 0x7f;
61 if (length_len == 0) {
62 // ITU-T X.690 section 10.1 (DER length forms) requires encoding the
63 // length with the minimum number of octets. Besides, it makes no sense
64 // for the length to be encoded in 0 octets.
65 return false;
67 if (length_len > sizeof(value_len)) {
68 // The length is encoded in multiple octets, with the first octet
69 // indicating how many octets follow. Those octets need to be combined
70 // to form a size_t, so the number of octets to follow (length_len)
71 // must be small enough so that they fit in a size_t.
72 return false;
74 uint8_t length_byte;
75 for (size_t i = 0; i < length_len; i++) {
76 if (!reader.ReadByte(&length_byte))
77 return false;
78 // A first length byte of all zeroes means the length was not encoded in
79 // minimum length.
80 if (i == 0 && length_byte == 0)
81 return false;
82 value_len <<= 8;
83 value_len += length_byte;
85 if (value_len < 0x80) {
86 // If value_len is < 0x80, then it could have been encoded in a single
87 // byte, meaning it was not encoded in minimum length.
88 return false;
92 if (!reader.ReadBytes(value_len, out))
93 return false;
94 advance_mark_ = reader.NewMark();
95 *tag = tag_byte;
96 return true;
99 bool Parser::Advance() {
100 if (advance_mark_.IsEmpty())
101 return false;
102 if (!input_.AdvanceToMark(advance_mark_))
103 return false;
104 advance_mark_ = Mark::NullMark();
105 return true;
108 bool Parser::HasMore() {
109 return input_.HasMore();
112 bool Parser::ReadRawTLV(Input* out) {
113 Tag tag;
114 Input value;
115 if (!PeekTagAndValue(&tag, &value))
116 return false;
117 if (!input_.ReadToMark(advance_mark_, out))
118 return false;
119 advance_mark_ = Mark::NullMark();
121 return true;
124 bool Parser::ReadTagAndValue(Tag* tag, Input* out) {
125 if (!PeekTagAndValue(tag, out))
126 return false;
127 CHECK(Advance());
128 return true;
131 bool Parser::ReadOptionalTag(Tag tag, Input* out, bool* present) {
132 if (!HasMore()) {
133 *present = false;
134 return true;
137 Tag read_tag;
138 Input value;
139 if (!PeekTagAndValue(&read_tag, &value))
140 return false;
141 *present = false;
142 if (read_tag == tag) {
143 *present = true;
144 *out = value;
145 CHECK(Advance());
146 } else {
147 advance_mark_ = Mark::NullMark();
149 return true;
152 bool Parser::SkipOptionalTag(Tag tag, bool* present) {
153 Input out;
154 return ReadOptionalTag(tag, &out, present);
157 bool Parser::ReadTag(Tag tag, Input* out) {
158 bool present;
159 return ReadOptionalTag(tag, out, &present) && present;
162 bool Parser::SkipTag(Tag tag) {
163 Input out;
164 return ReadTag(tag, &out);
167 // Type-specific variants of ReadTag
169 bool Parser::ReadConstructed(Tag tag, Parser* out) {
170 if (!IsConstructed(tag))
171 return false;
172 Input data;
173 if (!ReadTag(tag, &data))
174 return false;
175 *out = Parser(data);
176 return true;
179 bool Parser::ReadSequence(Parser* out) {
180 return ReadConstructed(kSequence, out);
183 bool Parser::ReadUint64(uint64_t* out) {
184 Input encodedInt;
185 if (!ReadTag(kInteger, &encodedInt))
186 return false;
187 return ParseUint64(encodedInt, out);
190 } // namespace der
192 } // namespace net