OpenSSL mit Mono verbinden

In einem früheren Artikel wurde der Prozess der Integration der GOST-Zertifikate von CryptoPro in Mono beschrieben. Ebenso beschäftigen wir uns mit der Verbindung von RSA-Zertifikaten.


Wir haben weiterhin eines unserer in C # geschriebenen Serversysteme auf Linux portiert, und die Warteschlange hat den RSA-bezogenen Teil erreicht. Wenn die Schwierigkeiten beim Verbinden beim letzten Mal leicht durch das Zusammenspiel zweier Systeme erklärt werden konnten, die ursprünglich nicht miteinander verbunden waren, erwartete niemand beim Verbinden von „normalen“ RSA-Zertifikaten von Mono einen Haken.



Die Installation des Zertifikats und des Schlüssels verursachte keine Probleme, und das System sah es sogar im Standardspeicher. Es war jedoch nicht mehr möglich, Daten aus einer zuvor generierten Signatur zu signieren, zu verschlüsseln oder zu extrahieren - mono fiel mit einem Fehler stabil aus. Ich musste, wie im Fall von CryptoPro, eine direkte Verbindung zur Verschlüsselungsbibliothek herstellen. Für RSA-Zertifikate unter Linux ist OpenSSL der Hauptkandidat für eine solche Verbindung.


Installation des Zertifikats


Glücklicherweise verfügt Centos 7 über eine integrierte Version von OpenSSL - 1.0.2k. Um keine zusätzlichen Schwierigkeiten in das System einzuführen, haben wir uns entschlossen, eine Verbindung zu dieser Version herzustellen. Mit OpenSSL können Sie jedoch spezielle Datei-Zertifikatspeicher erstellen:


  1. Ein solches Geschäft enthält Zertifikate und CRLs, keine privaten Schlüssel. In diesem Fall müssen sie separat gespeichert werden.
  2. Das Speichern von Zertifikaten und privaten Schlüsseln in Windows auf einer Festplatte in unsicherer Form ist „extrem unsicher“ (die Verantwortlichen für digitale Sicherheit beschreiben dies normalerweise umfangreicher und weniger zensiert). Um ehrlich zu sein, ist dies unter Linux nicht sehr sicher, aber in der Tat üblich üben;
  3. Die Koordination des Speicherorts solcher Repositorys unter Windows und Linux ist recht problematisch.
  4. Im Falle einer manuellen Implementierung des Speichers ist ein Dienstprogramm erforderlich, um den Satz von Zertifikaten zu verwalten.
  5. mono selbst verwendet Festplattenspeicher mit einer OpenSSL-Struktur und speichert private Schlüssel in offener Form in der Nähe.

Aus diesen Gründen verwenden wir die Standardspeicher für .NET- und Mono-Zertifikate, um OpenSSL zu verbinden. Unter Linux müssen dazu zunächst das Zertifikat und der private Schlüssel im Mono-Repository abgelegt werden.

Installation des Zertifikats
Wir werden hierfür das Standarddienstprogramm certmgr verwenden. Installieren Sie zunächst den privaten Schlüssel von pfx:

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

Dann legen wir das Zertifikat von diesem pfx ab, der private Schlüssel stellt automatisch eine Verbindung dazu her:

certmgr -add -c My {cer file}

Wenn Sie den Schlüssel im Speicher des Computers installieren möchten, müssen Sie die Option -m hinzufügen.

Danach kann das Zertifikat im Repository angezeigt werden:

certmgr -list -c -v My

Achten Sie auf die Ausstellung. Es ist zu beachten, dass das Zertifikat für das System sichtbar ist und an den zuvor heruntergeladenen privaten Schlüssel gebunden ist. Danach können Sie mit der Verbindung im Code fortfahren.

Verbindung im Code


