OPC UA基础SDK:服务器没有分配实例证书

本文关键字:分配 实例 证书 服务器 UA 基础 SDK OPC | 更新日期: 2023-09-27 17:54:23

我正在使用c#的Foundation SDK,试图以最小的方式启动一个简单的服务器。

这是我到目前为止的尝试。

public void StartServer()
{
    var config = new ApplicationConfiguration
    {
        ApplicationName = "TestServer",
        ApplicationType = ApplicationType.Client,
        SecurityConfiguration = new SecurityConfiguration
        {
            ApplicationCertificate = new CertificateIdentifier
            {
                StoreType = @"Windows", 
                StorePath = @"CurrentUser'My",
                SubjectName = Utils.Format(@"CN={0}, DC={1}", "TestServer", Dns.GetHostName())
            }, 
            TrustedPeerCertificates = new CertificateTrustList
            {
                StoreType = @"Windows", 
                StorePath = @"CurrentUser'TrustedPeople",
            }, 
            NonceLength = 32, 
            AutoAcceptUntrustedCertificates = true,
            ConfigureFirewall = false
        },
        TransportConfigurations = new TransportConfigurationCollection(),
        TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
        ServerConfiguration = new ServerConfiguration
        {
            SecurityPolicies = new ServerSecurityPolicyCollection
            {
                new ServerSecurityPolicy
                {
                    SecurityLevel = 0,
                    SecurityMode = MessageSecurityMode.None,
                    SecurityPolicyUri = "http://opcfoundation.org/UA/SecurityPolicy#None"
                }
            },
            UserTokenPolicies = new UserTokenPolicyCollection
            {
                new UserTokenPolicy { TokenType = UserTokenType.Anonymous }
            },
            DiagnosticsEnabled = true,
            MaxSessionCount = 100,
            MinSessionTimeout = 5000,
            MaxSessionTimeout = 10000,
            MaxBrowseContinuationPoints = 10,
            MaxQueryContinuationPoints = 10,
            MaxHistoryContinuationPoints = 100,
            MaxRequestAge = 600000,
            MinPublishingInterval = 100,
            MaxPublishingInterval = 3600000,
            PublishingResolution = 50,
            MaxSubscriptionLifetime = 3600000,
            MaxMessageQueueSize = 10,
            MaxNotificationQueueSize = 100,
            MaxNotificationsPerPublish = 1000,
            MinMetadataSamplingInterval = 1000
        }
    };
    config.Validate(ApplicationType.Server);
    var server = new MyCustomServer();
    server.Start(config);
}

当我尝试调用该方法时,我得到以下异常:

Opc.Ua.ServiceResultException: Server does not have an instance certificate assigned.
   à Opc.Ua.ServerBase.OnServerStarting(ApplicationConfiguration configuration) dans ...'OPC Foundation'Stack'Core'Stack'Server'ServerBase.cs:ligne 1607
   à Opc.Ua.Server.StandardServer.OnServerStarting(ApplicationConfiguration configuration) dans ...'OPC Foundation'SampleApplications'SDK'Server'Server'StandardServer.cs:ligne 2628
   à Opc.Ua.ServerBase.Start(ApplicationConfiguration configuration) dans ...'OPC Foundation'Stack'Core'Stack'Server'ServerBase.cs:ligne 232
   à SlimFixtures.ServerDriver.StartServer() dans ...'ServerDriver.cs:ligne 71

我做错了什么?

OPC UA基础SDK:服务器没有分配实例证书

所以您发现基于基础代码的服务器总是需要证书。创建自签名证书很容易,如果您使用的是当前用户/我的Windows商店,则不需要管理员登录。

您可以在验证后调用此扩展方法:

config.Validate(ApplicationType.Server);
config.EnsureApplicationCertificate();
其他地方的

public static class ServiceExtensions
{
    /// <summary>
    /// Ensures the application certificate is present and valid.
    /// </summary>
    public static void EnsureApplicationCertificate(this ApplicationConfiguration configuration)
    {
        const ushort keySize = 1024;
        const ushort lifetimeInMonths = 300;
        if (configuration == null)
        {
            throw new ArgumentNullException("configuration");
        }
        bool errorFlag = false;
        string hostName = Dns.GetHostName();
        var serverDomainNames = configuration.GetServerDomainNames();
        var applicationCertificate = configuration.SecurityConfiguration.ApplicationCertificate;
        var certificate = applicationCertificate.Find(true);
        if (certificate != null)
        {
            // if cert found then check domains
            var domainsFromCertficate = Utils.GetDomainsFromCertficate(certificate);
            foreach (string serverDomainName in serverDomainNames)
            {
                if (Utils.FindStringIgnoreCase(domainsFromCertficate, serverDomainName))
                {
                    continue;
                }
                if (String.Equals(serverDomainName, "localhost", StringComparison.OrdinalIgnoreCase))
                {
                    if (Utils.FindStringIgnoreCase(domainsFromCertficate, hostName))
                    {
                        continue;
                    }
                    var hostEntry = Dns.GetHostEntry(hostName);
                    if (hostEntry.Aliases.Any(alias => Utils.FindStringIgnoreCase(domainsFromCertficate, alias)))
                    {
                        continue;
                    }
                    if (hostEntry.AddressList.Any(ipAddress => Utils.FindStringIgnoreCase(domainsFromCertficate, ipAddress.ToString())))
                    {
                        continue;
                    }
                }
                Trace.TraceInformation("The application is configured to use domain '{0}' which does not appear in the certificate.", serverDomainName);
                errorFlag = true;
            } // end for
            // if no errors and keySizes match
            if (!errorFlag && (keySize == certificate.PublicKey.Key.KeySize))
            {
                return; // cert okay
            }
        }
        // if we get here then we'll create a new cert
        if (certificate == null)
        {
            certificate = applicationCertificate.Find(false);
            if (certificate != null)
            {
                Trace.TraceInformation("Matching certificate with SubjectName '{0}' found but without a private key.", applicationCertificate.SubjectName);
            }
        }
        // lets check if there is any to delete
        if (certificate != null)
        {
            using (var store2 = applicationCertificate.OpenStore())
            {
                store2.Delete(certificate.Thumbprint);
            }
        }
        if (serverDomainNames.Count == 0)
        {
            serverDomainNames.Add(hostName);
        }
        CertificateFactory.CreateCertificate(applicationCertificate.StoreType, applicationCertificate.StorePath, configuration.ApplicationUri, configuration.ApplicationName, null, serverDomainNames, keySize, lifetimeInMonths);
        Trace.TraceInformation("Created new certificate with SubjectName '{0}', in certificate store '{1}'.", applicationCertificate.SubjectName, applicationCertificate.StorePath);
        configuration.CertificateValidator.Update(configuration.SecurityConfiguration);
    }
}

对于较新的库版本,有一个内置选项来检查应用程序实例证书。它在ApplicationInstance类上可用。

你可以这样使用它:

var applicationConfiguration = new ApplicationConfiguration
{
    ApplicationName = "Aggregation server",
    ...
};
await applicationConfiguration.Validate(ApplicationType.ClientAndServer);
var applicationInstance = new ApplicationInstance(applicationConfiguration);
// This call will check that the application instance certificate exists, and will create it if not
var result =
    await applicationInstance.CheckApplicationInstanceCertificate(false, CertificateFactory.DefaultKeySize);
var server = new AggregationServer();
await applicationInstance.Start(server);
System.Console.ReadKey();
server.Stop();