PyDERASN: wie ich eine ASN.1-Bibliothek mit Slots und Blobs geschrieben habe

ASN.1 dies ist ein Standard (ISO, ITU-T, GOST) der Sprache, die strukturierte Informationen beschreibt, sowie der Regeln zur Kodierung dieser Informationen. FĂŒr mich als Programmierer ist es einfach ein weiteres Format zur Serialisierung und Darstellung von Daten, gleichwertig mit JSON, XML, XDR und anderen. Es ist Ă€ußerst verbreitet in unserem tĂ€glichen Leben, und viele Menschen begegnen ihm: in der Mobil-, Festnetz-, VoIP-Kommunikation (UMTS, LTE, WiMAX, SS7, H.323), in Netzprotokollen (LDAP, SNMP, Kerberos), in allem, was die Kryptographie betrifft (X.509, CMS, PKCS-Standards), in Bankkarten und biometrischen PĂ€ssen, und vieles mehr.

In diesem Artikel wird PyDERASN: eine Python ASN.1-Bibliothek, die aktiv in Projekten verwendet wird, die mit Kryptographie in Atlas.

PyDERASN: wie ich eine ASN.1-Bibliothek mit Slots und Blobs geschrieben habe
Im Allgemeinen sollte man ASN.1 fĂŒr kryptographische Aufgaben nicht empfehlen: ASN.1 und seine Codecs sind komplex. Das bedeutet, dass der Code nicht einfach sein wird, und das ist immer ein zusĂ€tzlicher Angriffsvektor. GenĂŒgt es, einen Blick darauf zu werfen auf die Liste der Schwachstellen in ASN.1-Bibliotheken. Bruce Schneier rĂ€t in seiner Cryptography Engineering auch von der Verwendung dieses Standards aufgrund seiner KomplexitĂ€t ab: „Die bekannteste TLV-Kodierung ist ASN.1, aber sie ist unglaublich komplex und wir scheuen uns davor.“ Leider haben wir heute jedoch Infrastrukturen öffentlicher SchlĂŒssel in denen aktiv X.509-Zertifikate, CRL, OCSP, TSP, CMP-Protokolle, CMC, Nachrichten CMS, und viele Standards PKCS. Daher muss man mit ASN.1 umgehen können, wenn man sich mit etwas beschĂ€ftigt, das mit Kryptographie zu tun hat.

ASN.1 kann auf viele Arten / Codecs kodiert werden:

  • BER (Basic Encoding Rules)
  • CER (Canonical Encoding Rules)
  • DER (Distinguished Encoding Rules)
  • GSER (Generic String Encoding Rules)
  • JER (JSON Encoding Rules)
  • LWER (Light Weight Encoding Rules)
  • OER (Octet Encoding Rules)
  • PER (Packed Encoding Rules)
  • SER (Signalling specific Encoding Rules)
  • XER (XML Encoding Rules)

und einigen anderen. In kryptographischen Fragen werden in der Praxis jedoch zwei verwendet: BER und DER. Selbst in signierten XML-Dokumenten (XMLDSig, XAdES) werden dennoch Base64-kodierte ASN.1 DER-Objekte vorhanden sein, wie auch im JSON-orientierten Protokoll ACME von Let’s Encrypt. Es ist besser, sich mit all diesen Codecs und Prinzipien der Kodierung BER / CER / DER in Artikeln und BĂŒchern auseinanderzusetzen: ASN.1 einfach erklĂ€rt, ASN.1 — Kommunikation zwischen heterogenen Systemen von Olivier Dubuisson, ASN.1 Komplett von Prof. John Larmouth.

