公钥基础结构:GCrypt库是对OpenSSL的替代,具有对俄罗斯密码的支持

2018年下半年将至,基于俄罗斯密码学的PKI中“第2000年”将很快到来。 这是由于事实
不允许使用GOST R 34.10-2001签名方案在2018年12月31日之后生成签名!
今天,按照GOST R 34.10-2001的要求接收带有签名的证书已经没有意义。
同时,在OpenSSL的基础上开发了许多服务或应用程序,这些服务或应用程序支持GOST R 34.10-2001的工作。

但是今天,在opensl的​​标准版本中,既不支持GOST R 34.11-2012和GOST R 34.10-2012。 此外,在1.1版中,标准发行版中包含GOST加密支持(“ GOST引擎已过期,因此已被删除。”)。

所有这些使我们寻求使用证书,电子签名(“ CMS格式消息”)和基于新的俄罗斯加密技术的其他PKI对象的替代方法。

一种可能的方法是使用GCrypt库。 该库支持新算法GOST R 34.11-2012(哈希算法)和GOST R 34.10-2012(签名算法)。

密钥对生成


因此,我们首先生成包含私钥和公钥的密钥对。 当前,在俄罗斯密码学中,存在三种类型的签名密钥,它们具有对应的oid-s。
-GOST R 34.10-2001,密钥长度为256位,oid为1.2.643.2.2.19(0x2a,0x85、0x03、0x02、0x02、0x13);
-GOST R 34.10-2012,密钥长度为256位(以下简称GOST R 34.10-12-256),oid 1.2.643.7.1.1.1.1(0x2a,0x85、0x03、0x07、0x01、0x01、0x01、0x01);
-GOST R 34.10-2012,密钥长度为512位(以下称为GOST R 34.10-12-512),oid 1.2.643.7.1.1.1.2(0x2a,0x85、0x03、0x07、0x01、0x01、0x01、0x02)。
并立即注意,就数学,生成算法及其实现而言,GOST R 34.10-2001和GOST R 34.10-12-256的密钥绝对相同! 以及用于基于电子签名形成电子签名的相同算法。 只能通过有关证书中包含的密钥的信息来判断所讨论的密钥中的哪一个。 那么为什么要采用两个不同的oid? 仅强调一个事实,即在使用GOST R 34.10-2001密钥生成电子签名时,应使用根据GOST R 34.10-94获得的哈希,而在使用GOST R 34.10-12-256密钥时,则应遵循GOST R 34.10-获得的哈希。长度为256位的212。 虽然为了强调这一点,但有相应的oid -s:
-1.2.643.2.2.3(0x2a,0x85、0x03、0x02、0x02、0x03)-签名算法GOST R 34.10-2001,密钥为256,哈希为GOST R 34.11-94;
-1.2.643.7.1.1.3.2(0x2a,0x85、0x03、0x07、0x01、0x01、0x03、0x02)-签名算法GOST R 34.10-2012,密钥为256,哈希为GOST R 34.11-2012;
-1.2.643.7.1.1.3.3(0x2a,0x85、0x03、0x07、0x01、0x01、0x03、0x03)-签名算法GOST R 34.10-2012,密钥512,带有哈希值GOST R 34.11-2012。
因此,存在一些用oid-s进行的排序,也就是说。

GOST系列的键属于椭圆曲线上的键系列。 要生成密钥对,您需要在椭圆曲线上指定一个基点。

标准化“加密信息安全”技术委员会( TC 26 )建议对GOST R 34.10-2012-512密钥使用两个基点:
-GOST2012-tc26-A(libgcrypt术语中的昵称),oid为1.2.643.7.1.2.1.2.1(0x2a,0x85、0x03、0x07、0x01、0x02、0x01、0x02、0x01);
-GOST2012-tc26-B,oid为1.2.643.7.1.2.1.2.2(0x2a,0x85、0x03、0x07、0x01、0x02、0x01、0x02、0x02);
对于长度为256位的GOST R 34.10密钥,建议三个基点:
-oid为1.2.643.2.2.35.1的GOST2001-CryptoPro-A(0x2a,0x85、0x03、0x02、0x02、0x23、0x01);
-oid为1.2.643.2.2.35.2的GOST2001-CryptoPro-B(0x2a,0x85、0x03、0x02、0x02、0x23、0x02);
-oid为1.2.643.2.2.35.3的GOST2001-CryptoPro-C(0x2a,0x85、0x03、0x02、0x02、0x23、0x03)。
对于长度为256位的GOST R 34.10密钥,为基点定义了另外两个oid:
-oid为1.2.643.2.2.36.0的GOST2001-CryptoPro-XchA(0x2a,0x85、0x03、0x02、0x02、0x24、0x00);
-oid为1.2.643.2.2.36.1的GOST2001-CryptoPro-XchB(0x2a,0x85、0x03、0x02、0x02、0x24、0x01)。
但是,实际上,这些oid分别指代oid为1.2.643.2.2.35.1的GOST2001-CryptoPro-A的基点和oid为1.2.643.2.2.35.3的GOST2001-CryptoPro-C的基点。
并且在使用这些oid处理基点时应考虑到这一点。

要生成密钥对,使用以下形式的gcry_pk_genkey函数:

gcry_error_t gcry_pk_genkey (gcry sexp t *key_pair, gcry sexp t key_spec ). 

必须在parms变量中设置参数,以内部S表达式 (sexp)的格式生成密钥对。 为了根据GOST生成密钥对,以以下S表达式的形式设置参数:

 (genkey ( (curve _))),  

ecc确定椭圆曲线上密钥对的生成,并且基点应指示TK-26建议的特定点。 指定的基点是确定将生成哪个密钥对的基点。 例如,如果您指定GOST2012-tc26-A或GOST2012-tc26-B,则将根据GOST R 34.10-2012生成密钥对,密钥长度为512位。 您可以直接指定oid来代替基点的昵称:

 (genkey ( (curve «1.2.643.2.2.35.3»))) 

在后一种情况下,假定将根据GOST R 34.10生成密钥对,密钥长度为256位,基点为GOST2001-CryptoPro-C。

下面是一个示例C程序,演示了密钥生成

GenKey.c
 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> /*  S-*/ static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } int main(int argc, char* argv[]) { gpg_error_t err; gcry_sexp_t key_spec, key_pair, pub_key, sec_key; /* */ char *curve_gost[] = {"GOST2001-CryptoPro-A", "GOST2001-CryptoPro-B", "GOST2001-CryptoPro-C", "GOST2012-tc26-A", "GOST2012-tc26-B", NULL}; /*     */ err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecc (curve %s)))", curve_gost[1]); if (err) { fprintf(stderr, "creating S-expression failed: %s\n", gcry_strerror (err)); exit (1); } err = gcry_pk_genkey (&key_pair, key_spec); if (err){ fprintf(stderr, "creating %s key failed: %s\n", argv[1], gcry_strerror (err)); exit(1); } /* S-  */ show_sexp ("ECC GOST key pair:\n", key_pair); /*  */ pub_key = gcry_sexp_find_token (key_pair, "public-key", 0); if (! pub_key) { fprintf(stderr, "public part missing in key\n"); exit(1); } /* S-  */ show_sexp ("ECC GOST public key:\n", pub_key); /*  */ sec_key = gcry_sexp_find_token (key_pair, "private-key", 0); if (! sec_key){ fprintf(stderr, "private part missing in key\n"); exit(1); } /* S-  */ show_sexp ("ECC GOST private key:\n", sec_key); /* ,   */ gcry_sexp_release (key_pair); /* ,    */ gcry_sexp_release (key_spec); } 


要广播该示例,您需要运行以下命令:

 $cc –o GenKey GenKey.c –lgcrypt $ 

启动GenKey模块后,我们得到

密钥对
 ECC GOST key pair: (key-data (public-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) ) ) (private-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) (d #1ABB5A62BFF88C97567B467C6F4017242FE344B4F4BC8906CE40A0F9D51CBE48#) ) ) ) ECC GOST public key: (public-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) ) ) ECC GOST private key: (private-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) (d #1ABB5A62BFF88C97567B467C6F4017242FE344B4F4BC8906CE40A0F9D51CBE48#) ) ) 

现在,有了私钥,您可以创建电子签名。

文件杂凑


创建文档的电子签名(ES)首先从要签名的文档获得哈希值。 要签署文档,可以选择以下算法之一:
-1.2.643.2.2.3(0x2a,0x85、0x03、0x02、0x02、0x03)-签名算法GOST R 34.10-2001,密钥为256,密钥为GOST R 34.11-94,哈希长度为256位;
-1.2.643.7.1.1.3.2(0x2a,0x85、0x03、0x07、0x01、0x01、0x03、0x02)-签名算法GOST R 34.10-2012,密钥为256,根据GOST R 34.11-2012进行哈希处理,哈希长度为256位;
-1.2.643.7.1.1.3.3(0x2a,0x85、0x03、0x07、0x01、0x01、0x03、0x03)-签名算法GOST R 34.10-2012,密钥为512,根据GOST R 34.11-2012具有哈希值,哈希长度为512位。
这些算法不仅确定将用于获得电子签名的私钥的类型,而且确定哈希函数算法。 GCrypt库实现了所有三种类型的功能。 哈希算法GOST R 34.11-94(参数参数为1.2.643.2.2.30.1-0x2a,0x85、0x03、0x02、0x02、0x1e,0x01)以昵称GOSTR3411_CP实现,GOST R 34.11-2012算法的长度为以昵称STRIBOG256和GOST R 34.11-2012算法实现了256位(oid 1.2.43.7.1.1.2.2-0x2a,0x85、0x03、0x07、0x01、0x01、0x02、0x02),长度为512位(oid 1.2.43.7 .1.1.2.3-以昵称STRIBOG512实现了0x2a,0x85、0x03、0x07、0x01、0x01、0x02、0x03)。

以下是C语言中用于从文件中存储的文档计算哈希值的模块代码

摘要_gcrypt.c:
 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> int main(int argc, char* argv[]) { gpg_error_t err; int algo = GCRY_MD_NONE; int i; unsigned char *h; size_t size; gcry_md_hd_t hd; FILE *fp; unsigned char buf[1024]; char *dgst_gost[] = {"GOSTR3411_CP", "STRIBOG256", "STRIBOG512", NULL}; i = 0; /*  -*/ if (argc == 3) algo = gcry_md_map_name (argv[1]); if (algo == GCRY_MD_NONE) { fprintf(stderr, "Usage: digest_gcrypt <nick_name_digest> <file_for_digest>\n"); fprintf(stderr, "<nick_name_digest>="); while (dgst_gost[i] != NULL){ if (i > 0 ) fprintf(stderr, " | ", dgst_gost[i]); fprintf(stderr, "%s", dgst_gost[i]); i++; } fprintf(stderr, "\n"); exit (1); } /*   */ err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s\n", gcry_strerror (err)); exit (1); } /*  */ if (!strcmp (argv[2], "-")) fp = stdin; else fp = fopen (argv[2], "r"); if (fp == NULL) { fprintf(stderr, "Cannot fopen file=%s\n", argv[2]); exit(1); } /*   */ while (!feof (fp)) { size = fread (buf, 1, sizeof(buf), fp); gcry_md_write (hd, buf, size); } /*  */ h = gcry_md_read(hd, 0); /*  */ printf("  %s = %d ( )\n", argv[1], gcry_md_get_algo_dlen (algo)); printf("   %s:\n", argv[2]); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02x", h[i]); printf("\n"); fflush(stdout); /* */ gcry_md_reset(hd); gcry_md_close(hd); } 

