Menghubungkan OpenSSL ke Mono

Dalam artikel sebelumnya, proses mengintegrasikan sertifikat GOST CryptoPro dengan mono dijelaskan. Dalam hal yang sama, kami berkutat menghubungkan sertifikat RSA.


Kami terus mem-port salah satu sistem server kami yang ditulis dalam C # ke Linux, dan antrian mencapai bagian terkait RSA. Jika terakhir kali kesulitan dalam menghubungkan dengan mudah dijelaskan oleh interaksi dua sistem yang awalnya tidak terhubung satu sama lain, maka ketika menghubungkan sertifikat RSA "biasa" dari mono, tidak ada yang mengharapkan tangkapan.



Memasang sertifikat dan kunci tidak menyebabkan masalah, dan sistem bahkan melihatnya dalam penyimpanan standar. Namun, itu tidak lagi mungkin untuk menandatangani, mengenkripsi, atau mengekstrak data dari tanda tangan yang dihasilkan sebelumnya - mono jatuh secara stabil dengan kesalahan. Saya harus, seperti dalam kasus CryptoPro, terhubung langsung ke perpustakaan enkripsi. Untuk sertifikat RSA di Linux, kandidat utama untuk koneksi semacam itu adalah OpenSSL.


Instalasi Sertifikat


Untungnya, Centos 7 memiliki versi bawaan OpenSSL - 1.0.2k. Agar tidak memperkenalkan kesulitan tambahan ke dalam sistem, kami memutuskan untuk terhubung ke versi ini. OpenSSL memungkinkan Anda membuat toko sertifikat file khusus, namun:


  1. toko semacam itu mengandung sertifikat dan CRL, bukan kunci pribadi, jadi dalam hal ini mereka harus disimpan secara terpisah;
  2. menyimpan sertifikat dan kunci pribadi di Windows pada disk dalam bentuk tidak aman adalah "sangat tidak aman" (mereka yang bertanggung jawab untuk keamanan digital biasanya menggambarkannya lebih luas dan lebih sedikit sensor), jujur ​​saja, ini tidak terlalu aman di Linux, tetapi, pada kenyataannya, umum latihan;
  3. mengoordinasi lokasi repositori semacam itu di Windows dan Linux cukup bermasalah;
  4. dalam hal implementasi penyimpanan secara manual, sebuah utilitas akan diperlukan untuk mengelola set sertifikat;
  5. mono sendiri menggunakan penyimpanan disk dengan struktur OpenSSL, dan juga menyimpan kunci pribadi dalam bentuk terbuka di dekatnya;

Untuk alasan ini, kami akan menggunakan toko .Net dan mono sertifikat standar untuk menghubungkan OpenSSL. Untuk melakukan ini, di Linux, sertifikat dan kunci pribadi pertama-tama harus ditempatkan di repositori mono.

Instalasi Sertifikat
Kami akan menggunakan utilitas certmgr standar untuk ini. Pertama, instal kunci pribadi dari pfx:

certmgr -importKey -c -p {password} My {pfx file}

Kemudian kami menempatkan sertifikat dari pfx ini, kunci pribadi akan terhubung secara otomatis:

certmgr -add -c My {cer file}

Jika Anda ingin menginstal kunci di penyimpanan untuk mesin, Anda harus menambahkan opsi -m.

Setelah itu sertifikat dapat dilihat di repositori:

certmgr -list -c -v My

Perhatikan penerbitannya. Perlu dicatat bahwa sertifikat terlihat oleh sistem, dan terkait dengan kunci pribadi yang diunduh sebelumnya. Setelah itu, Anda dapat melanjutkan ke koneksi dalam kode.

Koneksi dalam kode


Sama seperti terakhir kali, sistem, meskipun porting ke Linux, seharusnya terus berfungsi di lingkungan Windows. Oleh karena itu, secara lahiriah, bekerja dengan kriptografi harus dilakukan melalui metode umum dari bentuk "byte [] SignData (byte [] _arData, X509Certificate2 _pCert)", yang harus bekerja sama di Linux dan Windows.


Idealnya, harus ada metode yang bekerja seperti di Windows - terlepas dari jenis sertifikat (di Linux melalui OpenSSL atau CryptoPro tergantung pada sertifikat, dan pada Windows melalui crypt32).


Analisis perpustakaan OpenSSL menunjukkan bahwa di Windows perpustakaan utama adalah "libeay32.dll", dan di Linux "libcrypto.so.10". Seperti yang terakhir kali, kami membentuk dua kelas WOpenSSLAPI dan LOpenSSLAPI, yang berisi daftar metode pustaka perpustakaan:

 [DllImport(CTRYPTLIB, CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.Cdecl)] internal static extern void OPENSSL_init(); 

Perhatikan konvensi pemanggilan, tidak seperti CryptoPro - ini harus secara eksplisit ditentukan. Sintaks untuk menghubungkan masing-masing metode kali ini harus dihasilkan secara independen berdasarkan file sumber * .h OpenSSL.


Aturan dasar untuk menghasilkan sintaks panggilan dalam C # berdasarkan data dari file .h adalah sebagai berikut:


  1. semua tautan ke struktur, string, dll. - IntPtr, termasuk tautan di dalam struktur itu sendiri;
  2. tautan ke tautan - ref IntPtr, jika opsi ini tidak berfungsi, maka cukup IntPtr. Dalam hal ini, tautan itu sendiri harus diletakkan dan dihapus secara manual;
  3. array - byte [];
  4. long in C (OpenSSL) adalah int di C # (kesalahan kecil, sekilas, dapat berubah menjadi jam mencari sumber kesalahan yang tidak dapat diprediksi);

Dalam deklarasi, karena kebiasaan, Anda dapat menentukan SetLastError = true, tetapi perpustakaan akan mengabaikan ini - kesalahan tidak akan tersedia melalui Marshal.GetLastWin32Error (). OpenSSL memiliki metode sendiri untuk mengakses kesalahan.


