توصيل CryptoPro بـ Mono

فيما يتعلق بالانتقال إلى Linux ، أصبح من الضروري نقل أحد أنظمة الخادم الخاصة بنا المكتوبة بلغة C # إلى Mono. يعمل النظام مع التوقيعات الرقمية المحسنة ، لذلك كانت إحدى المهام التي واجهناها هي اختبار أداء شهادات GOST من CryptoPro أحادية. قامت CryptoPro نفسها بتطبيق CSP لنظام التشغيل Linux لبعض الوقت ، لكن المحاولة الأولى لاستخدامه أظهرت أن فئات تشفير Mono الأصلية (على غرار تلك الموجودة في القاعدة. Net - X509Store ، X509Certificate2 ، إلخ) لا تعمل فقط مع مفاتيح الضيف ، بل إنها أيضًا لا تراهم في خزائنهم. ونتيجة لذلك ، كان لا بد من ربط العمل مع التشفير مباشرة من خلال مكتبات CryptoPro.



تثبيت الشهادة


قبل تنفيذ التعليمات البرمجية ، يجب تثبيت الشهادة والتأكد من أنها تعمل بشكل جيد.


تثبيت الشهادة

تم تثبيت إصدار مكون CryptoPro CSP 3.9 على Centos 7 في المجلد / opt / cprocsp. لتجنب التعارضات بين الأدوات المساعدة mono و CryptoPro التي تحمل الاسم نفسه (على سبيل المثال ، certmgr) ، لم يتم إدخال المسار إلى المجلد في متغيرات البيئة وتم استدعاء جميع الأدوات المساعدة في المسار الكامل.


أولاً ، نحدد قائمة القراء:
/opt/cprocsp/bin/amd64/csptest -enum -info -type PP_ENUMREADERS | iconv -f cp1251


إذا لم يكن هناك قارئ من المجلد الموجود على القرص (HDIMAGE) ضمن القائمة ، فضعه:
/opt/cprocsp/sbin/amd64/cpconfig -hardware reader -add HDIMAGE store


ثم يمكنك إنشاء حاويات من النموذج '\\. \ HDIMAGE \ {container name}' عن طريق إنشاء حاوية جديدة باستخدام المفاتيح:
/opt/cprocsp/bin/amd64/csptest -keyset -provtype 75 -newkeyset -cont '\\.\HDIMAGE\test'


أو من خلال إنشاء مجلد / var / opt / cprocsp / keys / root / {container name} .000 ، والذي يحتوي على المجموعة القياسية من ملفات حاويات CryptoPro (* .key ، * .mask ، وما إلى ذلك).


بعد ذلك ، يمكن تثبيت الشهادة من الحاوية في مخزن الشهادات:
/opt/cprocsp/bin/amd64/certmgr -inst mMy -cont '\\.\HDIMAGE\{ }'


يمكن رؤية الشهادة المثبتة بالأمر التالي:
/opt/cprocsp/bin/amd64/certmgr -list mMy


يمكن التحقق من تشغيل الشهادة على النحو التالي:
/opt/cprocsp/bin/amd64/cryptcp – sign -norev -thumbprint {} {} { }
/opt/cprocsp/bin/amd64/cryptcp – verify -norev { }


إذا كان كل شيء على ما يرام مع الشهادة ، فيمكنك المتابعة إلى الاتصال في الرمز.



الاتصال في التعليمات البرمجية


على الرغم من عملية النقل إلى Linux ، كان من المفترض أن يستمر النظام في العمل في بيئة Windows ، لذا من الخارج ، يجب أن يتم العمل مع التشفير من خلال الطرق العامة للنموذج "byte [] SignData (byte [] _arData، X509Certificate2 _pCert)" ، والتي يجب أن تعمل على قدم المساواة على لينكس وكذلك على ويندوز.


تبين أن تحليل طرق مكتبات التشفير كان ناجحًا ، لأن CryptoPro نفذت مكتبة "libcapi20.so" التي تحاكي تمامًا مكتبات التشفير القياسية Windows - "crypt32.dll" و "advapi32.dll". ربما ، بالطبع ، ليس تمامًا ، ولكن جميع الطرق اللازمة للعمل مع التشفير متوفرة هناك ، وجميعها تقريبًا.


لذلك ، نقوم بتشكيل فئتين ثابتتين "WCryptoAPI" و "LCryptoAPI" ، كل منهما يستورد المجموعة اللازمة من الطرق على النحو التالي:


 [DllImport(LIBCAPI20, SetLastError = true)] internal static extern bool CertCloseStore(IntPtr _hCertStore, uint _iFlags); 

يمكن إنشاء بنية الاتصال لكل طريقة بشكل مستقل ، أو استخدام موقع pinvoke على الويب ، أو نسخها من مصادر .Net (فئة CAPISafe ). من نفس الوحدة النمطية ، يمكنك رسم ثوابت وهياكل مرتبطة بالتشفير ، والتي يجعل وجودها الحياة أسهل عند العمل مع مكتبات خارجية.


ثم نقوم بتشكيل الفئة الثابتة "UCryptoAPI" والتي ، بناءً على النظام ، ستطلق على طريقة واحدة من فئتين:


 /**<summary> </summary> * <param name="_iFlags"> (  0)</param> * <param name="_hCertStore">   </param> * <returns>   </returns> * **/ internal static bool CertCloseStore(IntPtr _hCertStore, uint _iFlags) { if (fIsLinux) return LCryptoAPI.CertCloseStore(_hCertStore, _iFlags); else return WCryptoAPI.CertCloseStore(_hCertStore, _iFlags); } /**<summary>  </summary>**/ public static bool fIsLinux { get { int iPlatform = (int) Environment.OSVersion.Platform; return (iPlatform == 4) || (iPlatform == 6) || (iPlatform == 128); } } 

وبالتالي ، باستخدام طرق فئة UCryptoAPI ، يمكنك تنفيذ كود موحد تقريبًا لكلا النظامين.


بحث الشهادة


