OPC UA Foundation SDK:服务器未分配实例证书

问题描述 投票:1回答:2

我正在使用带有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

我究竟做错了什么?

c# opc opc-ua
2个回答
2
投票

因此,您发现基于基础代码的服务器始终需要证书。创建自签名证书很简单,如果您使用的是当前用户/我的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);
    }

}

0
投票

使用更新版本的库,有一个内置选项来检查应用程序实例证书。它可以在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();
热门问题
推荐问题
最新问题