Infrastruktur kunci publik: Perpustakaan GCrypt sebagai alternatif untuk OpenSSL dengan dukungan untuk kriptografi Rusia

Paruh kedua tahun 2018 semakin dekat dan "tahun 2000" di PKI berdasarkan kriptografi Rusia akan segera datang. Ini disebabkan oleh kenyataan bahwa
Menggunakan skema tanda tangan GOST R 34.10-2001 untuk menghasilkan tanda tangan setelah 31 Desember 2018 tidak diperbolehkan!
Hari ini tidak masuk akal untuk menerima sertifikat dengan tanda tangan sesuai dengan GOST R 34.10-2001.
Pada saat yang sama, banyak layanan atau aplikasi dikembangkan berdasarkan OpenSSL, yang mendukung pekerjaan dengan GOST R 34.10-2001.

Tetapi hari ini dalam versi standar openssl tidak ada dukungan untuk GOST R 34.11-2012 dan GOST R 34.10-2012. Selain itu, dalam versi 1.1, dukungan kriptografi GOST dikecualikan dari distribusi standar ("Mesin GOST kedaluwarsa dan karenanya telah dihapus.").

Semua ini membuat kami mencari cara alternatif untuk bekerja dengan sertifikat, dengan tanda tangan elektronik ("pesan format CMS") dan objek PKI lainnya berdasarkan kriptografi Rusia yang baru.

Salah satu cara yang memungkinkan adalah dengan menggunakan pustaka GCrypt . Perpustakaan ini mendukung algoritma baru GOST R 34.11-2012 (algoritma hashing) dan GOST R 34.10-2012 (algoritma tanda tangan).

Generasi pasangan kunci


Jadi, kami mulai dengan membuat pasangan kunci yang berisi kunci privat dan publik. Saat ini, dalam kriptografi Rusia ada tiga jenis kunci tanda tangan dengan oid-s yang sesuai
- GOST R 34.10-2001 dengan panjang kunci 256 bit, oid 1.2.643.2.2.19 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x13);
- GOST R 34.10-2012 dengan panjang kunci 256 bit (selanjutnya GOST R 34.10-12-256), ditawarkan 1.2.643.7.1.1.1.1 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x01, 0x01);
- GOST R 34.10-2012 dengan panjang kunci 512 bit (selanjutnya GOST R 34.10-12-512), ditawarkan 1.2.643.7.1.1.1.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x01, 0x02).
Dan segera perhatikan bahwa dalam hal matematika, algoritme pembangkitan dan implementasinya, kunci-kunci GOST R 34.10-2001 dan GOST R 34.10-12-256 benar-benar identik! Serta algoritma yang identik untuk pembentukan tanda tangan elektronik berdasarkan pada mereka. Manakah dari kunci yang dimaksud hanya dapat dinilai dengan informasi tentang kunci yang terkandung, misalnya, dalam sertifikat. Jadi mengapa perlu dua oid yang berbeda? Hanya menekankan fakta bahwa saat membuat tanda tangan elektronik dengan kunci GOST R 34.10-2001, hash yang diperoleh sesuai dengan GOST R 34.10-94 harus digunakan, dan saat menggunakan kunci GOST R 34.10-12-256, hash diperoleh sesuai dengan GOST R 34.10- 212 dengan panjang 256 bit. Meskipun, untuk menekankan ini, ada oid-s yang sesuai:
- 1.2.643.2.2.3 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x03) - algoritma tanda tangan GOST R 34.10-2001 dengan kunci 256 dengan hashing GOST R 34.11-94;
- 1.2.643.7.1.1.3.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x02) - algoritma tanda tangan GOST R 34.10-2012 dengan kunci 256 dengan hashing GOST R 34.11-2012;
- 1.2.643.7.1.1.3.3 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x03, 0x03) - algoritma tanda tangan GOST R 34.10-2012 dengan kunci 512 dengan hashing GOST R 34.11-2012.
Dengan demikian, ada beberapa penyortiran dengan oid-s, tetapi begitulah adanya.

Kunci dari keluarga GOST milik keluarga kunci pada kurva elips. Untuk menghasilkan pasangan kunci, Anda harus menentukan titik dasar pada kurva elips.

Komite teknis untuk standardisasi "Keamanan informasi kriptografi" ( TC 26 ) merekomendasikan untuk menggunakan dua poin dasar untuk tombol GOST R 34.10-2012-512:
- GOST2012-tc26-A (nama panggilan dalam terminologi libgcrypt) dengan oid 1.2.643.7.1.2.1.2.1 (0x2a, 0x85, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02, 0x01);
- GOST2012-tc26-B dengan oid 1.2.643.7.1.2.1.2.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02, 0x02);
Untuk kunci GOST R 34.10 dengan panjang 256 bit, tiga titik dasar direkomendasikan:
- GOST2001-CryptoPro-A dengan oid om 1.2.643.2.2.35.1 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x23, 0x01);
- GOST2001-CryptoPro-B dengan oid 1.2.643.2.2.35.2 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x23, 0x02);
- GOST2001-CryptoPro-C dengan oid 1.2.643.2.2.35.3 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x23, 0x03).
Untuk kunci GOST R 34.10 dengan panjang 256 bit, dua oid lagi ditentukan untuk titik dasar:
- GOST2001-CryptoPro-XchA dengan oid 1.2.643.2.2.36.0 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x24, 0x24, 0x00);
- GOST2001-CryptoPro-XchB dengan oid 1.2.643.2.2.36.1 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x24, 0x24, 0x01).
Namun, pada kenyataannya, oid ini merujuk ke titik dasar GOST2001-CryptoPro-A dengan oid 1.2.643.2.2.35.1 dan GOST2001-CryptoPro-C dengan oid 1.2.643.2.2.35.3.
Dan ini harus diperhitungkan saat memproses poin dasar dengan oid-s ini.

