# HG changeset patch # User František Kučera # Date 1624215962 -7200 # Node ID 02725d301010f466d7f9a833984b1a723ab67c22 # Parent d5e2cb9e31f15ed1fee4d5dd609159281f89552f somehow parse nested SEQUENCEs and SETs + support definite long form of lengths (multiple length octets) diff -r d5e2cb9e31f1 -r 02725d301010 src/lib/ASN1ContentHandler.h --- a/src/lib/ASN1ContentHandler.h Sun Jun 20 20:16:46 2021 +0200 +++ b/src/lib/ASN1ContentHandler.h Sun Jun 20 21:06:02 2021 +0200 @@ -27,12 +27,12 @@ class ASN1ContentHandler { public: - enum class CollectionType { - Sequence, - Set + enum class CollectionType : uint64_t { + Sequence = 16, + Set = 17 }; - enum class StringType { + enum class StringType : uint64_t { OctetString, UTF8String, NumericString, diff -r d5e2cb9e31f1 -r 02725d301010 src/lib/AbstractParser.cpp --- a/src/lib/AbstractParser.cpp Sun Jun 20 20:16:46 2021 +0200 +++ b/src/lib/AbstractParser.cpp Sun Jun 20 21:06:02 2021 +0200 @@ -82,6 +82,10 @@ implementation->buffer.read(buffer, length); } +size_t AbstractParser::getBytesRead() { + return implementation->buffer.getBytesRead(); +} + } } } diff -r d5e2cb9e31f1 -r 02725d301010 src/lib/AbstractParser.h --- a/src/lib/AbstractParser.h Sun Jun 20 20:16:46 2021 +0200 +++ b/src/lib/AbstractParser.h Sun Jun 20 21:06:02 2021 +0200 @@ -106,6 +106,11 @@ void peek(uint8_t* buffer, const size_t length); /** + * @return total number of bytes that were successfully read + */ + size_t getBytesRead(); + + /** * Reads input from buffers using read(), parses data and usually emits the result (e.g. to a handler/listener). * Is specific for particular format/parser. * diff -r d5e2cb9e31f1 -r 02725d301010 src/lib/BasicASN1Reader.h --- a/src/lib/BasicASN1Reader.h Sun Jun 20 20:16:46 2021 +0200 +++ b/src/lib/BasicASN1Reader.h Sun Jun 20 21:06:02 2021 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include #include "ASN1Reader.h" @@ -56,6 +57,25 @@ size_t length; }; + class LevelMetadata { + public: + bool definiteLength; + size_t length; + size_t start; + }; + + std::vector level; + + void checkRemainingItems() { + if (level.size()) { + LevelMetadata& l = level.back(); + if (l.definiteLength && l.length == getBytesRead() - l.start) { + level.pop_back(); + handlers.writeCollectionEnd(); + } + } + } + Header readHeader() { Header h; @@ -72,33 +92,76 @@ uint8_t lengthByte; read(&lengthByte, 1); - std::wcerr << L"lengthByte = " << lengthByte << std::endl; - if (lengthByte >> 7 == 0) { + // definite short h.definiteLength = true; h.length = lengthByte; } else if (lengthByte == 0b10000000) { + // indefinite h.definiteLength = false; h.length = 0; } else if (lengthByte == 0xFF) { throw relpipe::writer::RelpipeWriterException(L"ASN.1 lengthByte == 0xFF (reserved value)"); // TODO: better exception } else { - // FIXME: longer values - throw relpipe::writer::RelpipeWriterException(L"not yet implemented, ASN.1 lengthBytes: longer value"); // TODO: better exception + // definite long + h.definiteLength = true; + h.length = 0; + std::vector lengthBytes(lengthByte & 0b01111111, 0); + read(lengthBytes.data(), lengthBytes.size()); + for (uint8_t l : lengthBytes) h.length = (h.length << 8) + l; } - + return h; } void readNext() { + checkRemainingItems(); Header typeHeader = readHeader(); - commit(); + // commit(); // TODO: commit here and recover later instead of rollback? if (!started) { handlers.writeStreamStart(); started = true; } + + // TODO: check tagClass and pc + // TODO: constants, more types + if (typeHeader.tag == 0) handlers.writeCollectionEnd(); + else if (typeHeader.tag == 16) { + level.push_back({typeHeader.definiteLength, typeHeader.length, getBytesRead()}); // TODO: transaction + handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Sequence); + } else if (typeHeader.tag == 17) { + level.push_back({typeHeader.definiteLength, typeHeader.length, getBytesRead()}); // TODO: transaction + handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Set); + } else if (typeHeader.tag == 5 && typeHeader.length == 0) { + handlers.writeNull(); + } else if (typeHeader.tag == 1) { + bool value; + read((uint8_t*) & value, 1); + handlers.writeBoolean(value); + } else { + // TODO: do not skip, parse + std::vector temp(typeHeader.length, 0); + read(temp.data(), typeHeader.length); + // TODO: recover transaction? + + std::stringstream description; + description << "value:" + << " tag = " << typeHeader.tag + << " tagClass = " << (int) typeHeader.tagClass + << " pc = " << (int) typeHeader.pc + << " length = " << typeHeader.length + << " definite = " << (typeHeader.definiteLength ? "true" : "false"); + + handlers.writeString(ASN1ContentHandler::StringType::UTF8String, description.str()); + } + + commit(); + + + // TODO: remove debug/demo output: + return; handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Sequence); handlers.writeNull(); handlers.writeBoolean(true); @@ -127,7 +190,8 @@ public: void close() override { - if (started) handlers.writeStreamEnd(); + // TODO: check the bytes remaining in the buffer + //if (started) handlers.writeStreamEnd(); } }; diff -r d5e2cb9e31f1 -r 02725d301010 src/lib/TransactionalBuffer.h --- a/src/lib/TransactionalBuffer.h Sun Jun 20 20:16:46 2021 +0200 +++ b/src/lib/TransactionalBuffer.h Sun Jun 20 21:06:02 2021 +0200 @@ -37,6 +37,9 @@ size_t readPosition = 0; size_t readPositionCommited = 0; + size_t bytesRead = 0; + size_t bytesReadCommited = 0; + size_t availableForReading() { if (readPosition < writePosition) return writePosition - readPosition; else if (readPosition > writePosition) return bufferSize - readPosition + writePosition; @@ -99,6 +102,7 @@ peek(outputBuffer, length); readPosition = (readPosition + length) % bufferSize; hasData = readPosition != writePosition; + bytesRead += length; } void peek(uint8_t* outputBuffer, const size_t length) { @@ -114,11 +118,18 @@ void commitRead() { readPositionCommited = readPosition; + bytesReadCommited = bytesRead; } void rollbackRead() { readPosition = readPositionCommited; + bytesRead = bytesReadCommited; } + + size_t getBytesRead() { + return bytesRead; + } + };