The “H” hour is inexorably approaching: “the use of the signature scheme GOST R 34.10-2001 for the formation of a signature after December 31, 2018 is not allowed!”. And finally, on July 16, 2018, a notice appeared on the website of the Federal Situational Center for e-government on issuing key certificates for verifying electronic signatures of subordinate certifying centers at the parent certification center in accordance with GOST R 34.10-2012. True, it is still not clear when the issue of old certificates will cease. But the "process has begun" and it pleases.

And ultimately, it will be possible to use the domestic electronic signature in the KMail mail client (by the way, in many other mail clients), and in the Kleopatra utility both for checking the electronic signature and its generation for various files:
Now about the main thing. In the future we will proceed from the fact that users store their personal certificates (private key and electronic signature verification key certificate) on PKCS # 11 tokens / smartcards with implementation of at least electronic signature generation functions (CKM_GOSTR3410 mechanisms for generating electronic signature according to GOST R 34.10-2001 / 2012 with a key length of 256 bits and / or CKM_GOSTR3410_512 for the formation of electronic signature according to GOST R 34.10-2012 with a key length of 512 bits). The best option is when the functionality of the token / smarcard supports the PKCS # 11 v.2.40 standard./* 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; } #if 0 … #endif 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: export LIBS=" -lksba" #./configure --without-gnutls ./configure --without-openssl make 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, ")"); 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); 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. */ … scdaemon-program /usr/local/bin64/gnupg-pkcs11-scd pinentry-program /usr/bin/pinentry-qt … # # /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 … 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$ 





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



Source: https://habr.com/ru/post/417735/
All Articles