Untuk menghasilkan pasangan kunci, fungsi gcry_pk_genkey dari formulir berikut digunakan:

gcry_error_t gcry_pk_genkey (gcry sexp t *key_pair, gcry sexp t key_spec ). 

Parameter harus diatur dalam variabel parms untuk menghasilkan pasangan kunci dalam format ekspresi-S internal (sexp). Untuk menghasilkan pasangan kunci berdasarkan GOST, parameter ditetapkan dalam bentuk ekspresi S berikut:

 (genkey ( (curve _))),  

ecc menentukan generasi pasangan kunci pada kurva elips, dan titik dasar harus menunjukkan titik spesifik yang direkomendasikan oleh TK-26. Ini adalah titik dasar yang ditentukan yang menentukan pasangan kunci mana yang akan dihasilkan. Jika Anda menentukan, misalnya, GOST2012-tc26-A atau GOST2012-tc26-B, maka pasangan kunci akan dihasilkan sesuai dengan GOST R 34.10-2012 dengan panjang kunci 512 bit. Alih-alih nama panggilan titik dasar, Anda dapat menentukan oid secara langsung:

 (genkey ( (curve «1.2.643.2.2.35.3»))) 

Dalam kasus terakhir, diasumsikan bahwa pasangan kunci akan dihasilkan sesuai dengan GOST R 34.10 dengan panjang kunci 256 bit dan titik dasar GOST2001-CryptoPro-C.

Di bawah ini adalah contoh program C yang menunjukkan generasi kunci

GenKey.c
 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> /*  S-*/ static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } int main(int argc, char* argv[]) { gpg_error_t err; gcry_sexp_t key_spec, key_pair, pub_key, sec_key; /* */ char *curve_gost[] = {"GOST2001-CryptoPro-A", "GOST2001-CryptoPro-B", "GOST2001-CryptoPro-C", "GOST2012-tc26-A", "GOST2012-tc26-B", NULL}; /*     */ err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecc (curve %s)))", curve_gost[1]); if (err) { fprintf(stderr, "creating S-expression failed: %s\n", gcry_strerror (err)); exit (1); } err = gcry_pk_genkey (&key_pair, key_spec); if (err){ fprintf(stderr, "creating %s key failed: %s\n", argv[1], gcry_strerror (err)); exit(1); } /* S-  */ show_sexp ("ECC GOST key pair:\n", key_pair); /*  */ pub_key = gcry_sexp_find_token (key_pair, "public-key", 0); if (! pub_key) { fprintf(stderr, "public part missing in key\n"); exit(1); } /* S-  */ show_sexp ("ECC GOST public key:\n", pub_key); /*  */ sec_key = gcry_sexp_find_token (key_pair, "private-key", 0); if (! sec_key){ fprintf(stderr, "private part missing in key\n"); exit(1); } /* S-  */ show_sexp ("ECC GOST private key:\n", sec_key); /* ,   */ gcry_sexp_release (key_pair); /* ,    */ gcry_sexp_release (key_spec); } 


Untuk menyiarkan contoh, Anda perlu menjalankan perintah:

 $cc –o GenKey GenKey.c –lgcrypt $ 

Setelah memulai modul GenKey, kita dapatkan

pasangan kunci
 ECC GOST key pair: (key-data (public-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) ) ) (private-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) (d #1ABB5A62BFF88C97567B467C6F4017242FE344B4F4BC8906CE40A0F9D51CBE48#) ) ) ) ECC GOST public key: (public-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) ) ) ECC GOST private key: (private-key (ecc (curve GOST2001-CryptoPro-B) (q #043484CF83F837AAC7ABD4707DE27F5A1F6161120C0D77B63DFFC7D50A7772A12D1E836E6257766E8B83209DD59845F8080BA29E9A86D0A6B6C2D68F44650B3A14#) (d #1ABB5A62BFF88C97567B467C6F4017242FE344B4F4BC8906CE40A0F9D51CBE48#) ) ) 

Sekarang, dengan memiliki kunci pribadi, Anda dapat membuat tanda tangan elektronik.

Hashing dokumen


Pembuatan tanda tangan elektronik (ES) dari suatu dokumen dimulai dengan memperoleh nilai hash dari dokumen yang ditandatangani. Untuk menandatangani dokumen, salah satu algoritme dapat dipilih:
- 1.2.643.2.2.3 (0x2a, 0x85, 0x03, 0x02, 0x02, 0x03) - algoritma tanda tangan GOST R 34.10-2001 dengan kunci 256 dengan hashing menurut GOST R 34.11-94 dengan panjang hash 256 bit;
- 1.2.643.7.1.1.3.2 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x03, 0x02) - algoritma tanda tangan GOST R 34.10-2012 dengan kunci 256 dengan hashing menurut GOST R 34.11-2012 dengan panjang hash 256 bit;
- 1.2.643.7.1.1.3.3 (0x2a, 0x85, 0x03, 0x07, 0x01, 0x03, 0x03) - algoritma tanda tangan GOST R 34.10-2012 dengan kunci 512 dengan hashing menurut GOST R 34.11-2012 dengan panjang hash 512 bit.
Algoritma ini menentukan tidak hanya jenis kunci pribadi yang akan digunakan untuk mendapatkan tanda tangan elektronik, tetapi juga algoritma fungsi hash. Pustaka GCrypt mengimplementasikan ketiga jenis fungsi. Algoritma hash GOST R 34.11-94 (dengan parameter oid 1.2.643.2.2.30.1 - 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x1e, 0x01) diimplementasikan dengan nama panggilan GOSTR3411_CP, algoritma GOST R 34.11-2012 dengan panjang 256 bit (oid 1.2.43.7.1.1.2.2 - 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02) diimplementasikan dengan nama julukan STRIBOG256 dan algoritma GOST R 34.11-2012 dengan panjang 512 bit (oid 1.2.43.7 .1.1.2.3 - 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x03) diimplementasikan dengan nama panggilan STRIBOG512.