BER ist ein binÀres Byte-orientiertes (z.B. PER, das in der Mobilkommunikation beliebt ist - bit-orientiert) TLV-Format. Jedes Element wird in Form von: Tag kodiert (Tag), identifizierend den Typ des kodierten Elements (Ganzzahl, Zeichenfolge, Datum usw.), LÀnge (Length) des Inhalts und des eigentlichen Inhalts (Value). BER ermöglicht optional das Weglassen des LÀngenwerts, indem ein spezieller unbestimmter LÀngenwert festgelegt wird und die Nachricht mit dem End-Of-Octets-Tag endet. Neben der Kodierung der LÀnge gibt es in BER viele Variationen in der Art und Weise, wie Datentypen kodiert werden, wie zum Beispiel:

  • INTEGER, OBJECT IDENTIFIER, BIT STRING und die LĂ€nge des Elements kann unnormalisiert (nicht in minimaler Form kodiert) sein;
  • BOOLEAN ist wahr, wenn der Inhalt ungleich null ist;
  • BIT STRING kann "ĂŒberflĂŒssige" Null-Bits enthalten;
  • BIT STRING, OCTET STRING und alle ihre abgeleiteten Zeichenfolgen-Typen, einschließlich Datum/Zeit, können in variable StĂŒcke (Chunks) aufgeteilt werden, deren LĂ€nge beim (De)kodieren im Voraus nicht bekannt ist;
  • UTCTime/GeneralizedTime können unterschiedliche Methoden zur Angabe der Zeitverschiebung und "ĂŒberflĂŒssige" Nullteile von Sekunden haben;
  • DEFAULT-Werte SEQUENCE können kodiert werden, mĂŒssen aber nicht;
  • Benannte Werte der letzten Bits in BIT STRING können nach Wunsch nicht kodiert werden;
  • SEQUENCE (OF)/SET (OF) können eine beliebige Reihenfolge der Elemente haben.

Aufgrund all dieser genannten Punkte ist es nicht immer möglich, Daten so zu kodieren, dass sie identisch zur Originalform sind. Daher wurde eine Teilmenge von Regeln entwickelt: DER - strikt regulierend, nur einen zulĂ€ssigen Kodierungsweg zulĂ€ssig, was fĂŒr kryptografische Aufgaben entscheidend ist, da z.B. die Änderung eines Bits die Signatur oder PrĂŒfziffer ungĂŒltig macht. DER hat einen wesentlichen Nachteil: die LĂ€ngen aller Elemente mĂŒssen wĂ€hrend der Kodierung im Voraus bekannt sein, was eine strömende Serialisierung der Daten nicht erlaubt. Der CER-Codec hat diesen Nachteil nicht, da er ebenfalls eine eindeutige Darstellung der Daten garantiert. Leider (oder GlĂŒck, dass wir noch keine komplizierteren Dekoder haben?) wurde er nicht populĂ€r. Daher finden wir in der Praxis eine "gemischte" Verwendung von BER- und DER-kodierten Daten. Da sowohl CER als auch DER Teilmengen von BER sind, kann jeder BER-Dekoder sie verarbeiten.

Probleme mit pyasn1

Bei der Arbeit schreiben wir viele Programme in Python, die mit Kryptografie zu tun haben. Vor einigen Jahren gab es praktisch keine Auswahl an freien Bibliotheken: Entweder sind es sehr low-level Bibliotheken, die einfach nur kodieren/dekodieren, zum Beispiel eine ganze Zahl und den Header einer Struktur, oder es ist die Bibliothek pyasn1. Damit haben wir einige Jahre gearbeitet und waren anfangs sehr zufrieden, da sie es ermöglicht, mit ASN.1-Strukturen wie mit hochgradigen Objekten zu arbeiten: Zum Beispiel erlaubt das dekodierte Objekt eines X.509-Zertifikats den Zugriff auf seine Felder ĂŒber ein Wörterbuch-Interface: cert[«tbsCertificate»][«serialNumber»] zeigt uns die Seriennummer dieses Zertifikats an. Analog dazu kann man komplexe Objekte „aufbauen“, indem man mit ihnen wie mit Listen und Dictionaries arbeitet und anschließend einfach die Funktion pyasn1.codec.der.encoder.encode aufruft, um die serialisierte Darstellung des Dokuments zu erhalten.

Allerdings traten MĂ€ngel, Probleme und EinschrĂ€nkungen auf. In pyasn1 gab es und gibt es leider immer noch Fehler: Zum Zeitpunkt des Schreibens dieses Artikels wird einer der Basisdatentypen — GeneralizedTime, falsch dekodiert und kodiert.

