--- a/src/lib/BasicASN1Reader.h Mon Jun 28 22:48:04 2021 +0200
+++ b/src/lib/BasicASN1Reader.h Wed Jun 30 20:11:39 2021 +0200
@@ -49,6 +49,46 @@
Constructed = 1
};
+ enum UniversalType : uint64_t {
+ EndOfContent = 0x00,
+ Boolean = 0x01,
+ Integer = 0x02,
+ BitString = 0x03,
+ OctetString = 0x04,
+ Null = 0x05,
+ ObjectIdentifier = 0x06,
+ ObjectDescriptor = 0x07,
+ External = 0x08,
+ Real = 0x09,
+ Enumerated = 0xA,
+ Embedded = 0xB,
+ UTF8String = 0xC,
+ RelativeObjectIdentifier = 0xD,
+ Time = 0xE,
+ Reserved = 0xF,
+ Sequence = 0x10,
+ Set = 0x11,
+ NumericString = 0x12,
+ PrintableString = 0x13,
+ T61String = 0x14,
+ VideotexString = 0x15,
+ IA5String = 0x16,
+ UTCTime = 0x17,
+ GeneralizedTime = 0x18,
+ GraphicString = 0x19,
+ VisibleString = 0x1A,
+ GeneralString = 0x1B,
+ UniversalString = 0x1C,
+ CharacterString = 0x1D,
+ BMPString = 0x1E,
+ Date = 0x1F,
+ TimeOfDay = 0x20,
+ DateTime = 0x21,
+ Duration = 0x22,
+ ObjectIdentifierIRI = 0x23,
+ RelativeObjectIdentifierIRI = 0x24,
+ };
+
class Header {
public:
TagClass tagClass;
@@ -136,46 +176,46 @@
// TODO: check tagClass and pc
// TODO: constants, more types
- if (typeHeader.tag == 0 && typeHeader.tagClass == TagClass::Universal && typeHeader.pc == PC::Primitive) {
+ if (typeHeader.tag == UniversalType::EndOfContent && typeHeader.tagClass == TagClass::Universal && typeHeader.pc == PC::Primitive) {
handlers.writeCollectionEnd();
- } else if (typeHeader.tag == 16) {
+ } else if (typeHeader.tag == UniversalType::Sequence) {
level.push_back({typeHeader.definiteLength, typeHeader.length, getBytesRead()}); // TODO: transaction
handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Sequence);
- } else if (typeHeader.tag == 17) {
+ } else if (typeHeader.tag == UniversalType::Set) {
level.push_back({typeHeader.definiteLength, typeHeader.length, getBytesRead()}); // TODO: transaction
handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Set);
} else if (typeHeader.pc == PC::Constructed) {
level.push_back({typeHeader.definiteLength, typeHeader.length, getBytesRead()}); // TODO: transaction
handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Constructed);
- } else if (typeHeader.tag == 5 && typeHeader.length == 0) {
+ } else if (typeHeader.tag == UniversalType::Null && typeHeader.length == 0) {
handlers.writeNull();
- } else if (typeHeader.tag == 1) {
+ } else if (typeHeader.tag == UniversalType::Boolean && typeHeader.definiteLength && typeHeader.length == 1) {
bool value;
read((uint8_t*) & value, 1);
handlers.writeBoolean(value);
- } else if (typeHeader.tag == 2 && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
+ } 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);
handlers.writeInteger(ASN1ContentHandler::Integer(value));
- } else if (typeHeader.tag == 6 && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
+ } 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({value});
- } else if (typeHeader.tag == 12 && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
+ } 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);
handlers.writeString(ASN1ContentHandler::StringType::UTF8String, s);
- } else if (typeHeader.tag == 19 && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
+ } 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);
- } else if (typeHeader.tag == 0x17 && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
+ } else if (typeHeader.tag == UniversalType::UTCTime && typeHeader.tagClass == TagClass::Universal && typeHeader.definiteLength) {
// TODO: check available bytes before allocating buffer
std::string s;
s.resize(typeHeader.length);
@@ -184,7 +224,14 @@
ASN1ContentHandler::DateTime dateTime;
std::smatch match;
- if (std::regex_match(s, match, std::regex("([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})Z"))) {
+ if (std::regex_match(s, match, std::regex("([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?(Z|([+-][0-9]{2})'?([0-9]{2})'?)"))) {
+ // Supported UTCTime formats:
+ // YYMMDDhhmmZ
+ // YYMMDDhhmmssZ
+ // YYMMDDhhmm+hhmm
+ // YYMMDDhhmm-hhmm
+ // YYMMDDhhmmss+hhmm
+ // YYMMDDhhmmss-hhmm
int i = 1;
uint32_t year = std::stoi(match[i++]);
dateTime.year = year < 50 ? 2000 + year : 1900 + year;
@@ -192,17 +239,46 @@
dateTime.day = std::stoi(match[i++]);
dateTime.hour = std::stoi(match[i++]);
dateTime.minute = std::stoi(match[i++]);
- dateTime.precision = ASN1ContentHandler::DateTime::Precision::Second;
+ dateTime.precision = match[i].length() ? ASN1ContentHandler::DateTime::Precision::Second : ASN1ContentHandler::DateTime::Precision::Minute;
+ dateTime.second = match[i].length() ? std::stoi(match[i++]) : 0;
+ if (match[i++] != "Z") {
+ dateTime.timezoneHour = std::stoi(match[i++]);
+ dateTime.timezoneMinute = std::stoi(match[i++]);
+ }
handlers.writeDateTime(ASN1ContentHandler::DateTimeType::UTCTime, dateTime);
} else {
- // FIXME: decode more UTCTime formats:
- // YYMMDDhhmmZ
- // YYMMDDhhmm+hh'mm'
- // YYMMDDhhmm-hh'mm'
- // YYMMDDhhmmssZ
- // YYMMDDhhmmss+hh'mm'
- // YYMMDDhhmmss-hh'mm'
- handlers.writeString(ASN1ContentHandler::StringType::UTF8String, "FIXME: UTCTime format not yet supported: " + s);
+ throw std::invalid_argument("Unsupported UTCTime format: " + s); // TODO: better exception
+ }
+
+ } 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);
+
+ ASN1ContentHandler::DateTime dateTime;
+
+ std::smatch match;
+ if (std::regex_match(s, match, std::regex("([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})(\\.([0-9]{1,3}))?(Z|([+-][0-9]{2})'?([0-9]{2})'?)"))) {
+ int i = 1;
+ dateTime.year = std::stoi(match[i++]);
+ dateTime.month = std::stoi(match[i++]);
+ dateTime.day = std::stoi(match[i++]);
+ dateTime.hour = std::stoi(match[i++]);
+ dateTime.minute = std::stoi(match[i++]);
+ dateTime.second = match[i].length() ? std::stoi(match[i++]) : 0;
+ dateTime.precision = match[i++].length() ? ASN1ContentHandler::DateTime::Precision::Nanosecond : ASN1ContentHandler::DateTime::Precision::Second;
+ if (match[i].length() == 1) dateTime.nanosecond = std::stoi(match[i++]) * 100 * 1000000;
+ else if (match[i].length() == 2) dateTime.nanosecond = std::stoi(match[i++]) * 10 * 1000000;
+ else if (match[i].length() == 3) dateTime.nanosecond = std::stoi(match[i++]) * 1000000;
+ else i++;
+ if (match[i++] != "Z") {
+ dateTime.timezoneHour = std::stoi(match[i++]);
+ dateTime.timezoneMinute = std::stoi(match[i++]);
+ }
+ handlers.writeDateTime(ASN1ContentHandler::DateTimeType::GeneralizedTime, dateTime);
+ } else {
+ throw std::invalid_argument("Unsupported GeneralizedTime format: " + s); // TODO: better exception
}
} else {