Di bawah ini adalah kode modul dalam C untuk menghitung nilai hash dari dokumen yang disimpan dalam file

digest_gcrypt.c:
 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <gcrypt.h> int main(int argc, char* argv[]) { gpg_error_t err; int algo = GCRY_MD_NONE; int i; unsigned char *h; size_t size; gcry_md_hd_t hd; FILE *fp; unsigned char buf[1024]; char *dgst_gost[] = {"GOSTR3411_CP", "STRIBOG256", "STRIBOG512", NULL}; i = 0; /*  -*/ if (argc == 3) algo = gcry_md_map_name (argv[1]); if (algo == GCRY_MD_NONE) { fprintf(stderr, "Usage: digest_gcrypt <nick_name_digest> <file_for_digest>\n"); fprintf(stderr, "<nick_name_digest>="); while (dgst_gost[i] != NULL){ if (i > 0 ) fprintf(stderr, " | ", dgst_gost[i]); fprintf(stderr, "%s", dgst_gost[i]); i++; } fprintf(stderr, "\n"); exit (1); } /*   */ err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s\n", gcry_strerror (err)); exit (1); } /*  */ if (!strcmp (argv[2], "-")) fp = stdin; else fp = fopen (argv[2], "r"); if (fp == NULL) { fprintf(stderr, "Cannot fopen file=%s\n", argv[2]); exit(1); } /*   */ while (!feof (fp)) { size = fread (buf, 1, sizeof(buf), fp); gcry_md_write (hd, buf, size); } /*  */ h = gcry_md_read(hd, 0); /*  */ printf("  %s = %d ( )\n", argv[1], gcry_md_get_algo_dlen (algo)); printf("   %s:\n", argv[2]); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02x", h[i]); printf("\n"); fflush(stdout); /* */ gcry_md_reset(hd); gcry_md_close(hd); } 

Kami menerjemahkan modul ini dan mendapatkan utilitas perhitungan hash:

 $cc -o digest_file digest_file.c -lgcrypt $./digest_file Usage: digest_gcrypt <nick_name_digest> <file_for_digest> <nick_name_digest>=GOSTR3411_CP | STRIBOG256 | STRIBOG512 $./digest_file STRIBOG256 digest_file.c   STRIBOG256 = 32 ( )    digest_file.c: f6818dfb26073747266dc721c332d703eb21f2b17e3433c809e0e23b68443d4a $ 

Pembentukan tanda tangan elektronik dan verifikasi


Sekarang kami memiliki kunci pribadi dan hash dokumen, kami juga dapat membuat tanda tangan elektronik dokumen:

 gcry_error_t gcry_pk_sign (gcry sexp t *r_sig, gcry sexp t data, gcry sexp t skey ),  

r_sig -sexp-variable di mana tanda tangan elektronik akan disimpan,
skey - variabel sexp dengan kunci pribadi (lihat di atas), yang digunakan untuk menghasilkan tanda tangan,
data - sexp-variable, yang menunjukkan jenis tanda tangan (dalam kasus kami, gost) dan hash dari dokumen yang ditandatangani.
Harus diingat bahwa nilai hash yang diberikan ke input gcry_pk_sign untuk menghasilkan tanda tangan GOST R 34.10 harus dalam format big-endian, mis. sebenarnya terbalik (seperti yang dikatakan seorang teman: "Tradisi Rusia dalam memperlakukan byte yang dicerna dengan sedikit-endian"). Dengan mengingat hal ini, persiapan variabel seks datap adalah sebagai berikut:

 ... gcry_sexp_t data; unsigned char c; int len_xy; gcry_mpi_t x; … /*    */ printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); fflush(stdout); /*   mpi-*/ x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); /* sexp- data   –   */ err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); /*    data */ show_sexp ("data :\n", data); 
Semuanya siap untuk menerima tanda tangan dan melihatnya <source: lang = "cpp"> ...
gcry_sexp_t sig_r, sig_s;
...
/ * Tanda tangani hash * /
err = gcry_pk_sign (& sig, data, sec_key);
if (err) {
fprintf (stderr, "gagal masuk:% s \ n", gcry_strerror (err));
keluar (1);
}
/ * Kami mencetak tanda tangan * /
show_sexp ("ECC GOST SIG: \ n", sig);
/ * Pilih dan cetak komponen tanda tangan r dan s * /
sig_r = gcry_sexp_find_token (sig, "r", 0);
if (! sig_r) {
fprintf (stderr, "r bagian hilang dalam sig \ n");
keluar (1);
}
show_sexp ("ECC GOST Sig R-bagian: \ n", sig_r);
sig_s = gcry_sexp_find_token (sig, "s", 0);
if (! sig_s) {
fprintf (stderr, "bagian yang hilang di sig \ n");
keluar (1);
}
show_sexp ("ECC GOST Sig S-bagian: \ n", sig_s);
... Anda dapat memverifikasi tanda tangan sebagai berikut:
 … err = gcry_pk_verify (sig, data, pub_key); if (err) { putchar ('\n'); show_sexp ("seckey:\n", sec_key); show_sexp ("data:\n", data); show_sexp ("sig:\n", sig); fprintf(stderr, "verify failed: %s\n", gcry_strerror (err)); exit(1); } … 

Verifikasi tanda tangan elektronik GOST R 34.10 dalam sertifikat


Salah satu objek utama infrastruktur kunci publik (PKI) adalah sertifikat X509. Rekomendasi TC-26 tentang komposisi dan struktur sertifikat dinyatakan dalam dokumen “SPESIFIKASI TEKNIS MENGGUNAKAN GOST R 34.10, GOST R 34.11 ALGORITMA DALAM PROFIL SERTIFIKAT DAN TINJAUAN SERTIFIKAT CRL (CRL) DARI INFRASTRUKTUR TERBUKA KUNCI 9 X. Komite X. perlindungan informasi ”(Menit No. 13 dari 04.24.2014).” Sesuai dengan rekomendasi ini bahwa semua CA yang terakreditasi di Kementerian Komunikasi mengeluarkan sertifikat Rusia.

