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
我做错了什么?
所以您发现基于基础代码的服务器总是需要证书。创建自签名证书很容易,如果您使用的是当前用户/我的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();