
Dalam komentar pada artikel "Utilitas lintas platform berbahasa Inggris untuk melihat sertifikat x509 yang memenuhi syarat Rusia" ada keinginan dari pengguna
Pas untuk tidak hanya "penguraian sertifikat", tetapi juga untuk menerima "rantai sertifikat root dan melaksanakan validasi PKI, setidaknya untuk sertifikat dengan token dengan kunci yang dapat diekstraksi. ". Memperoleh rantai sertifikat dijelaskan dalam salah satu artikel sebelumnya. Benar, ini tentang sertifikat yang disimpan dalam file, tetapi kami berjanji untuk menambahkan mekanisme untuk bekerja dengan sertifikat yang disimpan di token PKCS # 11. Dan itulah yang terjadi pada akhirnya.

Utilitas parsing dan melihat ditulis dalam Tcl / Tk, dan untuk menambahkan token / kartu pintar PKCS # 11 ke dalamnya, melihat sertifikat serta memeriksa validitas sertifikat, perlu untuk menyelesaikan beberapa masalah:
- menentukan mekanisme untuk mendapatkan sertifikat dari token / smart card;
- periksa sertifikat terhadap daftar sertifikat CRL yang dicabut;
- periksa sertifikat validitas dengan mekanisme OCSP.
Akses ke Token PKCS # 11
Untuk mengakses token dan sertifikat yang tersimpan di dalamnya, kami akan menggunakan paket
TclPKCS11 . Paket ini didistribusikan dalam biner dan kode sumber. Kode sumber akan berguna nanti ketika kita menambahkan dukungan token dengan kriptografi Rusia ke paket. Ada dua cara untuk mengunduh paket TclPKCS11, atau menggunakan perintah tcl dari formulir:
load < tclpkcs11> Tclpkcs11
Atau unduh hanya sebagai paket pki :: pkcs11, setelah meletakkan pustaka tclpkcs11 dan file pkgIndex.tcl ke dalam direktori yang nyaman bagi Anda (dalam kasus kami, ini adalah subdirektori pkcs11 dari direktori saat ini) dan menambahkannya ke jalur auto_path:
#lappend auto_path [file dirname [info scrypt]] lappend auto_path pkcs11 package require pki package require pki::pkcs11
Karena kami tertarik pada token terutama dengan dukungan untuk kriptografi Rusia, dari paket TclPKCS11 kami akan menggunakan
fungsi -
fungsi berikut:
::pki::pkcs11::loadmodule <filename> -> handle ::pki::pkcs11::unloadmodule <handle> -> true/false ::pki::pkcs11::listslots <handle> -> list: slotId label flags ::pki::pkcs11::listcerts <handle> <slotId> -> list: keylist ::pki::pkcs11::login <handle> <slotId> <password> -> true/false ::pki::pkcs11::logout <handle> <slotId> -> true/false
Segera buat reservasi bahwa fungsi masuk dan keluar tidak akan dipertimbangkan di sini. Ini disebabkan oleh fakta bahwa dalam artikel ini kita hanya akan berurusan dengan sertifikat, dan mereka adalah objek token publik. Untuk mengakses objek publik tidak perlu masuk melalui kode PIN pada token.
Fungsi pertama :: pki :: pkcs11 :: loadmodule adalah untuk memuat pustaka PKCS # 11, yang mendukung token / kartu pintar tempat sertifikat berada. Perpustakaan dapat diperoleh dengan membeli token, atau diunduh dari Internet, atau sudah diinstal sebelumnya di komputer. Bagaimanapun, Anda perlu tahu perpustakaan mana yang mendukung token Anda. Fungsi loadmodule mengembalikan pegangan ke pustaka yang dimuat:
set filelib "/usr/local/lib64/librtpkcs11ecp_2.0.so" set handle [::pki::pkcs11::loadmodule $filelib]
Karenanya, ada fungsi untuk membongkar pustaka yang dimuat:
::pki::pkcs11::unloadmodule $handle
Setelah perpustakaan dimuat dan kami memiliki pegangannya, Anda bisa mendapatkan daftar slot yang didukung oleh perpustakaan ini:
::pki::pkcs11::listslots $handle {0 {ruToken ECP } {TOKEN_PRESENT RNG LOGIN_REQUIRED USER_PIN_INITIALIZED TOKEN_INITIALIZED REMOVABLE_DEVICE HW_SLOT}} {1 { } {REMOVABLE_DEVICE HW_SLOT}} . . . {14 { } {REMOVABLE_D EVICE HW_SLOT}}
Dalam contoh ini, daftar berisi 15 (lima belas dari 0 hingga 14) elemen. Itu adalah berapa banyak slot yang dapat didukung oleh keluarga token RuToken. Pada gilirannya, setiap elemen dari daftar itu sendiri adalah daftar dari tiga elemen:
{{ } { } { }}
Elemen pertama dari daftar adalah nomor slot. Elemen kedua dari daftar adalah label yang terletak di slot token (32 byte). Jika slotnya kosong, maka elemen kedua berisi 32 spasi. Dan yang terakhir, elemen ketiga dari daftar berisi bendera. Kami tidak akan mempertimbangkan seluruh rangkaian bendera. Yang menarik bagi kami dalam bendera ini adalah keberadaan bendera TOKEN_PRESENT. Bendera inilah yang menunjukkan bahwa token ada di slot, dan sertifikat yang menarik bagi kami bisa ada di token. Bendera adalah hal yang sangat berguna, mereka menggambarkan keadaan token, status kode PIN, dll. Berdasarkan nilai bendera, token PKCS # 11 dikelola:

Sekarang, tidak ada yang mencegah Anda menulis prosedur slots_with_token, yang akan mengembalikan daftar slot dengan label token di dalamnya:
#!/usr/bin/tclsh lappend auto_path pkcs11 package require pki package require pki::pkcs11 # proc ::slots_with_token {handle} { set slots [pki::pkcs11::listslots $handle] # puts "Slots: $slots" array set listtok [] 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 listtok($slotid) $slotlabel } } # parray listtok return [array get listtok] } set filelib "/usr/local/lib64/librtpkcs11ecp_2.0.so" if {[catch {set handle [::pki::pkcs11::loadmodule $filelib]} res]} { puts "Cannot load library $filelib : $res" exit } # set listslots {} set listslots [::slots_with_token $handle] # while {[llength $listslots] == 0} { puts " " after 3000 set listslots [::slots_with_token $handle] } # foreach {slotid labeltok} $listslots { puts "Number slot: $slotid" puts "Label token: $labeltok" }
Jika Anda menjalankan skrip ini, setelah menyimpannya di file slots_with_token.tcl, maka sebagai hasilnya kita mendapatkan:
$ ./slots_with_token.tcl listtok(0) = ruToken ECP listtok(1) = RuTokenECP20 Number slot: 0 Label token: RuTokenECP20 Number slot: 1 Label token: ruToken ECP $
Dari 15 slot yang tersedia untuk perpustakaan ini, hanya dua yang terlibat, nol dan yang pertama.
Sekarang tidak ada yang mencegah mendapatkan daftar sertifikat yang terletak di token tertentu:
set listcerts [::pki::pkcs11::listcerts $handle $slotid]
Setiap item daftar berisi informasi tentang satu sertifikat. Untuk mendapatkan informasi dari sertifikat, fungsi :: pki :: pkcs11 :: listcerts menggunakan fungsi :: pki :: x509 :: parse_cert dari paket pki. Tetapi fungsi :: pki :: pkcs11 :: listcerts melengkapi daftar ini dengan data yang melekat pada protokol PKCS # 11, yaitu:
- pkcs11_ elemen label (dalam terminologi atribut PKCS # 11 CKA_LABEL);
- elemen pkcs11_id (dalam terminologi atribut PKCS # 11 CKA_ID);
- elemen pkcs11_handle yang berisi indikasi pustaka PKCS # 11 yang dimuat;
- elemen pkcs11_slotid yang berisi jumlah slot dengan token tempat sertifikat ini berada;
- elemen tipe yang berisi nilai pkcs11 untuk sertifikat yang ada di token.
Ingat bahwa elemen yang tersisa terutama ditentukan oleh fungsi pki :: parse_cert.
Di bawah ini adalah prosedur untuk memperoleh daftar label (listCert) sertifikat (CKA_LABEL, pkcs11_label) dan array pengidentifikasi yang diurai (:: certs_p11). Kunci untuk mengakses elemen array sertifikat adalah label sertifikat (CKA_LABEL, pkcs11_label):
# proc listcerttok {handle token_slotlabel token_slotid} { # set listCer {} # array set ::arrayCer [] set ::certs_p11 [pki::pkcs11::listcerts $handle $token_slotid] if {[llength $::certs_p11] == 0} { puts {Certificates are not on the token:$tokenslotlabel} return $listCer } foreach certinfo_list $::certs_p11 { unset -nocomplain certinfo array set certinfo $certinfo_list set certinfo(pubkeyinfo) [::pki::x509::parse_cert_pubkeyinfo $certinfo(cert)] set ::arrayCer($certinfo(pkcs11_label)) $certinfo(cert) lappend listCer $certinfo(pkcs11_label) } return $listCer }
Dan sekarang kami telah mem-parsing sertifikat, kami dengan tenang menampilkan daftar label mereka di kotak kombo:

Cara mengurai kunci publik GOST yang kami pertimbangkan di artikel sebelumnya.
Dua kata tentang ekspor sertifikat. Sertifikat diekspor baik dalam encoding PEM dan encoding DER (tombol DER, format PEM). Paket pki memiliki fungsi yang mudah pki :: _ encode_pem untuk mengkonversi ke format PEM:
set bufpem [::pki::_encode_pem <der-buffer> <Headline> <Lastline>]
misalnya:
set certpem [::pki::encode_pen $cert_der "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"]
Dengan memilih label sertifikat septik dalam kotak kombo, kami mendapatkan akses ke badan sertifikat:
# set nick [.saveCert.labExp.listCert get] # foreach certinfo_list $::certs_p11 { unset -nocomplain cert_parse array set cert_parse $certinfo_list if {$cert_parse(pkcs11_label) == $nick} { # set cert_parse(pubkeyinfo) [::pki::x509::parse_cert_pubkeyinfo $cert_parse(cert)] break } } # file|pkcs11 set ::tekcert "pkcs11"
Mekanisme lebih lanjut untuk penguraian sertifikat dan menampilkannya sebelumnya dibahas di
sini .
Validasi Sertifikat
Saat menguraikan sertifikat, variabel :: notbefore dan :: notafter menyimpan tanggal dari mana sertifikat dapat digunakan dalam operasi kriptografi (tanda, enkripsi, dll.), Dan tanggal kedaluwarsa sertifikat. Prosedur untuk memeriksa masa berlaku sertifikat adalah:
proc cert_valid_date {} { # # set startdate $::notbefore # set enddate $::notafter # set now [clock seconds] set isvalid 1 set reason "Certificate is valid" if {$startdate > $now} { set isvalid 0 # set reason "Certificate is not yet valid" } elseif {$now > $enddate} { set isvalid 0 # set reason "Certificate has expired" } return [list $isvalid $reason] }
Daftar yang dikembalikan berisi dua item. Elemen pertama dapat berisi 0 (nol) atau 1 (satu). Nilai "1" menunjukkan bahwa sertifikat itu valid, dan 0 menunjukkan bahwa sertifikat itu tidak valid. Alasan sertifikat tidak valid diungkapkan dalam elemen kedua. Elemen ini dapat berisi satu dari tiga nilai:
- sertifikat valid (elemen pertama dari daftar adalah 1):
- sertifikat belum valid (sertifikat belum kedaluwarsa)
- sertifikat telah kedaluwarsa.
Validitas sertifikat ditentukan tidak hanya oleh masa berlakunya. Sertifikat dapat ditangguhkan atau diberhentikan oleh pusat sertifikasi, baik atas inisiatifnya sendiri dan atas permintaan pemegang sertifikat, misalnya, jika kehilangan media dengan kunci pribadi. Dalam hal ini, sertifikat tersebut dimasukkan oleh otoritas sertifikasi dalam daftar sertifikat COS / CRL yang dicabut yang didistribusikan oleh CA. Biasanya, titik distribusi CRL termasuk dalam sertifikat. Dari daftar sertifikat yang dicabut, validitas sertifikat diperiksa.
Validasi validitas sertifikat oleh SOS / CRL
Langkah pertama adalah mendapatkan SOS, lalu parsing dan periksa sertifikatnya.
Daftar poin penerbitan COC / CRL ada dalam ekstensi sertifikat dengan oid 2.5.29.31 (id-ce-cRLDistributionPoints):
array set extcert $cert_parse(extensions) set ::crlfile "" if {[info exists extcert(2.5.29.31)]} { set ::crlfile [crlpoints [lindex $extcert(2.5.29.31) 1]] } else { puts "cannot load CRL" }
Sebenarnya memuat file dengan SOS / CRL adalah sebagai berikut:
set filecrl "" set pointcrl "" foreach pointcrl $::crlfile { set filecrl [readca $pointcrl $dir] if {$filecrl != ""} { set f [file join $dir [file tail $pointcrl]] set fd [open $fw] chan configure $fd -translation binary puts -nonewline $fd $filecrl close $fd set filecrl $f break } # CRL . CRL } if {$filecrl == ""} { puts "Cannot load CRL" }
Sebenarnya, prosedur readca digunakan untuk memuat COC / CRL:
proc readca {url dir} { set cer "" # if { "https://" == [string range $url 0 7]} { # tls http::register https 443 ::tls::socket } # if {[catch {set token [http::geturl $url -binary 1] # set ere [http::status $token] if {$ere == "ok"} { # set code [http::ncode $token] if {$code == 200} { # set cer [http::data $token] } elseif {$code == 301 || $code == 302} { # , set newURL [dict get [http::meta $token] Location] # set cer [readca $newURL $dir] } else { # set cer "" } } } error]} { # , set cer "" } return $cer }
Variabel dir menyimpan path ke direktori di mana COS / CRL akan disimpan, dan variabel url berisi daftar poin distribusi CRL yang sebelumnya diterima.
Ketika menerima SOS / CRL, saya tiba-tiba harus menghadapi kenyataan bahwa untuk beberapa sertifikat daftar ini harus diterima melalui protokol https (tls) dalam mode anonim. Jujur, ini mengejutkan: daftar CRL adalah dokumen publik dan integritasnya dilindungi oleh tanda tangan elektronik dan saya memiliki akses ke sana melalui https anonim menurut saya. Tetapi tidak ada yang bisa dilakukan, Anda harus menghubungkan paket tls - paket membutuhkan tls.
Jika SOS / CRL tidak dapat diunduh, maka sertifikat tidak dapat diverifikasi jika jalur akses dengan layanan OCSP tidak ditentukan dalam sertifikat. Tetapi ini akan dibahas dalam salah satu artikel berikut.
Jadi, ada sertifikat untuk verifikasi, ada daftar SOS / CRL, masih harus memeriksa sertifikat untuk itu. Sayangnya, tidak ada fungsi yang sesuai dalam paket pki. Oleh karena itu, saya harus menulis prosedur untuk memeriksa validitas sertifikat (tidak dicabut) dari daftar sertifikat yang dicabut.
validaty_cert_from_crl: proc validaty_cert_from_crl {crl sernum issuer} { array set ret [list] if { [string range $crl 0 9 ] == "-----BEGIN" } { array set parsed_crl [::pki::_parse_pem $crl "-----BEGIN X509 CRL-----" "-----END X509 CRL-----"] set crl $parsed_crl(data) } ::asn::asnGetSequence crl crl_seq ::asn::asnGetSequence crl_seq crl_base ::asn::asnPeekByte crl_base peek_tag if {$peek_tag == 0x02} { # .CRL ::asn::asnGetInteger crl_base ret(version) incr ret(version) } else { set ret(version) 1 } ::asn::asnGetSequence crl_base crl_full ::asn::asnGetObjectIdentifier crl_full ret(signtype) ::::asn::asnGetSequence crl_base crl_issue set ret(issue) [::pki::x509::_dn_to_string $crl_issue] # /CRL if {$ret(issue) != $issuer } { #/CRL set ret(error) "Bad Issuer" return [array get ret] } binary scan $crl_issue H* ret(issue_hex) # ::asn::asnGetUTCTime crl_base ret(publishDate) # ::asn::asnGetUTCTime crl_base ret(nextDate) # ::asn::asnPeekByte crl_base peek_tag if {$peek_tag != 0x30} { # return [array get ret] } ::asn::asnGetSequence crl_base lcert # binary scan $lcert H* ret(lcert) while {$lcert != ""} { ::asn::asnGetSequence lcert lcerti # ::asn::asnGetBigInteger lcerti ret(sernumrev) set ret(sernumrev) [::math::bignum::tostr $ret(sernumrev)] # CRL if {$ret(sernumrev) != $sernum} { continue } # . ::asn::asnGetUTCTime lcerti ret(revokeDate) if {$lcerti != ""} { # ::asn::asnGetSequence lcerti lcertir ::asn::asnGetSequence lcertir reasone ::asn::asnGetObjectIdentifier reasone ret(reasone) ::asn::asnGetOctetString reasone reasone2 ::asn::asnGetEnumeration reasone2 ret(reasoneData) } break; } return [array get ret] }
Parameter untuk fungsi ini adalah daftar pencabutan sertifikat (crl), nomor seri sertifikat yang diverifikasi (sernum), dan penerbitnya (penerbit).
Daftar pencabutan sertifikat (crl) dimuat sebagai berikut:
set f [open $filecrl r] chan configure $f -translation binary set crl [read $f] close $f
Nomor seri sertifikat terverifikasi (sernum) dan penerbitnya (penerbit) diambil dari sertifikat yang diuraikan dan disimpan dalam variabel :: sncert dan :: issuercert.
Semua prosedur dapat ditemukan dalam kode sumber. Kode sumber utilitas dan distribusinya untuk Linux, OS X (macOS) dan MS Windows dapat ditemukan di sini.
Utilitas juga mempertahankan kemampuan untuk melihat dan memverifikasi sertifikat yang disimpan dalam file:

Omong-omong, sertifikat yang dilihat dari file juga dapat diekspor, serta yang disimpan di token. Ini membuatnya mudah untuk mengkonversi file sertifikat dari format DER ke PEM dan sebaliknya.
Sekarang kami memiliki satu penampil untuk sertifikat yang disimpan dalam file dan pada token / kartu pintar PKCS # 11.
Ya, saya melewatkan intinya: untuk memeriksa validitas sertifikat, klik tombol "Tambahan" dan pilih item menu "Validaty oleh CRL" atau tekan tombol mouse kanan dan ketika kursor berada pada informasi utama bidang dan juga pilih item menu "Validaty oleh CRL":

Tangkapan layar ini menunjukkan penelusuran dan validasi sertifikat dalam token cloud.
Sebagai kesimpulan, kami mencatat hal berikut. Dalam komentarnya pada
artikel tersebut , pengguna
Pas dengan benar mencatat tentang token PKCS # 11 bahwa mereka “sendiri dapat menghitung semuanya”. Ya, token sebenarnya adalah komputer kriptografis. Dan dalam artikel berikut kita akan berbicara tidak hanya tentang bagaimana sertifikat diverifikasi menggunakan protokol OCSP, tetapi juga tentang bagaimana menggunakan mekanisme kriptografi (kita berbicara, tentu saja, kriptografi GOST) dari token / kecerdasan untuk menghitung hash (GOST R 34-10- 94/2012), pembentukan dan verifikasi tanda tangan, dll.