Untuk memverifikasi tanda tangan dalam sertifikat, perlu (lihat di atas) untuk mendapatkan hash dari sertifikat yang diverifikasi, tanda tangannya dan kunci publik dari sertifikat root. Perhatikan bahwa untuk sertifikat yang ditandatangani sendiri, semua data ini disimpan dalam satu sertifikat.
Untuk bekerja dengan objek PKI / PKI (sertifikat, CMS, permintaan
dll.), sebagai suatu peraturan, perpustakaan KSBA digunakan, yang saat ini tidak mendukung rekomendasi TK-26, walaupun ada pengalaman dukungan tersebut. Pada dasarnya, tidak ada yang mencegah menambahkan dukungan untuk rekomendasi TK-26 ke proyek ksba.
Pada tahap ini, pada tahap pengujian GCrypt, akan lebih mudah untuk menggunakan bahasa skrip seperti Python , Tcl, dll. Untuk bekerja dengan objek PKI / PKI (sertifikat, dll.) Dengan kriptografi Rusia. Bahasa scripting Tcl dipilih. Sangat mudah dan sederhana untuk menulis program prototipe di atasnya, yang kemudian dapat ditransfer ke bahasa C. Tcl termasuk paket PKI yang berisi prosedur untuk parsing objek PKI, khususnya, prosedur untuk parsing sertifikat :: pki :: x509 :: parse_cert. Berdasarkan prosedur parse_cert, prosedur parse_gost_cert dikembangkan, yang terletak di file

parse_cert_gost_oid.tcl
 proc parse_cert_gost {cert} { # parray ::pki::oids #puts "parse_cert_gost=$cert" set cert_seq "" if { [string range $cert 0 9 ] == "-----BEGIN" } { array set parsed_cert [::pki::_parse_pem $cert "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"] set cert_seq $parsed_cert(data) } else { #FORMAT DER set cert_seq $cert } set finger [::sha1::sha1 $cert_seq] set ret(fingerprint) $finger binary scan $cert_seq H* certdb set ret(certdb) $certdb #puts "CERTDB=$certdb" array set ret [list] # Decode X.509 certificate, which is an ASN.1 sequence ::asn::asnGetSequence cert_seq wholething ::asn::asnGetSequence wholething cert set ret(cert) $cert set ret(cert) [::asn::asnSequence $ret(cert)] if {0} { set ff [open "/tmp/tbs.der" w] fconfigure $ff -translation binary puts -nonewline $ff $ret(cert) close $ff } binary scan $ret(cert) H* ret(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) incr ret(version) } else { set ret(version) 1 } ::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 binary scan $pubkeyinfo H* pubkeyinfoG set ret(pubkeyinfo) $pubkeyinfoG ::asn::asnGetSequence pubkeyinfo pubkey_algoid binary scan $pubkey_algoid H* pubkey_algoidG set ret(pubkey_algoid) $pubkey_algoidG ::asn::asnGetObjectIdentifier pubkey_algoid ret(pubkey_algo) ::asn::asnGetBitString pubkeyinfo pubkey set extensions_list [list] while {$cert != ""} { ::asn::asnPeekByte cert peek_tag switch -- [format {0x%02x} $peek_tag] { "0xa1" { ::asn::asnGetContext cert - issuerUniqID } "0xa2" { ::asn::asnGetContext cert - subjectUniqID } "0xa3" { ::asn::asnGetContext cert - extensions_ctx ::asn::asnGetSequence extensions_ctx extensions while {$extensions != ""} { ::asn::asnGetSequence extensions extension ::asn::asnGetObjectIdentifier extension ext_oid ::asn::asnPeekByte extension peek_tag if {$peek_tag == 0x1} { ::asn::asnGetBoolean extension ext_critical } else { set ext_critical false } ::asn::asnGetOctetString extension ext_value_seq set ext_oid [::pki::_oid_number_to_name $ext_oid] set ext_value [list $ext_critical] switch -- $ext_oid { id-ce-basicConstraints { ::asn::asnGetSequence ext_value_seq ext_value_bin if {$ext_value_bin != ""} { ::asn::asnGetBoolean ext_value_bin allowCA } else { set allowCA "false" } if {$ext_value_bin != ""} { ::asn::asnGetInteger ext_value_bin caDepth } else { set caDepth -1 } lappend ext_value $allowCA $caDepth } default { binary scan $ext_value_seq H* ext_value_seq_hex lappend ext_value $ext_value_seq_hex } } lappend extensions_list $ext_oid $ext_value } } } } set ret(extensions) $extensions_list ::asn::asnGetSequence wholething signature_algo_seq ::asn::asnGetObjectIdentifier signature_algo_seq ret(signature_algo) ::asn::asnGetBitString wholething ret(signature) # Convert values from ASN.1 decoder to usable values if needed set ret(notBefore) [::pki::x509::_utctime_to_native $ret(notBefore)] set ret(notAfter) [::pki::x509::_utctime_to_native $ret(notAfter)] set ret(serial_number) [::math::bignum::tostr $ret(serial_number)] set ret(data_signature_algo) [::pki::_oid_number_to_name $ret(data_signature_algo)] set ret(signature_algo) [::pki::_oid_number_to_name $ret(signature_algo)] set ret(pubkey_algo) [::pki::_oid_number_to_name $ret(pubkey_algo)] set ret(issuer) [::pki::x509::_dn_to_string $issuer] set ret(subject) [::pki::x509::_dn_to_string $subject] set ret(signature) [binary format B* $ret(signature)] binary scan $ret(signature) H* ret(signature) # Handle RSA public keys by extracting N and E #puts "PUBKEY_ALGO=$ret(pubkey_algo)" 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 } "GostR2012_256" - "GostR2012_512" - "GostR2001" - "1.2.643.2.2.19" - "1.2.643.7.1.1.1.1" - "1.2.643.7.1.1.1.2" { # gost2001, gost2012-256,gost2012-512 set pubkey [binary format B* $pubkey] #puts "LL=[string length $pubkey]" if {[string length $pubkey] < 100} { set pubk [string range $pubkey 2 end] } else { set pubk [string range $pubkey 3 end] } set pubkey_revert [string reverse $pubk] binary scan $pubkey_revert H* ret(pubkey_rev) binary scan $pubkey H* ret(pubkey) set ret(type) gost ::asn::asnGetSequence pubkey_algoid pubalgost #OID -  ::asn::asnGetObjectIdentifier pubalgost ret(paramkey) set ret(paramkey) [::pki::_oid_number_to_name $ret(paramkey)] #OID -   ::asn::asnGetObjectIdentifier pubalgost ret(hashkey) set ret(hashkey) [::pki::_oid_number_to_name $ret(hashkey)] #puts "ret(paramkey)=$ret(paramkey)\n" #puts "ret(hashkey)=$ret(hashkey)\n" } } return [array get ret] } proc set_nick_for_oid {} { # set ::pki::oids(1.2.643.2.2.19) "gost2001pubKey" # set ::pki::oids(1.2.643.2.2.3) "gost2001withGOST3411_94" 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.3) "  34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) "  34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) "  34.10-2012-512" # set ::pki::oids(1.2.643.2.2.3) "gost" # set ::pki::oids(1.2.643.7.1.1.3.2) "gost" # set ::pki::oids(1.2.643.7.1.1.3.3) "gost" #  # set ::pki::oids(1.2.643.2.2.19) "  34.10-2001" # set ::pki::oids(1.2.643.7.1.1.1.1) "  34.10-2012 256 " # set ::pki::oids(1.2.643.7.1.1.1.2) "  34.10-2012 512 " set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid-     34.10-2001    34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" # { "GOST2001-CryptoPro-A", set ::pki::oids("GOST2001-CryptoPro-XchA" }, # { "GOST2001-CryptoPro-C", set ::pki::oids("GOST2001-CryptoPro-XchB" }, set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid-     34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick   set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" } 


Prosedur parse_gost_cert dirancang untuk mengurai sertifikat berdasarkan kriptografi Rusia.
File ini juga berisi prosedur untuk menetapkan nama panggilan ke oid-s dari kriptografi Rusia, dengan mempertimbangkan proyek GCrypt:
 proc set_nick_for_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.3) "  34.10-2001-256" set ::pki::oids(1.2.643.7.1.1.3.2) "  34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) "  34.10-2012-512" #  set ::pki::oids(1.2.643.2.2.19) "GostR2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GostR2012_256" set ::pki::oids(1.2.643.7.1.1.1.2) "GostR2012_512" #Oid-     34.10-2001    34.10-2012-256 set ::pki::oids(1.2.643.2.2.35.0) "GOST2001-test" set ::pki::oids(1.2.643.2.2.35.1) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.35.2) "GOST2001-CryptoPro-B" set ::pki::oids(1.2.643.2.2.35.3) "GOST2001-CryptoPro-C" set ::pki::oids(1.2.643.2.2.36.0) "GOST2001-CryptoPro-A" set ::pki::oids(1.2.643.2.2.36.1) "GOST2001-CryptoPro-C" #Oid-     34.10-2012-512 set ::pki::oids(1.2.643.7.1.2.1.2.1) "GOST2012-tc26-A" set ::pki::oids(1.2.643.7.1.2.1.2.2) "GOST2012-tc26-B" #Nick   set ::pki::oids(1.2.643.7.1.1.2.2) "STRIBOG256" set ::pki::oids(1.2.643.7.1.1.2.3) "STRIBOG512" set ::pki::oids(1.2.643.2.2.30.1) "GOSTR3411_CP" } 