Wie beim letzten Mal sollte das System, obwohl es auf Linux portiert wurde, weiterhin in der Windows-Umgebung funktionieren. Daher sollte die Arbeit mit Kryptographie äußerlich mit allgemeinen Methoden der Form „Byte [] SignData (Byte [] _arData, X509Certificate2 _pCert)“ durchgeführt werden, die sowohl unter Linux als auch unter Windows gleich funktionieren sollten.


Idealerweise sollte es Methoden geben, die genau wie unter Windows funktionieren - unabhängig vom Zertifikatstyp (unter Linux über OpenSSL oder CryptoPro je nach Zertifikat und unter Windows über crypt32).


Die Analyse der OpenSSL-Bibliotheken ergab, dass unter Windows die Hauptbibliothek "libeay32.dll" und unter Linux "libcrypto.so.10" lautet. Wie beim letzten Mal bilden wir zwei Klassen WOpenSSLAPI und LOpenSSLAPI, die eine Liste von Bibliotheksbibliotheksmethoden enthalten:

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

Beachten Sie im Gegensatz zu CryptoPro die Aufrufkonvention - hier muss sie explizit angegeben werden. Die Syntax zum Verbinden der einzelnen Methoden muss dieses Mal unabhängig basierend auf * .h OpenSSL-Quelldateien generiert werden .


Die Grundregeln zum Generieren der Aufrufsyntax in C # basierend auf Daten aus .h-Dateien lauten wie folgt:


  1. alle Links zu Strukturen, Zeichenfolgen usw. - IntPtr, einschließlich Links innerhalb der Strukturen selbst;
  2. Links zu Links - Ref IntPtr, wenn diese Option nicht funktioniert, dann nur IntPtr. In diesem Fall muss der Link selbst manuell eingefügt und entfernt werden.
  3. Arrays - Byte [];
  4. long in C (OpenSSL) ist ein int in C # (ein kleiner Fehler kann auf den ersten Blick zu stundenlangem Suchen nach der Quelle unvorhersehbarer Fehler werden);

In der Deklaration können Sie aus Gewohnheit SetLastError = true angeben, die Bibliothek ignoriert dies jedoch - Fehler sind über Marshal.GetLastWin32Error () nicht verfügbar. OpenSSL verfügt über eigene Methoden für den Zugriff auf Fehler.


Und dann bilden wir die bereits bekannte statische Klasse „UOpenSSLAPI“, die je nach System die Methode einer von zwei Klassen aufruft:


 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); } } 

Wir stellen sofort fest, dass ein kritischer Abschnitt vorhanden ist. OpenSSL bietet theoretisch Arbeit in einer Multithread-Umgebung. Zunächst wird jedoch in der Beschreibung gesagt, dass dies nicht garantiert ist:


Sie können die meisten Objekte jedoch nicht gleichzeitig in mehreren Threads verwenden.

