Infraestrutura de chave pública: tokens GnuPG / SMIME e PKCS # 11 com suporte para criptografia russa

A hora "H" está inexoravelmente se aproximando: "o uso do esquema de assinatura GOST R 34.10-2001 para gerar uma assinatura após 31 de dezembro de 2018 não é permitido!" E, finalmente, em 16 de julho de 2018, um aviso apareceu no site do Centro Federal de Situação do Governo Eletrônico no início da emissão de certificados de chaves para verificação de assinaturas eletrônicas de autoridades de certificação subordinadas no centro de certificação principal, de acordo com GOST R 34.10-2012. É verdade que ainda não está claro quando a liberação de certificados antigos será interrompida. Mas o "processo começou" e agrada.

A introdução de uma nova assinatura eletrônica implica a disponibilidade de fundos não apenas para a emissão de certificados de acordo com o GOST R 34.10-2012, mas também a disponibilidade de meios para gerar e verificar essa assinatura. Você já pode falar sobre uma dessas ferramentas nas páginas habr.



A assinatura eletrônica é usada ativamente não apenas no gerenciamento de documentos eletrônicos (EDI), mas também na correspondência eletrônica (email):



Se falarmos sobre projetos OpenSource no campo da PKI com base em certificados X509, juntamente com o Network Security Services (NSS), o OpenSSL, o projeto GnuPG / SMIME é muito popular. O núcleo criptográfico deste projeto é a biblioteca LibGCrypt . É significativo que esta biblioteca suporte os algoritmos criptográficos GOST R 34.10-2012 e GOST R 34.11-2012 (STRIBOG256 e STRIBOG512) e não exija nenhum aprimoramento, pelo menos para as funções de geração de assinatura eletrônica e verificação. O GnuPG usa a biblioteca LibKSBA para analisar e manipular objetos PKI (certificados, solicitações de certificado, assinaturas eletrônicas, etc.). Diferentemente do LibGCrypt, a biblioteca libksba não implementa as recomendações do TK-26 para mensagens criptográficas no formato CMS. O artigo mostra a modernização da biblioteca libksba relacionada à análise de certificados X509 e mensagens CMS (PKCS7), que possibilitou verificar a assinatura eletrônica dos certificados e a assinatura eletrônica dos documentos PKCS # 7. Hoje iremos além e adicionaremos funcionalidade à biblioteca para a formação do formato CMS PKCS # 7. Isso fornecerá suporte para assinatura eletrônica de acordo com o GOST R 34.10-2001.2012 (após uma certa modernização do próprio projeto GnuPG) e no módulo GnuPG / SM.

E, no final, será possível usar uma assinatura eletrônica doméstica no cliente de email do KMail (a propósito, e em muitos outros clientes de email) e no utilitário Kleopatra para verificar a assinatura eletrônica e sua formação para vários arquivos:



imagem Agora sobre a principal coisa. No futuro, assumiremos que os usuários armazenam seus certificados pessoais (chave privada e certificado de chave de verificação de assinatura eletrônica) em tokens / smartcards PKCS # 11 com pelo menos as funções de geração de assinatura eletrônica implementadas neles (mecanismos CKM_GOSTR3410 para gerar assinaturas eletrônicas de acordo com GOST R 10/34/2001/2012 com um comprimento de chave de 256 bits e / ou CKM_GOSTR3410_512 para formar um ES de acordo com GOST R 34.10-2012 com um comprimento de chave de 512 bits). A melhor opção é quando a funcionalidade de token / cartão inteligente suporta o padrão PKCS # 11 v.2.40.

O GnuPG usa o utilitário gnupg_pkcs11_scd para acessar os tokens do PKCS # 11. Nossos exemplos usam a versão 0.9.1 do utilitário gnupg_pkcs11_csd. A principal tarefa desse utilitário (além de organizar a execução das funções criptográficas do PKCS # 11, por exemplo, para assinar um hash) é analisar os certificados armazenados no token, obter informações sobre a chave aberta na forma de uma expressão S e transferi-lo para a cadeia. Esta operação é executada pela função keyutil_get_cert_sexp, localizada no arquivo keyutil.c. Infelizmente, este utilitário é apenas para trabalhar com certificados RSA. Porém, como temos a biblioteca libksba à nossa disposição e até a aprimoramos para trabalhar com certificados GOST, foi surpreendentemente simples reescrever a função keyutil_get_cert_sexp para processar quaisquer certificados suportados pela biblioteca 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; } 

O código original é colocado em um bloco:

 #if 0 … #endif 

O patch completo para o utilitário gnupg_pkcs11_scd está aqui
 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: 


Dado esse patch, o script a seguir é usado para criar o utilitário gnupg_pkcs11_scd:

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

Esse patch eventualmente permitirá o uso de tokens GOST (incluindo certificados pelo FSB da Rússia), pelo menos para a formação de uma assinatura eletrônica.

Não vamos nos aprofundar nas melhorias da biblioteca libksba, mas apenas dar
patch completo para 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, ")"); 


Os comentários existentes tornam possível entender a lógica das alterações introduzidas, que são determinadas principalmente pelas recomendações do TC-26 .

Resta fazer alterações nos módulos gnupg-agent (diretório do agente) e no módulo gpgsm (diretório sm).

O patch para o módulo gnupg-agent está aqui
 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); 

O patch para o módulo gpgsm pode ser visto aqui
 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. */ 


Patches para os módulos gnupg-agent e gpgsm foram feitos para o gnupg-2.1.21 . gnupg-2.2.9 .

libksba, gnupg, gnupg_pkcs11_scd , PKCS#11 gpg-agent.conf :

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

gnu-pkcs11-scd.conf PKCS#11 , :

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

. , gpg-agent :

 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:



«» , .

kleopatra PIN- :



, , , , .

, « → Manage Smartcards». , :



, , LoadCertificates ( ):



(not certified), ( → ):



, , :



( , , ), , .

, KMail ( → KMail → → < > → → → SMIME):



« »:



« » , :



, → :



( ).

, GnuPG OpenSSL, NSS.

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


All Articles