ASN.1 Byteorder

24.08.2019

Heute schreibe ich einmal einen Knowledge-Base Eintrag der maximal eine der fünf Personen, die sich bisher auf meine Homepage verirrt haben, interessiert 1. Es geht um die Kodierung von Längenwerten in ASN.1. Um jetzt nicht auch noch meinen letzten Leser zu verlieren, muss ich etwas ausholen:

Was ist ASN.1

ASN.1 wurde im Jahr 1984 als gemeinsamer Standard von ITU und ISO/IEC geschaffen. Schon damals war es schwierig Daten zwischen unterschiedlichen Systemen auszutauschen. Jedes System verwendete unterschiedliche Kodierungen und das machte die Kommunikaton kompliziert. ASN.1 definiert eine Beschreibungssprache mit der Informationen über die Struktur von Daten ausgetauscht werden können. Verschiedene Kodierungsvorschriften (BER, DER und CER) legen exakt fest, wie die Daten auf Bit-Ebene übertragen werden müssen, so dass alle Systeme sie, unabhängig von der konkreten Implementierung der Software, dekodieren können.

Seit 1988 ist ASN.1 ein eigenständiger Standard: X.208. Der Standard wurde 1995 nochmals umfassend überarbeitet und ist jetzt in der X.680 Standards-Serie dokumentiert. Die Kodierungsvorschriften sind im der Standards-Serie X.690 beschrieben. Der entsprechende ISO-Standard heißen ISO 88242.

Tag, Length, Value

Die Kodierung von ASN.1 ist ein sog. TLV-Format. TLV steht für Tag, Length, Value also Markierung (oder Typ), Länge und Wert. D. h. eine ASN.1 Struktur ist ein Datenstrom, in welchem einzelne Datenelemente aufeinander folgen. Jedes Datenelement beginnt mit einer Typenmarkierung und einer Längenangabe. Nach dieser Längenangabe folgen die zu diesem Datenelement gehörenden Daten. Es gibt auch Datenelement, welche weitere Datenelemente enthalten (Sequenzen oder Sets). Hierdurch lassen sich Blöcke schachteln und komplexe Strukturen und Datentypen aufbauen. Die Struktur sieht also im allgemeinen folgendermaßen aus:

TLV-Struktur

Im ASN.1-Standards werden folgen von Bytes immer als Oktets bezeichnet.

Für das Identifier-Oktet beschreibt X.690 (Basic Encoding Rules) Kapitel 8.1.2 exakt wie eines oder mehrere Bytes kodiert werden müssen. Auch wo das höst- und das niederwertigste Bit zu stehen haben ist dort definiert.

Beim Längen-Oktet gibt es zwei Kodierungen. Eine kurze und eine lange. Die kurze Kodierung muss für Inhalte verwendet werden, die kürzer als 128 Oktets (Bytes) sind. Sind die Inhalte länger, muss die Kodierung nach Kapitel 8.1.3.5 verwendet werden. Soll eine Länge von mehr als 127 Oktets kodiert werden, wird die Länge des Längen-Oktets im ersten Oktet des Längen-Feldes gespeichert. Dabei wird das MSB auf 1 gesetzt. Die Bits 0-7 kodieren dann, wie viele Bytes folgen, wobei niemals alle Bits auf 1 gesetzt werden dürfen. Es können also maximal 126 Oktets für das Kodieren der Länge der Daten verwendet werden.

Eine Frage lässt die Dokumentation an dieser stelle jedoch offen: Welche Bytereihenfolge (Endianess) muss für das kodieren der Länge verwendet werden. Sobald die Länge größer als 255 wird, ist mehr als ein Oktet notwendig und die Byterehenfolge spielt eine Rolle.

Kurzes oder langes Ende?

Leider legen die ASN.1 Encoding Rules keine globale Bytereihenfolge fest. Für das Längenfeld wird in Kapitel 8.1.3.5 einfach gesagt:

...shall be the encoding of an unsigned binary integer equal to the number of octets in the contents octets... X.690 08/2015

Das ist jetzt ausgesprochen wage, da nirgends festgelegt wird, wie ein “unsigned binary integer” kodiert werden soll. Ein Hinweis findet sich in Kapitel 8.3.3 bei der Kodierung von Integer-Werten in einer Notiz:

The value of a two's complement binary number is derived by numbering the bits in the contents octets, starting with bit 1 of the last octet as bit zero and ending the numbering with bit 8 of the first octet. Each bit is assigned a numerical value of 2N , where N is its position in the above numbering sequence. The value of the two's complement binary number is obtained by summing the numerical values assigned to each bit for those bits which are set to one, excluding bit 8 of the first octet, and then reducing this value by the numerical value assigned to bit 8 of the first octet if that bit is set to one. X.690 08/2015

Auch wenn es hier um Integer-Werte mit Vorzeichen geht, hilft uns das weiter: Die Bits sollen von Bit 1 (LSB) im letzten Oktet zu Bit 8 (MSB) im ersten Oktet durchnummerriert werden. Jedes auf 1 gesetzte Bit ist dann 2n Wert. Also haben wir es hier mit einer Big-Endian3-Kodierung zu tun. Probiert man es aus, ist dies auch tatsächlich so.

Es ist also leider etwas Interpretation nötig um der Lösung auf die Spur zu kommen Aber jetzt habe ich es aufgeschrieben und falls mal wieder jemand Fragt, brauche ich nur den Link zu verschicken.


  1. Hallo Michael :) ↩︎

  2. …und ist natürlich Kostenpflichtig. ↩︎

  3. Big-Endian bedeutet, dass das höchstwertige Byte an der niedrigsten Adresse gespeichert wird. In einem Datenstrom wird das höchstwertige Byte zuerst übertragen. Das dicke Ende des Wertes kommt also zuerst. ↩︎