我们翻译此模块并获取哈希计算实用程序:

 $cc -o digest_file digest_file.c -lgcrypt $./digest_file Usage: digest_gcrypt <nick_name_digest> <file_for_digest> <nick_name_digest>=GOSTR3411_CP | STRIBOG256 | STRIBOG512 $./digest_file STRIBOG256 digest_file.c   STRIBOG256 = 32 ( )    digest_file.c: f6818dfb26073747266dc721c332d703eb21f2b17e3433c809e0e23b68443d4a $ 

电子签名的形成及其验证


现在我们有了文档的私钥和哈希,我们还可以生成文档的电子签名:

 gcry_error_t gcry_pk_sign (gcry sexp t *r_sig, gcry sexp t data, gcry sexp t skey ),  

r_sig -sexp-variable用于保存电子签名的位置,
skey-具有私钥(请参见上文)的sexp变量,用于生成签名,
data -sexp-variable,表示签名的类型(在我们的示例中为gost)和签名文档的哈希值。
应当记住,提供给gcry_pk_sign输入以生成GOST R 34.10签名的哈希值应采用大端顺序格式,即 实际上倒过来了(正如一个朋友说的:“俄罗斯以小端顺序处理摘要字节的传统”)。 考虑到这一点,datap sex变量的准备如下:

 ... gcry_sexp_t data; unsigned char c; int len_xy; gcry_mpi_t x; … /*    */ printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); fflush(stdout); /*   mpi-*/ x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); /* sexp- data   –   */ err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); /*    data */ show_sexp ("data :\n", data); 
一切准备就绪,可以接收签名并对其进行查看<source:lang =“ cpp”> ...
gcry_sexp_t sig_r,sig_s;
...
/ *在哈希上签名* /
err = gcry_pk_sign(&sig,data,sec_key);
如果(错误){
fprintf(stderr,“签名失败:%s \ n”,gcry_strerror(err));
出口(1);
}
/ *我们打印签名* /
show_sexp(“ ECC GOST SIG:\ n”,sig);
/ *选择并打印签名r和s的组件* /
sig_r = gcry_sexp_find_token(sig,“ r”,0);
如果(!sig_r){
fprintf(stderr,“ sig \ n中缺少r部分”);
出口(1);
}
show_sexp(“ ECC GOST Sig R-part:\ n”,sig_r);
sig_s = gcry_sexp_find_token(sig,“ s”,0);
如果(!sig_s){
fprintf(stderr,“ sig \ n中缺少的部分”);
出口(1);
}
show_sexp(“ ECC GOST Sig S-part:\ n”,sig_s);
...您可以如下验证签名:
 … err = gcry_pk_verify (sig, data, pub_key); if (err) { putchar ('\n'); show_sexp ("seckey:\n", sec_key); show_sexp ("data:\n", data); show_sexp ("sig:\n", sig); fprintf(stderr, "verify failed: %s\n", gcry_strerror (err)); exit(1); } … 

证书中GOST R 34.10电子签名的验证


X509证书是公钥基础结构(PKI)的主要对象之一。 TC-26关于证书的组成和结构的建议在文件X的X.委员会X密钥9的开放基础结构中使用GOST R 34.10,GOST R 34.11算法的技术规范和证书审查CRL(CRL)中提出。信息保护”(2014年4月24日第13分钟)。根据这些建议,俄罗斯交通部认可的所有CA都会颁发证书。