Und zweitens ist die Verbindungsmethode nicht die trivialste. Die übliche Zwei-Kern-VM (Server mit dem Intel Xeon E5649-Prozessor im Hyper-Threading-Modus) liefert bei Verwendung eines solchen kritischen Abschnitts etwa 100 vollständige Zyklen (siehe Testalgorithmus aus dem vorherigen Artikel ) oder 600 Signaturen pro Sekunde, was für die meisten Aufgaben grundsätzlich ausreicht ( Bei starker Belastung wird ohnehin die Microservice- oder Knotenarchitektur des Systems verwendet.


OpenSSL initialisieren und entladen


Im Gegensatz zu CryptoPro erfordert OpenSSL bestimmte Aktionen, bevor Sie es verwenden und nachdem Sie die Arbeit mit der Bibliothek beendet haben:

 /**<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(); } 


Fehlerinformationen


OpenSSL speichert Fehlerinformationen in internen Strukturen, für die es spezielle Methoden in der Bibliothek gibt. Leider sind einige der einfachen Methoden, wie z. B. ERR_error_string, instabil, sodass Sie komplexere Methoden verwenden müssen:


Fehlerinformationen abrufen
 /**<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()); } 

Ein Fehler in OpenSSL enthält Informationen über die Bibliothek, in der er aufgetreten ist, die Methode und den Grund. Nach Erhalt des Fehlercodes selbst müssen daher alle drei Teile separat extrahiert und in einer Textzeile zusammengefasst werden. Die Länge jeder Zeile beträgt laut OpenSSL- Dokumentation nicht mehr als 120 Zeichen. Da wir verwalteten Code verwenden, müssen wir die Zeile sorgfältig aus dem Link extrahieren:


Abrufen eines Strings durch 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 ""; } } 

Fehler beim Überprüfen von Zertifikaten fallen nicht in die allgemeine Liste und müssen je nach Überprüfungskontext mit einer separaten Methode extrahiert werden:


Zertifikatüberprüfungsfehler erhalten
 /**<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)); } 

Zertifikatsuche


Wie immer beginnt die Kryptografie mit einer Zertifikatsuche. Wir verwenden Vollzeitspeicher, daher suchen wir mit regulären Methoden:


Zertifikatsuche
 /**<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(); } } } 

Achten Sie auf den kritischen Abschnitt. Mono mit Zertifikaten funktioniert auch über OpenSSL, jedoch nicht über UOpenSSLAPI. Wenn Sie dies hier nicht tun, können unter Last Speicherlecks und unverständliche Fehler auftreten.


Das Hauptmerkmal ist die Erstellung eines Zertifikats. Im Gegensatz zur Version für CryptoPro erhalten wir in diesem Fall das Zertifikat selbst (X509Certificate2) aus dem Store, und der Link in Handle darin ist bereits auf die OpenSSL-Struktur X509_st gerichtet. Es scheint notwendig zu sein, aber es gibt keinen Zeiger auf EVP_PKEY (Link zur privaten Schlüsselstruktur in OpenSSL) im Zertifikat.

Wie sich herausstellte, wird der private Schlüssel selbst im internen Feld des Zertifikats - impl / fallback / _cert / _rsa / rsa - gespeichert. Dies ist die RSAManaged-Klasse, und ein kurzer Blick auf ihren Code (z. B. die DecryptValue- Methode) zeigt, wie schlecht Mono mit Kryptografie ist. Anstatt OpenSSL-Kryptografietechniken ehrlich zu verwenden, scheinen sie mehrere Algorithmen manuell implementiert zu haben. Diese Annahme wird durch ein leeres Suchergebnis für ihr Projekt für OpenSSL-Methoden wie CMS_final, CMS_sign oder CMS_ContentInfo_new unterstützt. Und ohne sie ist die Bildung einer Standard-CMS-Signaturstruktur kaum vorstellbar. Gleichzeitig wird die Arbeit mit Zertifikaten teilweise über OpenSSL ausgeführt.


Dies bedeutet, dass der private Schlüssel von Mono entladen und über PEM in EVP_PKEY geladen werden muss. Aus diesem Grund benötigen wir erneut den Klassenerben von X509Certificate, in dem alle zusätzlichen Links gespeichert werden.


Hier sind nur Versuche, wie im Fall von CryptoPro, ein neues Zertifikat aus Handle zu erstellen - führen ebenfalls nicht zum Erfolg (Mono stürzt mit einem Fehler ab), und das Erstellen auf der Grundlage des empfangenen Zertifikats führt zu Speicherverlusten. Daher besteht die einzige Möglichkeit darin, ein Zertifikat basierend auf einem Byte-Array mit pem zu erstellen. Das PEM-Zertifikat kann wie folgt erworben werden:


Erhalt eines PEM-Zertifikats
 /**<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; } } 

Das Zertifikat wird ohne privaten Schlüssel erhalten und wir verbinden es selbst und bilden ein separates Feld für einen Link zu ENV_PKEY:


Generieren von ENV_PKEY basierend auf dem privaten PEM-Schlüssel
 /**<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); } } 

Beim Hochladen des privaten Schlüssels in PEM ist die Aufgabe viel komplizierter als das PEM-Zertifikat, wird jedoch hier bereits beschrieben. Beachten Sie, dass das Entladen des privaten Schlüssels ein „äußerst unsicheres“ Geschäft ist und dies in jeder Hinsicht vermieden werden sollte. Und da ein solches Entladen für die Arbeit mit OpenSSL erforderlich ist, ist es unter Windows besser, die crypt32.dll-Methoden oder reguläre .Net-Klassen zu verwenden, wenn Sie diese Bibliothek verwenden. Unter Linux muss man vorerst so arbeiten.


Es ist auch zu beachten, dass die generierten Links einen nicht verwalteten Speicherbereich anzeigen und freigegeben werden müssen. Weil in .Net 4.5 ist X509Certificate2 nicht verfügbar, dann müssen Sie dies im Destruktor tun


Unterschreiben


Um OpenSSL zu signieren, können Sie die vereinfachte CMS_sign-Methode verwenden. Bei der Auswahl eines Algorithmus wird jedoch eine Konfigurationsdatei verwendet, die für alle Zertifikate gleich ist. Daher ist es besser, sich auf den Code dieser Methode zu verlassen, um eine ähnliche Signaturgenerierung zu implementieren:


Datensignatur
 /**<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); } } 

Der Fortschritt des Algorithmus ist wie folgt. Konvertieren Sie zunächst das eingehende Zertifikat (falls es sich um X509Certificate2 handelt) in unseren Typ. Weil Da wir mit Links zu einem nicht verwalteten Speicherbereich arbeiten, müssen wir diese sorgfältig überwachen. Einige Zeit, nachdem der Link zum Zertifikat außerhalb des Gültigkeitsbereichs liegt, wird der Destruktor gestartet. Und darin haben wir bereits genau die Methoden vorgeschrieben, die erforderlich sind, um den gesamten damit verbundenen nicht verwalteten Speicher zu löschen. Dieser Ansatz ermöglicht es uns, keine Zeit damit zu verschwenden, diese Links direkt innerhalb der Methode zu verfolgen.


Nachdem wir uns mit dem Zertifikat befasst haben, bilden wir ein BIO mit Daten und einer Signaturstruktur. Dann fügen wir die Daten des Unterzeichners hinzu, setzen das Flag zum Trennen der Signatur und beginnen mit der endgültigen Bildung der Signatur. Das Ergebnis wird an BIO übertragen. Es bleibt nur ein Array von Bytes aus dem BIO zu extrahieren. Das Konvertieren von BIO in eine Reihe von Bytes und umgekehrt wird häufig verwendet. Es ist daher besser, sie in eine separate Methode zu setzen:


BIO in Byte [] und umgekehrt
 /**<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; } 

Wie bei CryptoPro müssen Informationen zum Signatur-Hashing-Algorithmus aus dem Zertifikat extrahiert werden. Bei OpenSSL wird es jedoch direkt im Zertifikat gespeichert:


Abrufen eines Hash-Algorithmus
 /**<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); } 

Die Methode stellte sich als ziemlich schwierig heraus, aber sie funktioniert. Sie finden die Methode EVP_get_digestbynid in der Dokumentation 1.0.2, die Bibliotheken der von uns verwendeten Version exportieren sie jedoch nicht. Deshalb bilden wir zuerst nid und auf seiner Basis einen Kurznamen. Und bereits mit einem Kurznamen können Sie den Algorithmus auf die normale Weise extrahieren, indem Sie nach Namen suchen.


Überprüfung der Unterschrift


Die empfangene Unterschrift muss überprüft werden. OpenSSL überprüft die Signatur wie folgt:


Überprüfung der Unterschrift
 /**<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); } } 

Zunächst werden die Signaturdaten vom Byte-Array in die CMS-Struktur konvertiert:


Bildung der CMS-Struktur
 /**<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); } 

, .


Fazit


, . X509Certificate2 (mono) . .


, Windows . . Linux , , .


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


Referenzen


  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/de423769/


All Articles