src/lib/BasicASN1Reader.h
branchv_0
changeset 31 a87c97aecbf6
parent 30 e27e133731ee
child 32 00d76921c547
equal deleted inserted replaced
30:e27e133731ee 31:a87c97aecbf6
   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 	}