In unseren Projekten speichern wir zur Einsparung von Platz oft nur den Pfad zur Datei, die Verschiebung und die LÀnge in Bytes des Objekts, auf das wir verweisen möchten. Zum Beispiel wird eine beliebige signierte Datei mit Sicherheit in einer CMS SignedData ASN.1 Struktur zu finden sein:

  0     [1,3,1018]  ContentInfo SEQUENCE
  4     [1,1,   9]   . contentType: ContentType OBJECT IDENTIFIER 1.2.840.113549.1.7.2 (id_signedData)
 19-4   [0,0,1003]   . content: [0] EXPLICIT [UNIV 16] ANY
 19     [1,3, 999]   . . DEFINED BY id_signedData: SignedData SEQUENCE
 23     [1,1,   1]   . . . version: CMSVersion INTEGER v3 (03)
 26     [1,1,  19]   . . . digestAlgorithms: DigestAlgorithmIdentifiers SET OF
                           [...]
 47     [1,3, 769]   . . . encapContentInfo: EncapsulatedContentInfo SEQUENCE
 51     [1,1,   8]   . . . . eContentType: ContentType OBJECT IDENTIFIER 1.3.6.1.5.5.7.12.2 (id_cct_PKIData)
 65-4   [1,3, 751]   . . . . eContent: [0] EXPLICIT OCTET STRING 751 bytes OPTIONAL

                 HIER IST DER INHALT DER ZUGESICHERTEN DATEI MIT EINER GRÖSSE VON 751 BYTE

820     [1,2, 199]   . . . signerInfos: SignerInfos SET OF
823     [1,2, 196]   . . . . 0: SignerInfo SEQUENCE
826     [1,1,   1]   . . . . . version: CMSVersion INTEGER v3 (03)
829     [0,0,  22]   . . . . . sid: SignerIdentifier CHOICE subjectKeyIdentifier
                               [...]
956     [1,1,  64]   . . . . . signature: SignatureValue OCTET STRING 64 bytes
                     . . . . . . C1:B3:88:BA:F8:92:1C:E6:3E:41:9B:E0:D3:E9:AF:D8
                     . . . . . . 47:4A:8A:9D:94:5D:56:6B:F0:C1:20:38:D2:72:22:12
                     . . . . . . 9F:76:46:F6:51:5F:9A:8D:BF:D7:A6:9B:FD:C5:DA:D2
                     . . . . . . F3:6B:00:14:A4:9D:D7:B5:E1:A6:86:44:86:A7:E8:C9

Und wir können die originale signierte Datei mit einer Verschiebung von 65 Bytes und einer LĂ€nge von 751 Bytes abrufen. pyasn1 speichert diese Informationen nicht in seinen dekodierten Objekten. Eine sogenannte TLVSeeker-Bibliothek wurde erstellt – eine kleine Bibliothek, die es ermöglicht, Tags und LĂ€ngen von Objekten zu dekodieren, mit einem Interface, in dem wir Befehle wie 'wechsle zum nĂ€chsten Tag', 'gehe in den Tag hinein' (wir gehen in den SEQUENCE-Objekt hinein), 'gehe zum nĂ€chsten Tag', 'melde deinen Offset und die LĂ€nge des Objekts, wo wir uns befinden' gegeben haben. Dies war eine 'manuelle' Navigation durch ASN.1 DER-serialisierte Daten. Aber so konnte man nicht mit BER-serialisierten Daten arbeiten, da beispielsweise eine Bytefolge OCTET STRING in Form mehrerer Chunks codiert sein konnte.

