Infrastruktur für öffentliche Schlüssel: GnuPG / SMIME- und PKCS # 11-Token mit Unterstützung für die russische Kryptographie

Die Stunde "H" rückt unaufhaltsam näher: "Die Verwendung des Signaturschemas GOST R 34.10-2001 zum Generieren einer Signatur nach dem 31. Dezember 2018 ist nicht zulässig!" Und schließlich erschien am 16. Juli 2018 auf der Website des Federal Situation Center der Electronic Government ein Hinweis zu Beginn der Ausstellung eines Zertifikats über Verifizierungsschlüssel für elektronische Signaturen untergeordneter Zertifizierungszentren im Hauptzertifizierungszentrum gemäß GOST R 34.10-2012. Es ist zwar immer noch nicht klar, wann die Freigabe alter Zertifikate eingestellt wird. Aber der "Prozess hat begonnen" und es gefällt.

Die Einführung einer neuen elektronischen Signatur impliziert die Verfügbarkeit von Mitteln nicht nur für die Ausstellung von Zertifikaten gemäß GOST R 34.10-2012, sondern auch die Verfügbarkeit von Mitteln zur Erstellung und Überprüfung dieser Signatur. Sie können bereits auf den habr-Seiten über eines dieser Tools sprechen.



Die elektronische Signatur wird nicht nur im elektronischen Dokumentenmanagement (EDI), sondern auch in der elektronischen Korrespondenz (E-Mail) aktiv eingesetzt:



Wenn wir über OpenSource-Projekte im Bereich PKI auf der Basis von X509-Zertifikaten sprechen, ist das GnuPG / SMIME- Projekt neben Network Security Services (NSS) und OpenSSL sehr beliebt. Der kryptografische Kern dieses Projekts ist die LibGCrypt- Bibliothek. Es ist wichtig, dass diese Bibliothek die kryptografischen Algorithmen GOST R 34.10-2012 und GOST R 34.11-2012 (STRIBOG256 und STRIBOG512) unterstützt und zumindest für die Funktionen zum Generieren einer elektronischen Signatur und deren Überprüfung keine Verfeinerung erfordert. GnuPG verwendet die LibKSBA- Bibliothek zum Parsen und Bearbeiten von PKI-Objekten (Zertifikate, Zertifikatanforderungen, elektronische Signaturen usw.). Im Gegensatz zu LibGCrypt implementiert die libksba-Bibliothek die TK-26- Empfehlungen für kryptografische Nachrichten im CMS-Format nicht. Der Artikel zeigt die Modernisierung der libksba-Bibliothek im Zusammenhang mit der Analyse von X509-Zertifikaten und CMS-Nachrichten (PKCS7), mit der die elektronische Signatur von Zertifikaten und die elektronische Signatur von PKCS # 7-Dokumenten überprüft werden konnten. Heute werden wir noch weiter gehen und der Bibliothek Funktionen für die Bildung des CMS-Formats PKCS # 7 hinzufügen. Dies bietet Unterstützung für die elektronische Signatur gemäß GOST R 34.10-2001.2012 (nach einer gewissen Modernisierung des GnuPG-Projekts selbst) und im GnuPG / SM-Modul.

Am Ende wird es möglich sein, eine inländische elektronische Signatur sowohl im KMail-Mail-Client (übrigens und in vielen anderen Mail-Clients) als auch im Dienstprogramm Kleopatra zu verwenden, um die elektronische Signatur und ihre Bildung für verschiedene Dateien zu überprüfen:



Bild Nun zur Hauptsache. In Zukunft gehen wir davon aus, dass Benutzer ihre persönlichen Zertifikate (privater Schlüssel und Zertifikat eines Verifizierungsschlüssels für elektronische Signaturen) auf PKCS # 11-Token / Smartcards speichern, auf denen mindestens die Funktionen zur Erzeugung elektronischer Signaturen implementiert sind (CKM_GOSTR3410-Mechanismen zum Generieren elektronischer Signaturen gemäß GOST R. 34.10.2001/2012 mit einer Schlüssellänge von 256 Bit und / oder CKM_GOSTR3410_512 zur Bildung eines ES nach GOST R 34.10-2012 mit einer Schlüssellänge von 512 Bit). Die beste Option ist, wenn die Token- / Smartcard-Funktionalität den PKCS # 11 v.2.40-Standard unterstützt.

GnuPG verwendet das Dienstprogramm gnupg_pkcs11_scd, um auf PKCS # 11- Token zuzugreifen. In unseren Beispielen wird das Dienstprogramm gnupg_pkcs11_csd Version 0.9.1 verwendet . Die Hauptaufgabe dieses Dienstprogramms (zusätzlich zur Organisation der Ausführung von kryptografischen PKCS # 11-Funktionen, z. B. zum Signieren eines Hashs) besteht darin, die auf dem Token gespeicherten Zertifikate zu analysieren, Informationen über den offenen Schlüssel in Form eines S-Ausdrucks abzurufen und diese in der Kette zu übertragen. Diese Operation wird von der Funktion keyutil_get_cert_sexp ausgeführt, die sich in der Datei keyutil.c befindet. Leider ist dieses Dienstprogramm nur für die Arbeit mit RSA-Zertifikaten vorgesehen. Da wir jedoch über die libksba-Bibliothek verfügen und diese sogar für die Arbeit mit GOST-Zertifikaten modifiziert haben, stellte sich heraus, dass es überraschend einfach war, die Funktion keyutil_get_cert_sexp neu zu schreiben, um alle von der libksba-Bibliothek unterstützten Zertifikate zu verarbeiten:

/* Convert X.509 RSA/ECC/DSA/GOST public key into gcrypt internal sexp form. The resul is stored in *sexp, which must be freed (using ) when not needed anymore. *sexp must be NULL on entry, since it is overwritten. */ gpg_err_code_t keyutil_get_cert_sexp ( unsigned char *der, size_t len, gcry_sexp_t *p_sexp ) { gpg_err_code_t error = GPG_ERR_GENERAL; gcry_mpi_t n_mpi = NULL; gcry_mpi_t e_mpi = NULL; gcry_sexp_t sexp = NULL; gpg_error_t err; ksba_sexp_t p; ksba_cert_t ks_cert; size_t n; err = ksba_cert_new (&ks_cert); if (err) { error = GPG_ERR_BAD_KEY; goto cleanup; } err = ksba_cert_init_from_mem (ks_cert, der, len); if (err) { error = GPG_ERR_BAD_KEY; goto cleanup; } /* Get the public key from the certificate. */ p = ksba_cert_get_public_key (ks_cert); n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { ksba_free (p); error = GPG_ERR_BAD_KEY; goto cleanup; } err = gcry_sexp_sscan ( p_sexp, NULL, p, n); if (err) { error = GPG_ERR_BAD_KEY; goto cleanup; } ksba_free (p); error = GPG_ERR_NO_ERROR; goto cleanup; #if 0 if ( (error = keyutil_get_cert_mpi ( der, len, &n_mpi, &e_mpi )) != GPG_ERR_NO_ERROR ) { goto cleanup; } if ( gcry_sexp_build ( &sexp, NULL, "(public-key (rsa (n %m) (e %m)))", n_mpi, e_mpi ) ) { error = GPG_ERR_BAD_KEY; goto cleanup; } *p_sexp = sexp; sexp = NULL; error = GPG_ERR_NO_ERROR; #endif cleanup: if (n_mpi != NULL) { gcry_mpi_release (n_mpi); n_mpi = NULL; } if (e_mpi != NULL) { gcry_mpi_release (e_mpi); e_mpi = NULL; } if (sexp != NULL) { gcry_sexp_release (sexp); sexp = NULL; } return error; } 

Der Originalcode ist in einem Block eingeschlossen:

 #if 0 … #endif 

Der vollständige Patch für das Dienstprogramm gnupg_pkcs11_scd ist hier
 diff -u PKCS11_CSD_ORIG/command.c PKCS11_CSD/command.c --- PKCS11_CSD_ORIG/command.c 2018-07-19 16:25:20.778692015 +0300 +++ PKCS11_CSD/command.c 2018-07-19 16:25:10.238691435 +0300 @@ -1002,6 +1002,8 @@ { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; + CK_MECHANISM_TYPE mech_type = CKM_RSA_PKCS; + int pubkey_type; gpg_err_code_t error = GPG_ERR_GENERAL; pkcs11h_certificate_id_t cert_id = NULL; @@ -1021,8 +1023,18 @@ INJECT_SHA224, INJECT_SHA256, INJECT_SHA384, - INJECT_SHA512 + INJECT_SHA512, +/*For GOST*/ + INJECT_GOSTR3411_CP, + INJECT_STRIBOG256, + INJECT_STRIBOG512 } inject = INJECT_NONE; +#define NSSCK_VENDOR_PKCS11_RU_TEAM 0xd4321000 //0x80000000|0x54321000 +#define NSSCK_VENDOR_PKSC11_RU_TEAM NSSCK_VENDOR_PKCS11_RU_TEAM +#define CK_VENDOR_PKCS11_RU_TEAM_TC26 NSSCK_VENDOR_PKCS11_RU_TEAM +#define CKM_GOSTR3410 0x00001201 +// TC 26 +#define CKM_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TC26 |0x006) if (data->data == NULL) { error = GPG_ERR_INV_DATA; @@ -1107,6 +1119,16 @@ else if (!strcmp(hash, "sha512") && data->size == 0x40) { inject = INJECT_SHA512; } + else if (!strcmp(hash, "gost3411_94") || !strcmp(hash, "gost3411_CP") || !strcmp(hash, "gostr3411_94") || !strcmp(hash, "gostr3411_CP")) { + inject = INJECT_GOSTR3411_CP; + } + else if (!strcmp(hash, "gost3411_12_256") || !strcmp(hash, "gostr3411_12_256") || !strcasecmp(hash, "stribog256")) { + inject = INJECT_STRIBOG256; + } + else if (!strcmp(hash, "gost3411_12_512") || !strcmp(hash, "gostr3411_12_512") || !strcasecmp(hash, "stribog512")) { + inject = INJECT_STRIBOG512; + } + else { common_log (LOG_DEBUG, "unsupported hash algo (hash=%s,size=%d)", hash, data->size); error = GPG_ERR_UNSUPPORTED_ALGORITHM; @@ -1169,6 +1191,23 @@ oid = sha512_prefix; oid_size = sizeof(sha512_prefix); break; +/* */ + case INJECT_GOSTR3411_CP: + oid = ""; + oid_size = 0; + mech_type = CKM_GOSTR3410; + break; + case INJECT_STRIBOG256: + oid = ""; + oid_size = 0; + mech_type = CKM_GOSTR3410; + break; + case INJECT_STRIBOG512: + oid = ""; + oid_size = 0; + mech_type = CKM_GOSTR3410_512; + break; + default: error = GPG_ERR_INV_DATA; goto cleanup; @@ -1232,7 +1271,7 @@ (error = common_map_pkcs11_error ( pkcs11h_certificate_signAny ( cert, - CKM_RSA_PKCS, + mech_type, _data->data, _data->size, NULL, @@ -1252,7 +1291,7 @@ (error = common_map_pkcs11_error ( pkcs11h_certificate_signAny ( cert, - CKM_RSA_PKCS, + mech_type, _data->data, _data->size, sig, @@ -1298,6 +1337,9 @@ return gpg_error (error); } +/* */ +#define CKM_GOSTR3410_KEY_WRAP 0x00001203 + /** Decrypt data (set by SETDATA) with certificate id in line. */ gpg_error_t cmd_pkdecrypt (assuan_context_t ctx, char *line) { @@ -1309,6 +1351,7 @@ int session_locked = 0; cmd_data_t *data = (cmd_data_t *)assuan_get_pointer (ctx); cmd_data_t _data; + CK_MECHANISM_TYPE mech_type; if ( data == NULL || @@ -1317,6 +1360,13 @@ error = GPG_ERR_INV_DATA; goto cleanup; } + if(memmem(data->data, data->size,"\x2A\x85\x03", 3)){ +/* */ + mech_type = CKM_GOSTR3410_KEY_WRAP; + } + else{ + mech_type = CKM_RSA_PKCS; + } /* * Guess.. taken from openpgp card implementation @@ -1376,7 +1426,7 @@ (error = common_map_pkcs11_error ( pkcs11h_certificate_decryptAny ( cert, - CKM_RSA_PKCS, + mech_type, _data.data, _data.size, NULL, @@ -1396,7 +1446,7 @@ (error = common_map_pkcs11_error ( pkcs11h_certificate_decryptAny ( cert, - CKM_RSA_PKCS, + mech_type, _data.data, _data.size, ptext, @@ -1591,6 +1641,29 @@ goto cleanup; } } + else if (!strcmp (line, "APPTYPE")) { + if ( + (error = assuan_write_status( + ctx, + "APPTYPE", + "NKS" + )) != GPG_ERR_NO_ERROR + ) { + goto cleanup; + } + } + else if (!strcmp (line, "NKS-VERSION")) { + if ( + (error = assuan_write_status( + ctx, + "NKS-VERSION", + "3" + )) != GPG_ERR_NO_ERROR + ) { + goto cleanup; + } + } + else if (!strcmp (line, "KEY-ATTR")) { int i; for (i=0;i<3;i++) { diff -u PKCS11_CSD_ORIG/keyutil.c PKCS11_CSD/keyutil.c --- PKCS11_CSD_ORIG/keyutil.c 2018-07-19 16:25:20.779692015 +0300 +++ PKCS11_CSD/keyutil.c 2018-07-19 16:51:48.934779338 +0300 @@ -45,6 +45,7 @@ typedef const unsigned char *my_openssl_d2i_t; #endif #endif +#include <ksba.h> gpg_err_code_t keyutil_get_cert_mpi ( @@ -193,10 +194,10 @@ return error; } -/** - Convert X.509 RSA public key into gcrypt internal sexp form. Only RSA - public keys are accepted at the moment. The resul is stored in *sexp, - which must be freed (using ) when not needed anymore. *sexp must be + +/* + Convert X.509 RSA/ECC/DSA/GOST public key into gcrypt internal sexp form. The resul is stored + in *sexp, which must be freed (using ) when not needed anymore. *sexp must be NULL on entry, since it is overwritten. */ gpg_err_code_t @@ -210,6 +211,40 @@ gcry_mpi_t e_mpi = NULL; gcry_sexp_t sexp = NULL; + gpg_error_t err; + ksba_sexp_t p; + ksba_cert_t ks_cert; + size_t n; + + err = ksba_cert_new (&ks_cert); + if (err) { + error = GPG_ERR_BAD_KEY; + goto cleanup; + } + err = ksba_cert_init_from_mem (ks_cert, der, len); + if (err) { + error = GPG_ERR_BAD_KEY; + goto cleanup; + } + /* Get the public key from the certificate. */ + p = ksba_cert_get_public_key (ks_cert); + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + if (!n) + { + ksba_free (p); + error = GPG_ERR_BAD_KEY; + goto cleanup; + } + err = gcry_sexp_sscan ( p_sexp, NULL, p, n); + if (err) { + error = GPG_ERR_BAD_KEY; + goto cleanup; + } + ksba_free (p); + error = GPG_ERR_NO_ERROR; + goto cleanup; +#if 0 + if ( (error = keyutil_get_cert_mpi ( der, @@ -237,6 +272,7 @@ *p_sexp = sexp; sexp = NULL; error = GPG_ERR_NO_ERROR; +#endif cleanup: 


In Anbetracht dieses Patches wird das folgende Skript verwendet, um das Dienstprogramm gnupg_pkcs11_scd zu erstellen:

 export LIBS=" -lksba" #./configure --without-gnutls ./configure --without-openssl make 

Dieser Patch wird schließlich die Verwendung von GOST-Token (einschließlich der vom russischen FSB zertifizierten) ermöglichen, zumindest für die Bildung einer elektronischen Signatur.

Wir werden nicht auf die Verbesserungen der libksba-Bibliothek eingehen, sondern nur geben
vollständiger Patch für libksba
 diff -u KSBA_ORIG/cms.c KSBA/cms.c --- KSBA_ORIG/cms.c 2013-03-15 23:26:38.000000000 +0400 +++ KSBA/cms.c 2018-07-19 08:24:48.774106713 +0300 @@ -1581,6 +1581,15 @@ Note that IDX is only used for consistency checks. */ +/* For GOST + r_sig = (sig-val + (gost + (r <mpi>) + (s <mpi>) + ) + (hash <name_hash>)) +*/ + gpg_error_t ksba_cms_set_sig_val (ksba_cms_t cms, int idx, ksba_const_sexp_t sigval) { @@ -1588,6 +1597,7 @@ unsigned long n; struct sig_val_s *sv, **sv_tail; int i; + int gost; if (!cms) return gpg_error (GPG_ERR_INV_VALUE); @@ -1615,6 +1625,11 @@ /* Break out the algorithm ID. */ if (!(n = snext (&s))) return gpg_error (GPG_ERR_INV_SEXP); + gost = 0; + if (n==4 && s[0] == 'g' && s[1] == 'o' && s[2] == 's' && s[3] == 't') { + /* kludge to allow "gost" to be passed as algorithm name */ + gost = 1; + } sv = xtrycalloc (1, sizeof *sv); if (!sv) @@ -1680,6 +1695,11 @@ s++; n--; } +if(gost){ + sv->value = xtrymalloc (n * 2); +} +else + sv->value = xtrymalloc (n); if (!sv->value) { @@ -1687,6 +1707,11 @@ xfree (sv); return gpg_error (GPG_ERR_ENOMEM); } +/*r  s     - -26*/ +if(gost == 1) + memcpy (sv->value + n, s, n); +else + memcpy (sv->value, s, n); sv->valuelen = n; s += n; @@ -1698,6 +1723,84 @@ return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* but may also be an invalid one */ } s++; +if(gost == 1){ + unsigned char sh[30]; + + if (*s != '(') + { + xfree (sv->algo); + xfree (sv); + return gpg_error (digitp (s)? GPG_ERR_UNKNOWN_SEXP : GPG_ERR_INV_SEXP); + } + s++; + if (!(n = snext (&s))) + { + xfree (sv->algo); + xfree (sv); + return gpg_error (GPG_ERR_INV_SEXP); + } + + s += n; /* ignore the name of the parameter */ + + if (!digitp(s)) + { + xfree (sv->algo); + xfree (sv); + /* May also be an invalid S-EXP. */ + return gpg_error (GPG_ERR_UNKNOWN_SEXP); + } + if (!(n = snext (&s))) + { + xfree (sv->algo); + xfree (sv); + return gpg_error (GPG_ERR_INV_SEXP); + } + + if (n > 1 && !*s) + { /* We might have a leading zero due to the way we encode + MPIs - this zero should not go into the OCTECT STRING. */ + s++; + n--; + } +/*r  s     - -26*/ + memcpy (sv->value, s, n); + sv->valuelen += n; + s += n; + + if ( *s != ')' && s[1] != ')' && s[2] != '(' ) + { + xfree (sv->value); + xfree (sv->algo); + xfree (sv); + return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* but may also be an invalid one */ + } + s++;s++;s++; + if (!(n = snext (&s))) + { + xfree (sv->algo); + xfree (sv); + return gpg_error (GPG_ERR_INV_SEXP); + } + s += n; + if (!(n = snext (&s))) + { + xfree (sv->algo); + xfree (sv); + return gpg_error (GPG_ERR_INV_SEXP); + } + strncpy(sh, s, n); + if(!strcmp(sh, "1.2.643.7.1.1.2.2") || !strcasecmp(sh, "stribog256")) + sv->algo = xtrystrdup ("1.2.643.7.1.1.1.1"); + else if(!strcmp(sh, "1.2.643.7.1.1.2.3") || !strcasecmp(sh, "stribog512")) + sv->algo = xtrystrdup ("1.2.643.7.1.1.1.2"); + else if(!strcmp(sh, "1.2.643.2.2.9") || !strcasecmp(sh, "gostr3411_CP")) + sv->algo = xtrystrdup ("1.2.643.2.2.19"); + else { + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + } + s += n; + +} /* fixme: end loop over parameters */ /* we need 2 closing parenthesis */ diff -u KSBA_ORIG/dn.c KSBA/dn.c --- KSBA_ORIG/dn.c 2016-08-22 11:40:58.000000000 +0300 +++ KSBA/dn.c 2018-06-26 19:24:32.000000000 +0300 @@ -48,6 +48,7 @@ 2 = David Chadwick, July 2003 <draft-ietf-pkix-dnstrings-02.txt> 3 = Peter Gutmann + 4 = tk26 */ const char *description; size_t oidlen; @@ -74,12 +75,17 @@ "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19", "0.9.2342.19200300.100.1.25" }, {"UID", 1, "userid", 10, "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01", "0.9.2342.19200300.100.1.1 " }, -{"EMAIL", 3, "emailAddress", 9, +{"E", 1, "emailAddress", 9, "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01", "1.2.840.113549.1.9.1" }, +/*oid-    TK-26*/ +{"OGRN", 4, "OGRN", 5, "\x2a\x85\x03\x64\x01", "1.2.643.100.1" }, +{"INN", 4, "INN", 8, "\x2a\x85\x03\x03\x81\x03\x01\x01", "1.2.643.3.131.1.1" }, +{"SNILS", 4, "SNILS", 5, "\x2a\x85\x03\x64\x03", "1.2.643.100.3" }, +{"OGRNIP", 4, "OGRNIP", 5, "\x2a\x85\x03\x64\x05", "1.2.643.100.5" }, + { NULL } }; - #define N 0x00 #define P 0x01 static unsigned char charclasses[128] = { @@ -555,8 +561,8 @@ name = NULL; for (i=0; oid_name_tbl[i].name; i++) { - if (oid_name_tbl[i].source == 1 - && node->len == oid_name_tbl[i].oidlen +/* oid-  DN    */ + if (node->len == oid_name_tbl[i].oidlen && !memcmp (image+node->off+node->nhdr, oid_name_tbl[i].oid, node->len)) { @@ -604,6 +610,9 @@ case TYPE_UTF8_STRING: append_utf8_value (image+node->off+node->nhdr, node->len, sb); break; +/*  NUMERIC_STRING*/ + case TYPE_NUMERIC_STRING: + case TYPE_PRINTABLE_STRING: case TYPE_IA5_STRING: /* we assume that wrong encodings are latin-1 */ diff -u KSBA_ORIG/keyinfo.c KSBA/keyinfo.c --- KSBA_ORIG/keyinfo.c 2015-10-28 13:41:48.000000000 +0300 +++ KSBA/keyinfo.c 2018-07-19 09:03:27.936234230 +0300 @@ -45,7 +45,6 @@ #include "convert.h" #include "ber-help.h" - /* Constants used for the public key algorithms. */ typedef enum { @@ -98,6 +97,19 @@ "1.2.840.10045.2.1", /* ecPublicKey */ "\x2a\x86\x48\xce\x3d\x02\x01", 7, 1, PKALGO_ECC, "ecc", "q", "\x80" }, +/*oid- - */ + { /* GOST3410-2001 */ + "1.2.643.2.2.19", /* gostPublicKey-2001 */ + "\x2a\x85\x03\x02\x02\x13", 6, + 1, PKALGO_ECC, "ecc", "q", "\x80" }, + { /* GOST3410-2012-256 */ + "1.2.643.7.1.1.1.1", /* gostPublicKey-2012-256 */ + "\x2a\x85\x03\x07\x01\x01\x01\x01", 8, + 1, PKALGO_ECC, "ecc", "q", "\x80" }, + { /* GOST3410-2012-512 */ + "1.2.643.7.1.1.1.2", /* gostPublicKey-2012-512 */ + "\x2a\x85\x03\x07\x01\x01\x01\x02", 8, + 1, PKALGO_ECC, "ecc", "q", "\x80" }, {NULL} }; @@ -209,6 +221,31 @@ "1.3.36.3.4.3.2.2", /* sigS_ISO9796-2rndWithrsa_ripemd160 */ "\x2B\x24\x03\x04\x03\x02\x02", 7, 0, PKALGO_RSA, "rsa", "s", "\x82", NULL, NULL, "rmd160" }, + { /* GOST3410-2001 */ + "1.2.643.2.2.19", /* gostPublicKey-2001 */ + "\x2a\x85\x03\x02\x02\x13", 6, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "gostr3411_CP" }, + { /* GOST3410-2012-256 */ + "1.2.643.7.1.1.1.1", /* gostPublicKey-2012-256 */ + "\x2a\x85\x03\x07\x01\x01\x01\x01", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog256"}, + { /* GOST3410-2012-512 */ + "1.2.643.7.1.1.1.2", /* gostPublicKey-2012-512 */ + "\x2a\x85\x03\x07\x01\x01\x01\x02", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog512"}, + + { /* GOST3411-2012-256 */ + "1.2.643.7.1.1.3.2", /* STRIBOG256 */ + "\x2a\x85\x03\x07\x01\x01\x03\x02", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog256" }, + { /* GOST3411-2012-512 */ + "1.2.643.7.1.1.3.3", /* STRIBOG512 */ + "\x2a\x85\x03\x07\x01\x01\x03\x03", 8, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "stribog512" }, + { /* GOST3410-2001-Signature */ + "1.2.643.2.2.3", /* gosrPublicKey-2001 avec signature */ + "\x2a\x85\x03\x02\x02\x03", 6, + 1, PKALGO_ECC, "gost", "s", "\x80", NULL, NULL, "gostr3411_CP" }, {NULL} }; @@ -218,6 +255,20 @@ "1.2.840.113549.1.1.1", /* rsaEncryption (RSAES-PKCA1-v1.5) */ "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", 9, 1, PKALGO_RSA, "rsa", "a", "\x82" }, +/*oid- -    */ + { + "1.2.643.2.2.19", /*GOST R34.10-2001 */ + "\x2A\x85\x03\x02\x02\x13", 6, + 1, PKALGO_ECC, "ecc", "a", "\x80" }, + { + "1.2.643.7.1.1.1.1", /*GOST R34.10-2012-256 */ + "\x2A\x85\x03\x07\x01\x01\x01\x01", 8, + 1, PKALGO_ECC, "ecc", "a", "\x80" }, + { + "1.2.643.7.1.1.1.2", /*GOST R34.10-2012-512 */ + "\x2A\x85\x03\x07\x01\x01\x01\x02", 8, + 1, PKALGO_ECC, "ecc", "a", "\x80" }, + {NULL} }; @@ -267,6 +318,13 @@ { "1.2.643.2.2.35.1", "GOST2001-CryptoPro-A" }, { "1.2.643.2.2.35.2", "GOST2001-CryptoPro-B" }, { "1.2.643.2.2.35.3", "GOST2001-CryptoPro-C" }, +/* oid-       34.10-2001/2012*/ +// "GOST2001-CryptoPro-XchA" + { "1.2.643.2.2.36.0", "GOST2001-CryptoPro-A" }, +// "GOST2001-CryptoPro-XchB" + { "1.2.643.2.2.36.1", "GOST2001-CryptoPro-C" }, + + { "1.2.643.7.1.2.1.2.1", "GOST2012-tc26-A" }, { "1.2.643.7.1.2.1.2.2", "GOST2012-tc26-B" }, @@ -393,7 +451,8 @@ /* get the object identifier */ if (!derlen) return gpg_error (GPG_ERR_INV_KEYINFO); - c = *der++; derlen--; + c = *der++; + derlen--; if ( c != 0x06 ) return gpg_error (GPG_ERR_UNEXPECTED_TAG); /* not an OBJECT IDENTIFIER */ TLV_LENGTH(der); @@ -418,6 +477,7 @@ if (!derlen) return gpg_error (GPG_ERR_INV_KEYINFO); c = *der++; derlen--; + if ( c == 0x05 ) { /*printf ("parameter: NULL \n"); the usual case */ @@ -471,6 +531,7 @@ else { /* printf ("parameter: with tag %02x - ignored\n", c); */ + TLV_LENGTH(der); seqlen -= der - startparm; /* skip the value */ @@ -692,6 +753,8 @@ const unsigned char *ctrl; const char *elem; struct stringbuf sb; + int gost_key; + char *parm_oid_hash = NULL; *r_string = NULL; @@ -701,6 +764,7 @@ c = *der++; derlen--; if ( c != 0x30 ) return gpg_error (GPG_ERR_UNEXPECTED_TAG); /* not a SEQUENCE */ + TLV_LENGTH(der); /* and now the inner part */ err = get_algorithm (1, der, derlen, &nread, &off, &len, &is_bitstr, @@ -715,13 +779,36 @@ && !memcmp (der+off, pk_algo_table[algoidx].oid, len)) break; } + if (!pk_algo_table[algoidx].oid) return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM); if (!pk_algo_table[algoidx].supported) return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); +/*   1 - - */ + gost_key = !memcmp(pk_algo_table[algoidx].oidstring, "1.2.643", 7); if (parm_off && parm_len && parm_type == TYPE_OBJECT_ID) parm_oid = ksba_oid_to_str (der+parm_off, parm_len); + else +/*  - */ + if (parm_off && parm_len && parm_type == TYPE_SEQUENCE && gost_key && (*(der+parm_off + off - 2) == TYPE_OBJECT_ID)){ +/* oid curve  -*/ + int len_hash; + int len_curve; + unsigned char* addr_hash; + unsigned char* addr_curve; + len_curve = (int) *(der+parm_off + off -1); + addr_curve = der+parm_off + off; + parm_oid = ksba_oid_to_str (addr_curve, len_curve); +/* oid   -*/ + if( *(addr_curve + len_curve)== TYPE_OBJECT_ID) { + len_hash = (unsigned int) *(der+parm_off + off + len_curve + 1); + addr_hash = addr_curve + len_curve + 2; + parm_oid_hash = ksba_oid_to_str (addr_hash, len_hash); + } +/* oid    -*/ + } + else if (parm_off && parm_len) { parmder = der + parm_off; @@ -762,6 +849,13 @@ put_stringbuf_sexp (&sb, "curve"); put_stringbuf_sexp (&sb, parm_oid); put_stringbuf (&sb, ")"); +/* oid-  - */ + if(gost_key && parm_oid_hash) { + put_stringbuf (&sb, "("); + put_stringbuf_sexp (&sb, "hash"); + put_stringbuf_sexp (&sb, parm_oid_hash); + put_stringbuf (&sb, ")"); + } } /* If parameters are given and we have a description for them, parse @@ -851,6 +945,43 @@ put_stringbuf (&sb, "("); tmp[0] = *elem; tmp[1] = 0; put_stringbuf_sexp (&sb, tmp); +/*        TK-26*/ + if(gost_key){ + unsigned char pk[129]; + unsigned char *x; + unsigned char *y; + int len_pk; + int len_xy; + int i; + unsigned char c_inv; + int offset; + pk[0] = 0x04; + if(len == 131 || len == 66){ + offset = 0; + if(der[0] == 0x04 && der[1] & 0x80) + offset = 3; + else if(der[0] == 0x04 && der[1] & 0x40) + offset = 2; + len_pk = len - offset; + memcpy(&pk[1], der + offset, len_pk); + x = &pk[1]; + len_xy = len_pk / 2; + y = x + len_xy; +/*REVERT-INVERTIROVANIE*/ + for (i = 0; i < (len_xy/2); i++) { + c_inv = *(x + i); + *(x + i) = *(x + len_xy - i - 1); + *(x + len_xy - i - 1) = c_inv; + } + for (i = 0; i < (len_xy/2); i++) { + c_inv = y[i]; + y[i] = y[len_xy - i -1]; + y[len_xy - i - 1] = c_inv; + } + put_stringbuf_mem_sexp (&sb, pk , len_pk + 1); + } + } else + put_stringbuf_mem_sexp (&sb, der, len); der += len; derlen -= len; @@ -1606,6 +1737,7 @@ const unsigned char *ctrl; const char *elem; struct stringbuf sb; + int gost_sign; /* FIXME: The entire function is very similar to keyinfo_to_sexp */ *r_string = NULL; @@ -1615,7 +1747,6 @@ else algo_table = enc_algo_table; - err = get_algorithm (1, der, derlen, &nread, &off, &len, &is_bitstr, NULL, NULL, NULL); if (err) @@ -1628,11 +1759,16 @@ && !memcmp (der+off, algo_table[algoidx].oid, len)) break; } + if (!algo_table[algoidx].oid) return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM); + if (!algo_table[algoidx].supported) return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); +/*    oid-*/ + gost_sign = !memcmp(algo_table[algoidx].oidstring, "1.2.643", 7); + der += nread; derlen -= nread; @@ -1682,8 +1818,21 @@ put_stringbuf (&sb, "("); tmp[0] = *elem; tmp[1] = 0; +/*   ,  r  ,  s   */ + if(gost_sign == 1 && algo_table == sig_algo_table){ + put_stringbuf_sexp (&sb, "r"); + put_stringbuf_mem_sexp (&sb, der+(len/2), len/2); + put_stringbuf (&sb, ")"); + put_stringbuf (&sb, "("); + put_stringbuf_sexp (&sb, "s"); + put_stringbuf_mem_sexp (&sb, der, len/2); + } + else{ + put_stringbuf_sexp (&sb, tmp); put_stringbuf_mem_sexp (&sb, der, len); + } + der += len; derlen -= len; put_stringbuf (&sb, ")"); 


