blob: 907cf3c898b35853f2ae27d1e5d2883a4d03764b [file] [log] [blame]
Bob Beckbc97b7a2023-04-18 08:35:15 -06001// Copyright 2015 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "parser.h"
6
7#include "fillins/check.h"
8#include "parse_values.h"
9
10namespace bssl::der {
11
12Parser::Parser() {
13 CBS_init(&cbs_, nullptr, 0);
14}
15
16Parser::Parser(const Input& input) {
17 CBS_init(&cbs_, input.UnsafeData(), input.Length());
18}
19
20bool Parser::PeekTagAndValue(Tag* tag, Input* out) {
21 CBS peeker = cbs_;
22 CBS tmp_out;
23 size_t header_len;
24 unsigned tag_value;
25 if (!CBS_get_any_asn1_element(&peeker, &tmp_out, &tag_value, &header_len) ||
26 !CBS_skip(&tmp_out, header_len)) {
27 return false;
28 }
29 advance_len_ = CBS_len(&tmp_out) + header_len;
30 *tag = tag_value;
31 *out = Input(CBS_data(&tmp_out), CBS_len(&tmp_out));
32 return true;
33}
34
35bool Parser::Advance() {
36 if (advance_len_ == 0)
37 return false;
38 bool ret = !!CBS_skip(&cbs_, advance_len_);
39 advance_len_ = 0;
40 return ret;
41}
42
43bool Parser::HasMore() {
44 return CBS_len(&cbs_) > 0;
45}
46
47bool Parser::ReadRawTLV(Input* out) {
48 CBS tmp_out;
49 if (!CBS_get_any_asn1_element(&cbs_, &tmp_out, nullptr, nullptr))
50 return false;
51 *out = Input(CBS_data(&tmp_out), CBS_len(&tmp_out));
52 return true;
53}
54
55bool Parser::ReadTagAndValue(Tag* tag, Input* out) {
56 if (!PeekTagAndValue(tag, out))
57 return false;
58 CHECK(Advance());
59 return true;
60}
61
62bool Parser::ReadOptionalTag(Tag tag, std::optional<Input>* out) {
63 if (!HasMore()) {
64 *out = std::nullopt;
65 return true;
66 }
67 Tag actual_tag;
68 Input value;
69 if (!PeekTagAndValue(&actual_tag, &value)) {
70 return false;
71 }
72 if (actual_tag == tag) {
73 CHECK(Advance());
74 *out = value;
75 } else {
76 advance_len_ = 0;
77 *out = std::nullopt;
78 }
79 return true;
80}
81
82bool Parser::ReadOptionalTag(Tag tag, Input* out, bool* present) {
83 std::optional<Input> tmp_out;
84 if (!ReadOptionalTag(tag, &tmp_out))
85 return false;
86 *present = tmp_out.has_value();
87 *out = tmp_out.value_or(der::Input());
88 return true;
89}
90
91bool Parser::SkipOptionalTag(Tag tag, bool* present) {
92 Input out;
93 return ReadOptionalTag(tag, &out, present);
94}
95
96bool Parser::ReadTag(Tag tag, Input* out) {
97 Tag actual_tag;
98 Input value;
99 if (!PeekTagAndValue(&actual_tag, &value) || actual_tag != tag) {
100 return false;
101 }
102 CHECK(Advance());
103 *out = value;
104 return true;
105}
106
107bool Parser::SkipTag(Tag tag) {
108 Input out;
109 return ReadTag(tag, &out);
110}
111
112// Type-specific variants of ReadTag
113
114bool Parser::ReadConstructed(Tag tag, Parser* out) {
115 if (!IsConstructed(tag))
116 return false;
117 Input data;
118 if (!ReadTag(tag, &data))
119 return false;
120 *out = Parser(data);
121 return true;
122}
123
124bool Parser::ReadSequence(Parser* out) {
125 return ReadConstructed(kSequence, out);
126}
127
128bool Parser::ReadUint8(uint8_t* out) {
129 Input encoded_int;
130 if (!ReadTag(kInteger, &encoded_int))
131 return false;
132 return ParseUint8(encoded_int, out);
133}
134
135bool Parser::ReadUint64(uint64_t* out) {
136 Input encoded_int;
137 if (!ReadTag(kInteger, &encoded_int))
138 return false;
139 return ParseUint64(encoded_int, out);
140}
141
142std::optional<BitString> Parser::ReadBitString() {
143 Input value;
144 if (!ReadTag(kBitString, &value))
145 return std::nullopt;
146 return ParseBitString(value);
147}
148
149bool Parser::ReadGeneralizedTime(GeneralizedTime* out) {
150 Input value;
151 if (!ReadTag(kGeneralizedTime, &value))
152 return false;
153 return ParseGeneralizedTime(value, out);
154}
155
156} // namespace bssl::der