Delete unused downloads page asset.
[chromium-blink-merge.git] / net / der / parser.cc
blob6419549cf044998e362503b0b8b0300afc3343f5
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()) {
17 Parser::Parser(const Input& input)
18 : input_(input), advance_mark_(Mark::NullMark()) {
21 bool Parser::PeekTagAndValue(Tag* tag, Input* out) {
22 ByteReader reader = input_;
24 // Don't support tags > 30.
25 uint8_t tag_byte;
26 if (!reader.ReadByte(&tag_byte))
27 return false;
29 // ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a
30 // tag number no greater than 30. This parser only supports tag numbers up
31 // to 30.
32 // If the tag number is 31 (0x1F, the largest value that fits in the allotted
33 // bytes), then the tag is more than one byte long and the continuation bytes
34 // contain the real tag number. We only support tag numbers < 31 (and thus
35 // single-byte tags).
36 if ((tag_byte & kTagNumberMask) == 31)
37 return false;
39 // Parse length. The format for the length encoding is specified in
40 // ITU-T X.690 section 8.1.3.
41 size_t value_len = 0; // Number of bytes used to encode just the value.
43 uint8_t length_first_byte;
44 if (!reader.ReadByte(&length_first_byte))
45 return false;
46 if ((length_first_byte & 0x80) == 0) {
47 // Short form for length - it's only one byte long.
48 value_len = length_first_byte & 0x7f;
49 } else {
50 // Long form for length - it's encoded across multiple bytes.
51 if (length_first_byte == 0xff) {
52 // ITU-T X.690 clause 8.1.3.5.c specifies the value 0xff shall not be
53 // used.
54 return false;
56 // The high bit indicated that this is the long form, while the next 7 bits
57 // encode the number of subsequent octets used to encode the length
58 // (ITU-T X.690 clause 8.1.3.5.b).
59 size_t length_len = length_first_byte & 0x7f;
60 if (length_len == 0) {
61 // ITU-T X.690 section 10.1 (DER length forms) requires encoding the
62 // length with the minimum number of octets. Besides, it makes no sense
63 // for the length to be encoded in 0 octets.
64 return false;
66 if (length_len > sizeof(value_len)) {
67 // The length is encoded in multiple octets, with the first octet
68 // indicating how many octets follow. Those octets need to be combined
69 // to form a size_t, so the number of octets to follow (length_len)
70 // must be small enough so that they fit in a size_t.
71 return false;
73 uint8_t length_byte;
74 for (size_t i = 0; i < length_len; i++) {
75 if (!reader.ReadByte(&length_byte))
76 return false;
77 // A first length byte of all zeroes means the length was not encoded in
78 // minimum length.
79 if (i == 0 && length_byte == 0)
80 return false;
81 value_len <<= 8;
82 value_len += length_byte;
84 if (value_len < 0x80) {
85 // If value_len is < 0x80, then it could have been encoded in a single
86 // byte, meaning it was not encoded in minimum length.
87 return false;
91 if (!reader.ReadBytes(value_len, out))
92 return false;
93 advance_mark_ = reader.NewMark();
94 *tag = tag_byte;
95 return true;
98 bool Parser::Advance() {
99 if (advance_mark_.IsEmpty())
100 return false;
101 if (!input_.AdvanceToMark(advance_mark_))
102 return false;
103 advance_mark_ = Mark::NullMark();
104 return true;
107 bool Parser::HasMore() {
108 return input_.HasMore();
111 bool Parser::ReadRawTLV(Input* out) {
112 Tag tag;
113 Input value;
114 if (!PeekTagAndValue(&tag, &value))
115 return false;
116 if (!input_.ReadToMark(advance_mark_, out))
117 return false;
118 advance_mark_ = Mark::NullMark();
120 return true;
123 bool Parser::ReadTagAndValue(Tag* tag, Input* out) {
124 if (!PeekTagAndValue(tag, out))
125 return false;
126 CHECK(Advance());
127 return true;
130 bool Parser::ReadOptionalTag(Tag tag, Input* out, bool* present) {
131 if (!HasMore()) {
132 *present = false;
133 return true;
136 Tag read_tag;
137 Input value;
138 if (!PeekTagAndValue(&read_tag, &value))
139 return false;
140 *present = false;
141 if (read_tag == tag) {
142 *present = true;
143 *out = value;
144 CHECK(Advance());
145 } else {
146 advance_mark_ = Mark::NullMark();
148 return true;
151 bool Parser::SkipOptionalTag(Tag tag, bool* present) {
152 Input out;
153 return ReadOptionalTag(tag, &out, present);
156 bool Parser::ReadTag(Tag tag, Input* out) {
157 bool present;
158 return ReadOptionalTag(tag, out, &present) && present;
161 bool Parser::SkipTag(Tag tag) {
162 Input out;
163 return ReadTag(tag, &out);
166 // Type-specific variants of ReadTag
168 bool Parser::ReadConstructed(Tag tag, Parser* out) {
169 if (!IsConstructed(tag))
170 return false;
171 Input data;
172 if (!ReadTag(tag, &data))
173 return false;
174 *out = Parser(data);
175 return true;
178 bool Parser::ReadSequence(Parser* out) {
179 return ReadConstructed(kSequence, out);
182 bool Parser::ReadUint64(uint64_t* out) {
183 Input encoded_int;
184 if (!ReadTag(kInteger, &encoded_int))
185 return false;
186 return ParseUint64(encoded_int, out);
189 bool Parser::ReadBitString(BitString* bit_string) {
190 Input value;
191 if (!ReadTag(kBitString, &value))
192 return false;
193 return ParseBitString(value, bit_string);
196 } // namespace der
198 } // namespace net