Plattformübergreifendes englisches Dienstprogramm zum Anzeigen russisch qualifizierter Zertifikate x509

Bild Heute ist die Verwendung digitaler Zertifikate X509 v.3 an der Tagesordnung. Immer mehr Menschen nutzen sie, um auf die Website des Staatsdienstes, des Bundessteuerdienstes, elektronischer Gebote usw. zuzugreifen. Und immer mehr Menschen möchten wissen, was sich in dieser „Truhe“ befindet, die als Zertifikat bezeichnet wird. Und wenn das Zertifikat ein Analogon eines Passes ist, wie kann es dann gelesen / angezeigt werden? Ja, in Betriebssystemen gibt es verschiedene Dienstprogramme zum Anzeigen. Aber sie werden dem normalen Bürger wenig geben. Nehmen wir zum Beispiel das Dienstprogramm gcr-viewer, das in der Tat das Standardwerkzeug für die Anzeige auf Linux-Systemen und damit auf inländischen Betriebssystemen ist :



Standard-Viewer


Das Dienstprogramm ist gut gemacht, bequem. Im Allgemeinen ist es als universelles Dienstprogramm zum Anzeigen von Dateien gedacht, die Daten in verschiedenen kryptografischen Formaten enthalten (Zertifikate, Anforderungen, elektronische Signaturen / PKCS # 7, geschützte Container PKCS # 12 usw.). Leider ist es für die westliche Kryptographie konzipiert und berücksichtigt keine in Ihrem Land eingegebenen Oids. Wenn Sie sich den Screenshot ansehen, werden unverständliche Zeichen angezeigt, wenn die Informationen zum Zertifikatsinhaber angezeigt werden. Links sind die Oids selbst und rechts in der 16. Form die asn1-Struktur mit ihren Werten. In diesem Fall sind dies OGRN (1.2.643.100.1), SNILS (1.2.643.100.3) und TIN (1.2.643.3.131.1.1). Und so sollte ein gewöhnlicher Bürger sicherstellen, dass dies seine Daten sind. Denken Sie nicht, dass dies nur unter Linux möglich ist, es ist eine gemeinsame Funktion jedes Zertifikat-Viewers. Und wenn Sie weiter schauen, wird alles unverständlich:



Einige Erweiterungen, Bezeichner und Werte werden angezeigt. In diesem Fall verbirgt oid 1.2.643.100.111 den Namen der CIPF, die vom Benutzer zum Generieren des Schlüsselpaars verwendet wurde, den privaten Schlüssel, mit dem die Zertifikatanforderung signiert wurde, und den öffentlichen Schlüssel, von dem im Zertifikat liegt:



Und hier ist dem Zertifikatsinhaber wenig bekannt. Er versteht nicht einmal, mit welchem ​​Algorithmus der Schlüssel generiert wurde, entweder GOST R 34.10-2001 oder GOST R 34.10-2012 und mit welcher Schlüssellänge.

Sie können weiterhin Beispiele nennen. Wenn zum Beispiel die Gültigkeit des Zertifikats klar ist, wo ist dann der Schlüssel?

Es gibt zwei weitere Fragen, auf die Zertifikatsinhaber eine Antwort haben möchten: Wo kann ich eine Kette von Stammzertifikaten erhalten (oder noch besser nur eine) und eine ähnliche Frage in der Liste der widerrufenen Zertifikate.

Und schließlich möchte ich ein universelles Dienstprogramm haben, das die Merkmale der russischen PKI / PKI berücksichtigt, die wirklich plattformübergreifend ist und auf inländischen und nicht inländischen Betriebssystemen ausgeführt wird . Was ist zu entwickeln? Natürlich in einer Skriptsprache, schon allein wegen ihrer plattformübergreifenden Natur.

Dann erinnerte ich mich, dass die schöne Skriptsprache Tcl (Tool Command Language) kürzlich ihr 30-jähriges Bestehen gefeiert hatte. Es ist eine Freude, darauf zu programmieren. Es hat eine große Anzahl von Erweiterungen (Paket), die fast alles erlauben. Um mit ASN-Strukturen arbeiten zu können, gibt es ein ASN-Paket. Darüber hinaus gibt es für die Arbeit mit Zertifikaten (wir sind in diesem Fall daran interessiert, sie zu analysieren) ein pki-Paket. Und für die Entwicklung einer grafischen Oberfläche gibt es ein Tk-Paket.

Trotzdem kann man über Pyton mit Tkinter und über Perl und über Rubin sagen. Jeder kann nach seinem Geschmack wählen. Wir halten an einem Haufen Tcl / Tk.

Wir werden das Grafikdesign für das Dienstprogramm vom Dienstprogramm gcr-viewer ausleihen. Und noch eine Anforderung.

Da Habr eine englische Version hatte , wollte ich, dass das Dienstprogramm verschiedene Schnittstellen hat (Russisch / Englisch). Dies ist jedoch nicht der Hauptgrund. Noch wichtiger ist, dass immer mehr Bürger der westlichen Welt Bürger der Russischen Föderation werden, zum Beispiel der weltberühmte Schauspieler Depardieu. Sie können Einwände erheben: Er ist ein Franzose. Ich bin aber auch ein Militärübersetzer aus dem Französischen:



Es ist also einfach, eine französische Benutzeroberfläche hinzuzufügen. Aber ich denke, Depardieu hat keine Probleme mit der englischen Sprache. Auf der anderen Seite ist unser Land multinational und es wäre sehr schön, wenn die inländische Software und das inländische Betriebssystem mindestens mehrere nationale Schnittstellen hätten.
Ein wenig voraus zu laufen, ist das, was daraus wurde:



Wir laden einen Übersetzer ein


Beginnen wir also mit dem „Übersetzer“. Im Screenshot versteckt er sich unter der Nationalflagge. Die Hauptanforderung für einen Übersetzer ist die Synchronisation der Übersetzung, d.h. die Möglichkeit, jederzeit zu einer anderen Sprache zu wechseln. Die Übersetzerfunktionen in Tcl / Tk sind das msgcat-Paket:

package require msgcat 

Verwenden Sie den folgenden Befehl, um die aktuelle Sprache festzulegen:

 msgcat::mclocale ru 

Das Vokabular des „Übersetzers“ wird wie folgt in der Datei ru.msg gespeichert:

 #  msgcat::mcset      #     mcset namespace import -force msgcat::mcset #     mcset ru "Language" "" … 

Das Folgende ist der Text des Tests
Skript mit Übersetzer:
 #!/usr/bin/wish -f #  msgcat package require msgcat #   ru msgcat::mclocale ru #  ::msgcat::mc      #     mc namespace import msgcat::mc #    [msgcat::mclocale].msg. #       . msgcat::mcload [file join [file dirname [info script]]] #  image create photo rf_32x21_f -file rf_32x21.png image create photo gb_32x21_f -file gb_32x21.png #,      label .lab -text "[mc Language]: " -relief flat -bd 0 –bg snow -anchor sw -width 10 button .but_lang -image rf_32x21_f -command ::changelang -relief flat -bd 0 pack .lab -side left -pady {2 0} pack .but_lang -side left #      proc ::changelang {} { #     #    if {[msgcat::mclocale] == "ru"} { msgcat::mclocale en .but_lang configure -image gb_32x21_f } else { msgcat::mclocale ru .but_lang configure -image rf_32x21_f } #  .lab configure -text "[mc Language]: " } 


In diesem Skript fungiert die Prozedur :: changelang als Übersetzer, der aufgerufen wird, wenn die Schaltfläche .but_lang mit dem Flag gedrückt wird.

Wenn Sie dieses Skript ausführen, werden Sie deutlich sehen, wie der Übersetzer funktioniert:



Holen Sie sich den öffentlichen Schlüssel


Nachdem wir uns für einen Übersetzer entschieden haben, fahren wir mit der Analyse des Zertifikats fort. Dazu benötigen wir das pki-Paket:

 package require pki). 