Die vorhandenen Kommentare ermöglichen es, die Logik der eingeführten Änderungen zu verstehen, die in erster Linie durch die Empfehlungen des TC-26 bestimmt wird .

Es bleiben Änderungen an den gnupg-agent-Modulen (Agentenverzeichnis) und dem gpgsm-Modul (sm-Verzeichnis) vorzunehmen.

Der Patch für das gnupg-agent-Modul ist hier
 diff -u AGENT_ORIG/call-scd.c AGENT/call-scd.c --- AGENT_ORIG/call-scd.c 2017-05-15 15:13:22.000000000 +0300 +++ AGENT/call-scd.c 2018-07-19 09:27:36.904313900 +0300 @@ -806,6 +806,14 @@ case GCRY_MD_SHA256: return "--hash=sha256"; case GCRY_MD_SHA384: return "--hash=sha384"; case GCRY_MD_SHA512: return "--hash=sha512"; +/*  34.11-2001/2012*/ + case GCRY_MD_STRIBOG512: + return "--hash=stribog512"; + case GCRY_MD_STRIBOG256: + return "--hash=stribog256"; + case GCRY_MD_GOSTR3411_CP: + return "--hash=gostr3411_CP"; + default: return ""; } } @@ -884,6 +892,7 @@ else snprintf (line, sizeof line, "PKSIGN %s %s", hash_algo_option (mdalgo), keyid); + rc = assuan_transact (ctrl->scd_local->ctx, line, put_membuf_cb, &data, inq_needpin, &inqparm, @@ -901,6 +910,7 @@ } *r_buf = get_membuf (&data, r_buflen); + return unlock_scd (ctrl, 0); } diff -u AGENT_ORIG/divert-scd.c AGENT/divert-scd.c --- AGENT_ORIG/divert-scd.c 2017-04-03 18:13:56.000000000 +0300 +++ AGENT/divert-scd.c 2018-07-19 09:29:03.896318684 +0300 @@ -160,6 +160,17 @@ log_error ("no object identifier for algo %d\n", algo); return gpg_error (GPG_ERR_INTERNAL); } +/*-*/ + switch(algo) { + case GCRY_MD_STRIBOG512: + case GCRY_MD_STRIBOG256: + case GCRY_MD_GOSTR3411_CP: + case GCRY_MD_GOSTR3411_94: + asnlen = 0; + break; + default : + break; + } frame = xtrymalloc (asnlen + digestlen); if (!frame) @@ -423,6 +434,7 @@ (void)desc_text; rc = ask_for_card (ctrl, shadow_info, &kid); + if (rc) return rc; @@ -498,7 +510,7 @@ n = snext (&s); if (!n) return gpg_error (GPG_ERR_INV_SEXP); - if (smatch (&s, n, "rsa")) + if (smatch (&s, n, "rsa") || smatch (&s, n, "ecc")) { if (*s != '(') return gpg_error (GPG_ERR_UNKNOWN_SEXP); diff -u AGENT_ORIG/pksign.c AGENT/pksign.c --- AGENT_ORIG/pksign.c 2017-05-15 15:13:22.000000000 +0300 +++ AGENT/pksign.c 2018-07-19 09:30:28.771323350 +0300 @@ -328,6 +328,7 @@ int is_RSA = 0; int is_ECDSA = 0; int is_EdDSA = 0; + int is_ECGOST = 0; rc = agent_public_key_from_file (ctrl, ctrl->keygrip, &s_pkey); if (rc) @@ -345,6 +346,21 @@ is_RSA = 1; else if (key_type == GCRY_PK_ECDSA) is_ECDSA = 1; +/* -*/ + if (is_ECDSA) { + switch(ctrl->digest.algo) + { + case GCRY_MD_STRIBOG512: + case GCRY_MD_STRIBOG256: + case GCRY_MD_GOSTR3411_CP: + case GCRY_MD_GOSTR3411_94: + is_ECGOST = 1; + break; + default : + is_ECGOST = 0; + break; + } + } } { @@ -361,7 +377,7 @@ } if (rc) { - log_error ("smartcard signing failed: %s\n", gpg_strerror (rc)); + log_error ("agent_pksign_do: smartcard signing failed: %s\n", gpg_strerror (rc)); goto leave; } @@ -396,7 +412,8 @@ r_buflen = s_buflen = len/2; - if (*buf & 0x80) + if ((*buf & 0x80) && !is_ECGOST) + { r_buflen++; r_buf_allocated = xtrymalloc (r_buflen); @@ -409,8 +426,8 @@ } else r_buf = buf; + if ((*(buf + len/2) & 0x80) && !is_ECGOST) - if (*(buf + len/2) & 0x80) { s_buflen++; s_buf_allocated = xtrymalloc (s_buflen); @@ -427,6 +444,15 @@ else s_buf = buf + len/2; + if(is_ECGOST){ + rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(gost(r%b)(s%b))(hash %s))", + s_buflen, s_buf, + r_buflen, r_buf, + gcry_md_algo_name(ctrl->digest.algo)); + gcry_log_debugsxp ("SIG_VAL", s_sig); + } + else + rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))", r_buflen, r_buf, s_buflen, s_buf); 