يبدأ العمل مع التشفير عادةً بالبحث عن شهادة ، لهذا في crypt32.dll هناك طريقتان CertOpenStore (يفتح متجر الشهادات المحدد) و CertOpenSystemStore بسيطة (يفتح الشهادات الشخصية للمستخدم). نظرًا لأن العمل مع الشهادات لا يقتصر على شهادات المستخدم الشخصية ، فإننا نربط الشهادة الأولى:


بحث الشهادة
 /**<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> * **/ public static int FindCertificateCP(string _pFindValue, out X509Certificate2 _pCert, ref string _sError, StoreLocation _pLocation = StoreLocation.CurrentUser, StoreName _pName = StoreName.My, X509FindType _pFindType = X509FindType.FindByThumbprint, bool _fVerify = false) { _pCert = null; IntPtr hCert = IntPtr.Zero; GCHandle hInternal = new GCHandle(); GCHandle hFull = new GCHandle(); IntPtr hSysStore = IntPtr.Zero; try { // 0)   hSysStore = UCryptoAPI.CertOpenStore(UCConsts.AR_CERT_STORE_PROV_SYSTEM[fIsLinux.ToByte()], UCConsts.PKCS_7_OR_X509_ASN_ENCODING, IntPtr.Zero, UCUtils.MapX509StoreFlags(_pLocation, OpenFlags.ReadOnly), UCConsts.AR_CRYPTO_STORE_NAME[(int)_pName]); if (hSysStore == IntPtr.Zero) { _sError = UCConsts.S_ERR_STORE_OPEN.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } // 1)     if ((_pFindType == X509FindType.FindByThumbprint) || (_pFindType == X509FindType.FindBySerialNumber)) { byte[] arData = _pFindValue.FromHex(); CRYPTOAPI_BLOB cryptBlob; cryptBlob.cbData = arData.Length; hInternal = GCHandle.Alloc(arData, GCHandleType.Pinned); cryptBlob.pbData = hInternal.AddrOfPinnedObject(); hFull = GCHandle.Alloc(cryptBlob, GCHandleType.Pinned); } else { byte[] arData; if(fIsLinux) arData = Encoding.UTF8.GetBytes(_pFindValue); else arData = Encoding.Unicode.GetBytes(_pFindValue); hFull = GCHandle.Alloc(arData, GCHandleType.Pinned); } // 2)  IntPtr hPrev = IntPtr.Zero; do { hCert = UCryptoAPI.CertFindCertificateInStore(hSysStore, UCConsts.PKCS_7_OR_X509_ASN_ENCODING, 0, UCConsts.AR_CRYPT_FIND_TYPE[(int)_pFindType, fIsLinux.ToByte()], hFull.AddrOfPinnedObject(), hPrev); // 2.1)   if(hPrev != IntPtr.Zero) UCryptoAPI.CertFreeCertificateContext(hPrev); // 2.2)    if(hCert == IntPtr.Zero) return UConsts.E_NO_CERTIFICATE; // 2.3)    X509Certificate2 pCert = new ISDP_X509Cert(hCert); if (!_fVerify || pCert.ISDPVerify()) { hCert = IntPtr.Zero; _pCert = pCert; return UConsts.S_OK; } hPrev = hCert; //    hCert = IntPtr.Zero; } while(hCert != IntPtr.Zero); return UConsts.E_NO_CERTIFICATE; } catch (Exception E) { _sError = UCConsts.S_FIND_CERT_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { //      if(hInternal.IsAllocated) hInternal.Free(); if(hFull.IsAllocated) hFull.Free(); if (hCert != IntPtr.Zero) UCryptoAPI.CertFreeCertificateContext(hCert); UCryptoAPI.CertCloseStore(hSysStore, 0); } } 


يتم البحث على عدة مراحل:
  1. فتحة تخزين
  2. تشكيل بنية البيانات التي نبحث عنها ؛
  3. بحث الشهادة ؛
  4. إذا لزم الأمر ، ثم التحقق من الشهادة (موصوفة في قسم منفصل) ؛
  5. إغلاق المستودع وإطلاق الهيكل من النقطة 2 (حيث يوجد عمل في كل مكان بذاكرة غير مُدارة. صافي ، لن يتم القيام بأي شيء لتنظيفه) ؛

هناك بعض النقاط الدقيقة عند البحث عن الشهادات.


يعمل CryptoPro على Linux مع سلاسل ANSI ، وعلى Windows مع UTF8 ، وبالتالي:


  1. عند توصيل طريقة فتح التخزين في Linux ، من الضروري الإشارة بوضوح إلى نوع التنظيم [In، MarshalAs (UnmanagedType.LPStr)] لمعلمة رمز التخزين ؛
  2. تمرير سلسلة البحث (على سبيل المثال ، باسم الموضوع) يجب تحويله إلى مجموعة من البايتات مع ترميزات مختلفة ؛
  3. لجميع ثوابت التشفير التي لها اختلاف حسب نوع السلسلة (على سبيل المثال ، CERT_FIND_SUBJECT_STR_A و CERT_FIND_SUBJECT_STR_W) في Windows ، يجب عليك تحديد * _W ، وفي Linux * _A ؛

يمكن أن تؤخذ طريقة MapX509StoreFlags مباشرة من مصادر Microsoft دون تغييرات ، فهي ببساطة تشكل قناعًا نهائيًا يعتمد على إشارات .Net.


تعتمد القيمة التي يتم بها البحث على نوع البحث (راجع MSDN لـ CertFindCertificateInStore ) ، يوضح المثال الخيارين الأكثر استخدامًا - لتنسيق السلسلة (أسماء الموضوع ، جهة الإصدار ، إلخ) والثنائي (بصمة الإصبع ، الرقم التسلسلي).


تختلف عملية إنشاء شهادة من IntPtr على نظامي التشغيل Windows و Linux. سيقوم Windows بإنشاء الشهادة بطريقة بسيطة:

  new X509Certificate2(hCert); 


في Linux ، عليك إنشاء شهادة في خطوتين:

 X509Certificate2(new X509Certificate(hCert)); 


في المستقبل ، نحتاج إلى الوصول إلى hCert للعمل ، ويجب تخزينه في كائن الشهادة. في نظام التشغيل Windows ، يمكن استرجاعها لاحقًا من خاصية Handle ، ولكن Linux يحول بنية CERT_CONTEXT التي تتبع ارتباط hCert إلى ارتباط إلى بنية x509_st (OpenSSL) ويسجلها في Handle. لذلك ، من الجدير إنشاء وراثة من X509Certificate2 (ISDP_X509Cert في المثال) ، والتي ستخزن hCert في كلا النظامين في حقل منفصل.


لا تنس أن هذا رابط لمنطقة من الذاكرة غير المُدارة ويجب تحريرها بعد انتهاء العمل. لأن في .Net 4.5 X509Certificate2 لا يمكن التخلص منه - يجب إجراء التنظيف باستخدام أسلوب CertFreeCertificateContext في المدمر.


تشكيل التوقيع


عند العمل مع شهادات GOST ، يتم دائمًا استخدام التوقيعات غير المتصلة مع أحد الموقعين. من أجل إنشاء مثل هذا التوقيع ، مطلوب كتلة رمز بسيطة إلى حد ما:


تشكيل التوقيع
 /**<summary>  </summary> * <param name="_arData">  </param> * <param name="_pCert"></param> * <param name="_sError">   </param> * <param name="_arRes"> </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ public static int SignDataCP(byte[] _arData, X509Certificate2 _pCert, out byte[] _arRes, ref string _sError) { _arRes = new byte[0]; // 0)   CRYPT_SIGN_MESSAGE_PARA pParams = new CRYPT_SIGN_MESSAGE_PARA(); pParams.cbSize = Marshal.SizeOf(typeof(CRYPT_SIGN_MESSAGE_PARA)); pParams.dwMsgEncodingType = (int)(UCConsts.PKCS_7_OR_X509_ASN_ENCODING); pParams.pSigningCert = _pCert.getRealHandle(); pParams.cMsgCert = 1; pParams.HashAlgorithm.pszObjId = _pCert.getHashAlgirtmOid(); IntPtr pGlobData = Marshal.AllocHGlobal(_arData.Length); GCHandle pGC = GCHandle.Alloc(_pCert.getRealHandle(), GCHandleType.Pinned); try { pParams.rgpMsgCert = pGC.AddrOfPinnedObject(); Marshal.Copy(_arData, 0, pGlobData, _arData.Length); uint iLen = 50000; byte[] arRes = new byte[iLen]; // 1)   if (!UCryptoAPI.CryptSignMessage(ref pParams, true, 1, new IntPtr[1] { pGlobData }, new uint[1] { (uint)_arData.Length }, arRes, ref iLen)) { _sError = UCConsts.S_MAKE_SIGN_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } Array.Resize(ref arRes, (int)iLen); _arRes = arRes; return UConsts.S_OK;; } catch (Exception E) { _sError = UCConsts.S_MAKE_SIGN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { pGC.Free(); Marshal.FreeHGlobal(pGlobData); } } 

أثناء عمل الطريقة ، يتم تشكيل هيكل مع معلمات ويتم استدعاء طريقة التوقيع. يمكن أن تسمح لك بنية المعلمة بحفظ الشهادات في التوقيع لتشكيل سلسلة كاملة (حقلي cMsgCert و rgpMsgCert ، يخزن الأول عدد الشهادات ، والقائمة الثانية لروابط هياكل هذه الشهادات).


يمكن أن تتلقى طريقة التوقيع وثيقة واحدة أو أكثر للتوقيع المتزامن مع توقيع واحد. بالمناسبة ، هذا لا يتعارض مع القانون الفيدرالي 63 وهو مريح للغاية ، لأنه من غير المحتمل أن يكون المستخدم سعيدًا بالحاجة إلى النقر على زر "تسجيل" عدة مرات.


الغريب الرئيسي في هذه الطريقة هو أنها لا تعمل في وضع مكالمتين ، وهو أمر نموذجي لمعظم طرق المكتبة التي تعمل مع كتل كبيرة من الذاكرة (الأولى ذات القيمة الخالية - ترجع طول المخزن المؤقت المطلوب ، والثاني يملأ المخزن المؤقت). لذلك ، من الضروري إنشاء مخزن مؤقت كبير ، ثم تقصيره إلى طوله الفعلي.


المشكلة الخطيرة الوحيدة هي البحث عن OID لخوارزمية التجزئة (Digest) المستخدمة عند التوقيع - في شكل صريح ليس في الشهادة (هناك فقط خوارزمية التوقيع نفسه). وإذا كان بإمكانك تحديده بسلسلة فارغة على نظام Windows - سيتم التقاطه تلقائيًا ، ولكن سيرفض Linux التوقيع إذا لم تكن الخوارزمية متشابهة.


ولكن هناك خدعة - في المعلومات حول خوارزمية التوقيع (البنية CRYPT_OID_INFO) يتم تخزين OID للتوقيع في pszOID ، ويتم تخزين معرف خوارزمية التجزئة في Algid. وتحويل Algid إلى OID هو أمر تقني بالفعل:


الحصول على OID لخوارزمية التجزئة
 /**<summary> OID   </summary> * <param name="_hCertHandle"> </param> * <param name="_sOID">  OID</param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int GetHashAlgoritmOID(IntPtr _hCertHandle, out string _sOID, ref string _sError) { _sOID = ""; IntPtr hHashAlgInfo = IntPtr.Zero; IntPtr hData = IntPtr.Zero; try { CERT_CONTEXT pContext = (CERT_CONTEXT)Marshal.PtrToStructure(_hCertHandle, typeof(CERT_CONTEXT)); CERT_INFO pCertInfo = (CERT_INFO)Marshal.PtrToStructure(pContext.pCertInfo, typeof(CERT_INFO)); //  AlgID //  UCryptoAPI.CertAlgIdToOID  Windows   ,   byte[] arData = BitConverter.GetBytes(UCryptoAPI.CertOIDToAlgId(pCertInfo.SignatureAlgorithm.pszObjId)); hData = Marshal.AllocHGlobal(arData.Length); Marshal.Copy(arData, 0, hData, arData.Length); //  OID hHashAlgInfo = UCryptoAPI.CryptFindOIDInfo(UCConsts.CRYPT_OID_INFO_ALGID_KEY, hData, UCConsts.CRYPT_HASH_ALG_OID_GROUP_ID); if (hHashAlgInfo == IntPtr.Zero) { _sError = UCConsts.S_NO_HASH_ALG_ERR.Frm( Marshal.GetLastWin32Error()); return UConsts.E_GEN_EXCEPTION; } CRYPT_OID_INFO pHashAlgInfo = (CRYPT_OID_INFO)Marshal.PtrToStructure(hHashAlgInfo, typeof(CRYPT_OID_INFO)); _sOID = pHashAlgInfo.pszOID; return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_DETERM_HASH_ALG_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { Marshal.FreeHGlobal(hData); } } 

بعد قراءة التعليمات البرمجية بعناية ، قد تتفاجأ بأن معرف الخوارزمية يتم الحصول عليه بطريقة بسيطة (CertOIDToAlgId) وأن Oid فيه معقد (CryptFindOIDInfo). سيكون من المنطقي افتراض استخدام أي من الطريقتين المعقدة أو كلتا الطريقتين البسيطتين ، وفي Linux يعمل كلا الخيارين بنجاح. ومع ذلك ، في Windows ، يكون الخيار الصعب للحصول على معرف والحصول على معرف OID غير مستقر ، لذا فإن مثل هذا المختلط الغريب سيكون حلاً مستقرًا.


التحقق من التوقيع


يتم التحقق من التوقيع على مرحلتين ، في البداية يتم التحقق من التوقيع نفسه ، ثم يتم التحقق من الشهادة التي تم إنشاؤها بها (السلسلة ، تاريخ التوقيع ، وما إلى ذلك).
وكذلك عند التوقيع ، يجب عليك تحديد مجموعة البيانات المراد توقيعها ، ومعلمات التوقيع والتوقيع نفسه:


التحقق من التوقيع
 /**<summary>      </summary> * <returns></returns> * **/ internal static CRYPT_VERIFY_MESSAGE_PARA GetStdSignVerifyPar() { CRYPT_VERIFY_MESSAGE_PARA pVerifyParams = new CRYPT_VERIFY_MESSAGE_PARA(); pVerifyParams.cbSize = (int)Marshal.SizeOf(pVerifyParams); pVerifyParams.dwMsgEncodingType = UCConsts.PKCS_7_OR_X509_ASN_ENCODING; pVerifyParams.hCryptProv = 0; pVerifyParams.pfnGetSignerCertificate = IntPtr.Zero; pVerifyParams.pvGetArg = IntPtr.Zero; return pVerifyParams; } /**<summary> </summary> * <param name="_arData">,   </param> * <param name="_pSign"></param> * <param name="_pCert"></param> * <param name="_sError">   </param> * <param name="_fVerifyOnlySign">  </param> * <param name="_pRevMode">  </param> * <param name="_pRevFlag">  </param> * <returns>  ,  UConsts.S_OK   </returns> * <remarks>   </remarks> * **/ public static int CheckSignCP(byte[] _arData, byte[] _pSign, out X509Certificate2 _pCert, ref string _sError, bool _fVerifyOnlySign = true, X509RevocationMode _pRevMode = X509RevocationMode.Online, X509RevocationFlag _pRevFlag = X509RevocationFlag.ExcludeRoot){ _pCert = null; IntPtr pHData = Marshal.AllocHGlobal(_arData.Length); GCHandle pCertContext = GCHandle.Alloc(IntPtr.Zero, GCHandleType.Pinned); try { Marshal.Copy(_arData, 0, pHData, _arData.Length); CRYPT_VERIFY_MESSAGE_PARA pVerParam = UCUtils.GetStdSignVerifyPar(); // 0)   bool fRes = UCryptoAPI.CryptVerifyDetachedMessageSignature( ref pVerParam, //   0, //   _pSign, //  _pSign.Length, //   1, // -    new IntPtr[1] { pHData }, //   new int[1] { _arData.Length }, //    pCertContext.AddrOfPinnedObject());//    if (!fRes) { _sError = UCConsts.S_SIGN_CHECK_ERR.Frm(Marshal.GetLastWin32Error().ToString("X")); return UConsts.E_CRYPTO_ERR; } // 1)   _pCert = new ISDP_X509Cert((IntPtr)pCertContext.Target); if (_pCert == null) { _sError = UCConsts.S_SIGN_CHECK_CERT_ERR; return UConsts.E_CRYPTO_ERR; } // 2)   if (!_fVerifyOnlySign) { List<DateTime> pDates; // 2.1)    int iRes = GetSignDateTimeCP(_pSign, out pDates, ref _sError); // 2.2)    iRes = _pCert.ISDPVerify(ref _sError, pDates[0], _pRevMode, _pRevFlag); if (iRes != UConsts.S_OK) return iRes; } return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_SIGN_CHECK_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION;; } finally { Marshal.FreeHGlobal(pHData); if ((_pCert == null) && pCertContext.IsAllocated && ((IntPtr)pCertContext.Target != IntPtr.Zero)) UCryptoAPI.CertFreeCertificateContext((IntPtr)pCertContext.Target); pCertContext.Free(); } } 

للراحة ، تم نقل عملية تشكيل بنية مع معلمات إلى طريقة منفصلة (GetStdSignVerifyPar). بعد ذلك ، يتم التحقق من التوقيع نفسه ويتم استخراج الموقع الأول (من أجل الخير ، من الضروري استخراج الكل ، ولكن التوقيع الذي يحتوي على العديد من الموقعين لا يزال غريباً).


بعد استخراج شهادة المُوقِّع ، سنحوِّلها إلى فصلنا ونتحقق منها (إذا تم تحديدها في معلمات الطريقة). للتحقق ، يتم استخدام تاريخ توقيع الموقّع الأول (انظر القسم الخاص باستخراج المعلومات من التوقيع ، والقسم الخاص بفحص الشهادة).


استخراج معلومات التوقيع


غالبًا ما تتطلب أنظمة التشفير تمثيلًا مطبوعًا للتوقيع. في كل حالة ، يكون الأمر مختلفًا ، لذا من الأفضل إنشاء فئة من المعلومات حول التوقيع ، والتي ستحتوي على معلومات في شكل مناسب للاستخدام ، وبمساعدة لها ، قم بتقديم عرض تقديمي مطبوع. في .Net هناك مثل هذه الفئة - SignedCms ، ومع ذلك ، فإن التناظرية أحادية مع توقيعات CritoPro ترفض العمل في الأول ، وثانيًا تحتوي على المعدل المختوم وثالثًا تقريبًا جميع خصائصها محمية ضد الكتابة ، لذلك سيكون عليك إنشاء نظيرتك الخاصة.


يحتوي التوقيع نفسه على عنصرين رئيسيين - قائمة الشهادات وقائمة الموقعين. قد تكون قائمة الشهادات فارغة ، أو قد تحتوي على جميع شهادات التحقق ، بما في ذلك السلاسل الكاملة. تشير قائمة الموقعين على عدد التوقيعات الحقيقية. يتم الاتصال بينهما عن طريق الرقم التسلسلي والناشر (المصدر). نظريًا ، في توقيع واحد يمكن أن تكون هناك شهادتان من ناشرين مختلفين بنفس الرقم التسلسلي ، ولكن في الممارسة العملية يمكن إهمالها والبحث عنها فقط من خلال الرقم التسلسلي.


قراءة التوقيع كما يلي:


استخراج معلومات التوقيع
 /**<summary></summary> * <param name="_arSign"></param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ public int Decode(byte[] _arSign, ref string _sError) { IntPtr hMsg = IntPtr.Zero; // 0)   try { hMsg = UCryptoAPI.CryptMsgOpenToDecode(UCConsts.PKCS_7_OR_X509_ASN_ENCODING, UCConsts.CMSG_DETACHED_FLAG, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (hMsg == IntPtr.Zero) { _sError = UCConsts.S_CRYP_MSG_FORM_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } // 1)   if (!UCryptoAPI.CryptMsgUpdate(hMsg, _arSign, (uint)_arSign.Length, true)) { _sError = UCConsts.S_CRYP_MSG_SIGN_COPY_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } // 2)   (PKCS7 SignedData) uint iMessType = UCUtils.GetCryptMsgParam<uint>(hMsg, UCConsts.CMSG_TYPE_PARAM); if (UCConsts.CMSG_SIGNED != iMessType) { _sError = UCConsts.S_CRYP_MSG_SIGN_TYPE_ERR.Frm(iMessType, UCConsts.CMSG_SIGNED); return UConsts.E_CRYPTO_ERR; } // 3)    fpCertificates = UCUtils.GetSignCertificates(hMsg); // 4)   uint iSignerCount = UCUtils.GetCryptMsgParam<uint>(hMsg, UCConsts.CMSG_SIGNER_COUNT_PARAM); for (int i = 0; i < iSignerCount; i++) { ISDPSignerInfo pInfo = new ISDPSignerInfo(); fpSignerInfos.Add(pInfo); int iRes = pInfo.Decode(hMsg, i, this, ref _sError); if (iRes != UConsts.S_OK) return iRes; } return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_SIGN_INFO_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hMsg != IntPtr.Zero) UCryptoAPI.CryptMsgClose(hMsg); } } 

يتم تحليل التوقيع في عدة مراحل ، أولاً يتم تكوين بنية الرسالة (CryptMsgOpenToDecode) ، ثم يتم إدخال بيانات التوقيع الحقيقي (CryptMsgUpdate) فيه. يبقى التحقق من أن هذا هو التوقيع الحقيقي والحصول أولاً على قائمة الشهادات ، ثم قائمة الموقعين. يتم استرداد قائمة الشهادات بالتسلسل:


الحصول على قائمة الشهادات
 /**<summary>     </summary> * <param name="_hMsg">Handle </param> * <returns> </returns> * **/ internal static X509Certificate2Collection GetSignCertificates(IntPtr _hMsg) { X509Certificate2Collection certificates = new X509Certificate2Collection(); uint iCnt = GetCryptMsgParam<uint>(_hMsg, UCConsts.CMSG_CERT_COUNT_PARAM); for (int i = 0; i < iCnt; i++) { IntPtr hInfo = IntPtr.Zero; IntPtr hCert = IntPtr.Zero; try { uint iLen = 0; if (!GetCryptMsgParam(_hMsg, UCConsts.CMSG_CERT_PARAM, out hInfo, out iLen)) continue; hCert = UCryptoAPI.CertCreateCertificateContext(UCConsts.PKCS_7_OR_X509_ASN_ENCODING, hInfo, iLen); if (hCert != IntPtr.Zero) { certificates.Add(new ISDP_X509Cert(hCert)); hCert = IntPtr.Zero; } } finally { if (hInfo != IntPtr.Zero) Marshal.FreeHGlobal(hInfo); if (hInfo != IntPtr.Zero) Marshal.FreeHGlobal(hCert); } } return certificates; } 

أولاً ، يتم تحديد عدد الشهادات من المعلمة CMSG_CERT_COUNT_PARAM ، ثم يتم استرداد المعلومات حول كل شهادة بشكل تسلسلي. تكمل عملية إنشاء سياق الشهادة وعلى أساس الشهادة نفسها عملية الإنشاء.


استرجاع بيانات الموقّع أكثر صعوبة. تحتوي على إشارة للشهادة وقائمة بمعلمات التوقيع (على سبيل المثال ، تاريخ التوقيع). عملية استخراج البيانات هي كما يلي:


استرداد معلومات الموقِّع
 /**<summary>   </summary> * <param name="_hMsg">Handler </param> * <param name="_iIndex"> </param> * <param name="_pSignedCms"> </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ public int Decode(IntPtr _hMsg, int _iIndex, ISDPSignedCms _pSignedCms, ref string _sError) { // 1)   uint iLen = 0; // 2)  IntPtr hInfo = IntPtr.Zero; try { if (!UCryptoAPI.CryptMsgGetParam(_hMsg, UCConsts.CMSG_SIGNER_INFO_PARAM, (uint)_iIndex, IntPtr.Zero, ref iLen)) { _sError = UCConsts.S_ERR_SIGNER_INFO_LEN.Frm(_iIndex, Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } hInfo = Marshal.AllocHGlobal((int)iLen); if (!UCryptoAPI.CryptMsgGetParam(_hMsg, UCConsts.CMSG_SIGNER_INFO_PARAM, (uint)_iIndex, hInfo, ref iLen)) { _sError = UCConsts.S_ERR_SIGNER_INFO.Frm(_iIndex, Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } CMSG_SIGNER_INFO pSignerInfo = (CMSG_SIGNER_INFO) Marshal.PtrToStructure(hInfo, typeof(CMSG_SIGNER_INFO)); // 2.1)   byte[] arSerial = new byte[pSignerInfo.SerialNumber.cbData]; Marshal.Copy(pSignerInfo.SerialNumber.pbData, arSerial, 0, arSerial.Length); X509Certificate2Collection pLocCerts = _pSignedCms.pCertificates.Find(X509FindType.FindBySerialNumber, arSerial.Reverse().ToArray().ToHex(), false); if (pLocCerts.Count != 1) { _sError = UCConsts.S_ERR_SIGNER_INFO_CERT.Frm(_iIndex); return UConsts.E_NO_CERTIFICATE; } fpCertificate = pLocCerts[0]; fpSignedAttributes = UCUtils.ReadCryptoAttrsCollection(pSignerInfo.AuthAttrs); return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_ERR_SIGNER_INFO_READ.Frm(_iIndex, E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hInfo != IntPtr.Zero) Marshal.FreeHGlobal(hInfo); } } 

في سياقها ، يتم تحديد حجم هيكل الموقع أولاً ، ثم يتم استخراج الهيكل CMSG_SIGNER_INFO. من السهل العثور على الرقم التسلسلي للشهادة فيه واستخدامه للعثور على الشهادة التي تحتاجها في القائمة المستخرجة سابقًا. يرجى ملاحظة أن الرقم التسلسلي في الترتيب العكسي.


بعد استخراج الشهادة ، من الضروري تحديد معلمات التوقيع ، وأهمها تاريخ التوقيع (حتى إذا لم يتم التحقق منها بواسطة خادم الطابع الزمني ، فمن المهم جدًا للعرض).


قائمة سمات التوقيع
 /**<summary>   </summary> * <param name="_pAttrs"> </param> * <returns> </returns> * **/ internal static CryptographicAttributeObjectCollection ReadCryptoAttrsCollection(CRYPT_ATTRIBUTES _pAttrs) { CryptographicAttributeObjectCollection pRes = new CryptographicAttributeObjectCollection(); for (int i = 0; i < _pAttrs.cAttr; i++) { IntPtr hAttr = new IntPtr((long)_pAttrs.rgAttr + (i * Marshal.SizeOf(typeof(CRYPT_ATTRIBUTE)))); CRYPT_ATTRIBUTE pAttr = (CRYPT_ATTRIBUTE) Marshal.PtrToStructure(hAttr, typeof(CRYPT_ATTRIBUTE)); CryptographicAttributeObject pAttrInfo = new CryptographicAttributeObject(new Oid(pAttr.pszObjId), GetAsnEncodedDataCollection(pAttr)); pRes.Add(pAttrInfo); } return pRes; } 

السمات هي مرجع متداخل لشكل Oid - قائمة القيم (في الواقع ، هذا هو هيكل ASN.1 انفجر). بعد اجتياز المستوى الأول ، نشكل قائمة متداخلة:


سمة توقيع التحليل
 /**<summary>      </summary> * <param name="_sName"></param> * <returns> </returns> * **/ internal static Pkcs9AttributeObject Pkcs9AttributeFromOID(string _sName) { switch (_sName) { case UCConsts.S_SIGN_DATE_OID : return new Pkcs9SigningTime(); // case UConsts.S_CONTENT_TYPE_OID : return new Pkcs9ContentType(); ->>  Mono  // case UConsts.S_MESS_DIGEST_OID : return new Pkcs9MessageDigest(); default: return new Pkcs9AttributeObject(); } } /**<summary>  ASN</summary> * <param name="_pAttr"></param> * <returns></returns> * **/ internal static AsnEncodedDataCollection GetAsnEncodedDataCollection (CRYPT_ATTRIBUTE _pAttr) { AsnEncodedDataCollection pRes = new AsnEncodedDataCollection(); Oid pOid = new Oid(_pAttr.pszObjId); string sOid = pOid.Value; for (uint i = 0; i < _pAttr.cValue; i++) { checked { IntPtr pAttributeBlob = new IntPtr((long)_pAttr.rgValue + (i * Marshal.SizeOf(typeof(CRYPTOAPI_BLOB)))); Pkcs9AttributeObject attribute = new Pkcs9AttributeObject(pOid, BlobToByteArray(pAttributeBlob)); Pkcs9AttributeObject customAttribute = Pkcs9AttributeFromOID(sOid); if (customAttribute != null) { customAttribute.CopyFrom(attribute); attribute = customAttribute; } pRes.Add(attribute); } } return pRes; } 

Pkcs9AttributeObject. , mono . Mono .


— — SignedCms, .



, , . (, , ).


 /**<summary> </summary> * <param name="_arInput">  </param> * <param name="_pCert"></param> * <param name="_arRes"></param> * <param name="_sError">   </param> * <returns>   ,  UConsts.S_OK   </returns> * **/ public static int EncryptDataCP(byte[] _arInput, X509Certificate2 _pCert, out byte[] _arRes, ref string _sError) { _arRes = new byte[0]; try { // 0)   CRYPT_ENCRYPT_MESSAGE_PARA pParams = new CRYPT_ENCRYPT_MESSAGE_PARA(); pParams.dwMsgEncodingType = UCConsts.PKCS_7_OR_X509_ASN_ENCODING; pParams.ContentEncryptionAlgorithm.pszObjId = _pCert.getEncodeAlgirtmOid(); pParams.cbSize = Marshal.SizeOf(pParams); // 1)   int iLen = 0; if (!UCryptoAPI.CryptEncryptMessage(ref pParams, 1, new IntPtr[] { _pCert.getRealHandle() }, _arInput, _arInput.Length, null, ref iLen)) { _sError = UCConsts.S_CRYPT_ENCODE_LEN_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } // 2)     _arRes = new byte[iLen]; if (!UCryptoAPI.CryptEncryptMessage(ref pParams, 1, new IntPtr[] {_pCert.getRealHandle() }, _arInput, _arInput.Length, _arRes, ref iLen)) { _sError = UCConsts.S_CRYPT_ENCODE_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_CRYPT_ENCODE_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } } 

— , . , , .


, , .


. , ( ). :


 /**<summary> OID   </summary> * <param name="_hCertHandle"> </param> * <param name="_sOID">  OID</param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int GetEncodeAlgoritmOID(IntPtr _hCertHandle, out string _sOID, ref string _sError) { bool fNeedRelease = false; _sOID = ""; uint iKeySpec = 0; IntPtr hCrypto = IntPtr.Zero; try { // 0)    if (!UCryptoAPI.CryptAcquireCertificatePrivateKey(_hCertHandle, 0, IntPtr.Zero, ref hCrypto, ref iKeySpec, ref fNeedRelease)) { _sError = UCConsts.S_CRYPTO_PROV_INIT_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } uint iLen = 1000; byte[] arData = new byte[1000]; uint iFlag = 1; //  // 1)      while (UCryptoAPI.CryptGetProvParam(hCrypto, UCConsts.PP_ENUMALGS, arData, ref iLen, iFlag)){ iFlag = 2; //  PROV_ENUMALGS pInfo = ConvertBytesToStruct<PROV_ENUMALGS>(arData); // 2)   OID     byte[] arDataAlg = BitConverter.GetBytes(pInfo.aiAlgid); IntPtr hDataAlg = Marshal.AllocHGlobal(arDataAlg.Length); try { Marshal.Copy(arDataAlg, 0, hDataAlg, arDataAlg.Length); IntPtr hHashAlgInfo2 = UCryptoAPI.CryptFindOIDInfo(UCConsts.CRYPT_OID_INFO_ALGID_KEY, hDataAlg, UCConsts.CRYPT_ENCRYPT_ALG_OID_GROUP_ID); // 2.1)  -  if (hHashAlgInfo2 != IntPtr.Zero) { CRYPT_OID_INFO pHashAlgInfo2 = (CRYPT_OID_INFO)Marshal.PtrToStructure(hHashAlgInfo2, typeof(CRYPT_OID_INFO)); _sOID = pHashAlgInfo2.pszOID ; return UConsts.S_OK; } } finally { Marshal.FreeHGlobal(hDataAlg); } } // 3)   -  _sError = UCConsts.S_NO_ENCODE_ALG_ERR; return UConsts.E_CRYPTO_ERR; } catch (Exception E) { _sError = UCConsts.S_DETERM_ENCODE_ALG_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; }finally { if((hCrypto != IntPtr.Zero) && fNeedRelease) UCryptoAPI.CryptReleaseContext(hCrypto, 0); } } 

. ( , , , .), . (UCConsts.CRYPT_ENCRYPT_ALG_OID_GROUP_ID). — .


( ).



, , . . — , :


 /**<summary> </summary> * <param name="_arInput">  </param> * <param name="_arRes"></param> * <param name="_sError">   </param> * <param name="_pCert"></param> * <returns>  ,  UCOnsts.S_OK   </returns> * **/ public static int DecryptDataCP(byte[] _arInput, out X509Certificate2 _pCert, out byte[] _arRes, ref string _sError) { _arRes = new byte[0]; _pCert = null; IntPtr hSysStore = UCryptoAPI.CertOpenSystemStore(IntPtr.Zero, UCConsts.AR_CRYPTO_STORE_NAME[(int)StoreName.My]); GCHandle GC = GCHandle.Alloc(hSysStore, GCHandleType.Pinned); IntPtr hOutCertL = IntPtr.Zero; IntPtr hOutCert = IntPtr.Zero; try { // 0)   CRYPT_DECRYPT_MESSAGE_PARA pParams = new CRYPT_DECRYPT_MESSAGE_PARA(); pParams.dwMsgAndCertEncodingType = UCConsts.PKCS_7_OR_X509_ASN_ENCODING; pParams.cCertStore = 1; pParams.rghCertStore = GC.AddrOfPinnedObject(); pParams.cbSize = Marshal.SizeOf(pParams); int iLen = 0; // 1)     if (!UCryptoAPI.CryptDecryptMessage(ref pParams, _arInput, _arInput.Length, null, ref iLen, ref hOutCertL)) { _sError = UCConsts.S_DECRYPT_LEN_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } // 2)    _arRes = new byte[iLen]; if (!UCryptoAPI.CryptDecryptMessage(ref pParams, _arInput, _arInput.Length, _arRes, ref iLen, ref hOutCert)) { _sError = UCConsts.S_DECRYPT_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } // 3)     if (hOutCert != IntPtr.Zero) _pCert = new ISDP_X509Cert(hOutCert); if(_pCert != null) hOutCert = IntPtr.Zero; //    return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_DECRYPT_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if (hOutCertL != IntPtr.Zero) UCryptoAPI.CertFreeCertificateContext(hOutCertL); if (hOutCert != IntPtr.Zero) UCryptoAPI.CertFreeCertificateContext(hOutCert); GC.Free(); UCryptoAPI.CertCloseStore(hSysStore, 0); } } 

, . , ( Linux ).



, , , , . , . :


  1. ( , , . .);
  2. — ;
  3. — ;
  4. , , (CRL);

, .


كما هو واضح من المقدمة ، فإن التحقق من صحة الصلاحية هو واحد من أصعب المهام. هذا هو السبب في أن المكتبة لديها الكثير من الطرق لتنفيذ كل عنصر على حدة. لذلك ، من أجل البساطة ، ننتقل إلى مصادر .Net لأسلوب X509Certificate2.Verify () ونأخذها كأساس.


يتكون التحقق من مرحلتين:
  1. تشكيل سلسلة من الشهادات وصولاً إلى الجذر ؛
  2. تحقق من كل الشهادات الموجودة فيه (للإلغاء ، والوقت ، وما إلى ذلك) ؛

يجب أن يتم هذا التحقق قبل التوقيع والتشفير في التاريخ الحالي ، وفي وقت التحقق من التوقيع في تاريخ التوقيع. طريقة التحقق نفسها صغيرة:


التحقق من الشهادة
 /**<summary> </summary> * <param name="_iRevFlag"> </param> * <param name="_iRevMode"> </param> * <param name="_hPolicy">   </param> * <param name="_hCert"> </param> * <param name="_iCTLTimeout">   </param> * <param name="_rOnDate"> </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int VerifyCertificate (IntPtr _hCert, X509RevocationMode _iRevMode, X509RevocationFlag _iRevFlag, DateTime _rOnDate, TimeSpan _iCTLTimeout, IntPtr _hPolicy, ref string _sError) { if (_hCert == IntPtr.Zero) { _sError = UCConsts.S_CRYPTO_CERT_CHECK_ERR; return UConsts.E_NO_CERTIFICATE; } CERT_CHAIN_POLICY_PARA pPolicyParam = new CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_PARA))); CERT_CHAIN_POLICY_STATUS pPolicyStatus = new CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_STATUS))); // 1)   IntPtr hChain = IntPtr.Zero; try { int iRes = BuildChain(new IntPtr(UCConsts.HCCE_CURRENT_USER), _hCert, __iRevMode, _iRevFlag, _rOnDate, _iCTLTimeout, ref hChain, ref _sError); if (iRes != UConsts.S_OK) return iRes; // 2)   if (UCryptoAPI.CertVerifyCertificateChainPolicy(_hPolicy, hChain, ref pPolicyParam, ref pPolicyStatus)) { if (pPolicyStatus.dwError != 0) { _sError = UCConsts.S_CRYPTO_CHAIN_CHECK_ERR.Frm(pPolicyStatus.dwError); return UConsts.E_CRYPTO_ERR; } } else{ _sError = UCConsts.S_CRYPTO_CHAIN_CHECK_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } return UConsts.S_OK; } catch (Exception E) { _sError = UCConsts.S_CRYPTO_CERT_VERIFY_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { if(hChain != IntPtr.Zero) UCryptoAPI.CertFreeCertificateChain(hChain); } } 

أولاً ، يتم تشكيل سلسلة باستخدام طريقة BuildChain ، ومن ثم يتم فحصها. أثناء تشكيل السلسلة ، يتم تشكيل هيكل المعلمات وتاريخ التحقق وعلامات الاختيار:


 /**<summary>    </summary> * <param name="_hChain">  </param> * <param name="_iRevFlag"> </param> * <param name="_iRevMode"> </param> * <param name="_hChainEngine"> </param> * <param name="_hCert"> </param> * <param name="_rCTLTimeOut">   </param> * <param name="_rOnDate"> </param> * <param name="_sError">   </param> * <returns>  ,  UConsts.S_OK   </returns> * **/ internal static int BuildChain (IntPtr _hChainEngine, IntPtr _hCert, X509RevocationMode _iRevMode, X509RevocationFlag _iRevFlag, DateTime _rOnDate, TimeSpan _rCTLTimeOut, ref IntPtr _hChain, ref string _sError) { // 0)    if (_hCert == IntPtr.Zero) { _sError = UCConsts.S_CRYPTO_CERT_CHAIN_ERR; return UConsts.E_NO_CERTIFICATE; } // 1)  CERT_CHAIN_PARA pChainParams = new CERT_CHAIN_PARA(); pChainParams.cbSize = (uint) Marshal.SizeOf(pChainParams); IntPtr hAppPolicy = IntPtr.Zero; IntPtr hCertPolicy = IntPtr.Zero; try { // 2)    pChainParams.dwUrlRetrievalTimeout = (uint)Math.Floor(_rCTLTimeOut.TotalMilliseconds); // 3)   FILETIME pVerifyTime = new FILETIME(_rOnDate.ToFileTime()); // 4)   uint _iFlags = MapRevocationFlags(_iRevMode, _iRevFlag); // 5)   if (!UCryptoAPI.CertGetCertificateChain(_hChainEngine, _hCert, ref pVerifyTime, IntPtr.Zero, ref pChainParams, _iFlags, IntPtr.Zero, ref _hChain)) { _sError = UCConsts.S_CRYPTO_CHAIN_BUILD_ERR.Frm(Marshal.GetLastWin32Error()); return UConsts.E_CRYPTO_ERR; } } catch(Exception E) { _sError = UCConsts.S_CRYPTO_CHAIN_GEN_ERR.Frm(E.Message); return UConsts.E_GEN_EXCEPTION; } finally { Marshal.FreeHGlobal(hAppPolicy); Marshal.FreeHGlobal(hCertPolicy); } return UConsts.S_OK; } 

, Microsoft. hCertPolicy hAppPolicy OID-, , . , , .


(, ).


MapRevocationFlags — .Net — uint .


الخلاصة


:


  1. 10 ;
  2. ;
  3. byte[] {1, 2, 3, 4, 5};
  4. ;
  5. ;
  6. byte[] {1, 2, 3, 4, 5};
  7. ;

Windows Linux 1-, 10- 50- , Linux . Linux - - ( , ), «» . (deadlock-) ( «Access Violation»).


UCryptoAPI . fpCPSection object :


 private static object fpCPSection = new object(); /**<summary> </summary> * <param name="_hCryptMsg">  </param> * **/ internal static bool CryptMsgClose(IntPtr _hCryptMsg) { lock (pCPSection) { if (fIsLinux) return LCryptoAPI.CryptMsgClose(_hCryptMsg); else return WCryptoAPI.CryptMsgClose(_hCryptMsg); } } /**<summary>     </summary>**/ public static object pCPSection { get { return fpCPSection;} } 

, Linux- .


mono Issuer Subject . , , mono X500DistinguishedName . , mono ( ), (impl.issuerName impl.subjectName). (Reflection) X500DistinguishedName, CERT_CONTEXT .


المراجع


  1. CAPILite
  2. c #
  3. .Net:
    1. CAPIBase
    2. X509Certificate2
    3. SignedCMS
    4. SignerInfo

  4. mono:
    1. X509Certificate2
    2. X509CertificateImplBtls

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


All Articles