Ein weiterer Nachteil fĂŒr unsere Aufgaben ist die UnfĂ€higkeit von pyasn1, aus den dekodierten Objekten zu erkennen, ob ein bestimmtes Feld in der SEQUENCE vorhanden war oder nicht. Wenn die Struktur zum Beispiel das Feld Field SEQUENCE OF Smth OPTIONAL enthĂ€lt, könnte es in den empfangenen Daten komplett fehlen (OPTIONAL) oder vorhanden sein, jedoch eine LĂ€nge von null aufweisen (leere Liste). Im Allgemeinen konnte dies nicht festgestellt werden. Das ist jedoch notwendig fĂŒr eine strikte Validierung der eingehenden Daten. Stellen Sie sich vor, ein Zertifizierungsstelle hĂ€tte ein Zertifikat mit aus ASN.1-Schema-Sicht 'nicht ganz' gĂŒltigen Daten ausgestaltet! Zum Beispiel hat die Zertifizierungsstelle 'TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı' in ihrem Root-Zertifikat die zulĂ€ssigen Grenzen ĂŒberschritten. RFC 5280 LĂ€ngenbeschrĂ€nkungen des subject-Komponenten - es ist nicht ehrlich möglich, sie nach dem Schema zu dekodieren. DER-Codec erfordert, dass ein Feld, dessen Wert gleich dem DEFAULT ist, bei der Übertragung nicht kodiert wird - solche Dokumente begegnen einem im echten Leben, und die erste Version von PyDERASN erlaubte ganz bewusst ein solches nicht valides (nach DER) Verhalten, um die AbwĂ€rtskompatibilitĂ€t zu wahren.

Eine weitere EinschrĂ€nkung ist die Unmöglichkeit, leicht zu erkennen, in welchem Format (BER/DER) ein bestimmtes Objekt in der Struktur codiert wurde. Zum Beispiel besagt der CMS-Standard, dass die Nachricht in BER codiert ist, aber das Feld signedAttrs, fĂŒr das die kryptografische Signatur erstellt wird, muss in DER vorliegen. Wenn wir in DER dekodieren, erhalten wir Probleme bei der Verarbeitung der CMS selbst; wenn wir in BER dekodieren, wissen wir nicht, in welchem Format signedAttrs vorlag. Letztendlich mĂŒssen wir mit TLVSeeker (einem Pendant, das es in pyasn1 nicht gibt) die Position jedes der signedAttrs-Felder suchen und diese separat aus der serialisierten Darstellung in DER dekodieren.

Wir hĂ€tten uns sehr gewĂŒnscht, dass die automatische Verarbeitung der DEFINED BY-Felder, die sehr hĂ€ufig vorkommen, möglich ist. Nach der Dekodierung der ASN.1-Struktur können viele ANY-Felder ĂŒbrig bleiben, die gemĂ€ĂŸ dem im Strukturfeld angegebenen OBJECT IDENTIFIER weiterverarbeitet werden mĂŒssen. In Python bedeutet dies, dass wir if-Anweisungen schreiben und den Decoder fĂŒr das ANY-Feld aufrufen mĂŒssen.

Die EinfĂŒhrung von PyDERASN

Im Atlas senden wir regelmĂ€ĂŸig, wenn wir auf Probleme stoßen oder verwendete Open-Source-Programme optimieren, Patches nach oben. In pyasn1 haben wir einige Male Verbesserungen eingereicht, aber der Code von pyasn1 ist nicht einfach zu verstehen, und manchmal gab es inkompatible API-Änderungen, die uns betroffen haben. Zudem sind wir es gewohnt, Tests mit generativem Testen zu schreiben, was in pyasn1 nicht vorhanden war.

Eines schönen Tages beschloss ich, dass es genug war, und es Zeit sei, eine eigene Bibliothek mit __slots__, Offsets und hervorragend darstellbaren Blobs zu schreiben! Nur einen ASN.1-Codec zu erstellen wĂ€re nicht ausreichend gewesen — wir mussten all unsere voneinander abhĂ€ngigen Projekte darauf umstellen, und das sind Hunderttausende von Codezeilen, in denen viel mit ASN.1-Strukturen gearbeitet wird. Ein weiteres Kriterium fĂŒr sie war, dass der aktuelle pyasn1-Code leicht portierbar sein sollte. Nachdem ich meinen gesamten Urlaub investiert hatte, schrieb ich diese Bibliothek und stellte alle Projekte darauf um. Da sie praktisch 100%-ige Testabdeckung haben, bedeutete das auch die vollstĂ€ndige FunktionalitĂ€t der Bibliothek.

