# HG changeset patch # User František Kučera # Date 1625179321 -7200 # Node ID 8941a679299f95daafdfa29479d9233a3a422b05 # Parent 9b6f86760384e5e549f2c8c3ffd96c013f4e7a86 BitString and OctetString support diff -r 9b6f86760384 -r 8941a679299f src/lib/ASN1ContentHandler.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 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 value) override { + handler->writeBitString(value); } void writeOID(ObjectIdentifier value) override { diff -r 9b6f86760384 -r 8941a679299f src/lib/BasicASN1Reader.h --- 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 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(); diff -r 9b6f86760384 -r 8941a679299f src/lib/GenericASN1ContentHandler.h --- 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 +#include + #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 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();