Инфраструктура открытых ключей: GnuPG/SMIME и токены PKCS#11 с поддержкой российской криптографии

werxobmhyrih1p207etb8pudwuw.png
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 )
+               (s )
+             )
+             (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
                  
                  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, ")");


© Habrahabr.ru