Cara mengkonfigurasi Linux untuk memasuki domain menggunakan algoritma GOST

Pendahuluan



Protokol Kerberos 5 sekarang aktif digunakan untuk otentikasi. Fitur protokol ini adalah protokol melakukan otentikasi berdasarkan empat pilar:


  1. Enkripsi simetris;
  2. Hashing
  3. EDS;
  4. Pihak Tepercaya Ketiga.

Dimulai dengan versi kelima, sekarang dimungkinkan untuk menggunakan enkripsi asimetris (untuk tanda tangan elektronik). Tidak masuk akal untuk memikirkan pengoperasian protokol Kerberos, karena deskripsi algoritme dapat ditemukan di sini .


Sayangnya, jumlah algoritma enkripsi, hashing dan tanda tangan digital yang digunakan protokol ini tidak sebesar yang saya inginkan, jadi dalam artikel ini saya ingin menunjukkan cara menambahkan mudah dan sederhana algoritma sendiri untuk implementasi protokol ini oleh MIT . Kami akan menambahkan algoritma domestik kami: GOST 28147-89 (alias Magma), GOST R 34.11-2012 (alias Stribog) dan GOST R 34.10-2012 (Saya juga ingin memiliki alias untuk itu, tetapi saya tidak tahu :(). Siap solusi untuk algoritma ini dapat ditemukan di repositori saya . Di sisi klien, kami akan menggunakan implementasi perangkat keras dari algoritma GOST di Rutoken EDS 2.0 dan implementasi perangkat lunak mereka dalam engine GOST untuk openssl. jangan tinggalkan ingatannya selama operasi kriptografi Untuk opsi ini, diperlukan mesin.


Sebelum mulai menerapkan algoritma, kami menjelaskan tempat-tempat utama di mana perubahan akan dilakukan. Di dalam direktori src / lib / crypto / adalah implementasi dari semua algoritma yang bertanggung jawab untuk kriptografi dan hashing simetris. Ini memiliki 2 implementasi dari algoritma kriptografi ini: builtin dan openssl. Untuk menghemat waktu dan ruang, kami, tentu saja, akan menambahkan implementasi algoritma menggunakan openssl, di mana mereka sudah ada (baik, atau hampir di sana, tetapi lebih lanjut tentang itu nanti). Untuk menambahkan algoritma asimetris, Anda perlu mengubah plugin src / plugins / preauth / pkinit


Jika Anda belum mengonfigurasi Kerberos, maka petunjuk untuk konfigurasi dan pengoperasian awalnya dapat ditemukan di sini . Selanjutnya, penulis mengasumsikan bahwa Anda bekerja dengan domain AKTIV-TEST.RU


Menambahkan Algoritma Hash dan Enkripsi Simetris


Seperti yang telah diumumkan sebelumnya, kami tidak akan menulis enkripsi dan hashing algoritma dari awal, tetapi akan menggunakan implementasi yang sudah jadi dari algoritma ini di openssl. Secara langsung, openssl tidak mendukung implementasi algoritma dalam negeri, tetapi memiliki mobilitas dalam hal ini dan memungkinkan Anda untuk menambahkan algoritma baru menggunakan mekanisme GOST mesin untuk bekerja dengan kunci dalam sistem file dan disimpan pada token - rtengine.


Pengantar kecil ke engine engine openssl dan menghubungkan engine GOST


Engine in openssl adalah pustaka dinamis kecil yang memuat loadsl ke runtime sesuai permintaan. Setiap perpustakaan harus mengandung simbol (fungsi) tertentu untuk memuat algoritma yang diperlukan. Dalam tulisan ini, kami akan menggunakan engine gost, yang berisi semua algoritma kriptografi domestik yang diperlukan.


Instalasi sangat sederhana, misalnya, dan hasil sebagai berikut:


  1. Unduh implementasi mesin ini dari repositori .


  2. membangun perpustakaan dengan itu (mkdir build && cd build && cmake ... && make):


    mkdir build cd build cmake .. make 

  3. Dalam direktori bin (YANG AKAN MUNCUL DALAM KATALOG ROOT PROYEK !!!) akan ada pustaka dinamis gost.so - ini adalah mesin kami. Ini harus dipindahkan ke direktori tempat mesin openssl disimpan. Cari tahu lokasi direktori ini menggunakan:


     openssl version -a | grep ENGINESDIR 

  4. Terserah yang terakhir - Anda perlu memberi tahu openssl di mana mesin yang diberikan dan apa namanya. Anda dapat melakukan ini dengan mengubah file konfigurasi openssl.cnf. Lokasi yang dapat ditemukan menggunakan:


     openssl version -a | grep OPENSSLDIR 

    Di akhir file ini Anda perlu menambahkan konten berikut:


     #     openssl_conf = openssl_def ... #    # OpenSSL default section [openssl_def] engines = engine_section # Engine section [engine_section] gost = gost_section # Engine gost section [gost_section] engine_id = gost dynamic_path = /path/to/engines/dir/with/gost.so default_algorithms = ALL init = 0 


Setelah itu, mesin ini akan muncul di openssl. Anda dapat memeriksa kinerjanya dengan memaksa, misalnya, untuk membuat kunci pribadi dalam file sesuai dengan GOST R 34.10-2012:


 openssl genpkey -engine gost -algorithm gost2012_512 -pkeyopt paramset:A -out client_key.pem 

Bendera-engine hanya menunjukkan mesin mana yang perlu dimuat sebelum mulai bekerja sehingga algoritma pembuatan kunci untuk GOST R 34.10-2012 menjadi terlihat.


Implementasi algoritma hash


Mari kita mulai dengan yang paling sederhana - dengan penerapan algoritma Stribog. Kerberos memiliki koneksi yang kuat antara hashing dan algoritma enkripsi, yaitu, Anda tidak bisa hanya memilih dan memilih satu algoritma untuk enkripsi, dan untuk hashing yang lain, Anda perlu mengintegrasikan algoritma hash dan enkripsi. Alasan untuk ini tidak diketahui oleh saya, tetapi karena aturan seperti itu ada di sana - mari kita coba untuk membuat kombinasi dari algoritma Stribog dan AES.


  1. Karena kita perlu kepercayaan pada koneksi di tempat yang berbeda dari program kita, pertama mari kita buat pustaka gost_helper kecil yang akan berisi fungsi inisialisasi mesin di openssl, serta beberapa fungsi yang mengembalikan konteks dari beberapa algoritma hashing untuk kenyamanan - ini akan membantu kita di masa depan. Kami menamai pustaka ini gost_helper dan membuat file sumber dan header yang sesuai untuknya di direktori src / lib / crypto / openssl / :


     // gost_helper.h #include <openssl/evp.h> //    GOST void krb5int_init_gost(); //  ,     const EVP_MD * EVP_gostR3411_2012_256(); const EVP_MD * EVP_gostR3411_2012_512(); // gost_helper.c #include "gost_helper.h" #include <openssl/engine.h> //     static ENGINE *eng = NULL; void krb5int_init_gost() { //    ,      if (eng) return; OPENSSL_add_all_algorithms_conf(); ERR_load_crypto_strings(); if (!(eng = ENGINE_by_id("gost"))) { printf("Engine gost doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); } const EVP_MD * EVP_gostR3411_2012_256() { krb5int_init_gost(); return EVP_get_digestbynid(NID_id_GostR3411_2012_256); } const EVP_MD * EVP_gostR3411_2012_512() { krb5int_init_gost(); return EVP_get_digestbynid(NID_id_GostR3411_2012_512); } 

  2. Setelah menambahkan perpustakaan tambahan, Anda harus mendeklarasikan keberadaannya di Makefile dan menulis dependensi file-nya. Untuk melakukan ini, tambahkan berikut ini:


     #    src/lib/crypto/openssl/Makefile.in      : STLIBOBJS=\ hmac.o \ ... stubs.o \ gost_helper.o OBJS=\ $(OUTPRE)hmac.$(OBJEXT) \ ... $(OUTPRE)stubs.$(OBJEXT) \ $(OUTPRE)gost_helper$(OBJEXT) SRCS=\ $(srcdir)/hmac.c \ ... $(srcdir)/stubs.c \ $(srcdir)/gost_helper.c #    src/lib/crypto/openssl/deps ,         : gost_helper.so gost_helper.po $(OUTPRE)gost_helper.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ gost_helper.c gost_helper.h 

  3. Perlu dicatat bahwa di masa mendatang, saat menghubungkan pustaka ini, kita perlu menambahkan dependensi beberapa file pada header pustaka ini. Ini dilakukan dengan sangat sederhana - tujuannya ditemukan, di mana Anda perlu menambahkan dependensi pada file deps dan ketergantungan pada rel / path / ke / gost_helper.h direkam . Sebagai contoh, di src / lib / crypto / openssl / hash_provider / deps Anda perlu menambahkan yang berikut:


     hash_evp.so hash_evp.po $(OUTPRE)hash_evp.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ ... $(srcdir)/../gost_helper.h hash_evp.c 

    Untuk menghemat ruang dalam artikel dan untuk meregangkan otak Anda, saya tidak akan lagi memperhatikannya: hati-hati dan hati-hati!


  4. Sekarang tambahkan implementasi fungsi hash, semua implementasinya ada di src / lib / crypto / openssl / hash_provider / hash_evp.c . Di sana Anda perlu menambahkan yang berikut:


     //     deps !!!          #include "crypto_int.h" #include "gost_helper.h" #include <openssl/evp.h> ... static krb5_error_code hash_sha384(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_sha384(), data, num_data, output); } static krb5_error_code hash_stribog256(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_gostR3411_2012_256(), data, num_data, output); } static krb5_error_code hash_stribog512(const krb5_crypto_iov *data, size_t num_data, krb5_data *output) { return hash_evp(EVP_gostR3411_2012_512(), data, num_data, output); } //    /*   --    --      --        --     */ const struct krb5_hash_provider krb5int_hash_sha384 = { "SHA-384", 48, 128, hash_sha384 }; const struct krb5_hash_provider krb5int_hash_stribog256 = { "GOSTR34.11-2012-256", 32, 64, hash_stribog256 }; const struct krb5_hash_provider krb5int_hash_stribog512 = { "GOSTR34.11-2012-512", 64, 64, hash_stribog512 }; 

  5. Sekarang kita perlu mendeklarasikan konteks ini di seluruh perpustakaan. Untuk melakukan ini, buat deskripsi mereka di file src / lib / crypto / krb / crypto_int.h .


     //  ,    ,        ,     krb5_hash_provider   -     : ... struct krb5_hash_provider { char hash_name[32]; //  8 size_t hashsize, blocksize; krb5_error_code (*hash)(const krb5_crypto_iov *data, size_t num_data, krb5_data *output); }; ... extern const struct krb5_hash_provider krb5int_hash_sha384; extern const struct krb5_hash_provider krb5int_hash_stribog256; extern const struct krb5_hash_provider krb5int_hash_stribog512; ... 

  6. Kami akan mendeklarasikan pengidentifikasi bundel Stribog dan AES, memperkenalkan makro yang akan kami sebut CKSUMTYPE_STRIBOG_256_AES256 , CKSUMTYPE_STRIBOG_512_AES256 , ENCTYPE_AES256_CTS_STRIBOG_256 , ENCTYPE_TRS Mereka harus dideklarasikan dalam template file header src / include / krb5 / krb5.hin . Akan terlihat seperti ini:


     #define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018 /**< RFC 4757 */ #define ENCTYPE_CAMELLIA128_CTS_CMAC 0x0019 /**< RFC 6803 */ #define ENCTYPE_CAMELLIA256_CTS_CMAC 0x001a /**< RFC 6803 */ #define ENCTYPE_AES256_CTS_STRIBOG_256 0x001b /**< NO RFC */ #define ENCTYPE_AES256_CTS_STRIBOG_512 0x001c /**< NO RFC */ #define ENCTYPE_UNKNOWN 0x01ff ... #define CKSUMTYPE_CMAC_CAMELLIA256 0x0012 /**< RFC 6803 */ #define CKSUMTYPE_MD5_HMAC_ARCFOUR -137 /* Microsoft netlogon */ #define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /**< RFC 4757 */ #define CKSUMTYPE_STRIBOG_256_AES256 -139 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_512_AES256 -140 /**< NO RFC */ 

  7. Sekarang Anda perlu menambahkan dua bundel fungsi hashing dan enkripsi dan fungsi enkripsi dan hashing. Mengapa dua, jika mereka setara, Anda bertanya? Jawaban: Saya tidak tahu, atau apakah itu penopang sejarah atau cara optimasi. Namun demikian, mari kita tambahkan struktur baru ke file yang diperlukan:


     //   src/lib/crypto/krb/cksumtypes.c          /*   --   --     --       --    --       --       --    "  "   --     --     --   */ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = { ... { CKSUMTYPE_STRIBOG_256_AES256, "stribog-256-aes256", { 0 }, "STRIBOG256 AES256 key", &krb5int_enc_aes256, &krb5int_hash_stribog256, krb5int_etm_checksum, NULL, 64, 32, 0 }, { CKSUMTYPE_STRIBOG_512_AES256, "stribog-512-aes256", { 0 }, "STRIBOG512 AES256 key", &krb5int_enc_aes256, &krb5int_hash_stribog512, krb5int_etm_checksum, NULL, 64, 64, 0 }, }; //   src/lib/crypto/krb/etypes.c         : /*   --   --   --   --   --      --      --           --   ,     --    ,       --    ,       --         --        --    --   */ const struct krb5_keytypes krb5int_enctypes_list[] = { ... { ENCTYPE_AES256_CTS_STRIBOG_256, "aes256-cts-stribog-256", { "aes256-stribog256" }, "AES-256 CTS mode with 256-bit stribog", &krb5int_enc_aes256, &krb5int_hash_stribog256, 16, krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt, krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_STRIBOG_256_AES256, 0 /*flags*/, 256 }, { ENCTYPE_AES256_CTS_STRIBOG_512, "aes256-cts-stribog-512", { "aes256-stribog512" }, "AES-256 CTS mode with 512-bit stribog", &krb5int_enc_aes256, &krb5int_hash_stribog512, 16, krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt, krb5int_aes2_string_to_key, k5_rand2key_direct, krb5int_aes2_prf, CKSUMTYPE_STRIBOG_512_AES256, 0 /*flags*/, 256 }, }; 

  8. Tampaknya hanya itu, tetapi tidak! Lalu ada masalah yang akan terlihat hanya selama proses debugging, beberapa dari mereka bisa dihindari dengan menunjukkan, misalnya, pointer fungsi lain dalam struktur di atas, tetapi kita akan pergi dengan cara yang lebih rumit untuk menunjukkan apa lagi yang harus diperbaiki di sepanjang jalan. Saya belajar tentang semua masalah ini hanya menggunakan debugger:


     //   src/lib/crypto/openssl/hmac.c    map_digest --    -   .         .  : #include "crypto_int.h" #include "gost_helper.h" #include <openssl/hmac.h> #include <openssl/evp.h> static const EVP_MD * map_digest(const struct krb5_hash_provider *hash) { if (!strncmp(hash->hash_name, "SHA1",4)) return EVP_sha1(); ... else if (!strncmp(hash->hash_name, "GOSTR34.11-2012-256", 19)) return EVP_gostR3411_2012_256(); else if (!strncmp(hash->hash_name, "GOSTR34.11-2012-512", 19)) return EVP_gostR3411_2012_512(); else return NULL; } //   src/lib/crypto/openssl/pbkdf2.c  krb5int_pbkdf2_hmac,        : krb5_error_code krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash, const krb5_data *out, unsigned long count, const krb5_data *pass, const krb5_data *salt) { const EVP_MD *md = NULL; /* Get the message digest handle corresponding to the hash. */ if (hash == &krb5int_hash_sha1) md = EVP_sha1(); ... else if (hash == &krb5int_hash_stribog256) md = EVP_gostR3411_2012_256(); else if (hash == &krb5int_hash_stribog512) md = EVP_gostR3411_2012_512(); ... return 0; } //   src/lib/krb5/krb/init_ctx.c      ,   : static krb5_enctype default_enctype_list[] = { ... ENCTYPE_AES256_CTS_STRIBOG_256, ENCTYPE_AES256_CTS_STRIBOG_512, 0 }; 


Setelah semua perubahan ini, Anda dapat memeriksa operasi algoritme. Kami akan mengumpulkan semua yang telah kami lakukan.


 autoconf ./configure --with-crypto-impl=openssl #     openssl make sudo make install 

Sekarang mari kita mulai memeriksa. Untuk melakukan ini, mari kita gunakan algoritma yang telah kita terapkan secara paksa ke dalam file konfigurasi Kerberos. Lakukan hal berikut:


  1. Hentikan krb5kdc:


     service krb5-kdc stop 

  2. Kami akan memperbaiki file konfigurasi kdc.conf (saya punya /usr/local/var/krb5kdc/kdc.conf untuk saya). Setel hashing paksa menggunakan algoritma yang baru diperkenalkan:


     [realms] AKTIV-TEST.RU = { master_key_type = aes256-stribog512 supported_enctypes = aes256-stribog512:normal default_tgs_enctypes = aes256-stribog512 default_tkt_enctypes = aes256-stribog512 permitted_enctypes = aes256-stribog512 } #       256  

  3. Perubahan serupa dalam file konfigurasi dari seluruh protokol krb5.conf (saya memilikinya di /etc/krb5.conf):


     [libdefaults] supported_enctypes = aes256-stribog512:normal default_tgs_enctypes = aes256-stribog512 default_tkt_enctypes = aes256-stribog512 permitted_enctypes = aes256-stribog512 #      256  

  4. Selanjutnya, jalankan krb5kdc sejak Jika perubahan master_key, Anda mungkin harus membuat basis data kepala sekolah lagi menggunakan krb5_newrealm.


  5. Setelah itu, kami membuat semua kepala sekolah yang diperlukan dan Anda dapat mulai bekerja. Coba otentikasi dengan kinit.


  6. Kami akan memverifikasi bahwa hashing terjadi sesuai dengan algoritma yang ditentukan.
    menggunakan klist -e.



Jika layanan tidak dimulai, maka itu dapat dimulai dari bawah root menggunakan src / kdc / krb5kdc . Jika semuanya dimulai, itu berjalan dengan lancar - selamat! Kalau tidak - sayangnya, saya tidak menawarkan obat mujarab untuk semua masalah, tetapi hanya menawarkan instruksi "kecil" yang berisi langkah-langkah dasar yang harus Anda ambil untuk mengimplementasikan algoritma baru di Kerberos. Dan jika tidak ada yang berhasil untuk Anda - ambil gdb dan lihat di mana masalahnya. Saya hanya bisa memberi Anda beberapa tips:


  1. Anda dapat membangun proyek dalam mode debug jika Anda meneruskannya ke ./configure CFLAGS = "-g -O0";
  2. krb5kdc dapat diluncurkan di latar belakang menggunakan flag -n;
  3. Saya harap ini tidak terjadi (walaupun saya masih datang dengan penerapan algoritma asimetris) - Anda mungkin memerlukan simbol debugging openssl - baik menginstalnya dari repositori atau menginstal openssl dari sumber dengan simbol debugging;
  4. hal yang sama berlaku untuk mesin gost.

Gagasan dari serangkaian tips ini harus cukup bagi Anda untuk menyelamatkan diri dari membuang waktu mencari "yang tidak diketahui".


Implementasi dari algoritma enkripsi


Di bagian ini saya akan menunjukkan bagaimana Anda dapat menambahkan algoritma enkripsi data Anda sendiri di Kerberos, dan kami akan mencoba membuat sekelompok Magma dan Stribog, ditambahkan di bagian terakhir. Di sini saya sudah berasumsi bahwa pustaka gost_helper kecil telah ditambahkan di bagian terakhir. Nah, rentangkan jari Anda dan lanjutkan:


  1. Pertama, kami menggambarkan algoritma di libk5crypto perpustakaan kami dengan menjelaskannya di file header src / lib / crypto / krb / crypto_int.h .


     ... extern const struct krb5_enc_provider krb5int_enc_camellia256; extern const struct krb5_enc_provider krb5int_enc_gost89; ... 

  2. Dalam direktori src / lib / crypto / openssl / enc_provider tambahkan sumber gost.c, yang berisi implementasi semua algoritma yang diperlukan (saya mengambil sumber dari algoritma des sebagai basis). Penting untuk dicatat bahwa kami hanya menerapkan mode enkripsi cbc, jadi untuk pengujian sendiri Anda dapat mengambil mode enkripsi lain dan menambahkannya:


     #include "crypto_int.h" #include "gost_helper.h" #include <openssl/evp.h> #define BLOCK_SIZE 8 static krb5_error_code krb5int_gost_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { int ret, olen = BLOCK_SIZE; unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE]; struct iov_cursor cursor; EVP_CIPHER_CTX *ctx; //          ,   krb5int_gost_encrypt,    : krb5int_init_gost(); ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; ret = EVP_EncryptInit_ex(ctx, EVP_get_cipherbynid(NID_gost89_cbc), NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL); if (!ret) { EVP_CIPHER_CTX_free(ctx); return KRB5_CRYPTO_INTERNAL; } EVP_CIPHER_CTX_set_padding(ctx,0); k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); while (k5_iov_cursor_get(&cursor, iblock)) { ret = EVP_EncryptUpdate(ctx, oblock, &olen, iblock, BLOCK_SIZE); if (!ret) break; k5_iov_cursor_put(&cursor, oblock); } if (ivec != NULL) memcpy(ivec->data, oblock, BLOCK_SIZE); EVP_CIPHER_CTX_free(ctx); zap(iblock, sizeof(iblock)); zap(oblock, sizeof(oblock)); if (ret != 1) return KRB5_CRYPTO_INTERNAL; return 0; } static krb5_error_code krb5int_gost_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { int ret, olen = BLOCK_SIZE; unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE]; struct iov_cursor cursor; EVP_CIPHER_CTX *ctx; krb5int_init_gost(); ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return ENOMEM; ret = EVP_DecryptInit_ex(ctx, EVP_get_cipherbynid(NID_gost89_cbc), NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL); if (!ret) { EVP_CIPHER_CTX_free(ctx); return KRB5_CRYPTO_INTERNAL; } EVP_CIPHER_CTX_set_padding(ctx,0); k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); while (k5_iov_cursor_get(&cursor, iblock)) { ret = EVP_DecryptUpdate(ctx, oblock, &olen, (unsigned char *)iblock, BLOCK_SIZE); if (!ret) break; k5_iov_cursor_put(&cursor, oblock); } if (ivec != NULL) memcpy(ivec->data, iblock, BLOCK_SIZE); EVP_CIPHER_CTX_free(ctx); zap(iblock, sizeof(iblock)); zap(oblock, sizeof(oblock)); if (ret != 1) return KRB5_CRYPTO_INTERNAL; return 0; } static krb5_error_code krb5int_gost_init_state (const krb5_keyblock *key, krb5_keyusage usage, krb5_data *state) { state->length = 8; state->data = (void *) malloc(8); if (state->data == NULL) return ENOMEM; memset(state->data, 0, state->length); return 0; } static void krb5int_gost_free_state(krb5_data *state) { free(state->data); *state = empty_data(); } /*   --  ,    -- -       --        --      --      --    cbc-mac checksum,      , ..       --       --         */ const struct krb5_enc_provider krb5int_enc_gost89 = { BLOCK_SIZE, 32, 32, krb5int_gost_encrypt, krb5int_gost_decrypt, NULL, krb5int_gost_init_state, krb5int_gost_free_state }; 

  3. Dalam templat src / lib / crypto / openssl / enc_provider / Makefile.in, kami menunjukkan bahwa sumber baru telah muncul:


     STLIBOBJS= \ des.o \ ... gost.o OBJS= \ $(OUTPRE)des.$(OBJEXT) \ ... $(OUTPRE)gost$(OBJEXT) SRCS= \ $(srcdir)/des.c \ ... $(srcdir)/gost.c 

  4. Jangan lupa menentukan dependensi di src / lib / crypto / openssl / enc_provider / deps :


     gost.so gost.po $(OUTPRE)gost.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \ $(srcdir)/../crypto_mod.h $(top_srcdir)/include/k5-buf.h \ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h $(srcdir)/../gost_helper.h gost.c 

  5. Tambahkan pengidentifikasi bundel ke src / include / krb5 / krb5.hin :


     ... #define ENCTYPE_AES256_CTS_STRIBOG_256 0x001b /**< NO RFC */ #define ENCTYPE_AES256_CTS_STRIBOG_512 0x001c /**< NO RFC */ #define ENCTYPE_GOST89_CBC_STRIBOG_256 0x001d /**< SOME GOST */ #define ENCTYPE_GOST89_CBC_STRIBOG_512 0x001e /**< SOME GOST */ #define ENCTYPE_UNKNOWN 0x01ff ... #define CKSUMTYPE_STRIBOG_256_AES256 -139 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_512_AES256 -140 /**< NO RFC */ #define CKSUMTYPE_STRIBOG_256_GOST89 -141 /**< SOME GOST */ #define CKSUMTYPE_STRIBOG_512_GOST89 -142 /**< SOME GOST */ 

  6. Mari kita jelaskan struktur bundel fungsi hash dan enkripsi, seperti pada bagian terakhir:


     // src/lib/crypto/krb/cksumtypes.c const struct krb5_cksumtypes krb5int_cksumtypes_list[] = { ... { CKSUMTYPE_STRIBOG_256_GOST89, "stribog-256-gost89", { 0 }, "STRIBOG256 GOST89 key", &krb5int_enc_gost89, &krb5int_hash_stribog256, krb5int_dk_checksum, NULL, 64, 32, 0 }, { CKSUMTYPE_STRIBOG_512_GOST89, "stribog-512-gost89", { 0 }, "STRIBOG512 GOST89 key", &krb5int_enc_gost89, &krb5int_hash_stribog512, krb5int_dk_checksum, NULL, 64, 64, 0 }, }; // src/lib/crypto/krb/etypes.c //       ,         , ,      aes const struct krb5_keytypes krb5int_enctypes_list[] = { ... { ENCTYPE_GOST89_CBC_STRIBOG_256, "gost89-cbc-stribog-256", { "gost89-stribog256" }, "GOST 28147-89 CBC mode with 256-bit stribog", &krb5int_enc_gost89, &krb5int_hash_stribog256, 16, krb5int_dk_crypto_length, krb5int_dk_encrypt, krb5int_dk_decrypt, krb5int_dk_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_STRIBOG_256_GOST89, 0 /*flags*/, 256 }, { ENCTYPE_GOST89_CBC_STRIBOG_512, "gost89-cbc-stribog-512", { "gost89-stribog512" }, "GOST 28147-89 CBC mode with 512-bit stribog", &krb5int_enc_gost89, &krb5int_hash_stribog512, 16, krb5int_dk_crypto_length, krb5int_dk_encrypt, krb5int_dk_decrypt, krb5int_dk_string_to_key, k5_rand2key_direct, krb5int_dk_prf, CKSUMTYPE_STRIBOG_512_GOST89, 0 /*flags*/, 256 }, }; 

  7. Tambahkan ke daftar mode enkripsi default di file src / lib / krb5 / krb / init_ctx.c :


     static krb5_enctype default_enctype_list[] = { ... ENCTYPE_AES256_CTS_STRIBOG_256, ENCTYPE_AES256_CTS_STRIBOG_512, ENCTYPE_GOST89_CBC_STRIBOG_256, ENCTYPE_GOST89_CBC_STRIBOG_512, 0 }; 


Setelah manipulasi ini, Anda dapat mencoba menguji algoritma yang baru diperkenalkan. Pengujian dilakukan dengan cara yang sama seperti pada bagian terakhir . Nama bundel dapat diambil sebagai alias (misalnya, gost89-stribog512) atau menggunakan nama algoritma itu sendiri (misalnya, gost89-cbc-stribog-512). Saya berharap semuanya bekerja, jika tidak jangan lupa tentang apa yang saya katakan sebelumnya .


Menambahkan Algoritma Tanda Tangan Digital


Hore! Kami melanjutkan ke bagian akhir artikel ini dan mencoba menambahkan algoritma tanda tangan elektronik kami sendiri. Jangan takut, menambahkan itu lebih mudah daripada yang lain, jadi mari kita mulai sesegera mungkin ... Meskipun tidak, tunggu sedikit komentar untuk memulai.


Enkripsi asimetris adalah hal yang cukup berat. – : , - . ...


, . , , . . . . , . , . , , β€” . .

Sesuatu seperti itu. , , . : . , , , , , .


openssl ( )


, -, openssl rtengine. GOST, , .


  1. SDK rutoken sdk/openssl/rtengine/bin/ engine.


  2. librtpkcs11ecp.so.


  3. master OpenSC 8cf1e6f


  4. , openssl.cnf:


     #     openssl_conf = openssl_def ... #    # OpenSSL default section [openssl_def] engines = engine_section # Engine section [engine_section] gost = gost_section rtengine = rtengine_section # Engine gost section [gost_section] engine_id = gost dynamic_path = /usr/lib/x86_64-linux-gnu/engines-1.1/gost.so default_algorithms = ALL # Engine rtengine section [rtengine_section] engine_id = rtengine dynamic_path = /path/to/engine/librtengine.so MODULE_PATH = /path/to/module/librtpkcs11ecp.so RAND_TOKEN = pkcs11:manufacturer=Aktiv%20Co.;model=Rutoken%20ECP default_algorithms = CIPHERS, DIGEST, PKEY, RAND 


engine .


, KDC


kerberos . , .


  1. , , , KDC:


     openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:B -out CA_key.pem #    openssl req -engine gost -key CA_key.pem -new -x509 -out CA_cert.pem #    openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:B -out KDC_key.pem #   KDC openssl req -engine gost -new -out KDC.req -key ./KDC_key.pem #      KDC # !!!     pkinit_extensions    REALM=AKTIV-TEST.RU; export REALM #   KDC CLIENT=127.0.0.1; export CLIENT #   ,     (    KDC).    ,   localhost openssl x509 -engine gost -req -in ./KDC.req -CAkey ./CA_key.pem -CA ./CA_cert.pem -out ./KDC.pem -extfile ./pkinit_extensions -extensions kdc_cert -CAcreateserial #    KDC. sudo cp ./KDC.pem ./KDC_key.pem ./CA_cert.pem /var/lib/krb5kdc #        kdc. 

  2. kdc, , :


     [kdcdefaults] ... pkinit_identity = FILE:/var/lib/krb5kdc/KDC.pem,/var/lib/krb5kdc/KDC_key.pem pkinit_anchors = FILE:/var/lib/krb5kdc/CA_cert.pem 


[libdefaults]
spake_preauth_groups = edwards25519


 3.      : ```bash sudo kadmin.local kadmin.local$: modprinc +requires_preauth user 

  1. . , , : :


    1. , KDC:


       openssl genpkey -engine gost -algorithm gost2012_256 -pkeyopt paramset:B -out client_key.pem #    openssl req -engine gost -new -out client.req -key ./client_key.pem #       

    2. :


       pkcs11-tool --module /path/to/module/librtpkcs11ecp.so --keypairgen --key-type GOSTR3410-2012-256:B -l --id 45 #             id=45 openssl req -engine rtengine -new -key="pkcs11:id=E" -keyform engine -out client.req #         . E -- ascii  45 


  2. :


     REALM=AKTIV-TEST.RU; export REALM #   CLIENT=user; export CLIENT #  ,     openssl x509 -engine gost -CAkey ./CA_key.pem -CA ./CA_cert.pem -req -in ./client.req -extensions client_cert -extfile ./pkinit_extensions -out client.pem openssl x509 -engine gost -in client.pem -out client.crt -outform DER #     PEM   CRT 

  3. : , – :


     sudo cp ./client_key.pem client.pem /etc/krb5 #   pkcs11-tool --module /usr/lib/librtpkcs11ecp.so -l -y cert -w ./client.crt --id 45 #   (     id,   ) 

  4. ( /etc/krb5.conf):


     [libdefaults] ... pkinit_anchors = FILE:/var/lib/krb5kdc/CA_cert.pem #     pkinit_identities = FILE:/etc/krb5/client.pem,/etc/krb5/client_key.pem #     #pkinit_identities = PKCS11:/usr/lib/librtpkcs11ecp.so 


, . ! .



, – - 2 ! src/plugins/preauth/pkinit/pkcs11.h src/plugins/preauth/pkinit/pkinit_crypto_openssl.c


  1. pkcs11.h . – , , . ( ). sdk/pkcs11/include/rtpkcs11t.h . :


     ... #define CKK_TWOFISH (0x21) #define CKK_GOSTR3410 (0x30) #define CKK_GOSTR3411 (0x31) #define CKK_GOST28147 (0x32) #define CKK_VENDOR_DEFINED (1UL << 31) // A mask for new GOST algorithms. // For details visit https://tc26.ru/standarts/perevody/guidelines-the-pkcs-11-extensions-for-implementing-the-gost-r-34-10-2012-and-gost-r-34-11-2012-russian-standards-.html #define NSSCK_VENDOR_PKCS11_RU_TEAM (CKK_VENDOR_DEFINED | 0x54321000) #define CK_VENDOR_PKCS11_RU_TEAM_TK26 NSSCK_VENDOR_PKCS11_RU_TEAM #define CKK_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x003) ... #define CKM_AES_MAC_GENERAL (0x1084) #define CKM_AES_CBC_PAD (0x1085) #define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL) #define CKM_GOSTR3410 (0x1201UL) #define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL) #define CKM_GOSTR3410_KEY_WRAP (0x1203UL) #define CKM_GOSTR3410_DERIVE (0x1204UL) #define CKM_GOSTR3410_512_KEY_PAIR_GEN (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x005) #define CKM_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x006) #define CKM_GOSTR3410_12_DERIVE (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x007) #define CKM_GOSTR3410_WITH_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x008) #define CKM_GOSTR3410_WITH_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x009) #define CKM_GOSTR3411 (0x1210UL) #define CKM_GOSTR3411_HMAC (0x1211UL) #define CKM_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x012) #define CKM_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x013) #define CKM_GOSTR3411_12_256_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x014) #define CKM_GOSTR3411_12_512_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x015) #define CKM_GOST28147_KEY_GEN (0x1220UL) #define CKM_GOST28147_ECB (0x1221UL) #define CKM_GOST28147 (0x1222UL) #define CKM_GOST28147_MAC (0x1223UL) #define CKM_GOST28147_KEY_WRAP (0x1224UL) 

    , .


  2. pkinit_crypto_openssl.c , , . get_key, .. - :


     #include <dirent.h> #include <arpa/inet.h> #include <openssl/engine.h> static ENGINE *eng = NULL; krb5int_init_engines() { if (eng) return; OPENSSL_add_all_algorithms_conf(); ERR_load_crypto_strings(); if (!(eng = ENGINE_by_id("rtengine"))) { printf("Engine rtengine doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); if (!(eng = ENGINE_by_id("gost"))) { printf("Engine gost doesn't exist"); return; } ENGINE_init(eng); ENGINE_set_default(eng, ENGINE_METHOD_ALL); } ... get_key(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, char *filename, const char *fsname, EVP_PKEY **retkey, const char *password) { ... krb5_error_code retval; krb5int_init_engines(); ... } ... int pkinit_openssl_init() { /* Initialize OpenSSL. */ ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); krb5int_init_engines(); return 0; } 

  3. . – RSA , sha1. , . , , . , .. RSA :


     //       krb5_error_code pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx, CK_ATTRIBUTE_TYPE usage, CK_OBJECT_HANDLE *objp) { ... true_false = TRUE; attrs[nattrs].type = usage; attrs[nattrs].pValue = &true_false; attrs[nattrs].ulValueLen = sizeof true_false; nattrs++; #endif // keytype = CKK_RSA; // attrs[nattrs].type = CKA_KEY_TYPE; // attrs[nattrs].pValue = &keytype; // attrs[nattrs].ulValueLen = sizeof keytype; // nattrs++; ... } //             : static int ckk_key_to_nid(CK_KEY_TYPE type) { switch(type){ case CKK_GOSTR3410: return NID_id_GostR3410_2012_256; case CKK_GOSTR3410_512: return NID_id_GostR3410_2012_512; default: return NID_rsa; } } // ,     ,     : static int pkinit_get_pkey_type(krb5_context context, pkinit_identity_crypto_context id_cryptoctx) { CK_OBJECT_HANDLE obj; CK_ATTRIBUTE attrs[1]; CK_KEY_TYPE key_type; int r; //  : if (pkinit_open_session(context, id_cryptoctx)) { pkiDebug("can't open pkcs11 session\n"); return NID_rsa; } //   : if (pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj)) { return NID_rsa; } //   : attrs[0].type = CKA_KEY_TYPE; attrs[0].pValue = &key_type; attrs[0].ulValueLen = sizeof (key_type); if ((r = id_cryptoctx->p11->C_GetAttributeValue(id_cryptoctx->session, obj, attrs, 1)) != CKR_OK) { pkiDebug("C_GetAttributeValue: %s\n Used RSA\n", pkinit_pkcs11_code_to_text(r)); return NID_rsa; } //   : return ckk_key_to_nid(key_type); } // ,        ,     : static int pkey_to_digest_nid(const EVP_PKEY* const pkey) { switch (EVP_PKEY_id(pkey)) { case NID_id_GostR3410_2012_256: return NID_id_GostR3411_2012_256; case NID_id_GostR3410_2012_512: return NID_id_GostR3411_2012_512; case NID_id_GostR3410_2001: return NID_id_GostR3411_2012_256; default: return NID_sha1; } } // ,       : static int get_digest_nid(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; //    (   ),   NID ,    if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return NID_id_GostR3411_2012_256; case NID_id_GostR3410_2012_512: return NID_id_GostR3411_2012_512; case NID_id_GostR3410_2001: return NID_id_GostR3411_2012_256; default: return NID_sha1; } } // ,     : static int get_alg_nid(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return NID_id_tc26_signwithdigest_gost3410_2012_256; case NID_id_GostR3410_2012_512: return NID_id_tc26_signwithdigest_gost3410_2012_512; case NID_id_GostR3410_2001: return NID_id_tc26_signwithdigest_gost3410_2012_256; default: return NID_sha1WithRSAEncryption; } } //    : static CK_MECHANISM_TYPE get_mech_type(krb5_context context, const pkinit_identity_crypto_context id_cryptctx) { int nid; if (id_cryptctx->my_key) { nid = EVP_PKEY_id(id_cryptctx->my_key); } else { nid = pkinit_get_pkey_type(context, id_cryptctx); } switch (nid) { case NID_id_GostR3410_2012_256: return CKM_GOSTR3410_WITH_GOSTR3411_12_256; case NID_id_GostR3410_2012_512: return CKM_GOSTR3410_WITH_GOSTR3411_12_512; case NID_id_GostR3410_2001: return CKM_GOSTR3410_WITH_GOSTR3411_12_256; default: return CKM_RSA_PKCS; } } 

  4. cms_signeddata_create create_signature :


     krb5_error_code cms_signeddata_create(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, pkinit_req_crypto_context req_cryptoctx, pkinit_identity_crypto_context id_cryptoctx, int cms_msg_type, int include_certchain, unsigned char *data, unsigned int data_len, unsigned char **signed_data, unsigned int *signed_data_len) { ... /* Set digest algs */ p7si->digest_alg->algorithm = OBJ_nid2obj( get_digest_nid(context, id_cryptoctx)); ... p7si->digest_enc_alg->algorithm = OBJ_nid2obj(get_alg_nid(context, id_cryptoctx)); ... EVP_DigestInit_ex(ctx, EVP_get_digestbynid(get_digest_nid(context, id_cryptoctx)), NULL); ... alen = (unsigned int )ASN1_item_i2d((ASN1_VALUE *) sk, &abuf, ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); ... //   ,      (    ): if (id_cryptoctx->pkcs11_method == 1 && get_digest_nid(context, id_cryptoctx) == NID_sha1) { } static krb5_error_code create_signature(unsigned char **sig, unsigned int *sig_len, unsigned char *data, unsigned int data_len, EVP_PKEY *pkey) { ... EVP_SignInit(ctx, EVP_get_digestbynid(pkey_to_digest_nid(pkey))); ... } //       : static krb5_error_code pkinit_sign_data_pkcs11(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, unsigned char *data, unsigned int data_len, unsigned char **sig, unsigned int *sig_len) { ... mech.mechanism = get_mech_type(context, id_cryptoctx); mech.pParameter = NULL; mech.ulParameterLen = 0; ... } 


, ( , , ):


 sudo kinit user 

user, , .


, .

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


All Articles