Das pki-Paket funktioniert mit RSA-Algorithmusschlüsseln und -Zertifikaten. Wenn das Zertifikat (proc :: pki :: x509 :: parse_cert) mit einem anderen Schlüsseltyp erstellt wurde, erhalten wir keine Informationen zu diesem Schlüssel:

 # Handle RSA public keys by extracting N and E switch -- $ret(pubkey_algo) { "rsaEncryption" { set pubkey [binary format B* $pubkey] binary scan $pubkey H* ret(pubkey) ::asn::asnGetSequence pubkey pubkey_parts ::asn::asnGetBigInteger pubkey_parts ret(n) ::asn::asnGetBigInteger pubkey_parts ret(e) set ret(n) [::math::bignum::tostr $ret(n)] set ret(e) [::math::bignum::tostr $ret(e)] set ret(l) [expr {int([::pki::_bits $ret(n)] / 8.0000 + 0.5) * 8}] set ret(type) rsa } } 

Überraschenderweise gibt der Public-Key-Algorithmus immer noch zurück (ret (pubkey_algo))
Die Situation ist dieselbe wie beim Parsen der Zertifikatanforderung (proc :: pki :: pkcs :: parse_csr):

 # Parse public key, based on type switch -- $pubkey_type { "rsaEncryption" { set pubkey [binary format B* $pubkey] ::asn::asnGetSequence pubkey pubkey_parts ::asn::asnGetBigInteger pubkey_parts key(n) ::asn::asnGetBigInteger pubkey_parts key(e) set key(n) [::math::bignum::tostr $key(n)] set key(e) [::math::bignum::tostr $key(e)] set key(l) [expr {2**int(ceil(log([::pki::_bits $key(n)])/log(2)))}] set key(type) rsa } default { return -code error "Unsupported key type: $pubkey_type" } } 

