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"
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.
27 if (!reader
.ReadByte(&tag_byte
))
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
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
37 if ((tag_byte
& kTagNumberMask
) == 31)
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
))
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;
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
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.
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.
75 for (size_t i
= 0; i
< length_len
; i
++) {
76 if (!reader
.ReadByte(&length_byte
))
78 // A first length byte of all zeroes means the length was not encoded in
80 if (i
== 0 && length_byte
== 0)
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.
92 if (!reader
.ReadBytes(value_len
, out
))
94 advance_mark_
= reader
.NewMark();
99 bool Parser::Advance() {
100 if (advance_mark_
.IsEmpty())
102 if (!input_
.AdvanceToMark(advance_mark_
))
104 advance_mark_
= Mark::NullMark();
108 bool Parser::HasMore() {
109 return input_
.HasMore();
112 bool Parser::ReadRawTLV(Input
* out
) {
115 if (!PeekTagAndValue(&tag
, &value
))
117 if (!input_
.ReadToMark(advance_mark_
, out
))
119 advance_mark_
= Mark::NullMark();
124 bool Parser::ReadTagAndValue(Tag
* tag
, Input
* out
) {
125 if (!PeekTagAndValue(tag
, out
))
131 bool Parser::ReadOptionalTag(Tag tag
, Input
* out
, bool* present
) {
139 if (!PeekTagAndValue(&read_tag
, &value
))
142 if (read_tag
== tag
) {
147 advance_mark_
= Mark::NullMark();
152 bool Parser::SkipOptionalTag(Tag tag
, bool* present
) {
154 return ReadOptionalTag(tag
, &out
, present
);
157 bool Parser::ReadTag(Tag tag
, Input
* out
) {
159 return ReadOptionalTag(tag
, out
, &present
) && present
;
162 bool Parser::SkipTag(Tag tag
) {
164 return ReadTag(tag
, &out
);
167 // Type-specific variants of ReadTag
169 bool Parser::ReadConstructed(Tag tag
, Parser
* out
) {
170 if (!IsConstructed(tag
))
173 if (!ReadTag(tag
, &data
))
179 bool Parser::ReadSequence(Parser
* out
) {
180 return ReadConstructed(kSequence
, out
);
183 bool Parser::ReadUint64(uint64_t* out
) {
185 if (!ReadTag(kInteger
, &encodedInt
))
187 return ParseUint64(encodedInt
, out
);