Der Patch für das gpgsm-Modul ist hier zu sehen
 diff -u SM_ORIG/call-agent.c SM/call-agent.c --- SM_ORIG/call-agent.c 2017-04-03 18:13:56.000000000 +0300 +++ SM/call-agent.c 2018-07-19 09:37:08.411345324 +0300 @@ -234,6 +234,7 @@ rc = start_agent (ctrl); if (rc) return rc; + inq_parm.ctrl = ctrl; inq_parm.ctx = agent_ctx; @@ -313,6 +314,14 @@ case GCRY_MD_RMD160:hashopt = "--hash=rmd160"; break; case GCRY_MD_MD5: hashopt = "--hash=md5"; break; case GCRY_MD_SHA256:hashopt = "--hash=sha256"; break; +/*-*/ + case GCRY_MD_STRIBOG512: + hashopt = "--hash=stribog512"; break; + case GCRY_MD_STRIBOG256: + hashopt = "--hash=stribog256"; break; + case GCRY_MD_GOSTR3411_CP: + hashopt = "--hash=gostr3411_CP"; break; + default: return gpg_error (GPG_ERR_DIGEST_ALGO); } @@ -357,7 +366,20 @@ xfree (sigbuf); return 0; } - p = stpcpy (p, "(7:sig-val(3:rsa(1:s" ); +/*  -*/ + switch(digestalgo) + { + case GCRY_MD_STRIBOG512: + case GCRY_MD_STRIBOG256: + case GCRY_MD_GOSTR3411_CP: + case GCRY_MD_GOSTR3411_94: + p = stpcpy (p, "(7:sig-val(3:ecc(1:s" ); + break; + default: + p = stpcpy (p, "(7:sig-val(3:rsa(1:s" ); + break; + } + sprintf (p, "%u:", (unsigned int)sigbuflen); p += strlen (p); memcpy (p, sigbuf, sigbuflen); diff -u SM_ORIG/certcheck.c SM/certcheck.c --- SM_ORIG/certcheck.c 2017-04-03 18:13:56.000000000 +0300 +++ SM/certcheck.c 2018-07-19 09:37:52.028347722 +0300 @@ -71,11 +71,13 @@ size_t nframe; unsigned char *frame; - if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA) + if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA || pkalgo == GCRY_PK_ECC) + { unsigned int qbits; - if ( pkalgo == GCRY_PK_ECDSA ) + if ( pkalgo == GCRY_PK_ECDSA || pkalgo == GCRY_PK_ECC) + qbits = gcry_pk_get_nbits (pkey); else qbits = get_dsa_qbits (pkey); @@ -169,7 +171,7 @@ memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len; assert ( n == nframe ); } - if (DBG_CRYPTO) +// if (DBG_CRYPTO) { int j; log_debug ("encoded hash:"); @@ -177,6 +179,22 @@ log_printf (" %02X", frame[j]); log_printf ("\n"); } + int i; + for (i = 0; i < (nframe/2); i++) { + unsigned char c; + c = frame[i]; + frame[i] = frame[nframe - i -1]; + frame[nframe - i - 1] = c; + } + if (DBG_CRYPTO) + { + int j; + log_debug ("GOST encoded hash:"); + for (j=0; j < nframe; j++) + log_printf (" %02X", frame[j]); + log_printf ("\n"); + } + } gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe); xfree (frame); diff -u SM_ORIG/gpgsm.c SM/gpgsm.c --- SM_ORIG/gpgsm.c 2017-05-15 15:13:22.000000000 +0300 +++ SM/gpgsm.c 2018-07-19 09:38:33.277349990 +0300 @@ -471,6 +471,7 @@ { switch (algo) { + case GCRY_PK_ECC: case GCRY_PK_RSA: case GCRY_PK_ECDSA: return gcry_pk_test_algo (algo); @@ -1577,6 +1578,10 @@ opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.3"; else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA256") ) opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.4"; + else if (!strcmp (opt.def_cipher_algoid, "GOST28147") ) +// opt.def_cipher_algoid = "1.2.643.2.2.21"; + opt.def_cipher_algoid = "1.2.643.2.2.31.1"; + if (cmd != aGPGConfList) { diff -u SM_ORIG/keylist.c SM/keylist.c --- SM_ORIG/keylist.c 2017-05-15 15:13:22.000000000 +0300 +++ SM/keylist.c 2018-07-19 20:20:11.560466784 +0300 @@ -769,6 +769,42 @@ unsigned int nbits; algoname = gcry_pk_algo_name (gpgsm_get_key_algo_info (cert, &nbits)); +/*  -*/ + if(!strncasecmp(algoname, "ecc", 3)){ + gpg_error_t err; + ksba_sexp_t p; + size_t n; + gcry_sexp_t s_pkey, l2; + const char *str_hash; + const char *str_curve; + /* Get the public key from the issuer certificate. */ + p = ksba_cert_get_public_key (cert); + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + err = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + ksba_free (p); +/* */ + l2 = gcry_sexp_find_token (s_pkey, "hash", 0); + str_hash = gcry_sexp_nth_string (l2, 1); + gcry_sexp_release (l2); +/* curve*/ + l2 = gcry_sexp_find_token (s_pkey, "curve", 0); + str_curve = gcry_sexp_nth_string (l2, 1); + gcry_sexp_release (l2); + gcry_sexp_release (s_pkey); + if(!memcmp(str_hash, "1.2.643.7", 9)){ +/* GOST R 34.10-2012-512 */ + es_fprintf (fp, " keyType: %u bit %s (Curve: %s))\n", + nbits, "GOST R 34.10-2012", str_curve); + } else if(!memcmp(str_hash, "1.2.643.2", 9)){ +/* GOST R 34.10-2012-246 */ + es_fprintf (fp, " keyType: %u bit %s (Curve: %s))\n", + nbits, "GOST R 34.10-2001", str_curve); + } else + es_fprintf (fp, " keyType: %u bit %s\n", + nbits, algoname? algoname:"?"); + } + else + es_fprintf (fp, " keyType: %u bit %s\n", nbits, algoname? algoname:"?"); } @@ -1118,6 +1154,42 @@ unsigned int nbits; algoname = gcry_pk_algo_name (gpgsm_get_key_algo_info (cert, &nbits)); +/*  -*/ + if(!strncasecmp(algoname, "ecc", 3)){ + gpg_error_t err; + ksba_sexp_t p; + size_t n; + gcry_sexp_t s_pkey, l2; + const char *str_hash; + const char *str_curve; + /* Get the public key from the issuer certificate. */ + p = ksba_cert_get_public_key (cert); + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + err = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + ksba_free (p); +/* */ + l2 = gcry_sexp_find_token (s_pkey, "hash", 0); + str_hash = gcry_sexp_nth_string (l2, 1); + gcry_sexp_release (l2); +/* curve*/ + l2 = gcry_sexp_find_token (s_pkey, "curve", 0); + str_curve = gcry_sexp_nth_string (l2, 1); + gcry_sexp_release (l2); + gcry_sexp_release (s_pkey); + if(!memcmp(str_hash, "1.2.643.7", 9)){ +/* GOST R 34.10-2012-512 */ + es_fprintf (fp, " keyType: %u bit %s (Curve: %s))\n", + nbits, "GOST R 34.10-2012", str_curve); + } else if(!memcmp(str_hash, "1.2.643.2", 9)){ +/* GOST R 34.10-2012-246 */ + es_fprintf (fp, " keyType: %u bit %s (Curve: %s))\n", + nbits, "GOST R 34.10-2001", str_curve); + } else + es_fprintf (fp, " keyType: %u bit %s\n", + nbits, algoname? algoname:"?"); + } + else + es_fprintf (fp, " key type: %u bit %s\n", nbits, algoname? algoname:"?"); } diff -u SM_ORIG/sign.c SM/sign.c --- SM_ORIG/sign.c 2017-05-15 15:13:22.000000000 +0300 +++ SM/sign.c 2018-07-19 09:41:05.738358373 +0300 @@ -33,7 +33,41 @@ #include "keydb.h" #include "../common/i18n.h" +char *cert_get_digest_algo_from_pk(ksba_cert_t cert) { + gpg_error_t err; + ksba_sexp_t p; + size_t n; + gcry_sexp_t s_pubkey; + char buf[50]; + const char *s; + gcry_sexp_t h_pk; + + /* Get the public key from the certificate. */ + p = ksba_cert_get_public_key (cert); + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + if (!n) + { + ksba_free (p); + return NULL; + } + err = gcry_sexp_sscan ( &s_pubkey, NULL, p, n); + ksba_free (p); + if (err) { + return NULL; + } + h_pk = gcry_sexp_find_token (s_pubkey, "hash", 0); + if (h_pk){ + s = gcry_sexp_nth_data (h_pk, 1, &n); + memcpy(buf, s, n); + buf[n] = '\0'; + gcry_sexp_release (s_pubkey); + gcry_sexp_release (h_pk); + return (strdup(buf)); + } else { + return NULL; + } +} /* Hash the data and return if something was hashed. Return -1 on error. */ static int @@ -301,8 +335,6 @@ return err; } - - /* Perform a sign operation. @@ -328,6 +360,8 @@ ksba_isotime_t signed_at; certlist_t cl; int release_signerlist = 0; + const unsigned char *shash; + size_t lshash; audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN); @@ -435,8 +469,15 @@ } else { + oid = (char *)cert_get_digest_algo_from_pk(cl->cert); + if (oid == NULL || strncmp(oid, "1.2.643", 7)) + oid = ksba_cert_get_digest_algo (cl->cert); cl->hash_algo = oid ? gcry_md_map_name (oid) : 0; + if(oid != NULL && !strcmp(oid, "1.2.643.2.2.30.1")){ + cl->hash_algo = GCRY_MD_GOSTR3411_CP; + } + } switch (cl->hash_algo) { @@ -446,6 +487,15 @@ case GCRY_MD_SHA256: oid = "2.16.840.1.101.3.4.2.1"; break; case GCRY_MD_SHA384: oid = "2.16.840.1.101.3.4.2.2"; break; case GCRY_MD_SHA512: oid = "2.16.840.1.101.3.4.2.3"; break; + case GCRY_MD_STRIBOG256: /* GOST R 34.11-2012, 256 bit. */ + oid = "1.2.643.7.1.1.2.2"; break; + case GCRY_MD_STRIBOG512: /* GOST R 34.11-2012, 512 bit. */ + oid = "1.2.643.7.1.1.2.3"; break; + case GCRY_MD_GOSTR3411_CP: /* GOST R 34.11-94. */ + oid = "1.2.643.2.2.9"; break; + case GCRY_MD_GOSTR3411_94: /* GOST R 34.11-94. TK26 */ + oid = "1.2.643.2.2.9"; break; + /* case GCRY_MD_WHIRLPOOL: oid = "No OID yet"; break; */ case GCRY_MD_MD5: /* We don't want to use MD5. */ 


