'OPC UA Secure connection in C#

I am quite new to OPC UA protocol; I recently wrote a C interface to connect to some machines using the libraries from OPCFoundation, and so far I did not have to deal with certificates, since all the machines allowed unsecured connections.

Having now to connect to a machine that uses certificates, how should I modify my code in order to simulate the "trust server certificate" action I can take on UAExpert software, which warns about the certificate, but allows me to trust the certificate from the machine (saving it to a local folder) and continue with the session?

In my code, I have "AutoAcceptUntrustedCertificates = true", but when I try to open the session I get a

Opc.Ua.ServiceResultException "Certificate is not trusted.\r\nSubjectName: [email protected] ..."

Thanks in advance

    using Opc.Ua;
    using Opc.Ua.Client;
    using Opc.Ua.Configuration;

    private static String CallOpcUA(string indirizzoMacchina, string displayNome, string idNodo)
    {
        var config = new ApplicationConfiguration()
        {
            ApplicationName = "MyApp",
            ApplicationUri = Utils.Format(@"urn:{0}:MyApp", System.Net.Dns.GetHostName()),
            ApplicationType = ApplicationType.Client,
            SecurityConfiguration = new SecurityConfiguration
            {
                ApplicationCertificate = new CertificateIdentifier { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault", SubjectName = "MyApp" },
                TrustedIssuerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Certificate Authorities" },
                TrustedPeerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Applications" },
                RejectedCertificateStore = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\RejectedCertificates" },
                AutoAcceptUntrustedCertificates = true
            },
            TransportConfigurations = new TransportConfigurationCollection(),
            TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
            ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
            TraceConfiguration = new TraceConfiguration()
        };
        config.Validate(ApplicationType.Client).GetAwaiter().GetResult();
        if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
        {
            config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); };
            config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateTimeInvalid); };
        }

        var application = new ApplicationInstance
        {
            ApplicationName = "MyApplication",
            ApplicationType = ApplicationType.Client,
            ApplicationConfiguration = config
        };

        try
        {
            application.CheckApplicationInstanceCertificate(false, 2048).GetAwaiter().GetResult();
        }
        catch (System.IO.FileLoadException e)
        {
        }

        try
        {
            identity = new UserIdentity();

            var selectedEndpoint = CoreClientUtils.SelectEndpoint(indirizzoMacchina, useSecurity: false);

            using (var session = Session.Create(config, new ConfiguredEndpoint(null, selectedEndpoint, EndpointConfiguration.Create(config)), false, "", 60000, identity, null).GetAwaiter().GetResult())
            {
               
                [read value from the node]

            }

        }
        catch (Opc.Ua.ServiceResultException e)
        {
        }
        
    }


Solution 1:[1]

With OPC UA secure endpoint, you have always to provide a client certificate. You can't omit this, and the server should have this certificate in it's trust list. Otherwise the server will probably refuse your connection.

I can't see in your code, that you provide your client certificate.

You can't override this with a client side AutoAcceptUntrustedCertificates=true.

Solution 2:[2]

This will probably be to late for the author of the question, but it might help others.

Try adding a certificate validator which auto accepts untrusted certificates:

    var config = new ApplicationConfiguration()
    {
        ApplicationName = "MyApp",
        ApplicationUri = Utils.Format(@"urn:{0}:MyApp", System.Net.Dns.GetHostName()),
        ApplicationType = ApplicationType.Client,
        SecurityConfiguration = new SecurityConfiguration
        {
            ApplicationCertificate = new CertificateIdentifier { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault", SubjectName = "MyApp" },
            TrustedIssuerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Certificate Authorities" },
            TrustedPeerCertificates = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\UA Applications" },
            RejectedCertificateStore = new CertificateTrustList { StoreType = @"Directory", StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\RejectedCertificates" },
            AutoAcceptUntrustedCertificates = true
        },
        TransportConfigurations = new TransportConfigurationCollection(),
        TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
        ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
        TraceConfiguration = new TraceConfiguration(),

        // ***** ADD THIS ***** //
        CertificateValidator = new CertificateValidator() { AutoAcceptUntrustedCertificates = true },
    };

Solution 3:[3]

Just as a quick fix, replace this:

if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
{
    config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); };
    config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateTimeInvalid); };
}

For this:

if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
{
    config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = true; };
}

It worked for me with several different servers.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Frank Burkart
Solution 2 Fightingpolleke
Solution 3 joltra