Prosedur parse_gost_cert memungkinkan Anda untuk mendapatkan sertifikat TBS , tanda tangan sertifikat, jenis tanda tangan, kunci publik. Jika kami mempertimbangkan sertifikat yang ditandatangani sendiri, maka ini cukup untuk memverifikasi tanda tangan. Jika kami memverifikasi tanda tangan sertifikat yang ditandatangani (dikeluarkan) oleh sertifikat lain (penerbit dan subjek sertifikat tidak cocok), maka prosedur untuk mendapatkan informasi untuk memverifikasi tanda tangan adalah sebagai berikut:

- dari sertifikat yang diverifikasi kami mengekstrak sertifikat TBS, jenis tanda tangan dan tanda tangan itu sendiri;
- kami mengekstrak kunci publik dari sertifikat root.

Yang paling bertanggung jawab dalam menyiapkan data sumber untuk memverifikasi penandatanganan sertifikat adalah kepatuhan ketat terhadap rekomendasi TK-26. Untuk nilai kunci publik, mereka terdengar seperti ini:
Representasi kunci publik dari GostR3410-2012-256-PublicKey identik dengan representasi kunci publik dari GOST R 34.10-2001 [IETF RFC 4491], dan HARUS berisi 64 oktet, di mana 32 oktet pertama berisi koordinat x dalam tampilan little-endian dan 32 oktet berisi koordinat y dalam tampilan little-endian.

GostR3410-2012-512-PublicKey Public Key View HARUS berisi
128 oktet, di mana 64 oktet pertama berisi koordinat x dalam tampilan little-endian, dan 64 oktet kedua berisi koordinat y dalam tampilan little-endian.
Saat mengunggah tanda tangan, Anda harus dipandu oleh hal berikut:
Algoritma tanda tangan GOST R 34.10-2012 dengan panjang kode hash 256-bit digunakan untuk menghasilkan tanda tangan digital dalam bentuk dua angka 256-bit, r dan s. Representasinya dalam bentuk string oktet (OCTET STRING) identik dengan representasi tanda tangan GOST R 34.10-2001 [IETF RFC 4491] dan terdiri dari 64 oktet; 32 oktet pertama berisi angka s dalam representasi big-endian (oktet tertinggi ditulis pertama), dan 32 oktet kedua berisi angka r dalam representasi big-endian.