Für gnupg-2.1.21 wurden Patches für die Module gnupg-agent und gpgsm erstellt .Das Übertragen dieser Patches ist beispielsweise für die Version gnupg-2.2.9 nicht schwierig.

Fügen Sie nach dem Zusammenstellen der geänderten Versionen von libksba, gnupg, dem Dienstprogramm gnupg_pkcs11_scd und der Installation auf dem System die folgenden Zeilen zur Konfigurationsdatei gpg-agent.conf hinzu, um eine Schnittstelle mit PKCS # 11-Token bereitzustellen:

 … scdaemon-program /usr/local/bin64/gnupg-pkcs11-scd pinentry-program /usr/bin/pinentry-qt … 

Geben Sie dann in der Konfigurationsdatei gnu-pkcs11-scd.conf die PKCS # 11-Bibliotheken für die zu verwendenden Token an:

 #     #  /usr/local/lib64/libls11sw2016.so … # Comma-separated list of available provider names. Then set # attributes for each provider using the provider-[name]-attribute # syntax. providers mytokenpkcs11 provider-mytokenpkcs11-library /usr/local/lib64/libls11sw2016.so # , ,  ruTokenECP #provider-metokenpkcs11-library /usr/local/lib64/librutokenecp.so provider-mytokenpkcs11-cert-private … 

