ASN.1 (Abstract Syntax Notation One) DER (Distinguished Encoding Rules) is a standard-backed serialization scheme used in many different use-cases. Particularly popular usage scenarios are X.509 certificates and some telecommunication / networking protocols.
DER is self-describing encoding scheme which allows representation of simple, atomic data elements, such as strings and numbers, and complex objects, such as sequences of other elements.
DER is a subset of BER (Basic Encoding Rules), with an emphasis on being non-ambiguous: there's always exactly one canonical way to encode a data structure defined in terms of ASN.1 using DER.
This spec allows full parsing of format syntax, but to understand the semantics, one would typically require a dictionary of Object Identifiers (OIDs), to match OID bodies against some human-readable list of constants. OIDs are covered by many different standards, so typically it's simpler to use a pre-compiled list of them, such as:
This page hosts a formal specification of ASN.1 DER (Abstract Syntax Notation One, Distinguished Encoding Rules) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
digraph {
rankdir=LR;
node [shape=plaintext];
subgraph cluster__asn1_der {
label="Asn1Der";
graph[style=dotted];
asn1_der__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="type_tag_pos">0</TD><TD PORT="type_tag_size">1</TD><TD>u1→TypeTag</TD><TD PORT="type_tag_type">type_tag</TD></TR>
<TR><TD PORT="len_pos">1</TD><TD PORT="len_size">4</TD><TD>LenEncoded</TD><TD PORT="len_type">len</TD></TR>
<TR><TD PORT="body_pos">5</TD><TD PORT="body_size">...</TD><TD>switch (type_tag)</TD><TD PORT="body_type">body</TD></TR>
</TABLE>>];
asn1_der__seq_body_switch [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#F0F2E4">case</TD><TD BGCOLOR="#F0F2E4">type</TD></TR>
<TR><TD>:type_tag_printable_string</TD><TD PORT="case0">BodyPrintableString</TD></TR>
<TR><TD>:type_tag_sequence_10</TD><TD PORT="case1">BodySequence</TD></TR>
<TR><TD>:type_tag_set</TD><TD PORT="case2">BodySequence</TD></TR>
<TR><TD>:type_tag_sequence_30</TD><TD PORT="case3">BodySequence</TD></TR>
<TR><TD>:type_tag_utf8string</TD><TD PORT="case4">BodyUtf8string</TD></TR>
<TR><TD>:type_tag_object_id</TD><TD PORT="case5">BodyObjectId</TD></TR>
</TABLE>>];
subgraph cluster__body_sequence {
label="Asn1Der::BodySequence";
graph[style=dotted];
body_sequence__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="entries_pos">0</TD><TD PORT="entries_size">...</TD><TD>Asn1Der</TD><TD PORT="entries_type">entries</TD></TR>
<TR><TD COLSPAN="4" PORT="entries__repeat">repeat to end of stream</TD></TR>
</TABLE>>];
}
subgraph cluster__body_utf8string {
label="Asn1Der::BodyUtf8string";
graph[style=dotted];
body_utf8string__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="str_pos">0</TD><TD PORT="str_size">⇲</TD><TD>str(UTF-8)</TD><TD PORT="str_type">str</TD></TR>
</TABLE>>];
}
subgraph cluster__body_object_id {
label="Asn1Der::BodyObjectId";
graph[style=dotted];
body_object_id__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="first_and_second_pos">0</TD><TD PORT="first_and_second_size">1</TD><TD>u1</TD><TD PORT="first_and_second_type">first_and_second</TD></TR>
<TR><TD PORT="rest_pos">1</TD><TD PORT="rest_size">⇲</TD><TD></TD><TD PORT="rest_type">rest</TD></TR>
</TABLE>>];
body_object_id__inst__first [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>first</TD><TD>(first_and_second / 40)</TD></TR>
</TABLE>>];
body_object_id__inst__second [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>second</TD><TD>(first_and_second % 40)</TD></TR>
</TABLE>>];
}
subgraph cluster__len_encoded {
label="Asn1Der::LenEncoded";
graph[style=dotted];
len_encoded__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="b1_pos">0</TD><TD PORT="b1_size">1</TD><TD>u1</TD><TD PORT="b1_type">b1</TD></TR>
<TR><TD PORT="int2_pos">1</TD><TD PORT="int2_size">2</TD><TD>u2be</TD><TD PORT="int2_type">int2</TD></TR>
<TR><TD PORT="int1_pos">3</TD><TD PORT="int1_size">1</TD><TD>u1</TD><TD PORT="int1_type">int1</TD></TR>
</TABLE>>];
len_encoded__inst__result [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>result</TD><TD>(b1 == 129 ? int1 : (b1 == 130 ? int2 : b1))</TD></TR>
</TABLE>>];
}
subgraph cluster__body_printable_string {
label="Asn1Der::BodyPrintableString";
graph[style=dotted];
body_printable_string__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="str_pos">0</TD><TD PORT="str_size">⇲</TD><TD>str(ASCII)</TD><TD PORT="str_type">str</TD></TR>
</TABLE>>];
}
}
asn1_der__seq:len_type -> len_encoded__seq [style=bold];
asn1_der__seq:body_type -> asn1_der__seq_body_switch [style=bold];
asn1_der__seq_body_switch:case0 -> body_printable_string__seq [style=bold];
asn1_der__seq_body_switch:case1 -> body_sequence__seq [style=bold];
asn1_der__seq_body_switch:case2 -> body_sequence__seq [style=bold];
asn1_der__seq_body_switch:case3 -> body_sequence__seq [style=bold];
asn1_der__seq_body_switch:case4 -> body_utf8string__seq [style=bold];
asn1_der__seq_body_switch:case5 -> body_object_id__seq [style=bold];
asn1_der__seq:type_tag_type -> asn1_der__seq:body_type [color="#404040"];
body_sequence__seq:entries_type -> asn1_der__seq [style=bold];
body_object_id__seq:first_and_second_type -> body_object_id__inst__first [color="#404040"];
body_object_id__seq:first_and_second_type -> body_object_id__inst__second [color="#404040"];
len_encoded__seq:b1_type -> len_encoded__inst__result [color="#404040"];
len_encoded__seq:int1_type -> len_encoded__inst__result [color="#404040"];
len_encoded__seq:b1_type -> len_encoded__inst__result [color="#404040"];
len_encoded__seq:int2_type -> len_encoded__inst__result [color="#404040"];
len_encoded__seq:b1_type -> len_encoded__inst__result [color="#404040"];
}