Algoritma tanda tangan GOST R 34.10-2012 dengan panjang kode hash 512 digunakan untuk menghasilkan tanda tangan digital dalam bentuk dua angka 512-bit, kunci publik sesuai dengan r dan s. Representasinya sebagai string oktet (OCTET STRING) terdiri dari 128 oktet; 64 oktet pertama berisi angka s dalam representasi big-endian (oktet tertinggi ditulis pertama), dan 64 oktet kedua berisi angka r dalam representasi big-endian.
Berdasarkan rekomendasi ini, modul Tcl parse_certs_for_verify_load.tcl menyiapkan data sumber untuk verifikasi penandatanganan sertifikat

terlihat seperti ini:
 #!/usr/bin/tclsh #  PKI package require pki #     -  source parse_cert_gost_oid.tcl if {$argc != 2} { puts "Usage: parse_certs_for_verify_load.tcl < > < >" exit 1 } #  if {[file exists "[lindex $argv 0]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts "  [lindex $argv 0]" exit 1 } #  if {[file exists "[lindex $argv 1]"] == 0 } { puts "Usage: parse_certs_for_verify_load.tcl < > < >" puts "  [lindex $argv 1]" exit 1 } # nick-  - oid- set_nick_for_oid set file [lindex $argv 0] set f [open $file r] set cert [read $f] close $f #READ DER-format if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } array set cert_user [parse_cert_gost $cert] #  -26 set len_sign [expr [string length $cert_user(signature)] /2] set sign_r [string range $cert_user(signature) $len_sign end] set sign_s [string range $cert_user(signature) 0 [expr $len_sign - 1]] #puts " : $file" set file [lindex $argv 1] set f [open $file r] set cert [read $f] close $f #READ DER if { [string range $cert 0 9 ] != "-----BEGIN" } { set fd [open $file] chan configure $fd -translation binary set cert [read $fd] close $fd } #     array set cert_ca [parse_cert_gost $cert] #  -26 set len_key [expr [string length $cert_ca(pubkey_rev)]/2] set key_pub_left [string range $cert_ca(pubkey_rev) $len_key end] set key_pub_right [string range $cert_ca(pubkey_rev) 0 [expr $len_key - 1]] puts "/* C-:      */" #TBS-  puts "char tbc\[\] = \"[string toupper $cert_user(cert)]\";" # - puts "char hash_type\[\] = \"$cert_ca(hashkey)\";" #    puts "unsigned char pub_key_ca\[\] = \"(public-key \"" puts "\"(ecc \"" puts "\" (curve $cert_ca(paramkey))\"" puts "\" (q #04[string toupper $key_pub_left$key_pub_right]#)\"" puts "\")\"" puts "\")\";" #   puts "unsigned char sig_cert\[\] = \"(sig-val\"" puts "\"($cert_ca(type) \"" puts "\" (r #[string toupper $sign_r]#)\"" puts "\" (s #[string toupper $sign_s]#)\"" puts "\")\"" puts "\")\";" puts "/*    TEST_from_TCL.h*/" puts "/*  TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt    TEST_from_Tcl*/" 


Untuk pengujian, kami mengambil dua sertifikat nyata:

sertifikat \ "UT 1 IS GUTs.pem \"
-----BEGIN CERTIFICATE-----
MIIGrDCCBlugAwIBAgILAOvBBVQAAAAAAFkwCAYGKoUDAgIDMIIBSjEeMBwGCSqG
SIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwT
Nzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMT8wPQYD
VQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g0KLQstC10YDRgdC6
0LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB0LLRj9C30Ywg0KDQ
vtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDExGjAYBggqhQMDgQMB
ARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy0L3QvtC5INGD0LTQ
vtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgDAeFw0xNjAzMTYxMjAy
NTFaFw0yNzA3MTIxMjAyNTFaMIIBITEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEeMBwGCSqGSIb3DQEJARYPZGl0
QG1pbnN2eWF6LnJ1MTwwOgYDVQQJDDMxMjUzNzUg0LMuINCc0L7RgdC60LLQsCDR
g9C7LiDQotCy0LXRgNGB0LrQsNGPINC0LjcxLDAqBgNVBAoMI9Cc0LjQvdC60L7Q
vNGB0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
HDAaBgNVBAgMEzc3INCzLiDQnNC+0YHQutCy0LAxCzAJBgNVBAYTAlJVMRswGQYD
VQQDDBLQo9CmIDEg0JjQoSDQk9Cj0KYwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAQYH
KoUDAgIeAQNDAARAx70Y7WYQ4ODtdiSSx3MJnr1GQBEIExiPO/LWj1TRKES1OcDI
YgtdOBGVYSvbsStl10jkAOG0OpnGsd2by4m+LaOCA0MwggM/MA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFBGIaV7vyOlz23pXNbzSAfMF/qfRMAsGA1UdDwQEAwIB
hjCCAYsGA1UdIwSCAYIwggF+gBSLmDuJGFHo75wCeLjqyNQgslXJXaGCAVKkggFO
MIIBSjEeMBwGCSqGSIb3DQEJARYPZGl0QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJS
VTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB
0LrQstCwMT8wPQYDVQQJDDYxMjUzNzUg0LMuINCc0L7RgdC60LLQsCwg0YPQuy4g
0KLQstC10YDRgdC60LDRjywg0LQuIDcxLDAqBgNVBAoMI9Cc0LjQvdC60L7QvNGB
0LLRj9C30Ywg0KDQvtGB0YHQuNC4MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDEx
GjAYBggqhQMDgQMBARIMMDA3NzEwNDc0Mzc1MUEwPwYDVQQDDDjQk9C+0LvQvtCy
0L3QvtC5INGD0LTQvtGB0YLQvtCy0LXRgNGP0Y7RidC40Lkg0YbQtdC90YLRgIIQ
NGgeQMtB7zOpoLfIdpKaKTBZBgNVHR8EUjBQMCagJKAihiBodHRwOi8vcm9zdGVs
ZWNvbS5ydS9jZHAvZ3VjLmNybDAmoCSgIoYgaHR0cDovL3JlZXN0ci1wa2kucnUv
Y2RwL2d1Yy5jcmwwJgYFKoUDZG8EHQwb0JrRgNC40L/RgtC+LdCf0YDQviBDU1Ag
My42MCUGA1UdIAQeMBwwCAYGKoUDZHEBMAgGBiqFA2RxAjAGBgRVHSAAMIHGBgUq
hQNkcASBvDCBuQwj0J/QkNCa0JwgwqvQmtGA0LjQv9GC0L7Qn9GA0L4gSFNNwrsM
INCf0JDQmiDCq9CT0L7Qu9C+0LLQvdC+0Lkg0KPQpsK7DDbQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzMvMi8yLTk5OSDQvtGCIDA1LjA3LjIwMTIMONCX0LDQ
utC70Y7Rh9C10L3QuNC1IOKEliAxNDkvNy8xLzQvMi02MDMg0L7RgiAwNi4wNy4y
MDEyMAgGBiqFAwICAwNBAKVYokUvb7XAMPJF38ZPKO2BFBldmGEfqsfmsiO35Y52
kTkx512H3YLqWMrOLjIfVMJhc+DTCNeXWY6bhK4/DRU=
-----END CERTIFICATE-----