Alles ist bereit zu gehen. Überprüfen Sie, ob das gpg-agent-Modul ausgeführt wird:

 bash-4.3$ gpg-agent --daemon gpg-agent[1196]: enabled debug flags: ipc gpg-agent:  gpg   -  , ,    gpg-agent: secmem usage: 0/32768 bytes in 0 blocks bash-4.3$ 

Kleopatra betritt also die Arena:



Die Schaltfläche Importieren wird hauptsächlich zum Importieren von Stammzertifikaten in das System verwendet, die zur Überprüfung der Gültigkeit persönlicher Zertifikate erforderlich sind.

Beim Starten des Dienstprogramms kleopatra wird möglicherweise ein PIN-Code für das verbundene Token angefordert:



In Zukunft wird dieses Fenster immer angezeigt, wenn der Zugriff auf den auf dem Token gespeicherten privaten Schlüssel erforderlich ist, z. B. beim Signieren einer E-Mail oder Datei.

Sie wählen also den Menüpunkt "Service → Smartcards verwalten". Wenn zuvor noch keine Zertifikate vom Token heruntergeladen wurden, wird das folgende Fenster angezeigt:



Um die Zertifikate auf dem verbundenen Token anzuzeigen, klicken Sie einfach auf die Schaltfläche LoadCertificates:



