Infrastructure de clé publique: jetons GnuPG / SMIME et PKCS # 11 avec prise en charge de la cryptographie russe

L'heure "H" approche inexorablement: "l'utilisation du schéma de signature GOST R 34.10-2001 pour générer une signature après le 31 décembre 2018 n'est pas autorisée!" Et enfin, le 16 juillet 2018, un avis est apparu sur le site du Centre fédéral de situation du gouvernement électronique sur le début de la délivrance des certificats de clés pour vérifier les signatures électroniques des autorités de certification subordonnées au centre de certification en chef conformément à GOST R 34.10-2012. Certes, il n'est toujours pas clair quand la libération des anciens certificats va s'arrêter. Mais le "processus a commencé" et il plaît.

L'introduction d'une nouvelle signature électronique implique la disponibilité de fonds non seulement pour l' émission de certificats conformément à GOST R 34.10-2012, mais également la disponibilité de moyens pour générer et vérifier cette signature. Vous pouvez déjà parler de l'un de ces outils sur les pages habr.



La signature électronique est activement utilisée non seulement dans la gestion électronique des documents (EDI), mais également dans la correspondance électronique (e-mail):



Si nous parlons de projets OpenSource dans le domaine des PKI basés sur des certificats X509, alors avec les services de sécurité réseau (NSS), OpenSSL, le projet GnuPG / SMIME est très populaire. Le cœur cryptographique de ce projet est la bibliothèque LibGCrypt . De manière significative, cette bibliothèque prend en charge les algorithmes cryptographiques GOST R 34.10-2012 et GOST R 34.11-2012 (STRIBOG256 et STRIBOG512) et ne nécessite aucun raffinement, au moins pour les fonctions de génération d'une signature électronique et de sa vérification. GnuPG utilise la bibliothèque LibKSBA pour analyser et manipuler les objets PKI (certificats, demandes de certificats, signatures électroniques, etc.). Contrairement à LibGCrypt, la bibliothèque libksba n'implémente pas les recommandations TK-26 pour les messages cryptographiques au format CMS. L' article montre la modernisation de la bibliothèque libksba liée à l'analyse des certificats X509 et des messages CMS (PKCS7), qui a permis de vérifier la signature électronique des certificats et la signature électronique des documents PKCS # 7. Aujourd'hui, nous allons aller plus loin et ajouter des fonctionnalités à la bibliothèque pour la formation du format CMS PKCS # 7. Cela fournira un support pour la signature électronique conformément à GOST R 34.10-2001.2012 (après une certaine modernisation du projet GnuPG lui-même) et dans le module GnuPG / SM.

Et à la fin, il sera possible d'utiliser une signature électronique nationale à la fois dans le client de messagerie KMail (en passant, et dans de nombreux autres clients de messagerie), et dans l'utilitaire Kleopatra à la fois pour vérifier la signature électronique et sa formation pour divers fichiers:



image Maintenant sur la chose principale. À l'avenir, nous supposerons que les utilisateurs stockent leurs certificats personnels (clé privée et certificat de clé de vérification de signature électronique) sur des jetons / cartes à puce PKCS # 11 avec au moins les fonctions de génération de signature électronique implémentées sur eux (mécanismes CKM_GOSTR3410 pour générer des signatures électroniques conformément à GOST R 10/34/2001/2012 avec une longueur de clé de 256 bits et / ou CKM_GOSTR3410_512 pour former un ES selon GOST R 34.10-2012 avec une longueur de clé de 512 bits) La meilleure option est lorsque la fonctionnalité de jeton / carte à puce prend en charge la norme PKCS # 11 v.2.40.