PyDERASN hat Ă€hnlich eine nahezu 100%-ige Testabdeckung. Es wird generatives Testen mit einer großartigen Bibliothek eingesetzt, hypothesis. Außerdem wurde auch Fuzzing py-afl durchgefĂŒhrt.-em auf 32-Kern Maschinen. Trotz der Tatsache, dass wir praktisch keinen Python2-Code mehr haben, sorgt PyDERASN dennoch fĂŒr die KompatibilitĂ€t und hat deshalb eine einzige sechs AbhĂ€ngigkeit. DarĂŒber hinaus wurde es getestet gegenĂŒber ASN.1:2008 Compliance-Test-Suite.

Das Prinzip der Arbeit mit ihm Ă€hnelt pyasn1 – die Arbeit mit hochrangigen Python-Objekten. Die Beschreibung von ASN.1-Schemata ist Ă€hnlich.

class TBSCertificate(Sequence):
    schema = (
        ("version", Version(expl=tag_ctxc(0), default="v1")),
        ("serialNumber", CertificateSerialNumber()),
        ("signature", AlgorithmIdentifier()),
        ("issuer", Name()),
        ("validity", Validity()),
        ("subject", Name()),
        ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
        ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
        ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
        ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
    )

Jedoch hat PyDERASN eine Art strenger Typisierung. In pyasn1 konnte, wenn das Feld den Typ CMSVersion(INTEGER) hatte, ein int oder INTEGER zugewiesen werden. PyDERASN verlangt strikt, dass das zugewiesene Objekt genau CMSVersion ist. DarĂŒber hinaus, weil wir Python3-Code schreiben, verwenden wir auch Typanmerkungen, sodass in unseren Funktionen keine unklaren Argumente wie def func(serial, contents) vorhanden sind, sondern def func(serial: CertificateSerialNumber, contents: EncapsulatedContentInfo), und PyDERASN hilft, solchen Code einzuhalten.

Dabei gibt es in PyDERASN Ă€ußerst nĂŒtzliche Erleichterungen dieser Typisierung. pyasn1 erlaubte es nicht, im SubjectKeyIdentifier().subtype(implicitTag=Tag(
)) das Feld mit einem SubjectKeyIdentifier() Objekt (ohne den erforderlichen IMPLICIT TAG) zu belegen, und man musste oft Objekte nur aufgrund geĂ€nderter IMPLICIT/EXPLICIT-Tags kopieren und neu erstellen. PyDERASN achtet streng nur auf den Basistyp – die Tags werden automatisch aus dem bereits vorhandenen ASN.1-Schema eingefĂŒgt. Das vereinfacht den Code von Anwendungen erheblich.

Wenn ein Fehler beim Dekodieren auftritt, ist es in pyasn1 nicht einfach zu verstehen, wo genau er aufgetreten ist. Zum Beispiel erhalten wir im bereits erwĂ€hnten tĂŒrkischen Zertifikat einen solchen Fehler: UTF8String (tbsCertificate:issuer:rdnSequence:3:0:value:DEFINED BY 2.5.4.10:utf8String) (bei 138) unzureichende Grenzen: 1 ⇐ 77 ⇐ 64. Bei der Erstellung von ASN.1-Strukturen können Menschen Fehler machen, und das hilft, Anwendungen leichter zu debuggen oder Probleme mit codierten Dokumenten der Gegenseite zu klĂ€ren.

In der ersten Version von PyDERASN gab es keine UnterstĂŒtzung fĂŒr BER-Codierung. Diese kam viel spĂ€ter hinzu und die Verarbeitung von UTCTime/GeneralizedTime mit Zeitzonen wird bis heute noch nicht unterstĂŒtzt. Das wird in Zukunft kommen, denn das Projekt wird hauptsĂ€chlich in der Freizeit entwickelt.

In der ersten Version gab es auch keine Behandlung von DEFINED BY-Feldern. Nach einigen Monaten erschien diese Möglichkeit und wurde aktiv genutzt, wodurch der Code der Anwendungen erheblich verkĂŒrzt wurde – durch eine einzige Decodierungsoperation konnte die gesamte bis ins Detail aufgeschlĂŒsselte Struktur erhalten werden. Zu diesem Zweck werden in dem Schema angegeben, welche Felder was "definieren". Zum Beispiel die Beschreibung des CMSSchemas:

class ContentInfo(Sequence):
    schema = (
        ("contentType", ContentType(defines=((("content",), {
            id_authenticatedData: AuthenticatedData(),
            id_digestedData: DigestedData(),
            id_encryptedData: EncryptedData(),
            id_envelopedData: EnvelopedData(),
            id_signedData: SignedData(),
        }),))),
        ("content", Any(expl=tag_ctxc(0))),
    )

besagt, dass wenn contentType OID mit dem Wert id_signedData enthĂ€lt, das Feld content (das sich in diesem SEQUENCE befindet) gemĂ€ĂŸ dem Schema SignedData dekodiert werden muss. Warum so viele Klammern? Ein Feld kann mehrere Felder gleichzeitig "definieren", wie es in EnvelopedData-Strukturen der Fall ist. Die definierten Felder werden durch den sogenannten decode path identifiziert – dieser gibt den genauen Standort jedes Elements in allen Strukturen an.

Nicht immer möchte man oder hat die Möglichkeit, diese Defines sofort in das Schema aufzunehmen. Es kann anwendungsspezifische FÀlle geben, in denen OIDs und Strukturen nur in einem externen Projekt bekannt sind. PyDERASN bietet die Möglichkeit, diese Defines direkt beim Dekodieren der Struktur anzugeben:

ContentInfo().decode(data, ctx={"defines_by_path": ((
    (
        "content", DecodePathDefBy(id_signedData),
        "certificates", any, "certificate", "tbsCertificate",
        "extensions", any, "extnID",
    ),
    ((("extnValue",), {
        id_ce_authorityKeyIdentifier: AuthorityKeyIdentifier(),
        id_ce_basicConstraints: BasicConstraints(),
        [...]
        id_ru_subjectSignTool: SubjectSignTool(),
    }),),
),)})

Hier sagen wir, dass im CMS SignedData fĂŒr alle angehĂ€ngten Zertifikate alle ihre Erweiterungen zu dekodieren sind (AuthorityKeyIdentifier, BasicConstraints, SubjectSignTool usw.). Wir geben durch den decode path an, welchem Element die Defines "untergeschoben" werden mĂŒssen, als ob sie im Schema festgelegt wurden.

Schließlich bietet PyDERASN die Möglichkeit, von der Befehlszeile aus ASN.1-Dateien zu dekodieren und hat eine umfangreiche schöne Ausgabe. Man kann beliebige ASN.1 dekodieren oder ein genau definiertes Schema vorgeben und sieht etwas Ähnliches:

PyDERASN: wie ich eine ASN.1-Bibliothek mit Slots und Blobs geschrieben habe

Angezeigte Informationen: Objektverschiebung, TaglĂ€nge, InhaltlĂ€nge, Vorhandensein von EOC (Ende der Oktette), Indikator fĂŒr BER-Codierung, Indikator fĂŒr indeterminierte LĂ€ngen-Codierung, LĂ€nge und Verschiebung des EXPLICIT Tags (falls vorhanden), Tiefe der Schachtelung des Objekts in Strukturen, IMPLICIT/EXPLICIT Tagwert, Objekttitel gemĂ€ĂŸ Schema, sein grundlegender ASN.1 Typ, Reihenfolge innerhalb SEQUENCE/SET OF, Wert von CHOICE (falls vorhanden), menschenlesbarer Name INTEGER/ENUMERATED/BIT STRING gemĂ€ĂŸ Schema, Wert eines beliebigen grundlegenden Typs, DEFAULT/OPTIONAL Flag aus dem Schema, Indikator, dass das Objekt automatisch als DEFINED BY dekodiert wurde und durch welches OID dies geschah, menschenlesbarer OID.