dan sertifikat akarnya \ "SEC Minkomsvyaz.pem \":
-----BEGIN CERTIFICATE-----
MIIFGTCCBMigAwIBAgIQNGgeQMtB7zOpoLfIdpKaKTAIBgYqhQMCAgMwggFKMR4w
HAYJKoZIhvcNAQkBFg9kaXRAbWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYD
VQQIDBM3NyDQsy4g0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAx
PzA9BgNVBAkMNjEyNTM3NSDQsy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXR
gNGB0LrQsNGPLCDQtC4gNzEsMCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfR
jCDQoNC+0YHRgdC40LgxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqF
AwOBAwEBEgwwMDc3MTA0NzQzNzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg
0YPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMB4XDTEyMDcy
MDEyMzExNFoXDTI3MDcxNzEyMzExNFowggFKMR4wHAYJKoZIhvcNAQkBFg9kaXRA
bWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYDVQQIDBM3NyDQsy4g0JzQvtGB
0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAxPzA9BgNVBAkMNjEyNTM3NSDQ
sy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXRgNGB0LrQsNGPLCDQtC4gNzEs
MCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfRjCDQoNC+0YHRgdC40LgxGDAW
BgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqFAwOBAwEBEgwwMDc3MTA0NzQz
NzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg0YPQtNC+0YHRgtC+0LLQtdGA
0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqF
AwICHgEDQwAEQI+lv3kQI8jWka1kMVdbvpvFioP0Pyn3Knmp+2XD6KgPWnXEIlSR
X8g/IYracDr51YsNc2KE3C7mkH6hA3M3ofujggGCMIIBfjCBxgYFKoUDZHAEgbww
gbkMI9Cf0JDQmtCcIMKr0JrRgNC40L/RgtC+0J/RgNC+IEhTTcK7DCDQn9CQ0Jog
wqvQk9C+0LvQvtCy0L3QvtC5INCj0KbCuww20JfQsNC60LvRjtGH0LXQvdC40LUg
4oSWIDE0OS8zLzIvMi05OTkg0L7RgiAwNS4wNy4yMDEyDDjQl9Cw0LrQu9GO0YfQ
tdC90LjQtSDihJYgMTQ5LzcvMS80LzItNjAzINC+0YIgMDYuMDcuMjAxMjAuBgUq
hQNkbwQlDCPQn9CQ0JrQnCDCq9Ca0YDQuNC/0YLQvtCf0YDQviBIU03CuzBDBgNV
HSAEPDA6MAgGBiqFA2RxATAIBgYqhQNkcQIwCAYGKoUDZHEDMAgGBiqFA2RxBDAI
BgYqhQNkcQUwBgYEVR0gADAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUi5g7iRhR6O+cAni46sjUILJVyV0wCAYGKoUDAgIDA0EA23Re
ec/Y27rpMi+iFbgWCazGY3skBTq5ZGsQKOUxCe4mO7UBDACiWqdA0nvqiQMXeHgq
o//fO9pxuIHtymwyMg==
-----END CERTIFICATE-----

Kami akan menyiapkan data awal untuk memeriksa sertifikat "UT 1 IS GUTs.pem":

 $ ./parse_certs_for_verify_load.tcl " 1  .pem" " .pem" > TEST_from_TCL.h $echo "  TEST_from_TCL.h" $cat TEST_from_TCL.h /* C-:      */ char tbc[] = "3082065B . . . "; char hash_type[] = "GOSTR3411_CP"; unsigned char pub_key_ca[] = "(public-key " "(ecc " " (curve GOST2001-CryptoPro-A)" " (q #040FA8E8C365FBA9792AF7293FF4838AC59BBE5B573164AD91D6C8231079BFA58FFBA1377303A17E90E62EDC8462730D8BD5F93A70DA8A213FC85F915422C4755A#)" ")" ")"; unsigned char sig_cert[] = "(sig-val" "(gost " " (r #913931E75D87DD82EA58CACE2E321F54C26173E0D308D797598E9B84AE3F0D15#)" " (s #A558A2452F6FB5C030F245DFC64F28ED8114195D98611FAAC7E6B223B7E58E76#)" ")" ")"; /*    TEST_from_TCL.h*/ /*  TEST_from_Tcl.c: cc -o TEST_from_Tcl TEST_from_Tcl.c -lgcrypt    TEST_from_Tcl*/ $ 

