加密令牌PKCS#11。 图形实用程序“具有签名和添加时间戳的功能”。 第一部分

在对文章“在脚本语言中使用PKCS#11加密令牌机制”的评论中, kovserg读者写道
“我们期待这篇文章具有签署文档和添加时间戳的功能。”
早些时候, pas Habr的另一位参与者写道 ,这对于PKCS#11令牌(每个人都可以计数)(意味着主要是用于生成密钥,生成和验证电子密钥的加密操作),摆脱各种中间层并具有一种实用程序,可以使用令牌本身的机制来形成证书请求并签署文档,验证文档的签名,验证证书的签名和有效性。

熟悉实用程序


结果,我们将该实用程序提交给了用户法院

guipkcs7_tclpkcs11:



此实用程序的驱动力是PKCS#11加密令牌 ,至少支持GOST R 34.10-2012的俄罗斯加密。 如果您打算使用公共服务等,则仍然需要购买已通过俄罗斯FSB认证系统认证测试的令牌。 如果这是您的内部电子文档管理,那么您当然可以决定。 PKCS#11令牌可以不同:软件,硬件甚至 。 该实用程序是用脚本语言Tcl / Tk编写的。 购买PKCS#11令牌时,请不要忘记获取或询问在哪里可以下载用于各种平台的已购买令牌的库。 图书馆通常是免费提供的。 该实用程序使用TclPKCS11程序包来访问加密和其他令牌功能 。 该实用程序从选择支持令牌的库开始。 请注意,库库可以同时使用多个令牌(组合框“选择令牌/智能卡”):



可能会出现问题,但是如果未初始化令牌或需要更改PIN码等,该怎么办? 答案很简单-使用p11conf令牌配置实​​用程序。

要更新令牌列表(禁用令牌,添加一个新令牌),只需单击
通过图标 位于组合框“选择令牌/智能卡”右侧
组合框“证书”包含所选(当前)令牌上存储的所有证书的标签:



如果单击图标 位于组合框证书右侧的窗口将显示一个窗口,其中包含证书的内容:



如果单击查看窗口中的“保存/保存”按钮,则以文本格式解析的证书的内容将保存在您指定的文件中。
要查看有关当前令牌的信息,可以单击“ 6.令牌信息”按钮或将光标移到令牌标签:



为了找出当前令牌支持哪些加密机制,只需单击按钮“ 5.机制列表”:



创建证书申请

我们传递给该实用程序的主要功能。 第一个这样的功能是创建证书请求(按钮“ 3.证书请求”):



如果所选令牌不支持生成这种类型的密钥,则会出现消息“令牌不支持密钥...”。 在这种情况下,您需要选择其他类型的密钥或其他令牌。 在此示例中,您可以使用RuToken ECP 2.0令牌(请参阅第二个屏幕截图)。 组合框“证书持有者”允许您指定谁将拥有证书:个人,法人实体或个人企业家。 依此,将在接下来的页面中形成要填写的字段。

这里的一个重要字段是“名称CIPF”字段。 它是合格证书的组成部分,它指示密码信息保护系统如何生成密钥对。 您可以在产品表格中或购买令牌时找到加密信息保护证书的名称。 我发现很难说,令牌信息中的类型字段是否与密码信息保护系统的名称一致。 因此,最好查看表格。 单击下一步,然后填写必填字段:



填写时,该实用程序会尝试通过发出适当的警告来控制填写字段(电子邮件,PSRN等)的正确性。 填写主要字段后,将要求您确定证书申请在计算机上的格式和存储位置。 您还需要输入令牌的PIN码:



单击“下一步”按钮后,将要求您再次查看输入的内容,并按“完成”键确认您的决定:



而且,如果单击“完成”按钮,将在令牌上生成一个密钥对,一个请求将被创建并签名:



并且您可以确保密钥已生成并存储在令牌上吗? 是的 我们按下“ 7.令牌对象”按钮,输入PIN码以访问令牌,并查找其标签与您在创建证书请求时填写的“ COMMON NANE”(CN)字段匹配的SKO_PRIVATE_KEY和CKO_PUBLIV_KEY对象。 在我们的示例中,它是“全能哈伯”:



看了一下,立即转到另一页。 密钥对已成功创建的最佳证据是签名请求本身的存在。 为了验证这一点,请按“查看请求/证书”按钮,选择已保存的请求,单击“查看证书的请求”按钮,然后查看有关密钥对的信息:



确保已成功创建请求后,使用私钥安全地隐藏令牌或将其放在心脏附近(老一代人知道如何存储派对或Komsomol门票),将请求复制到闪存驱动器,获取必要的文档(护照等)。并前往CA获得证书。 是的,如果这不是部门的CA,那么您仍然需要付款。 一切都像是护照

我们去CA取得证书
在这种情况下,为了向尊敬的Habr颁发证书,我们也将使用所有Habr页面中的CA。 CA开始考虑我们的应用程序:



在应用程序进入CA数据库之后,授权管理员将其考虑并拒绝或批准:



申请被批准后,申请人与CA的授权人一起确定使用证书的目的:



在那之后,没有什么可以阻止证书的颁发:



颁发证书后,CA员工将已颁发的证书导出到Hab。Habr的闪存驱动器:



我们放了令牌证书


因此,证书的幸运持有者返回了他的祖国,首先决定将令牌的证书放在密钥对旁边。 为此,在实用程序的主窗口上,单击按钮“ 4.查看请求/证书”,选择包含证书的文件和操作“查看证书”,然后单击按钮以执行操作“:



我们还可以通过选择适当的操作来检查证书的有效性(但我们还没有时间撤销证书)或签名的正确性:



证书签名验证实用程序代码
#!/usr/bin/env tclsh package require pki load ./tclpkcs11.so Tclpkcs11 #     PKCS#11 #set pkcs11_module "/usr/local/lib64/librtpkcs11ecp_2.0.so" set pkcs11_module "/usr/local/lib64/libls11sw2016.so" puts "Connect the Token and press Enter" gets stdin yes set handle [pki::pkcs11::loadmodule $pkcs11_module] set slots [pki::pkcs11::listslots $handle] set i 0 foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set token_slotlabel $slotlabel set token_slotid $slotid #    incr i break } } if {$i == 0} { puts "   . ." exit } # PEM  DER proc ::cert_to_der {data} { if {[string first "-----BEGIN CERTIFICATE-----" $data] != -1} { set data [string map {"\r\n" "\n"} $data] } array set parsed_cert [::pki::_parse_pem $data "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"] if {[string range $parsed_cert(data) 0 0 ] == "0" } { #   DER- "0" == 0x30 set asnblock $parsed_cert(data) } else { set asnblock "" } return $asnblock } proc usage {use error} { puts "Copyright(C) Orlov Vladimir (http://museum.lissi-crypto.ru/) 2019" if {$use == 1} { puts $error puts "Usage:\nverify_cert_with_pkcs11 <file with certificate> \[<file with CA certificate>\]\n" } } set countcert [llength $argv] if { $countcert < 1 || $countcert > 2 } { usage 1 "Bad usage!" exit } set file [lindex $argv 0] if {![file exists $file]} { usage 1 "File $file not exist" exit } #  cert_user puts "Loading user certificate: $file" set fd [open $file] chan configure $fd -translation binary set cert_user [read $fd] close $fd if {$cert_user == "" } { usage 1 "Bad file with certificate user: $file" exit } set cert_user [cert_to_der $cert_user] if {$cert_user == ""} { puts "User certificate bad" exit } catch {array set cert_parse [::pki::x509::parse_cert $cert_user]} if {![info exists cert_parse]} { puts "User certificate bad" exit } #parray cert_parse if {$countcert == 1} { if {$cert_parse(issuer) != $cert_parse(subject)} { puts "Bad usage: not self signed certificate" } else { set cert_CA $cert_user } } else { set fileca [lindex $argv 1] if {![file exists $fileca]} { usage 1 "File $fileca not exist" exit } #  cert_CA puts "Loading CA certificate: $fileca" set fd [open $fileca] chan configure $fd -translation binary set cert_CA [read $fd] close $fd if {$cert_CA == "" } { usage 1 "Bad file with certificate CA=$fileca" exit } set cert_CA [cert_to_der $cert_CA] if {$cert_CA == ""} { puts "CA certificate bad" exit } } foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set token_slotlabel $slotlabel set token_slotid $slotid } } #    catch {array set cert_parse_CA [::pki::x509::parse_cert $cert_CA]} if {![info exists cert_parse_CA]} { puts "CA certificate bad" exit } #  if {$cert_parse(issuer) != $cert_parse_CA(subject)} { puts "Bad issuer" exit } set aa [dict create pkcs11_handle $handle pkcs11_slotid $token_slotid] set tbs_cert [binary format H* $cert_parse(cert)] catch {set signature_algo_number [::pki::_oid_name_to_number $cert_parse(signature_algo)]} if {![info exists signature_algo_number]} { set signature_algo_number $cert_parse(signature_algo) } switch -- $signature_algo_number { "1.2.643.2.2.3" - "1 2 643 2 2 3" { # "GOST R 34.10-2001 with GOST R 34.11-94" set digest_algo "gostr3411" } "1.2.643.7.1.1.3.2" - "1 2 643 7 1 1 3 2" { # "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" set digest_algo "stribog256" } "1.2.643.7.1.1.3.3" - "1 2 643 7 1 1 3 3" { # "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" set digest_algo "stribog512" } default { puts "  :$signature_algo_number" exit } } #   tbs-!!!! set digest_hex [pki::pkcs11::digest $digest_algo $tbs_cert $aa] # asn-   #    binary scan $cert_CA H* cert_CA_hex array set infopk [pki::pkcs11::pubkeyinfo $cert_CA_hex [list pkcs11_handle $handle pkcs11_slotid $token_slotid]] set lpk [dict create pkcs11_handle $handle pkcs11_slotid $token_slotid] # pybkeyinfo     lappend lpk "pubkeyinfo" lappend lpk $infopk(pubkeyinfo) array set lpkar $lpk puts "Enter PIN user for you token \"$token_slotlabel\":" gets stdin password if { [pki::pkcs11::login $handle $token_slotid $password] == 0 } { puts "Bad PIN" exit } if {[catch {set verify [pki::pkcs11::verify $digest_hex $cert_parse(signature) $lpk]} res] } { puts "  =$res" exit } if {$verify != 1} { puts "BAD SIGNATURE=$verify" } else { puts "SIGNATURE OK=$verify" } 


但是我们现在对将接收到的证书导入我们的令牌的操作感兴趣。 选择“为令牌导入证书”操作,然后单击“执行操作”按钮。 该实用程序将验证证书的电子签名。 为此,您将需要输入令牌的PIN码。 如果一切顺利,那么证书将被导入令牌:



证书的标签(昵称)可以在证书列表中看到:



这是我们的个人证书,即具有密钥对的证书。 如果您再次查看令牌上的对象列表,我们将找到三个标签为“来自UT 12_512的全能哈伯”和相同的CKA_ID的对象。 这三个对象是证书本身(CKO_CERTIFICATE),公共(CKO_PUBLIC_KEY)和私有(CKO_PRIVATE_KEY)密钥。 此三重对象的标签设置如下:
<CN证书发行者>的<CN证书持有者>。

下面我们展示了如何更改标签。

现在我们已经将证书放在令牌上,如何访问它? 为了访问使用位于令牌上的证书的功能,只需将光标移至“证书”标签,然后按鼠标右键:



我们用电子签名签署了第一份文件


让我们等待下一篇文章。 您必须等待几天。 从屏幕截图中可以了解到那里还有什么:



继续这里

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


All Articles