modul OpenSSL::ASN1
Abstract Syntax Notation One (oder ASN.1) ist eine Notationssyntax zur Beschreibung von Datenstrukturen und ist in ITU-T X.680 definiert. ASN.1 selbst schreibt keine Kodierungs- oder Parsing-Regeln vor, aber normalerweise werden ASN.1-Datenstrukturen mit den Distinguished Encoding Rules (DER) oder seltener mit den Basic Encoding Rules (BER) kodiert, die in ITU-T X.690 beschrieben sind. DER- und BER-Kodierungen sind binäre Tag-Length-Value (TLV) Kodierungen, die im Vergleich zu anderen gängigen Datenbeschreibungsformaten wie XML, JSON usw. recht prägnant sind. ASN.1-Datenstrukturen sind in kryptografischen Anwendungen sehr verbreitet, z. B. sind X.509-öffentliche Schlüsselzertifikate oder Zertifikatsperrlisten (CRLs) alle in ASN.1 definiert und DER-kodiert. ASN.1, DER und BER sind die Bausteine der angewandten Kryptografie. Das ASN1 Modul stellt die notwendigen Klassen bereit, die die Erzeugung von ASN.1-Datenstrukturen und die Methoden zu deren Kodierung mittels DER-Kodierung ermöglichen. Die decode-Methode erlaubt das Parsen beliebiger BER-/DER-kodierter Daten in ein Ruby-Objekt, das dann nach Belieben modifiziert und neu kodiert werden kann.
ASN.1-Klassen-Hierarchie
Die Basisklasse für ASN.1-Strukturen ist ASN1Data. ASN1Data bietet Attribute zum Lesen und Setzen des Tags, der Tag-Klasse und schließlich des Wertes eines bestimmten ASN.1-Elements. Beim Parsen werden alle getaggten Werte (implizit oder explizit) durch ASN1Data-Instanzen repräsentiert, da ihr „echter Typ“ nur mithilfe von Out-of-Band-Informationen aus der ASN.1-Typdeklaration ermittelt werden kann. Da diese Information normalerweise beim Kodieren eines Typs bekannt ist, bieten alle Unterklassen von ASN1Data ein zusätzliches Attribut tagging, das es ermöglicht, einen Wert implizit (:IMPLICIT) oder explizit (:EXPLICIT) zu kodieren.
Constructive
Constructive ist, wie der Name schon sagt, die Basisklasse für alle konstruierten Kodierungen, d. h. solche, die aus mehreren Werten bestehen, im Gegensatz zu „primitiven“ Kodierungen mit nur einem einzigen Wert. Der Wert eines Constructive ist immer ein Array.
ASN1::Set und ASN1::Sequence
Die gebräuchlichsten konstruierten Kodierungen sind SETs und SEQUENCEs, weshalb es zwei Unterklassen von Constructive gibt, die jeweils eine davon repräsentieren.
Primitive
Dies ist die Oberklasse aller primitiven Werte. Primitive selbst wird beim Parsen von ASN.1-Daten nicht verwendet. Alle Werte sind entweder Instanzen einer entsprechenden Unterklasse von Primitive oder Instanzen von ASN1Data, wenn der Wert implizit oder explizit getaggt war. Bitte siehe Primitive Dokumentation für Details zu Unterklassen und deren jeweilige Abbildungen von ASN.1-Datentypen auf Ruby-Objekte.
Mögliche Werte für tagging
Beim Erstellen eines ASN1Data-Objekts kann die ASN.1-Typdefinition erfordern, dass bestimmte Elemente entweder implizit oder explizit getaggt werden. Dies kann durch manuelles Setzen des tagging-Attributs für Unterklassen von ASN1Data erreicht werden. Verwenden Sie das Symbol :IMPLICIT für implizites Tagging und :EXPLICIT, wenn das Element explizites Tagging erfordert.
Mögliche Werte für tag_class
Es ist möglich, beliebige ASN1Data-Objekte zu erstellen, die auch eine PRIVATE- oder APPLICATION-Tag-Klasse unterstützen. Mögliche Werte für das tag_class-Attribut sind:
-
:UNIVERSAL(der Standard für ungetaggte Werte) -
:CONTEXT_SPECIFIC(der Standard für getaggte Werte) -
:APPLICATION -
:PRIVATE
Tag-Konstanten
Für jeden universellen Tag ist eine Konstante definiert
-
OpenSSL::ASN1::EOC (0)
-
OpenSSL::ASN1::BOOLEAN (1)
-
OpenSSL::ASN1::INTEGER (2)
-
OpenSSL::ASN1::BIT_STRING (3)
-
OpenSSL::ASN1::OCTET_STRING (4)
-
OpenSSL::ASN1::NULL (5)
-
OpenSSL::ASN1::OBJECT (6)
-
OpenSSL::ASN1::ENUMERATED (10)
-
OpenSSL::ASN1::UTF8STRING (12)
-
OpenSSL::ASN1::SEQUENCE (16)
-
OpenSSL::ASN1::SET (17)
-
OpenSSL::ASN1::NUMERICSTRING (18)
-
OpenSSL::ASN1::PRINTABLESTRING (19)
-
OpenSSL::ASN1::T61STRING (20)
-
OpenSSL::ASN1::VIDEOTEXSTRING (21)
-
OpenSSL::ASN1::IA5STRING (22)
-
OpenSSL::ASN1::UTCTIME (23)
-
OpenSSL::ASN1::GENERALIZEDTIME (24)
-
OpenSSL::ASN1::GRAPHICSTRING (25)
-
OpenSSL::ASN1::ISO64STRING (26)
-
OpenSSL::ASN1::GENERALSTRING (27)
-
OpenSSL::ASN1::UNIVERSALSTRING (28)
-
OpenSSL::ASN1::BMPSTRING (30)
UNIVERSAL_TAG_NAME Konstante
Ein Array, das den Namen einer gegebenen Tag-Nummer speichert. Diese Namen sind dieselben wie der Name der zusätzlich definierten Tag-Konstante, z. B. UNIVERSAL_TAG_NAME[2] = "INTEGER" und OpenSSL::ASN1::INTEGER = 2.
Beispielverwendung
Dekodieren und Anzeigen einer DER-kodierten Datei
require 'openssl' require 'pp' der = File.binread('data.der') asn1 = OpenSSL::ASN1.decode(der) pp der
Erstellen einer ASN.1-Struktur und deren DER-Kodierung
require 'openssl' version = OpenSSL::ASN1::Integer.new(1) # Explicitly 0-tagged implies context-specific tag class serial = OpenSSL::ASN1::Integer.new(12345, 0, :EXPLICIT, :CONTEXT_SPECIFIC) name = OpenSSL::ASN1::PrintableString.new('Data 1') sequence = OpenSSL::ASN1::Sequence.new( [ version, serial, name ] ) der = sequence.to_der
Constants
- UNIVERSAL_TAG_NAME
-
Array, das Tag-Namen am Index des Tags speichert.
Öffentliche Klassenmethoden
Source
static VALUE
ossl_asn1_decode(VALUE self, VALUE obj)
{
VALUE ret;
unsigned char *p;
VALUE tmp;
long len, read = 0, offset = 0;
obj = ossl_to_der_if_possible(obj);
tmp = rb_str_new4(StringValue(obj));
p = (unsigned char *)RSTRING_PTR(tmp);
len = RSTRING_LEN(tmp);
ret = ossl_asn1_decode0(&p, len, &offset, 0, 0, &read);
RB_GC_GUARD(tmp);
int_ossl_decode_sanity_check(len, read, offset);
return ret;
}
Source
static VALUE
ossl_asn1_decode_all(VALUE self, VALUE obj)
{
VALUE ary, val;
unsigned char *p;
long len, tmp_len = 0, read = 0, offset = 0;
VALUE tmp;
obj = ossl_to_der_if_possible(obj);
tmp = rb_str_new4(StringValue(obj));
p = (unsigned char *)RSTRING_PTR(tmp);
len = RSTRING_LEN(tmp);
tmp_len = len;
ary = rb_ary_new();
while (tmp_len > 0) {
long tmp_read = 0;
val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
rb_ary_push(ary, val);
read += tmp_read;
tmp_len -= tmp_read;
}
RB_GC_GUARD(tmp);
int_ossl_decode_sanity_check(len, read, offset);
return ary;
}
Ähnlich wie decode, mit dem Unterschied, dass decode einen einzelnen, deutlichen Wert erwartet, der in der dargestellt ist. decode_all dekodiert dagegen eine Sequenz von sequenziellen BER/DER-Werten, die in der aufgereiht sind, und gibt sie als Array zurück.
Beispiel
ders = File.binread('asn1data_seq') asn1_ary = OpenSSL::ASN1.decode_all(ders)
Source
static VALUE
ossl_asn1_traverse(VALUE self, VALUE obj)
{
unsigned char *p;
VALUE tmp;
long len, read = 0, offset = 0;
obj = ossl_to_der_if_possible(obj);
tmp = rb_str_new4(StringValue(obj));
p = (unsigned char *)RSTRING_PTR(tmp);
len = RSTRING_LEN(tmp);
ossl_asn1_decode0(&p, len, &offset, 0, 1, &read);
RB_GC_GUARD(tmp);
int_ossl_decode_sanity_check(len, read, offset);
return Qnil;
}
Wenn ein Block gegeben ist, gibt er jedes der angetroffenen Elemente aus. Blockparameter sind (in dieser Reihenfolge)
-
depth: Die Rekursionstiefe, plus eins für jeden angetroffenen konstruierten Wert (
Integer) -
offset: Aktueller Byte-Offset (
Integer) -
header length: Kombinierte Länge in Bytes der Tag- und Längen-Header. (
Integer) -
length: Die gesamte verbleibende Länge der gesamten Daten (
Integer) -
constructed: Ob dieser Wert konstruiert ist oder nicht (Boolean)
-
tag_class: Aktuelle Tag-Klasse (
Symbol) -
tag: Die aktuelle Tag-Nummer (
Integer)
Beispiel
der = File.binread('asn1data.der') OpenSSL::ASN1.traverse(der) do | depth, offset, header_len, length, constructed, tag_class, tag| puts "Depth: #{depth} Offset: #{offset} Length: #{length}" puts "Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}" end