Skip to content

Commit

Permalink
ASN.1 enhancements (#1404)
Browse files Browse the repository at this point in the history
  • Loading branch information
seladb authored May 27, 2024
1 parent 2890a2f commit 00e80a5
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 28 deletions.
40 changes: 39 additions & 1 deletion Packet++/header/Asn1Codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ namespace pcpp

private:
uint8_t* m_Value = nullptr;
bool m_FreeValueOnDestruction = false;
};

/**
Expand All @@ -277,6 +276,14 @@ namespace pcpp
*/
explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType, const std::vector<Asn1Record*>& subRecords);

/**
* A constructor to create a constructed record
* @param tagClass The record tag class
* @param tagType The record tag type value
* @param subRecords A PointerVector of sub-records to assign as the record value
*/
explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType, const PointerVector<Asn1Record>& subRecords);

/**
* @return A reference to the list of sub-records. It's important to note that any modifications made to
* this list will directly affect the internal structure
Expand All @@ -291,6 +298,25 @@ namespace pcpp

std::vector<std::string> toStringList() override;

template<typename Iterator>
void init(Asn1TagClass tagClass, uint8_t tagType, Iterator begin, Iterator end)
{
m_TagType = tagType;
m_TagClass = tagClass;
m_IsConstructed = true;

size_t recordValueLength = 0;
for (Iterator recordIter = begin; recordIter != end; ++recordIter)
{
auto encodedRecord = (*recordIter)->encode();
auto copyRecord = Asn1Record::decode(encodedRecord.data(), encodedRecord.size(), false);
m_SubRecords.pushBack(copyRecord.release());
recordValueLength += encodedRecord.size();
}

m_ValueLength = recordValueLength;
m_TotalLength = recordValueLength + 1 + (m_ValueLength < 128 ? 1 : 2);
}
private:
PointerVector<Asn1Record> m_SubRecords;
};
Expand All @@ -310,6 +336,12 @@ namespace pcpp
*/
explicit Asn1SequenceRecord(const std::vector<Asn1Record*>& subRecords);

/**
* A constructor to create a record of type Sequence
* @param subRecords A PointerVector of sub-records to assign as the record value
*/
explicit Asn1SequenceRecord(const PointerVector<Asn1Record>& subRecords);

private:
Asn1SequenceRecord() = default;
};
Expand All @@ -329,6 +361,12 @@ namespace pcpp
*/
explicit Asn1SetRecord(const std::vector<Asn1Record*>& subRecords);

/**
* A constructor to create a record of type Set
* @param subRecords A PointerVector of sub-records to assign as the record value
*/
explicit Asn1SetRecord(const PointerVector<Asn1Record>& subRecords);

private:
Asn1SetRecord() = default;
};
Expand Down
48 changes: 21 additions & 27 deletions Packet++/src/Asn1Codec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,10 @@ namespace pcpp
return result;
}

// Assuming the size is always 4 bytes
uint8_t firstByte = 0x80 | sizeof(uint32_t);
// Assuming the size is always less than 256
uint8_t firstByte = 0x80 | 0x01;
result.push_back(firstByte);

result.push_back((m_ValueLength >> 24) & 0xff);
result.push_back((m_ValueLength >> 16) & 0xff);
result.push_back((m_ValueLength >> 8) & 0xff);
result.push_back(m_ValueLength & 0xff);
result.push_back(m_ValueLength);

return result;
}
Expand Down Expand Up @@ -451,23 +447,22 @@ namespace pcpp
m_TagClass = tagClass;
m_IsConstructed = isConstructed;
m_Value = new uint8_t[valueLen];
m_FreeValueOnDestruction = true;
memcpy(m_Value, value, valueLen);
m_ValueLength = valueLen;
m_TotalLength = m_ValueLength + 2;
}

Asn1GenericRecord::~Asn1GenericRecord()
{
if (m_Value && m_FreeValueOnDestruction)
{
delete m_Value;
}
delete m_Value;
}

void Asn1GenericRecord::decodeValue(uint8_t* data, bool lazy)
{
m_Value = data;
delete m_Value;

m_Value = new uint8_t[m_ValueLength];
memcpy(m_Value, data, m_ValueLength);
}

std::vector<uint8_t> Asn1GenericRecord::encodeValue() const
Expand All @@ -477,21 +472,12 @@ namespace pcpp

