diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4be638a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+################################################################################
+# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
+################################################################################
+
+/src/S7CommPlusDriver/Properties/PublishProfiles
diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json
new file mode 100644
index 0000000..f8b4888
--- /dev/null
+++ b/.vs/ProjectSettings.json
@@ -0,0 +1,3 @@
+{
+ "CurrentProjectSetting": null
+}
\ No newline at end of file
diff --git a/.vs/S7CommPlusDriver.slnx/FileContentIndex/dd4427cc-38fe-4a63-a882-9426dd5ac3be.vsidx b/.vs/S7CommPlusDriver.slnx/FileContentIndex/dd4427cc-38fe-4a63-a882-9426dd5ac3be.vsidx
new file mode 100644
index 0000000..56e70fc
Binary files /dev/null and b/.vs/S7CommPlusDriver.slnx/FileContentIndex/dd4427cc-38fe-4a63-a882-9426dd5ac3be.vsidx differ
diff --git a/.vs/S7CommPlusDriver.slnx/v18/.wsuo b/.vs/S7CommPlusDriver.slnx/v18/.wsuo
new file mode 100644
index 0000000..1987275
Binary files /dev/null and b/.vs/S7CommPlusDriver.slnx/v18/.wsuo differ
diff --git a/.vs/S7CommPlusDriver.slnx/v18/DocumentLayout.backup.json b/.vs/S7CommPlusDriver.slnx/v18/DocumentLayout.backup.json
new file mode 100644
index 0000000..da41b02
--- /dev/null
+++ b/.vs/S7CommPlusDriver.slnx/v18/DocumentLayout.backup.json
@@ -0,0 +1,12 @@
+{
+ "Version": 1,
+ "WorkspaceRootPath": "C:\\Users\\Admin\\source\\repos\\trupa\\S7CommPlusDriver\\",
+ "Documents": [],
+ "DocumentGroupContainers": [
+ {
+ "Orientation": 0,
+ "VerticalTabListWidth": 256,
+ "DocumentGroups": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vs/S7CommPlusDriver.slnx/v18/DocumentLayout.json b/.vs/S7CommPlusDriver.slnx/v18/DocumentLayout.json
new file mode 100644
index 0000000..da41b02
--- /dev/null
+++ b/.vs/S7CommPlusDriver.slnx/v18/DocumentLayout.json
@@ -0,0 +1,12 @@
+{
+ "Version": 1,
+ "WorkspaceRootPath": "C:\\Users\\Admin\\source\\repos\\trupa\\S7CommPlusDriver\\",
+ "Documents": [],
+ "DocumentGroupContainers": [
+ {
+ "Orientation": 0,
+ "VerticalTabListWidth": 256,
+ "DocumentGroups": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json
new file mode 100644
index 0000000..08213a0
--- /dev/null
+++ b/.vs/VSWorkspaceState.json
@@ -0,0 +1,8 @@
+{
+ "ExpandedNodes": [
+ "",
+ "\\src"
+ ],
+ "SelectedNode": "\\src\\S7CommPlusDriver.slnx",
+ "PreviewInSolutionExplorer": false
+}
\ No newline at end of file
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
new file mode 100644
index 0000000..d9c4276
Binary files /dev/null and b/.vs/slnx.sqlite differ
diff --git a/src/S7CommPlusDriver/Net/S7Client.cs b/src/S7CommPlusDriver/Net/S7Client.cs
index 28fa468..22a61ab 100644
--- a/src/S7CommPlusDriver/Net/S7Client.cs
+++ b/src/S7CommPlusDriver/Net/S7Client.cs
@@ -1,147 +1,157 @@
-#region License
-/******************************************************************************
- * S7CommPlusDriver
- *
- * Based on Snap7 (Sharp7.cs) by Davide Nardella licensed under LGPL
- *
- /****************************************************************************/
-#endregion
-
-using OpenSsl;
-using System;
-using System.IO;
-using System.Threading;
-
-namespace S7CommPlusDriver
-{
- // Teilweise basierend auf Snap7 (Sharp7.cs) von Davide Nardella
- // | Sharp7 is free software: you can redistribute it and/or modify |
- // | it under the terms of the Lesser GNU General Public License as published by |
- // | the Free Software Foundation, either version 3 of the License, or |
- // | (at your option) any later version. |
- public class S7Client : OpenSSLConnector.IConnectorCallback
- {
- //TODO: better API, maybe a Callback
+#region License
+/******************************************************************************
+ * S7CommPlusDriver
+ *
+ * Based on Snap7 (Sharp7.cs) by Davide Nardella licensed under LGPL
+ *
+ /****************************************************************************/
+#endregion
+
+using OpenSsl;
+using System;
+using System.IO;
+using System.Threading;
+
+namespace S7CommPlusDriver
+{
+ // Teilweise basierend auf Snap7 (Sharp7.cs) von Davide Nardella
+ // | Sharp7 is free software: you can redistribute it and/or modify |
+ // | it under the terms of the Lesser GNU General Public License as published by |
+ // | the Free Software Foundation, either version 3 of the License, or |
+ // | (at your option) any later version. |
+ public class S7Client : OpenSSLConnector.IConnectorCallback
+ {
+ //TODO: better API, maybe a Callback
public static bool WriteSslKeyToFile;
public static string WriteSslKeyPath;
- #region [Constants and TypeDefs]
-
- public int _LastError = 0;
-
- #endregion
-
- #region [S7 Telegrams]
-
- // ISO Connection Request telegram (contains also ISO Header and COTP Header)
- byte[] ISO_CR = {
- // TPKT (RFC1006 Header)
- 0x03, // RFC 1006 ID (3)
- 0x00, // Reserved, always 0
- 0x00, // High part of packet lenght (entire frame, payload and TPDU included)
- 0x24, // Low part of packet lenght (entire frame, payload and TPDU included)
- // COTP (ISO 8073 Header)
- 0x1f, // PDU Size Length
- 0xE0, // CR - Connection Request ID
- 0x00, // Dst Reference HI
- 0x00, // Dst Reference LO
- 0x00, // Src Reference HI
- 0x01, // Src Reference LO
- 0x00, // Class + Options Flags
- 0xC0, // PDU Max Length ID
- 0x01, // PDU Max Length HI
- 0x0A, // PDU Max Length LO
- 0xC1, // Src TSAP Identifier
- 0x02, // Src TSAP Length (2 bytes)
- 0x01, // Src TSAP HI (will be overwritten)
- 0x00, // Src TSAP LO (will be overwritten)
- 0xC2, // Dst TSAP Identifier
- 0x10, // Dst TSAP Length (16 bytes)
- // Ab hier TSAP ID (String)
- // SIMATIC-ROOT-HMI
- };
-
- // TPKT + ISO COTP Header (Connection Oriented Transport Protocol)
- byte[] TPKT_ISO = { // 7 bytes
- 0x03,0x00,
- 0x00,0x1f, // Telegram Length (Data Size + 31 or 35)
- 0x02,0xf0,0x80 // COTP (see above for info)
- };
-
- #endregion
-
- #region S7commPlus
-
- bool m_SslActive = false;
- Thread m_runThread;
- bool m_runThread_DoStop;
- IntPtr m_ptr_ssl_method;
- IntPtr m_ptr_ctx;
- OpenSSLConnector m_sslconn;
-
- DateTime m_DateTimeStarted;
- Native.SSL_CTX_keylog_cb_func m_keylog_cb;
-
- // OpenSSL möchte Daten auf den Socket aussenden.
- public void WriteData(byte[] pData, int dataLength)
- {
- // SSL fordert Daten zum Absenden an
- // TODO: Was ist, wenn SSL Daten verschicken möchte, die größer als eine TPDU sind?
- // Bei großen Zertifikaten oder ähnlichem? Fragmentierung hier?
- // Console.WriteLine("S7Client - OpenSSL WriteData: dataLength=" + dataLength);
- byte[] sendData = new byte[dataLength];
- Array.Copy(pData, sendData, dataLength);
- SendIsoPacket(sendData);
- }
-
- // OpenSSL meldet fertige Daten (decrypted) zum einlesen
- public void OnDataAvailable()
- {
- // Netzwerk meldet eintreffende Daten
- byte[] buf = new byte[8192];
- int bytesRead = m_sslconn.Receive(ref buf, buf.Length);
- // Console.WriteLine("S7Client - OpenSSL OnDataAvailable: bytesRead=" + bytesRead);
- byte[] readData = new byte[bytesRead];
- Array.Copy(buf, readData, bytesRead);
- OnDataReceived?.Invoke(readData, bytesRead);
- }
-
- // OpenSSL Key Callback Funktion. Gibt die ausgehandelden privaten Schlüssel aus. Kann beispielsweise
- // in eine Wireshark Aufzeichnung eingefügt werden um dort die TLS Kommunikation zu entschlüsseln.
- public void SSL_CTX_keylog_cb(IntPtr ssl, string line)
- {
- string filename = "key_" + m_DateTimeStarted.ToString("yyyyMMdd_HHmmss") + ".log";
+ #region [Constants and TypeDefs]
+
+ public int _LastError = 0;
+
+ #endregion
+
+ #region [S7 Telegrams]
+
+ // ISO Connection Request telegram (contains also ISO Header and COTP Header)
+ byte[] ISO_CR = {
+ // TPKT (RFC1006 Header)
+ 0x03, // RFC 1006 ID (3)
+ 0x00, // Reserved, always 0
+ 0x00, // High part of packet lenght (entire frame, payload and TPDU included)
+ 0x24, // Low part of packet lenght (entire frame, payload and TPDU included)
+ // COTP (ISO 8073 Header)
+ 0x1f, // PDU Size Length
+ 0xE0, // CR - Connection Request ID
+ 0x00, // Dst Reference HI
+ 0x00, // Dst Reference LO
+ 0x00, // Src Reference HI
+ 0x01, // Src Reference LO
+ 0x00, // Class + Options Flags
+ 0xC0, // PDU Max Length ID
+ 0x01, // PDU Max Length HI
+ 0x0A, // PDU Max Length LO
+ 0xC1, // Src TSAP Identifier
+ 0x02, // Src TSAP Length (2 bytes)
+ 0x01, // Src TSAP HI (will be overwritten)
+ 0x00, // Src TSAP LO (will be overwritten)
+ 0xC2, // Dst TSAP Identifier
+ 0x10, // Dst TSAP Length (16 bytes)
+ // Ab hier TSAP ID (String)
+ // SIMATIC-ROOT-HMI
+ };
+
+ // TPKT + ISO COTP Header (Connection Oriented Transport Protocol)
+ byte[] TPKT_ISO = { // 7 bytes
+ 0x03,0x00,
+ 0x00,0x1f, // Telegram Length (Data Size + 31 or 35)
+ 0x02,0xf0,0x80 // COTP (see above for info)
+ };
+
+ #endregion
+
+ #region S7commPlus
+
+ bool m_SslActive = false;
+ Thread m_runThread;
+ bool m_runThread_DoStop;
+ IntPtr m_ptr_ssl_method;
+ IntPtr m_ptr_ctx;
+ OpenSSLConnector m_sslconn;
+
+ DateTime m_DateTimeStarted;
+ Native.SSL_CTX_keylog_cb_func m_keylog_cb;
+
+ // OpenSSL möchte Daten auf den Socket aussenden.
+ public void WriteData(byte[] pData, int dataLength)
+ {
+ // SSL requests data for sending.
+ // We must fragment data that is larger than one TPDU (usually 1024 bytes).
+ const int maxTpduPayload = 900; // Safe value below 1024 to account for headers
+ int offset = 0;
+
+ while (offset < dataLength)
+ {
+ int chunkLength = Math.Min(maxTpduPayload, dataLength - offset);
+ byte[] chunk = new byte[chunkLength];
+ Array.Copy(pData, offset, chunk, 0, chunkLength);
+
+ // If this is the last piece of the original data, set the 'isLast' flag
+ bool isLast = (offset + chunkLength) == dataLength;
+ SendIsoFragment(chunk, isLast);
+
+ offset += chunkLength;
+ }
+ }
+
+ // OpenSSL meldet fertige Daten (decrypted) zum einlesen
+ public void OnDataAvailable()
+ {
+ // Netzwerk meldet eintreffende Daten
+ byte[] buf = new byte[8192];
+ int bytesRead = m_sslconn.Receive(ref buf, buf.Length);
+ // Console.WriteLine("S7Client - OpenSSL OnDataAvailable: bytesRead=" + bytesRead);
+ byte[] readData = new byte[bytesRead];
+ Array.Copy(buf, readData, bytesRead);
+ OnDataReceived?.Invoke(readData, bytesRead);
+ }
+
+ // OpenSSL Key Callback Funktion. Gibt die ausgehandelden privaten Schlüssel aus. Kann beispielsweise
+ // in eine Wireshark Aufzeichnung eingefügt werden um dort die TLS Kommunikation zu entschlüsseln.
+ public void SSL_CTX_keylog_cb(IntPtr ssl, string line)
+ {
+ string filename = "key_" + m_DateTimeStarted.ToString("yyyyMMdd_HHmmss") + ".log";
if (WriteSslKeyPath != null)
- filename = Path.Combine(WriteSslKeyPath, filename);
- StreamWriter file = new StreamWriter(filename, append: true);
- file.WriteLine(line);
- file.Close();
- }
-
- // Startet OpenSSL und aktiviert ab jetzt TLS
- public int SslActivate()
- {
- int ret;
- try
- {
- ret = Native.OPENSSL_init_ssl(0, IntPtr.Zero); // returns 1 on success or 0 on error
- if (ret != 1)
- {
- return S7Consts.errOpenSSL;
- }
- m_ptr_ssl_method = Native.ExpectNonNull(Native.TLS_client_method());
- m_ptr_ctx = Native.ExpectNonNull(Native.SSL_CTX_new(m_ptr_ssl_method));
- // TLS 1.3 forcieren, da wegen TLS on IsoOnTCP bekannt sein muss, um wie viele Bytes sich die verschlüsselten
- // Daten verlängern um die Pakete auf S7CommPlus-Ebene entsprechend zu fragmentieren.
- // Die Verlängerung geschieht z.B. durch Padding und HMAC. Bei TLS 1.3 existiert mit GCM kein Padding und verlängert sich immer
- // um 16 Bytes. Da auch TLS_CHACHA20_POLY1305_SHA256 zu den TLS 1.3 CipherSuite zählt, explizit die anderen setzen.
- Native.SSL_CTX_ctrl(m_ptr_ctx, Native.SSL_CTRL_SET_MIN_PROTO_VERSION, Native.TLS1_3_VERSION, IntPtr.Zero);
- ret = Native.SSL_CTX_set_ciphersuites(m_ptr_ctx, "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256");
- if (ret != 1)
- {
- return S7Consts.errOpenSSL;
- }
- m_sslconn = new OpenSSLConnector(m_ptr_ctx, this);
+ filename = Path.Combine(WriteSslKeyPath, filename);
+ StreamWriter file = new StreamWriter(filename, append: true);
+ file.WriteLine(line);
+ file.Close();
+ }
+
+ // Startet OpenSSL und aktiviert ab jetzt TLS
+ public int SslActivate()
+ {
+ int ret;
+ try
+ {
+ ret = Native.OPENSSL_init_ssl(0, IntPtr.Zero); // returns 1 on success or 0 on error
+ if (ret != 1)
+ {
+ return S7Consts.errOpenSSL;
+ }
+ m_ptr_ssl_method = Native.ExpectNonNull(Native.TLS_client_method());
+ m_ptr_ctx = Native.ExpectNonNull(Native.SSL_CTX_new(m_ptr_ssl_method));
+ // TLS 1.3 forcieren, da wegen TLS on IsoOnTCP bekannt sein muss, um wie viele Bytes sich die verschlüsselten
+ // Daten verlängern um die Pakete auf S7CommPlus-Ebene entsprechend zu fragmentieren.
+ // Die Verlängerung geschieht z.B. durch Padding und HMAC. Bei TLS 1.3 existiert mit GCM kein Padding und verlängert sich immer
+ // um 16 Bytes. Da auch TLS_CHACHA20_POLY1305_SHA256 zu den TLS 1.3 CipherSuite zählt, explizit die anderen setzen.
+ Native.SSL_CTX_ctrl(m_ptr_ctx, Native.SSL_CTRL_SET_MIN_PROTO_VERSION, Native.TLS1_3_VERSION, IntPtr.Zero);
+ ret = Native.SSL_CTX_set_ciphersuites(m_ptr_ctx, "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256");
+ if (ret != 1)
+ {
+ return S7Consts.errOpenSSL;
+ }
+ m_sslconn = new OpenSSLConnector(m_ptr_ctx, this);
m_sslconn.ExpectConnect();
// Keylog callback setzen
@@ -149,573 +159,599 @@ public int SslActivate()
{
m_keylog_cb = new Native.SSL_CTX_keylog_cb_func(SSL_CTX_keylog_cb);
Native.SSL_CTX_set_keylog_callback(m_ptr_ctx, m_keylog_cb);
- }
-
- m_SslActive = true;
- }
- catch
- {
- return S7Consts.errOpenSSL;
- }
- return 0;
- }
-
- // Deaktiviert TLS
- public void SslDeactivate()
- {
- m_SslActive = false;
- // TODO: Ist hier etwas zu OpenSSL-Ressourcen explizit freizugeben?
- }
- #endregion
-
- private void StartThread()
- {
- m_runThread_DoStop = false;
- m_runThread = new Thread(RunThread);
- m_runThread.Start();
- }
-
- // Der Task der kontinuierlich ausgeführt wird
- private void RunThread()
- {
- int Length;
- while (!m_runThread_DoStop)
- {
- // Versuchen zu lesen
- _LastError = 0;
- Length = RecvIsoPacket();
- // TODO: Hier nur den Payload zurückgeben
- if (Length > 0) {
- byte[] Buffer = new byte[Length - TPKT_ISO.Length];
- Array.Copy(PDU, TPKT_ISO.Length, Buffer, 0, Length - TPKT_ISO.Length);
- int Size = Length - TPKT_ISO.Length;
- if (m_SslActive)
- {
- // Durch SSL eingelesene Daten an SSL weiterleiten
- m_sslconn.ReadCompleted(Buffer, Size);
- } else {
- // Wenn etwas gelesen werden konnte, Client benachrichtigen
- OnDataReceived?.Invoke(Buffer, Size);
- }
- }
- }
- }
-
- public _OnDataReceived OnDataReceived;
- public delegate void _OnDataReceived(byte[] PDU, int len);
-
- #region [Internals]
-
- // Defaults
- private static int ISOTCP = 102; // ISOTCP Port
- private static int MinPduSizeToRequest = 240;
- private static int MaxPduSizeToRequest = 960;
- private static int DefaultTimeout = 2000;
- private static int IsoHSize = 7; // TPKT+COTP Header Size
-
- // Properties
- private int _PDULength = 0;
- private int _PduSizeRequested = 480;
- private int _PLCPort = ISOTCP;
- private int _RecvTimeout = DefaultTimeout;
- private int _SendTimeout = DefaultTimeout;
- private int _ConnTimeout = DefaultTimeout;
-
- // Privates
- private string IPAddress;
- private byte LocalTSAP_HI;
- private byte LocalTSAP_LO;
- private byte[] RemoteTSAP_S;
- private byte LastPDUType;
- private byte[] PDU = new byte[2048];
- private MsgSocket Socket = null;
- private int Time_ms = 0;
-
- private void CreateSocket()
- {
- try
- {
- Socket = new MsgSocket();
- Socket.ConnectTimeout = _ConnTimeout;
- Socket.ReadTimeout = _RecvTimeout;
- Socket.WriteTimeout = _SendTimeout;
- }
- catch
- {
- }
- }
-
- private int TCPConnect()
- {
- if (_LastError == 0)
- try
- {
- _LastError = Socket.Connect(IPAddress, _PLCPort);
- }
- catch
- {
- _LastError = S7Consts.errTCPConnectionFailed;
- }
- return _LastError;
- }
-
- private void RecvPacket(byte[] Buffer, int Start, int Size)
- {
- if (Connected)
- _LastError = Socket.Receive(Buffer, Start, Size);
- else
- _LastError = S7Consts.errTCPNotConnected;
- }
-
- private void SendPacket(byte[] Buffer, int Len)
- {
- _LastError = Socket.Send(Buffer, Len);
- }
-
- private void SendPacket(byte[] Buffer)
- {
- if (Connected)
- SendPacket(Buffer, Buffer.Length);
- else
- _LastError = S7Consts.errTCPNotConnected;
- }
-
- public void Send(byte[] Buffer)
- {
- if (m_SslActive)
- {
- m_sslconn.Write(Buffer, Buffer.Length);
- }
- else
- {
- SendIsoPacket(Buffer);
- }
- }
-
- private int SendIsoPacket(byte[] Buffer)
- {
- // Packt die zu sendenden Daten in den Iso-Header ein.
- int Size = Buffer.Length;
- _LastError = 0;
-
- Array.Copy(TPKT_ISO, 0, PDU, 0, TPKT_ISO.Length);
- SetWordAt(PDU, 2, (ushort)(Size + TPKT_ISO.Length));
- try
- {
- Array.Copy(Buffer, 0, PDU, TPKT_ISO.Length, Size);
- }
- catch
- {
- return S7Consts.errIsoInvalidPDU;
- }
- SendPacket(PDU, TPKT_ISO.Length + Size);
-
- return _LastError;
- }
-
- private UInt16 GetWordAt(byte[] Buffer, int Pos)
- {
- return (UInt16)((Buffer[Pos] << 8) | Buffer[Pos + 1]);
- }
-
- private void SetWordAt(byte[] Buffer, int Pos, UInt16 Value)
- {
- Buffer[Pos] = (byte)(Value >> 8);
- Buffer[Pos + 1] = (byte)(Value & 0x00FF);
- }
-
- private int RecvIsoPacket()
- {
- Boolean Done = false;
- int Size = 0;
- while ((_LastError == 0) && !Done)
- {
- // Get TPKT (4 bytes)
- RecvPacket(PDU, 0, 4);
- if (_LastError == 0)
- {
- Size = GetWordAt(PDU, 2);
- // Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes)
- if (Size == IsoHSize)
- RecvPacket(PDU, 4, 3); // Skip remaining 3 bytes and Done is still false
- else
- {
- // TODO: Größe korrekt prüfen
- //if ((Size > _PduSizeRequested + IsoHSize) || (Size < MinPduSize))
- // _LastError = S7Consts.errIsoInvalidPDU;
- //else
- Done = true; // a valid Length !=7 && >16 && <247
- }
- }
- }
- if (_LastError == 0)
- {
- RecvPacket(PDU, 4, 3); // Skip remaining 3 COTP bytes
- LastPDUType = PDU[5]; // Stores PDU Type, we need it
- // Receives the S7 Payload
- RecvPacket(PDU, 7, Size - IsoHSize);
- }
- if (_LastError == 0)
- return Size;
- else
- return 0;
- }
-
- private int ISOConnect()
- {
- int Size;
- byte[] isocon = new byte[ISO_CR.Length + RemoteTSAP_S.Length];
- ISO_CR[16] = LocalTSAP_HI;
- ISO_CR[17] = LocalTSAP_LO;
-
- ISO_CR[3] = (byte)(20 + RemoteTSAP_S.Length);
- ISO_CR[4] = (byte)(15 + RemoteTSAP_S.Length);
- ISO_CR[19] = (byte)RemoteTSAP_S.Length;
-
- Array.Copy(ISO_CR, isocon, 20);
- Array.Copy(RemoteTSAP_S, 0, isocon, 20, RemoteTSAP_S.Length);
-
- // Sends the connection request telegram
- SendPacket(isocon);
- if (_LastError == 0)
- {
- // Gets the reply (if any)
- Size = RecvIsoPacket();
- if (_LastError == 0)
- {
- if (Size == 36)
- {
- if (LastPDUType != (byte)0xD0) // 0xD0 = CC Connection confirm
- _LastError = S7Consts.errIsoConnect;
- }
- else
- _LastError = S7Consts.errIsoInvalidPDU;
- }
- }
- return _LastError;
- }
-
- public byte[] getOMSExporterSecret()
- {
- if (m_sslconn == null) return null;
- return m_sslconn.getOMSExporterSecret();
- }
-
- #endregion
-
- #region [Class Control]
-
- public S7Client()
- {
- m_DateTimeStarted = DateTime.Now;
- CreateSocket();
- }
-
- ~S7Client()
- {
- Disconnect();
- }
-
- public int Connect()
- {
- _LastError = 0;
- Time_ms = 0;
- int Elapsed = Environment.TickCount;
- if (!Connected)
- {
- TCPConnect(); // First stage : TCP Connection
- if (_LastError == 0)
- {
- ISOConnect(); // Second stage : ISOTCP (ISO 8073) Connection
- if (_LastError == 0)
- {
- // _LastError = S7P_InitSSLRequest(); // Third stage : Init SSL Request
- StartThread();
- }
- }
- }
- if (_LastError != 0)
- Disconnect();
- else
- Time_ms = Environment.TickCount - Elapsed;
-
- return _LastError;
- }
-
- public int SetConnectionParams(string Address, ushort LocalTSAP, byte[] RemoteTSAP)
- {
- int LocTSAP = LocalTSAP & 0x0000FFFF;
- IPAddress = Address;
- LocalTSAP_HI = (byte)(LocTSAP >> 8);
- LocalTSAP_LO = (byte)(LocTSAP & 0x00FF);
-
- RemoteTSAP_S = new byte[RemoteTSAP.Length];
- Array.Copy(RemoteTSAP, RemoteTSAP_S, RemoteTSAP.Length);
-
- return 0;
- }
-
- public int Disconnect()
- {
- m_runThread_DoStop = true;
- m_runThread?.Join();
-
- Socket.Close();
-
- return 0;
- }
-
- public int GetParam(Int32 ParamNumber, ref int Value)
- {
- int Result = 0;
- switch (ParamNumber)
- {
- case S7Consts.p_u16_RemotePort:
- {
- Value = PLCPort;
- break;
- }
- case S7Consts.p_i32_PingTimeout:
- {
- Value = ConnTimeout;
- break;
- }
- case S7Consts.p_i32_SendTimeout:
- {
- Value = SendTimeout;
- break;
- }
- case S7Consts.p_i32_RecvTimeout:
- {
- Value = RecvTimeout;
- break;
- }
- case S7Consts.p_i32_PDURequest:
- {
- Value = PduSizeRequested;
- break;
- }
- default:
- {
- Result = S7Consts.errCliInvalidParamNumber;
- break;
- }
- }
- return Result;
- }
-
- // Set Properties for compatibility with Snap7.net.cs
- public int SetParam(Int32 ParamNumber, ref int Value)
- {
- int Result = 0;
- switch (ParamNumber)
- {
- case S7Consts.p_u16_RemotePort:
- {
- PLCPort = Value;
- break;
- }
- case S7Consts.p_i32_PingTimeout:
- {
- ConnTimeout = Value;
- break;
- }
- case S7Consts.p_i32_SendTimeout:
- {
- SendTimeout = Value;
- break;
- }
- case S7Consts.p_i32_RecvTimeout:
- {
- RecvTimeout = Value;
- break;
- }
- case S7Consts.p_i32_PDURequest:
- {
- PduSizeRequested = Value;
- break;
- }
- default:
- {
- Result = S7Consts.errCliInvalidParamNumber;
- break;
- }
- }
- return Result;
- }
-
- #endregion
-
- #region [Info Functions / Properties]
-
- public static string ErrorText(int Error)
- {
- switch (Error)
- {
- case 0: return "OK";
- case S7Consts.errTCPSocketCreation: return "SYS : Error creating the Socket";
- case S7Consts.errTCPConnectionTimeout: return "TCP : Connection Timeout";
- case S7Consts.errTCPConnectionFailed: return "TCP : Connection Error";
- case S7Consts.errTCPReceiveTimeout: return "TCP : Data receive Timeout";
- case S7Consts.errTCPDataReceive: return "TCP : Error receiving Data";
- case S7Consts.errTCPSendTimeout: return "TCP : Data send Timeout";
- case S7Consts.errTCPDataSend: return "TCP : Error sending Data";
- case S7Consts.errTCPConnectionReset: return "TCP : Connection reset by the Peer";
- case S7Consts.errTCPNotConnected: return "CLI : Client not connected";
- case S7Consts.errTCPUnreachableHost: return "TCP : Unreachable host";
- case S7Consts.errIsoConnect: return "ISO : Connection Error";
- case S7Consts.errIsoInvalidPDU: return "ISO : Invalid PDU received";
- case S7Consts.errIsoInvalidDataSize: return "ISO : Invalid Buffer passed to Send/Receive";
- case S7Consts.errCliNegotiatingPDU: return "CLI : Error in PDU negotiation";
- case S7Consts.errCliInvalidParams: return "CLI : invalid param(s) supplied";
- case S7Consts.errCliJobPending: return "CLI : Job pending";
- case S7Consts.errCliTooManyItems: return "CLI : too may items (>20) in multi read/write";
- case S7Consts.errCliInvalidWordLen: return "CLI : invalid WordLength";
- case S7Consts.errCliPartialDataWritten: return "CLI : Partial data written";
- case S7Consts.errCliSizeOverPDU: return "CPU : total data exceeds the PDU size";
- case S7Consts.errCliInvalidPlcAnswer: return "CLI : invalid CPU answer";
- case S7Consts.errCliAddressOutOfRange: return "CPU : Address out of range";
- case S7Consts.errCliInvalidTransportSize: return "CPU : Invalid Transport size";
- case S7Consts.errCliWriteDataSizeMismatch: return "CPU : Data size mismatch";
- case S7Consts.errCliItemNotAvailable: return "CPU : Item not available";
- case S7Consts.errCliInvalidValue: return "CPU : Invalid value supplied";
- case S7Consts.errCliCannotStartPLC: return "CPU : Cannot start PLC";
- case S7Consts.errCliAlreadyRun: return "CPU : PLC already RUN";
- case S7Consts.errCliCannotStopPLC: return "CPU : Cannot stop PLC";
- case S7Consts.errCliCannotCopyRamToRom: return "CPU : Cannot copy RAM to ROM";
- case S7Consts.errCliCannotCompress: return "CPU : Cannot compress";
- case S7Consts.errCliAlreadyStop: return "CPU : PLC already STOP";
- case S7Consts.errCliFunNotAvailable: return "CPU : Function not available";
- case S7Consts.errCliUploadSequenceFailed: return "CPU : Upload sequence failed";
- case S7Consts.errCliInvalidDataSizeRecvd: return "CLI : Invalid data size received";
- case S7Consts.errCliInvalidBlockType: return "CLI : Invalid block type";
- case S7Consts.errCliInvalidBlockNumber: return "CLI : Invalid block number";
- case S7Consts.errCliInvalidBlockSize: return "CLI : Invalid block size";
- case S7Consts.errCliNeedPassword: return "CPU : Function not authorized for current protection level";
- case S7Consts.errCliInvalidPassword: return "CPU : Invalid password";
- case S7Consts.errCliAccessDenied: return "CPU : Access denied";
- case S7Consts.errCliNoPasswordToSetOrClear: return "CPU : No password to set or clear";
- case S7Consts.errCliJobTimeout: return "CLI : Job Timeout";
- case S7Consts.errCliFunctionRefused: return "CLI : function refused by CPU (Unknown error)";
- case S7Consts.errCliPartialDataRead: return "CLI : Partial data read";
- case S7Consts.errCliBufferTooSmall: return "CLI : The buffer supplied is too small to accomplish the operation";
- case S7Consts.errCliDestroying: return "CLI : Cannot perform (destroying)";
- case S7Consts.errCliInvalidParamNumber: return "CLI : Invalid Param Number";
- case S7Consts.errCliCannotChangeParam: return "CLI : Cannot change this param now";
- case S7Consts.errCliFunctionNotImplemented: return "CLI : Function not implemented";
- case S7Consts.errCliFirmwareNotSupported: return "CLI : Firmware not supported";
- case S7Consts.errCliDeviceNotSupported: return "CLI : Device type not supported";
- default: return "CLI : Unknown error (0x" + Convert.ToString(Error, 16) + ")";
- };
- }
-
- public int LastError()
- {
- return _LastError;
- }
-
- public int RequestedPduLength()
- {
- return _PduSizeRequested;
- }
-
- public int NegotiatedPduLength()
- {
- return _PDULength;
- }
-
- public int ExecTime()
- {
- return Time_ms;
- }
-
- public int ExecutionTime
- {
- get
- {
- return Time_ms;
- }
- }
-
- public int PduSizeNegotiated
- {
- get
- {
- return _PDULength;
- }
- }
-
- public int PduSizeRequested
- {
- get
- {
- return _PduSizeRequested;
- }
- set
- {
- if (value < MinPduSizeToRequest)
- value = MinPduSizeToRequest;
- if (value > MaxPduSizeToRequest)
- value = MaxPduSizeToRequest;
- _PduSizeRequested = value;
- }
- }
-
- public int PLCPort
- {
- get
- {
- return _PLCPort;
- }
- set
- {
- _PLCPort = value;
- }
- }
-
- public int ConnTimeout
- {
- get
- {
- return _ConnTimeout;
- }
- set
- {
- _ConnTimeout = value;
- }
- }
-
- public int RecvTimeout
- {
- get
- {
- return _RecvTimeout;
- }
- set
- {
- _RecvTimeout = value;
- }
- }
-
- public int SendTimeout
- {
- get
- {
- return _SendTimeout;
- }
- set
- {
- _SendTimeout = value;
- }
- }
-
- public bool Connected
- {
- get
- {
- return (Socket != null) && (Socket.Connected);
- }
- }
- #endregion
- }
-}
+ }
+
+ m_SslActive = true;
+ }
+ catch
+ {
+ return S7Consts.errOpenSSL;
+ }
+ return 0;
+ }
+
+ // Deaktiviert TLS
+ public void SslDeactivate()
+ {
+ m_SslActive = false;
+ // TODO: Ist hier etwas zu OpenSSL-Ressourcen explizit freizugeben?
+ }
+ #endregion
+
+ private void StartThread()
+ {
+ m_runThread_DoStop = false;
+ m_runThread = new Thread(RunThread);
+ m_runThread.Start();
+ }
+
+ // Der Task der kontinuierlich ausgeführt wird
+ private void RunThread()
+ {
+ int Length;
+ while (!m_runThread_DoStop)
+ {
+ // Versuchen zu lesen
+ _LastError = 0;
+ Length = RecvIsoPacket();
+ // TODO: Hier nur den Payload zurückgeben
+ if (Length > 0) {
+ byte[] Buffer = new byte[Length - TPKT_ISO.Length];
+ Array.Copy(PDU, TPKT_ISO.Length, Buffer, 0, Length - TPKT_ISO.Length);
+ int Size = Length - TPKT_ISO.Length;
+ if (m_SslActive)
+ {
+ // Durch SSL eingelesene Daten an SSL weiterleiten
+ m_sslconn.ReadCompleted(Buffer, Size);
+ } else {
+ // Wenn etwas gelesen werden konnte, Client benachrichtigen
+ OnDataReceived?.Invoke(Buffer, Size);
+ }
+ }
+ }
+ }
+
+ public _OnDataReceived OnDataReceived;
+ public delegate void _OnDataReceived(byte[] PDU, int len);
+
+ #region [Internals]
+
+ // Defaults
+ private static int ISOTCP = 102; // ISOTCP Port
+ private static int MinPduSizeToRequest = 240;
+ private static int MaxPduSizeToRequest = 960;
+ private static int DefaultTimeout = 2000;
+ private static int IsoHSize = 7; // TPKT+COTP Header Size
+
+ // Properties
+ private int _PDULength = 0;
+ private int _PduSizeRequested = 480;
+ private int _PLCPort = ISOTCP;
+ private int _RecvTimeout = DefaultTimeout;
+ private int _SendTimeout = DefaultTimeout;
+ private int _ConnTimeout = DefaultTimeout;
+
+ // Privates
+ private string IPAddress;
+ private byte LocalTSAP_HI;
+ private byte LocalTSAP_LO;
+ private byte[] RemoteTSAP_S;
+ private byte LastPDUType;
+ private byte[] PDU = new byte[2048];
+ private MsgSocket Socket = null;
+ private int Time_ms = 0;
+
+ private void CreateSocket()
+ {
+ try
+ {
+ Socket = new MsgSocket();
+ Socket.ConnectTimeout = _ConnTimeout;
+ Socket.ReadTimeout = _RecvTimeout;
+ Socket.WriteTimeout = _SendTimeout;
+ }
+ catch
+ {
+ }
+ }
+
+ private int TCPConnect()
+ {
+ if (_LastError == 0)
+ try
+ {
+ _LastError = Socket.Connect(IPAddress, _PLCPort);
+ }
+ catch
+ {
+ _LastError = S7Consts.errTCPConnectionFailed;
+ }
+ return _LastError;
+ }
+
+ private void RecvPacket(byte[] Buffer, int Start, int Size)
+ {
+ if (Connected)
+ _LastError = Socket.Receive(Buffer, Start, Size);
+ else
+ _LastError = S7Consts.errTCPNotConnected;
+ }
+
+ // Sends a fragment of data with a TPKT+COTP header. If isLast=true, the End of Transmission flag is set in the COTP header.
+ private void SendIsoFragment(byte[] buffer, bool isLast)
+ {
+ int size = buffer.Length;
+ // TPKT (4 bytes) + COTP (3 bytes) = 7 bytes header
+ byte[] frame = new byte[size + 7];
+
+ // --- TPKT Header ---
+ frame[0] = 0x03; // Version
+ frame[1] = 0x00; // Reserved
+ ushort totalLen = (ushort)(size + 7);
+ frame[2] = (byte)(totalLen >> 8);
+ frame[3] = (byte)(totalLen & 0xFF);
+
+ // --- COTP Header (DT Data) ---
+ frame[4] = 0x02; // Length
+ frame[5] = 0xf0; // PDU Type (Data)
+ // 0x80 = End of transmission (Last Unit), 0x00 = More fragments coming
+ frame[6] = (byte)(isLast ? 0x80 : 0x00);
+
+ Array.Copy(buffer, 0, frame, 7, size);
+
+ // Use your existing SendPacket method to push to the MsgSocket
+ SendPacket(frame, frame.Length);
+ }
+
+ private void SendPacket(byte[] Buffer, int Len)
+ {
+ _LastError = Socket.Send(Buffer, Len);
+ }
+
+ private void SendPacket(byte[] Buffer)
+ {
+ if (Connected)
+ SendPacket(Buffer, Buffer.Length);
+ else
+ _LastError = S7Consts.errTCPNotConnected;
+ }
+
+ public void Send(byte[] Buffer)
+ {
+ if (m_SslActive)
+ {
+ m_sslconn.Write(Buffer, Buffer.Length);
+ }
+ else
+ {
+ SendIsoPacket(Buffer);
+ }
+ }
+
+ private int SendIsoPacket(byte[] Buffer)
+ {
+ // Packt die zu sendenden Daten in den Iso-Header ein.
+ int Size = Buffer.Length;
+ _LastError = 0;
+
+ Array.Copy(TPKT_ISO, 0, PDU, 0, TPKT_ISO.Length);
+ SetWordAt(PDU, 2, (ushort)(Size + TPKT_ISO.Length));
+ try
+ {
+ Array.Copy(Buffer, 0, PDU, TPKT_ISO.Length, Size);
+ }
+ catch
+ {
+ return S7Consts.errIsoInvalidPDU;
+ }
+ SendPacket(PDU, TPKT_ISO.Length + Size);
+
+ return _LastError;
+ }
+
+ private UInt16 GetWordAt(byte[] Buffer, int Pos)
+ {
+ return (UInt16)((Buffer[Pos] << 8) | Buffer[Pos + 1]);
+ }
+
+ private void SetWordAt(byte[] Buffer, int Pos, UInt16 Value)
+ {
+ Buffer[Pos] = (byte)(Value >> 8);
+ Buffer[Pos + 1] = (byte)(Value & 0x00FF);
+ }
+
+ private int RecvIsoPacket()
+ {
+ Boolean Done = false;
+ int Size = 0;
+ while ((_LastError == 0) && !Done)
+ {
+ // Get TPKT (4 bytes)
+ RecvPacket(PDU, 0, 4);
+ if (_LastError == 0)
+ {
+ Size = GetWordAt(PDU, 2);
+ // Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes)
+ if (Size == IsoHSize)
+ RecvPacket(PDU, 4, 3); // Skip remaining 3 bytes and Done is still false
+ else
+ {
+ // TODO: Größe korrekt prüfen
+ //if ((Size > _PduSizeRequested + IsoHSize) || (Size < MinPduSize))
+ // _LastError = S7Consts.errIsoInvalidPDU;
+ //else
+ Done = true; // a valid Length !=7 && >16 && <247
+ }
+ }
+ }
+ if (_LastError == 0)
+ {
+ RecvPacket(PDU, 4, 3); // Skip remaining 3 COTP bytes
+ LastPDUType = PDU[5]; // Stores PDU Type, we need it
+ // Receives the S7 Payload
+ RecvPacket(PDU, 7, Size - IsoHSize);
+ }
+ if (_LastError == 0)
+ return Size;
+ else
+ return 0;
+ }
+
+ private int ISOConnect()
+ {
+ int Size;
+ byte[] isocon = new byte[ISO_CR.Length + RemoteTSAP_S.Length];
+ ISO_CR[16] = LocalTSAP_HI;
+ ISO_CR[17] = LocalTSAP_LO;
+
+ ISO_CR[3] = (byte)(20 + RemoteTSAP_S.Length);
+ ISO_CR[4] = (byte)(15 + RemoteTSAP_S.Length);
+ ISO_CR[19] = (byte)RemoteTSAP_S.Length;
+
+ Array.Copy(ISO_CR, isocon, 20);
+ Array.Copy(RemoteTSAP_S, 0, isocon, 20, RemoteTSAP_S.Length);
+
+ // Sends the connection request telegram
+ SendPacket(isocon);
+ if (_LastError == 0)
+ {
+ // Gets the reply (if any)
+ Size = RecvIsoPacket();
+ if (_LastError == 0)
+ {
+ if (Size == 36)
+ {
+ if (LastPDUType != (byte)0xD0) // 0xD0 = CC Connection confirm
+ _LastError = S7Consts.errIsoConnect;
+ }
+ else
+ _LastError = S7Consts.errIsoInvalidPDU;
+ }
+ }
+ return _LastError;
+ }
+
+ public byte[] getOMSExporterSecret()
+ {
+ if (m_sslconn == null) return null;
+ return m_sslconn.getOMSExporterSecret();
+ }
+
+ #endregion
+
+ #region [Class Control]
+
+ public S7Client()
+ {
+ m_DateTimeStarted = DateTime.Now;
+ CreateSocket();
+ }
+
+ ~S7Client()
+ {
+ Disconnect();
+ }
+
+ public int Connect()
+ {
+ _LastError = 0;
+ Time_ms = 0;
+ int Elapsed = Environment.TickCount;
+ if (!Connected)
+ {
+ TCPConnect(); // First stage : TCP Connection
+ if (_LastError == 0)
+ {
+ ISOConnect(); // Second stage : ISOTCP (ISO 8073) Connection
+ if (_LastError == 0)
+ {
+ // _LastError = S7P_InitSSLRequest(); // Third stage : Init SSL Request
+ StartThread();
+ }
+ }
+ }
+ if (_LastError != 0)
+ Disconnect();
+ else
+ Time_ms = Environment.TickCount - Elapsed;
+
+ return _LastError;
+ }
+
+ public int SetConnectionParams(string Address, ushort LocalTSAP, byte[] RemoteTSAP)
+ {
+ int LocTSAP = LocalTSAP & 0x0000FFFF;
+ IPAddress = Address;
+ LocalTSAP_HI = (byte)(LocTSAP >> 8);
+ LocalTSAP_LO = (byte)(LocTSAP & 0x00FF);
+
+ RemoteTSAP_S = new byte[RemoteTSAP.Length];
+ Array.Copy(RemoteTSAP, RemoteTSAP_S, RemoteTSAP.Length);
+
+ return 0;
+ }
+
+ public int Disconnect()
+ {
+ m_runThread_DoStop = true;
+ m_runThread?.Join();
+
+ Socket.Close();
+
+ return 0;
+ }
+
+ public int GetParam(Int32 ParamNumber, ref int Value)
+ {
+ int Result = 0;
+ switch (ParamNumber)
+ {
+ case S7Consts.p_u16_RemotePort:
+ {
+ Value = PLCPort;
+ break;
+ }
+ case S7Consts.p_i32_PingTimeout:
+ {
+ Value = ConnTimeout;
+ break;
+ }
+ case S7Consts.p_i32_SendTimeout:
+ {
+ Value = SendTimeout;
+ break;
+ }
+ case S7Consts.p_i32_RecvTimeout:
+ {
+ Value = RecvTimeout;
+ break;
+ }
+ case S7Consts.p_i32_PDURequest:
+ {
+ Value = PduSizeRequested;
+ break;
+ }
+ default:
+ {
+ Result = S7Consts.errCliInvalidParamNumber;
+ break;
+ }
+ }
+ return Result;
+ }
+
+ // Set Properties for compatibility with Snap7.net.cs
+ public int SetParam(Int32 ParamNumber, ref int Value)
+ {
+ int Result = 0;
+ switch (ParamNumber)
+ {
+ case S7Consts.p_u16_RemotePort:
+ {
+ PLCPort = Value;
+ break;
+ }
+ case S7Consts.p_i32_PingTimeout:
+ {
+ ConnTimeout = Value;
+ break;
+ }
+ case S7Consts.p_i32_SendTimeout:
+ {
+ SendTimeout = Value;
+ break;
+ }
+ case S7Consts.p_i32_RecvTimeout:
+ {
+ RecvTimeout = Value;
+ break;
+ }
+ case S7Consts.p_i32_PDURequest:
+ {
+ PduSizeRequested = Value;
+ break;
+ }
+ default:
+ {
+ Result = S7Consts.errCliInvalidParamNumber;
+ break;
+ }
+ }
+ return Result;
+ }
+
+ #endregion
+
+ #region [Info Functions / Properties]
+
+ public static string ErrorText(int Error)
+ {
+ switch (Error)
+ {
+ case 0: return "OK";
+ case S7Consts.errTCPSocketCreation: return "SYS : Error creating the Socket";
+ case S7Consts.errTCPConnectionTimeout: return "TCP : Connection Timeout";
+ case S7Consts.errTCPConnectionFailed: return "TCP : Connection Error";
+ case S7Consts.errTCPReceiveTimeout: return "TCP : Data receive Timeout";
+ case S7Consts.errTCPDataReceive: return "TCP : Error receiving Data";
+ case S7Consts.errTCPSendTimeout: return "TCP : Data send Timeout";
+ case S7Consts.errTCPDataSend: return "TCP : Error sending Data";
+ case S7Consts.errTCPConnectionReset: return "TCP : Connection reset by the Peer";
+ case S7Consts.errTCPNotConnected: return "CLI : Client not connected";
+ case S7Consts.errTCPUnreachableHost: return "TCP : Unreachable host";
+ case S7Consts.errIsoConnect: return "ISO : Connection Error";
+ case S7Consts.errIsoInvalidPDU: return "ISO : Invalid PDU received";
+ case S7Consts.errIsoInvalidDataSize: return "ISO : Invalid Buffer passed to Send/Receive";
+ case S7Consts.errCliNegotiatingPDU: return "CLI : Error in PDU negotiation";
+ case S7Consts.errCliInvalidParams: return "CLI : invalid param(s) supplied";
+ case S7Consts.errCliJobPending: return "CLI : Job pending";
+ case S7Consts.errCliTooManyItems: return "CLI : too may items (>20) in multi read/write";
+ case S7Consts.errCliInvalidWordLen: return "CLI : invalid WordLength";
+ case S7Consts.errCliPartialDataWritten: return "CLI : Partial data written";
+ case S7Consts.errCliSizeOverPDU: return "CPU : total data exceeds the PDU size";
+ case S7Consts.errCliInvalidPlcAnswer: return "CLI : invalid CPU answer";
+ case S7Consts.errCliAddressOutOfRange: return "CPU : Address out of range";
+ case S7Consts.errCliInvalidTransportSize: return "CPU : Invalid Transport size";
+ case S7Consts.errCliWriteDataSizeMismatch: return "CPU : Data size mismatch";
+ case S7Consts.errCliItemNotAvailable: return "CPU : Item not available";
+ case S7Consts.errCliInvalidValue: return "CPU : Invalid value supplied";
+ case S7Consts.errCliCannotStartPLC: return "CPU : Cannot start PLC";
+ case S7Consts.errCliAlreadyRun: return "CPU : PLC already RUN";
+ case S7Consts.errCliCannotStopPLC: return "CPU : Cannot stop PLC";
+ case S7Consts.errCliCannotCopyRamToRom: return "CPU : Cannot copy RAM to ROM";
+ case S7Consts.errCliCannotCompress: return "CPU : Cannot compress";
+ case S7Consts.errCliAlreadyStop: return "CPU : PLC already STOP";
+ case S7Consts.errCliFunNotAvailable: return "CPU : Function not available";
+ case S7Consts.errCliUploadSequenceFailed: return "CPU : Upload sequence failed";
+ case S7Consts.errCliInvalidDataSizeRecvd: return "CLI : Invalid data size received";
+ case S7Consts.errCliInvalidBlockType: return "CLI : Invalid block type";
+ case S7Consts.errCliInvalidBlockNumber: return "CLI : Invalid block number";
+ case S7Consts.errCliInvalidBlockSize: return "CLI : Invalid block size";
+ case S7Consts.errCliNeedPassword: return "CPU : Function not authorized for current protection level";
+ case S7Consts.errCliInvalidPassword: return "CPU : Invalid password";
+ case S7Consts.errCliAccessDenied: return "CPU : Access denied";
+ case S7Consts.errCliNoPasswordToSetOrClear: return "CPU : No password to set or clear";
+ case S7Consts.errCliJobTimeout: return "CLI : Job Timeout";
+ case S7Consts.errCliFunctionRefused: return "CLI : function refused by CPU (Unknown error)";
+ case S7Consts.errCliPartialDataRead: return "CLI : Partial data read";
+ case S7Consts.errCliBufferTooSmall: return "CLI : The buffer supplied is too small to accomplish the operation";
+ case S7Consts.errCliDestroying: return "CLI : Cannot perform (destroying)";
+ case S7Consts.errCliInvalidParamNumber: return "CLI : Invalid Param Number";
+ case S7Consts.errCliCannotChangeParam: return "CLI : Cannot change this param now";
+ case S7Consts.errCliFunctionNotImplemented: return "CLI : Function not implemented";
+ case S7Consts.errCliFirmwareNotSupported: return "CLI : Firmware not supported";
+ case S7Consts.errCliDeviceNotSupported: return "CLI : Device type not supported";
+ default: return "CLI : Unknown error (0x" + Convert.ToString(Error, 16) + ")";
+ };
+ }
+
+ public int LastError()
+ {
+ return _LastError;
+ }
+
+ public int RequestedPduLength()
+ {
+ return _PduSizeRequested;
+ }
+
+ public int NegotiatedPduLength()
+ {
+ return _PDULength;
+ }
+
+ public int ExecTime()
+ {
+ return Time_ms;
+ }
+
+ public int ExecutionTime
+ {
+ get
+ {
+ return Time_ms;
+ }
+ }
+
+ public int PduSizeNegotiated
+ {
+ get
+ {
+ return _PDULength;
+ }
+ }
+
+ public int PduSizeRequested
+ {
+ get
+ {
+ return _PduSizeRequested;
+ }
+ set
+ {
+ if (value < MinPduSizeToRequest)
+ value = MinPduSizeToRequest;
+ if (value > MaxPduSizeToRequest)
+ value = MaxPduSizeToRequest;
+ _PduSizeRequested = value;
+ }
+ }
+
+ public int PLCPort
+ {
+ get
+ {
+ return _PLCPort;
+ }
+ set
+ {
+ _PLCPort = value;
+ }
+ }
+
+ public int ConnTimeout
+ {
+ get
+ {
+ return _ConnTimeout;
+ }
+ set
+ {
+ _ConnTimeout = value;
+ }
+ }
+
+ public int RecvTimeout
+ {
+ get
+ {
+ return _RecvTimeout;
+ }
+ set
+ {
+ _RecvTimeout = value;
+ }
+ }
+
+ public int SendTimeout
+ {
+ get
+ {
+ return _SendTimeout;
+ }
+ set
+ {
+ _SendTimeout = value;
+ }
+ }
+
+ public bool Connected
+ {
+ get
+ {
+ return (Socket != null) && (Socket.Connected);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/src/S7CommPlusDriver/OpenSSL/Native.cs b/src/S7CommPlusDriver/OpenSSL/Native.cs
index 3d85084..a689054 100644
--- a/src/S7CommPlusDriver/OpenSSL/Native.cs
+++ b/src/S7CommPlusDriver/OpenSSL/Native.cs
@@ -1,375 +1,420 @@
-#region License
-/******************************************************************************
- * S7CommPlusDriver
- *
- * Copyright (C) 2023 Thomas Wiens, th.wiens@gmx.de
- *
- * This file is part of S7CommPlusDriver.
- *
- * S7CommPlusDriver is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- /****************************************************************************/
-#endregion
-
-using System;
-using System.IO;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace OpenSsl
-{
-
-
- public class Native
+#region License
+/******************************************************************************
+ * S7CommPlusDriver
+ *
+ * Copyright (C) 2023 Thomas Wiens, th.wiens@gmx.de
+ *
+ * This file is part of S7CommPlusDriver.
+ *
+ * S7CommPlusDriver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ /****************************************************************************/
+#endregion
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace OpenSsl
+{
+
+
+ public class Native
{
- const string DLLNAME = "libcrypto-3";
+ const string DLLNAME = "libcrypto-3";
const string SSLDLLNAME = "libssl-3";
static Native()
{
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), DllImportResolver);
}
+
private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
- if (libraryName == DLLNAME)
- {
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.X86)
- return NativeLibrary.Load(Path.Combine("runtimes", "win-x86", "native", "libcrypto-3.dll"), assembly, searchPath);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.X64)
- return NativeLibrary.Load(Path.Combine("runtimes", "win-x64", "native", "libcrypto-3-x64.dll"), assembly, searchPath);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- return NativeLibrary.Load(Path.Combine("runtimes", "win-arm64", "native", "libcrypto-3-arm64.dll"), assembly, searchPath);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- return NativeLibrary.Load("libcrypto.3.dylib", assembly, searchPath);
- return IntPtr.Zero;
- }
+ Console.WriteLine($"[OpenSSL-Debug] Attempting to resolve: {libraryName}");
+ string targetLib = null;
- if(libraryName == SSLDLLNAME)
+ if (libraryName == DLLNAME || libraryName == SSLDLLNAME)
{
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.X86)
- return NativeLibrary.Load(Path.Combine("runtimes", "win-x86", "native", "libssl-3.dll"), assembly, searchPath);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.X64)
- return NativeLibrary.Load(Path.Combine("runtimes", "win-x64", "native", "libssl-3-x64.dll"), assembly, searchPath);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- return NativeLibrary.Load(Path.Combine("runtimes", "win-arm64", "native", "libssl-3-arm64.dll"), assembly, searchPath);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- return NativeLibrary.Load("libssl.3.dylib", assembly, searchPath);
- return IntPtr.Zero;
+ // 1. Handle Windows
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ if (RuntimeInformation.ProcessArchitecture == Architecture.X86)
+ targetLib = Path.Combine("runtimes", "win-x86", "native", libraryName == DLLNAME ? "libcrypto-3.dll" : "libssl-3.dll");
+ else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
+ targetLib = Path.Combine("runtimes", "win-x64", "native", libraryName == DLLNAME ? "libcrypto-3-x64.dll" : "libssl-3-x64.dll");
+ else if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
+ targetLib = Path.Combine("runtimes", "win-arm64", "native", libraryName == DLLNAME ? "libcrypto-3-arm64.dll" : "libssl-3-arm64.dll");
+ }
+ // 2. Handle macOS
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ targetLib = libraryName == DLLNAME ? "libcrypto.3.dylib" : "libssl.3.dylib";
+ }
+ // 3. Handle Linux (Aarch64 / x64)
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ // Linux should find this by name globally.
+ targetLib = libraryName == DLLNAME ? "libcrypto.so.3" : "libssl.so.3";
+ }
+
+ if (targetLib != null)
+ {
+ try
+ {
+ //Console.WriteLine($"[OpenSSL-Debug] Trying NativeLibrary.Load: {targetLib}");
+ IntPtr handle = NativeLibrary.Load(targetLib, assembly, searchPath);
+ //Console.WriteLine($"[OpenSSL-Debug] Successfully loaded: {targetLib} (Handle: {handle})");
+ return handle;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[OpenSSL-Debug] Failed primary load ({targetLib}): {ex.Message}");
+
+ // Fallback attempt for Linux/OSX
+ try
+ {
+ string fallback = libraryName == DLLNAME ? "libcrypto.so" : "libssl.so";
+ //Console.WriteLine($"[OpenSSL-Debug] Attempting fallback: {fallback}");
+ return NativeLibrary.Load(fallback, assembly, searchPath);
+ }
+ catch (Exception ex2)
+ {
+ Console.WriteLine($"[OpenSSL-Debug] Fallback failed: {ex2.Message}");
+ return IntPtr.Zero;
+ }
+ }
+ }
}
- // Otherwise, fallback to default import resolver.
return IntPtr.Zero;
- }
-
- #region Delegates
-
- // typedef void (*SSL_CTX_keylog_cb_func)(const SSL *ssl, const char *line);
- // void SSL_CTX_set_keylog_callback(SSL_CTX* ctx, SSL_CTX_keylog_cb_func cb);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void SSL_CTX_keylog_cb_func(IntPtr ssl, string line);
-
- #endregion
-
- #region OPENSSL
-
- // int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int OPENSSL_init_ssl(UInt64 opts, IntPtr settings);
-
- #endregion
-
- #region SSL
-
- public const int SSL_NOTHING = 1;
- public const int SSL_WRITING = 2;
- public const int SSL_READING = 3;
- public const int SSL_X509_LOOKUP = 4;
- public const int SSL_ASYNC_PAUSED = 5;
- public const int SSL_ASYNC_NO_JOBS = 6;
- public const int SSL_CLIENT_HELLO_CB = 7;
- public const int SSL_RETRY_VERIFY = 8;
-
- public const int SSL_CTRL_GET_CLIENT_CERT_REQUEST = 9;
- public const int SSL_CTRL_GET_NUM_RENEGOTIATIONS = 10;
- public const int SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS = 11;
- public const int SSL_CTRL_GET_TOTAL_RENEGOTIATIONS = 12;
- public const int SSL_CTRL_GET_FLAGS = 13;
- public const int SSL_CTRL_EXTRA_CHAIN_CERT = 14;
- public const int SSL_CTRL_SET_MSG_CALLBACK = 15;
- public const int SSL_CTRL_SET_MSG_CALLBACK_ARG = 16;
- public const int SSL_CTRL_SET_MTU = 17;
- public const int SSL_CTRL_SESS_NUMBER = 20;
- public const int SSL_CTRL_SESS_CONNECT = 21;
- public const int SSL_CTRL_SESS_CONNECT_GOOD = 22;
- public const int SSL_CTRL_SESS_CONNECT_RENEGOTIATE = 23;
- public const int SSL_CTRL_SESS_ACCEPT = 24;
- public const int SSL_CTRL_SESS_ACCEPT_GOOD = 25;
- public const int SSL_CTRL_SESS_ACCEPT_RENEGOTIATE = 26;
- public const int SSL_CTRL_SESS_HIT = 27;
- public const int SSL_CTRL_SESS_CB_HIT = 28;
- public const int SSL_CTRL_SESS_MISSES = 29;
- public const int SSL_CTRL_SESS_TIMEOUTS = 30;
- public const int SSL_CTRL_SESS_CACHE_FULL = 31;
- public const int SSL_CTRL_MODE = 33;
- public const int SSL_CTRL_GET_READ_AHEAD = 40;
- public const int SSL_CTRL_SET_READ_AHEAD = 41;
- public const int SSL_CTRL_SET_SESS_CACHE_SIZE = 42;
- public const int SSL_CTRL_GET_SESS_CACHE_SIZE = 43;
- public const int SSL_CTRL_SET_SESS_CACHE_MODE = 44;
- public const int SSL_CTRL_GET_SESS_CACHE_MODE = 45;
- public const int SSL_CTRL_GET_MAX_CERT_LIST = 50;
- public const int SSL_CTRL_SET_MAX_CERT_LIST = 51;
- public const int SSL_CTRL_SET_MAX_SEND_FRAGMENT = 52;
- public const int SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53;
- public const int SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54;
- public const int SSL_CTRL_SET_TLSEXT_HOSTNAME = 55;
- public const int SSL_CTRL_SET_TLSEXT_DEBUG_CB = 56;
- public const int SSL_CTRL_SET_TLSEXT_DEBUG_ARG = 57;
- public const int SSL_CTRL_GET_TLSEXT_TICKET_KEYS = 58;
- public const int SSL_CTRL_SET_TLSEXT_TICKET_KEYS = 59;
- public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB = 63;
- public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG = 64;
- public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE = 65;
- public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS = 66;
- public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS = 67;
- public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS = 68;
- public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS = 69;
- public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP = 70;
- public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP = 71;
- public const int SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB = 75;
- public const int SSL_CTRL_SET_SRP_VERIFY_PARAM_CB = 76;
- public const int SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB = 77;
- public const int SSL_CTRL_SET_SRP_ARG = 78;
- public const int SSL_CTRL_SET_TLS_EXT_SRP_USERNAME = 79;
- public const int SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH = 80;
- public const int SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD = 81;
- public const int DTLS_CTRL_GET_TIMEOUT = 73;
- public const int DTLS_CTRL_HANDLE_TIMEOUT = 74;
- public const int SSL_CTRL_GET_RI_SUPPORT = 76;
- public const int SSL_CTRL_CLEAR_MODE = 78;
- public const int SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB = 79;
- public const int SSL_CTRL_GET_EXTRA_CHAIN_CERTS = 82;
- public const int SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS = 83;
- public const int SSL_CTRL_CHAIN = 88;
- public const int SSL_CTRL_CHAIN_CERT = 89;
- public const int SSL_CTRL_GET_GROUPS = 90;
- public const int SSL_CTRL_SET_GROUPS = 91;
- public const int SSL_CTRL_SET_GROUPS_LIST = 92;
- public const int SSL_CTRL_GET_SHARED_GROUP = 93;
- public const int SSL_CTRL_SET_SIGALGS = 97;
- public const int SSL_CTRL_SET_SIGALGS_LIST = 98;
- public const int SSL_CTRL_CERT_FLAGS = 99;
- public const int SSL_CTRL_CLEAR_CERT_FLAGS = 100;
- public const int SSL_CTRL_SET_CLIENT_SIGALGS = 101;
- public const int SSL_CTRL_SET_CLIENT_SIGALGS_LIST = 102;
- public const int SSL_CTRL_GET_CLIENT_CERT_TYPES = 103;
- public const int SSL_CTRL_SET_CLIENT_CERT_TYPES = 104;
- public const int SSL_CTRL_BUILD_CERT_CHAIN = 105;
- public const int SSL_CTRL_SET_VERIFY_CERT_STORE = 106;
- public const int SSL_CTRL_SET_CHAIN_CERT_STORE = 107;
- public const int SSL_CTRL_GET_PEER_SIGNATURE_NID = 108;
- public const int SSL_CTRL_GET_PEER_TMP_KEY = 109;
- public const int SSL_CTRL_GET_RAW_CIPHERLIST = 110;
- public const int SSL_CTRL_GET_EC_POINT_FORMATS = 111;
- public const int SSL_CTRL_GET_CHAIN_CERTS = 115;
- public const int SSL_CTRL_SELECT_CURRENT_CERT = 116;
- public const int SSL_CTRL_SET_CURRENT_CERT = 117;
- public const int SSL_CTRL_SET_DH_AUTO = 118;
- public const int DTLS_CTRL_SET_LINK_MTU = 120;
- public const int DTLS_CTRL_GET_LINK_MIN_MTU = 121;
- public const int SSL_CTRL_GET_EXTMS_SUPPORT = 122;
- public const int SSL_CTRL_SET_MIN_PROTO_VERSION = 123;
- public const int SSL_CTRL_SET_MAX_PROTO_VERSION = 124;
- public const int SSL_CTRL_SET_SPLIT_SEND_FRAGMENT = 125;
- public const int SSL_CTRL_SET_MAX_PIPELINES = 126;
- public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE = 127;
- public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB = 128;
- public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG = 129;
- public const int SSL_CTRL_GET_MIN_PROTO_VERSION = 130;
- public const int SSL_CTRL_GET_MAX_PROTO_VERSION = 131;
- public const int SSL_CTRL_GET_SIGNATURE_NID = 132;
- public const int SSL_CTRL_GET_TMP_KEY = 133;
- public const int SSL_CTRL_GET_NEGOTIATED_GROUP = 134;
- public const int SSL_CTRL_SET_RETRY_VERIFY = 136;
- public const int SSL_CTRL_GET_VERIFY_CERT_STORE = 137;
- public const int SSL_CTRL_GET_CHAIN_CERT_STORE = 138;
-
- // SSL/TLS related defines useful to providers
- // from: prov_ssl.h
- public const int TLS1_VERSION = 0x0301;
- public const int TLS1_1_VERSION = 0x0302;
- public const int TLS1_2_VERSION = 0x0303;
- public const int TLS1_3_VERSION = 0x0304;
-
- // int SSL_connect(SSL *ssl);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int SSL_connect(IntPtr ssl);
-
- // void SSL_free(SSL *ssl);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern void SSL_free(IntPtr ssl);
-
- // int SSL_get_error(const SSL *ssl, int ret);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int SSL_get_error(IntPtr ssl, int ret_code);
-
- // int SSL_in_init(const SSL *s);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int SSL_in_init(IntPtr ssl);
-
- // SSL *SSL_new(SSL_CTX *ctx);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr SSL_new(IntPtr ctx);
-
- // int SSL_read(SSL *ssl, void *buf, int num);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int SSL_read(IntPtr ssl, byte[] buf, int len);
-
- // void SSL_set_accept_state(SSL *ssl);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern void SSL_set_accept_state(IntPtr ssl);
-
- // void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern void SSL_set_bio(IntPtr ssl, IntPtr read_bio, IntPtr write_bio);
-
- // void SSL_set_connect_state(SSL *ssl);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern void SSL_set_connect_state(IntPtr ssl);
-
- // const char *SSL_state_string_long(const SSL *ssl);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr SSL_state_string_long(IntPtr ssl);
-
- // int SSL_want(const SSL* ssl);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int SSL_want(IntPtr ssl);
-
- // int SSL_write(SSL *ssl, const void *buf, int num);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int SSL_write(IntPtr ssl, byte[] buf, int len);
-
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr TLS_client_method();
-
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr SSL_export_keying_material(IntPtr ssl, byte[] outKeyMaterial, nint outKeyMaterialLength, char[] label, nint labelLength, IntPtr context, nint contextLength, int useContext);
-
- #endregion
-
- #region SSL_CTX
-
- // long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern long SSL_CTX_ctrl(IntPtr ctx, int cmd, long arg, IntPtr parg);
-
- // void SSL_CTX_free(SSL_CTX *ctx);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern void SSL_CTX_free(IntPtr ctx);
-
- // SSL_CTX *SSL_CTX_new(const SSL_METHOD *method);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr SSL_CTX_new(IntPtr sslMethod);
-
- // int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int SSL_CTX_set_ciphersuites(IntPtr ctx, string str);
-
- // typedef void (*SSL_CTX_keylog_cb_func)(const SSL *ssl, const char *line);
- // void SSL_CTX_set_keylog_callback(SSL_CTX* ctx, SSL_CTX_keylog_cb_func cb);
- [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern void SSL_CTX_set_keylog_callback(IntPtr ctx, SSL_CTX_keylog_cb_func cb);
-
- #endregion
-
- #region BIO
-
- // long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern long BIO_ctrl(IntPtr bp, int cmd, long larg, IntPtr parg);
-
- // size_t BIO_ctrl_pending(BIO *b);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern nint BIO_ctrl_pending(IntPtr bio);
-
- // void BIO_free_all(BIO *a);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern void BIO_free_all(IntPtr bio);
-
- // int BIO_free(BIO *a);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int BIO_free(IntPtr bio);
-
- // BIO * BIO_new(const BIO_METHOD *type);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr BIO_new(IntPtr type);
-
- // int BIO_read(BIO *b, void *buf, int len);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int BIO_read(IntPtr b, byte[] buf, int len);
-
- // BIO_METHOD * BIO_s_mem(void);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr BIO_s_mem();
-
- // int BIO_test_flags(const BIO *b, int flags);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int BIO_test_flags(IntPtr b, int flags);
-
- // int BIO_should_retry(BIO *b) -> define in bio.h: BIO_test_flags(a, BIO_FLAGS_SHOULD_RETRY)
- const int BIO_FLAGS_SHOULD_RETRY = 0x08;
- public static int BIO_should_retry(IntPtr b)
- {
- return Native.BIO_test_flags(b, BIO_FLAGS_SHOULD_RETRY);
- }
-
- // int BIO_write(BIO *b, const void *data, int dlen);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern int BIO_write(IntPtr b, byte[] data, int dlen);
-
- // BIO_set_mem_eof_return -> define in bio.h: BIO_ctrl(b,BIO_C_SET_BUF_MEM_EOF_RETURN,v,NULL)
- const int BIO_C_SET_BUF_MEM_EOF_RETURN = 130; // return end of input
- public static long BIO_set_mem_eof_return(IntPtr b, int v)
- {
- return Native.BIO_ctrl(b, BIO_C_SET_BUF_MEM_EOF_RETURN, v, IntPtr.Zero);
- }
- #endregion
-
- #region ERR
- public const int SSL_ERROR_NONE = 0;
- public const int SSL_ERROR_SSL = 1;
- public const int SSL_ERROR_WANT_READ = 2;
- public const int SSL_ERROR_WANT_WRITE = 3;
- public const int SSL_ERROR_WANT_X509_LOOKUP = 4;
- public const int SSL_ERROR_SYSCALL = 5;
- public const int SSL_ERROR_ZERO_RETURN = 6;
- public const int SSL_ERROR_WANT_CONNECT = 7;
- public const int SSL_ERROR_WANT_ACCEPT = 8;
-
- // void ERR_error_string_n(unsigned long e, char *buf, size_t len);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- //public static extern void ERR_error_string_n(ulong e, IntPtr buf, size_t len);
- public static extern void ERR_error_string_n(ulong e, byte[] buf, nint len);
-
- // unsigned long ERR_get_error(void);
- [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
- public static extern ulong ERR_get_error();
-
- #endregion
-
- #region Utilities
-
- public static IntPtr ExpectNonNull(IntPtr ptr)
- {
- if (ptr == IntPtr.Zero)
- throw new Exception();
-
- return ptr;
- }
-
- #endregion
- }
-}
+ }
+
+ #region Delegates
+
+ // typedef void (*SSL_CTX_keylog_cb_func)(const SSL *ssl, const char *line);
+ // void SSL_CTX_set_keylog_callback(SSL_CTX* ctx, SSL_CTX_keylog_cb_func cb);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void SSL_CTX_keylog_cb_func(IntPtr ssl, string line);
+
+ #endregion
+
+ #region OPENSSL
+
+ // int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int OPENSSL_init_ssl(UInt64 opts, IntPtr settings);
+
+ #endregion
+
+ #region SSL
+
+ public const int SSL_NOTHING = 1;
+ public const int SSL_WRITING = 2;
+ public const int SSL_READING = 3;
+ public const int SSL_X509_LOOKUP = 4;
+ public const int SSL_ASYNC_PAUSED = 5;
+ public const int SSL_ASYNC_NO_JOBS = 6;
+ public const int SSL_CLIENT_HELLO_CB = 7;
+ public const int SSL_RETRY_VERIFY = 8;
+
+ public const int SSL_CTRL_GET_CLIENT_CERT_REQUEST = 9;
+ public const int SSL_CTRL_GET_NUM_RENEGOTIATIONS = 10;
+ public const int SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS = 11;
+ public const int SSL_CTRL_GET_TOTAL_RENEGOTIATIONS = 12;
+ public const int SSL_CTRL_GET_FLAGS = 13;
+ public const int SSL_CTRL_EXTRA_CHAIN_CERT = 14;
+ public const int SSL_CTRL_SET_MSG_CALLBACK = 15;
+ public const int SSL_CTRL_SET_MSG_CALLBACK_ARG = 16;
+ public const int SSL_CTRL_SET_MTU = 17;
+ public const int SSL_CTRL_SESS_NUMBER = 20;
+ public const int SSL_CTRL_SESS_CONNECT = 21;
+ public const int SSL_CTRL_SESS_CONNECT_GOOD = 22;
+ public const int SSL_CTRL_SESS_CONNECT_RENEGOTIATE = 23;
+ public const int SSL_CTRL_SESS_ACCEPT = 24;
+ public const int SSL_CTRL_SESS_ACCEPT_GOOD = 25;
+ public const int SSL_CTRL_SESS_ACCEPT_RENEGOTIATE = 26;
+ public const int SSL_CTRL_SESS_HIT = 27;
+ public const int SSL_CTRL_SESS_CB_HIT = 28;
+ public const int SSL_CTRL_SESS_MISSES = 29;
+ public const int SSL_CTRL_SESS_TIMEOUTS = 30;
+ public const int SSL_CTRL_SESS_CACHE_FULL = 31;
+ public const int SSL_CTRL_MODE = 33;
+ public const int SSL_CTRL_GET_READ_AHEAD = 40;
+ public const int SSL_CTRL_SET_READ_AHEAD = 41;
+ public const int SSL_CTRL_SET_SESS_CACHE_SIZE = 42;
+ public const int SSL_CTRL_GET_SESS_CACHE_SIZE = 43;
+ public const int SSL_CTRL_SET_SESS_CACHE_MODE = 44;
+ public const int SSL_CTRL_GET_SESS_CACHE_MODE = 45;
+ public const int SSL_CTRL_GET_MAX_CERT_LIST = 50;
+ public const int SSL_CTRL_SET_MAX_CERT_LIST = 51;
+ public const int SSL_CTRL_SET_MAX_SEND_FRAGMENT = 52;
+ public const int SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53;
+ public const int SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54;
+ public const int SSL_CTRL_SET_TLSEXT_HOSTNAME = 55;
+ public const int SSL_CTRL_SET_TLSEXT_DEBUG_CB = 56;
+ public const int SSL_CTRL_SET_TLSEXT_DEBUG_ARG = 57;
+ public const int SSL_CTRL_GET_TLSEXT_TICKET_KEYS = 58;
+ public const int SSL_CTRL_SET_TLSEXT_TICKET_KEYS = 59;
+ public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB = 63;
+ public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG = 64;
+ public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE = 65;
+ public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS = 66;
+ public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS = 67;
+ public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS = 68;
+ public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS = 69;
+ public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP = 70;
+ public const int SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP = 71;
+ public const int SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB = 75;
+ public const int SSL_CTRL_SET_SRP_VERIFY_PARAM_CB = 76;
+ public const int SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB = 77;
+ public const int SSL_CTRL_SET_SRP_ARG = 78;
+ public const int SSL_CTRL_SET_TLS_EXT_SRP_USERNAME = 79;
+ public const int SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH = 80;
+ public const int SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD = 81;
+ public const int DTLS_CTRL_GET_TIMEOUT = 73;
+ public const int DTLS_CTRL_HANDLE_TIMEOUT = 74;
+ public const int SSL_CTRL_GET_RI_SUPPORT = 76;
+ public const int SSL_CTRL_CLEAR_MODE = 78;
+ public const int SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB = 79;
+ public const int SSL_CTRL_GET_EXTRA_CHAIN_CERTS = 82;
+ public const int SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS = 83;
+ public const int SSL_CTRL_CHAIN = 88;
+ public const int SSL_CTRL_CHAIN_CERT = 89;
+ public const int SSL_CTRL_GET_GROUPS = 90;
+ public const int SSL_CTRL_SET_GROUPS = 91;
+ public const int SSL_CTRL_SET_GROUPS_LIST = 92;
+ public const int SSL_CTRL_GET_SHARED_GROUP = 93;
+ public const int SSL_CTRL_SET_SIGALGS = 97;
+ public const int SSL_CTRL_SET_SIGALGS_LIST = 98;
+ public const int SSL_CTRL_CERT_FLAGS = 99;
+ public const int SSL_CTRL_CLEAR_CERT_FLAGS = 100;
+ public const int SSL_CTRL_SET_CLIENT_SIGALGS = 101;
+ public const int SSL_CTRL_SET_CLIENT_SIGALGS_LIST = 102;
+ public const int SSL_CTRL_GET_CLIENT_CERT_TYPES = 103;
+ public const int SSL_CTRL_SET_CLIENT_CERT_TYPES = 104;
+ public const int SSL_CTRL_BUILD_CERT_CHAIN = 105;
+ public const int SSL_CTRL_SET_VERIFY_CERT_STORE = 106;
+ public const int SSL_CTRL_SET_CHAIN_CERT_STORE = 107;
+ public const int SSL_CTRL_GET_PEER_SIGNATURE_NID = 108;
+ public const int SSL_CTRL_GET_PEER_TMP_KEY = 109;
+ public const int SSL_CTRL_GET_RAW_CIPHERLIST = 110;
+ public const int SSL_CTRL_GET_EC_POINT_FORMATS = 111;
+ public const int SSL_CTRL_GET_CHAIN_CERTS = 115;
+ public const int SSL_CTRL_SELECT_CURRENT_CERT = 116;
+ public const int SSL_CTRL_SET_CURRENT_CERT = 117;
+ public const int SSL_CTRL_SET_DH_AUTO = 118;
+ public const int DTLS_CTRL_SET_LINK_MTU = 120;
+ public const int DTLS_CTRL_GET_LINK_MIN_MTU = 121;
+ public const int SSL_CTRL_GET_EXTMS_SUPPORT = 122;
+ public const int SSL_CTRL_SET_MIN_PROTO_VERSION = 123;
+ public const int SSL_CTRL_SET_MAX_PROTO_VERSION = 124;
+ public const int SSL_CTRL_SET_SPLIT_SEND_FRAGMENT = 125;
+ public const int SSL_CTRL_SET_MAX_PIPELINES = 126;
+ public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE = 127;
+ public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB = 128;
+ public const int SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG = 129;
+ public const int SSL_CTRL_GET_MIN_PROTO_VERSION = 130;
+ public const int SSL_CTRL_GET_MAX_PROTO_VERSION = 131;
+ public const int SSL_CTRL_GET_SIGNATURE_NID = 132;
+ public const int SSL_CTRL_GET_TMP_KEY = 133;
+ public const int SSL_CTRL_GET_NEGOTIATED_GROUP = 134;
+ public const int SSL_CTRL_SET_RETRY_VERIFY = 136;
+ public const int SSL_CTRL_GET_VERIFY_CERT_STORE = 137;
+ public const int SSL_CTRL_GET_CHAIN_CERT_STORE = 138;
+
+ // SSL/TLS related defines useful to providers
+ // from: prov_ssl.h
+ public const int TLS1_VERSION = 0x0301;
+ public const int TLS1_1_VERSION = 0x0302;
+ public const int TLS1_2_VERSION = 0x0303;
+ public const int TLS1_3_VERSION = 0x0304;
+
+ // int SSL_connect(SSL *ssl);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_connect(IntPtr ssl);
+
+ // void SSL_free(SSL *ssl);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void SSL_free(IntPtr ssl);
+
+ // int SSL_get_error(const SSL *ssl, int ret);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_get_error(IntPtr ssl, int ret_code);
+
+ // int SSL_in_init(const SSL *s);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_in_init(IntPtr ssl);
+
+ // SSL *SSL_new(SSL_CTX *ctx);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr SSL_new(IntPtr ctx);
+
+ // int SSL_read(SSL *ssl, void *buf, int num);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_read(IntPtr ssl, byte[] buf, int len);
+
+ // void SSL_set_accept_state(SSL *ssl);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void SSL_set_accept_state(IntPtr ssl);
+
+ // void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void SSL_set_bio(IntPtr ssl, IntPtr read_bio, IntPtr write_bio);
+
+ // void SSL_set_connect_state(SSL *ssl);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void SSL_set_connect_state(IntPtr ssl);
+
+ // const char *SSL_state_string_long(const SSL *ssl);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr SSL_state_string_long(IntPtr ssl);
+
+ // int SSL_want(const SSL* ssl);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_want(IntPtr ssl);
+
+ // int SSL_write(SSL *ssl, const void *buf, int num);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_write(IntPtr ssl, byte[] buf, int len);
+
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr TLS_client_method();
+
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_export_keying_material
+ (
+ IntPtr ssl,
+ [Out] byte[] outKeyMaterial,
+ nint outKeyMaterialLength,
+ byte[] label, // Changed to byte[] for Linux
+ nint labelLength,
+ IntPtr context,
+ nint contextLength,
+ int useContext
+ );
+
+ #endregion
+
+ #region SSL_CTX
+
+ // long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern long SSL_CTX_ctrl(IntPtr ctx, int cmd, long arg, IntPtr parg);
+
+ // void SSL_CTX_free(SSL_CTX *ctx);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void SSL_CTX_free(IntPtr ctx);
+
+ // SSL_CTX *SSL_CTX_new(const SSL_METHOD *method);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr SSL_CTX_new(IntPtr sslMethod);
+
+ // int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_CTX_set_ciphersuites(IntPtr ctx, string str);
+
+ // typedef void (*SSL_CTX_keylog_cb_func)(const SSL *ssl, const char *line);
+ // void SSL_CTX_set_keylog_callback(SSL_CTX* ctx, SSL_CTX_keylog_cb_func cb);
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void SSL_CTX_set_keylog_callback(IntPtr ctx, SSL_CTX_keylog_cb_func cb);
+
+ #endregion
+
+ #region BIO
+ //Added for troubleshoot force handshake in SSL_connect
+ [DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int SSL_do_handshake(IntPtr ssl);
+
+ // long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ // Change return and larg from long to nint
+ public static extern nint BIO_ctrl(IntPtr bp, int cmd, nint larg, IntPtr parg);
+
+ // size_t BIO_ctrl_pending(BIO *b);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern nint BIO_ctrl_pending(IntPtr bio);
+
+ // void BIO_free_all(BIO *a);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void BIO_free_all(IntPtr bio);
+
+ // int BIO_free(BIO *a);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int BIO_free(IntPtr bio);
+
+ // BIO * BIO_new(const BIO_METHOD *type);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr BIO_new(IntPtr type);
+
+ // int BIO_read(BIO *b, void *buf, int len);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int BIO_read(IntPtr b, byte[] buf, int len);
+
+ // BIO_METHOD * BIO_s_mem(void);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern IntPtr BIO_s_mem();
+
+ // int BIO_test_flags(const BIO *b, int flags);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int BIO_test_flags(IntPtr b, int flags);
+
+ // int BIO_should_retry(BIO *b) -> define in bio.h: BIO_test_flags(a, BIO_FLAGS_SHOULD_RETRY)
+ const int BIO_FLAGS_SHOULD_RETRY = 0x08;
+ public static int BIO_should_retry(IntPtr b)
+ {
+ return Native.BIO_test_flags(b, BIO_FLAGS_SHOULD_RETRY);
+ }
+
+ // int BIO_write(BIO *b, const void *data, int dlen);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int BIO_write(IntPtr b, byte[] data, int dlen);
+
+ // BIO_set_mem_eof_return -> define in bio.h: BIO_ctrl(b,BIO_C_SET_BUF_MEM_EOF_RETURN,v,NULL)
+ //Changed Long to nint for v and return type
+ const int BIO_C_SET_BUF_MEM_EOF_RETURN = 130; // return end of input
+ public static nint BIO_set_mem_eof_return(IntPtr b, int v)
+ {
+ // Use nint for the third parameter
+ return Native.BIO_ctrl(b, BIO_C_SET_BUF_MEM_EOF_RETURN, (nint)v, IntPtr.Zero);
+ }
+ #endregion
+
+ #region ERR
+ public const int SSL_ERROR_NONE = 0;
+ public const int SSL_ERROR_SSL = 1;
+ public const int SSL_ERROR_WANT_READ = 2;
+ public const int SSL_ERROR_WANT_WRITE = 3;
+ public const int SSL_ERROR_WANT_X509_LOOKUP = 4;
+ public const int SSL_ERROR_SYSCALL = 5;
+ public const int SSL_ERROR_ZERO_RETURN = 6;
+ public const int SSL_ERROR_WANT_CONNECT = 7;
+ public const int SSL_ERROR_WANT_ACCEPT = 8;
+
+ // void ERR_error_string_n(unsigned long e, char *buf, size_t len);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ //public static extern void ERR_error_string_n(ulong e, IntPtr buf, size_t len);
+ public static extern void ERR_error_string_n(ulong e, byte[] buf, nint len);
+
+ // unsigned long ERR_get_error(void);
+ [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
+ public static extern ulong ERR_get_error();
+
+ #endregion
+
+ #region Utilities
+
+ public static IntPtr ExpectNonNull(IntPtr ptr)
+ {
+ if (ptr == IntPtr.Zero)
+ throw new Exception();
+
+ return ptr;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs b/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs
index bf61865..8293161 100644
--- a/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs
+++ b/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs
@@ -102,10 +102,14 @@ private int DataToWrite(byte[] pData, int dataLength)
private int DataToRead(byte[] pData, int dataLength)
{
+ //Console.WriteLine($"[DEBUG] Passing {dataLength} bytes to BIO_write.");
+
m_readRequired = false;
int bytesUsed = Native.BIO_write(m_pBioIn, pData, dataLength);
+ //Console.WriteLine($"[OpenSSL-Net] Written to BIO_In: {bytesUsed} bytes.");
+
byte[] pBuffer = null;
int bufferSize = 0;
@@ -134,17 +138,24 @@ private int DataToRead(byte[] pData, int dataLength)
private void SendPendingData()
{
- while (Native.BIO_ctrl_pending(m_pBioOut) > 0)
+
+ nint pending = Native.BIO_ctrl_pending(m_pBioOut);
+
+ while (pending > 0)
{
+ //Console.WriteLine($"[BIO-Debug] BIO_ctrl_pending reported: {pending} bytes available.");
+
byte[] pBuffer = null;
int bufferSize = 0;
GetNextWriteDataBuffer(ref pBuffer, ref bufferSize);
int bytesToSend = Native.BIO_read(m_pBioOut, pBuffer, bufferSize);
+ //Console.WriteLine($"[BIO-Debug] BIO_read attempted. Result: {bytesToSend} bytes.");
if (bytesToSend > 0)
{
+ //Console.WriteLine($"[OpenSSL-Net] Read {bytesToSend} bytes from BIO_Out to send to PLC.");
OnDataToWrite(pBuffer, bytesToSend);
}
@@ -155,6 +166,8 @@ private void SendPendingData()
HandleError(bytesToSend);
}
}
+ // Refresh pending count
+ pending = Native.BIO_ctrl_pending(m_pBioOut);
}
}
@@ -167,7 +180,7 @@ void HandleError(int result)
{
if (result <= 0)
{
- int error = Native.SSL_get_error(m_pSslConnection, result);
+ int error = (int)Native.SSL_get_error(m_pSslConnection, result);
switch (error)
{
@@ -192,6 +205,18 @@ protected void RunSSL()
GetPendingOperations(ref dataToRead, ref dataToWrite);
+ // DEBUG: Force a handshake attempt to see if OpenSSL has something to say
+ //int handshakeRet = Native.SSL_do_handshake(m_pSslConnection);
+
+ //if (handshakeRet <= 0)
+ //{
+ // int err = (int)Native.SSL_get_error(m_pSslConnection, handshakeRet);
+ // if (err != Native.SSL_ERROR_WANT_READ)
+ // {
+ // Console.WriteLine($"[Handshake-Debug] SSL_do_handshake result: {handshakeRet}, Error: {err}");
+ // }
+ //}
+
while ((!m_readRequired && dataToWrite) || dataToRead)
{
if (Native.SSL_in_init(m_pSslConnection) != 0)
@@ -216,6 +241,13 @@ protected void RunSSL()
GetPendingOperations(ref dataToRead, ref dataToWrite);
}
+
+ //If BIO_read isn't triggering, see if anything is stuck in BioOut
+ //if (Native.BIO_ctrl_pending(m_pBioOut) > 0)
+ //{
+ // //Console.WriteLine($"[BIO-Debug] Handshake loop finished but {Native.BIO_ctrl_pending(m_pBioOut)} bytes are still stuck in BioOut.");
+ // SendPendingData();
+ //}
}
public void Write(byte[] pData,int dataLen)
@@ -346,14 +378,16 @@ void PutbackBuffer(DataBufferList list, DataBuffer pBuffer)
list.AddFirst(pBuffer);
}
- ///
/// Create OMS exporter secret that is needed for the legitimation with the PLC
///
/// Secret
public byte[] getOMSExporterSecret()
{
byte[] secretOut = new byte[32];
- int ret = (int)Native.SSL_export_keying_material(m_pSslConnection, secretOut, (nint)secretOut.Length, "EXPERIMENTAL_OMS".ToCharArray(), 16, IntPtr.Zero, 0, 0);
+ // Convert to UTF8 bytes to avoid the 2-byte char issue in linux
+ byte[] labelBytes = System.Text.Encoding.UTF8.GetBytes("EXPERIMENTAL_OMS");
+ int ret = Native.SSL_export_keying_material(m_pSslConnection,secretOut,(nint)secretOut.Length,labelBytes,(nint)labelBytes.Length,IntPtr.Zero,0,0);
+
return secretOut;
}
}