BitString and OctetString support v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Fri, 02 Jul 2021 00:42:01 +0200
branchv_0
changeset 23 8941a679299f
parent 22 9b6f86760384
child 24 114810ee2386
BitString and OctetString support
src/lib/ASN1ContentHandler.h
src/lib/BasicASN1Reader.h
src/lib/GenericASN1ContentHandler.h
--- a/src/lib/ASN1ContentHandler.h	Wed Jun 30 20:11:39 2021 +0200
+++ b/src/lib/ASN1ContentHandler.h	Fri Jul 02 00:42:01 2021 +0200
@@ -37,19 +37,18 @@
 	};
 
 	enum class StringType : uint64_t {
-		OctetString,
-		UTF8String,
-		NumericString,
-		PrintableString,
-		T61String,
-		VideotexString,
-		IA5String,
-		GraphicString,
-		VisibleString,
-		GeneralString,
-		UniversalString,
-		CharacterString,
-		BMPString,
+		UTF8String = 0xC,
+		NumericString = 0x12,
+		PrintableString = 0x13,
+		T61String = 0x14,
+		VideotexString = 0x15,
+		IA5String = 0x16,
+		GraphicString = 0x19,
+		VisibleString = 0x1A,
+		GeneralString = 0x1B,
+		UniversalString = 0x1C,
+		CharacterString = 0x1D,
+		BMPString = 0x1E,
 	};
 
 	enum class DateTimeType : uint64_t {
@@ -238,7 +237,19 @@
 	virtual void writeBoolean(bool value) = 0;
 	virtual void writeNull() = 0;
 	virtual void writeInteger(Integer value) = 0;
-	virtual void writeString(StringType type, std::string value) = 0;
+	/**
+	 * @param type original type in ASN.1
+	 * @param value original text converted to UTF-8
+	 */
+	virtual void writeTextString(StringType type, std::string value) = 0;
+	/**
+	 * @param value arbitrary sequence of octets (bytes), usually not a human-readable text
+	 */
+	virtual void writeOctetString(std::string value) = 0;
+	/**
+	 * @param value arbitrary sequence of bits (booleans), usually not a human-readable text
+	 */
+	virtual void writeBitString(std::vector<bool> value) = 0;
 	virtual void writeOID(ObjectIdentifier value) = 0;
 	virtual void writeDateTime(DateTimeType type, DateTime value) = 0;
 	// Object descriptor
@@ -290,8 +301,16 @@
 		handler->writeInteger(value);
 	}
 
-	void writeString(StringType type, std::string value) override {
-		handler->writeString(type, value);
+	void writeTextString(StringType type, std::string value) override {
+		handler->writeTextString(type, value);
+	}
+
+	void writeOctetString(std::string value) override {
+		handler->writeOctetString(value);
+	}
+
+	void writeBitString(std::vector<bool> value) override {
+		handler->writeBitString(value);
 	}
 
 	void writeOID(ObjectIdentifier value) override {
--- a/src/lib/BasicASN1Reader.h	Wed Jun 30 20:11:39 2021 +0200
+++ b/src/lib/BasicASN1Reader.h	Fri Jul 02 00:42:01 2021 +0200
@@ -207,16 +207,36 @@
 			std::string s;
 			s.resize(typeHeader.length);
 			read((uint8_t*) s.data(), typeHeader.length);
-			handlers.writeString(ASN1ContentHandler::StringType::UTF8String, s);
+			handlers.writeTextString(ASN1ContentHandler::StringType::UTF8String, s);
 		} else if (typeHeader.tag == UniversalType::PrintableString && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
 			// TODO: check encoding
 			// TODO: check available bytes before allocating buffer
 			std::string s;
 			s.resize(typeHeader.length);
 			read((uint8_t*) s.data(), typeHeader.length);
-			handlers.writeString(ASN1ContentHandler::StringType::PrintableString, s);
+			handlers.writeTextString(ASN1ContentHandler::StringType::PrintableString, s);
+		} else if (typeHeader.tag == UniversalType::OctetString && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
+			// TODO: check available bytes before allocating buffer
+			std::string s;
+			s.resize(typeHeader.length);
+			read((uint8_t*) s.data(), typeHeader.length);
+			handlers.writeOctetString(s);
+		} else if (typeHeader.tag == UniversalType::BitString && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
+			// TODO: check available bytes before allocating buffer
+			std::string s;
+			s.resize(typeHeader.length);
+			read((uint8_t*) s.data(), typeHeader.length);
+			std::vector<bool> bits;
+			// TODO: throw exception on wrong padding or insufficient length?
+			if (s.size() > 1) {
+				uint8_t padding = s[0];
+				for (uint8_t j = padding; j < 8; j++) bits.push_back(s.back() & 1 << j);
+				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);
+			}
+			handlers.writeBitString(bits);
 		} else if (typeHeader.tag == UniversalType::UTCTime && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
 			// TODO: check available bytes before allocating buffer
+			// TODO: check encoding
 			std::string s;
 			s.resize(typeHeader.length);
 			read((uint8_t*) s.data(), typeHeader.length);
@@ -295,7 +315,7 @@
 					<< " length = " << typeHeader.length
 					<< " definite = " << (typeHeader.definiteLength ? "true" : "false");
 
-			handlers.writeString(ASN1ContentHandler::StringType::UTF8String, description.str());
+			handlers.writeTextString(ASN1ContentHandler::StringType::UTF8String, description.str());
 		}
 
 		commit();
--- a/src/lib/GenericASN1ContentHandler.h	Wed Jun 30 20:11:39 2021 +0200
+++ b/src/lib/GenericASN1ContentHandler.h	Fri Jul 02 00:42:01 2021 +0200
@@ -16,6 +16,9 @@
  */
 #pragma once
 
+#include <sstream>
+#include <iomanip>
+
 #include "ASN1ContentHandler.h"
 #include "XMLContentHandler.h"
 
@@ -77,13 +80,32 @@
 		handlers.writeEndElement();
 	}
 
-	void writeString(StringType type, std::string value) override {
-		handlers.writeStartElement("string");
+	void writeTextString(StringType type, std::string value) override {
+		handlers.writeStartElement("text-string",{"type", std::to_string((uint64_t) type)}); // TODO: type name, better attributes
 		handlers.writeCharacters(value);
 		handlers.writeEndElement();
 	}
 
+	void writeOctetString(std::string value) override {
+		std::stringstream hex;
+		hex << std::hex << std::setfill('0');
+		for (uint8_t b : value) hex << std::setw(2) << (int) b;
+		handlers.writeStartElement("octet-string",{"length", std::to_string(value.size())});
+		handlers.writeCharacters(hex.str());
+		handlers.writeEndElement();
+	}
+
+	void writeBitString(std::vector<bool> value) override {
+		std::stringstream bits;
+		for (bool b : value) bits << (int) b;
+		// for (bool b : value) bits << (b ? ':' : '.'); // TODO: configurable true/false symbols?
+		handlers.writeStartElement("bit-string",{"length", std::to_string(value.size())});
+		handlers.writeCharacters(bits.str());
+		handlers.writeEndElement();
+	}
+
 	void writeOID(ObjectIdentifier value) override {
+		// TODO: optionally expand into separate elements with additional metadata
 		handlers.writeStartElement("oid");
 		handlers.writeCharacters(value.toString());
 		handlers.writeEndElement();