Wenn es keine Stammzertifikate für Benutzerzertifikate gibt (nicht zertifiziert), müssen Sie diese installieren (Datei → Importieren oder die Schaltfläche Importieren):



Nach der Installation der Stammzertifikate werden nun gute Zertifikate in der Liste der vertrauenswürdigen Zertifikate angezeigt:



Wenn mit dem Zertifikat alles in Ordnung ist (Ablaufdatum) ist nicht abgelaufen, die Kette der Stammzertifikate ist vorhanden, das Zertifikat wurde nicht widerrufen), es hat die Validierungsprüfung bestanden, dann kann ein solches Zertifikat, wenn sich ein privater Schlüssel auf dem Token befindet, zum Erstellen einer elektronischen Signatur verwendet werden.

All dies ist bei der Installation eines Zertifikats deutlich zu erkennen, das standardmäßig zum Signieren von Buchstaben im KMail-Mail-Client verwendet wird (Einstellungen → KMail-Einstellungen → Profile → <Eigentümerprofil> → Ändern → Kryptografie → SMIME-Signaturzertifikat):



Sie können auch versuchen, die Datei „fehlerhaft“ zu signieren mit Zertifikat “: Der



Versuch, ein Dokument mit einem„ schlechten Zertifikat “zu signieren, schlägt fehl. Sie müssen gute Zertifikate verwenden:



Damit eine E-Mail mit elektronischer Signatur signiert werden kann, aktivieren Sie einfach das Kontrollkästchen → Signatur L Brief: Der



Brief wird beim Senden automatisch signiert (Senden-Taste).

Abschließend möchte ich die Entwickler von Anwendungen für die inländische PKI noch einmal darauf aufmerksam machen, dass das GnuPG-Projekt als Entwicklungsumgebung sowohl OpenSSL als auch NSS in seinen Fähigkeiten nicht viel unterlegen ist.

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


All Articles