跨平台的英语实用程序,用于查看俄罗斯合格证书x509

图片 今天,使用数字证书X509 v.3已变得司空见惯。 越来越多的人使用它们来访问国家服务局,联邦税务局,电子招标等网站。 越来越多的人想知道这个“胸”称为证书的含义。 如果证书是护照的类似物,那么如何读取/查看它。 是的,在操作系统中有多种实用程序可供查看。 但是他们对普通公民几乎没有任何帮助。 以gcr-viewer实用程序为例,它实际上是在Linux系统上(因此在家用OS中)进行查看的标准工具:



标准观众


该实用程序制作精良,方便。 通常,它旨在用作查看包含各种密码格式(证书,请求,电子签名/ PKCS#7,受保护的容器PKCS#12等)的数据的文件的通用实用程序。 但是,不幸的是,它是为西方密码学设计的,并未考虑您所在国家/地区输入的oid。 并且,如果您查看屏幕截图,那么当显示有关证书持有者的信息时,将出现难以理解的字符。 oid本身在左侧,而第16种形式的右侧是其值的asn1-结构。 在这种情况下,它们是OGRN(1.2.643.100.1),SNILS(1.2.643.100.3)和TIN(1.2.643.3.131.1.1)。 这就是普通公民应确保这是他的数据的方式。 不要以为这仅在Linux上,它是任何证书查看器的共同功能。 如果您进一步看,那么一切都会变得令人费解:



出现一些扩展名,标识符和值。 在这种情况下,oid om 1.2.643.100.111隐藏了CIPF的名称,该名称由用户用来生成密钥对,用于签名证书请求的私钥以及位于证书中的公钥:



在这里,证书持有者了解得很少。 他甚至不了解使用哪种算法来生成密钥(GOST R 34.10-2001或GOST R 34.10-2012)以及密钥长度。

您可以继续举例。 例如,如果证书的有效性是明确的,那么密钥在哪里?

证书持有者还想回答两个问题:在哪里可以获得一连串的根证书(或者甚至可以得到一个),以及在已撤销证书列表中的类似问题。

最后,我想拥有一个通用的实用程序,该实用程序考虑了俄罗斯PKI / PKI的功能,该功能确实是跨平台的,并且可以在家用和非家用OS上运行。 要发展什么? 当然,如果只是因为它们的跨平台性质,就使用脚本语言。

然后我想起了漂亮的脚本语言Tcl(工具命令语言)最近庆祝了它的30周年 。 很高兴对此进行编程。 它具有大量扩展(程序包),几乎可以执行所有操作。 因此,要使用ASN结构,有一个asn包。 此外,对于使用证书(在这种情况下我们有兴趣解析它们),有一个pki软件包。 为了开发图形界面,有一个Tk软件包。

对于带有Tkinter的Pyton,Perl和红宝石,可以说都是一样的。 每个人都可以根据自己的口味选择。 我们在Tcl / Tk处停下来。

我们将从gcr-viewer实用程序借用该实用程序的图形设计。 还有一个要求。

由于Habr具有英语版本 ,因此我希望该实用程序具有不同的界面(俄语/英语)。 但这不是主要原因。 更重要的是,越来越多的西方世界公民成为俄罗斯联邦的公民,例如,世界著名的演员德帕迪约。 他们可能会反对:他是法国人。 但是我还是一名法语的军事翻译:



因此,添加法语界面非常容易。 但是我认为Depardieu的英语没有问题。 另一方面,我们的国家是跨国公司,如果家用软件和家用操作系统至少具有几个国家接口,那将是很好的选择。
领先一点,这就是结果:



我们邀请翻译


因此,让我们从“翻译器”开始。 在屏幕截图中,他躲在国旗下。 译者的主要要求是翻译的同步,即 随时可以切换到另一种语言的能力。 Tcl / Tk中的翻译器功能由msgcat软件包执行:

package require msgcat 

要设置当前语言,请使用以下命令:

 msgcat::mclocale ru 

“翻译器”的词汇存储在ru.msg文件中,如下所示:

 #  msgcat::mcset      #     mcset namespace import -force msgcat::mcset #     mcset ru "Language" "" … 

以下是测试文字
带翻译器的脚本:
 #!/usr/bin/wish -f #  msgcat package require msgcat #   ru msgcat::mclocale ru #  ::msgcat::mc      #     mc namespace import msgcat::mc #    [msgcat::mclocale].msg. #       . msgcat::mcload [file join [file dirname [info script]]] #  image create photo rf_32x21_f -file rf_32x21.png image create photo gb_32x21_f -file gb_32x21.png #,      label .lab -text "[mc Language]: " -relief flat -bd 0 –bg snow -anchor sw -width 10 button .but_lang -image rf_32x21_f -command ::changelang -relief flat -bd 0 pack .lab -side left -pady {2 0} pack .but_lang -side left #      proc ::changelang {} { #     #    if {[msgcat::mclocale] == "ru"} { msgcat::mclocale en .but_lang configure -image gb_32x21_f } else { msgcat::mclocale ru .but_lang configure -image rf_32x21_f } #  .lab configure -text "[mc Language]: " } 


在此脚本中,:: changelang过程充当翻译器,当按下带有标志的.but_lang按钮时,将调用该过程。

如果运行此脚本,您将清楚地看到转换器的工作方式:



获取公钥


现在,我们已经决定要翻译,让我们继续分析证书。 为此,我们需要pki包:

 package require pki). 

pki软件包旨在与RSA算法密钥和证书一起使用。 如果使用不同类型的密钥创建了证书(proc :: pki :: x509 :: parse_cert),那么我们将不会收到有关此密钥的信息:

 # Handle RSA public keys by extracting N and E 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 } } 

令人惊讶的是,公钥算法仍然返回(ret(pubkey_algo))
解析证书请求的情况相同(proc :: pki :: pkcs :: parse_csr):

 # Parse public key, based on type switch -- $pubkey_type { "rsaEncryption" { set pubkey [binary format B* $pubkey] ::asn::asnGetSequence pubkey pubkey_parts ::asn::asnGetBigInteger pubkey_parts key(n) ::asn::asnGetBigInteger pubkey_parts key(e) set key(n) [::math::bignum::tostr $key(n)] set key(e) [::math::bignum::tostr $key(e)] set key(l) [expr {2**int(ceil(log([::pki::_bits $key(n)])/log(2)))}] set key(type) rsa } default { return -code error "Unsupported key type: $pubkey_type" } } 

但是在这里他甚至返回有关错误的信息。 但是,今天,除了RSA以外,还使用了欧盟椭圆曲线上的键,包括GOST R 34.10-2012(GOST R 34.10-2001现在也已发布)。

但是默认情况下,只要返回证书或请求中的公钥的ASN结构就足够了,用户本人将根据密钥的类型来解析公钥。 为此,只需将十六进制值的公钥ASN结构添加到返回值中:

 proc ::pki::x509::parse_cert {cert} { . . . ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo #    ASN-  . binary scan $pubkeyinfo H* ret(pubkey_pubkeyinfo) . . . } 

一切,无事可做。 这样,:: pki :: x509 :: parse_cert过程将返回大多数证书扩展名,原因很简单,即它不知道如何解析它们(例如,带有我们合格证书的subjectSignTool),即 由用户自行决定。

另一方面,:: pki :: x509 :: parse_cert过程返回tbs证书的结果之一,该证书包含该证书的所有信息,但其签名(签名)和签名类型(signature_algo)除外:

 #    set fd [open «cert.pem» r] chan configure –translation binary set datacert [read $fd] close $fd #  array set cert_parse [::pki::x509::parse_cert $datacert] # tbs- set cert_tbs_hex $cert_parse(cert) 

我们编写了从tbs证书中提取公钥信息的过程:

 proc ::pki::x509::parse_cert_pubkeyinfo {cert_tbs_hex} { array set ret [list] set wholething [binary format H* $cert_tbs_hex] ::asn::asnGetSequence wholething 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) } ::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 #    hex asn-   binary scan $pubkeyinfo H* ret(pubkeyinfo) return $ret(pubkeyinfo) } 

并且由于我们对俄语密码学感兴趣,因此我们将立即编写解析GOST公钥的过程:

 proc parse_key_gost {pubkeyinfo_hex} { array set ret [list] set pubkeyinfo [binary format H* $pubkeyinfo_hex] ::asn::asnGetSequence pubkeyinfo pubkey_algoid ::asn::asnGetObjectIdentifier pubkey_algoid ret(pubkey_algo) #,   - if {[string first "1 2 643 " $ret(pubkey_algo)] == -1} { return [array get ret] } ::asn::asnGetBitString pubkeyinfo pubkey set pubkey [binary format B* $pubkey] #   binary scan $pubkey H* ret(pubkey) ::asn::asnGetSequence pubkey_algoid pubalgost #OID -  ::asn::asnGetObjectIdentifier pubalgost ret(paramkey) #OID -   ::asn::asnGetObjectIdentifier pubalgost ret(hashkey) #puts "ret(paramkey)=$ret(paramkey)\n" #puts "ret(hashkey)=$ret(hashkey)\n" #parray ret #  :  ,     return [array get ret] } 

是的,我几乎错过了它:加载pki包后,您需要添加到数组:: pki :: oids来表示GOST和合格证书的特征,或者在此数组中根本不存在的oid:

 package require pki # 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.19) "GOST R 34.10-2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GOST R 34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.1.2) "GOST R 34.10-2012-512" set ::pki::oids(1.2.643.2.2.3) "GOST R 34.10-2001 with GOST R 34.11-94" set ::pki::oids(1.2.643.7.1.1.3.2) "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" set ::pki::oids(1.2.643.100.113.1) "KC1 Class Sign Tool" set ::pki::oids(1.2.643.100.113.2) "KC2 Class Sign Tool" . . . 

您还可以通过添加到ru.msg文件来补充翻译者的词汇:

 mcset ru "GOST R 34.10-2001" "  34.10-2001" mcset ru "GOST R 34.10-2012-256" "  34.10-2012-256" mcset ru "GOST R 34.10-2012-512" "  34.10-2012-512" mcset ru "GOST R 34.10-2001 with GOST R 34.11-94" "  34.10-2001    34.11-94" mcset ru "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" "  34.10-2012-256    34.11-2012-256" mcset ru "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" "  34.10-2012-512    34.11-2012-512" . . . 



根证书链和证书吊销列表


前面已经讨论了如何获取根证书链。 以此类推,编写了一个程序来获取已撤销的COS / CRL证书列表。 可以找到该实用程序的源代码及其针对Linux,OS X(macOS)和MS Windows的发行版


在源代码中,您可以找到解析证书扩展的所有过程。
对于Tk的反对者(Tcl / Tk,Python / Tkinter等),我建议找到两个实用程序之间的十(十)个区别:用gtk编写的gcr-viewer实用程序和用Tk开发的certViewer实用程序:



PKCS#11令牌/智能卡证书


上面我们讨论了使用存储在文件中的证书(浏览,获取根证书链,吊销证书列表,sha1和sha256的指纹等)。 但是,仍有证书存储在PKCS#11令牌/智能卡上。 自然的愿望不仅是看到它们,然后将其导出到文件中。 如何执行此操作,我们将在以下文章中进行描述:

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


All Articles