Verifikasi penandatanganan sertifikat dilakukan oleh modul:

TEST_from_TCL.c
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <gcrypt.h> #include "TEST_from_TCL.h" #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define xmalloc(a) gcry_xmalloc ((a)) static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * hex2buffer (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) return NULL; /* Invalid hex digits. */ ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } int main(int argc, char* argv[]) { gpg_error_t err; int algo; gcry_md_hd_t hd; unsigned char *tbs_ptr; size_t len_tbs; int i; unsigned char *h; gcry_sexp_t pub_key; gcry_sexp_t data; gcry_sexp_t sig; gcry_mpi_t x; int len_xy; unsigned char c; /*   little-endian  big-endian*/ unsigned short arch = 1; /* 0x0001 */ tbs_ptr = hex2buffer(tbc, &len_tbs); if (tbs_ptr == NULL) { fprintf (stderr, "Bad tbs\n"); exit(1); } algo = gcry_md_map_name (hash_type); if (algo == GCRY_MD_NONE) { fprintf (stderr, "Unknown algorithm '%s'\n", hash_type); exit (1); } err = gcry_md_open(&hd, algo, 0); if (err) { fprintf (stderr, "LibGCrypt error %s/%s\n", gcry_strsource (err), gcry_strerror (err)); exit (1); } gcry_md_write (hd, tbs_ptr, len_tbs); h = gcry_md_read(hd, 0); // len_xy = gcry_md_get_algo_dlen (algo); /*    */ printf("%s\n", *((unsigned char *) &arch) == 0 ? " big-endian" : " little-endian"); len_xy = *((unsigned char *) &arch) == 0 ? 0:gcry_md_get_algo_dlen (algo); for (i = 0; i < (len_xy/2); i++) { c = *(h + i); *(h + i) = *(h + len_xy - i - 1); *(h + len_xy - i - 1) = c; } fprintf(stderr, " =%d\n", gcry_md_get_algo_dlen (algo)); for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) printf("%02X", h[i]); // printf("\n %s\n", tbc); fflush(stdout); /*  */ x = gcry_mpi_set_opaque_copy(NULL, h, gcry_md_get_algo_dlen (algo) * 8); /*  */ gcry_md_reset(hd); gcry_md_close(hd); /* */ err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); show_sexp ("ECC GOST data cert:\n", data); fprintf (stderr, "\nStep 1\n"); /*    */ err = gcry_sexp_sscan (&pub_key, NULL, pub_key_ca, strlen (pub_key_ca)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for pub_key_ca\n"); exit(1); } show_sexp ("ECC GOST public key:\n", pub_key); fprintf (stderr, "Step 2\n"); /*   */ err = gcry_sexp_sscan (&sig, NULL, sig_cert, strlen (sig_cert)); if (err){ fprintf(stderr, "TEST_SEXP: er gcry_sexp_sscan for sig_cert\n"); exit(1); } show_sexp ("ECC GOST sig cert:\n", sig); fprintf (stderr, "Step 3\n"); /*  */ err = gcry_pk_verify (sig, data, pub_key); if (err) { fprintf (stderr, "TEST_SEXP: verify cert failed\n"); exit (1); } fprintf (stderr, "TEST_SEXP: verify cert OK!!\n"); } 

Kami menerjemahkan dan menjalankan utilitas TEST_from_TCL:

 $cc –o TEST_from_TCL TEST_from_TCL.c –lgcrypt $./TEST_from_TCL  little-endian  =32 D485903E7E8D60820118329060C558B9C733D53CA608C0C79363ECE7B4C1F799ECC GOST data cert: (data (flags gost) (value #D485903E7E8D60820118329060C558B9C733D53CA608C0C79363ECE7B4C1F799#) ) Step 1 ECC GOST public key: (public-key (ecc (curve GOST2001-CryptoPro-A) (q #040FA8E8C365FBA9792AF7293FF4838AC59BBE5B573164AD91D6C8231079BFA58FFBA1377303A17E90E 62EDC8462730D8BD5F93A70DA8A213FC85F915422C4755A#) ) ) Step 2 ECC GOST sig cert: (sig-val (gost (r #913931E75D87DD82EA58CACE2E321F54C26173E0D308D797598E9B84AE3F0D15#) (s #A558A2452F6FB5C030F245DFC64F28ED8114195D98611FAAC7E6B223B7E58E76#) ) ) Step 3 TEST_SEXP: verify cert OK!! $ 

Seperti yang Anda lihat, verifikasi tanda tangan sertifikat "UT 1 IS GUTs.pem" berhasil. Masih memverifikasi sertifikat root itu sendiri "GUT Minkomsvyaz.pem." Sederhana, jalankan perintah:

 $ parse_certs_for_verify_load.tcl " .pem" " .pem" > TEST_from_TCL.h $  .. 

Jika ada yang ingin memeriksa sertifikat dengan kunci GOST lainnya (GOST R 34.10-2012-256 atau GOST R 34.10-2012-512), maka ia dapat menggunakan CAFL63 CA dan menyiapkan sertifikat apa pun:

gambar

Jadi, penelitian yang dilakukan menunjukkan bahwa perpustakaan GCrypt mungkin juga dulu bekerja dengan kriptografi Rusia. Prospek langsung terlihat dalam menyelesaikan perpustakaan KSBA dan memperluas paket pki dari bahasa scripting Tcl (atau mungkin Python) dengan dukungan untuk kriptografi Rusia.

Mereka yang ingin menggunakan pustaka GCrypt untuk enkripsi, saya sarankan lihat di sini .

Source: https://habr.com/ru/post/id414249/


All Articles