#include <stdio.h>
#include <stdint.h>
#include <memory.h>
#include "ASN1.h"
ASN1Object::ASN1Object(const std::vector<uint8_t>& asn1_encoded_data)
: m_type(ASN1_Invalid)
{
m_tmp = 1;
if (asn1_encoded_data.size() < 2)
{
printf("not enough data to form an object\n");
return;
}
uint8_t sizeByte = asn1_encoded_data[1];
size_t size = 0;
if (sizeByte & 0x80)
{
sizeByte &= 0x7F;
if (asn1_encoded_data.size() < (sizeByte + 2))
{
printf("not enough data to decode the size bytes %i (data size: %li)\n", sizeByte, asn1_encoded_data.size());
return;
}
for (int i = 0; i < sizeByte; i++)
{
size <<= 8;
size |= asn1_encoded_data[2 + i];
}
if (asn1_encoded_data.size() < (sizeByte + 2 + size))
{
printf("not enough data to decode an object of size %li (data size: %li)\n", size, asn1_encoded_data.size());
return;
}
}
else
{
size = sizeByte;
if (asn1_encoded_data.size() < (size + 2))
{
printf("not enough data to decode a small object of size %li (data size: %li)\n", size, asn1_encoded_data.size());
return;
}
sizeByte = 0;
}
m_tmp = 2 + sizeByte;
// Copy the data
m_data.resize(size);
memcpy(&m_data[0], &asn1_encoded_data[sizeByte + 2], size);
// Set the type
m_type = (ASN1Type)asn1_encoded_data[0];
if (m_type == ASN1_Sequence || m_type == ASN1_Set)
{
size_t sizeRemaining = size;
size_t offset = 0;
while (sizeRemaining)
{
std::vector<uint8_t> data;
data.resize(sizeRemaining);
memcpy(&data[0], &m_data[offset], sizeRemaining);
ASN1Object child(data);
if (child.m_type == ASN1_Invalid)
{
printf("error with decoding the children of sequence or set\n");
return;
}
m_children.push_back(child);
sizeRemaining -= child.m_data.size() + child.m_tmp;
offset += child.m_data.size() + child.m_tmp;
}
}
}
void ASN1Object::Print(int indent) const
{
const char* ASN1TypeNames[0x32] = {
"INVALID", "BOOLEAN", "INTEGER", "BIT_STRING", "OCTET_STRING", "NULL", "OBJECT_ID",
0, 0, 0, 0, 0, "UTF8String", 0, 0, 0, 0, 0, 0, "PrintableString", "TeletexString",
0, "IA5String", 0, 0, 0, 0, 0, 0, 0, "BMPString", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, "SEQUENCE", "SET"
};
// Encoded Length:
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb648641(v=vs.85).aspx
// if len < 128, single byte, otherwise it is bit 7 + sizeof(len), followed by len
const char* typeName = 0;
if (m_type >= 0 && m_type < 0x32)
{
typeName = ASN1TypeNames[m_type];
}
if (!typeName)
{
printf("invalid type: %i\n", m_type);
return;
}
for (int i = 0; i < indent; i++)
printf(" ");
printf("Type: %s, Size: %li\n", typeName, m_data.size());
if (m_type == ASN1_Sequence || m_type == ASN1_Set)
for (const ASN1Object& obj: m_children)
obj.Print(indent + 2);
}