Aktualizr
C++ SOTA Client
asn1-cerstream.cc
1 #include "asn1-cerstream.h"
2 
3 namespace asn1 {
4 
5 Serializer& Serializer::operator<<(int32_t val) {
6  result.append(cer_encode_integer(val));
7  return *this;
8 }
9 
10 Serializer& Serializer::operator<<(bool val) {
11  result.append(cer_encode_integer(static_cast<int32_t>(val)));
12  return *this;
13 }
14 
15 Serializer& Serializer::operator<<(const std::string& val) {
16  result.append(cer_encode_string(val, last_type));
17  return *this;
18 }
19 
20 Serializer& Serializer::operator<<(ASN1_UniversalTag tag) {
21  // only support primitive universal tags, sequence serialized with tokens
22  result.push_back(static_cast<char>(tag & 0xFF));
23  last_type = tag;
24  return *this;
25 }
26 
27 Serializer& Serializer::operator<<(const Token& tok) {
28  switch (tok.type) {
29  case Token::seq_tok:
30  result.push_back(0x30);
31  result.push_back(static_cast<char>(0x80));
32  break;
33  case Token::endseq_tok:
34  case Token::endexpl_tok:
35  result.push_back(0x00);
36  result.push_back(0x00);
37  break;
38  case Token::expl_tok: {
39  auto full_tag = static_cast<uint8_t>(dynamic_cast<const ExplicitToken&>(tok).tag |
40  dynamic_cast<const ExplicitToken&>(tok).tag_class);
41  result.push_back(static_cast<char>(full_tag | 0x20)); // set 'constructed' bit
42  result.push_back(static_cast<char>(0x80));
43  break;
44  }
45  default:
46  throw std::runtime_error("Unknown token type in ASN1 serialization");
47  }
48  return *this;
49 }
50 
51 Deserializer& Deserializer::operator>>(int32_t& val) {
52  if ((opt_count == 0) || opt_present) {
53  val = int_param;
54  }
55  return *this;
56 }
57 
58 Deserializer& Deserializer::operator>>(bool& val) {
59  if ((opt_count == 0) || opt_present) {
60  val = (int_param != 0);
61  }
62  return *this;
63 }
64 
65 Deserializer& Deserializer::operator>>(std::string& val) {
66  if ((opt_count == 0) || opt_present) {
67  val = string_param;
68  }
69  return *this;
70 }
71 
72 Deserializer& Deserializer::operator>>(ASN1_UniversalTag tag) {
73  int32_t endpos = 0;
74  if ((opt_count != 0) && !opt_present && !opt_first) {
75  return *this;
76  }
77 
78  if (tag != cer_decode_token(data, &endpos, &int_param, &string_param)) {
79  // failed to read first tag from OPTIONAL => OPTIONAL not present
80  if ((opt_count != 0) && opt_first) {
81  opt_present = false;
82  opt_first = false;
83  return *this;
84  }
85 
86  throw deserialization_error();
87  }
88  if ((opt_count != 0) && opt_first) {
89  opt_present = true;
90  opt_first = false;
91  }
92  if (!seq_lengths.empty() && seq_lengths.top() > 0) {
93  seq_consumed.top() += endpos;
94  if (seq_consumed.top() > seq_lengths.top()) {
95  throw deserialization_error();
96  }
97  }
98  data = data.substr(static_cast<size_t>(endpos));
99  return *this;
100 }
101 
102 Deserializer& Deserializer::operator>>(const Token& tok) {
103  int32_t endpos;
104  int32_t seq_len;
105 
106  if ((opt_count != 0) && !opt_present && !opt_first) {
107  if (tok.type == Token::endopt_tok) {
108  --opt_count;
109  bool* result = dynamic_cast<const EndoptToken&>(tok).result_p;
110  if (result != nullptr) {
111  *result = opt_present;
112  }
113  }
114  return *this;
115  }
116 
117  switch (tok.type) {
118  case Token::seq_tok:
119  if (kAsn1Sequence != cer_decode_token(data, &endpos, &seq_len, nullptr)) {
120  if ((opt_count != 0) && opt_first) {
121  opt_present = false;
122  opt_first = false;
123  break;
124  }
125 
126  throw deserialization_error();
127  }
128  if ((opt_count != 0) && opt_first) {
129  opt_present = true;
130  opt_first = false;
131  }
132 
133  data = data.substr(static_cast<size_t>(endpos));
134  seq_lengths.push(seq_len);
135  seq_consumed.push(0);
136  break;
137 
138  case Token::endseq_tok:
139  case Token::endexpl_tok: {
140  int32_t len = seq_lengths.top();
141  int32_t cons_len = seq_consumed.top();
142  seq_lengths.pop();
143  seq_consumed.pop();
144  if (len >= 0) {
145  if (cons_len != len) {
146  throw deserialization_error();
147  }
148  } else {
149  if (kAsn1EndSequence != cer_decode_token(data, &endpos, nullptr, nullptr)) {
150  throw deserialization_error();
151  }
152  data = data.substr(static_cast<size_t>(endpos));
153  cons_len += endpos;
154  }
155 
156  // add total length of current sequence to consumed bytes of the parent sequence
157  if (!seq_lengths.empty()) {
158  seq_consumed.top() += cons_len + 2;
159  }
160  break;
161  }
162 
163  case Token::restseq_tok: {
164  int32_t len = seq_lengths.top();
165  int32_t cons_len = seq_consumed.top();
166  seq_lengths.pop();
167  seq_consumed.pop();
168  if (len >= 0) {
169  while (len > cons_len) {
170  if (cer_decode_token(data, &endpos, nullptr, nullptr) == kUnknown) {
171  throw deserialization_error();
172  }
173  data = data.substr(static_cast<size_t>(endpos));
174  cons_len += endpos;
175  }
176  if (cons_len != len) {
177  throw deserialization_error();
178  }
179  } else {
180  int nestedness = 0;
181  int32_t decoded_int = 0;
182 
183  for (;;) {
184  if (data.empty()) { // end of data before end of sequence
185  throw deserialization_error();
186  }
187  uint8_t ret = cer_decode_token(data, &endpos, &decoded_int, nullptr);
188  data = data.substr(static_cast<size_t>(endpos));
189  cons_len += endpos;
190 
191  if (ret == kUnknown) {
192  throw deserialization_error();
193  }
194  if (ret == kAsn1Sequence) { // TODO: explicit tags (constructed tokens in general)
195  // indefininte length, expect an end of sequence marker
196  if (decoded_int == -1) {
197  ++nestedness;
198  }
199  } else if (ret == kAsn1EndSequence) {
200  if (nestedness == 0) {
201  break;
202  }
203  --nestedness;
204  }
205  }
206  }
207  if (!seq_lengths.empty()) {
208  seq_consumed.top() += cons_len + 2;
209  }
210  break;
211  }
212 
213  case Token::expl_tok: {
214  auto full_tag = static_cast<uint8_t>(dynamic_cast<const ExplicitToken&>(tok).tag |
215  dynamic_cast<const ExplicitToken&>(tok).tag_class);
216  if (full_tag != cer_decode_token(data, &endpos, &seq_len, nullptr)) {
217  if ((opt_count != 0) && opt_first) {
218  opt_present = false;
219  opt_first = false;
220  break;
221  }
222  throw deserialization_error();
223  }
224  if ((opt_count != 0) && opt_first) {
225  opt_present = true;
226  opt_first = false;
227  }
228 
229  data = data.substr(static_cast<size_t>(endpos));
230  seq_lengths.push(seq_len);
231  seq_consumed.push(0);
232  break;
233  }
234 
235  case Token::peekexpl_tok: {
236  uint8_t full_tag = cer_decode_token(data, &endpos, &seq_len, nullptr);
237  if (full_tag == kUnknown) {
238  throw deserialization_error();
239  }
240  if ((opt_count != 0) && opt_first) {
241  opt_present = true;
242  opt_first = false;
243  }
244 
245  uint8_t* out_tag = dynamic_cast<const PeekExplicitToken&>(tok).tag;
246  ASN1_Class* out_tag_class = dynamic_cast<const PeekExplicitToken&>(tok).tag_class;
247  if (out_tag != nullptr) {
248  *out_tag = full_tag & 0x1F;
249  }
250  if (out_tag_class != nullptr) {
251  *out_tag_class = static_cast<ASN1_Class>(full_tag & 0xC0);
252  }
253 
254  data = data.substr(static_cast<size_t>(endpos));
255  seq_lengths.push(seq_len);
256  seq_consumed.push(0);
257  break;
258  }
259 
260  case Token::opt_tok:
261  ++opt_count;
262  opt_first = true;
263  break;
264 
265  case Token::endopt_tok: {
266  --opt_count;
267  bool* result = dynamic_cast<const EndoptToken&>(tok).result_p;
268  if (result != nullptr) {
269  *result = opt_present;
270  }
271  break;
272  }
273 
274  default:
275  throw std::runtime_error("Unknown token type in ASN1 serialization");
276  }
277  // seq_lengths.pop();
278  // seq_consumed.pop();
279  return *this;
280 }
281 
282 } // namespace asn1
deserialization_error
Definition: asn1-cer.h:44
data
General data structures.
Definition: types.h:217
result
Results of libaktualizr API calls.
Definition: results.h:12