parse encapsulated structures (octet string or bit string containing valid ASN.1): reusable readString() method + let exception do its job on invalid input instead of attempt to allocate too much memory
(typeHeader.length may contain insane numbers if input in isValidBER() is not valid ASN.1/BER)
--- a/src/lib/BasicASN1Reader.h Sun Jul 18 12:37:40 2021 +0200
+++ b/src/lib/BasicASN1Reader.h Sun Jul 18 20:08:29 2021 +0200
@@ -112,7 +112,28 @@
return h;
}
- void readNext() {
+ const std::string readString(size_t length) {
+ std::string result;
+
+ for (size_t remaining = length; remaining;) {
+ size_t current = std::min(remaining, (size_t) 3);
+ result.resize(result.size() + current);
+ read((uint8_t*) result.data() + result.size() - current, current);
+ remaining -= current;
+ }
+
+ return result;
+ }
+
+ const std::vector<uint8_t> readVector(size_t length) {
+ std::vector<uint8_t> result;
+ std::string s = readString(length); // TODO: read directly to the vector
+ result.resize(length);
+ for (size_t i = 0; i < length; i++) result[i] = (uint8_t) s[i];
+ return result;
+ }
+
+ void processNext() {
using TagClass = ASN1ContentHandler::TagClass;
using PC = ASN1ContentHandler::PC;
@@ -146,38 +167,24 @@
read((uint8_t*) & value, 1);
handlers->writeBoolean(typeHeader, value);
} else if (typeHeader.tag == UniversalType::Integer && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
- // TODO: check available bytes before allocating buffer
- std::vector<uint8_t> value(typeHeader.length, 0x00);
- read(value.data(), typeHeader.length);
+ std::vector<uint8_t> value = readVector(typeHeader.length);
handlers->writeInteger(typeHeader, ASN1ContentHandler::Integer(value));
} else if (typeHeader.tag == UniversalType::ObjectIdentifier && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
std::vector<uint8_t> value(typeHeader.length, 0x00);
read(value.data(), typeHeader.length);
handlers->writeOID(typeHeader,{value});
} else if (typeHeader.tag == UniversalType::UTF8String && 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::string s = readString(typeHeader.length);
handlers->writeTextString(typeHeader, 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);
+ std::string s = readString(typeHeader.length);
handlers->writeTextString(typeHeader, 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);
+ std::string s = readString(typeHeader.length);
if (processEncapsulatedContent(typeHeader, s) == false) handlers->writeOctetString(typeHeader, 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::string s = readString(typeHeader.length);
if (processEncapsulatedContent(typeHeader, s) == false) {
std::vector<bool> bits;
// TODO: throw exception on wrong padding or insufficient length?
@@ -189,11 +196,8 @@
handlers->writeBitString(typeHeader, 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);
+ std::string s = readString(typeHeader.length);
ASN1ContentHandler::DateTime dateTime;
@@ -219,10 +223,7 @@
}
} else if (typeHeader.tag == UniversalType::GeneralizedTime && 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::string s = readString(typeHeader.length);
ASN1ContentHandler::DateTime dateTime;
@@ -252,10 +253,7 @@
} else {
// TODO: do not skip, parse
- // TODO: check available bytes before allocating buffer
- std::string s;
- s.resize(typeHeader.length);
- read((uint8_t*) s.data(), typeHeader.length);
+ std::string s = readString(typeHeader.length);
handlers->writeSpecific(typeHeader, s);
}
@@ -327,7 +325,7 @@
protected:
void update() override {
- while (true) readNext();
+ while (true) processNext();
}
public: