
Jam "H" semakin mendekati: "penggunaan skema tanda tangan GOST R 34.10-2001 untuk menghasilkan tanda tangan setelah 31 Desember 2018 tidak diizinkan!".
Namun, kemudian terjadi kesalahan, seseorang tidak siap, dan penggunaan GOST R 34.10-2001 diperpanjang untuk 2019. Tapi tiba-tiba semua orang bergegas untuk mentransfer CA ke GOST R 34.10-2012, dan untuk mentransfer warga biasa ke sertifikat baru. Orang-orang memiliki beberapa sertifikat di tangan mereka. Saat memeriksa sertifikat atau tanda tangan elektronik, pertanyaan mulai muncul, dan dari mana mendapatkan sertifikat root untuk menginstal di toko sertifikat akar tepercaya.
Ini berlaku untuk kedua toko sertifikat di Windows dan toko sertifikat di Firefox dan Google Chrome, GnuPG, LibreOffice, klien email, dan bahkan OpenSSL. Tentu saja, perlu untuk mengurus ini ketika menerima sertifikat di CA dan menulis rantai sertifikat ke USB flash drive. Dan di sisi lain, kami memiliki masyarakat digital dan setiap saat harus bisa mendapatkan rantai ini dari jaringan.
Simpleadmin menunjukkan cara melakukan ini di halaman Habr. Namun, bagi warga negara biasa itu masih sulit (terutama jika Anda memperhitungkan bahwa sebagian besar dari mereka ada di Windows): Anda perlu memiliki beberapa jenis openssl, sebuah utilitas besar yang tidak saya miliki di komputer saya, dan tidak semua orang tahu Anda bisa menggunakan wget sebagai gantinya. Dan berapa banyak tindakan yang perlu dilakukan. Tentu saja ada jalan keluar, menulis skrip, tetapi tidak hanya skrip di atas openssl dan sejenisnya, tetapi dikemas dalam modul yang dapat dieksekusi mandiri untuk berbagai platform.
Tidak ada keraguan apa yang harus ditulis - dalam
Tcl dan Python . Dan kita mulai dengan Tcl dan
inilah sebabnya :
* wiki sialan di mana bahkan ada mainan (Anda dapat melihat hal-hal menarik di sana :)
* lembar contekan
* build tclkit normal (1,5 - 2 MB sebagai biaya untuk platform lintas nyata)
* dan perakitan eTcl favorit saya dari Evolane (dipelihara dengan hati-hati dari situs yang telah meninggal :(
pertahankan peringkat Tcl / Tk yang tinggi pada daftar toolkit pribadi saya
dan, ya, wiki.tcl.tk/16867 (server web kecil dari cgi ke Tcl, secara berkala digunakan dengan keteguhan yang patut ditiru di bawah tclkit)
dan juga indah dan cantik :)
Untuk ini saya akan menambahkan ketersediaan utilitas
freewrap , yang akan membantu kami membangun utilitas mandiri untuk Linux dan MS Windows. Sebagai hasilnya, kita akan memiliki utilitas chainfromcert:
bash-4.3$ ./chainfromcert_linux64 Copyright(C)2019 Usage: chainfromcert <file with certificate> <directory for chain certificate> Bad usage! bash-4.3$
Sebagai parameter, utilitas menetapkan file dengan sertifikat pengguna (baik dalam format PEM dan format DER) dan direktori di mana sertifikat CA yang termasuk dalam rantai akan disimpan:
bash-4.3$ ./chainfromcert_linux64 ./cert_test.der /tmp Loading file: cert_test.der Directory for chain: . cert 1 from http://ca.ekey.ru/cdp/ekeyUC2012.cer cert 2 from http://reestr-pki.ru/cdp/guc_gost12.crt Goodby! Length chain=2 Copyright(C) 2019 bash-4.3$
Sekarang pertimbangkan cara kerja utilitas.
Informasi tentang otoritas sertifikasi yang menerbitkan sertifikat kepada pengguna disimpan dalam ekstensi dengan oid 1.3.6.1.5.5.7.1.1. Ekstensi ini dapat menyimpan lokasi sertifikat CA (oid 1.3.6.1.5.5.7.48.2) dan informasi tentang layanan OCSP CA (oid 1.3.6.1.5.5.7.48.1):

Dan informasi, misalnya, tentang periode penggunaan kunci tanda tangan elektronik disimpan dalam ekstensi dengan oid 2.5.29.16.
Untuk mengurai sertifikat dan mengakses ekstensi sertifikat, kami akan menggunakan paket pki:
#!/usr/bin/tclsh -f package require pki
Kami juga akan membutuhkan paket base64:
package require base64
Paket pki, serta paket asn dan paket base64 yang dimuatnya, akan membantu kami mengonversi sertifikat dari PEM encoding ke pengkodean DER, mengurai struktur ASN dan benar-benar mengakses informasi tentang lokasi sertifikat CA.
Utilitas dimulai dengan memeriksa parameter dan mengunduh file dengan sertifikat:
proc usage {use } { puts "Copyright(C) 2011-2019" if {$use == 1} { puts "Usage:\nchainfromcert <file with certificate> <directory for chain certificate>\n" } } if {[llength $argv] != 2 } { usage 1 puts "Bad usage!" exit } set file [lindex $argv 0] if {![file exists $file]} { puts "File $file not exist" usage 1 exit } puts "Loading file: $file" set dir [lindex $argv 1] if {![file exists $dir]} { puts "Dir $dir not exist" usage 1 exit } puts "Directory for chain: $dir" set fd [open $file] chan configure $fd -translation binary set data [read $fd] close $fd if {$data == "" } { puts "Bad file with certificate=$file" usage 1 exit }
Semuanya jelas di sini dan kami mencatat hanya satu hal - file dengan sertifikat dianggap sebagai file biner:
chan configure $fd -translation binary
Hal ini disebabkan oleh fakta bahwa sertifikat dapat disimpan baik dalam format DER (kode biner) dan dalam format PEM (pengkodean base64).
Setelah file dimuat, prosedur chainfromcert disebut:
set depth [chainfromcert $data $dir]
yang sebenarnya mengunduh sertifikat root:
proc chainfromcert {cert dir} { if {$cert == "" } { exit } set asndata [cert_to_der $cert] if {$asndata == "" } { # , return -1 } array set cert_parse [::pki::x509::parse_cert $asndata] array set extcert $cert_parse(extensions) if {![info exists extcert(1.3.6.1.5.5.7.1.1)]} { # return 0 } set a [lindex $extcert(1.3.6.1.5.5.7.1.1) 0] # if {$a == "false"} { # puts $a # } # ASN1- Hex- set b [lindex $extcert(1.3.6.1.5.5.7.1.1) 1] # set c [binary format H* $b] #Sequence 1.3.6.1.5.5.7.1.1 ::asn::asnGetSequence c c_par_first # 1.3.6.1.5.5.7.1.1 while {[string length $c_par_first] > 0 } { # (sequence) ::asn::asnGetSequence c_par_first c_par # oid ::asn::asnGetObjectIdentifier c_par c_type set tas1 [::pki::_oid_number_to_name $c_type] # ::asn::asnGetContext c_par c_par_two # oid if {$tas1 == "1.3.6.1.5.5.7.48.2" } { # set certca [readca $c_par $dir] if {$certca == ""} { # . continue } else { global count # set f [file join $dir [file tail $c_par]] set fd [open $fw] chan configure $fd -translation binary puts -nonewline $fd $certca close $fd incr count puts "cert $count from $c_par" # chainfromcert $certca $dir continue } } elseif {$tas1 == "1.3.6.1.5.5.7.48.1" } { # puts "OCSP server (oid=$tas1)=$c_par" } } # return $count }
Tidak ada yang ditambahkan ke komentar, tetapi kami masih belum mempertimbangkan prosedur readca:
proc readca {url dir} { set cer "" # 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 }
Prosedur ini didasarkan pada penggunaan paket http:
package require http
Untuk membaca sertifikat, kami menggunakan fungsi berikut:
set token [http::geturl $url -binary 1]
Tujuan dari sisa fungsi yang digunakan jelas dari komentar. Kami hanya akan memberikan dekripsi kode pengembalian untuk fungsi http :: ncodel:
200 Permintaan berhasil diselesaikan
206 Permintaan berhasil diselesaikan, tetapi hanya sebagian file yang diunduh
301 File dipindahkan ke lokasi lain.
302 File dipindahkan sementara ke lokasi lain.
Diperlukan 401 otentikasi server
403 Akses ke sumber ini ditolak
404 Sumber yang ditentukan tidak dapat ditemukan.
500 Kesalahan internal
Satu prosedur masih harus dipertimbangkan, yaitu cert_to_der:
proc cert_to_der {data} { set lines [split $data \n] set hlines 0 set total 0 set first 0 # PEM- foreach line $lines { incr total if {[regexp {^-----BEGIN CERTIFICATE-----$} $line]} { if {$first} { incr total -1 break } else { set first 1 incr hlines } } if {[regexp {^(.*):(.*)$} $line ]} { incr hlines } } if { $first == 0 && [string range $data 0 0 ] == "0" } { # DER- "0" == 0x30 return $data } if {$first == 0} {return ""} set block [join [lrange $lines $hlines [expr {$total-1}]]] #from PEM to DER set asnblock [base64::decode $block] return $asnblock }
Prosedurnya sangat sederhana. Jika ini adalah file PEM dengan sertifikat ("----- BEGIN CERTIFICATE -----"), maka badan file ini dipilih dan dikonversi ke kode binar:
set asnblock [base64::decode $block]
Jika ini bukan file PEM, maka ini "kesamaan" dengan pengkodean asn diperiksa (bit nol harus 0x30).
Itu saja, tetap menambahkan baris terakhir:
if {$depth == -1} { puts "Bad file with certificate=$file" usage 1 exit } puts "Goodby!\nLength chain=$depth" usage 0 exit
Sekarang kami mengumpulkan semuanya dalam satu file dengan nama
chainfromcert.tcl #!/usr/bin/tclsh encoding system utf-8 package require pki package require base64 #package require asn package require http global count set count 0 proc chainfromcert {cert dir} { if {$cert == "" } { exit } set asndata [cert_to_der $cert] if {$asndata == "" } { # , return -1 } array set cert_parse [::pki::x509::parse_cert $asndata] array set extcert $cert_parse(extensions) if {![info exists extcert(1.3.6.1.5.5.7.1.1)]} { # return 0 } set a [lindex $extcert(1.3.6.1.5.5.7.1.1) 0] # if {$a == "false"} { # puts $a # } # ASN1- Hex- set b [lindex $extcert(1.3.6.1.5.5.7.1.1) 1] # set c [binary format H* $b] #Sequence 1.3.6.1.5.5.7.1.1 ::asn::asnGetSequence c c_par_first # 1.3.6.1.5.5.7.1.1 while {[string length $c_par_first] > 0 } { # (sequence) ::asn::asnGetSequence c_par_first c_par # oid ::asn::asnGetObjectIdentifier c_par c_type set tas1 [::pki::_oid_number_to_name $c_type] # ::asn::asnGetContext c_par c_par_two # oid if {$tas1 == "1.3.6.1.5.5.7.48.2" } { # set certca [readca $c_par $dir] if {$certca == ""} { # . continue } else { global count # set f [file join $dir [file tail $c_par]] set fd [open $fw] chan configure $fd -translation binary puts -nonewline $fd $certca close $fd incr count puts "cert $count from $c_par" # chainfromcert $certca $dir continue } } elseif {$tas1 == "1.3.6.1.5.5.7.48.1" } { # puts "OCSP server (oid=$tas1)=$c_par" } } # return $count } proc readca {url dir} { set cer "" # 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 } proc cert_to_der {data} { set lines [split $data \n] set hlines 0 set total 0 set first 0 # PEM- foreach line $lines { incr total # if {[regexp {^-----(.*?)-----$} $line]} {} if {[regexp {^-----BEGIN CERTIFICATE-----$} $line]} { if {$first} { incr total -1 break } else { set first 1 incr hlines } } if {[regexp {^(.*):(.*)$} $line ]} { incr hlines } } if { $first == 0 && [string range $data 0 0 ] == "0" } { # DER- "0" == 0x30 return $data } if {$first == 0} {return ""} set block [join [lrange $lines $hlines [expr {$total-1}]]] #from PEM to DER set asnblock [base64::decode $block] return $asnblock } proc usage {use } { puts "Copyright(C) Orlov Vladimir 2011-2019" if {$use == 1} { puts "Usage:\nchainfromcert <file with certificate> <directory for chain certificate>\n" } } if {[llength $argv] != 2 } { usage 1 puts "Bad usage!" exit } set file [lindex $argv 0] if {![file exists $file]} { puts "File $file not exist" usage 1 exit } puts "Loading file: $file" set dir [lindex $argv 1] if {![file exists $dir]} { puts "Dir $dir not exist" usage 1 exit } puts "Directory for chain: $dir" set fd [open $file] chan configure $fd -translation binary set data [read $fd] close $fd if {$data == "" } { puts "Bad file with certificate=$file" usage 1 exit } set depth [chainfromcert $data $dir] if {$depth == -1} { puts "Bad file with certificate=$file" usage 1 exit } puts "Goodby!\nLength chain=$depth" usage 0 exit
Anda dapat memeriksa operasi file ini menggunakan interpreter tclsh:
$ tclsh ./chainfromcert.tcl cert_orlov.der /tmp Loading file: cert_test.der Directory for chain: /tmp cert 1 from http://ca.ekey.ru/cdp/ekeyUC2012.cer cert 2 from http://reestr-pki.ru/cdp/guc_gost12.crt Goodby! Length chain=2 Copyright(C) 2019 $
Akibatnya, kami mendapat rantai dua sertifikat di direktori / tmp.
Tetapi kami ingin mendapatkan modul yang dapat dieksekusi untuk platform Linux dan Windows dan agar pengguna tidak memikirkan penerjemah apa pun.
Untuk tujuan ini kita akan menggunakan utilitas
freewrapTCLSH . Dengan menggunakan utilitas ini, kami akan membuat modul yang dapat dieksekusi dari utilitas kami untuk platform Linux dan Windows, baik 32-bit dan 64-bit. Utilitas dapat dibangun untuk semua platform di platform apa pun. Maaf untuk tautologi. Saya akan membangun di linux_x86_64 (Mageia).
Untuk membangun, Anda perlu:
1. Utilitas freewrapTCLSH untuk platform linux_x86_64;
2. File freewrapTCLSH dengan utilitas ini untuk setiap platform:
- freewrapTCLSH_linux32
- freewrapTCLSH_linux64
- freewrapTCLSH_win32
- freewrapTCLSH_win64
3. File sumber utilitas kami: chainfromcert.tcl
Jadi, chainfromcerty_linuxx86 rakitan yang dapat dieksekusi untuk platform Linux x86:
$freewrapTCLSH chainfromcert.tcl –w freewrapTCLSH_linux32 –o chainfromcerty_linuxx86 $
Perakitan utilitas untuk platform Windows 64-bit terlihat seperti ini:
$freewrapTCLSH chainfromcert.tcl –w freewrapTCLSH_win64 –o chainfromcerty_win64.exe $
Dll Utilitas siap digunakan. Mereka telah menyerap semua yang diperlukan untuk pekerjaan mereka.
Kode ditulis dengan cara yang sama dengan Python.
Dalam beberapa hari mendatang, saya berpikir untuk menambah paket
fsb795 (yang ditulis dengan Python) dengan fungsi untuk mendapatkan rantai sertifikat root.