diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
index 4b95c19e..efff22ef 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
@@ -27,6 +27,7 @@ using System.Collections.Generic;
using System.Collections;
using IEC61850.Common;
+using IEC61850.TLS;
///
/// IEC 61850 API for the libiec61850 .NET wrapper library
@@ -558,9 +559,6 @@ namespace IEC61850
///
public class IedServer
{
- [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
- static extern IntPtr IedServer_create(IntPtr modelRef);
-
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr IedServer_createWithConfig(IntPtr modelRef, IntPtr tlsConfiguration, IntPtr serverConfiguratio);
@@ -789,19 +787,30 @@ namespace IEC61850
private Dictionary clientConnections = new Dictionary ();
- public IedServer(IedModel iedModel)
+
+
+ public IedServer(IedModel iedModel, IedServerConfig config = null)
{
- self = IedServer_create(iedModel.self);
+ IntPtr nativeConfig = IntPtr.Zero;
+
+ if (config != null)
+ nativeConfig = config.self;
+
+ self = IedServer_createWithConfig (iedModel.self, IntPtr.Zero, nativeConfig);
}
- public IedServer(IedModel iedModel, IedServerConfig config)
+ public IedServer(IedModel iedModel, TLSConfiguration tlsConfig, IedServerConfig config = null)
{
IntPtr nativeConfig = IntPtr.Zero;
+ IntPtr nativeTLSConfig = IntPtr.Zero;
if (config != null)
nativeConfig = config.self;
- self = IedServer_createWithConfig (iedModel.self, IntPtr.Zero, nativeConfig);
+ if (tlsConfig != null)
+ nativeTLSConfig = tlsConfig.GetNativeInstance ();
+
+ self = IedServer_createWithConfig (iedModel.self, nativeTLSConfig, nativeConfig);
}
// causes undefined behavior
@@ -850,7 +859,7 @@ namespace IEC61850
/// Start MMS server
public void Start ()
{
- Start(102);
+ Start(-1);
}
///
diff --git a/dotnet/IEC61850forCSharp/TLS.cs b/dotnet/IEC61850forCSharp/TLS.cs
index b7d67dc0..69a273b0 100644
--- a/dotnet/IEC61850forCSharp/TLS.cs
+++ b/dotnet/IEC61850forCSharp/TLS.cs
@@ -139,7 +139,6 @@ namespace IEC61850
public void SetOwnCertificate(string filename)
{
if (TLSConfiguration_setOwnCertificateFromFile (self, filename) == false) {
- Console.WriteLine ("Failed to read certificate from file!");
throw new CryptographicException ("Failed to read certificate from file");
}
}
@@ -149,7 +148,6 @@ namespace IEC61850
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_setOwnCertificate (self, certBytes, certBytes.Length) == false) {
- Console.WriteLine ("Failed to set certificate!");
throw new CryptographicException ("Failed to set certificate");
}
}
@@ -157,7 +155,6 @@ namespace IEC61850
public void AddAllowedCertificate(string filename)
{
if (TLSConfiguration_addAllowedCertificateFromFile (self, filename) == false) {
- Console.WriteLine ("Failed to read allowed certificate from file!");
throw new CryptographicException ("Failed to read allowed certificate from file");
}
}
@@ -167,7 +164,6 @@ namespace IEC61850
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_addAllowedCertificate (self, certBytes, certBytes.Length) == false) {
- Console.WriteLine ("Failed to add allowed certificate!");
throw new CryptographicException ("Failed to add allowed certificate");
}
}
@@ -175,7 +171,6 @@ namespace IEC61850
public void AddCACertificate(string filename)
{
if (TLSConfiguration_addCACertificateFromFile (self, filename) == false) {
- Console.WriteLine ("Failed to read CA certificate from file!");
throw new CryptographicException ("Failed to read CA certificate from file");
}
}
@@ -185,7 +180,6 @@ namespace IEC61850
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_addCACertificate (self, certBytes, certBytes.Length) == false) {
- Console.WriteLine ("Failed to add CA certificate!");
throw new CryptographicException ("Failed to add CA certificate");
}
}
@@ -193,7 +187,6 @@ namespace IEC61850
public void SetOwnKey (string filename, string password)
{
if (TLSConfiguration_setOwnKeyFromFile (self, filename, password) == false) {
- Console.WriteLine ("Failed to read own key from file!");
throw new CryptographicException ("Failed to read own key from file");
}
}
@@ -203,7 +196,6 @@ namespace IEC61850
byte[] certBytes = key.Export (X509ContentType.Pkcs12);
if (TLSConfiguration_setOwnKey (self, certBytes, certBytes.Length, password) == false) {
- Console.WriteLine ("Failed to set own key!");
throw new CryptographicException ("Failed to set own key");
}
}
diff --git a/dotnet/dotnet.sln b/dotnet/dotnet.sln
index 067ccaf9..ba1be6f4 100644
--- a/dotnet/dotnet.sln
+++ b/dotnet/dotnet.sln
@@ -42,6 +42,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "goose_subscriber", "goose_s
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sv_subscriber", "sv_subscriber\sv_subscriber.csproj", "{44651D2D-3252-4FD5-8B8B-5552DBE1B499}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tls_server_example", "tls_server_example\tls_server_example.csproj", "{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -96,6 +98,10 @@ Global
{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}.Release|Any CPU.Build.0 = Release|Any CPU
{C351CFA4-E54E-49A1-86CE-69643535541A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C351CFA4-E54E-49A1-86CE-69643535541A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C351CFA4-E54E-49A1-86CE-69643535541A}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/dotnet/tls_server_example/Program.cs b/dotnet/tls_server_example/Program.cs
new file mode 100644
index 00000000..e7aa0cfc
--- /dev/null
+++ b/dotnet/tls_server_example/Program.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Threading;
+using System.Security.Cryptography.X509Certificates;
+
+using IEC61850.Server;
+using IEC61850.Common;
+using IEC61850.TLS;
+
+namespace tls_server_example
+{
+ class MainClass
+ {
+ public static void Main (string[] args)
+ {
+ bool running = true;
+
+ /* run until Ctrl-C is pressed */
+ Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
+ e.Cancel = true;
+ running = false;
+ };
+
+ IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile ("model.cfg");
+
+ if (iedModel == null) {
+ Console.WriteLine ("No valid data model found!");
+ return;
+ }
+
+ DataObject spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference ("GenericIO/GGIO1.SPCSO1");
+
+ TLSConfiguration tlsConfig = new TLSConfiguration ();
+
+ tlsConfig.SetOwnCertificate (new X509Certificate2 ("server.cer"));
+
+ tlsConfig.SetOwnKey ("server-key.pem", null);
+
+ // Add a CA certificate to check the certificate provided by the server - not required when ChainValidation == false
+ tlsConfig.AddCACertificate (new X509Certificate2 ("root.cer"));
+
+ // Check if the certificate is signed by a provided CA
+ tlsConfig.ChainValidation = true;
+
+ // Check that the shown server certificate is in the list of allowed certificates
+ tlsConfig.AllowOnlyKnownCertificates = false;
+
+ IedServer iedServer = new IedServer (iedModel, tlsConfig);
+
+ iedServer.SetControlHandler (spcso1, delegate(DataObject controlObject, object parameter, MmsValue ctlVal, bool test) {
+ bool val = ctlVal.GetBoolean();
+
+ if (val)
+ Console.WriteLine("received binary control command: on");
+ else
+ Console.WriteLine("received binary control command: off");
+
+ return ControlHandlerResult.OK;
+ }, null);
+
+ iedServer.Start ();
+ Console.WriteLine ("Server started");
+
+ GC.Collect ();
+
+ DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference ("GenericIO/GGIO1.AnIn1");
+
+ DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild ("mag.f");
+ DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild ("t");
+
+ float floatVal = 1.0f;
+
+ while (running) {
+ floatVal += 1f;
+ iedServer.UpdateTimestampAttributeValue (ggio1AnIn1T, new Timestamp (DateTime.Now));
+ iedServer.UpdateFloatAttributeValue (ggio1AnIn1magF, floatVal);
+ Thread.Sleep (100);
+ }
+
+ iedServer.Stop ();
+ Console.WriteLine ("Server stopped");
+
+ iedServer.Destroy ();
+ }
+ }
+}
diff --git a/dotnet/tls_server_example/Properties/AssemblyInfo.cs b/dotnet/tls_server_example/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..638df635
--- /dev/null
+++ b/dotnet/tls_server_example/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle ("tls_server_example")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("mzillgit")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion ("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/dotnet/tls_server_example/model.cfg b/dotnet/tls_server_example/model.cfg
new file mode 100644
index 00000000..6f332425
--- /dev/null
+++ b/dotnet/tls_server_example/model.cfg
@@ -0,0 +1,237 @@
+MODEL(simpleIO){
+LD(GenericIO){
+LN(LLN0){
+DO(Mod 0){
+DA(stVal 0 12 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+DA(ctlModel 0 12 4 0 0)=0;
+}
+DO(Beh 0){
+DA(stVal 0 12 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Health 0){
+DA(stVal 0 3 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(NamPlt 0){
+DA(vendor 0 20 5 0 0);
+DA(swRev 0 20 5 0 0);
+DA(d 0 20 5 0 0);
+DA(configRev 0 20 5 0 0);
+DA(ldNs 0 20 11 0 0);
+}
+DS(Events){
+DE(GGIO1$ST$SPCSO1$stVal);
+DE(GGIO1$ST$SPCSO2$stVal);
+DE(GGIO1$ST$SPCSO3$stVal);
+DE(GGIO1$ST$SPCSO4$stVal);
+}
+DS(AnalogValues){
+DE(GGIO1$MX$AnIn1);
+DE(GGIO1$MX$AnIn2);
+DE(GGIO1$MX$AnIn3);
+DE(GGIO1$MX$AnIn4);
+}
+RC(EventsRCB01 Events 0 Events 1 24 111 50 1000);
+RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 24 111 50 1000);
+LC(EventLog Events GenericIO/LLN0$EventLog 19 0 0 1);
+LC(GeneralLog - - 19 0 0 1);
+LOG(GeneralLog);
+LOG(EventLog);
+GC(gcbEvents events Events 2 0 -1 -1 ){
+PA(4 273 4096 010ccd010001);
+}
+GC(gcbAnalogValues analog AnalogValues 2 0 -1 -1 ){
+PA(4 273 4096 010ccd010001);
+}
+}
+LN(LPHD1){
+DO(PhyNam 0){
+DA(vendor 0 20 5 0 0);
+}
+DO(PhyHealth 0){
+DA(stVal 0 3 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Proxy 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+}
+LN(GGIO1){
+DO(Mod 0){
+DA(stVal 0 12 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+DA(ctlModel 0 12 4 0 0)=0;
+}
+DO(Beh 0){
+DA(stVal 0 12 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Health 0){
+DA(stVal 0 3 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(NamPlt 0){
+DA(vendor 0 20 5 0 0);
+DA(swRev 0 20 5 0 0);
+DA(d 0 20 5 0 0);
+}
+DO(AnIn1 0){
+DA(mag 0 27 1 1 0){
+DA(f 0 10 1 1 0);
+}
+DA(q 0 23 1 2 0);
+DA(t 0 22 1 0 0);
+}
+DO(AnIn2 0){
+DA(mag 0 27 1 1 101){
+DA(f 0 10 1 1 0);
+}
+DA(q 0 23 1 2 0);
+DA(t 0 22 1 0 102);
+}
+DO(AnIn3 0){
+DA(mag 0 27 1 1 0){
+DA(f 0 10 1 1 0);
+}
+DA(q 0 23 1 2 0);
+DA(t 0 22 1 0 0);
+}
+DO(AnIn4 0){
+DA(mag 0 27 1 1 0){
+DA(f 0 10 1 1 0);
+}
+DA(q 0 23 1 2 0);
+DA(t 0 22 1 0 0);
+}
+DO(SPCSO1 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(Oper 0 27 12 0 0){
+DA(ctlVal 0 0 12 0 0);
+DA(origin 0 27 12 0 0){
+DA(orCat 0 12 12 0 0);
+DA(orIdent 0 13 12 0 0);
+}
+DA(ctlNum 0 6 12 0 0);
+DA(T 0 22 12 0 0);
+DA(Test 0 0 12 0 0);
+DA(Check 0 24 12 0 0);
+}
+DA(ctlModel 0 12 4 0 0)=1;
+DA(t 0 22 0 0 0);
+}
+DO(SPCSO2 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(Oper 0 27 12 0 0){
+DA(ctlVal 0 0 12 0 0);
+DA(origin 0 27 12 0 0){
+DA(orCat 0 12 12 0 0);
+DA(orIdent 0 13 12 0 0);
+}
+DA(ctlNum 0 6 12 0 0);
+DA(T 0 22 12 0 0);
+DA(Test 0 0 12 0 0);
+DA(Check 0 24 12 0 0);
+}
+DA(ctlModel 0 12 4 0 0)=1;
+DA(t 0 22 0 0 0);
+}
+DO(SPCSO3 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(Oper 0 27 12 0 0){
+DA(ctlVal 0 0 12 0 0);
+DA(origin 0 27 12 0 0){
+DA(orCat 0 12 12 0 0);
+DA(orIdent 0 13 12 0 0);
+}
+DA(ctlNum 0 6 12 0 0);
+DA(T 0 22 12 0 0);
+DA(Test 0 0 12 0 0);
+DA(Check 0 24 12 0 0);
+}
+DA(ctlModel 0 12 4 0 0)=1;
+DA(t 0 22 0 0 0);
+}
+DO(SPCSO4 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(Oper 0 27 12 0 0){
+DA(ctlVal 0 0 12 0 0);
+DA(origin 0 27 12 0 0){
+DA(orCat 0 12 12 0 0);
+DA(orIdent 0 13 12 0 0);
+}
+DA(ctlNum 0 6 12 0 0);
+DA(T 0 22 12 0 0);
+DA(Test 0 0 12 0 0);
+DA(Check 0 24 12 0 0);
+}
+DA(ctlModel 0 12 4 0 0)=1;
+DA(t 0 22 0 0 0);
+}
+DO(Ind1 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Ind2 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Ind3 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Ind4 0){
+DA(stVal 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+}
+LN(PDUP1){
+DO(Beh 0){
+DA(stVal 0 12 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Mod 0){
+DA(stVal 0 12 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+DA(ctlModel 0 12 4 0 0)=0;
+}
+DO(Str 0){
+DA(general 0 0 0 1 0);
+DA(dirGeneral 0 12 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(Op 0){
+DA(general 0 0 0 1 0);
+DA(q 0 23 0 2 0);
+DA(t 0 22 0 0 0);
+}
+DO(OpDlTmms 0){
+DA(setVal 0 3 2 1 0);
+}
+DO(RsDlTmms 0){
+DA(setVal 0 3 2 1 0);
+}
+}
+}
+}
diff --git a/dotnet/tls_server_example/root.cer b/dotnet/tls_server_example/root.cer
new file mode 100644
index 00000000..87683444
Binary files /dev/null and b/dotnet/tls_server_example/root.cer differ
diff --git a/dotnet/tls_server_example/server-key.pem b/dotnet/tls_server_example/server-key.pem
new file mode 100644
index 00000000..6fe35295
--- /dev/null
+++ b/dotnet/tls_server_example/server-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAu3Fjxb904UdyV/dDfvs8SFi6zJeNoMYjmpXm/LBcFSH3zGoK
+wdcMovrUTED3Cc6Ww84AYpJ5MRMPTct7DfKJkWfSnkzOPmLldTSTv3RvzGVb4NzK
+QqA5aSVDqAzPiP5RnFT6Q4KWRe69TMFxpw7zMXCJx9jDggqN1oojGGkmSgYGXnFd
+Nc20Mujejh5pihgwnN4Y/bPFyxJwvIMj+D8qr9klhEmXKPTiX9UFd8oLkn9JCB6+
+SiHhNyFIo+Llossn1Q2hxCGty36fAhEWzpfBTaY510VLjie9y4q9GPTwxITDqSQd
+xcX8IuvrbxX0DyEK507SMmTJmB9448eF9ZCWFQIDAQABAoIBAC80BuQtqslwrKLq
+adz4d93gOmp7X/c07pJnXZwU7ZuEylp3+e2Gsm/4qq3pTkzx8ZWtsvsf19U774av
+z3VbtrkfZDLpNKcRUKeLbgmw0NawT8r4zxaoMsz/zWHsl/bv1K2B2ORXZnCGBrXl
+oTFo2mWA6bGiLNn6vm1grCXhlPreywyG/kFK3pi2VvkpvG3XZSI7mmZ0Dq/MD3nO
+03oOZBqwwnMObfQQdhKE7646/+KgeuF/JsXaUH4bkHmtzYWyocWYMqpC0hjpNWlQ
+cKuQ7t1kfmpsGD9aNW4+ND2ok9BdxIiC+rPXS9NDqZxoWLp+a8seU++uqk1l8RPq
+tPE3LqECgYEAz1NmemNLiUsKvyemUvjp8+dJupzWtdV7fsnCbYhj/5gDA2UhFKCf
+dP9xiHCdNe0797oAqHY7c3JhS4ug8haDy9aDIu5GG2DNYzjX/oYm4ywbCdRx+uEN
+RcTw69FjSYVGkObmxWYszwsFybRasV6PYamg65qYR3FlvW2Td4Fndy8CgYEA53L/
+zHtBRQiNGJU9jfMHeX0bTtXIAt622Qn78jw0it/rhXWi2RwG2Cw5Q2aPRJ6uMt9F
+yk1+GAPZcwYqwjq/nKRrl71Tn+KDWIk5rz1fNYRkaXtnMLs2MOogqoDTBshW0QBq
+tnPrFNsaLKX6V92Az69wHjd2uwvLQLTvS/EuNfsCgYEAr3to/uhytAd3VirKRep3
+o0E+D5zWw1upxrwhPDK4aUuSKVp8sIfvz8iyoQiomE9vdZPTIMPKOEI1BgtuM9pI
+vcyYfIVvg5bg4T3o3H9SBPB9BknyG6ZHZKl4PjGht0X+X4GBDM4Z2Tj8Mijcpsph
+1AkOsrzMbZQWyEoqCnnWSHMCgYAFEHUcak4BTrCXqxxPsNOnCt/AF9lqhqkFkrxa
+joqvxzqGDw7jJUPZEw6ltObJn5c8Mbp7NLrfl6X4aFgjK9npeYeJKHFd/DzXgRks
+BnHA4Aa6cCLP5CjJZTYVxP/ZFCUiKZosJ9kq+ahW9cLGjWg2IyaW4qvMZ/OolMzv
+onVaZQKBgQCir8u1vDsyA4JQXMytPHBJe27XaLRGULvteNydVB59Vt21a99o5gt1
+5B9gwWArZdZby3/KZiliNmzp8lMCrLJYjTL5WK6dbWdq92X5hCOofKPIjEcgHjhk
+mvnAos3HeC83bJQtADXhw9jR7Vr6GJLM9HDcIgeIMzX7+BuqlMgaHA==
+-----END RSA PRIVATE KEY-----
diff --git a/dotnet/tls_server_example/server.cer b/dotnet/tls_server_example/server.cer
new file mode 100644
index 00000000..957bdc30
Binary files /dev/null and b/dotnet/tls_server_example/server.cer differ
diff --git a/dotnet/tls_server_example/tls_server_example.csproj b/dotnet/tls_server_example/tls_server_example.csproj
new file mode 100644
index 00000000..012dd760
--- /dev/null
+++ b/dotnet/tls_server_example/tls_server_example.csproj
@@ -0,0 +1,58 @@
+
+
+
+ Debug
+ AnyCPU
+ {B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}
+ Exe
+ tls_server_example
+ tls_server_example
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ full
+ true
+ bin\Release
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
+ IEC61850.NET
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
\ No newline at end of file