Rutoken, OpenSSL und eine lokale Zertifizierungsstelle zum Signieren von Nachrichten

Vor einiger Zeit bestand im Rahmen des Projekts die Notwendigkeit, die gleichzeitige Anzahl von Computern zu begrenzen, die Zugriff auf eine Webanwendung haben, die im lokalen Netzwerk des Kunden ausgeführt wird.

Die Entscheidung, Hardware-USB-Token zur Identifizierung des Computers zu verwenden, fiel von selbst. Die Wahl lag beim Rutoken EDS: Es funktioniert ohne Treiber. Um in einer Webanwendung zu arbeiten, benötigen Sie nur ein vom Entwickler freigegebenes Browser-Plug-In. Da das Token den Computer und nicht den Benutzer identifizieren sollte, sollte die Arbeit mit ihm vollständig „transparent“ sein: Wenn es vorhanden ist, arbeitet das System einfach still, ohne dem Benutzer unnötige Fragen zu stellen.

Es wurde entschieden: Wenn Sie sich beim System anmelden, signieren Sie die Benutzeranmeldeinformationen mit einer uneingeschränkten Signatur des auf Rutoken gespeicherten Zertifikats mithilfe des Rootoken-Plugins und überprüfen Sie den Server. Überprüfen Sie nach einer erfolgreichen Anmeldung mit dem Plugin das physische Vorhandensein desselben Tokens und melden Sie sich vom System ab, wenn dies nicht der Fall ist. Im Rahmen des genannten Projekts war dies ausreichend.

Sie müssen eine eigene Zertifizierungsstelle (CA) erstellen, um signierte Nachrichten auszutauschen oder signierte Nachrichten von einem Client an einen Server zu senden. Client-Zertifikate müssen sich auf USB-Token in privaten Schlüsselcontainern befinden, und die Signaturüberprüfung muss auf dem Server mithilfe von OpenSSL durchgeführt werden

Also die Aufgabe: Installation und Konfiguration auf dem Linux-Server der CA. Stellen Sie Client-Zertifikate bereit, die Computer auf USB-Token identifizieren .