Asn1ConstructedRecord::Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType, const std::vector<Asn1Record*>& subRecords)
{
m_TagType = tagType;
m_TagClass = tagClass;
m_IsConstructed = true;

size_t recordValueLength = 0;
for (auto record : subRecords)
{
auto encodedRecord = record->encode();
auto copyRecord = Asn1Record::decode(encodedRecord.data(), encodedRecord.size(), false);
m_SubRecords.pushBack(copyRecord.release());
recordValueLength += encodedRecord.size();
}
init(tagClass, tagType, subRecords.begin(), subRecords.end());
}

m_ValueLength = recordValueLength;
m_TotalLength = recordValueLength + 2;
Asn1ConstructedRecord::Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType, const PointerVector<Asn1Record>& subRecords)
{
init(tagClass, tagType, subRecords.begin(), subRecords.end());
}

void Asn1ConstructedRecord::decodeValue(uint8_t* data, bool lazy)
Expand Down Expand Up @@ -545,10 +531,18 @@ namespace pcpp
: Asn1ConstructedRecord(Asn1TagClass::Universal, static_cast<uint8_t>(Asn1UniversalTagType::Sequence), subRecords)
{}

Asn1SequenceRecord::Asn1SequenceRecord(const PointerVector<Asn1Record>& subRecords)
: Asn1ConstructedRecord(Asn1TagClass::Universal, static_cast<uint8_t>(Asn1UniversalTagType::Sequence), subRecords)
{}

Asn1SetRecord::Asn1SetRecord(const std::vector<Asn1Record*>& subRecords)
: Asn1ConstructedRecord(Asn1TagClass::Universal, static_cast<uint8_t>(Asn1UniversalTagType::Set), subRecords)
{}

Asn1SetRecord::Asn1SetRecord(const PointerVector<Asn1Record>& subRecords)
: Asn1ConstructedRecord(Asn1TagClass::Universal, static_cast<uint8_t>(Asn1UniversalTagType::Set), subRecords)
{}

Asn1PrimitiveRecord::Asn1PrimitiveRecord(Asn1UniversalTagType tagType) : Asn1Record()
{
m_TagType = static_cast<uint8_t >(tagType);
Expand Down
42 changes: 42 additions & 0 deletions Tests/Packet++Test/Tests/Asn1Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,18 @@ PTF_TEST_CASE(Asn1EncodingTest)
PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen)
}

// Long length
{
pcpp::Asn1OctetStringRecord record("12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

uint8_t data[203];
auto dataLen = pcpp::hexStringToByteArray("0481c83132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930", data, 203);

auto encodedValue = record.encode();
PTF_ASSERT_EQUAL(encodedValue.size(), dataLen);
PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen)
}

// Integer 1 byte
{
pcpp::Asn1IntegerRecord record(6);
Expand Down Expand Up @@ -570,6 +582,21 @@ PTF_TEST_CASE(Asn1EncodingTest)
PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen);
}

// Sequence initialized with a PointerVector
{
pcpp::PointerVector<pcpp::Asn1Record> subRecords;
subRecords.pushBack(new pcpp::Asn1OctetStringRecord("abcd"));
subRecords.pushBack(new pcpp::Asn1IntegerRecord(1000));
pcpp::Asn1SequenceRecord record(subRecords);

uint8_t data[20];
auto dataLen = pcpp::hexStringToByteArray("300a040461626364020203e8", data, 20);

auto encodedValue = record.encode();
PTF_ASSERT_EQUAL(encodedValue.size(), dataLen);
PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen);
}

// Set
{
pcpp::Asn1OctetStringRecord octestStringRecord("abcd");
Expand All @@ -594,4 +621,19 @@ PTF_TEST_CASE(Asn1EncodingTest)
PTF_ASSERT_EQUAL(encodedValue.size(), dataLen);
PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen);
}

// Set initialized with a PointerVector
{
pcpp::PointerVector<pcpp::Asn1Record> subRecords;
subRecords.pushBack(new pcpp::Asn1IntegerRecord(1000));
subRecords.pushBack(new pcpp::Asn1OctetStringRecord("abcd"));
pcpp::Asn1SetRecord record(subRecords);

uint8_t data[20];
auto dataLen = pcpp::hexStringToByteArray("310a020203e8040461626364", data, 20);

auto encodedValue = record.encode();
PTF_ASSERT_EQUAL(encodedValue.size(), dataLen);
PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen);
}
} // Asn1EncodingTest

0 comments on commit 00e80a5

Please sign in to comment.