/* ======================================================================== * Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Security.Cryptography.X509Certificates; using Microsoft.Extensions.Logging; using Opc.Ua.Bindings; using Opc.Ua.Security; namespace Opc.Ua { /// /// Stores the configurable configuration information for a UA application. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class ApplicationConfiguration { /// /// The default constructor. /// public ApplicationConfiguration() { Initialize(); } /// /// The default constructor. /// public ApplicationConfiguration(ITelemetryContext telemetry) { Initialize(telemetry); Initialize(); } /// /// The constructor from a template. /// public ApplicationConfiguration(ApplicationConfiguration template) { ApplicationName = template.ApplicationName; ApplicationType = template.ApplicationType; ApplicationUri = template.ApplicationUri; DiscoveryServerConfiguration = template.DiscoveryServerConfiguration; m_securityConfiguration = template.m_securityConfiguration; m_transportConfigurations = template.m_transportConfigurations; ServerConfiguration = template.ServerConfiguration; ClientConfiguration = template.ClientConfiguration; DisableHiResClock = template.DisableHiResClock; CertificateValidator = template.CertificateValidator; TransportQuotas = template.TransportQuotas; #pragma warning disable CS0618 // Type or member is obsolete TraceConfiguration = template.TraceConfiguration; #pragma warning restore CS0618 // Type or member is obsolete m_extensions = template.m_extensions; m_extensionObjects = template.m_extensionObjects; SourceFilePath = template.SourceFilePath; m_properties = template.m_properties; m_telemetry = template.m_telemetry; m_logger = template.m_logger; } /// /// Sets private members to default values. /// private void Initialize() { SourceFilePath = null; m_securityConfiguration = new SecurityConfiguration(); m_transportConfigurations = []; DisableHiResClock = false; m_properties = []; m_extensionObjects = []; CertificateValidator ??= new CertificateValidator(m_telemetry); m_logger ??= m_telemetry.CreateLogger(); } /// /// Initialize telemetry context - after loading /// /// The telemetry context to use to create obvservability instruments internal void Initialize(ITelemetryContext telemetry) { m_telemetry = telemetry; m_logger = telemetry.CreateLogger(); CertificateValidator = new CertificateValidator(m_telemetry); } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { m_telemetry = AmbientMessageContext.Telemetry; Initialize(); } /// /// Gets an object used to synchronize access to the properties dictionary. /// /// /// The object used to synchronize access to the properties dictionary. /// public object PropertiesLock => m_properties; /// /// Gets a dictionary used to save state associated with the application. /// /// /// The dictionary used to save state associated with the application. /// public IDictionary Properties => m_properties; /// /// Storage for decoded extensions of the application. /// Used by ParseExtension if no matching XmlElement is found. /// public IList ExtensionObjects => m_extensionObjects; /// /// A descriptive name for the application (not necessarily unique). /// /// The name of the application. [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 0)] public string ApplicationName { get; set; } /// /// A unique identifier for the application instance. /// /// The application URI. [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 1)] public string ApplicationUri { get; set; } /// /// A unique identifier for the product. /// /// The product URI. [DataMember(IsRequired = false, Order = 2)] public string ProductUri { get; set; } /// /// The type of application. /// /// The type of the application. [DataMember(IsRequired = true, Order = 3)] public ApplicationType ApplicationType { get; set; } /// /// The security configuration for the application. /// /// The security configuration. [DataMember(IsRequired = false, EmitDefaultValue = true, Order = 4)] public SecurityConfiguration SecurityConfiguration { get => m_securityConfiguration; set => m_securityConfiguration = value ?? new SecurityConfiguration(); } /// /// The transport configuration for the application. /// /// The transport configurations. [DataMember(IsRequired = false, EmitDefaultValue = true, Order = 5)] public TransportConfigurationCollection TransportConfigurations { get => m_transportConfigurations; set => m_transportConfigurations = value ?? []; } /// /// The quotas that are used at the transport layer. /// /// The transport quotas. [DataMember(IsRequired = false, EmitDefaultValue = true, Order = 6)] public TransportQuotas TransportQuotas { get; set; } /// /// Additional configuration for server applications. /// /// The server configuration. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 7)] public ServerConfiguration ServerConfiguration { get; set; } /// /// Additional configuration for client applications. /// /// The client configuration. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 8)] public ClientConfiguration ClientConfiguration { get; set; } /// /// Additional configuration of the discovery server. /// /// The discovery server configuration. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 9)] public DiscoveryServerConfiguration DiscoveryServerConfiguration { get; set; } /// /// A bucket to store additional application specific configuration data. /// /// The extensions. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 10)] public XmlElementCollection Extensions { get => m_extensions; set => m_extensions = value; } /// /// Configuration of the trace and information about log file /// /// The trace configuration. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 11)] [Obsolete("Use ITelemetryContext and ILogger-based diagnostics instead.")] public TraceConfiguration TraceConfiguration { get; set; } /// /// Disabling / enabling high resolution clock /// /// true if high resolution clock is disabled; otherwise, false. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 12)] public bool DisableHiResClock { get; set; } private ITelemetryContext m_telemetry; private ILogger m_logger; private SecurityConfiguration m_securityConfiguration; private TransportConfigurationCollection m_transportConfigurations; private XmlElementCollection m_extensions; private List m_extensionObjects; private Dictionary m_properties; } /// /// Specifies various limits that apply to the transport or secure channel layers. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class TransportQuotas { /// /// The default constructor. /// public TransportQuotas() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { // encoding limits MaxMessageSize = DefaultEncodingLimits.MaxMessageSize; MaxStringLength = DefaultEncodingLimits.MaxStringLength; MaxByteStringLength = DefaultEncodingLimits.MaxByteStringLength; MaxArrayLength = DefaultEncodingLimits.MaxArrayLength; MaxEncodingNestingLevels = DefaultEncodingLimits.MaxEncodingNestingLevels; MaxDecoderRecoveries = DefaultEncodingLimits.MaxDecoderRecoveries; // message limits MaxBufferSize = TcpMessageLimits.DefaultMaxBufferSize; OperationTimeout = TcpMessageLimits.DefaultOperationTimeout; ChannelLifetime = TcpMessageLimits.DefaultChannelLifetime; SecurityTokenLifetime = TcpMessageLimits.DefaultSecurityTokenLifeTime; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// The default timeout to use when sending requests (in milliseconds). /// /// The operation timeout. [DataMember(IsRequired = false, Order = 0)] public int OperationTimeout { get; set; } /// /// The maximum length of string encoded in a message body. /// /// The max length of the string. [DataMember(IsRequired = false, Order = 1)] public int MaxStringLength { get; set; } /// /// The maximum length of a byte string encoded in a message body. /// /// The max length of the byte string. [DataMember(IsRequired = false, Order = 2)] public int MaxByteStringLength { get; set; } /// /// The maximum length of an array encoded in a message body. /// /// The max length of the array. [DataMember(IsRequired = false, Order = 3)] public int MaxArrayLength { get; set; } /// /// The maximum length of a message body. /// /// The max size of the message. [DataMember(IsRequired = false, Order = 4)] public int MaxMessageSize { get; set; } /// /// The maximum size of the buffer to use when sending messages. /// /// The max size of the buffer. [DataMember(IsRequired = false, Order = 5)] public int MaxBufferSize { get; set; } /// /// The maximum nesting level accepted while encoding or decoding objects. /// [DataMember(IsRequired = false, Order = 6)] public int MaxEncodingNestingLevels { get; set; } /// /// The number of times the decoder can recover from a decoder error /// of an IEncodeable before throwing a decoder error. /// [DataMember(IsRequired = false, Order = 7)] public int MaxDecoderRecoveries { get; set; } /// /// The lifetime of a secure channel (in milliseconds). /// /// The channel lifetime. [DataMember(IsRequired = false, Order = 8)] public int ChannelLifetime { get; set; } /// /// The lifetime of a security token (in milliseconds). /// /// The security token lifetime. [DataMember(IsRequired = false, Order = 9)] public int SecurityTokenLifetime { get; set; } } /// /// Specifies parameters used for tracing. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class TraceConfiguration { /// /// The default constructor. /// public TraceConfiguration() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { OutputFilePath = null; DeleteOnLoad = false; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// The output file used to log the trace information. /// /// The output file path. [DataMember(IsRequired = false, Order = 0)] public string OutputFilePath { get; set; } /// /// Whether the existing log file should be deleted when the application configuration is loaded. /// /// true if existing log file should be deleted when the application configuration is loaded; otherwise, false. [DataMember(IsRequired = false, Order = 1)] public bool DeleteOnLoad { get; set; } /// /// The masks used to select what is written to the output /// Masks supported by the trace feature: /// - Do not output any messages -None = 0x0; /// - Output error messages - Error = 0x1; /// - Output informational messages - Information = 0x2; /// - Output stack traces - StackTrace = 0x4; /// - Output basic messages for service calls - Service = 0x8; /// - Output detailed messages for service calls - ServiceDetail = 0x10; /// - Output basic messages for each operation - Operation = 0x20; /// - Output detailed messages for each operation - OperationDetail = 0x40; /// - Output messages related to application initialization or shutdown - StartStop = 0x80; /// - Output messages related to a call to an external system - ExternalSystem = 0x100; /// - Output messages related to security. - Security = 0x200; /// /// The trace masks. [DataMember(IsRequired = false, Order = 2)] public int TraceMasks { get; set; } } /// /// Specifies the configuration information for a transport protocol /// /// /// Each application is allows to have one transport configure per protocol type. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class TransportConfiguration { /// /// The default constructor. /// public TransportConfiguration() { } /// /// The default constructor. /// /// The URL scheme. /// The type. public TransportConfiguration(string urlScheme, Type type) { UriScheme = urlScheme; TypeName = type.AssemblyQualifiedName; } /// /// The URL prefix used by the application (http, opc.tcp, net.tpc, etc.). /// /// The URI scheme. [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 0)] public string UriScheme { get; set; } /// /// The name of the class that defines the binding for the transport. /// /// The name of the type. /// /// /// This can be any instance of the System.ServiceModel.Channels.Binding class /// that implements these constructors: /// /// /// XxxBinding(EndpointDescription description, EndpointConfiguration configuration); /// XxxBinding(IList{EndpointDescription} descriptions, EndpointConfiguration configuration) /// XxxBinding(EndpointConfiguration configuration) /// /// [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 1)] public string TypeName { get; set; } } /// /// A collection of TransportConfiguration objects. /// [CollectionDataContract( Name = "ListOfTransportConfiguration", Namespace = Namespaces.OpcUaConfig, ItemName = "TransportConfiguration" )] public class TransportConfigurationCollection : List { /// /// Initializes an empty collection. /// public TransportConfigurationCollection() { } /// /// Initializes the collection from another collection. /// /// A collection of values to add to this new collection /// /// is null. /// public TransportConfigurationCollection(IEnumerable collection) : base(collection) { } /// /// Initializes the collection with the specified capacity. /// /// The capacity. public TransportConfigurationCollection(int capacity) : base(capacity) { } } /// /// A class that defines a group of security policies supported by the server. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class ServerSecurityPolicy { /// /// The default constructor. /// public ServerSecurityPolicy() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { SecurityMode = MessageSecurityMode.SignAndEncrypt; SecurityPolicyUri = SecurityPolicies.Basic256Sha256; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// Obsolete version of CalculateSecurityLevel that does not take a logger. /// [Obsolete("Use CalculateSecurityLevel(MessageSecurityMode mode, string policyUri, ILogger logger) instead.")] public static byte CalculateSecurityLevel( MessageSecurityMode mode, string policyUri) { return SecuredApplication.CalculateSecurityLevel(mode, policyUri); } /// /// Calculates the security level, given the security mode and policy /// Invalid and none is discouraged /// Just signing is always weaker than any use of encryption /// public static byte CalculateSecurityLevel( MessageSecurityMode mode, string policyUri, ILogger logger) { return SecuredApplication.CalculateSecurityLevel(mode, policyUri, logger); } /// /// Specifies whether the messages are signed and encrypted or simply signed /// /// The security mode. [DataMember(IsRequired = false, Order = 1)] public MessageSecurityMode SecurityMode { get; set; } /// /// The security policy to use. /// /// The security policy URI. [DataMember(IsRequired = false, Order = 2)] public string SecurityPolicyUri { get; set; } } /// /// A collection of ServerSecurityPolicy objects. /// [CollectionDataContract( Name = "ListOfServerSecurityPolicy", Namespace = Namespaces.OpcUaConfig, ItemName = "ServerSecurityPolicy" )] public class ServerSecurityPolicyCollection : List { /// /// Initializes an empty collection. /// public ServerSecurityPolicyCollection() { } /// /// Initializes the collection from another collection. /// /// A collection of values to add to this new collection /// /// is null. /// public ServerSecurityPolicyCollection(IEnumerable collection) : base(collection) { } /// /// Initializes the collection with the specified capacity. /// /// The capacity. public ServerSecurityPolicyCollection(int capacity) : base(capacity) { } } /// /// The security configuration for the application. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class SecurityConfiguration { /// /// The default constructor. /// public SecurityConfiguration() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { m_applicationCertificates = []; m_trustedIssuerCertificates = new CertificateTrustList(); m_trustedPeerCertificates = new CertificateTrustList(); NonceLength = 32; MaxRejectedCertificates = 5; AutoAcceptUntrustedCertificates = false; RejectSHA1SignedCertificates = true; RejectUnknownRevocationStatus = false; MinimumCertificateKeySize = CertificateFactory.DefaultKeySize; AddAppCertToTrustedStore = true; SendCertificateChain = true; SuppressNonceValidationErrors = false; IsDeprecatedConfiguration = false; } /// /// Initializes the object during deserialization. /// [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// The application instance certificate. /// Kept for backward compatibility with configuration files which only support RSA certificates. /// /// The application certificate. /// /// This certificate must contain the application uri. /// For servers, URLs for each supported protocol must also be present. /// [IgnoreDataMember] public CertificateIdentifier ApplicationCertificate { get { if (m_applicationCertificates.Count > 0) { return m_applicationCertificates[0]; } return null; } set { if (m_applicationCertificates.Count > 0) { if (value == null) { m_applicationCertificates.RemoveAt(0); } else { m_applicationCertificates[0] = value; } } else { m_applicationCertificates.Add(value); } SupportedSecurityPolicies = BuildSupportedSecurityPolicies(); m_applicationCertificates[0].CertificateType = ObjectTypeIds .RsaSha256ApplicationCertificateType; IsDeprecatedConfiguration = true; } } /// /// This private property exists solely to control serialization of the legacy single /// certificate element. It is emitted only when the configuration was marked deprecated. /// [DataMember(Name = "ApplicationCertificate", IsRequired = false, EmitDefaultValue = false, Order = 0)] private CertificateIdentifier ApplicationCertificateLegacy { get => IsDeprecatedConfiguration ? ApplicationCertificate : null; set => ApplicationCertificate = value; } /// /// The application instance certificates in use for the application. /// [IgnoreDataMember] public CertificateIdentifierCollection ApplicationCertificates { get => m_applicationCertificates; set { if (value == null || value.Count == 0) { m_applicationCertificates = []; return; } // If both legacy () and modern () elements // are present during deserialization (as a consequence of previous serialization that included both unintentionally), // prefer the modern representation and clear the // deprecated flag when we process the collection below. var newCertificates = new CertificateIdentifierCollection(value); // Remove unsupported certificate types for (int i = newCertificates.Count - 1; i >= 0; i--) { if (!Utils.IsSupportedCertificateType(newCertificates[i].CertificateType)) { // TODO: Log when ITelemetry instance is available newCertificates.RemoveAt(i); } } // Remove any duplicates based on thumbprint // Only perform duplicate detection if we have actual loaded certificates for (int i = 0; i < newCertificates.Count; i++) { for (int j = newCertificates.Count - 1; j > i; j--) { bool isDuplicate = false; // Only check for duplicates if both certificates are actually loaded if (newCertificates[i].Certificate != null && newCertificates[j].Certificate != null) { // Compare by actual certificate thumbprint isDuplicate = newCertificates[i].Certificate.Thumbprint.Equals( newCertificates[j].Certificate.Thumbprint, StringComparison.OrdinalIgnoreCase); } // If certificates aren't loaded yet, compare by explicit thumbprint configuration else if (!string.IsNullOrEmpty(newCertificates[i].Thumbprint) && !string.IsNullOrEmpty(newCertificates[j].Thumbprint)) { isDuplicate = newCertificates[i].Thumbprint.Equals( newCertificates[j].Thumbprint, StringComparison.OrdinalIgnoreCase); } if (isDuplicate) { newCertificates.RemoveAt(j); } } } m_applicationCertificates = newCertificates; // Presence of the modern collection takes precedence over legacy; clear the flag so // hybrid configurations are treated as modern. IsDeprecatedConfiguration = false; SupportedSecurityPolicies = BuildSupportedSecurityPolicies(); } } /// /// This private property exists solely to control the serialization of the modern certificates collection. /// Emit only when the configuration is not marked deprecated. /// [DataMember(Name = "ApplicationCertificates", IsRequired = false, EmitDefaultValue = false, Order = 1)] private CertificateIdentifierCollection ApplicationCertificatesDataContract { get => IsDeprecatedConfiguration ? null : ApplicationCertificates; set => ApplicationCertificates = value; } /// /// The store containing any additional issuer certificates. /// [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 2)] public CertificateTrustList TrustedIssuerCertificates { get => m_trustedIssuerCertificates; set => m_trustedIssuerCertificates = value ?? new CertificateTrustList(); } /// /// The trusted certificate store. /// [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 4)] public CertificateTrustList TrustedPeerCertificates { get => m_trustedPeerCertificates; set => m_trustedPeerCertificates = value ?? new CertificateTrustList(); } /// /// The length of nonce in the CreateSession service. /// /// /// The length of nonce in the CreateSession service. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 6)] public int NonceLength { get; set; } /// /// A store where invalid certificates can be placed for later review by the administrator. /// /// /// A store where invalid certificates can be placed for later review by the administrator. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 7)] public CertificateStoreIdentifier RejectedCertificateStore { get; set; } /// /// Gets or sets a value indicating how many certificates are kept /// in the rejected store before the oldest is removed. /// /// /// This value can be set by applications. /// The number of certificates to keep in the rejected store before it is updated. /// to keep all rejected certificates. /// A negative number to keep no history. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 8)] public int MaxRejectedCertificates { get; set; } /// /// Gets or sets a value indicating whether untrusted certificates should be automatically accepted. /// /// /// This flag can be set to by servers that allow anonymous clients or use user credentials for authentication. /// It can be set by clients that connect to URLs specified in configuration rather than with user entry. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 9)] public bool AutoAcceptUntrustedCertificates { get; set; } /// /// Gets or sets a directory which contains files representing users roles. /// [DataMember(Order = 10)] public string UserRoleDirectory { get; set; } /// /// Gets or sets a value indicating whether SHA-1 signed certificates are accepted. /// /// /// This flag can be set to false by servers that accept SHA-1 signed certificates. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 11)] public bool RejectSHA1SignedCertificates { get; set; } /// /// Gets or sets a value indicating whether certificates with unavailable revocation lists are not accepted. /// /// /// This flag can be set to true by servers that must have a revocation list for each CA (even if empty). /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 12)] public bool RejectUnknownRevocationStatus { get; set; } /// /// Gets or sets a value indicating which minimum certificate key strength is accepted. /// The value is ignored for certificates with a ECDSA signature. /// /// /// This value can be set to 1024, 2048 or 4096 by servers /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 13)] public ushort MinimumCertificateKeySize { get; set; } /// /// Gets or sets a value indicating whether the Validator skips the full chain validation /// for already validated or accepted certificates. /// /// /// This flag can be set to true by applications. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 14)] public bool UseValidatedCertificates { get; set; } /// /// Gets or sets a value indicating whether the application cert should be copied to the trusted store. /// /// /// It is useful for client/server applications running on the same host and sharing the cert store to autotrust. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 15)] public bool AddAppCertToTrustedStore { get; set; } /// /// Gets or sets a value indicating whether the application should send the complete certificate chain. /// /// /// If set to true the complete certificate chain will be sent for CA signed certificates. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 16)] public bool SendCertificateChain { get; set; } /// /// The store containing additional user issuer certificates. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 17)] public CertificateTrustList UserIssuerCertificates { get => m_userIssuerCertificates; set => m_userIssuerCertificates = value ?? new CertificateTrustList(); } /// /// The store containing trusted user certificates. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 18)] public CertificateTrustList TrustedUserCertificates { get => m_trustedUserCertificates; set => m_trustedUserCertificates = value ?? new CertificateTrustList(); } /// /// The store containing additional Https issuer certificates. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 19)] public CertificateTrustList HttpsIssuerCertificates { get => m_httpsIssuerCertificates; set => m_httpsIssuerCertificates = value ?? new CertificateTrustList(); } /// /// The store containing trusted Https certificates. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 20)] public CertificateTrustList TrustedHttpsCertificates { get => m_trustedHttpsCertificates; set => m_trustedHttpsCertificates = value ?? new CertificateTrustList(); } /// /// Gets or sets a value indicating whether the server nonce validation errors should be suppressed. /// /// /// Allows client interoperability with legacy servers which do not comply with the specification for nonce usage. /// If set to true the server nonce validation errors are suppressed. /// Please set this flag to true only in close and secured networks since it can cause security vulnerabilities. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 21)] public bool SuppressNonceValidationErrors { get; set; } /// /// The type of Configuration (deprecated or not) /// public bool IsDeprecatedConfiguration { get; set; } private CertificateIdentifierCollection m_applicationCertificates; private CertificateTrustList m_trustedIssuerCertificates; private CertificateTrustList m_trustedPeerCertificates; private CertificateTrustList m_httpsIssuerCertificates; private CertificateTrustList m_trustedHttpsCertificates; private CertificateTrustList m_userIssuerCertificates; private CertificateTrustList m_trustedUserCertificates; } /// /// A class that defines a group of sampling rates supported by the server. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class SamplingRateGroup { /// /// The default constructor. /// public SamplingRateGroup() { Initialize(); } /// /// Creates a group with the specified settings. /// /// The start. /// The increment. /// The count. public SamplingRateGroup(int start, int increment, int count) { Start = start; Increment = increment; Count = count; } /// /// Sets private members to default values. /// private void Initialize() { Start = 1000; Increment = 0; Count = 0; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// The first sampling rate in the group (in milliseconds). /// /// The first sampling rate in the group (in milliseconds). [DataMember(IsRequired = false, Order = 1)] public double Start { get; set; } /// /// The increment between sampling rates in the group (in milliseconds). /// /// The increment. /// /// An increment of 0 means the group only contains one sampling rate equal to the start. /// [DataMember(IsRequired = false, Order = 2)] public double Increment { get; set; } /// /// The number of sampling rates in the group. /// /// The count. /// /// A count of 0 means there is no limit. /// [DataMember(IsRequired = false, Order = 3)] public int Count { get; set; } } /// /// A collection of SamplingRateGroup objects. /// [CollectionDataContract( Name = "ListOfSamplingRateGroup", Namespace = Namespaces.OpcUaConfig, ItemName = "SamplingRateGroup" )] public class SamplingRateGroupCollection : List { /// /// Initializes an empty collection. /// public SamplingRateGroupCollection() { } /// /// Initializes the collection from another collection. /// /// A collection of values to add to this new collection /// /// is null. /// public SamplingRateGroupCollection(IEnumerable collection) : base(collection) { } /// /// Initializes the collection with the specified capacity. /// /// The capacity. public SamplingRateGroupCollection(int capacity) : base(capacity) { } } /// /// Specifies the configuration for a server application. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class ServerBaseConfiguration { /// /// The default constructor. /// public ServerBaseConfiguration() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { m_baseAddresses = []; m_alternateBaseAddresses = []; m_securityPolicies = []; MinRequestThreadCount = 10; MaxRequestThreadCount = 100; MaxQueuedRequestCount = 200; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// Remove unsupported security policies and expand wild cards. /// [OnDeserialized] private void ValidateSecurityPolicyCollection(StreamingContext context) { string[] supportedPolicies = Ua.SecurityPolicies.GetDisplayNames(); var newPolicies = new ServerSecurityPolicyCollection(); foreach (ServerSecurityPolicy securityPolicy in m_securityPolicies) { if (string.IsNullOrWhiteSpace(securityPolicy.SecurityPolicyUri)) { // add wild card policies foreach (string policyUri in Ua.SecurityPolicies.GetDefaultUris()) { var newPolicy = new ServerSecurityPolicy { SecurityMode = securityPolicy.SecurityMode, SecurityPolicyUri = policyUri }; if (newPolicies.Find(s => s.SecurityMode == newPolicy.SecurityMode && string.Equals( s.SecurityPolicyUri, newPolicy.SecurityPolicyUri, StringComparison.Ordinal) ) == null) { newPolicies.Add(newPolicy); } } } else { for (int i = 0; i < supportedPolicies.Length; i++) { if (securityPolicy.SecurityPolicyUri .Contains(supportedPolicies[i], StringComparison.Ordinal)) { if (newPolicies.Find(s => s.SecurityMode == securityPolicy.SecurityMode && string.Equals( s.SecurityPolicyUri, securityPolicy.SecurityPolicyUri, StringComparison.Ordinal) ) == null) { newPolicies.Add(securityPolicy); } break; } } } } m_securityPolicies = newPolicies; } /// /// The base addresses for the server. /// /// The base addresses. /// /// The actually endpoints are constructed from the security policies. /// On one base address per supported transport protocol is allowed. /// [DataMember(IsRequired = false, Order = 0)] public StringCollection BaseAddresses { get => m_baseAddresses; set => m_baseAddresses = value ?? []; } /// /// Gets or sets the alternate base addresses. /// /// The alternate base addresses. /// /// These addresses are used to specify alternate paths to ther via firewalls, proxies /// or similar network infrastructure. If these paths are specified in the configuration /// file then the server will use the domain of the URL used by the client to determine /// which, if any, or the alternate addresses to use instead of the primary addresses. /// [DataMember(IsRequired = false, Order = 1)] public StringCollection AlternateBaseAddresses { get => m_alternateBaseAddresses; set => m_alternateBaseAddresses = value ?? []; } /// /// The security policies supported by the server. /// /// The security policies. /// /// An endpoint description is created for each combination of base address and security policy. /// [DataMember(IsRequired = false, Order = 2)] public ServerSecurityPolicyCollection SecurityPolicies { get => m_securityPolicies; set => m_securityPolicies = value ?? []; } /// /// The minimum number of threads assigned to processing requests. /// /// The minimum request thread count. [DataMember(IsRequired = false, Order = 3)] public int MinRequestThreadCount { get; set; } /// /// The maximum number of threads assigned to processing requests. /// /// The maximum request thread count. [DataMember(IsRequired = false, Order = 4)] public int MaxRequestThreadCount { get; set; } /// /// The maximum number of requests that will be queued waiting for a thread. /// /// The maximum queued request count. [DataMember(IsRequired = false, Order = 5)] public int MaxQueuedRequestCount { get; set; } private StringCollection m_baseAddresses; private StringCollection m_alternateBaseAddresses; private ServerSecurityPolicyCollection m_securityPolicies; } /// /// Specifies the configuration for a server application. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class ServerConfiguration : ServerBaseConfiguration { /// /// The default constructor. /// public ServerConfiguration() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { m_userTokenPolicies = []; DiagnosticsEnabled = false; MaxSessionCount = 100; MaxChannelCount = 1000; MaxSessionTimeout = 3600000; MinSessionTimeout = 10000; MaxBrowseContinuationPoints = 10; MaxQueryContinuationPoints = 10; MaxHistoryContinuationPoints = 100; MaxRequestAge = 600000; MinPublishingInterval = 100; MaxPublishingInterval = 3600000; PublishingResolution = 100; MinSubscriptionLifetime = 10000; MaxSubscriptionLifetime = 3600000; MaxMessageQueueSize = 10; MaxNotificationQueueSize = 100; MaxNotificationsPerPublish = 100; MinMetadataSamplingInterval = 1000; AvailableSamplingRates = []; RegistrationEndpoint = null; MaxRegistrationInterval = 30000; MaxPublishRequestCount = 20; MaxSubscriptionCount = 100; MaxEventQueueSize = 10000; // https://opcfoundation-onlineapplications.org/profilereporting/ for list of available profiles m_serverProfileArray = new string[] { "http://opcfoundation.org/UA-Profile/Server/StandardUA2017" }; ShutdownDelay = 5; m_serverCapabilities = new string[] { "DA" }; m_supportedPrivateKeyFormats = new string[] { "PFX", "PEM" }; MaxTrustListSize = 0; MultiCastDnsEnabled = false; OperationLimits = new OperationLimits(); AuditingEnabled = false; HttpsMutualTls = true; DurableSubscriptionsEnabled = false; MaxDurableNotificationQueueSize = 200000; MaxDurableEventQueueSize = 200000; MaxDurableSubscriptionLifetimeInHours = 10; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public new void Initialize(StreamingContext context) { Initialize(); } /// /// The user tokens accepted by the server. /// /// The user token policies. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 3)] public UserTokenPolicyCollection UserTokenPolicies { get => m_userTokenPolicies; set => m_userTokenPolicies = value ?? []; } /// /// Whether diagnostics are enabled. /// /// true if diagnostic is enabled; otherwise, false. [DataMember(IsRequired = false, Order = 4)] public bool DiagnosticsEnabled { get; set; } /// /// The maximum number of open sessions. /// /// The maximum session count. [DataMember(IsRequired = false, Order = 5)] public int MaxSessionCount { get; set; } /// /// The maximum number of supported secure channels. /// /// The channel lifetime. [DataMember(IsRequired = false, Order = 6)] public int MaxChannelCount { get; set; } /// /// That minimum period of that a session is allowed to remain /// open without communication from the client (in milliseconds). /// /// The minimum session timeout. [DataMember(IsRequired = false, Order = 7)] public int MinSessionTimeout { get; set; } /// /// That maximum period of that a session is allowed to remain /// open without communication from the client (in milliseconds). /// /// The maximum session timeout. [DataMember(IsRequired = false, Order = 8)] public int MaxSessionTimeout { get; set; } /// /// The maximum number of continuation points used for /// Browse/BrowseNext operations. /// /// The maximum number of continuation points used for Browse/BrowseNext operations [DataMember(IsRequired = false, Order = 9)] public int MaxBrowseContinuationPoints { get; set; } /// /// The maximum number of continuation points used for /// Query/QueryNext operations. /// /// The maximum number of query continuation points. [DataMember(IsRequired = false, Order = 10)] public int MaxQueryContinuationPoints { get; set; } /// /// The maximum number of continuation points used for HistoryRead operations. /// /// The maximum number of history continuation points. [DataMember(IsRequired = false, Order = 11)] public int MaxHistoryContinuationPoints { get; set; } /// /// The maximum age of an incoming request (old requests are rejected) (in milliseconds). /// /// The maximum age of an incoming request. [DataMember(IsRequired = false, Order = 12)] public int MaxRequestAge { get; set; } /// /// The minimum publishing interval supported by the server (in milliseconds). /// /// The minimum publishing interval. [DataMember(IsRequired = false, Order = 13)] public int MinPublishingInterval { get; set; } /// /// The maximum publishing interval supported by the server (in milliseconds). /// /// The maximum publishing interval. [DataMember(IsRequired = false, Order = 14)] public int MaxPublishingInterval { get; set; } /// /// The minimum difference between supported publishing interval (in milliseconds). /// /// The publishing resolution. [DataMember(IsRequired = false, Order = 15)] public int PublishingResolution { get; set; } /// /// How long the subscriptions will remain open without a publish from the client. /// /// The maximum subscription lifetime. [DataMember(IsRequired = false, Order = 16)] public int MaxSubscriptionLifetime { get; set; } /// /// The maximum number of messages saved in the queue for each subscription. /// /// The maximum size of the message queue. [DataMember(IsRequired = false, Order = 17)] public int MaxMessageQueueSize { get; set; } /// /// The maximum number of notificates saved in the queue for each monitored item. /// /// The maximum size of the notification queue. [DataMember(IsRequired = false, Order = 18)] public int MaxNotificationQueueSize { get; set; } /// /// The maximum number of notifications per publish. /// /// The maximum number of notifications per publish. [DataMember(IsRequired = false, Order = 19)] public int MaxNotificationsPerPublish { get; set; } /// /// The minimum sampling interval for metadata. /// /// The minimum sampling interval for metadata. [DataMember(IsRequired = false, Order = 20)] public int MinMetadataSamplingInterval { get; set; } /// /// The available sampling rates. /// /// The available sampling rates. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 21)] public SamplingRateGroupCollection AvailableSamplingRates { get; set; } /// /// The endpoint description for the registration endpoint. /// /// The registration endpoint. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 22)] public EndpointDescription RegistrationEndpoint { get; set; } /// /// The maximum time between registration attempts (in milliseconds). /// /// The maximum time between registration attempts (in milliseconds). [DataMember(IsRequired = false, Order = 23)] public int MaxRegistrationInterval { get; set; } /// /// The path to the file containing nodes persisted by the core node manager. /// /// The path to the file containing nodes persisted by the core node manager. [DataMember(IsRequired = false, Order = 24)] public string NodeManagerSaveFile { get; set; } /// /// The minimum lifetime for a subscription (in milliseconds). /// /// The minimum lifetime for a subscription. [DataMember(IsRequired = false, Order = 25)] public int MinSubscriptionLifetime { get; set; } /// /// The max publish request count. /// /// The max publish request count. [DataMember(IsRequired = false, Order = 26)] public int MaxPublishRequestCount { get; set; } /// /// The max subscription count. /// /// The max subscription count. [DataMember(IsRequired = false, Order = 27)] public int MaxSubscriptionCount { get; set; } /// /// The max size of the event queue. /// /// The max size of the event queue. [DataMember(IsRequired = false, Order = 28)] public int MaxEventQueueSize { get; set; } /// /// The server profile array. /// /// The array of server profiles. [DataMember(IsRequired = false, Order = 29)] public StringCollection ServerProfileArray { get => m_serverProfileArray; set => m_serverProfileArray = value ?? []; } /// /// The server shutdown delay. /// /// The number of seconds to delay the shutdown if a client is connected. [DataMember(IsRequired = false, Order = 30)] public int ShutdownDelay { get; set; } /// /// The server capabilities. /// The latest set of server capabilities is listed /// here. /// /// The array of server capabilites. [DataMember(IsRequired = false, Order = 31)] public StringCollection ServerCapabilities { get => m_serverCapabilities; set => m_serverCapabilities = value ?? []; } /// /// Gets or sets the supported private key format. /// /// The array of server profiles. [DataMember(IsRequired = false, Order = 32)] public StringCollection SupportedPrivateKeyFormats { get => m_supportedPrivateKeyFormats; set => m_supportedPrivateKeyFormats = value ?? []; } /// /// Gets or sets the max size of the trust list. /// [DataMember(IsRequired = false, Order = 33)] public int MaxTrustListSize { get; set; } /// /// Gets or sets if multicast DNS is enabled. /// [DataMember(IsRequired = false, Order = 34)] public bool MultiCastDnsEnabled { get; set; } /// /// Gets or sets reverse connect server configuration. /// [DataMember(IsRequired = false, Order = 35)] public ReverseConnectServerConfiguration ReverseConnect { get; set; } /// /// Gets or sets the operation limits of the OPC UA Server. /// [DataMember(IsRequired = false, Order = 36)] public OperationLimits OperationLimits { get; set; } /// /// Whether auditing is enabled. /// /// true if auditing is enabled; otherwise, false. [DataMember(IsRequired = false, Order = 37)] public bool AuditingEnabled { get; set; } /// /// Whether mTLS is required/enforced by the HttpsTransportListener /// /// true if mutual TLS is enabled; otherwise, false. [DataMember(IsRequired = false, Order = 38)] public bool HttpsMutualTls { get; set; } /// /// Enable / disable support for durable subscriptions /// /// true if durable subscriptions are enabled; otherwise, false. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 39)] public bool DurableSubscriptionsEnabled { get; set; } /// /// The maximum number of notifications saved in the durable queue for each monitored item. /// /// The maximum size of the durable notification queue. [DataMember(IsRequired = false, Order = 40)] public int MaxDurableNotificationQueueSize { get; set; } /// /// The max size of the durable event queue. /// /// The max size of the durable event queue. [DataMember(IsRequired = false, Order = 41)] public int MaxDurableEventQueueSize { get; set; } /// /// How long the durable subscriptions will remain open without a publish from the client. /// /// The maximum durable subscription lifetime. [DataMember(IsRequired = false, Order = 42)] public int MaxDurableSubscriptionLifetimeInHours { get; set; } private UserTokenPolicyCollection m_userTokenPolicies; private StringCollection m_serverProfileArray; private StringCollection m_serverCapabilities; private StringCollection m_supportedPrivateKeyFormats; } /// /// Stores the configuration of the reverse connections. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class ReverseConnectServerConfiguration { /// /// The default constructor. /// public ReverseConnectServerConfiguration() { Initialize(); } /// /// Initializes the object during deserialization. /// [OnDeserializing] private void Initialize(StreamingContext context) { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { ConnectInterval = 15000; ConnectTimeout = 30000; RejectTimeout = 60000; } /// /// A collection of reverse connect clients. /// [DataMember(Order = 10)] public ReverseConnectClientCollection Clients { get; set; } /// /// The interval after which a new reverse connection is attempted. /// [DataMember(Order = 20)] public int ConnectInterval { get; set; } /// /// The default timeout to wait for a response to a reverse connection. /// [DataMember(Order = 30)] public int ConnectTimeout { get; set; } /// /// The timeout to wait to establish a new reverse /// connection after a rejected attempt. /// [DataMember(Order = 40)] public int RejectTimeout { get; set; } } /// /// Stores the operation limits of a OPC UA Server. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class OperationLimits { /// /// The default constructor. /// public OperationLimits() { Initialize(); } /// /// Initializes the object during deserialization. /// [OnDeserializing] private void Initialize(StreamingContext context) { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { MaxNodesPerRead = 0; MaxNodesPerHistoryReadData = 0; MaxNodesPerHistoryReadEvents = 0; MaxNodesPerWrite = 0; MaxNodesPerHistoryUpdateData = 0; MaxNodesPerHistoryUpdateEvents = 0; MaxNodesPerMethodCall = 0; MaxNodesPerBrowse = 0; MaxNodesPerRegisterNodes = 0; MaxNodesPerTranslateBrowsePathsToNodeIds = 0; MaxNodesPerNodeManagement = 0; MaxMonitoredItemsPerCall = 0; } /// /// Indicates the maximum size of the nodesToRead array when a Client calls the Read Service. /// [DataMember(Order = 10)] public uint MaxNodesPerRead { get; set; } /// /// Indicates the maximum size of the nodesToRead array when a Client calls the HistoryRead /// Service using the historyReadDetails RAW, PROCESSED, MODIFIED or ATTIME. /// [DataMember(Order = 20)] public uint MaxNodesPerHistoryReadData { get; set; } /// /// Indicates the maximum size of the nodesToRead array when a Client calls the HistoryRead /// Service using the historyReadDetails EVENTS. /// [DataMember(Order = 30)] public uint MaxNodesPerHistoryReadEvents { get; set; } /// /// Indicates the maximum size of the nodesToWrite array when a Client calls the Write Service. /// [DataMember(Order = 40)] public uint MaxNodesPerWrite { get; set; } /// /// Indicates the maximum size of the historyUpdateDetails array supported by the Server /// when a Client calls the HistoryUpdate Service. /// [DataMember(Order = 50)] public uint MaxNodesPerHistoryUpdateData { get; set; } /// /// Indicates the maximum size of the historyUpdateDetails array /// when a Client calls the HistoryUpdate Service. /// [DataMember(Order = 60)] public uint MaxNodesPerHistoryUpdateEvents { get; set; } /// /// Indicates the maximum size of the methodsToCall array when a Client calls the Call Service. /// [DataMember(Order = 70)] public uint MaxNodesPerMethodCall { get; set; } /// /// Indicates the maximum size of the nodesToBrowse array when calling the Browse Service /// or the continuationPoints array when a Client calls the BrowseNext Service. /// [DataMember(Order = 80)] public uint MaxNodesPerBrowse { get; set; } /// /// Indicates the maximum size of the nodesToRegister array when a Client calls the RegisterNodes Service /// and the maximum size of the nodesToUnregister when calling the UnregisterNodes Service. /// [DataMember(Order = 90)] public uint MaxNodesPerRegisterNodes { get; set; } /// /// Indicates the maximum size of the browsePaths array when a Client calls the TranslateBrowsePathsToNodeIds Service. /// [DataMember(Order = 100)] public uint MaxNodesPerTranslateBrowsePathsToNodeIds { get; set; } /// /// Indicates the maximum size of the nodesToAdd array when a Client calls the AddNodes Service, /// the maximum size of the referencesToAdd array when a Client calls the AddReferences Service, /// the maximum size of the nodesToDelete array when a Client calls the DeleteNodes Service, /// and the maximum size of the referencesToDelete array when a Client calls the DeleteReferences Service. /// [DataMember(Order = 110)] public uint MaxNodesPerNodeManagement { get; set; } /// /// Indicates the maximum size of the itemsToCreate array when a Client calls the CreateMonitoredItems Service, /// the maximum size of the itemsToModify array when a Client calls the ModifyMonitoredItems Service, /// the maximum size of the monitoredItemIds array when a Client calls the SetMonitoringMode Service or the DeleteMonitoredItems Service, /// the maximum size of the sum of the linksToAdd and linksToRemove arrays when a Client calls the SetTriggering Service. /// [DataMember(Order = 120)] public uint MaxMonitoredItemsPerCall { get; set; } } /// /// Stores the configuration of the reverse connections. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class ReverseConnectClient { /// /// The default constructor. /// public ReverseConnectClient() { Initialize(); } /// /// Initializes the object during deserialization. /// [OnDeserializing] private void Initialize(StreamingContext context) { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { Enabled = true; } /// /// The endpoint Url of the reverse connect client endpoint. /// [DataMember(Order = 10)] public string EndpointUrl { get; set; } /// /// The timeout to wait for a response to a reverse connection. /// Overrides the default reverse connection setting. /// [DataMember(Order = 20)] public int Timeout { get; set; } /// /// The maximum count of active reverse connect sessions. /// 0 or undefined means unlimited number of sessions. /// 1 means a single connection is created at a time. /// n disables reverse hello once the total number of sessions /// in the server reaches n. /// [DataMember(Order = 30)] public int MaxSessionCount { get; set; } /// /// Specifies whether the sending of reverse connect attempts is enabled. /// [DataMember(Order = 40)] public bool Enabled { get; set; } = true; } /// /// A collection of reverse connect clients. /// [CollectionDataContract( Name = "ListOfReverseConnectClient", Namespace = Namespaces.OpcUaConfig, ItemName = "ReverseConnectClient" )] public class ReverseConnectClientCollection : List { /// /// Initializes an empty collection. /// public ReverseConnectClientCollection() { } /// /// Initializes the collection from another collection. /// /// A collection of values to add to this new collection /// /// is null. /// public ReverseConnectClientCollection(IEnumerable collection) : base(collection) { } /// /// Initializes the collection with the specified capacity. /// /// The capacity. public ReverseConnectClientCollection(int capacity) : base(capacity) { } } /// /// The configuration for a client application. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class ClientConfiguration { /// /// The default constructor. /// public ClientConfiguration() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { DefaultSessionTimeout = 60000; MinSubscriptionLifetime = 10000; m_wellKnownDiscoveryUrls = []; m_discoveryServers = []; OperationLimits = new OperationLimits(); } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// The default session timeout (in milliseconds). /// /// The default session timeout. [DataMember(IsRequired = false, Order = 0)] public int DefaultSessionTimeout { get; set; } /// /// The well known URLs for the local discovery servers. /// /// The well known discovery URLs. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 1)] public StringCollection WellKnownDiscoveryUrls { get => m_wellKnownDiscoveryUrls; set => m_wellKnownDiscoveryUrls = value ?? []; } /// /// The endpoint descriptions for central discovery servers. /// /// The endpoint descriptions for central discovery servers. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 2)] public EndpointDescriptionCollection DiscoveryServers { get => m_discoveryServers; set => m_discoveryServers = value ?? []; } /// /// The path to the file containing the cached endpoints. /// /// The path to the file containing the cached endpoints. [DataMember(IsRequired = false, Order = 3)] public string EndpointCacheFilePath { get; set; } /// /// The minimum lifetime for a subscription (in milliseconds). /// /// The minimum lifetime for a subscription. [DataMember(IsRequired = false, Order = 4)] public int MinSubscriptionLifetime { get; set; } /// /// The reverse connect Client configuration. /// [DataMember(IsRequired = false, Order = 5)] public ReverseConnectClientConfiguration ReverseConnect { get; set; } /// /// Gets or sets the default operation limits of the OPC UA client. /// /// /// Values not equal to zero are overwritten with smaller values set by the server. /// The values are used to limit client service calls. /// [DataMember(IsRequired = false, Order = 6)] public OperationLimits OperationLimits { get; set; } private StringCollection m_wellKnownDiscoveryUrls; private EndpointDescriptionCollection m_discoveryServers; } /// /// Stores the configuration of the reverse connections. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class ReverseConnectClientConfiguration { /// /// A collection of reverse connect client endpoints. /// [DataMember(Order = 10, IsRequired = false)] public ReverseConnectClientEndpointCollection ClientEndpoints { get; set; } /// /// The time a reverse hello port is held open to wait for a /// reverse connection until the request is rejected. /// [DataMember(Order = 20, IsRequired = false)] public int HoldTime { get; set; } = 15000; /// /// The timeout to wait for a reverse hello message. /// [DataMember(Order = 30, IsRequired = false)] public int WaitTimeout { get; set; } = 20000; } /// /// Stores the configuration of the reverse connections. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class ReverseConnectClientEndpoint { /// /// The endpoint Url of a reverse connect client. /// [DataMember(Order = 1, IsRequired = false)] public string EndpointUrl { get; set; } } /// /// A collection of reverse connect client endpoints. /// [CollectionDataContract( Name = "ListOfReverseConnectClientEndpoint", Namespace = Namespaces.OpcUaConfig, ItemName = "ClientEndpoint" )] public class ReverseConnectClientEndpointCollection : List { /// /// Initializes an empty collection. /// public ReverseConnectClientEndpointCollection() { } /// /// Initializes the collection from another collection. /// /// A collection of values to add to this new collection /// /// is null. /// public ReverseConnectClientEndpointCollection( IEnumerable collection) : base(collection) { } /// /// Initializes the collection with the specified capacity. /// /// The capacity. public ReverseConnectClientEndpointCollection(int capacity) : base(capacity) { } } /// /// Specifies the configuration for a discovery server application. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class DiscoveryServerConfiguration : ServerBaseConfiguration { /// /// The default constructor. /// public DiscoveryServerConfiguration() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { m_serverNames = []; ServerRegistrations = []; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public new void Initialize(StreamingContext context) { Initialize(); } /// /// The localized names for the discovery server. /// /// The server names. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 2)] public LocalizedTextCollection ServerNames { get => m_serverNames; set => m_serverNames = value ?? []; } /// /// The path to the file containing servers saved by the discovery server. /// /// The discovery server cache file. [DataMember(IsRequired = false, Order = 3)] public string DiscoveryServerCacheFile { get; set; } /// /// Gets or sets the server registrations associated with the discovery server. /// /// The server registrations. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 4)] public ServerRegistrationCollection ServerRegistrations { get; set; } private LocalizedTextCollection m_serverNames; } /// /// Specifies the configuration for a discovery server application. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class ServerRegistration { /// /// The default constructor. /// public ServerRegistration() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { ApplicationUri = null; m_alternateDiscoveryUrls = []; } /// /// Initializes the object during deserialization. /// /// The context. [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// Gets or sets the application URI of the server which the registration applies to. /// /// The application uri. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 1)] public string ApplicationUri { get; set; } /// /// Gets or sets the alternate discovery urls. /// /// The alternate discovery urls. /// /// /// These addresses are used to specify alternate paths to ther via firewalls, proxies /// or similar network infrastructure. If these paths are specified in the configuration /// file then the server will use the domain of the URL used by the client to determine /// which, if any, or the alternate addresses to use instead of the primary addresses. /// /// /// In the ideal world the server would provide these URLs during registration but this /// table allows the administrator to provide the information to the discovery server /// directly without requiring a patch to the server. /// /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 2)] public StringCollection AlternateDiscoveryUrls { get => m_alternateDiscoveryUrls; set => m_alternateDiscoveryUrls = value ?? []; } private StringCollection m_alternateDiscoveryUrls; } /// /// A collection of AdditionalServerRegistrationInfo objects. /// [CollectionDataContract( Name = "ListOfServerRegistration", Namespace = Namespaces.OpcUaConfig, ItemName = "ServerRegistration" )] public class ServerRegistrationCollection : List { /// /// Initializes an empty collection. /// public ServerRegistrationCollection() { } /// /// Initializes the collection from another collection. /// /// A collection of values to add to this new collection /// /// is null. /// public ServerRegistrationCollection(IEnumerable collection) : base(collection) { } /// /// Initializes the collection with the specified capacity. /// /// The capacity. public ServerRegistrationCollection(int capacity) : base(capacity) { } } /// /// Describes a certificate store. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class CertificateStoreIdentifier { /// /// The type of certificate store. /// /// /// If the StoreName is not empty, the CertificateStoreType.X509Store is returned, otherwise the StoreType is returned. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 0)] public string StoreType { get; set; } /// /// The path that identifies the certificate store. /// /// /// If the StoreName is not empty and the StoreLocation is empty, the Utils.Format("CurrentUser\\{0}", m_storeName) is returned. /// If the StoreName is not empty and the StoreLocation is not empty, the Utils.Format("{1}\\{0}", m_storeName, m_storeLocation) is returned. /// If the StoreName is empty, the m_storePath is returned. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 1)] public string StorePath { get => m_storePath; set { m_storePath = value; if (!string.IsNullOrEmpty(m_storePath) && string.IsNullOrEmpty(StoreType)) { StoreType = DetermineStoreType(m_storePath); } } } /// /// Options that can be used to suppress certificate validation errors. /// [DataMember( Name = "ValidationOptions", IsRequired = false, EmitDefaultValue = false, Order = 4)] internal int XmlEncodedValidationOptions { get => (int)ValidationOptions; set => ValidationOptions = (CertificateValidationOptions)value; } private string m_storePath; } [DataContract(Namespace = Namespaces.OpcUaConfig)] [KnownType(typeof(CertificateTrustList))] public partial class CertificateTrustList : CertificateStoreIdentifier { /// /// The default constructor. /// public CertificateTrustList() { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { m_trustedCertificates = []; } /// /// Initializes the object during deserialization. /// [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// The list of trusted certificates. /// /// /// The list of trusted certificates is set when TrustedCertificates is not a null value, /// otherwise new CertificateIdentifierCollection is set. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 3)] public CertificateIdentifierCollection TrustedCertificates { get => m_trustedCertificates; set => m_trustedCertificates = value ?? []; } private CertificateIdentifierCollection m_trustedCertificates; } [CollectionDataContract( Name = "ApplicationCertificates", Namespace = Namespaces.OpcUaConfig, ItemName = "CertificateIdentifier" )] public partial class CertificateIdentifierCollection : List { /// /// Initializes an empty collection. /// public CertificateIdentifierCollection() { } /// /// Initializes the collection from another collection. /// /// A collection of values to add to this new collection public CertificateIdentifierCollection(IEnumerable collection) : base(collection) { } /// /// Initializes the collection with the specified capacity. /// public CertificateIdentifierCollection(int capacity) : base(capacity) { } } [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class CertificateIdentifier { /// /// The default constructor. /// public CertificateIdentifier() { } /// /// Initializes the identifier with the raw data from a certificate. /// public CertificateIdentifier(X509Certificate2 certificate) { Certificate = certificate; } /// /// Initializes the identifier with the raw data from a certificate. /// public CertificateIdentifier( X509Certificate2 certificate, CertificateValidationOptions validationOptions) { Certificate = certificate; ValidationOptions = validationOptions; } /// /// Initializes the identifier with the raw data from a certificate. /// public CertificateIdentifier(byte[] rawData) { Certificate = CertificateFactory.Create(rawData); } /// /// The type of certificate store. /// /// The type of the store - defined in the . [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 10)] public string StoreType { get; set; } /// /// The path that identifies the certificate store. /// /// The store path in the form StoreName\\Store Location . [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 15)] public string StorePath { get => m_storePath; set { m_storePath = value; if (!string.IsNullOrEmpty(m_storePath) && string.IsNullOrEmpty(StoreType)) { StoreType = CertificateStoreIdentifier.DetermineStoreType(m_storePath); } } } /// /// The certificate's subject name - the distinguished name of an X509 certificate. /// /// /// The distinguished name of an X509 certificate acording to the Abstract Syntax Notation One (ASN.1) syntax. /// /// The subject field identifies the entity associated with the public key stored in the subject public /// key field. The subject name MAY be carried in the subject field and/or the subjectAltName extension. /// Where it is non-empty, the subject field MUST contain an X.500 distinguished name (DN). /// Name is defined by the following ASN.1 structures: /// Name ::= CHOICE {RDNSequence } /// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName /// RelativeDistinguishedName ::= SET OF AttributeTypeAndValue /// AttributeTypeAndValue ::= SEQUENCE {type AttributeType, value AttributeValue } /// AttributeType ::= OBJECT IDENTIFIER /// AttributeValue ::= ANY DEFINED BY AttributeType /// DirectoryString ::= CHOICE { /// teletexString TeletexString (SIZE (1..MAX)), /// printableString PrintableString (SIZE (1..MAX)), /// universalString UniversalString (SIZE (1..MAX)), /// utf8String UTF8String (SIZE (1..MAX)), /// bmpString BMPString (SIZE (1..MAX)) } /// The Name describes a hierarchical name composed of attributes, such as country name, and /// corresponding values, such as US. The type of the component AttributeValue is determined by /// the AttributeType; in general it will be a DirectoryString. /// String X.500 AttributeType: /// /// CN commonName /// L localityName /// ST stateOrProvinceName /// O organizationName /// OU organizationalUnitName /// C countryName /// STREET streetAddress /// DC domainComponent /// UID userid /// /// /// This notation is designed to be convenient for common forms of name. This section gives a few /// examples of distinguished names written using this notation. First is a name containing three relative /// distinguished names (RDNs): /// CN=Steve Kille,O=Isode Limited,C=GB /// /// /// RFC 3280 Internet X.509 Public Key Infrastructure, April 2002 /// RFC 2253 LADPv3 Distinguished Names, December 1997 /// /// /// /// /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 40)] public string SubjectName { get { if (m_certificate == null) { return m_subjectName; } return m_certificate.Subject; } set { if (m_certificate != null && !string.IsNullOrEmpty(value) && m_certificate.Subject != value) { throw new ArgumentException( "SubjectName does not match the SubjectName of the current certificate."); } m_subjectName = value; } } /// /// The certificate's thumbprint. /// /// The thumbprint of a certificate.. /// /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 50)] public string Thumbprint { get { if (m_certificate == null) { return m_thumbprint; } return m_certificate.Thumbprint; } set { if (m_certificate != null && !string.IsNullOrEmpty(value) && m_certificate.Thumbprint != value) { throw new ArgumentException( "Thumbprint does not match the thumbprint of the current certificate."); } m_thumbprint = value; } } /// /// Gets the DER encoded certificate data or create embedded in this instance certificate using the DER encoded certificate data. /// /// A byte array containing the X.509 certificate data. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 60)] public byte[] RawData { get { if (m_certificate == null) { return null; } return m_certificate.RawData; } set { if (value == null || value.Length == 0) { m_certificate = null; return; } m_certificate = CertificateFactory.Create(value); m_subjectName = m_certificate.Subject; m_thumbprint = m_certificate.Thumbprint; CertificateType = GetCertificateType(m_certificate); } } /// /// Gets or sets the XML encoded validation options - use to serialize the validation options. /// /// The XML encoded validation options. [DataMember( Name = "ValidationOptions", IsRequired = false, EmitDefaultValue = false, Order = 70)] internal int XmlEncodedValidationOptions { get => (int)ValidationOptions; set => ValidationOptions = (CertificateValidationOptions)value; } /// /// Gets or sets the certificate type. /// /// The NodeId of the certificate type, e.g. EccNistP256ApplicationCertificateType. [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 80)] public NodeId CertificateType { get; set; } /// /// The string representation of the certificate /// /// Rsa, RsaMin, RsaSha256, NistP256, NistP384, BrainpoolP256r1, BrainpoolP384r1, Curve25519, Curve448 [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 90)] public string CertificateTypeString { get => EncodeCertificateType(CertificateType); set => CertificateType = DecodeCertificateType(value); } private string m_storePath; private string m_subjectName; private string m_thumbprint; private X509Certificate2 m_certificate; } /// /// Stores a list of cached endpoints. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public partial class ConfiguredEndpointCollection { /// /// The default constructor. /// public ConfiguredEndpointCollection() { Initialize(); } /// /// Called by the .NET framework during deserialization. /// [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { m_knownHosts = []; m_discoveryUrls = [.. Utils.DiscoveryUrls]; m_endpoints = []; DefaultConfiguration = EndpointConfiguration.Create(); } /// /// A list of known hosts that can be used for discovery. /// [DataMember(Name = "KnownHosts", IsRequired = false, Order = 1)] public StringCollection KnownHosts { get => m_knownHosts; set => m_knownHosts = value ?? []; } /// /// The default configuration to use when connecting to an endpoint. /// [DataMember(Name = "Endpoints", IsRequired = false, Order = 2)] public List Endpoints { get => m_endpoints; private set { m_endpoints = value ?? []; foreach (ConfiguredEndpoint endpoint in m_endpoints) { endpoint.Collection = this; } } } /// /// The URL of the UA TCP proxy server. /// [DataMember(Name = "TcpProxyUrl", EmitDefaultValue = false, Order = 3)] public Uri TcpProxyUrl { get; set; } private string m_filepath; private StringCollection m_knownHosts; private StringCollection m_discoveryUrls; private List m_endpoints; } /// /// Stores the configuration information for an endpoint. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] [KnownType(typeof(UserNameIdentityToken))] [KnownType(typeof(X509IdentityToken))] [KnownType(typeof(IssuedIdentityToken))] public partial class ConfiguredEndpoint { /// /// The default constructor. /// public ConfiguredEndpoint() { Initialize(); } /// /// Called by the .NET framework during deserialization. /// [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { m_collection = null; m_description = new EndpointDescription(); m_configuration = null; UpdateBeforeConnect = true; BinaryEncodingSupport = BinaryEncodingSupport.Optional; SelectedUserTokenPolicyIndex = 0; UserIdentity = null; ReverseConnect = null; } /// /// The description for the endpoint. /// [DataMember(Name = "Endpoint", Order = 1, IsRequired = true)] public EndpointDescription Description { get => m_description; private set => m_description = value ?? new EndpointDescription(); } /// /// The configuration to use when connecting to an endpoint. /// [DataMember(Name = "Configuration", Order = 2, IsRequired = false)] public EndpointConfiguration Configuration { get => m_configuration; set { m_configuration = value; // copy default configuration if not already set. if (m_configuration == null) { if (m_collection != null) { Update(m_collection.DefaultConfiguration); } else { Update(EndpointConfiguration.Create()); } } } } /// /// Whether the endpoint information should be updated before connecting to the server. /// [DataMember(Name = "UpdateBeforeConnect", Order = 3, IsRequired = false)] public bool UpdateBeforeConnect { get; set; } /// /// The user identity to use when connecting to the endpoint. /// [DataMember(Name = "BinaryEncodingSupport", Order = 4, IsRequired = false)] public BinaryEncodingSupport BinaryEncodingSupport { get; set; } /// /// The user identity to use when connecting to the endpoint. /// [DataMember(Name = "SelectedUserTokenPolicy", Order = 5, IsRequired = false)] public int SelectedUserTokenPolicyIndex { get; set; } /// /// The user identity to use when connecting to the endpoint. /// [DataMember(Name = "UserIdentity", Order = 6, IsRequired = false)] public UserIdentityToken UserIdentity { get; set; } /// /// The reverse connect information. /// [DataMember(Name = "ReverseConnect", Order = 8, IsRequired = false)] public ReverseConnectEndpoint ReverseConnect { get; set; } /// /// A bucket to store additional application specific configuration data. /// [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 9)] public XmlElementCollection Extensions { get => m_extensions; set => m_extensions = value; } private ConfiguredEndpointCollection m_collection; private EndpointDescription m_description; private EndpointConfiguration m_configuration; private XmlElementCollection m_extensions; } /// /// The type of binary encoding support allowed by a channel. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public enum BinaryEncodingSupport { /// /// The UA binary encoding may be used. /// [EnumMember] Optional, /// /// The UA binary encoding must be used. /// [EnumMember] Required, /// /// The UA binary encoding may not be used. /// [EnumMember] None } /// /// Stores the reverse connect information for an endpoint. /// [DataContract(Namespace = Namespaces.OpcUaConfig)] public class ReverseConnectEndpoint { /// /// The default constructor. /// public ReverseConnectEndpoint() { Initialize(); } /// /// Called by the .NET framework during deserialization. /// [OnDeserializing] public void Initialize(StreamingContext context) { Initialize(); } /// /// Sets private members to default values. /// private void Initialize() { Enabled = false; ServerUri = null; Thumbprint = null; } /// /// Whether reverse connect is enabled for the endpoint. /// [DataMember(Name = "Enabled", Order = 1, IsRequired = false)] public bool Enabled { get; set; } /// /// The server Uri of the endpoint. /// [DataMember(Name = "ServerUri", Order = 2, IsRequired = false)] public string ServerUri { get; set; } /// /// The thumbprint of the certificate which contains /// the server Uri. /// [DataMember(Name = "Thumbprint", Order = 3, IsRequired = false)] public string Thumbprint { get; set; } } }