Um es zu lösen, benötigen Sie:


  1. Wir erstellen ein Verzeichnis, in dem sich die Zertifizierungsstelle befindet, und kopieren die im System enthaltene OpenSSL-Konfiguration (auf den neuesten Versionen von Ubuntu befindet sich /etc/ssl/openssl.cnf ).
  2. Wir konfigurieren "unsere" openssl.cnf:

    a) Fügen Sie am Anfang der Dateianweisungen zum Verbinden der Token-Engine Folgendes hinzu:

    openssl_conf = openssl_def [ openssl_def ] engines = engine_section [ engine_section ] rtengine = gost_section [ gost_section ] dynamic_path = /path/to/rutoken/openssl/connector/librtengine.so MODULE_PATH = /path/to/rutoken/pkcs11/librtpkcs11ecp.so RAND_TOKEN = pkcs11:manufacturer=Aktiv%20Co.;model=Rutoken%20ECP default_algorithms = CIPHERS, DIGEST, PKEY, RAND 

    b) Kommentieren Sie die Zeile aus

     # req_extensions = v3_req # The extensions to add to a certificate request 

    c) Geben Sie im Abschnitt [v3_req] die folgenden Parameter an:

     subjectSignTool = ASN1:FORMAT:UTF8,UTF8String:   extendedKeyUsage=emailProtection keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment 

    d) Entfernen Sie im Abschnitt [v3_ca] die kritische Option aus dem Parameter basicConstraints:

     basicConstraints = CA:true 

    Wofür? Ehrliche Antwort: Ich weiß es nicht. Alle Beispiele für Stammzertifikate, die ich heruntergeladen habe, um das Thema herauszufinden, waren jedoch ohne kritisches Zeichen. Ich stelle die Frage "wofür?" erfahrenere Kollegen.


    e) Legen Sie optional die Standardwerte fest, die angeboten werden, wenn selbstsignierte Zertifikate ausgestellt und Anforderungen für die Ausstellung von Client-Zertifikaten generiert werden. Diese Parameter befinden sich im Abschnitt [req_distinguished_name]

    Der Parameter mit dem Postfix _default ist der Standardwert. Ein Beispiel:

     countryName = Country Name (2 letter code) countryName_default = AU countryName_min = 2 countryName_max = 2 

    Wenn das System Sie auffordert, den Parameter countryName einzugeben , wird in eckigen Klammern angezeigt, dass der Wert AU standardmäßig beibehalten wird.


    Damit ist die Konfiguration der OpenSSL-Konfiguration abgeschlossen. Es bleibt offen, um OpenSSL anzuzeigen, dass es notwendig ist, es zu verwenden. Setzen Sie dazu die Umgebungsvariable OPENSSL_CONF:

     export OPENSSL_CONF=/path/to/your/openssl.cnf 
  3. Wir erstellen eine Verzeichnisstruktur, in der Informationen zu unserer Zertifizierungsstelle gespeichert werden.
    Wechseln Sie dazu in das erstellte Verzeichnis mit der gerade bearbeiteten Datei openssl.cnf und führen Sie die folgenden Schritte aus:

    a) Erstellen Sie darin Unterverzeichnisse:

    demoCA
    demoCA / privat
    demoCA / newcerts

    Hinweis: Der demoCA-Name wird im Abschnitt [CA_default] der Datei openssl.cnf angegeben . Sie können es ändern (in Schritt 2) und dann anstelle von demoCA damit arbeiten.

    b) Erstellen Sie im demoCA-Verzeichnis eine leere index.txt- Datei und eine serielle Datei, die wir mit einem Texteditor öffnen und dort Zeile 01 schreiben. Dies ist der Zähler für ausgestellte Zertifikate. Nach der Ausstellung jedes nächsten Zertifikats erhöht sich der Wert in dieser Datei um eins.
  4. Optional formatieren wir unser Token mit dem Dienstprogramm rtAdmin. Jetzt ist alles für die Bereitstellung der Zertifizierungsstelle bereit.

    Der Aktionsalgorithmus ist weitgehend einfach:

    a) Wir stellen das Stammzertifikat des Zertifizierungszentrums mit dem GOST-Algorithmus aus:

    • Generieren Sie einen privaten Schlüssel, um ein selbstsigniertes CA-Zertifikat auszustellen
    • Generieren Sie mit dem generierten Schlüssel ein selbstsigniertes X509-Zertifikat

    b) auf jedem der USB-Token

    • ein Schlüsselpaar generieren (den sogenannten privaten Schlüsselcontainer)
    • Generieren Sie eine Zertifikatsignierungsanforderung mit dem generierten Token-Schlüssel
    • Stellen Sie ein Zertifikat für diese Anfrage aus
    • Speichern Sie das Zertifikat auf dem Token im privaten Schlüsselcontainer

    Das Folgende ist eine Implementierung dieses Algorithmus für ein einzelnes Token:

    Generierung privater Schlüssel für CA-Zertifikat (wir verwenden den GOST-Algorithmus):

     openssl genpkey -algorithm gost2012_256 -pkeyopt paramset:A -outform PEM -out demoCA/private/cakey.pem 

    Wir stellen ein selbstsigniertes CA-Zertifikat aus:

     <b>openssl req -new -x509 -key demoCA/private/cakey.pem -out demoCA/certs/cacert.pem -extensions v3_ca -days +3650 -outform PEM 

    Bitte beachten Sie: Wir haben in der Befehlszeile angegeben, dass die v3_ca- Erweiterungen aus der openssl_cnf-Konfiguration verwendet werden müssen. Dort ist es unsere CA. Gültigkeit von 10 Jahren. Eine häufige Sache für CA. Aber mehr ist möglich.

    Während der Ausstellung eines Zertifikats werden Sie vom System aufgefordert, die Parameterwerte einzugeben, die sich im Abschnitt [req_distinguished_name] unserer Datei openssl.cnf befinden

    Jetzt starten wir Token-Operationen. Wenn das Token neu ist oder mit Standardwerten formatiert ist, lautet die PIN des Benutzers 12345678. Ich gehe davon aus, dass dies genau so ist. Andernfalls müssen Sie die richtige Benutzer-PIN angeben und im Allgemeinen sicherstellen, dass in den folgenden Beispielen die Namen der bereits auf dem Token vorhandenen Objekte nicht mit den eingegebenen Objekten überlappen.

    Zunächst generieren wir ein Schlüsselpaar. OpenSSL kann diesen Vorgang auf Rutoken nicht ausführen, daher verwenden wir das Dienstprogramm pkcs11-tool aus dem OpenSC-Paket:

     pkcs11-tool --module /path/to/your/librtpkcs11ecp.so --login --pin 12345678 --keypairgen --key-type GOSTR3410:A --id 303030303031 --label 'client01' 

    Wichtiger Hinweis: Wir haben die ID 303030303031 angegeben. Alle zwei Ziffern dieser ID sind nichts anderes als der ASCII-Code der Zeichen „0“ bzw. „1“. Bei Operationen mit OpenSSL sieht es wie folgt aus: "id = 000001"

    Generieren Sie eine Zertifikatanforderung:

     openssl req -utf8 -new -keyform engine -key 'pkcs11:id=000001' -engine rtengine -out demoCA/newcerts/client01.csr 

    Wenn alles richtig gemacht wurde, dann das System

    • Fordern Sie eine PIN an
    • fordert Parameter für den Zertifikatsnamen an (aus dem Abschnitt [req_distinguished_name] )
    • gibt eine Anforderungsdatei für die Zertifikatsignierung aus

    Mit dieser Anfrage signieren wir ein Client-Zertifikat ( im Beispiel ist das Zertifikat 1825 Tage gültig. Es ist wichtig, dass dieser Zeitraum den Gültigkeitszeitraum Ihres Stammzertifikats nicht überschreitet ):

     openssl ca -utf8 -days +1825 -keyfile demoCA/private/cakey.pem -cert demoCA/certs/cacert.pem -in demoCA/newcerts/client01.csr -outdir demoCA/newcerts -out demoCA/certs/client01.pem 

    Das System zeigt das Zertifikat an, fragt nach der Entscheidung, es zu unterschreiben (Antwort „y“) und nach der Entscheidung, das neue Zertifikat zu speichern (antworten Sie erneut mit „y“).

    Wir speichern das erhaltene Zertifikat für das Token:

     pkcs11-tool --module /path/to/your/librtpkcs11ecp.so --login --pin 12345678 --id=303030303031 -w demoCA/certs/client01.pem -y cert 

    Das ist alles.

    Testen des geschaffenen „Wunders“. Dazu unterschreiben und verifizieren wir die Unterschrift des Satzes "Hallo Welt!":

     echo Hello,world! | openssl cms -nodetach -sign -signer demoCA/certs/client01.pem -keyform engine -inkey "pkcs11:id=000001" -engine rtengine -binary -noattr -outform PEM | openssl cms -verify -CAfile demoCA/certs/cacert.pem -inform PEM 

    Wenn alles korrekt durchgeführt wurde, fordert das System eine PIN an, signiert die Nachricht, überprüft die Signatur und zeigt bei Erfolg die ursprüngliche Nachricht und das Ergebnis der Überprüfung an („Erfolg“).

    Bemerkung . Wenn Sie zur Titelaufgabe zurückkehren und mit dem Plugin signieren, sollte beachtet werden, dass das Plugin standardmäßig das Ergebnis der Signierung nicht im PEM-Format, sondern im DER-Format liefert, das in base64 codiert ist. Um die Signatur zu überprüfen, müssen Sie daher zuerst von base64 dekodieren und bei der Überprüfung das Eingabe-DER-Format angeben.

    Viel Glück!

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


All Articles