somehow parse nested SEQUENCEs and SETs + support definite long form of lengths (multiple length octets)
--- 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,
--- 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();
+}
+
}
}
}
--- 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.
*
--- 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 <memory>
#include <vector>
#include <array>
+#include <sstream>
#include "ASN1Reader.h"
@@ -56,6 +57,25 @@
size_t length;
};
+ class LevelMetadata {
+ public:
+ bool definiteLength;
+ size_t length;
+ size_t start;
+ };
+
+ std::vector<LevelMetadata> 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<uint8_t> 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<uint8_t> 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();
}
};
--- 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;
+ }
+
};