
Die zweite Hälfte des Jahres 2018 rückt näher und das auf der russischen Kryptographie basierende
„2000. Jahr“ in der
PKI sollte bald kommen. Dies liegt an der Tatsache, dass
Die Verwendung des Signaturschemas GOST R 34.10-2001 zum Generieren einer Signatur nach dem 31. Dezember 2018 ist nicht zulässig!
Heute macht es keinen Sinn, Zertifikate mit einer Unterschrift gemäß GOST R 34.10-2001 zu erhalten.
Gleichzeitig werden viele Dienste oder Anwendungen auf Basis von OpenSSL entwickelt, die die Arbeit mit GOST R 34.10-2001 unterstützten.
In der Standardversion von openssl gibt es heute jedoch keine Unterstützung für GOST R 34.11-2012 und GOST R 34.10-2012. Darüber hinaus ist in Version 1.1 die Unterstützung der GOST-Kryptografie von der Standardverteilung
ausgeschlossen („Die GOST-Engine war veraltet und wurde daher entfernt.“).
All dies lässt uns nach alternativen Möglichkeiten suchen, mit Zertifikaten zu arbeiten, mit elektronischer Signatur („CMS-Formatnachrichten“) und anderen PKI-Objekten, die auf der neuen russischen Kryptographie basieren.
Eine solche Möglichkeit ist die Verwendung der
GCrypt- Bibliothek. Diese Bibliothek unterstützt die neuen Algorithmen GOST R 34.11-2012 (Hashing-Algorithmen) und GOST R 34.10-2012 (Signaturalgorithmen).
Schlüsselpaargenerierung
Wir beginnen also damit, ein Schlüsselpaar zu generieren, das sowohl private als auch öffentliche Schlüssel enthält. Gegenwärtig gibt es in der russischen Kryptographie drei Arten von Signaturschlüsseln mit entsprechenden Oids
- GOST R 34.10-2001 mit einer Schlüssellänge von 256 Bit, oid 1.2.643.2.2.19 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x13);
- GOST R 34.10-2012 mit einer Schlüssellänge von 256 Bit (im Folgenden: GOST R 34.10-12-256), oid 1.2.643.7.1.1.1.1 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x01, 0x01);
- GOST R 34.10-2012 mit einer Schlüssellänge von 512 Bit (im Folgenden: GOST R 34.10-12-512), oid 1.2.643.7.1.1.1.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x01, 0x02).
Beachten Sie sofort, dass die Schlüssel von GOST R 34.10-2001 und GOST R 34.10-12-256 in Bezug auf Mathematik, Generierungsalgorithmen und deren Implementierung absolut identisch sind! Sowie identische Algorithmen zur Bildung elektronischer Signaturen, die darauf basieren. Welcher dieser fraglichen Schlüssel kann nur anhand von Informationen über den Schlüssel beurteilt werden, die beispielsweise im Zertifikat enthalten sind. Warum brauchte es zwei verschiedene Oids? Betonen Sie nur die Tatsache, dass beim Generieren einer elektronischen Signatur mit dem Schlüssel GOST R 34.10-2001 der gemäß GOST R 34.10-94 erhaltene Hash verwendet werden sollte und bei Verwendung des Schlüssels GOST R 34.10-12-256 der gemäß GOST R 34.10- erhaltene Hash. 212 mit einer Länge von 256 Bit. Um dies zu betonen, gibt es jedoch entsprechende oid-s:
- 1.2.643.2.2.3 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x03) - Signaturalgorithmus GOST R 34.10-2001 mit Schlüssel 256 mit Hashing GOST R 34.11-94;
- 1.2.643.7.1.1.3.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x02) - Signaturalgorithmus GOST R 34.10-2012 mit Schlüssel 256 mit Hashing GOST R 34.11-2012;
- 1.2.643.7.1.1.3.3 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x03) - Signaturalgorithmus GOST R 34.10-2012 mit Schlüssel 512 mit Hashing GOST R 34.11-2012.
Es gibt also eine Sortierung mit oid-s, aber das heißt, das heißt.
Schlüssel der GOST-Familie gehören auf elliptischen Kurven zur Schlüsselfamilie. Um ein Schlüsselpaar zu generieren, müssen Sie einen Basispunkt auf einer elliptischen Kurve angeben.
Das technische Komitee für Standardisierung „Kryptografische Informationssicherheit“ (
TC 26 ) empfahl die Verwendung von zwei Basispunkten für die Schlüssel GOST R 34.10-2012-512:
- GOST2012-tc26-A (Spitzname in der libgcrypt-Terminologie) mit oid 1.2.643.7.1.2.1.2.1 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02, 0x01);
- GOST2012-tc26-B mit oid 1.2.643.7.1.2.1.2.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02, 0x02);
Für GOST R 34.10-Schlüssel mit einer Länge von 256 Bit werden drei Basispunkte empfohlen:
- GOST2001-CryptoPro-A mit oid om 1.2.643.2.2.35.1 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01);
- GOST2001-CryptoPro-B mit oid 1.2.643.2.2.35.2 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x02);
- GOST2001-CryptoPro-C mit oid 1.2.643.2.2.35.3 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x03).
Für GOST R 34.10-Schlüssel mit einer Länge von 256 Bit sind zwei weitere Oids für die Basispunkte definiert:
- GOST2001-CryptoPro-XchA mit oid 1.2.643.2.2.36.0 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x24, 0x00);
- GOST2001-CryptoPro-XchB mit oid 1.2.643.2.2.36.1 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x24, 0x01).
In der Realität beziehen sich diese Oids jedoch auf die Basispunkte von GOST2001-CryptoPro-A mit oid 1.2.643.2.2.35.1 bzw. GOST2001-CryptoPro-C mit oid 1.2.643.2.2.35.3.
Und dies sollte bei der Verarbeitung von Basispunkten mit diesen Oids berücksichtigt werden.
Um ein Schlüsselpaar zu generieren, wird die Funktion gcry_pk_genkey des folgenden Formulars verwendet:
gcry_error_t gcry_pk_genkey (gcry sexp t *key_pair, gcry sexp t key_spec ).
In der Variablen parms müssen Parameter festgelegt werden, um das Schlüsselpaar im Format des internen
S-Ausdrucks (sexp) zu generieren. Um ein Schlüsselpaar nach GOST zu generieren, werden die Parameter in Form des folgenden S-Ausdrucks eingestellt:
(genkey ( (curve _))),
ecc bestimmt die Erzeugung des Schlüsselpaars auf elliptischen Kurven, und der Basispunkt sollte den vom TK-26 empfohlenen spezifischen Punkt angeben. Es ist der angegebene Basispunkt, der bestimmt, welches Schlüsselpaar generiert wird. Wenn Sie beispielsweise GOST2012-tc26-A oder GOST2012-tc26-B angeben, wird ein Schlüsselpaar gemäß GOST R 34.10-2012 mit einer Schlüssellänge von 512 Bit generiert. Anstelle des Spitznamens des Basispunkts können Sie oid direkt angeben:
(genkey ( (curve «1.2.643.2.2.35.3»)))
Im letzteren Fall wird angenommen, dass das Schlüsselpaar gemäß GOST R 34.10 mit einer Schlüssellänge von 256 Bit und einem GOST2001-CryptoPro-C-Basispunkt erzeugt wird.
Unten finden Sie ein Beispiel für ein C-Programm, das die Schlüsselgenerierung demonstriert
GenKey.c #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> /* S-*/ static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } int main(int argc, char* argv[]) { gpg_error_t err; gcry_sexp_t key_spec, key_pair, pub_key, sec_key; /* */ char *curve_gost[] = {"GOST2001-CryptoPro-A", "GOST2001-CryptoPro-B", "GOST2001-CryptoPro-C", "GOST2012-tc26-A", "GOST2012-tc26-B", NULL}; /* */ err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecc (curve %s)))", curve_gost[1]); if (err) { fprintf(stderr, "creating S-expression failed: %s\n", gcry_strerror (err)); exit (1); } err = gcry_pk_genkey (&key_pair, key_spec); if (err){ fprintf(stderr, "creating %s key failed: %s\n", argv[1], gcry_strerror (err)); exit(1); } /* S- */ show_sexp ("ECC GOST key pair:\n", key_pair); /* */ pub_key = gcry_sexp_find_token (key_pair, "public-key", 0); if (! pub_key) { fprintf(stderr, "public part missing in key\n"); exit(1); } /* S- */ show_sexp ("ECC GOST public key:\n", pub_key); /* */ sec_key = gcry_sexp_find_token (key_pair, "private-key", 0); if (! sec_key){ fprintf(stderr, "private part missing in key\n"); exit(1); } /* S- */ show_sexp ("ECC GOST private key:\n", sec_key); /* , */ gcry_sexp_release (key_pair); /* , */ gcry_sexp_release (key_spec); }
Um das Beispiel zu senden, müssen Sie den folgenden Befehl ausführen:
$cc –o GenKey GenKey.c –lgcrypt $
Nach dem Start des GenKey-Moduls erhalten wir
Schlüsselpaar ECC GOST key pair: (key-data (public-key (ecc (curve GOST2001-CryptoPro-B) (q
Mit dem privaten Schlüssel können Sie jetzt eine elektronische Signatur erstellen.
Dokumenten-Hashing
Die Erstellung einer elektronischen Signatur (ES) eines Dokuments beginnt mit dem Abrufen eines Hashwerts aus dem zu signierenden Dokument. Um ein Dokument zu signieren, kann einer der Algorithmen ausgewählt werden:
- 1.2.643.2.2.3 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x03) - Signaturalgorithmus GOST R 34.10-2001 mit Schlüssel 256 mit Hashing gemäß GOST R 34.11-94 mit Hash-Länge 256 Bit;
- 1.2.643.7.1.1.3.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x02) - Signaturalgorithmus GOST R 34.10-2012 mit einem Schlüssel von 256 mit Hashing gemäß GOST R 34.11-2012 mit einer Hash-Länge von 256 Bit;
- 1.2.643.7.1.1.3.3 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x03) - Signaturalgorithmus GOST R 34.10-2012 mit einem Schlüssel von 512 mit Hashing gemäß GOST R 34.11-2012 mit einer Hash-Länge von 512 Bit.
Diese Algorithmen bestimmen nicht nur den Typ des privaten Schlüssels, der zum Abrufen der elektronischen Signatur verwendet wird, sondern auch den Hash-Funktionsalgorithmus. Die GCrypt-Bibliothek implementiert alle drei Arten von Funktionen. Der Hash-Algorithmus GOST R 34.11-94 (mit Parameter oid 1.2.643.2.2.30.1 - 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01) wird unter dem Spitznamen GOSTR3411_CP implementiert, der GOST R 34.11-2012-Algorithmus mit Länge 256 Bit (oid 1.2.43.7.1.1.2.2 - 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02) werden unter dem Spitznamen STRIBOG256 und GOST R 34.11-2012 mit einer Länge von 512 Bit (oid 1.2.43.7) implementiert .1.1.2.3 - 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03) wird unter dem Spitznamen STRIBOG512 implementiert.
Unten finden Sie den Code des Moduls in C zur Berechnung des Hashwerts aus einem in einer Datei gespeicherten Dokument
Digest_gcrypt.c: #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> int main(int argc, char* argv[]) { gpg_error_t err; int algo = GCRY_MD_NONE; int i; unsigned char *h; size_t size; gcry_md_hd_t hd; FILE *fp; unsigned char buf[1024]; char *dgst_gost[] = {"GOSTR3411_CP", "STRIBOG256", "STRIBOG512", NULL}; i = 0; /* -*/ if (argc == 3) algo = gcry_md_map_name (argv[1]); if (algo == GCRY_MD_NONE) { fprintf(stderr, "Usage: digest_gcrypt <nick_name_digest> <file_for_digest>\n"); fprintf(stderr, "<nick_name_digest>="); while (dgst_gost[i] != NULL){ if (i > 0 ) fprintf(stderr, " | ", dgst_gost[i]); fprintf(stderr, "%s", dgst_gost[i]); i++; } fprintf(stderr, "\n"); exit (1); } /* */ err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s\n", gcry_strerror (err)); exit (1); } /* */ if (!strcmp (argv[2], "-")) fp = stdin; else fp = fopen (argv[2], "r"); if (fp == NULL) { fprintf(stderr, "Cannot fopen file=%s\n", argv[2]); exit(1); } /* */ while (!feof (fp)) { size = fread (buf, 1, sizeof(buf), fp); gcry_md_write (hd, buf, size); } /* */ h = gcry_md_read(hd, 0); /* */ printf(" %s = %d ( )\n", argv[1], gcry_md_get_algo_dlen (algo)); printf(" %s:\n", argv[2]); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02x", h[i]); printf("\n"); fflush(stdout); /* */ gcry_md_reset(hd); gcry_md_close(hd); }
Wir übersetzen dieses Modul und erhalten das Dienstprogramm zur Hash-Berechnung:
$cc -o digest_file digest_file.c -lgcrypt $./digest_file Usage: digest_gcrypt <nick_name_digest> <file_for_digest> <nick_name_digest>=GOSTR3411_CP | STRIBOG256 | STRIBOG512 $./digest_file STRIBOG256 digest_file.c STRIBOG256 = 32 ( ) digest_file.c: f6818dfb26073747266dc721c332d703eb21f2b17e3433c809e0e23b68443d4a $
Bildung der elektronischen Signatur und deren Überprüfung
Nachdem wir den privaten Schlüssel und den Hash des Dokuments haben, können wir auch eine elektronische Signatur des Dokuments generieren:
gcry_error_t gcry_pk_sign (gcry sexp t *r_sig, gcry sexp t data, gcry sexp t skey ),
r_sig -sexp-Variable, in der die elektronische Signatur gespeichert wird,
skey - eine sexp-Variable mit einem privaten Schlüssel (siehe oben), mit der eine Signatur generiert wird.
data - sexp-variable, die die Art der Signatur (in unserem Fall gost) und den Hash des signierten Dokuments angibt.
Es ist zu beachten, dass der Hash-Wert, der an die Eingabe gcry_pk_sign zum Erzeugen der GOST R 34.10-Signatur geliefert wird, im Big-Endian-Format vorliegen sollte, d. H. tatsächlich auf den Kopf gestellt (wie ein Freund sagte: "Die russische Tradition, Digest-Bytes in Little-Endian-Reihenfolge zu behandeln"). In diesem Sinne ist die Vorbereitung der Datap-Geschlechtsvariablen wie folgt:
... gcry_sexp_t data; unsigned char c; int len_xy; gcry_mpi_t x; … printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); fflush(stdout); x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); show_sexp ("data :\n", data);
Alles ist bereit, die Signatur zu empfangen und anzuzeigen <source: lang = "cpp"> ...
gcry_sexp_t sig_r, sig_s;
...
/ * Unterschreibe den Hash * /
err = gcry_pk_sign (& sig, data, sec_key);
if (err) {
fprintf (stderr, "Signieren fehlgeschlagen:% s \ n", gcry_strerror (err));
Ausfahrt (1);
}}
/ * Wir drucken die Unterschrift * /
show_sexp ("ECC GOST SIG: \ n", sig);
/ * Wähle die Komponenten der Signatur r und s aus und drucke sie aus * /
sig_r = gcry_sexp_find_token (sig, "r", 0);
if (! sig_r) {
fprintf (stderr, "r Teil fehlt in sig \ n");
Ausfahrt (1);
}}
show_sexp ("ECC GOST Sig R-Teil: \ n", sig_r);
sig_s = gcry_sexp_find_token (sig, "s", 0);
if (! sig_s) {
fprintf (stderr, "Teil fehlt in sig \ n");
Ausfahrt (1);
}}
show_sexp ("ECC GOST Sig S-Teil: \ n", sig_s);
... Sie können die Signatur wie folgt überprüfen:
… err = gcry_pk_verify (sig, data, pub_key); if (err) { putchar ('\n'); show_sexp ("seckey:\n", sec_key); show_sexp ("data:\n", data); show_sexp ("sig:\n", sig); fprintf(stderr, "verify failed: %s\n", gcry_strerror (err)); exit(1); } …
Überprüfung der elektronischen Signatur von GOST R 34.10 in Zertifikaten
Eines der Hauptziele der Public-Key-Infrastruktur (PKI) sind X509-Zertifikate. Die Empfehlungen von TC-26 zur Zusammensetzung und Struktur von Zertifikaten sind im Dokument „TECHNISCHE SPEZIFIKATION DER VERWENDUNG DER ALGORITHMEN GOST R 34.10, GOST R 34.11 IM ZERTIFIKATSPROFIL UND ZERTIFIKATSÜBERPRÜFUNG CRL (CRL) DER OFFENEN INFRASTRUKTUR DES SCHLÜSSELS 9 des X. Informationsschutz “(Protokoll Nr. 13 vom 24.04.2014).„ Gemäß diesen Empfehlungen stellen alle im russischen Kommunikationsministerium akkreditierten Zertifizierungsstellen Zertifikate aus.
Um die Signatur im Zertifikat zu überprüfen, müssen (siehe oben) der Hash des verifizierten Zertifikats, seine Signatur und der öffentliche Schlüssel des Stammzertifikats abgerufen werden. Beachten Sie nur, dass bei einem selbstsignierten Zertifikat alle diese Daten in einem Zertifikat gespeichert sind.
Arbeiten mit PKI / PKI-Objekten (Zertifikate, CMS, Anforderungen)

