OPCFoundation / UA-.NETStandard

OPC Unified Architecture .NET Standard
Other
1.95k stars 945 forks source link

Xamarin Android OPC UA Client - Establishing a secure connection by adding the server's certificate as an asset #502

Closed DaLammel closed 5 years ago

DaLammel commented 6 years ago

Hi everyone,

I'm currently trying to get my Xamarin Android Client to establish a secure connection to my OPC UA Server, but as soon as I try to enable any security features in the client's code it won't connect to the server anymore. The server is currently set up to support the SecurityPolicies "None" and "Basic256Sha256", as well as SecurityModes "None", "Sign" and "SignAndEncrypt". My goal is to disable both "None" options and only allow secure connections on the server.

The server also forces user authentication via username/password, however this part doesn't cause me any problems.

This whole project is more of a proof of concept and I know that I'll only ever use the client with this exact server. Therefore I want to include the server's certificate as an asset into my app and automatically use it as a "trusted" certificate so that I don't have to implement a way to accept the certificate manually.

This is how I've tried to copy the server certificate from the project's assets in my Client.cs:

        string serverCertFilename = "server_selfsigned_cert_2048.pem";
        string PKIPath = "/storage/emulated/0/OPC Foundation/PKI/";
        Directory.CreateDirectory(PKIPath + "trusted/");
        ServerCertPath = PKIPath + "trusted/" + serverCertFilename;

        [...]
        // in case the server certificate file doesn't exist: create new certificate file in internal storage as a copy of the Asset server certificate
        if (!File.Exists(ServerCertPath))
        {
            assets.Open(serverCertFilename).CopyTo(File.Create(ServerCertPath));
            /* string content;
            using (StreamReader sr = new StreamReader(assets.Open(serverCertFilename)))
            {
                content = sr.ReadToEnd();
            }
            File.WriteAllText(ServerCertPath, content);*/
        }

The corresponding settings in my ApplicationConfiguration look like this:

Directory /storage/emulated/0/OPC Foundation/PKI/own CN=AIS_Demonstrator_HMI_Applikation, O=AIS Directory /storage/emulated/0/OPC Foundation/PKI/issuer Directory /storage/emulated/0/OPC Foundation/PKI/trusted Directory /storage/emulated/0/OPC Foundation/PKI/rejected true

Lastly, my configuredEndpoint and session creation looks like this:

            Uri endpointURI = new Uri(endpointURL);
            var selectedEndpoint = CoreClientUtils.SelectEndpoint(endpointURL, false, 15000);
            var endpointConfiguration = EndpointConfiguration.Create(config);
            var endpoint = new ConfiguredEndpoint(selectedEndpoint.Server, endpointConfiguration);
            endpoint.Update(selectedEndpoint);

            var platform = Device.RuntimePlatform;
            var sessionName = "AIS Demonstrator Android Applikation";
            UserTokenPolicy utp = new UserTokenPolicy();
            utp.TokenType = UserTokenType.UserName;
            UserTokenPolicyCollection utpCollection = new UserTokenPolicyCollection();
            utpCollection.Add(utp);
            selectedEndpoint.UserIdentityTokens = utpCollection;
            selectedEndpoint.SecurityMode = MessageSecurityMode.SignAndEncrypt; // this doesn't seem to have any effect whatsoever
            UserIdentity SessionUserIdentity = new UserIdentity(MainActivity.UserName, MainActivity.UserPassword);
            session = await Session.Create(config, endpoint, false, sessionName, 30000, SessionUserIdentity, null);

My Problem is: as soon as i try to change any one (or all) of the following settings, my client can't connect to my server anymore:

What am I doing wrong? And is there an easier/better way to include the server's certificates in my client app? I would greatly appreciate any and all help I can get, thank you in advance and have a nice day!

AlinMoldovean commented 6 years ago

Hello @DaLammel ,

You should try using the CertificateValidator.CertificateValidation event. The event is triggered in case a certificate is not trusted during the validation and you can decide in application code if it can be accepted.

An example can be found in NetCoreConsoleClient project

config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation);

private static void CertificateValidator_CertificateValidation(CertificateValidator validator, CertificateValidationEventArgs e)
        {
            if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted)
            {
                e.Accept = autoAccept;
                if (autoAccept)
                {
                    Console.WriteLine("Accepted Certificate: {0}", e.Certificate.Subject);
                }
                else
                {
                    Console.WriteLine("Rejected Certificate: {0}", e.Certificate.Subject);
                }
            }
        }