要验证证书中的签名,有必要(参见上文)获取已验证证书的哈希,其签名和根证书的公钥。 请注意,对于自签名证书,所有这些数据都存储在一个证书中。
与PKI / PKI对象(证书,CMS,请求)一起使用
等),通常使用KSBA库,尽管有这样的支持经验 ,但该库目前不支持TK-26的建议。 基本上,没有什么可以阻止对ksba项目增加对TK-26建议的支持。
在此阶段,即GC​​rypt测试阶段,可以方便地使用脚本语言(如Python ,Tcl等)与带有俄罗斯密码的PKI / PKI对象(证书等)一起使用。 选择了脚本语言Tcl 。 在其上编写原型程序很容易,然后可以将其转换为C语言Tcl包含一个PKI包,其中包含用于解析PKI对象的过程,尤其是用于解析证书的过程::: pki :: x509 :: parse_cert。 基于parse_cert过程,开发了parse_gost_cert过程,该过程位于文件中

parse_cert_gost_oid.tcl
 proc parse_cert_gost {cert} { # parray ::pki::oids #puts "parse_cert_gost=$cert" set cert_seq "" if { [string range $cert 0 9 ] == "-----BEGIN" } { array set parsed_cert [::pki::_parse_pem $cert "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"] set cert_seq $parsed_cert(data) } else { #FORMAT DER set cert_seq $cert } set finger [::sha1::sha1 $cert_seq] set ret(fingerprint) $finger binary scan $cert_seq H* certdb set ret(certdb) $certdb #puts "CERTDB=$certdb" array set ret [list] # Decode X.509 certificate, which is an ASN.1 sequence ::asn::asnGetSequence cert_seq wholething ::asn::asnGetSequence wholething cert set ret(cert) $cert set ret(cert) [::asn::asnSequence $ret(cert)] if {0} { set ff [open "/tmp/tbs.der" w] fconfigure $ff -translation binary puts -nonewline $ff $ret(cert) close $ff } binary scan $ret(cert) H* ret(cert) ::asn::asnPeekByte cert peek_tag if {$peek_tag != 0x02} { # Version number is optional, if missing assumed to be value of 0 ::asn::asnGetContext cert - asn_version ::asn::asnGetInteger asn_version ret(version) incr ret(version) } else { set ret(version) 1 } ::asn::asnGetBigInteger cert ret(serial_number) ::asn::asnGetSequence cert data_signature_algo_seq ::asn::asnGetObjectIdentifier data_signature_algo_seq ret(data_signature_algo) ::asn::asnGetSequence cert issuer ::asn::asnGetSequence cert validity ::asn::asnGetUTCTime validity ret(notBefore) ::asn::asnGetUTCTime validity ret(notAfter) ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo binary scan $pubkeyinfo H* pubkeyinfoG set ret(pubkeyinfo) $pubkeyinfoG ::asn::asnGetSequence pubkeyinfo pubkey_algoid binary scan $pubkey_algoid H* pubkey_algoidG set ret(pubkey_algoid) $pubkey_algoidG ::asn::asnGetObjectIdentifier pubkey_algoid ret(pubkey_algo) ::asn::asnGetBitString pubkeyinfo pubkey set extensions_list [list] while {$cert != ""} { ::asn::asnPeekByte cert peek_tag switch -- [format {0x%02x} $peek_tag] { "0xa1" { ::asn::asnGetContext cert - issuerUniqID } "0xa2" { ::asn::asnGetContext cert - subjectUniqID } "0xa3" { ::asn::asnGetContext cert - extensions_ctx ::asn::asnGetSequence extensions_ctx extensions while {$extensions != ""} { ::asn::asnGetSequence extensions extension ::asn::asnGetObjectIdentifier extension ext_oid ::asn::asnPeekByte extension peek_tag if {$peek_tag == 0x1} { ::asn::asnGetBoolean extension ext_critical } else { set ext_critical false } ::asn::asnGetOctetString extension ext_value_seq set ext_oid [::pki::_oid_number_to_name $ext_oid] set ext_value [list $ext_critical] switch -- $ext_oid { id-ce-basicConstraints { ::asn::asnGetSequence ext_value_seq ext_value_bin if {$ext_value_bin != ""} { ::asn::asnGetBoolean ext_value_bin allowCA } else { set allowCA "false" } if {$ext_value_bin != ""} { ::asn::asnGetInteger ext_value_bin caDepth } else { set caDepth -1 } lappend ext_value $allowCA $caDepth } default { binary scan $ext_value_seq H* ext_value_seq_hex lappend ext_value $ext_value_seq_hex } } lappend extensions_list $ext_oid $ext_value } } } } set ret(extensions) $extensions_list ::asn::asnGetSequence wholething signature_algo_seq ::asn::asnGetObjectIdentifier signature_algo_seq ret(signature_algo) ::asn::asnGetBitString wholething ret(signature) # Convert values from ASN.1 decoder to usable values if needed set ret(notBefore) [::pki::x509::_utctime_to_native $ret(notBefore)] set ret(notAfter) [::pki::x509::_utctime_to_native $ret(notAfter)] set ret(serial_number) [::math::bignum::tostr $ret(serial_number)] set ret(data_signature_algo) [::pki::_oid_number_to_name $ret(data_signature_algo)] set ret(signature_algo) [::pki::_oid_number_to_name $ret(signature_algo)] set ret(pubkey_algo) [::pki::_oid_number_to_name $ret(pubkey_algo)] set ret(issuer) [::pki::x509::_dn_to_string $issuer] set ret(subject) [::pki::x509::_dn_to_string $subject] set ret(signature) [binary format B* $ret(signature)] binary scan $ret(signature) H* ret(signature) # Handle RSA public keys by extracting N and E #puts "PUBKEY_ALGO=$ret(pubkey_algo)" switch -- $ret(pubkey_algo) { "rsaEncryption" { set pubkey [binary format B* $pubkey] binary scan $pubkey H* ret(pubkey) ::asn::asnGetSequence pubkey pubkey_parts ::asn::asnGetBigInteger pubkey_parts ret(n) ::asn::asnGetBigInteger pubkey_parts ret(e) set ret(n) [::math::bignum::tostr $ret(n)] set ret(e) [::math::bignum::tostr $ret(e)] set ret(l) [expr {int([::pki::_bits $ret(n)] / 8.0000 + 0.5) * 8}] set ret(type) rsa } "GostR2012_256" - "GostR2012_512" - "GostR2001" - "1.2.643.2.2.19" - "1.2.643.7.1.1.1.1" - "1.2.643.7.1.1.1.2" { # gost2001, gost2012-256,gost2012-512 set pubkey [binary format B* $pubkey] #puts "LL=[string length $pubkey]" if {[string length $pubkey] < 100} { set pubk [string range $pubkey 2 end] } else { set pubk [string range $pubkey 3 end] } set pubkey_revert [string reverse $pubk] binary scan $pubkey_revert H* ret(pubkey_rev) binary scan $pubkey H* ret(pubkey) set ret(type) gost ::asn::asnGetSequence pubkey_algoid pubalgost #OID -  ::asn::asnGetObjectIdentifier pubalgost ret(paramkey) set ret(paramkey) [::pki::_oid_number_to_name $ret(paramkey)] #OID -   ::asn::asnGetObjectIdentifier pubalgost ret(hashkey) set ret(hashkey) [::pki::_oid_number_to_name $ret(hashkey)] #puts "ret(paramkey)=$ret(paramkey)\n" #puts "ret(hashkey)=$ret(hashkey)\n" } } return [array get ret] } proc set_nick_for_oid {} { # set ::pki::oids(1.2.643.2.2.19) "gost2001pubKey" # set ::pki::oids(1.2.643.2.2.3) "gost2001withGOST3411_94" set ::pki::oids(1.2.643.100.1) "OGRN" set ::pki::oids(1.2.643.100.5) "OGRNIP" set ::pki::oids(1.2.643.3.131.1.1) "INN" set ::pki::oids(1.2.643.100.3) "SNILS" #  set ::pki::oids(1.2.643.2.2.3) "  34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) "  34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) "  34.10-2012-512" # set ::pki::oids(1.2.643.2.2.3) "gost" # set ::pki::oids(1.2.643.7.1.1.3.2) "gost" # set ::pki::oids(1.2.643.7.1.1.3.3) "gost" #  # set ::pki::oids(1.2.643.2.2.19) "  34.10-2001" # set ::pki::oids(1.2.643.7.1.1.1.1) "  34.10-2012 256 " # set ::pki::oids(1.2.643.7.1.1.1.2) "  34.10-2012 512 " set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid-     34.10-2001    34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" # { "GOST2001-CryptoPro-A", set ::pki::oids("GOST2001-CryptoPro-XchA" }, # { "GOST2001-CryptoPro-C", set ::pki::oids("GOST2001-CryptoPro-XchB" }, set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid-     34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick   set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" } 


parse_gost_cert过程旨在根据俄文密码学分析证书。
考虑到GCrypt项目,该文件还包含为俄罗斯密码的oid-s分配昵称的过程:
 proc set_nick_for_oid {} { set ::pki::oids(1.2.643.100.1) "OGRN" set ::pki::oids(1.2.643.100.5) "OGRNIP" set ::pki::oids(1.2.643.3.131.1.1) "INN" set ::pki::oids(1.2.643.100.3) "SNILS" #  set ::pki::oids(1.2.643.2.2.3) "  34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) "  34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) "  34.10-2012-512" #  set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid-     34.10-2001    34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid-     34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick   set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" } 

parse_gost_cert过程允许您获取TBS证书 ,证书签名,签名类型,公共密钥。 如果我们考虑使用自签名证书,则足以验证签名。 如果我们验证由另一证书签名(颁发)的证书的签名(证书的颁发者和主题不匹配),则获取信息以验证签名的过程如下:

-从经过验证的证书中提取其TBS证书,签名类型和签名本身;
-我们从根证书中提取公钥。

在准备用于验证证书签名的源数据时,最负责任的是严格遵守TK-26的建议。 对于公钥值,它们听起来像这样:
GostR3410-2012-256-PublicKey的公钥表示形式与GOST R 34.10-2001 [IETF RFC 4491]的公钥表示形式相同,并且必须包含64个八位字节,其中前32个八位字节在little-endian视图中包含x坐标,而后32个八位字节则包含该坐标。在小端顺序视图中。

GostR3410-2012-512-PublicKey公钥视图必须包含
128个八位位组,其中前64个八位位组在little-endian视图中包含x坐标,而后64个八位位组在little-endian视图中包含y坐标。
上载签名时,应遵循以下准则:
具有256位哈希码长度的GOST R 34.10-2012签名算法用于生成两个256位数字r和s形式的数字签名。 它以八位字节字符串(OCTET STRING)的形式表示与签名GOST R 34.10-2001 [IETF RFC 4491]的表示相同,并且由64个八位字节组成。 前32个八位位组在big-endian表示形式中包含数字s(最高的八位位组首先写入),而后32个八位位组在big-endian表示形式中包含数字r。

具有512哈希码长度的GOST R 34.10-2012签名算法用于生成两个512位数字形式的数字签名,根据r和s为公钥。 它以八位字节字符串(OCTET STRING)表示,由128个八位字节组成; 前64个八位位组在big-endian表示形式中包含数字s(最高的八位位组首先写入),而后64个八位位组在big-endian表示形式中包含数字r。
根据这些建议,Tcl模块parse_certs_for_verify_load.tcl准备用于证书签名验证的源数据。

看起来像这样:
 #!/usr/bin/tclsh #  PKI package require pki #     -  source parse_cert_gost_oid.tcl if {$argc != 2} { puts "Usage: parse_certs_for_verify_load.tcl < > < >" exit 1 } #  if {[file exists "[lindex $argv 0]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts "  [lindex $argv 0]" exit 1 } #  if {[file exists "[lindex $argv 1]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts "  [lindex $argv 1]" exit 1 } # nick-  - oid- set_nick_for_oid set file [lindex $argv 0] set f [open $file r] set cert [read $f] close $f #READ DER-format if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } array set cert_user [parse_cert_gost $cert] #  -26 set len_sign [expr [string length $cert_user(signature)] /2] set sign_r [string range $cert_user(signature) $len_sign end] set sign_s [string range $cert_user(signature) 0 [expr $len_sign - 1]] #puts " : $file" set file [lindex $argv 1] set f [open $file r] set cert [read $f] close $f #READ DER if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } #     array set cert_ca [parse_cert_gost $cert] #  -26 set len_key [expr [string length $cert_ca(pubkey_rev)]/2] set key_pub_left [string range $cert_ca(pubkey_rev) $len_key end] set key_pub_right [string range $cert_ca(pubkey_rev) 0 [expr $len_key - 1]] puts "/* C-:      */" #TBS-  puts "char tbc\[\] = \"[string toupper $cert_user(cert)]\";" # - puts "char hash_type\[\] = \"$cert_ca(hashkey)\";" #    puts "unsigned char pub_key_ca\[\] = \"(public-key \"" puts "\"(ecc \"" puts "\" (curve $cert_ca(paramkey))\"" puts "\" (q #04[string toupper $key_pub_left$key_pub_right]#)\"" puts "\")\"" puts "\")\";" #   puts "unsigned char sig_cert\[\] = \"(sig-val\"" puts "\"($cert_ca(type) \"" puts "\" (r #[string toupper $sign_r]#)\"" puts "\" (s #[string toupper $sign_s]#)\"" puts "\")\"" puts "\")\";" puts "/*    TEST_from_TCL.h*/" puts "/*  TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt    TEST_from_Tcl*/" 


为了进行测试,我们采用了两个真实的证书:

证书\“ UTs 1 IS GUTs.pem \”
-----BEGIN CERTIFICATE-----
MIIGrDCCBlugAwIBAgILAOvBBVQAAAAAAFkwCAYGKoUDAgIDMIIBSjEeMBwGCSqG
SIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwT
Nzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMT8wPQYD
VQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g0KLQstC10YDRgdC6
0LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB0LLRj9C30Ywg0KDQ
vtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDExGjAYBggqhQMDgQMB
ARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy0L3QvtC5INGD0LTQ
vtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgDAeFw0xNjAzMTYxMjAy
NTFaFw0yNzA3MTIxMjAyNTFaMIIBITEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEeMBwGCSqGSIb3DQEJARYPZGl0
QG1pbnN2eWF6LnJ1MTwwOgYDVQQJDDMxMjUzNzUg0LMuINCc0L7RgdC60LLQsCDR
g9C7LiDQotCy0LXRgNGB0LrQsNGPINC0LjcxLDAqBgNVBAoMI9Cc0LjQvdC60L7Q
vNGB0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
HDAaBgNVBAgMEzc3INCzLiDQnNC+0YHQutCy0LAxCzAJBgNVBAYTAlJVMRswGQYD
VQQDDBLQo9CmIDEg0JjQoSDQk9Cj0KYwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAQYH
KoUDAgIeAQNDAARAx70Y7WYQ4ODtdiSSx3MJnr1GQBEIExiPO/LWj1TRKES1OcDI
YgtdOBGVYSvbsStl10jkAOG0OpnGsd2by4m+LaOCA0MwggM/MA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFBGIaV7vyOlz23pXNbzSAfMF/qfRMAsGA1UdDwQEAwIB
hjCCAYsGA1UdIwSCAYIwggF+gBSLmDuJGFHo75wCeLjqyNQgslXJXaGCAVKkggFO
MIIBSjEeMBwGCSqGSIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJS
VTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB
0LrQstCwMT8wPQYDVQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g
0KLQstC10YDRgdC60LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB
0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDEx
GjAYBggqhQMDgQMBARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy
0L3QvtC5INGD0LTQvtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgIIQ
NGgeQMtB7zOpoLfIdpKaKTBZBgNVHR8EUjBQMCagJKAihiBodHRwOi8vcm9zdGVs
ZWNvbS5ydS9jZHAvZ3VjLmNybDAmoCSgIoYgaHR0cDovL3JlZXN0ci1wa2kucnUv
Y2RwL2d1Yy5jcmwwJgYFKoUDZG8EHQwb0JrRgNC40L/RgtC+LdCf0YDQviBDU1Ag
My42MCUGA1UdIAQeMBwwCAYGKoUDZHEBMAgGBiqFA2RxAjAGBgRVHSAAMIHGBgUq
hQNkcASBvDCBuQwj0J/QkNCa0JwgwqvQmtGA0LjQv9GC0L7Qn9GA0L4gSFNNwrsM
INCf0JDQmiDCq9CT0L7Qu9C+0LLQvdC+0Lkg0KPQpsK7DDbQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzMvMi8yLTk5OSDQvtGCIDA1LjA3LjIwMTIMONCX0LDQ
utC70Y7Rh9C10L3QuNC1IOKEliAxNDkvNy8xLzQvMi02MDMg0L7RgiAwNi4wNy4y
MDEyMAgGBiqFAwICAwNBAKVYokUvb7XAMPJF38ZPKO2BFBldmGEfqsfmsiO35Y52
kTkx512H3YLqWMrOLjIfVMJhc+DTCNeXWY6bhK4/DRU=
-----END CERTIFICATE-----

及其根证书“ SEC Minkomsvyaz.pem”:
-----BEGIN CERTIFICATE-----
MIIFGTCCBMigAwIBAgIQNGgeQMtB7zOpoLfIdpKaKTAIBgYqhQMCAgMwggFKMR4w
HAYJKoZIhvcNAQkBFg9kaXRAbWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYD
VQQIDBM3NyDQsy4g0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
PzA9BgNVBAkMNjEyNTM3NSDQsy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXR
gNGB0LrQsNGPLCDQtC4gNzEsMCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfR
jCDQoNC+0YHRgdC40LgxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqF
AwOBAwEBEgwwMDc3MTA0NzQzNzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg
0YPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMB4XDTEyMDcy
MDEyMzExNFoXDTI3MDcxNzEyMzExNFowggFKMR4wHAYJKoZIhvcNAQkBFg9kaXRA
bWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYDVQQIDBM3NyDQsy4g0JzQvtGB
0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAxPzA9BgNVBAkMNjEyNTM3NSDQ
sy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXRgNGB0LrQsNGPLCDQtC4gNzEs
MCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfRjCDQoNC+0YHRgdC40LgxGDAW
BgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg0YPQtNC+0YHRgtC+0LLQtdGA
0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqF
AwICHgEDQwAEQI+lv3kQI8jWka1kMVdbvpvFioP0Pyn3Knmp+2XD6KgPWnXEIlSR
X8g/IYracDr51YsNc2KE3C7mkH6hA3M3ofujggGCMIIBfjCBxgYFKoUDZHAEgbww
gbkMI9Cf0JDQmtCcIMKr0JrRgNC40L/RgtC+0J/RgNC+IEhTTcK7DCDQn9CQ0Jog
wqvQk9C+0LvQvtCy0L3QvtC5INCj0KbCuww20JfQsNC60LvRjtGH0LXQvdC40LUg
4oSWIDE0OS8zLzIvMi05OTkg0L7RgiAwNS4wNy4yMDEyDDjQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzcvMS80LzItNjAzINC+0YIgMDYuMDcuMjAxMjAuBgUq
hQNkbwQlDCPQn9CQ0JrQnCDCq9Ca0YDQuNC/0YLQvtCf0YDQviBIU03CuzBDBgNV
HSAEPDA6MAgGBiqFA2RxATAIBgYqhQNkcQIwCAYGKoUDZHEDMAgGBiqFA2RxBDAI
BgYqhQNkcQUwBgYEVR0gADAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUi5g7iRhR6O+cAni46sjUILJVyV0wCAYGKoUDAgIDA0EA23Re
ec/Y27rpMi+iFbgWCazGY3skBTq5ZGsQKOUxCe4mO7UBDACiWqdA0nvqiQMXeHgq
o//fO9pxuIHtymwyMg==
-----END CERTIFICATE-----

我们将准备初始数据以检查证书“ UTs 1 IS GUTs.pem”:

 $ ./parse_certs_for_verify_load.tcl " 1  .pem" " .pem" > TEST_from_TCL.h $echo "  TEST_from_TCL.h" $cat TEST_from_TCL.h /* C-:      */ char tbc[] = "3082065B . . . "; char hash_type[] = "GOSTR3411_CP"; unsigned char pub_key_ca[] = "(public-key " "(ecc " " (curve GOST2001-CryptoPro-A)" " (q #040FA8E8C365FBA9792AF7293FF4838AC59BBE5B573164AD91D6C8231079BFA58FFBA1377303A17E90E62EDC8462730D8BD5F93A70DA8A213FC85F915422C4755A#)" ")" ")"; unsigned char sig_cert[] = "(sig-val" "(gost " " (r #913931E75D87DD82EA58CACE2E321F54C26173E0D308D797598E9B84AE3F0D15#)" " (s #A558A2452F6FB5C030F245DFC64F28ED8114195D98611FAAC7E6B223B7E58E76#)" ")" ")"; /*    TEST_from_TCL.h*/ /*  TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt    TEST_from_Tcl*/ $ 

证书签名的验证由模块执行:

TEST_from_TCL.c
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <gcrypt.h> #include "TEST_from_TCL.h" #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define xmalloc(a) gcry_xmalloc ((a)) static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * hex2buffer (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) return NULL; /* Invalid hex digits. */ ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } int main(int argc, char* argv[]) { gpg_error_t err; int algo; gcry_md_hd_t hd; unsigned char *tbs_ptr; size_t len_tbs; int i; unsigned char *h; gcry_sexp_t pub_key; gcry_sexp_t data; gcry_sexp_t sig; gcry_mpi_t x; int len_xy; unsigned char c; /*   little-endian  big-endian*/ unsigned short arch = 1; /* 0x0001 */ tbs_ptr = hex2buffer(tbc, &len_tbs); if (tbs_ptr == NULL) { fprintf (stderr, "Bad tbs\n"); exit(1); } algo = gcry_md_map_name (hash_type); if (algo == GCRY_MD_NONE) { fprintf (stderr, "Unknown algorithm '%s'\n", hash_type); exit (1); } err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s/%s\n", gcry_strsource (err), gcry_strerror (err)); exit (1); } gcry_md_write (hd, tbs_ptr, len_tbs); h = gcry_md_read(hd, 0); // len_xy = gcry_md_get_algo_dlen (algo); /*    */ printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); // printf("\n %s\n", tbc); fflush(stdout); /*  */ x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); /*  */ gcry_md_reset(hd); gcry_md_close(hd); /* */ err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); show_sexp ("ECC GOST data cert:\n", data); fprintf (stderr, "\nStep 1\n"); /*    */ err = gcry_sexp_sscan (&pub_key, NULL, pub_key_ca, strlen (pub_key_ca)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for pub_key_ca\n"); exit(1); } show_sexp ("ECC GOST public key:\n", pub_key); fprintf (stderr, "Step 2\n"); /*   */ err = gcry_sexp_sscan (&sig, NULL, sig_cert, strlen (sig_cert)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for sig_cert\n"); exit(1); } show_sexp ("ECC GOST sig cert:\n", sig); fprintf (stderr, "Step 3\n"); /*  */ err = gcry_pk_verify (sig, data, pub_key); if (err) { fprintf (stderr, "TEST_SEXP: verify cert failed\n"); exit (1); } fprintf (stderr, "TEST_SEXP: verify cert OK!!\n"); } 

我们翻译并执行TEST_from_TCL实用程序:

 $cc –o TEST_from_TCL TEST_from_TCL.c –lgcrypt $./TEST_from_TCL  little-endian  =32 D485903E7E8D60820118329060C558B9C733D53CA608C0C79363ECE7B4C1F799ECC GOST data cert: (data (flags gost) (value #D485903E7E8D60820118329060C558B9C733D53CA608C0C79363ECE7B4C1F799#) ) Step 1 ECC GOST public key: (public-key (ecc (curve GOST2001-CryptoPro-A) (q #040FA8E8C365FBA9792AF7293FF4838AC59BBE5B573164AD91D6C8231079BFA58FFBA1377303A17E90E 62EDC8462730D8BD5F93A70DA8A213FC85F915422C4755A#) ) ) Step 2 ECC GOST sig cert: (sig-val (gost (r #913931E75D87DD82EA58CACE2E321F54C26173E0D308D797598E9B84AE3F0D15#) (s #A558A2452F6FB5C030F245DFC64F28ED8114195D98611FAAC7E6B223B7E58E76#) ) ) Step 3 TEST_SEXP: verify cert OK!! $ 

如您所见,证书“ UTs 1 IS GUTs.pem”签名的验证成功。仍然需要验证根证书本身“ GUT Minkomsvyaz.pem”。很简单,只需运行以下命令:

 $ parse_certs_for_verify_load.tcl " .pem" " .pem" > TEST_from_TCL.h $  .. 

如果有人想用其他GOST密钥(GOST R 34.10-2012-256或GOST R 34.10-2012-512)检查证书,那么他可以使用CAFL63 CA并准备任何证书:

图片

因此,完成的研究表明,GCrypt库可能会过去曾与俄罗斯密码学合作。在确定KSBA库并扩展对Tcl脚本语言(或可能是Python)的pki包并支持俄罗斯密码学方面可以看到直接的前景。

那些想使用GCrypt库进行加密的人,建议在这里查看

Source: https://habr.com/ru/post/zh-CN414249/


All Articles