usw.) In der Regel wird die KSBA-Bibliothek verwendet, die derzeit die Empfehlungen von TK-26 nicht unterstützt, obwohl
Erfahrungen mit einer solchen Unterstützung vorliegen. Grundsätzlich hindert nichts daran, dem ksba-Projekt Unterstützung für die TK-26-Empfehlungen hinzuzufügen.
In dieser Phase, der GCrypt-Testphase, ist es praktisch, Skriptsprachen wie
Python , Tcl usw. zu verwenden, um mit PKI / PKI-Objekten (Zertifikaten usw.) mit russischer Kryptografie zu arbeiten. Die Skriptsprache
Tcl wurde ausgewählt. Es ist einfach und unkompliziert, einen Prototyp des Programms darauf zu schreiben, der dann in die Sprache C übertragen wird. Tcl enthält ein PKI-Paket, das Prozeduren zum Parsen von PKI-Objekten enthält, insbesondere die Prozedur zum Parsen von Zertifikaten :: pki :: x509 :: parse_cert. Basierend auf der Prozedur parse_cert wurde die Prozedur parse_gost_cert entwickelt, die sich in der Datei befindet
parse_cert_gost_oid.tcl proc parse_cert_gost {cert} { # parray ::pki::oids #puts "parse_cert_gost=$cert" set cert_seq "" if { [string range $cert 0 9 ] == "-----BEGIN" } { array set parsed_cert [::pki::_parse_pem $cert "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"] set cert_seq $parsed_cert(data) } else { #FORMAT DER set cert_seq $cert } set finger [::sha1::sha1 $cert_seq] set ret(fingerprint) $finger binary scan $cert_seq H* certdb set ret(certdb) $certdb #puts "CERTDB=$certdb" array set ret [list] # Decode X.509 certificate, which is an ASN.1 sequence ::asn::asnGetSequence cert_seq wholething ::asn::asnGetSequence wholething cert set ret(cert) $cert set ret(cert) [::asn::asnSequence $ret(cert)] if {0} { set ff [open "/tmp/tbs.der" w] fconfigure $ff -translation binary puts -nonewline $ff $ret(cert) close $ff } binary scan $ret(cert) H* ret(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) incr ret(version) } else { set ret(version) 1 } ::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 binary scan $pubkeyinfo H* pubkeyinfoG set ret(pubkeyinfo) $pubkeyinfoG ::asn::asnGetSequence pubkeyinfo pubkey_algoid binary scan $pubkey_algoid H* pubkey_algoidG set ret(pubkey_algoid) $pubkey_algoidG ::asn::asnGetObjectIdentifier pubkey_algoid ret(pubkey_algo) ::asn::asnGetBitString pubkeyinfo pubkey set extensions_list [list] while {$cert != ""} { ::asn::asnPeekByte cert peek_tag switch -- [format {0x%02x} $peek_tag] { "0xa1" { ::asn::asnGetContext cert - issuerUniqID } "0xa2" { ::asn::asnGetContext cert - subjectUniqID } "0xa3" { ::asn::asnGetContext cert - extensions_ctx ::asn::asnGetSequence extensions_ctx extensions while {$extensions != ""} { ::asn::asnGetSequence extensions extension ::asn::asnGetObjectIdentifier extension ext_oid ::asn::asnPeekByte extension peek_tag if {$peek_tag == 0x1} { ::asn::asnGetBoolean extension ext_critical } else { set ext_critical false } ::asn::asnGetOctetString extension ext_value_seq set ext_oid [::pki::_oid_number_to_name $ext_oid] set ext_value [list $ext_critical] switch -- $ext_oid { id-ce-basicConstraints { ::asn::asnGetSequence ext_value_seq ext_value_bin if {$ext_value_bin != ""} { ::asn::asnGetBoolean ext_value_bin allowCA } else { set allowCA "false" } if {$ext_value_bin != ""} { ::asn::asnGetInteger ext_value_bin caDepth } else { set caDepth -1 } lappend ext_value $allowCA $caDepth } default { binary scan $ext_value_seq H* ext_value_seq_hex lappend ext_value $ext_value_seq_hex } } lappend extensions_list $ext_oid $ext_value } } } } set ret(extensions) $extensions_list ::asn::asnGetSequence wholething signature_algo_seq ::asn::asnGetObjectIdentifier signature_algo_seq ret(signature_algo) ::asn::asnGetBitString wholething ret(signature) # Convert values from ASN.1 decoder to usable values if needed set ret(notBefore) [::pki::x509::_utctime_to_native $ret(notBefore)] set ret(notAfter) [::pki::x509::_utctime_to_native $ret(notAfter)] set ret(serial_number) [::math::bignum::tostr $ret(serial_number)] set ret(data_signature_algo) [::pki::_oid_number_to_name $ret(data_signature_algo)] set ret(signature_algo) [::pki::_oid_number_to_name $ret(signature_algo)] set ret(pubkey_algo) [::pki::_oid_number_to_name $ret(pubkey_algo)] set ret(issuer) [::pki::x509::_dn_to_string $issuer] set ret(subject) [::pki::x509::_dn_to_string $subject] set ret(signature) [binary format B* $ret(signature)] binary scan $ret(signature) H* ret(signature) # Handle RSA public keys by extracting N and E #puts "PUBKEY_ALGO=$ret(pubkey_algo)" 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 } "GostR2012_256" - "GostR2012_512" - "GostR2001" - "1.2.643.2.2.19" - "1.2.643.7.1.1.1.1" - "1.2.643.7.1.1.1.2" { # gost2001, gost2012-256,gost2012-512 set pubkey [binary format B* $pubkey] #puts "LL=[string length $pubkey]" if {[string length $pubkey] < 100} { set pubk [string range $pubkey 2 end] } else { set pubk [string range $pubkey 3 end] } set pubkey_revert [string reverse $pubk] binary scan $pubkey_revert H* ret(pubkey_rev) binary scan $pubkey H* ret(pubkey) set ret(type) gost ::asn::asnGetSequence pubkey_algoid pubalgost #OID - ::asn::asnGetObjectIdentifier pubalgost ret(paramkey) set ret(paramkey) [::pki::_oid_number_to_name $ret(paramkey)] #OID - ::asn::asnGetObjectIdentifier pubalgost ret(hashkey) set ret(hashkey) [::pki::_oid_number_to_name $ret(hashkey)] #puts "ret(paramkey)=$ret(paramkey)\n" #puts "ret(hashkey)=$ret(hashkey)\n" } } return [array get ret] } proc set_nick_for_oid {} { # set ::pki::oids(1.2.643.2.2.19) "gost2001pubKey" # set ::pki::oids(1.2.643.2.2.3) "gost2001withGOST3411_94" 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.3) " 34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) " 34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) " 34.10-2012-512" # set ::pki::oids(1.2.643.2.2.3) "gost" # set ::pki::oids(1.2.643.7.1.1.3.2) "gost" # set ::pki::oids(1.2.643.7.1.1.3.3) "gost" # # set ::pki::oids(1.2.643.2.2.19) " 34.10-2001" # set ::pki::oids(1.2.643.7.1.1.1.1) " 34.10-2012 256 " # set ::pki::oids(1.2.643.7.1.1.1.2) " 34.10-2012 512 " set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid- 34.10-2001 34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" # { "GOST2001-CryptoPro-A", set ::pki::oids("GOST2001-CryptoPro-XchA" }, # { "GOST2001-CryptoPro-C", set ::pki::oids("GOST2001-CryptoPro-XchB" }, set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid- 34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" }
Die Prozedur parse_gost_cert dient zum Parsen von Zertifikaten basierend auf russischer Kryptographie.
Diese Datei enthält auch das Verfahren zum Zuweisen von Spitznamen zu Oids der russischen Kryptographie unter Berücksichtigung des GCrypt-Projekts:
proc set_nick_for_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.3) " 34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) " 34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) " 34.10-2012-512" # set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid- 34.10-2001 34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid- 34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" }
Mit der Prozedur parse_gost_cert können Sie ein
TBS-Zertifikat , eine Zertifikatsignatur, einen Signaturtyp und einen öffentlichen Schlüssel abrufen. Wenn wir ein selbstsigniertes Zertifikat in Betracht ziehen, reicht dies aus, um die Signatur zu überprüfen. Wenn wir die Signatur eines von einem anderen Zertifikat signierten (ausgestellten) Zertifikats überprüfen (Aussteller und Betreff des Zertifikats stimmen nicht überein), gehen Sie wie folgt vor, um Informationen zum Überprüfen der Signatur zu erhalten:
- Aus dem verifizierten Zertifikat extrahieren wir das TBS-Zertifikat, die Art der Signatur und die Signatur selbst.
- Wir extrahieren den öffentlichen Schlüssel aus dem Stammzertifikat.
Bei der Vorbereitung der Quelldaten für die Überprüfung der Zertifikatsignatur ist die strikte Einhaltung der Empfehlungen von TK-26 am verantwortungsvollsten. Für einen öffentlichen Schlüsselwert klingen sie folgendermaßen:
Die Darstellung des öffentlichen Schlüssels von GostR3410-2012-256-PublicKey ist identisch mit der Darstellung des öffentlichen Schlüssels von GOST R 34.10-2001 [IETF RFC 4491] und MUSS 64 Oktette enthalten, wobei die ersten 32 Oktette die x-Koordinate in der Little-Endian-Ansicht und die zweiten 32 Oktette die Koordinate enthalten y in der Little-Endian-Ansicht.
GostR3410-2012-512-PublicKey Public Key View MUSS enthalten
128 Oktette, wobei die ersten 64 Oktette die x-Koordinate in der Little-Endian-Ansicht und die zweiten 64 Oktette die y-Koordinate in der Little-Endian-Ansicht enthalten.
Beim Hochladen einer Signatur sollten Sie Folgendes beachten:
Der Signaturalgorithmus GOST R 34.10-2012 mit einer 256-Bit-Hash-Codelänge wird verwendet, um eine digitale Signatur in Form von zwei 256-Bit-Zahlen, r und s, zu generieren. Seine Darstellung in Form eines Oktettstrings (OCTET STRING) ist identisch mit der Darstellung der Signatur GOST R 34.10-2001 [IETF RFC 4491] und besteht aus 64 Oktetten; Die ersten 32 Oktette enthalten die Zahl s in der Big-Endian-Darstellung (das höchste Oktett wird zuerst geschrieben), und die zweiten 32 Oktette enthalten die Zahl r in der Big-Endian-Darstellung.
Der Signaturalgorithmus GOST R 34.10-2012 mit einer Länge von 512 Hashcodes wird verwendet, um eine digitale Signatur in Form von zwei 512-Bit-Zahlen, öffentlichen Schlüsseln gemäß r und s, zu generieren. Seine Darstellung als Oktettstring (OCTET STRING) besteht aus 128 Oktetten; Die ersten 64 Oktette enthalten die Zahl s in der Big-Endian-Darstellung (das höchste Oktett wird zuerst geschrieben), und die zweiten 64 Oktette enthalten die Zahl r in der Big-Endian-Darstellung.
Basierend auf diesen Empfehlungen bereitet das Tcl-Modul
parse_certs_for_verify_load.tcl die Quelldaten für die Überprüfung der Zertifikatsignatur vor
sieht so aus: #!/usr/bin/tclsh # PKI package require pki # - source parse_cert_gost_oid.tcl if {$argc != 2} { puts "Usage: parse_certs_for_verify_load.tcl < > < >" exit 1 } # if {[file exists "[lindex $argv 0]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts " [lindex $argv 0]" exit 1 } # if {[file exists "[lindex $argv 1]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts " [lindex $argv 1]" exit 1 } # nick- - oid- set_nick_for_oid set file [lindex $argv 0] set f [open $file r] set cert [read $f] close $f #READ DER-format if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } array set cert_user [parse_cert_gost $cert] # -26 set len_sign [expr [string length $cert_user(signature)] /2] set sign_r [string range $cert_user(signature) $len_sign end] set sign_s [string range $cert_user(signature) 0 [expr $len_sign - 1]] #puts " : $file" set file [lindex $argv 1] set f [open $file r] set cert [read $f] close $f #READ DER if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } # array set cert_ca [parse_cert_gost $cert] # -26 set len_key [expr [string length $cert_ca(pubkey_rev)]/2] set key_pub_left [string range $cert_ca(pubkey_rev) $len_key end] set key_pub_right [string range $cert_ca(pubkey_rev) 0 [expr $len_key - 1]] puts "/* C-: */" #TBS- puts "char tbc\[\] = \"[string toupper $cert_user(cert)]\";" # - puts "char hash_type\[\] = \"$cert_ca(hashkey)\";" # puts "unsigned char pub_key_ca\[\] = \"(public-key \"" puts "\"(ecc \"" puts "\" (curve $cert_ca(paramkey))\"" puts "\" (q #04[string toupper $key_pub_left$key_pub_right]#)\"" puts "\")\"" puts "\")\";" # puts "unsigned char sig_cert\[\] = \"(sig-val\"" puts "\"($cert_ca(type) \"" puts "\" (r #[string toupper $sign_r]#)\"" puts "\" (s #[string toupper $sign_s]#)\"" puts "\")\"" puts "\")\";" puts "/* TEST_from_TCL.h*/" puts "/* TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt TEST_from_Tcl*/"
Zum Testen nehmen wir zwei echte Zertifikate:Zertifikat "UTs 1 IS GUTs.pem"-----BEGIN CERTIFICATE-----
MIIGrDCCBlugAwIBAgILAOvBBVQAAAAAAFkwCAYGKoUDAgIDMIIBSjEeMBwGCSqG
SIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwT
Nzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMT8wPQYD
VQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g0KLQstC10YDRgdC6
0LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB0LLRj9C30Ywg0KDQ
vtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDExGjAYBggqhQMDgQMB
ARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy0L3QvtC5INGD0LTQ
vtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgDAeFw0xNjAzMTYxMjAy
NTFaFw0yNzA3MTIxMjAyNTFaMIIBITEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEeMBwGCSqGSIb3DQEJARYPZGl0
QG1pbnN2eWF6LnJ1MTwwOgYDVQQJDDMxMjUzNzUg0LMuINCc0L7RgdC60LLQsCDR
g9C7LiDQotCy0LXRgNGB0LrQsNGPINC0LjcxLDAqBgNVBAoMI9Cc0LjQvdC60L7Q
vNGB0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
HDAaBgNVBAgMEzc3INCzLiDQnNC+0YHQutCy0LAxCzAJBgNVBAYTAlJVMRswGQYD
VQQDDBLQo9CmIDEg0JjQoSDQk9Cj0KYwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAQYH
KoUDAgIeAQNDAARAx70Y7WYQ4ODtdiSSx3MJnr1GQBEIExiPO/LWj1TRKES1OcDI
YgtdOBGVYSvbsStl10jkAOG0OpnGsd2by4m+LaOCA0MwggM/MA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFBGIaV7vyOlz23pXNbzSAfMF/qfRMAsGA1UdDwQEAwIB
hjCCAYsGA1UdIwSCAYIwggF+gBSLmDuJGFHo75wCeLjqyNQgslXJXaGCAVKkggFO
MIIBSjEeMBwGCSqGSIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJS
VTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB
0LrQstCwMT8wPQYDVQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g
0KLQstC10YDRgdC60LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB
0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDEx
GjAYBggqhQMDgQMBARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy
0L3QvtC5INGD0LTQvtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgIIQ
NGgeQMtB7zOpoLfIdpKaKTBZBgNVHR8EUjBQMCagJKAihiBodHRwOi8vcm9zdGVs
ZWNvbS5ydS9jZHAvZ3VjLmNybDAmoCSgIoYgaHR0cDovL3JlZXN0ci1wa2kucnUv
Y2RwL2d1Yy5jcmwwJgYFKoUDZG8EHQwb0JrRgNC40L/RgtC+LdCf0YDQviBDU1Ag
My42MCUGA1UdIAQeMBwwCAYGKoUDZHEBMAgGBiqFA2RxAjAGBgRVHSAAMIHGBgUq
hQNkcASBvDCBuQwj0J/QkNCa0JwgwqvQmtGA0LjQv9GC0L7Qn9GA0L4gSFNNwrsM
INCf0JDQmiDCq9CT0L7Qu9C+0LLQvdC+0Lkg0KPQpsK7DDbQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzMvMi8yLTk5OSDQvtGCIDA1LjA3LjIwMTIMONCX0LDQ
utC70Y7Rh9C10L3QuNC1IOKEliAxNDkvNy8xLzQvMi02MDMg0L7RgiAwNi4wNy4y
MDEyMAgGBiqFAwICAwNBAKVYokUvb7XAMPJF38ZPKO2BFBldmGEfqsfmsiO35Y52
kTkx512H3YLqWMrOLjIfVMJhc+DTCNeXWY6bhK4/DRU=
-----END CERTIFICATE-----
und sein Stammzertifikat "SEC Minkomsvyaz.pem":-----BEGIN CERTIFICATE-----
MIIFGTCCBMigAwIBAgIQNGgeQMtB7zOpoLfIdpKaKTAIBgYqhQMCAgMwggFKMR4w
HAYJKoZIhvcNAQkBFg9kaXRAbWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYD
VQQIDBM3NyDQsy4g0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
PzA9BgNVBAkMNjEyNTM3NSDQsy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXR
gNGB0LrQsNGPLCDQtC4gNzEsMCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfR
jCDQoNC+0YHRgdC40LgxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqF
AwOBAwEBEgwwMDc3MTA0NzQzNzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg
0YPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMB4XDTEyMDcy
MDEyMzExNFoXDTI3MDcxNzEyMzExNFowggFKMR4wHAYJKoZIhvcNAQkBFg9kaXRA
bWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYDVQQIDBM3NyDQsy4g0JzQvtGB
0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAxPzA9BgNVBAkMNjEyNTM3NSDQ
sy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXRgNGB0LrQsNGPLCDQtC4gNzEs
MCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfRjCDQoNC+0YHRgdC40LgxGDAW
BgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg0YPQtNC+0YHRgtC+0LLQtdGA
0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqF
AwICHgEDQwAEQI+lv3kQI8jWka1kMVdbvpvFioP0Pyn3Knmp+2XD6KgPWnXEIlSR
X8g/IYracDr51YsNc2KE3C7mkH6hA3M3ofujggGCMIIBfjCBxgYFKoUDZHAEgbww
gbkMI9Cf0JDQmtCcIMKr0JrRgNC40L/RgtC+0J/RgNC+IEhTTcK7DCDQn9CQ0Jog
wqvQk9C+0LvQvtCy0L3QvtC5INCj0KbCuww20JfQsNC60LvRjtGH0LXQvdC40LUg
4oSWIDE0OS8zLzIvMi05OTkg0L7RgiAwNS4wNy4yMDEyDDjQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzcvMS80LzItNjAzINC+0YIgMDYuMDcuMjAxMjAuBgUq
hQNkbwQlDCPQn9CQ0JrQnCDCq9Ca0YDQuNC/0YLQvtCf0YDQviBIU03CuzBDBgNV
HSAEPDA6MAgGBiqFA2RxATAIBgYqhQNkcQIwCAYGKoUDZHEDMAgGBiqFA2RxBDAI
BgYqhQNkcQUwBgYEVR0gADAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUi5g7iRhR6O+cAni46sjUILJVyV0wCAYGKoUDAgIDA0EA23Re
ec/Y27rpMi+iFbgWCazGY3skBTq5ZGsQKOUxCe4mO7UBDACiWqdA0nvqiQMXeHgq
o//fO9pxuIHtymwyMg==
-----END CERTIFICATE-----
Wir werden die ersten Daten für die Überprüfung des Zertifikats „UTs 1 IS GUTs.pem“ vorbereiten: $ ./parse_certs_for_verify_load.tcl " 1 .pem" " .pem" > TEST_from_TCL.h $echo " TEST_from_TCL.h" $cat TEST_from_TCL.h /* C-: */ char tbc[] = "3082065B . . . "; char hash_type[] = "GOSTR3411_CP"; unsigned char pub_key_ca[] = "(public-key " "(ecc " " (curve GOST2001-CryptoPro-A)" " (q #040FA8E8C365FBA9792AF7293FF4838AC59BBE5B573164AD91D6C8231079BFA58FFBA1377303A17E90E62EDC8462730D8BD5F93A70DA8A213FC85F915422C4755A#)" ")" ")"; unsigned char sig_cert[] = "(sig-val" "(gost " " (r #913931E75D87DD82EA58CACE2E321F54C26173E0D308D797598E9B84AE3F0D15#)" " (s #A558A2452F6FB5C030F245DFC64F28ED8114195D98611FAAC7E6B223B7E58E76#)" ")" ")"; /* TEST_from_TCL.h*/ /* TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt TEST_from_Tcl*/ $
Die Überprüfung der Zertifikatsignatur wird vom Modul durchgeführt:TEST_from_TCL.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <gcrypt.h> #include "TEST_from_TCL.h" #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define xmalloc(a) gcry_xmalloc ((a)) static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * hex2buffer (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) return NULL; /* Invalid hex digits. */ ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } int main(int argc, char* argv[]) { gpg_error_t err; int algo; gcry_md_hd_t hd; unsigned char *tbs_ptr; size_t len_tbs; int i; unsigned char *h; gcry_sexp_t pub_key; gcry_sexp_t data; gcry_sexp_t sig; gcry_mpi_t x; int len_xy; unsigned char c; /* little-endian big-endian*/ unsigned short arch = 1; /* 0x0001 */ tbs_ptr = hex2buffer(tbc, &len_tbs); if (tbs_ptr == NULL) { fprintf (stderr, "Bad tbs\n"); exit(1); } algo = gcry_md_map_name (hash_type); if (algo == GCRY_MD_NONE) { fprintf (stderr, "Unknown algorithm '%s'\n", hash_type); exit (1); } err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s/%s\n", gcry_strsource (err), gcry_strerror (err)); exit (1); } gcry_md_write (hd, tbs_ptr, len_tbs); h = gcry_md_read(hd, 0); // len_xy = gcry_md_get_algo_dlen (algo); /* */ printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); // printf("\n %s\n", tbc); fflush(stdout); /* */ x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); /* */ gcry_md_reset(hd); gcry_md_close(hd); /* */ err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); show_sexp ("ECC GOST data cert:\n", data); fprintf (stderr, "\nStep 1\n"); /* */ err = gcry_sexp_sscan (&pub_key, NULL, pub_key_ca, strlen (pub_key_ca)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for pub_key_ca\n"); exit(1); } show_sexp ("ECC GOST public key:\n", pub_key); fprintf (stderr, "Step 2\n"); /* */ err = gcry_sexp_sscan (&sig, NULL, sig_cert, strlen (sig_cert)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for sig_cert\n"); exit(1); } show_sexp ("ECC GOST sig cert:\n", sig); fprintf (stderr, "Step 3\n"); /* */ err = gcry_pk_verify (sig, data, pub_key); if (err) { fprintf (stderr, "TEST_SEXP: verify cert failed\n"); exit (1); } fprintf (stderr, "TEST_SEXP: verify cert OK!!\n"); }
Wir übersetzen und führen das Dienstprogramm TEST_from_TCL aus: $cc –o TEST_from_TCL TEST_from_TCL.c –lgcrypt $./TEST_from_TCL little-endian =32 D485903E7E8D60820118329060C558B9C733D53CA608C0C79363ECE7B4C1F799ECC GOST data cert: (data (flags gost) (value
Wie Sie sehen, war die Überprüfung der Signatur des Zertifikats "UTs 1 IS GUTs.pem" erfolgreich. Das Stammzertifikat selbst muss noch überprüft werden "GUT Minkomsvyaz.pem". Es ist ganz einfach, führen Sie einfach den folgenden Befehl aus: $ parse_certs_for_verify_load.tcl " .pem" " .pem" > TEST_from_TCL.h $ ..
Wenn jemand die Zertifikate mit anderen GOST-Schlüsseln (GOST R 34.10-2012-256 oder GOST R 34.10-2012-512) überprüfen möchte, kann er CAFL63 CA verwenden und alle Zertifikate vorbereiten:
Die durchgeführten Untersuchungen haben also gezeigt, dass die GCrypt-Bibliothek möglicherweise funktioniert verwendet, um mit russischer Kryptographie zu arbeiten. Die unmittelbare Aussicht besteht darin, die KSBA-Bibliothek fertigzustellen und das pki-Paket der Tcl-Skriptsprache (oder möglicherweise Python) mit Unterstützung für die russische Kryptographie zu erweitern.Für diejenigen, die die GCrypt-Bibliothek zur Verschlüsselung verwenden möchten, empfehle ich einen Blick hier .