diff --git a/dotnet/IEC61850forCSharp/AcseAuthenticationParameter.cs b/dotnet/IEC61850forCSharp/AcseAuthenticationParameter.cs new file mode 100644 index 00000000..1e5496b6 --- /dev/null +++ b/dotnet/IEC61850forCSharp/AcseAuthenticationParameter.cs @@ -0,0 +1,101 @@ +/* + * AcseAuthenticationParameter.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +// IEC 61850 API for the libiec61850 .NET wrapper library +namespace IEC61850 +{ + /// + /// Authentication mechanism used by AcseAuthenticator + /// + public enum AcseAuthenticationMechanism + { + /** Neither ACSE nor TLS authentication used */ + ACSE_AUTH_NONE = 0, + + /** Use ACSE password for client authentication */ + ACSE_AUTH_PASSWORD = 1, + + /** Use ACSE certificate for client authentication */ + ACSE_AUTH_CERTIFICATE = 2, + + /** Use TLS certificate for client authentication */ + ACSE_AUTH_TLS = 3 + } + + + public class AcseAuthenticationParameter + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr AcseAuthenticationParameter_create(); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void AcseAuthenticationParameter_setAuthMechanism(IntPtr self, int mechanism); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void AcseAuthenticationParameter_setPassword(IntPtr self, string password); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int AcseAuthenticationParameter_getAuthMechanism(IntPtr self); + + private IntPtr self = IntPtr.Zero; + + public AcseAuthenticationParameter() + { + self = AcseAuthenticationParameter_create(); + } + + public AcseAuthenticationParameter(IntPtr self) + { + this.self = self; + } + + public void SetAuthMechanism(AcseAuthenticationMechanism acseAuthenticationMechanism) + { + AcseAuthenticationParameter_setAuthMechanism(self,(int)acseAuthenticationMechanism); + } + + public void SetPassword(string password) + { + AcseAuthenticationParameter_setPassword(self, password); + } + + public AcseAuthenticationMechanism GetAuthMechanism() + { + return (AcseAuthenticationMechanism)AcseAuthenticationParameter_getAuthMechanism(self); + } + } + + public class IsoApplicationReference + { + private IntPtr self = IntPtr.Zero; + + public IsoApplicationReference(IntPtr self) + { + this.self= self; + } + } +} diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index 8f321fce..27cf390d 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -25,7 +25,10 @@ using IEC61850.Model; using IEC61850.TLS; using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data.Common; using System.Runtime.InteropServices; +using System.Security.Principal; // IEC 61850 API for the libiec61850 .NET wrapper library namespace IEC61850 @@ -1749,6 +1752,9 @@ namespace IEC61850 public class ClientConnection : IDisposable { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientConnection_getSecurityToken(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr ClientConnection_getPeerAddress(IntPtr self); @@ -1772,6 +1778,31 @@ namespace IEC61850 this.self = ClientConnection_claimOwnership(self); } + /// + /// Get the security token associated with this connection + /// The security token is an opaque handle that is associated with the connection.It is provided by the + /// authenticator (if one is present). If no security token is used then this function returns NULL + /// + /// the security token or NULL + public object GetSecurityToken() + { + lock (this) + { + if (self != IntPtr.Zero) + { + IntPtr token = ClientConnection_getSecurityToken(self); + + if (token != IntPtr.Zero) + { + GCHandle handle = GCHandle.FromIntPtr(token); + return handle as object; + } + } + } + + return null; + } + public string GetPeerAddress() { lock (this) @@ -2611,6 +2642,29 @@ namespace IEC61850 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void IedServer_SVCBEventHandler(IntPtr svcb, int eventType, IntPtr parameter); + /// + /// set the authenticator for this server + /// This function sets a user specified authenticator that is used to identify and authenticate clients that + /// wants to connect.The authenticator is called on each connection attempt.Depending on the return value + /// connections are accepted. + /// + /// the instance of IedServer to operate on. + /// the user provided authenticator callback + /// user provided parameter that is passed to the authenticator + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServer_setAuthenticator(IntPtr self, IedServer_AcseAuthenticator authenticator, IntPtr authenticatorParameter); + + /// + /// Callback function to authenticate a client + /// + /// user provided parameter - set when user registers the authenticator + /// the authentication parameters provided by the client + /// pointer where to store an application specific security token - can be ignored if not used. + /// ISO application reference (ap-title + ae-qualifier) + /// true if client connection is accepted, false otherwise + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool IedServer_AcseAuthenticator(IntPtr parameter, IntPtr authParameter, IntPtr securityToken, IntPtr appReference); + /// /// callback handler to control client read access to data attributes /// User provided callback function to control MMS client read access to IEC 61850 @@ -3166,7 +3220,6 @@ namespace IEC61850 IedServer_setSVCBHandler(self, sampledValuesControlBlock.Self, internalSVCBEventHandler, GCHandle.ToIntPtr(info.handle)); } - private void InternalSVCBEventHandlerImplementation(IntPtr svcb, int eventType, IntPtr parameter) { GCHandle handle = GCHandle.FromIntPtr(parameter); @@ -3177,6 +3230,38 @@ namespace IEC61850 info.sVCBEventHandler(info.sampledValuesControlBlock, (SMVEvent)eventType, info.svcHandlerParameter); } + //TODO -> Add appReference + public delegate bool AcseAuthenticatorHandler(object parameter, AcseAuthenticationParameter authParameter, object securityToken, IsoApplicationReference isoApplicationReference); + + private AcseAuthenticatorHandler acseAuthenticatorHandler = null; + private object acseAuthenticatorHandlerParameter = null; + private IedServer_AcseAuthenticator iedServer_AcseAuthenticator = null; + + public void SetAuthenticator(AcseAuthenticatorHandler acseAuthenticatorHandler, object acseAuthenticatorHandlerParameter) + { + this.acseAuthenticatorHandler = acseAuthenticatorHandler; + this.acseAuthenticatorHandlerParameter= acseAuthenticatorHandlerParameter; + + if(iedServer_AcseAuthenticator == null) + { + iedServer_AcseAuthenticator = new IedServer_AcseAuthenticator(InternalAcseAuthenticator); + IedServer_setAuthenticator(self, iedServer_AcseAuthenticator, IntPtr.Zero); + } + } + + private bool InternalAcseAuthenticator(IntPtr parameter, IntPtr authParameter, IntPtr securityToken, IntPtr appReference) + { + if(acseAuthenticatorHandler != null && authParameter != IntPtr.Zero && appReference != IntPtr.Zero) + { + AcseAuthenticationParameter acseAuthenticationParameter = new AcseAuthenticationParameter(authParameter); + IsoApplicationReference isoApplicationReference = new IsoApplicationReference(appReference); + GCHandle token = GCHandle.FromIntPtr(securityToken); + return acseAuthenticatorHandler(acseAuthenticatorHandlerParameter, acseAuthenticationParameter, token as object, isoApplicationReference); + } + + return false; + } + public delegate MmsDataAccessError ReadAccessHandler(LogicalDevice ld, LogicalNode ln, DataObject dataObject, FunctionalConstraint fc, ClientConnection connection, object parameter); private ReadAccessHandler readAccessHandler = null; diff --git a/dotnet/server_example_access_control/Program.cs b/dotnet/server_example_access_control/Program.cs index 2e6784e1..ac67dbef 100644 --- a/dotnet/server_example_access_control/Program.cs +++ b/dotnet/server_example_access_control/Program.cs @@ -17,6 +17,7 @@ using IEC61850.Client; using ReportControlBlock = IEC61850.Server.ReportControlBlock; using IEC61850.Model; using System.Data.Common; +using IEC61850; namespace server_access_control { @@ -142,12 +143,23 @@ namespace server_access_control /* Install handler to control access to control blocks (RCBs, LCBs, GoCBs, SVCBs, SGCBs)*/ bool ControlBlockAccessCallBack(object parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice ld, LogicalNode ln, string objectName, string subObjectName, ControlBlockAccessType accessType) { + string password = parameter as string; + object securityToken = connection.GetSecurityToken(); + + if(securityToken != null) + { + if ((securityToken as string == password)) + Console.WriteLine("Correct securityToken"); + else + Console.WriteLine("Incorrect securityToken"); + } + Console.WriteLine(acsiClass.ToString() + " "+ accessType.ToString() + " access " + ld.GetName() + ln.GetName() +"/"+ objectName + "." + subObjectName + "\n"); return true; } - iedServer.SetControlBlockAccessHandler(ControlBlockAccessCallBack, iedServer); + iedServer.SetControlBlockAccessHandler(ControlBlockAccessCallBack, "securityToken_password"); /* By default access to variables with FC=DC and FC=CF is not allowed. * This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used @@ -332,6 +344,22 @@ namespace server_access_control iedServer.SetSVCBHandler(sVCBEventHandler, sampledValuesControlBlock_1, null); iedServer.SetSVCBHandler(sVCBEventHandler, sampledValuesControlBlock_2, null); + + bool clientAuthenticator (object parameter, AcseAuthenticationParameter authParameter, object securityToken, IsoApplicationReference isoApplicationReference) + { + Console.WriteLine("ACSE Authenticator:\n"); + + IEC61850.AcseAuthenticationMechanism acseAuthenticationMechanism = authParameter.GetAuthMechanism(); + + if (acseAuthenticationMechanism == IEC61850.AcseAuthenticationMechanism.ACSE_AUTH_PASSWORD) + { + + } + return false; + } + + iedServer.SetAuthenticator(clientAuthenticator, null); + iedServer.Start(102); if (iedServer.IsRunning()) diff --git a/examples/iec61850_client_example5/client_example5.c b/examples/iec61850_client_example5/client_example5.c index e5bb22b7..973057a7 100644 --- a/examples/iec61850_client_example5/client_example5.c +++ b/examples/iec61850_client_example5/client_example5.c @@ -84,6 +84,8 @@ main(int argc, char** argv) printf("Failed to connect to %s:%i\n", hostname, tcpPort); } + while (true); + IedConnection_destroy(con); AcseAuthenticationParameter_destroy(auth); diff --git a/src/mms/inc/iso_connection_parameters.h b/src/mms/inc/iso_connection_parameters.h index cc443daf..af5a3db0 100644 --- a/src/mms/inc/iso_connection_parameters.h +++ b/src/mms/inc/iso_connection_parameters.h @@ -91,6 +91,9 @@ AcseAuthenticationParameter_destroy(AcseAuthenticationParameter self); LIB61850_API void AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, AcseAuthenticationMechanism mechanism); +LIB61850_API AcseAuthenticationMechanism +AcseAuthenticationParameter_getAuthMechanism(AcseAuthenticationParameter self); + LIB61850_API void AcseAuthenticationParameter_setPassword(AcseAuthenticationParameter self, char* password); diff --git a/src/mms/iso_common/iso_connection_parameters.c b/src/mms/iso_common/iso_connection_parameters.c index 858def8d..2478db6e 100644 --- a/src/mms/iso_common/iso_connection_parameters.c +++ b/src/mms/iso_common/iso_connection_parameters.c @@ -63,6 +63,12 @@ AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, A self->mechanism = mechanism; } +AcseAuthenticationMechanism +AcseAuthenticationParameter_getAuthMechanism(AcseAuthenticationParameter self) +{ + return self->mechanism; +} + IsoConnectionParameters IsoConnectionParameters_create() {