169 } else if (typeHeader.tag == UniversalType::OctetString && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) { |
169 } else if (typeHeader.tag == UniversalType::OctetString && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) { |
170 // TODO: check available bytes before allocating buffer |
170 // TODO: check available bytes before allocating buffer |
171 std::string s; |
171 std::string s; |
172 s.resize(typeHeader.length); |
172 s.resize(typeHeader.length); |
173 read((uint8_t*) s.data(), typeHeader.length); |
173 read((uint8_t*) s.data(), typeHeader.length); |
174 handlers.writeOctetString(typeHeader, s); |
174 if (processEncapsulatedContent(typeHeader, s) == false) handlers.writeOctetString(typeHeader, s); |
175 } else if (typeHeader.tag == UniversalType::BitString && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) { |
175 } else if (typeHeader.tag == UniversalType::BitString && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) { |
176 // TODO: check available bytes before allocating buffer |
176 // TODO: check available bytes before allocating buffer |
177 std::string s; |
177 std::string s; |
178 s.resize(typeHeader.length); |
178 s.resize(typeHeader.length); |
179 read((uint8_t*) s.data(), typeHeader.length); |
179 read((uint8_t*) s.data(), typeHeader.length); |
180 std::vector<bool> bits; |
180 if (processEncapsulatedContent(typeHeader, s) == false) { |
181 // TODO: throw exception on wrong padding or insufficient length? |
181 std::vector<bool> bits; |
182 if (s.size() > 1) { |
182 // TODO: throw exception on wrong padding or insufficient length? |
183 uint8_t padding = s[0]; |
183 if (s.size() > 1) { |
184 for (uint8_t j = padding; j < 8; j++) bits.push_back(s.back() & 1 << j); |
184 uint8_t padding = s[0]; |
185 for (size_t i = s.size() - 2; i > 0; i--) for (uint8_t j = 0; j < 8; j++) bits.push_back(s[i] & 1 << j); |
185 for (uint8_t j = padding; j < 8; j++) bits.push_back(s.back() & 1 << j); |
|
186 for (size_t i = s.size() - 2; i > 0; i--) for (uint8_t j = 0; j < 8; j++) bits.push_back(s[i] & 1 << j); |
|
187 } |
|
188 handlers.writeBitString(typeHeader, bits); |
186 } |
189 } |
187 handlers.writeBitString(typeHeader, bits); |
|
188 } else if (typeHeader.tag == UniversalType::UTCTime && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) { |
190 } else if (typeHeader.tag == UniversalType::UTCTime && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) { |
189 // TODO: check available bytes before allocating buffer |
191 // TODO: check available bytes before allocating buffer |
190 // TODO: check encoding |
192 // TODO: check encoding |
191 std::string s; |
193 std::string s; |
192 s.resize(typeHeader.length); |
194 s.resize(typeHeader.length); |
247 throw std::invalid_argument("Unsupported GeneralizedTime format: " + s); // TODO: better exception |
249 throw std::invalid_argument("Unsupported GeneralizedTime format: " + s); // TODO: better exception |
248 } |
250 } |
249 |
251 |
250 } else { |
252 } else { |
251 // TODO: do not skip, parse |
253 // TODO: do not skip, parse |
|
254 // TODO: check available bytes before allocating buffer |
252 std::vector<uint8_t> temp(typeHeader.length, 0); |
255 std::vector<uint8_t> temp(typeHeader.length, 0); |
253 read(temp.data(), typeHeader.length); |
256 read(temp.data(), typeHeader.length); |
254 // TODO: recover transaction? |
257 // TODO: recover transaction? |
255 |
258 |
256 std::stringstream description; |
259 std::stringstream description; |
259 << " tagClass = " << (int) typeHeader.tagClass |
262 << " tagClass = " << (int) typeHeader.tagClass |
260 << " pc = " << (int) typeHeader.pc |
263 << " pc = " << (int) typeHeader.pc |
261 << " length = " << typeHeader.length |
264 << " length = " << typeHeader.length |
262 << " definite = " << (typeHeader.definiteLength ? "true" : "false"); |
265 << " definite = " << (typeHeader.definiteLength ? "true" : "false"); |
263 |
266 |
|
267 // TODO: special event for unparsed? (instead of a text string) |
264 handlers.writeTextString(typeHeader, description.str()); |
268 handlers.writeTextString(typeHeader, description.str()); |
265 } |
269 } |
266 |
270 |
267 commit(); |
271 commit(); |
268 } |
272 } |
276 } catch (...) { |
280 } catch (...) { |
277 return false; |
281 return false; |
278 } |
282 } |
279 } |
283 } |
280 |
284 |
|
285 bool isValidBER(const std::string& input) { |
|
286 BasicASN1Reader encapsulatedReader; |
|
287 try { |
|
288 encapsulatedReader.write((const uint8_t*) input.c_str(), input.size()); |
|
289 encapsulatedReader.close(); |
|
290 return true; |
|
291 } catch (...) { |
|
292 return false; |
|
293 } |
|
294 } |
|
295 |
|
296 class EncapsulatedASN1ContentHandler : public ASN1ContentHandlerProxy { |
|
297 public: |
|
298 |
|
299 void writeStreamStart() override { |
|
300 // skip this event |
|
301 } |
|
302 |
|
303 void writeStreamEnd() override { |
|
304 // skip this event |
|
305 } |
|
306 }; |
|
307 |
|
308 /** |
|
309 * @param typeHeader |
|
310 * @param input OCTET STRING or BIT STRING raw bytes |
|
311 * @return whether we found valid content and passed parsed results to handlers |
|
312 */ |
|
313 bool processEncapsulatedContent(const BasicHeader& typeHeader, const std::string& input) { |
|
314 // TODO: avoid double parsing + encapsulated content might be also processed at the XML/DOM level where we may even do conditional processing based on XPath (evaluate only certain octet- or bit- strings) |
|
315 // We may also do the same as with SEQUENCE or SET (continue nested reading in this ASN1Rreader instance), but it would require valid encapsulated data and would avoid easy fallback to raw OCTET or BIT STRING. We would also have to check the boundaries of the nested part. |
|
316 if (isValidBER(input)) { |
|
317 handlers.writeCollectionStart(typeHeader); |
|
318 |
|
319 BasicASN1Reader encapsulatedReader; |
|
320 std::shared_ptr<EncapsulatedASN1ContentHandler> encapsulatedHandler = std::make_shared<EncapsulatedASN1ContentHandler>(); |
|
321 encapsulatedHandler->addHandler(std::shared_ptr<ASN1ContentHandlerProxy>(&handlers, [](auto doNotDeleteHere) { |
|
322 })); // FIXME: correct memory management |
|
323 encapsulatedReader.addHandler(encapsulatedHandler); |
|
324 |
|
325 encapsulatedReader.write((const uint8_t*) input.c_str(), input.size()); |
|
326 encapsulatedReader.close(); |
|
327 |
|
328 handlers.writeCollectionEnd(); |
|
329 return true; |
|
330 } else { |
|
331 return false; |
|
332 } |
|
333 } |
|
334 |
281 protected: |
335 protected: |
282 |
336 |
283 void update() override { |
337 void update() override { |
284 while (true) readNext(); |
338 while (true) readNext(); |
285 } |
339 } |
286 |
340 |
287 public: |
341 public: |
288 |
342 |
289 void close() override { |
343 void close() override { |
290 if (hasAvailableForReading()) throw std::logic_error("Unexpected content at the end of the stream"); // TODO: better exception |
344 if (hasAvailableForReading()) throw std::logic_error("Unexpected content at the end of the stream"); // TODO: better exception |
|
345 |
|
346 // TODO: check also open sequences etc.; maybe in the handler |
291 |
347 |
292 checkRemainingItems(); |
348 checkRemainingItems(); |
293 // TODO: check the bytes remaining in the buffer |
349 // TODO: check the bytes remaining in the buffer |
294 if (started) handlers.writeStreamEnd(); |
350 if (started) handlers.writeStreamEnd(); |
295 } |
351 } |