Dan kemudian kita membentuk kelas statis yang sudah akrab "UOpenSSLAPI" yang, tergantung pada sistem, akan memanggil metode salah satu dari dua kelas:


 private static object fpOSSection = new object(); /**<summary>  OpenSSL</summary>**/ public static void OPENSSL_init() { lock (pOSSection) { if (fIsLinux) LOpenSSLAPI.OPENSSL_init(); else WOpenSSLAPI.OPENSSL_init(); } } /**<summary>    OpenSSL</summary>**/ public static object pOSSection { get { return fpOSSection; } } /**<summary>  </summary>**/ public static bool fIsLinux { get { int iPlatform = (int) Environment.OSVersion.Platform; return (iPlatform == 4) || (iPlatform == 6) || (iPlatform == 128); } } 

Kami segera mencatat keberadaan bagian yang kritis. OpenSSL secara teoritis menyediakan pekerjaan di lingkungan multi-threaded. Tapi, pertama, segera dalam deskripsi dikatakan bahwa ini tidak dijamin:


Tetapi Anda masih tidak bisa secara bersamaan menggunakan sebagian besar objek di banyak utas.

Dan kedua, metode koneksi bukan yang paling sepele. VM dua-inti yang biasa (server dengan prosesor Intel Xeon E5649 dalam mode Hyper-Threading) saat menggunakan bagian kritis tersebut memberikan sekitar 100 siklus penuh (lihat algoritma pengujian dari artikel sebelumnya) atau 600 tanda tangan per detik, yang pada dasarnya cukup untuk sebagian besar tugas ( di bawah beban berat, arsitektur microservice atau nodal dari sistem akan tetap digunakan).


Menginisialisasi dan menurunkan OpenSSL


Tidak seperti CryptoPro OpenSSL membutuhkan tindakan tertentu sebelum Anda mulai menggunakannya dan setelah Anda selesai bekerja dengan perpustakaan:

 /**<summary> OpenSSL</summary>**/ public static void InitOpenSSL() { UOpenSSLAPI.OPENSSL_init(); UOpenSSLAPI.ERR_load_crypto_strings(); UOpenSSLAPI.ERR_load_RSA_strings(); UOpenSSLAPI.OPENSSL_add_all_algorithms_conf(); UOpenSSLAPI.OpenSSL_add_all_ciphers(); UOpenSSLAPI.OpenSSL_add_all_digests(); } /**<summary> OpenSSL</summary>**/ public static void CleanupOpenSSL() { UOpenSSLAPI.EVP_cleanup(); UOpenSSLAPI.CRYPTO_cleanup_all_ex_data(); UOpenSSLAPI.ERR_free_strings(); } 


Informasi Kesalahan


OpenSSL menyimpan informasi kesalahan dalam struktur internal yang ada metode khusus di perpustakaan. Sayangnya, beberapa metode sederhana, seperti ERR_error_string, tidak stabil, jadi Anda harus menggunakan metode yang lebih kompleks:


Mendapatkan Informasi Kesalahan
 /**<summary>    OpenSSL</summary> * <param name="_iErr"> </param> * <param name="_iPart"></param> * <returns> </returns> * **/ public static string GetErrStrPart(ulong _iErr, int _iPart) { // 0)    IntPtr hErrStr = IntPtr.Zero; switch (_iPart) { case 0: hErrStr = UOpenSSLAPI.ERR_lib_error_string(_iErr); break; case 1: hErrStr = UOpenSSLAPI.ERR_func_error_string(_iErr); break; case 2: hErrStr = UOpenSSLAPI.ERR_reason_error_string(_iErr); break; } // 1)   return PtrToFirstStr(hErrStr); } /**<summary>    OpenSSL</summary> * <param name="_iErr"> </param> * <returns> </returns> * **/ public static string GetErrStr(ulong _iErr ) { return UCConsts.S_GEN_LIB_ERR_MAKRO.Frm(_iErr, GetErrStrPart(_iErr, 0), GetErrStrPart(_iErr, 1), GetErrStrPart(_iErr, 2)); } /**<summary>    OpenSSL</summary> * <returns> </returns> * **/ public static string GetErrStrOS() { return GetErrStr(UOpenSSLAPI.ERR_get_error()); } 

Kesalahan dalam OpenSSL berisi informasi tentang perpustakaan tempat itu terjadi, metode dan alasannya. Oleh karena itu, setelah menerima kode kesalahan itu sendiri, perlu untuk mengekstrak ketiga bagian ini secara terpisah dan menyatukannya dalam satu baris teks. Panjang setiap baris, menurut dokumentasi OpenSSL , tidak melebihi 120 karakter, dan karena kami menggunakan kode terkelola, kami harus hati-hati mengekstrak baris dari tautan:


Mendapatkan string oleh IntPtr
 /**<summary>    PChar     _iLen</summary> * <param name="_hPtr">    </param> * <param name="_iLen">  </param> * <returns> </returns> * **/ public static string PtrToFirstStr(IntPtr _hPtr, int _iLen = 256) { if(_hPtr == IntPtr.Zero) return ""; try { byte[] arStr = new byte[_iLen]; Marshal.Copy(_hPtr, arStr, 0, arStr.Length); string[] arRes = Encoding.ASCII.GetString(arStr).Split(new char[] { (char)0 }, StringSplitOptions.RemoveEmptyEntries); if (arRes.Length > 0) return arRes[0]; return ""; }catch { return ""; } } 

Kesalahan saat memeriksa sertifikat tidak termasuk dalam daftar umum, dan itu harus diekstraksi dengan metode terpisah, sesuai dengan konteks verifikasi:


Terima kesalahan verifikasi sertifikat
 /**<summary>   </summary> * <param name="_hStoreCtx"> </param> * <returns> </returns> * **/ public static string GetCertVerifyErr(IntPtr _hStoreCtx) { int iErr = UOpenSSLAPI.X509_STORE_CTX_get_error(_hStoreCtx); return PtrToFirstStr(UOpenSSLAPI.X509_verify_cert_error_string(iErr)); } 

Pencarian Sertifikat


Seperti biasa, kriptografi dimulai dengan pencarian sertifikat. Kami menggunakan penyimpanan penuh waktu, jadi kami akan mencari menggunakan metode biasa:


Pencarian Sertifikat
 /**<summary>  (   )</summary> * <param name="_pFindType"> </param> * <param name="_pFindValue"> </param> * <param name="_pLocation"> </param> * <param name="_pName"> </param> * <param name="_pCert"> </param> * <param name="_sError">   </param> * <param name="_fVerify"> </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int FindCertificateOS(string _pFindValue, out X509Certificate2 _pCert, ref string _sError, StoreLocation _pLocation = StoreLocation.CurrentUser, StoreName _pName = StoreName.My, X509FindType _pFindType = X509FindType.FindByThumbprint, bool _fVerify = false) { lock (UOpenSSLAPI.pOSSection) { // 0)    _pCert = null; X509Store pStore = new X509Store(_pName, _pLocation); X509Certificate2Collection pCerts = null; try { // 1)   pStore.Open(OpenFlags.ReadOnly); // 2)    ( , .. Verify  Linux  false) pCerts = pStore.Certificates.Find(_pFindType, _pFindValue, false); if (pCerts.Count == 0) return UConsts.E_NO_CERTIFICATE; // 3)     if (!_fVerify) { _pCert = ISDP_X509Cert.Create(pCerts[0], TCryptoPath.cpOpenSSL); return UConsts.S_OK; } // 4)       foreach (X509Certificate2 pCert in pCerts) { ISDP_X509Cert pISDPCert = ISDP_X509Cert.Create(pCert, TCryptoPath.cpOpenSSL); if (pISDPCert.ISDPVerify()) { _pCert = pISDPCert; return UConsts.S_OK; } } return UConsts.E_NO_CERTIFICATE; } finally { if(pCerts != null) pCerts.Clear(); pStore.Close(); } } } 

Perhatikan bagian penting. Mono dengan sertifikat juga berfungsi melalui OpenSSL, tetapi tidak melalui UOpenSSLAPI. Jika Anda tidak melakukannya di sini, Anda bisa mendapatkan kebocoran memori dan kesalahan mengambang yang tidak dapat dipahami sedang dimuat.


Fitur utama adalah pembuatan sertifikat. Berbeda dengan versi untuk CryptoPro, dalam hal ini kami mendapatkan sertifikat itu sendiri (X509Certificate2) dari toko, dan tautan di Handle di dalamnya sudah diarahkan ke struktur OpenSSL X509_st. Tampaknya perlu, tetapi tidak ada pointer ke EVP_PKEY (tautan ke struktur kunci privat di OpenSSL) dalam sertifikat.

Kunci pribadi itu sendiri, ternyata, disimpan di tempat kosong di bidang internal sertifikat - impl / fallback / _cert / _rsa / rsa. Ini adalah kelas RSAManaged, dan melihat sekilas kodenya (misalnya, metode DecryptValue ) menunjukkan betapa buruknya mono dengan kriptografi. Alih-alih jujur ​​menggunakan teknik kriptografi OpenSSL, mereka tampaknya telah menerapkan beberapa algoritma secara manual. Asumsi ini didukung oleh hasil pencarian kosong untuk proyek mereka untuk metode OpenSSL seperti CMS_final, CMS_sign atau CMS_ContentInfo_new. Dan tanpa mereka, sulit untuk membayangkan pembentukan struktur tanda tangan CMS standar. Pada saat yang sama, bekerja dengan sertifikat sebagian dilakukan melalui OpenSSL.


Ini berarti bahwa kunci pribadi harus diturunkan dari mono dan dimuat ke EVP_PKEY melalui pem. Karena itu, kita perlu lagi pewaris kelas dari X509Certificate, yang akan menyimpan semua tautan tambahan.


Berikut ini hanya upaya, seperti dalam kasus CryptoPro untuk membuat sertifikat baru dari Handle - juga tidak mengarah pada kesuksesan (mono crash dengan kesalahan), dan membuat berdasarkan sertifikat yang diterima menyebabkan kebocoran memori. Oleh karena itu, satu-satunya pilihan adalah membuat sertifikat berdasarkan array byte yang berisi pem. Sertifikat PEM dapat diperoleh sebagai berikut:


Memperoleh sertifikat PEM
 /**<summary>  </summary> * <param name="_pCert"></param> * <param name="_arData">  </param> * <param name="_fBase64"> Base64</param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ public static int ToCerFile(this X509Certificate2 _pCert, out byte[] _arData, ref string _sError, bool _fBase64 = true) { _arData = new byte[0]; try { byte[] arData = _pCert.Export(X509ContentType.Cert); // 0) DER if (!_fBase64) { _arData = arData; return UConsts.S_OK; } // 1) Base64 using (TextWriter pWriter = new StringWriter()) { pWriter.WriteLine(UCConsts.S_PEM_BEGIN_CERT); pWriter.WriteLine(Convert.ToBase64String(arData, Base64FormattingOptions.InsertLineBreaks)); pWriter.WriteLine(UCConsts.S_PEM_END_CERT); // 1.2)   _arData = Encoding.UTF8.GetBytes(pWriter.ToString()); } return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_TO_PEM_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } } 

Sertifikat diperoleh tanpa kunci pribadi dan kami menghubungkannya sendiri, membentuk bidang terpisah untuk tautan ke ENV_PKEY:


Menghasilkan ENV_PKEY Berdasarkan PEM Private Key
 /**<summary> OpenSSL    (EVP_PKEY)    </summary> * <remarks>      PEM</remarks> * <param name="_arData">   </param> * <returns>   (EVP_PKEY)</returns> * **/ internal static IntPtr GetENV_PKEYOS(byte[] _arData) { IntPtr hBIOPem = IntPtr.Zero; try { // 0)   BIO hBIOPem = UOpenSSLAPI.BIO_new_mem_buf( _arData, _arData.Length); if (hBIOPem == IntPtr.Zero) return IntPtr.Zero; IntPtr hKey = IntPtr.Zero; // 1)     UOpenSSLAPI.PEM_read_bio_PrivateKey(hBIOPem, ref hKey, IntPtr.Zero, 0); return hKey; } finally { if(hBIOPem != IntPtr.Zero) UOpenSSLAPI.BIO_free(hBIOPem); } } 

Mengunggah kunci pribadi di PEM, tugasnya jauh lebih rumit daripada sertifikat PEM, tetapi sudah dijelaskan di sini . Perhatikan bahwa membongkar kunci pribadi adalah bisnis yang "sangat tidak aman", dan ini harus dihindari dalam segala hal. Dan karena pembongkaran seperti itu diperlukan untuk bekerja dengan OpenSSL, di Windows lebih baik menggunakan metode crypt32.dll atau kelas .Net biasa saat menggunakan perpustakaan ini. Di Linux, untuk saat ini, Anda harus bekerja seperti ini.


Perlu juga diingat bahwa tautan yang dibuat menunjukkan area memori yang tidak dikelola dan harus dibebaskan. Karena di .Net 4.5 X509Certificate2 bukan Disposable, maka Anda perlu melakukan ini di destructor


Menandatangani


Untuk menandatangani OpenSSL, Anda dapat menggunakan metode CMS_sign yang disederhanakan, namun, itu bergantung pada file konfigurasi dalam memilih algoritma, yang akan sama untuk semua sertifikat. Oleh karena itu, lebih baik mengandalkan kode metode ini untuk mengimplementasikan generasi tanda tangan serupa:


Tanda tangan data
 /**<summary>  </summary> * <param name="_arData">  </param> * <param name="_pCert"></param> * <param name="_sError">   </param> * <param name="_arRes"> </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int SignDataOS(byte[] _arData, X509Certificate2 _pCert, out byte[] _arRes, ref string _sError) { _arRes = new byte[0]; uint iFlags = UCConsts.CMS_DETACHED; IntPtr hData = IntPtr.Zero; IntPtr hBIORes = IntPtr.Zero; IntPtr hCMS = IntPtr.Zero; try { // 0)   ISDP_X509Cert pCert = ISDP_X509Cert.Convert(_pCert, TCryptoPath.cpOpenSSL); // 1)  BIO   int iRes = GetBIOByBytesOS(_arData, out hData, ref _sError); if (iRes != UConsts.S_OK) return iRes; // 2)   BIO hBIORes = UOpenSSLAPI.BIO_new(UOpenSSLAPI.BIO_s_mem()); // 3)    hCMS = UOpenSSLAPI.CMS_ContentInfo_new(); if (hCMS == IntPtr.Zero) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_CR_ERR); if (!UOpenSSLAPI.CMS_SignedData_init(hCMS)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_INIT_ERR); // 4)   if(UOpenSSLAPI.CMS_add1_signer(hCMS, pCert.hRealHandle, pCert.hOSKey, pCert.hOSDigestAlg, iFlags) == IntPtr.Zero) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_SET_SIGNER_ERR); // 5)   -   if (!UOpenSSLAPI.CMS_set_detached(hCMS, 1)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_SET_DET_ERR); // 6)    if (!UOpenSSLAPI.CMS_final(hCMS, hData, IntPtr.Zero, iFlags)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_FINAL_ERR); // 7)    BIO if (!UOpenSSLAPI.i2d_CMS_bio_stream(hBIORes, hCMS, IntPtr.Zero, iFlags)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_EXP_TO_BIO_ERR); // 8)     BIO return ReadFromBIO_OS(hBIORes, out _arRes, ref _sError); } catch (Exception E) { _sError = UCConsts.S_SIGN_OS_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hBIORes != IntPtr.Zero) UOpenSSLAPI.BIO_free(hBIORes); if(hData != IntPtr.Zero) UOpenSSLAPI.BIO_free(hData); if(hCMS != IntPtr.Zero) UOpenSSLAPI.CMS_ContentInfo_free(hCMS); } } 

Kemajuan algoritma adalah sebagai berikut. Pertama, konversikan sertifikat yang masuk (jika itu X509Certificate2) ke jenis kami. Karena Karena kami bekerja dengan tautan ke area memori yang tidak dikelola, kami harus memantaunya dengan cermat. Bersih beberapa waktu setelah tautan ke sertifikat di luar cakupan, ia akan meluncurkan destructor. Dan di dalamnya kita telah menentukan metode yang diperlukan untuk menghapus semua memori yang tidak dikelola yang terkait dengannya. Pendekatan ini memungkinkan kita untuk tidak membuang waktu melacak tautan ini langsung di dalam metode.


Setelah berurusan dengan sertifikat, kami membentuk BIO dengan data dan struktur tanda tangan. Kemudian kami menambahkan data dari penandatangan, mengatur bendera untuk memutuskan tanda tangan dan memulai formasi akhir tanda tangan. Hasilnya ditransfer ke BIO. Tetap hanya untuk mengekstrak array byte dari BIO. Mengubah BIO ke satu set byte dan sebaliknya sering digunakan, jadi lebih baik untuk menempatkannya dalam metode terpisah:


BIO dalam byte [] dan sebaliknya
 /**<summary>  BIO    OpenSSL</summary> * <param name="_hBIO"> BIO</param> * <param name="_sError">   </param> * <param name="_arRes"></param> * <param name="_iLen"> ,  0 -    </param> * <returns>   ,  UConsts.S_OK   </returns> * **/ internal static int ReadFromBIO_OS(IntPtr _hBIO, out byte[] _arRes, ref string _sError, uint _iLen = 0) { _arRes = new byte[0]; IntPtr hRes = IntPtr.Zero; uint iLen = _iLen; if(iLen == 0) iLen = int.MaxValue; try { // 0)   iLen = UOpenSSLAPI.BIO_read(_hBIO, IntPtr.Zero, int.MaxValue); // 1)      hRes = Marshal.AllocHGlobal((int)iLen); if (UOpenSSLAPI.BIO_read(_hBIO, hRes, iLen) != iLen) { _sError = UCConsts.S_OS_BIO_READ_LEN_ERR; return UConsts.E_CRYPTO_ERR; } // 2)   _arRes = new byte[iLen]; Marshal.Copy(hRes, _arRes, 0, _arRes.Length); return UConsts.S_OK;; } catch (Exception E) { _sError = UCConsts.S_OS_BIO_READ_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hRes != IntPtr.Zero) Marshal.FreeHGlobal(hRes); } } /**<summary> BIO   </summary> * <param name="_arData"></param> * <param name="_hBIO">   BIO</param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int GetBIOByBytesOS(byte[] _arData, out IntPtr _hBIO, ref string _sError) { _hBIO = UOpenSSLAPI.BIO_new_mem_buf( _arData, _arData.Length); if (_hBIO == IntPtr.Zero) return RetErrOS(ref _sError, UCConsts.S_OS_CM_BIO_CR_ERR); return UConsts.S_OK; } 

Seperti dalam kasus CryptoPro, perlu untuk mengekstrak informasi tentang algoritma hashing tanda tangan dari sertifikat. Tetapi dalam kasus OpenSSL, disimpan langsung dalam sertifikat:


Mengambil Algoritma Hash
 /**<summary>      OpenSSL</summary> * <param name="_hCert">  (X509)</param> * <returns> </returns> * **/ public static IntPtr GetDigestAlgOS(IntPtr _hCert) { x509_st pCert = (x509_st)Marshal.PtrToStructure(_hCert, typeof(x509_st)); X509_algor_st pAlgInfo = (X509_algor_st)Marshal.PtrToStructure(pCert.sig_alg, typeof(X509_algor_st)); IntPtr hAlgSn = UOpenSSLAPI.OBJ_nid2sn(UOpenSSLAPI.OBJ_obj2nid(pAlgInfo.algorithm)); return UOpenSSLAPI.EVP_get_digestbyname(hAlgSn); } 

Metode ini ternyata cukup rumit, tetapi berhasil. Anda dapat menemukan metode EVP_get_digestbynid dalam dokumentasi 1.0.2, namun pustaka versi yang kami gunakan tidak mengekspornya. Karena itu, pertama-tama kita membentuk nid, dan atas dasar itu nama pendek. Dan sudah dengan nama pendek, Anda dapat mengekstrak algoritme dengan cara biasa mencari berdasarkan nama.


Verifikasi Tanda Tangan


Tanda tangan yang diterima perlu verifikasi. OpenSSL memverifikasi tanda tangan sebagai berikut:


Verifikasi Tanda Tangan
 /**<summary> </summary> * <param name="_arData">,   </param> * <param name="_arSign"></param> * <param name="_pCert"></param> * <param name="_sError">   </param> * <param name="_pLocation"></param> * <param name="_fVerifyOnlySign">  </param> * <returns>  ,  UConsts.S_OK   </returns> * <remarks>   </remarks> * **/ internal static int CheckSignOS(byte[] _arData, byte[] _arSign, out X509Certificate2 _pCert, ref string _sError, bool _fVerifyOnlySign = true, StoreLocation _pLocation = StoreLocation.CurrentUser){ _pCert = null; IntPtr hBIOData = IntPtr.Zero; IntPtr hCMS = IntPtr.Zero; IntPtr hTrStore = IntPtr.Zero; try { // 0)  BIO     int iRes = GetBIOByBytesOS(_arData, out hBIOData, ref _sError); if (iRes != UConsts.S_OK) return iRes; // 1)   CMS iRes = GetCMSFromBytesOS(_arSign, out hCMS, ref _sError); if (iRes != UConsts.S_OK) return iRes; uint iFlag = UCConsts.CMS_DETACHED; // 2)    if (!_fVerifyOnlySign) { iRes = GetTrustStoreOS(_pLocation, out hTrStore, ref _sError); if (iRes != UConsts.S_OK) return iRes; } else iFlag |= UCConsts.CMS_NO_SIGNER_CERT_VERIFY; // 3)   if (!UOpenSSLAPI.CMS_verify(hCMS, IntPtr.Zero, hTrStore, hBIOData, IntPtr.Zero, iFlag)) return RetErrOS(ref _sError, UCConsts.S_OS_CM_CHECK_ERR); return UConsts.S_OK; } finally { if(hBIOData != IntPtr.Zero) UOpenSSLAPI.BIO_free(hBIOData); if(hCMS != IntPtr.Zero) UOpenSSLAPI.CMS_ContentInfo_free(hCMS); if(hTrStore != IntPtr.Zero) UOpenSSLAPI.X509_STORE_free(hTrStore); } } 

Pertama, data tanda tangan dikonversi dari array byte ke struktur CMS:


Pembentukan struktur CMS
 /**<summary> CMS   </summary> * <param name="_arData"> CMS</param> * <param name="_hCMS">    CMS</param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int GetCMSFromBytesOS(byte[] _arData, out IntPtr _hCMS, ref string _sError) { _hCMS = IntPtr.Zero; IntPtr hBIOCMS = IntPtr.Zero; IntPtr hCMS = IntPtr.Zero; try { // 0)   CMS hCMS = UOpenSSLAPI.CMS_ContentInfo_new(); if (hCMS == IntPtr.Zero) return RetErrOS(ref _sError); if (!UOpenSSLAPI.CMS_SignedData_init(hCMS)) return RetErrOS(ref _sError); // 1)    BIO hBIOCMS = UOpenSSLAPI.BIO_new_mem_buf(_arData, _arData.Length); if (hBIOCMS == IntPtr.Zero) return RetErrOS(ref _sError); // 2)   CMS if (UOpenSSLAPI.d2i_CMS_bio(hBIOCMS, ref hCMS) == IntPtr.Zero) return RetErrOS(ref _sError); // 3)   - ,    _hCMS = hCMS; hCMS = IntPtr.Zero; return UConsts.S_OK; } finally { if(hBIOCMS != IntPtr.Zero) UOpenSSLAPI.BIO_free(hBIOCMS); if(hCMS != IntPtr.Zero) UOpenSSLAPI.CMS_ContentInfo_free(hCMS); } } 

, BIO. , , ( ) :


 /**<summary>    </summary> * <param name="_hStore">   </param> * <param name="_pLocation"> </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> */ internal static int GetTrustStoreOS(StoreLocation _pLocation, out IntPtr _hStore, ref string _sError) { _hStore = IntPtr.Zero; IntPtr hStore = IntPtr.Zero; try { List<X509Certificate2> pCerts = GetCertList(_pLocation, StoreName.Root, TCryptoPath.cpOpenSSL); pCerts.AddRange(GetCertList(_pLocation, StoreName.AuthRoot, TCryptoPath.cpOpenSSL)); // 1)   hStore = UOpenSSLAPI.X509_STORE_new(); foreach (X509Certificate2 pCert in pCerts) { //      (    ) UOpenSSLAPI.X509_STORE_add_cert(hStore, pCert.getRealHandle()); } // 2)   UOpenSSLAPI.ERR_clear_error(); _hStore = hStore; hStore = IntPtr.Zero; return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_FORM_TRUST_STORE_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if (hStore != IntPtr.Zero) UOpenSSLAPI.X509_STORE_free(hStore); } 

, ( , ). CMS_Verify, .


(, CRL), iFlag .



. , , . .Net β€” SignedCms, .


( , ) . β€” , .


 /**<summary>  </summary> * <param name="_arSign"></param> * <param name="_sError">   </param> * <param name="_arContent">  </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal int DecodeOS(byte[] _arSign, byte[] _arContent, ref string _sError) { IntPtr hBIOData = IntPtr.Zero; IntPtr hCMS = IntPtr.Zero; IntPtr hCerts = IntPtr.Zero; try { // 0)    MS int iRes = UCUtils.GetCMSFromBytesOS(_arSign, out hCMS, ref _sError); if(iRes != UConsts.S_OK) return iRes; iRes = UCUtils.GetBIOByBytesOS(_arContent, out hBIOData, ref _sError); if(iRes != UConsts.S_OK) return iRes; // 1)   uint iFlags = UCConsts.CMS_NO_SIGNER_CERT_VERIFY; if(_arContent.Length == 0) iFlags |= UCConsts.CMS_NO_CONTENT_VERIFY; // 2)  CMS if (!UOpenSSLAPI.CMS_verify(hCMS, IntPtr.Zero, IntPtr.Zero, hBIOData, IntPtr.Zero, iFlags)) return UCUtils.RetErrOS(ref _sError, UCConsts.S_OS_CMS_VERIFY_ERR); // 3)   hCerts = UOpenSSLAPI.CMS_get0_signers(hCMS); int iCnt = UOpenSSLAPI.sk_num(hCerts); for (int i = 0; i < iCnt; i++) { IntPtr hCert = UOpenSSLAPI.sk_value(hCerts, i); byte[] arData; iRes = UCUtils.GetCertBytesOS(hCert, out arData, ref _sError); if(iRes != UConsts.S_OK) return iRes; fpCertificates.Add(ISDP_X509Cert.Create(arData, TCryptoPath.cpOpenSSL)); } // 4)   IntPtr hSigners = UOpenSSLAPI.CMS_get0_SignerInfos(hCMS); iCnt = UOpenSSLAPI.sk_num(hSigners); for (int i = 0; i < iCnt; i++) { IntPtr hSignerInfo = UOpenSSLAPI.sk_value(hSigners, i); // 4.1)    ISDPSignerInfo pInfo = new ISDPSignerInfo(this); iRes = pInfo.DecodeOS(hSignerInfo, ref _sError); if(iRes != UConsts.S_OK) return iRes; fpSignerInfos.Add(pInfo); } return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_OS_CMS_DECODE.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hCerts != IntPtr.Zero) UOpenSSLAPI.sk_free(hCerts); if(hBIOData != IntPtr.Zero) UOpenSSLAPI.BIO_free(hBIOData); if(hCMS != IntPtr.Zero) UOpenSSLAPI.CMS_ContentInfo_free(hCMS); } } 

, BIO ( ) CMS, . , β€” .


(STACK_OF(X509)), sk_pop, . , sk_value.


, CMS_get0_signers CMS_get1_certs. , . , , :


 CRYPTO_add(&cch->d.certificate->references, 1, CRYPTO_LOCK_X509); 

1.1.0 X509_up_ref, .
:


 /**<summary>   </summary> * <param name="_hSignerInfo">Handler    (OpenSSL)</param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ public int DecodeOS(IntPtr _hSignerInfo, ref string _sError) { try { // 0)    int iRes = UCUtils.GetSignerInfoCertOS(_hSignerInfo, fpSignedCMS.pCertificates, out fpCertificate, ref _sError); if(iRes != UConsts.S_OK) return iRes; // 1)    uint iPos = UOpenSSLAPI.CMS_signed_get_attr_by_NID(_hSignerInfo, UCConsts.NID_pkcs9_signingTime, 0); IntPtr hAttr = UOpenSSLAPI.CMS_signed_get_attr(_hSignerInfo, iPos); IntPtr hDateTime = UOpenSSLAPI.X509_ATTRIBUTE_get0_data(hAttr, 0, UCConsts.V_ASN1_UTCTIME, IntPtr.Zero); asn1_string_st pDate = (asn1_string_st)Marshal.PtrToStructure(hDateTime, typeof(asn1_string_st)); // 2)   Pkcs9SigningTime byte[] arDateAttr = new byte[pDate.iLength]; Marshal.Copy(pDate.hData, arDateAttr, 0, (int)pDate.iLength); arDateAttr = new byte[] { (byte)UCConsts.V_ASN1_UTCTIME, (byte)pDate.iLength}.Concat(arDateAttr).ToArray(); fpSignedAttributes.Add(new Pkcs9SigningTime(arDateAttr)); return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_CMS_SIGNER_DEC_OS_ER.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } } 

, , . ASN.1. asn1_string_st Pkcs9SigningTime.


:


 /**<summary>  </summary> * <param name="_hSignerInfo">  </param> * <param name="_pCert"> </param> * <param name="_pCerts">   </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int GetSignerInfoCertOS(IntPtr _hSignerInfo, X509Certificate2Collection _pCerts, out X509Certificate2 _pCert, ref string _sError) { _pCert = null; try { // 0)     IntPtr hKey = IntPtr.Zero; IntPtr hIssuer = IntPtr.Zero; IntPtr hSNO = IntPtr.Zero; if (!UOpenSSLAPI.CMS_SignerInfo_get0_signer_id(_hSignerInfo, ref hKey, ref hIssuer, ref hSNO)) return RetErrOS(ref _sError, UCConsts.S_GET_RECEIP_INFO_ERR); // 1)    string sSerial; int iRes = GetBinaryHexFromASNOS(hSNO, out sSerial, ref _sError); if(iRes != UConsts.S_OK) return iRes; X509Certificate2Collection pResCerts = _pCerts.Find(X509FindType.FindBySerialNumber, sSerial, false); if(pResCerts.Count == 0) return RetErrOS(ref _sError, UCConsts.S_NO_CERTIFICATE, UConsts.E_NO_CERTIFICATE); _pCert = pResCerts[0]; return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_GET_SIGN_INFO_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } } 

, . asn1_string_st, hex :


hex ANS.1
  /**<summary> Hex     ASN.1</summary> * <param name="_hASN">   ASN.1</param> * <param name="_sError">   </param> * <param name="_sHexData">   Hex</param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int GetBinaryHexFromASNOS(IntPtr _hASN, out string _sHexData, ref string _sError) { _sHexData = ""; try { asn1_string_st pSerial = (asn1_string_st)Marshal.PtrToStructure(_hASN, typeof(asn1_string_st)); byte[] arStr = new byte[pSerial.iLength]; Marshal.Copy(pSerial.hData, arStr, 0, (int)pSerial.iLength); _sHexData = arStr.ToHex().ToUpper(); return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_HEX_ASN_BINARY_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } } 

, , .



OpenSSL :


 /**<summary> </summary> * <param name="_arInput">  </param> * <param name="_pReceipients">  </param> * <param name="_arRes"></param> * <param name="_sError">   </param> * <returns>   ,  UConsts.S_OK   </returns> * **/ internal static int EncryptDataOS(byte[] _arInput, List<X509Certificate2> _pReceipients, out byte[] _arRes, ref string _sError) { _arRes = new byte[0]; uint iFlags = UCConsts.CMS_BINARY; IntPtr hData = IntPtr.Zero; IntPtr hReceipts = IntPtr.Zero; IntPtr hBIORes = IntPtr.Zero; IntPtr hCMS = IntPtr.Zero; try { // 0)  BIO     int iRes = GetBIOByBytesOS(_arInput, out hData, ref _sError); if (iRes != UConsts.S_OK) return iRes; // 1)     iRes = GetCertsStackOS(_pReceipients, out hReceipts, ref _sError); if (iRes != UConsts.S_OK) return iRes; // 2)  CMS hCMS = UOpenSSLAPI.CMS_encrypt(hReceipts, hData, UOpenSSLAPI.EVP_des_ede3_cbc(), iFlags); if (hCMS == IntPtr.Zero) return RetErrOS(ref _sError, UCConsts.S_ENC_CMS_ERR); // 3)  CMS  BIO hBIORes = UOpenSSLAPI.BIO_new(UOpenSSLAPI.BIO_s_mem()); if (!UOpenSSLAPI.i2d_CMS_bio_stream(hBIORes, hCMS, IntPtr.Zero, iFlags)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_EXP_TO_BIO_ERR); // 4)   BIO    return ReadFromBIO_OS(hBIORes, out _arRes, ref _sError); } catch (Exception E) { _sError = UCConsts.S_ENC_OS_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hBIORes != IntPtr.Zero) UOpenSSLAPI.BIO_free(hBIORes); if(hData != IntPtr.Zero) UOpenSSLAPI.BIO_free(hData); if(hCMS != IntPtr.Zero) UOpenSSLAPI.CMS_ContentInfo_free(hCMS); if(hReceipts != IntPtr.Zero) UOpenSSLAPI.sk_free(hReceipts); } } 

BIO β€” . . , BIO . OpenSSL , , , . EVP_des_ede3_cbc, .


, . . OpenSSL:


 /**<summary>  </summary>* <param name="_hStack"> </param> * <param name="_pCerts"> </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ public static int GetCertsStackOS(List<X509Certificate2> _pCerts, out IntPtr _hStack, ref string _sError) { _hStack = IntPtr.Zero; IntPtr hStack = IntPtr.Zero; try { hStack = UOpenSSLAPI.sk_new_null(); foreach (X509Certificate2 pCert in _pCerts) { // 0)  ,     ISDP_X509Cert pLocCert = ISDP_X509Cert.Convert(pCert, TCryptoPath.cpOpenSSL); // 1)  UOpenSSLAPI.sk_push(hStack, pLocCert.hRealHandle); } _hStack = hStack; hStack = IntPtr.Zero; return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_GEN_CERT_STACK_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hStack != IntPtr.Zero) UOpenSSLAPI.sk_free(hStack); } } 


, . :


  1. , ;
  2. ;
  3. ;
  4. ;
  5. BIO ;

 /**<summary> </summary> * <param name="_arInput">  </param> * <param name="_arRes"></param> * <param name="_pLocation"> ,  </param> * <param name="_sError">   </param> * <param name="_pCert"></param> * <returns>  ,  UCOnsts.S_OK   </returns> * **/ internal static int DecryptDataOS(byte[] _arInput, out X509Certificate2 _pCert, out byte[] _arRes, ref string _sError, StoreLocation _pLocation = StoreLocation.CurrentUser ) { _arRes = new byte[0]; _pCert = null; uint iFlag = UCConsts.CMS_BINARY; IntPtr hBIORes = IntPtr.Zero; IntPtr hCMS = IntPtr.Zero; X509Certificate2 pCert; try { // 0)   CMS int iRes = GetCMSFromBytesOS(_arInput, out hCMS, ref _sError); if (iRes != UConsts.S_OK) return iRes; // 1)     IntPtr hReceipts = UOpenSSLAPI.CMS_get0_RecipientInfos(hCMS); int iCnt = UOpenSSLAPI.sk_num(hReceipts); for(int i = 0; i < iCnt; i++) { IntPtr hRecep = UOpenSSLAPI.sk_value(hReceipts, i); iRes = GetRecepInfoCertOS(hRecep, _pLocation, out pCert, ref _sError); if (iRes != UConsts.S_OK && iRes != UConsts.E_NO_CERTIFICATE) return iRes; // 1.1)   if (iRes == UConsts.E_NO_CERTIFICATE) continue; ISDP_X509Cert pLocCert = ISDP_X509Cert.Convert(pCert); // 1.2)    if (pLocCert.hOSKey == IntPtr.Zero) continue; // 1.3)   if (!UOpenSSLAPI.CMS_RecipientInfo_set0_pkey(hRecep, pLocCert.hOSKey)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_SET_DEC_KEY_ERR); try { // 1.4)  if (!UOpenSSLAPI.CMS_RecipientInfo_decrypt(hCMS, hRecep)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_REC_DEC_ERR); } finally { // !!      UOpenSSLAPI.CMS_RecipientInfo_set0_pkey(hRecep, IntPtr.Zero); } // 1.5)   hBIORes = UOpenSSLAPI.BIO_new(UOpenSSLAPI.BIO_s_mem()); if (!UOpenSSLAPI.CMS_decrypt(hCMS, IntPtr.Zero, pLocCert.hRealHandle, IntPtr.Zero, hBIORes, iFlag)) return RetErrOS(ref _sError, UCConsts.S_OS_CMS_FULL_DEC_ERR); _pCert = pLocCert; // 2)     BIO return ReadFromBIO_OS(hBIORes, out _arRes, ref _sError); } _sError = UCConsts.S_DEC_NO_CERT_ERR; return UConsts.E_NO_CERTIFICATE; } catch (Exception E) { _sError = UCConsts.S_DEC_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hBIORes != IntPtr.Zero) UOpenSSLAPI.BIO_free(hBIORes); if(hCMS != IntPtr.Zero) UOpenSSLAPI.CMS_ContentInfo_free(hCMS); } } 

. , CMS_RecipientInfo_set0_pkey, CMS, .


, , . , . :


 /**<summary>  </summary> * <param name="_hRecep">  </param> * <param name="_pCert"> </param> * <param name="_pLocation">   </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int GetRecepInfoCertOS(IntPtr _hRecep, StoreLocation _pLocation, out X509Certificate2 _pCert, ref string _sError) { _pCert = null; try { // 0)     IntPtr hKey = IntPtr.Zero; IntPtr hIssuer = IntPtr.Zero; IntPtr hSNO = IntPtr.Zero; if (!UOpenSSLAPI.CMS_RecipientInfo_ktri_get0_signer_id(_hRecep, ref hKey, ref hIssuer, ref hSNO)) return RetErrOS(ref _sError, UCConsts.S_GET_RECEIP_INFO_ERR); // 1)    string sSerial; int iRes = GetBinaryHexFromASNOS(hSNO, out sSerial, ref _sError); if(iRes != UConsts.S_OK) return iRes; // 2)   iRes = FindCertificateOS(sSerial, out _pCert, ref _sError, _pLocation, StoreName.My, X509FindType.FindBySerialNumber); if(iRes != UConsts.S_OK) return iRes; return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_GET_RECEIP_INFO_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } } 

CMS_RecipientInfo_ktri_get0_signer_id , hSNO . .


C , , . ktri β€” . OpenSSL : CMS_RecipientInfo_kari_*, CMS_RecipientInfo_kekri_* CMS_RecipientInfo_set0_password pwri.



, . . , . . . OpenSSL . ( ), , .

, , , :


 /**<summary>    OpenSSL</summary> * <param name="_iRevFlag"> </param> * <param name="_iRevMode"> </param> * <param name="_hCert"> </param> * <param name="_rOnDate"> </param> * <param name="_pLocation"> </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int VerifyCertificateOS(IntPtr _hCert, X509RevocationMode _iRevMode, X509RevocationFlag _iRevFlag, StoreLocation _pLocation, DateTime _rOnDate, ref string _sError) { IntPtr hStore = IntPtr.Zero; IntPtr hStoreCtx = IntPtr.Zero; try { // 0)   int iRes = GetTrustStoreOS(_pLocation, out hStore, ref _sError); if(iRes != UConsts.S_OK) return iRes; // 1)    hStoreCtx = UOpenSSLAPI.X509_STORE_CTX_new(); if (!UOpenSSLAPI.X509_STORE_CTX_init(hStoreCtx, hStore, _hCert, IntPtr.Zero)) { _sError = UCConsts.S_CRYPTO_CONTEXT_CER_ERR; return UConsts.E_CRYPTO_ERR; } // 2)       SetStoreCtxCheckDate(hStoreCtx, _rOnDate); // 3)  if (!UOpenSSLAPI.X509_verify_cert(hStoreCtx)) { _sError = UCConsts.S_CRYPTO_CHAIN_CHECK_ERR.Frm(GetCertVerifyErr(hStoreCtx)); return UConsts.E_CRYPTO_ERR; } return UConsts.S_OK; } finally { if (hStore != IntPtr.Zero) UOpenSSLAPI.X509_STORE_free(hStore); if (hStoreCtx != IntPtr.Zero) UOpenSSLAPI.X509_STORE_CTX_free(hStoreCtx); } } 

(X509_STORE_CTX) . :


 /**<summary>   </summary> * <param name="_hStoreCtx"> </param> * <param name="_rDate"></param> * **/ public static void SetStoreCtxCheckDate(IntPtr _hStoreCtx, DateTime _rDate) { uint iFlags = UCConsts.X509_V_FLAG_USE_CHECK_TIME | UCConsts.X509_V_FLAG_X509_STRICT | UCConsts.X509_V_FLAG_CRL_CHECK_ALL; //   UOpenSSLAPI.X509_STORE_CTX_set_flags(_hStoreCtx, iFlags); //   UOpenSSLAPI.X509_STORE_CTX_set_time(_hStoreCtx, iFlags, (uint)_rDate.ToUnix()); //   -   UOpenSSLAPI.X509_STORE_CTX_set_trust(_hStoreCtx, UCConsts.X509_TRUST_TRUSTED); } 

, .


Kesimpulan


, . X509Certificate2 (mono) . .


, Windows . . Linux , , .


CSP 5.0 , RSA . , , , RSA, , .


Referensi


  1. OpenSSL 1.0.2 ManPages ;
  2. OpenSSL 1 2 ;
  3. OpenSSL :
    1. cms_smime.c;
  4. Wiki OpenSSL ;
  5. mono:
    1. RSAManaged ;

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


All Articles