Das System fĂŒr die hĂŒbsche Ausgabe (pretty printing) ist so konzipiert, dass es eine Sequenz von PP-Objekten erzeugt, die bereits durch separate Mittel visualisiert werden. Auf dem Screenshot ist der Renderer in einfacher, farbiger Textform zu sehen. Es gibt auch Renderer im JSON/HTML-Format, um dies mit Syntaxhervorhebung im ASN.1-Browser zu sehen wie in asn1js Projekt.

Andere Bibliotheken

Das war nicht das Ziel, aber PyDERASN ist erheblich schneller als pyasn1. Zum Beispiel kann das Dekodieren von CRL-Dateien in Megabyte-GrĂ¶ĂŸe so lange dauern, dass man ĂŒber Zwischenformate fĂŒr die Datenspeicherung (schnell) nachdenken und die Anwendungsarchitektur Ă€ndern muss. pyasn1 dekodiert CRL CACert.org auf meinem Laptop ĂŒber 20 Minuten, wĂ€hrend PyDERASN nur 28 Sekunden benötigt! Es gibt ein Projekt asn1crypto, das auf eine schnelle Verarbeitung von kryptografischen Strukturen abzielt: Es dekodiert (vollstĂ€ndig, nicht faul) dasselbe CRL in 29 Sekunden, verbraucht jedoch fast doppelt so viel Arbeitsspeicher bei der AusfĂŒhrung unter Python3 (983 MiB gegenĂŒber 498) und 3,5-mal so viel unter Python2 (1677 gegenĂŒber 488), wĂ€hrend pyasn1 sogar 4,3-mal mehr benötigt (2093 gegenĂŒber 488).

asn1crypto, das ich erwĂ€hnt habe, haben wir nicht berĂŒcksichtigt, da das Projekt noch in der Entstehung begriffen war und wir nichts darĂŒber gehört hatten. Jetzt wĂŒrden wir auch nicht in seine Richtung schauen, da ich sofort festgestellt habe, dass es den gleichen GeneralizedTime nicht in beliebiger Form akzeptiert und bei der Serialisierung die Bruchteile von Sekunden stillschweigend entfernt werden. Das ist akzeptabel fĂŒr die Arbeit mit X.509-Zertifikaten, aber im allgemeinen Fall nicht geeignet.

Im Moment ist PyDERASN der strengste der mir bekannten freien Python/Go DER-Dekodierer. In der Bibliothek encoding/asn1 meines geliebten Go gibt es keine strenge PrĂŒfung. OBJEKTIDENTIFIKATOR und UTCTime/GeneralizedTime-Zeichenfolgen. Manchmal kann Strenge hinderlich sein (hauptsĂ€chlich wegen der RĂŒckwĂ€rtskompatibilitĂ€t mit alten Anwendungen, die niemand aktualisieren wird), daher können in PyDERASN beim Dekodieren verschiedene Einstellungen ĂŒberprĂŒfungen gelockert werden.

Der Projektcode versucht, so einfach wie möglich zu sein. Die gesamte Bibliothek ist eine Datei. Der Code ist auf VerstĂ€ndlichkeit ausgelegt, ohne ĂŒberflĂŒssige Leistungsoptimierungen und DRY-Code. Wie bereits erwĂ€hnt, unterstĂŒtzt er kein vollstĂ€ndiges BER-Dekodieren von UTCTime/GeneralizedTime-Zeichenfolgen sowie von REAL, RELATIVE OID, EXTERNAL, INSTANCE OF, EMBEDDED PDV, CHARACTER STRING Datentypen. In allen anderen FĂ€llen sehe ich persönlich keinen Sinn darin, andere Bibliotheken in Python zu verwenden.

Wie alle meine Projekte, wie PyGOST, GoGOST, NNCP, GoVPN, ist PyDERASN vollstĂ€ndig freie Software, die unter den Bedingungen von LGPLv3+verbreitet wird und kostenlos heruntergeladen werden kann. Es gibt Beispiele fĂŒr die Nutzung in den hier und in Tests von PyGOST.

Sergej Matwejew, Cryptopunk, Mitglied der Open-Source-Stiftung, Python/Go-Entwickler, Hauptspezialist FGUP „NTZ Atlas“.

Quelle: habr.com

60GB SSD 8Gb DDR4