GnuPG utilise l'utilitaire gnupg_pkcs11_scd pour accéder aux jetons PKCS # 11. Nos exemples utilisent la version 0.9.1 de l' utilitaire gnupg_pkcs11_csd . La tâche principale de cet utilitaire (en plus d'organiser l'exécution des fonctions cryptographiques PKCS # 11, par exemple, pour signer un hachage) est d'analyser les certificats stockés sur le jeton, d'obtenir des informations sur la clé ouverte sous la forme d'une expression S et de la transférer dans la chaîne. Cette opération est effectuée par la fonction keyutil_get_cert_sexp, qui se trouve dans le fichier keyutil.c. Malheureusement, cet utilitaire ne sert qu'à travailler avec des certificats RSA. Mais puisque nous avons la bibliothèque libksba à notre disposition, et même l'avons améliorée pour qu'elle fonctionne avec les certificats GOST, il s'est avéré étonnamment simple de réécrire la fonction keyutil_get_cert_sexp pour traiter tous les certificats pris en charge par la bibliothèque libksba:

/* 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; } 

Le code d'origine est enfermé dans un bloc:

 #if 0 … #endif 

Le patch complet pour l'utilitaire gnupg_pkcs11_scd est ici
 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: 


Compte tenu de ce correctif, le script suivant est utilisé pour créer l'utilitaire gnupg_pkcs11_scd:

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

Ce patch permettra à terme d'utiliser des jetons GOST (y compris certifiés par le FSB de Russie), au moins pour la formation d'une signature électronique.

Nous ne nous attarderons pas sur les améliorations apportées à la bibliothèque libksba, mais
patch complet pour 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, ")"); 


Les commentaires existants permettent de comprendre la logique des changements introduits, qui est principalement déterminée par les recommandations du TC-26 .

Il reste à apporter des modifications aux modules gnupg-agent (répertoire agent) et au module gpgsm (répertoire sm).

Le patch pour le module gnupg-agent est ici
 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); 

Le patch pour le module gpgsm peut ĂŞtre vu ici
 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. */ 


Des correctifs pour les modules gnupg-agent et gpgsm ont été créés pour gnupg-2.1.21 .Pour transférer ces correctifs, disons que la version gnupg-2.2.9 n'est pas difficile.

Après avoir assemblé les versions modifiées de libksba, gnupg, l'utilitaire gnupg_pkcs11_scd et les avoir installées sur le système, pour fournir une interface avec les jetons PKCS # 11, ajoutez les lignes suivantes au fichier de configuration gpg-agent.conf:

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

Ensuite, dans le fichier de configuration gnu-pkcs11-scd.conf, spécifiez les bibliothèques PKCS # 11 pour les jetons à utiliser:

 #     #  /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 … 

Tout est prêt à partir. Vérifiez que le module gpg-agent est en cours d'exécution:

 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$ 

Ainsi, kleopatra entre dans l'arène:



le bouton Importer est principalement utilisé pour importer des certificats racine dans le système, qui sont nécessaires pour vérifier la validité des certificats personnels.

Lors du démarrage de l'utilitaire kleopatra, un code PIN pour le token connecté peut être demandé: à



l'avenir, cette fenêtre apparaîtra toujours lorsque l'accès à la clé privée stockée sur le token est requis, par exemple lors de la signature d'un e-mail ou d'un fichier.

Vous sélectionnez donc l'élément de menu "Service → Gérer les cartes à puce". Si les certificats n'ont pas été téléchargés à partir du jeton auparavant, la fenêtre suivante s'affiche:



Pour voir les certificats sur le jeton connecté, cliquez simplement sur le bouton LoadCertificates:



S'il n'y a pas de certificats racine pour les certificats utilisateur (non certifiés), alors vous devez les installer (Fichier → Importer ou le bouton Importer):



Maintenant, après l'installation des certificats racine, de bons certificats peuvent être vus dans la liste des certificats approuvés:



Si tout va bien avec le certificat (date d'expiration n'a pas expiré, la chaîne de certificats racine est présente, le certificat n'a pas été révoqué), il a passé le contrôle de validation, alors un tel certificat, s'il y a une clé privée sur le jeton, peut être utilisé pour créer une signature électronique.

Tout cela peut être clairement vu lors de l'installation du certificat, qui par défaut sera utilisé pour signer des lettres dans le client de messagerie KMail (Paramètres → Paramètres KMail → Profils → <profil du propriétaire> → Modifier → Cryptographie → Certificat de signature SMIME):



Vous pouvez également essayer de signer le fichier «mauvais avec un certificat ":



Tenter de signer un document avec un" mauvais certificat "échoue, vous devez utiliser de bons certificats:



Pour qu'un e-mail soit signé par signature électronique, il suffit de cocher les options → Signer Lettre L: La



lettre sera automatiquement signée lors de l'envoi (bouton d'envoi).

En conclusion, je voudrais une fois de plus attirer l'attention des développeurs d'applications pour l'ICP nationale sur le fait que le projet GnuPG en tant qu'environnement de développement n'est pas très inférieur dans ses capacités à la fois à OpenSSL et NSS.

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


All Articles