Aber hier gibt er sogar Informationen über den Fehler zurück. Aber heute werden neben RSA beispielsweise Schlüssel auf elliptischen Kurven der EU verwendet, einschließlich GOST R 34.10-2012 (GOST R 34.10-2001 gibt es derzeit auch).

Standardmäßig reicht es jedoch aus, die ASN-Struktur des öffentlichen Schlüssels zurückzugeben, der im Zertifikat oder in der Anforderung enthalten ist, und der Benutzer selbst analysiert den öffentlichen Schlüssel je nach Schlüsseltyp. Fügen Sie dazu einfach die ASN-Struktur des öffentlichen Schlüssels in hexadezimalen Werten zu den zurückgegebenen Werten hinzu:

 proc ::pki::x509::parse_cert {cert} { . . . ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo #    ASN-  . binary scan $pubkeyinfo H* ret(pubkey_pubkeyinfo) . . . } 

Alles, nichts anderes zu tun. Auf diese Weise gibt die Prozedur :: pki :: x509 :: parse_cert die meisten Zertifikatserweiterungen aus dem einfachen Grund zurück, dass sie nicht weiß, wie sie analysiert werden sollen (z. B. subjectSignTool mit unseren qualifizierten Zertifikaten), d. H. gibt nach Ermessen des Benutzers.

Andererseits gibt die Prozedur :: pki :: x509 :: parse_cert eines der Ergebnisse eines TBT-Zertifikats zurück , das alle Informationen aus dem Zertifikat enthält, mit Ausnahme der Signatur (Signatur) und des Signaturtyps (Signatur_algo):

 #    set fd [open «cert.pem» r] chan configure –translation binary set datacert [read $fd] close $fd #  array set cert_parse [::pki::x509::parse_cert $datacert] # tbs- set cert_tbs_hex $cert_parse(cert) 

Wir schreiben das Verfahren zum Extrahieren von Public-Key-Informationen aus einem TBS-Zertifikat:

 proc ::pki::x509::parse_cert_pubkeyinfo {cert_tbs_hex} { array set ret [list] set wholething [binary format H* $cert_tbs_hex] ::asn::asnGetSequence wholething cert ::asn::asnPeekByte cert peek_tag if {$peek_tag != 0x02} { # Version number is optional, if missing assumed to be value of 0 ::asn::asnGetContext cert - asn_version ::asn::asnGetInteger asn_version ret(version) } ::asn::asnGetBigInteger cert ret(serial_number) ::asn::asnGetSequence cert data_signature_algo_seq ::asn::asnGetObjectIdentifier data_signature_algo_seq ret(data_signature_algo) ::asn::asnGetSequence cert issuer ::asn::asnGetSequence cert validity ::asn::asnGetUTCTime validity ret(notBefore) ::asn::asnGetUTCTime validity ret(notAfter) ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo #    hex asn-   binary scan $pubkeyinfo H* ret(pubkeyinfo) return $ret(pubkeyinfo) } 

Und da wir an russischer Kryptographie interessiert sind, werden wir sofort das Verfahren zum Parsen des öffentlichen GOST-Schlüssels schreiben:

 proc parse_key_gost {pubkeyinfo_hex} { array set ret [list] set pubkeyinfo [binary format H* $pubkeyinfo_hex] ::asn::asnGetSequence pubkeyinfo pubkey_algoid ::asn::asnGetObjectIdentifier pubkey_algoid ret(pubkey_algo) #,   - if {[string first "1 2 643 " $ret(pubkey_algo)] == -1} { return [array get ret] } ::asn::asnGetBitString pubkeyinfo pubkey set pubkey [binary format B* $pubkey] #   binary scan $pubkey H* ret(pubkey) ::asn::asnGetSequence pubkey_algoid pubalgost #OID -  ::asn::asnGetObjectIdentifier pubalgost ret(paramkey) #OID -   ::asn::asnGetObjectIdentifier pubalgost ret(hashkey) #puts "ret(paramkey)=$ret(paramkey)\n" #puts "ret(hashkey)=$ret(hashkey)\n" #parray ret #  :  ,     return [array get ret] } 

Ja, ich habe es fast verpasst: Nach dem Laden des pki-Pakets müssen Sie dem Array :: pki :: oids oids hinzufügen, die das GOST und das qualifizierte Zertifikat charakterisieren oder in diesem Array einfach fehlen:

 package require pki # oid- set ::pki::oids(1.2.643.100.1) "OGRN" set ::pki::oids(1.2.643.100.5) "OGRNIP" set ::pki::oids(1.2.643.3.131.1.1) "INN" set ::pki::oids(1.2.643.100.3) "SNILS" set ::pki::oids(1.2.643.2.2.19) "GOST R 34.10-2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GOST R 34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.1.2) "GOST R 34.10-2012-512" set ::pki::oids(1.2.643.2.2.3) "GOST R 34.10-2001 with GOST R 34.11-94" set ::pki::oids(1.2.643.7.1.1.3.2) "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" set ::pki::oids(1.2.643.100.113.1) "KC1 Class Sign Tool" set ::pki::oids(1.2.643.100.113.2) "KC2 Class Sign Tool" . . . 

Sie können das Vokabular des Übersetzers auch auffüllen, indem Sie der Datei ru.msg Folgendes hinzufügen:

 mcset ru "GOST R 34.10-2001" "  34.10-2001" mcset ru "GOST R 34.10-2012-256" "  34.10-2012-256" mcset ru "GOST R 34.10-2012-512" "  34.10-2012-512" mcset ru "GOST R 34.10-2001 with GOST R 34.11-94" "  34.10-2001    34.11-94" mcset ru "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" "  34.10-2012-256    34.11-2012-256" mcset ru "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" "  34.10-2012-512    34.11-2012-512" . . . 
::


Stammzertifikatskette und Zertifikatsperrliste


Wie man eine Kette von Stammzertifikaten erhält, wurde bereits früher besprochen. In Analogie wird eine Prozedur geschrieben, um eine Liste der widerrufenen COS / CRL-Zertifikate zu erhalten. Der Quellcode des Dienstprogramms und seiner Distributionen für Linux, OS X (macOS) und MS Windows finden Sie hier


Im Quellcode finden Sie alle Verfahren zum Parsen von Zertifikatserweiterungen.
Für Gegner von Tk (Tcl / Tk, Python / Tkinter usw.) empfehle ich, wie sie sagen, 10 (zehn) Unterschiede zwischen den beiden Dienstprogrammen zu finden: das in gtk geschriebene Dienstprogramm gcr-viewer und das in Tk entwickelte Dienstprogramm certViewer:



PKCS # 11 Token / Smartcard-Zertifikate


Oben haben wir über die Arbeit mit Zertifikaten gesprochen (Durchsuchen, Abrufen der Kette von Stammzertifikaten, Listen widerrufener Zertifikate, Fingerabdrücke von sha1 und sha256 usw.), die in Dateien gespeichert sind. Auf PKCS # 11-Token / Smartcards sind jedoch noch Zertifikate gespeichert. Und der natürliche Wunsch besteht nicht nur darin, sie zu sehen und dann in eine Datei zu exportieren. Wie das geht, beschreiben wir im folgenden Artikel:

Source: https://habr.com/ru/post/de440754/


All Articles