
今天,使用数字证书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令牌/智能卡上。 自然的愿望不仅是看到它们,然后将其导出到文件中。 如何执行此操作,我们将在以下文章中进行描述:
