diff --git a/.gitignore b/.gitignore
index 8fe2c66045..81a981b19d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
/**/obj/**
/**/.vs
/**/bin/**
+/**/pki/**
/**/csx/**
/**/ecf/**
/**/*.log
@@ -36,4 +37,3 @@
*.cache
CodeCoverage
coverage.cobertura.xml
-
diff --git a/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs b/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs
index a023d4dd2b..2d9b4d253b 100644
--- a/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs
+++ b/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs
@@ -31,7 +31,7 @@ public static bool IsNull(this VariantValue value) {
///
public static T GetValueOrDefault(this Dictionary dict,
string key, T defaultValue) {
- if (dict != null && dict.TryGetValue(key, out var token)) {
+ if (dict != null && dict.TryGetValue(key, out var token) && token != null) {
try {
return token.ConvertTo();
}
@@ -52,7 +52,7 @@ public static T GetValueOrDefault(this Dictionary dict,
///
public static T? GetValueOrDefault(this Dictionary dict,
string key, T? defaultValue) where T : struct {
- if (dict != null && dict.TryGetValue(key, out var token)) {
+ if (dict != null && dict.TryGetValue(key, out var token) && token != null) {
try {
// Handle enumerations serialized as string
if (typeof(T).IsEnum &&
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs
index f5e8849d02..147dd45d1d 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs
@@ -15,8 +15,8 @@ namespace Microsoft.Azure.IIoT.OpcUa.Gateway.Server {
using Microsoft.Azure.IIoT.OpcUa.Twin;
using Microsoft.Azure.IIoT.OpcUa.History.Models;
using Microsoft.Azure.IIoT.OpcUa.History;
- using Microsoft.Azure.IIoT.Auth.Server;
using Microsoft.Azure.IIoT.Auth;
+ using Microsoft.Azure.IIoT.Serializers;
using Serilog;
using Opc.Ua;
using Opc.Ua.Configuration;
@@ -27,10 +27,12 @@ namespace Microsoft.Azure.IIoT.OpcUa.Gateway.Server {
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+ using System.Net;
+ using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using System.Text;
- using Microsoft.Azure.IIoT.Serializers;
+
///
/// Gateway server controller implementation
@@ -1597,33 +1599,33 @@ internal void OnRequestComplete(RequestContextModel context) {
///
private async Task InitAsync() {
var config = new ApplicationConfiguration {
- ApplicationName = "Opc UA Gateway Server",
+ // TODO provide proper naming here
+ ApplicationName = "Microsoft.Azure.IIoT.Gateway",
ApplicationType = Opc.Ua.ApplicationType.ClientAndServer,
ApplicationUri =
- $"urn:{Utils.GetHostName()}:Microsoft:OpcGatewayServer",
- ProductUri = "http://opcfoundation.org/UA/SampleServer",
+ $"urn:{Dns.GetHostName()}:Microsoft:Azure.IIoT.Gateway",
+ ProductUri = "https://www.github.com/Azure/Industrial-IoT",
SecurityConfiguration = new SecurityConfiguration {
ApplicationCertificate = new CertificateIdentifier {
- StoreType = "Directory",
- StorePath =
- "OPC Foundation/CertificateStores/MachineDefault",
- SubjectName = "Opc UA Gateway Server"
+ StoreType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
+ "X509Store" : "Directory",
+ StorePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
+ "CurrentUser\\UA_MachineDefault" :
+ "pki/own",
+ SubjectName = "Microsoft.Azure.IIoT.Gateway"
},
TrustedPeerCertificates = new CertificateTrustList {
StoreType = "Directory",
- StorePath =
- "OPC Foundation/CertificateStores/UA Applications",
+ StorePath = "pki/trusted",
},
TrustedIssuerCertificates = new CertificateTrustList {
StoreType = "Directory",
- StorePath =
- "OPC Foundation/CertificateStores/UA Certificate Authorities",
+ StorePath = "pki/issuers",
},
RejectedCertificateStore = new CertificateTrustList {
StoreType = "Directory",
- StorePath =
- "OPC Foundation/CertificateStores/RejectedCertificates",
+ StorePath = "pki/rejected"
},
AutoAcceptUntrustedCertificates = false
},
@@ -1686,8 +1688,7 @@ private async Task InitAsync() {
await config.CertificateValidator.Update(config.SecurityConfiguration);
// Use existing certificate, if it is there.
- var cert = await config.SecurityConfiguration.ApplicationCertificate
- .Find(true);
+ var cert = config.SecurityConfiguration.ApplicationCertificate.Certificate;
if (cert == null) {
// Create cert
#pragma warning disable IDE0067 // Dispose objects before losing scope
@@ -1702,12 +1703,11 @@ private async Task InitAsync() {
CertificateFactory.defaultHashSize,
false, null, null);
#pragma warning restore IDE0067 // Dispose objects before losing scope
- }
-
- if (cert != null) {
+
config.SecurityConfiguration.ApplicationCertificate.Certificate = cert;
- config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert);
+ await config.CertificateValidator.UpdateCertificate(config.SecurityConfiguration);
}
+ config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert);
var application = new ApplicationInstance(config);
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IClientServicesConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IClientServicesConfig.cs
deleted file mode 100644
index c08f9e663b..0000000000
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IClientServicesConfig.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-// ------------------------------------------------------------
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
-// ------------------------------------------------------------
-
-namespace Microsoft.Azure.IIoT.OpcUa.Protocol {
- using System;
-
- ///
- /// Client Services configuration
- ///
- public interface IClientServicesConfig {
-
- ///
- /// application's certificate store type: Directory or X509Store
- ///
- string AppCertStoreType { get; }
-
- ///
- /// root path of the pki security folder
- ///
- string PkiRootPath { get; }
-
- ///
- /// Path to the folder storing the application's certificate
- ///
- string OwnCertPath { get; }
-
- ///
- /// Path to the folder storing the application's trusted certificates
- ///
- string TrustedCertPath { get; }
-
- ///
- /// Path of the folder to store the trueste issuer (CA) certificates
- ///
- string IssuerCertPath { get; }
-
- ///
- /// Path of the folder to store the rejected certificates
- ///
- ///
- string RejectedCertPath { get; }
-
- ///
- /// flag to force automatically acceptance of untrusted certificates
- ///
- bool AutoAcceptUntrustedCertificates { get; }
-
- ///
- /// the default store path for the windows X509 certificates store in case
- /// X509Store store type is used
- ///
- string OwnCertX509StorePathDefault { get; }
-
- ///
- /// Default session timeout for client
- ///
- TimeSpan? DefaultSessionTimeout { get; }
-
- ///
- /// Default operation timeout
- ///
- TimeSpan? OperationTimeout { get; }
- }
-}
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs
index 1476409001..364277e761 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs
@@ -17,6 +17,6 @@ public interface IServerFactory {
///
///
ApplicationConfiguration CreateServer(IEnumerable ports,
- out ServerBase server);
+ string pkiRootPath, out ServerBase server);
}
}
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ClientServicesConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ClientServicesConfig.cs
deleted file mode 100644
index f8cac2b176..0000000000
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ClientServicesConfig.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// ------------------------------------------------------------
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
-// ------------------------------------------------------------
-
-namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime {
- using Microsoft.Azure.IIoT.Utils;
- using Microsoft.Extensions.Configuration;
- using System;
- using System.Runtime.InteropServices;
-
- ///
- /// Client's application configuration implementation
- ///
- public class ClientServicesConfig : ConfigBase, IClientServicesConfig {
-
-#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
- public const string AppCertStoreTypeKey = "AppCertStoreType";
- public const string PkiRootPathKey = "PkiRootPath";
- public const string OwnCertPathKey = "OwnCertPath";
- public const string TrustedCertPathKey = "TrustedCertPath";
- public const string IssuerCertPathKey = "IssuerCertPath";
- public const string RejectedCertPathKey = "RejectedCertPath";
- public const string AutoAcceptKey = "AutoAccept";
- public const string OwnCertX509StorePathDefaultKey = "OwnCertX509StorePathDefault";
- public const string SessionTimeoutKey = "SessionTimeout";
- public const string OperationTimeoutKey = "OperationTimeout";
-#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
-
- ///
- public string AppCertStoreType => GetStringOrDefault(AppCertStoreTypeKey,
- () => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
- "X509Store" : "Directory");
- ///
- public string PkiRootPath =>
- GetStringOrDefault(PkiRootPathKey,
- () => "pki");
- ///
- public string OwnCertPath =>
- GetStringOrDefault(OwnCertPathKey,
- () => PkiRootPath + "/own");
- ///
- public string TrustedCertPath =>
- GetStringOrDefault(TrustedCertPathKey,
- () => PkiRootPath + "/trusted");
- ///
- public string IssuerCertPath =>
- GetStringOrDefault(IssuerCertPathKey,
- () => PkiRootPath + "/issuer");
- ///
- public string RejectedCertPath =>
- GetStringOrDefault(RejectedCertPathKey,
- () => PkiRootPath + "/rejected");
- ///
- public string OwnCertX509StorePathDefault =>
- GetStringOrDefault(OwnCertX509StorePathDefaultKey,
- () => "CurrentUser\\UA_MachineDefault");
- ///
- public bool AutoAcceptUntrustedCertificates =>
- GetBoolOrDefault(AutoAcceptKey);
- ///
- public TimeSpan? DefaultSessionTimeout =>
- GetDurationOrNull(SessionTimeoutKey);
- ///
- public TimeSpan? OperationTimeout =>
- GetDurationOrNull(OperationTimeoutKey);
-
- ///
- /// Configuration constructor
- ///
- ///
- public ClientServicesConfig(IConfiguration configuration = null) :
- base(configuration) {
- }
- }
-}
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig2.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig.cs
similarity index 93%
rename from components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig2.cs
rename to components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig.cs
index cac4daa7c2..894137dcb4 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig2.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig.cs
@@ -12,7 +12,7 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime {
///
/// Default client configuration
///
- public class ClientServicesConfig2 : ConfigBase, IClientServicesConfig2, ISecurityConfig, ITransportQuotaConfig {
+ public class ClientServicesConfig : ConfigBase, IClientServicesConfig, ISecurityConfig, ITransportQuotaConfig {
///
/// Configuration
@@ -49,6 +49,8 @@ public class ClientServicesConfig2 : ConfigBase, IClientServicesConfig2, ISecuri
public uint MaxKeepAliveCount =>
(uint)GetIntOrDefault(MaxKeepAliveCountKey, () => 5);
+ ///
+ public string PkiRootPath => _security.PkiRootPath;
///
public CertificateInfo ApplicationCertificate => _security.ApplicationCertificate;
@@ -84,7 +86,7 @@ public class ClientServicesConfig2 : ConfigBase, IClientServicesConfig2, ISecuri
public int SecurityTokenLifetime => _transport.SecurityTokenLifetime;
///
- public ClientServicesConfig2(IConfiguration configuration = null) : base(configuration) {
+ public ClientServicesConfig(IConfiguration configuration = null) : base(configuration) {
_security = new SecurityConfig(configuration);
_transport = new TransportQuotaConfig(configuration);
}
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs
index d216dd38ac..ee1869f60a 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs
@@ -17,6 +17,7 @@ public class SecurityConfig : ConfigBase, ISecurityConfig {
/// Configuration
///
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
+ public const string PkiRootPathKey = "PkiRootPath";
public const string ApplicationCertificateStorePathKey = "ApplicationCertificateStorePath";
public const string ApplicationCertificateStoreTypeKey = "ApplicationCertificateStoreType";
public const string ApplicationCertificateSubjectNameKey = "ApplicationCertificateSubjectName";
@@ -31,11 +32,15 @@ public class SecurityConfig : ConfigBase, ISecurityConfig {
public const string MinimumCertificateKeySizeKey = "MinimumCertificateKeySize";
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
+ ///
+ public string PkiRootPath =>
+ GetStringOrDefault(PkiRootPathKey, () => "pki");
+
///
public CertificateInfo ApplicationCertificate => new CertificateInfo {
StorePath = GetStringOrDefault(ApplicationCertificateStorePathKey,
() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
- "CurrentUser\\My" : "/pki/own"),
+ "CurrentUser\\UA_MachineDefault" : $"{PkiRootPath}/own"),
StoreType = GetStringOrDefault(ApplicationCertificateStoreTypeKey,
() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
"X509Store" : "Directory"),
@@ -45,19 +50,19 @@ public class SecurityConfig : ConfigBase, ISecurityConfig {
///
public CertificateStore TrustedIssuerCertificates => new CertificateStore {
- StorePath = GetStringOrDefault(TrustedIssuerCertificatesPathKey, () => "/pki/trusted"),
+ StorePath = GetStringOrDefault(TrustedIssuerCertificatesPathKey, () => $"{PkiRootPath}/issuers"),
StoreType = GetStringOrDefault(TrustedIssuerCertificatesTypeKey, () => "Directory"),
};
///
public CertificateStore TrustedPeerCertificates => new CertificateStore {
- StorePath = GetStringOrDefault(TrustedPeerCertificatesPathKey, () => "/pki/trusted"),
+ StorePath = GetStringOrDefault(TrustedPeerCertificatesPathKey, () => $"{PkiRootPath}/trusted"),
StoreType = GetStringOrDefault(TrustedPeerCertificatesTypeKey, () => "Directory"),
};
///
public CertificateStore RejectedCertificateStore => new CertificateStore {
- StorePath = GetStringOrDefault(RejectedCertificateStorePathKey, () => "/pki/trusted"),
+ StorePath = GetStringOrDefault(RejectedCertificateStorePathKey, () => $"{PkiRootPath}/rejected"),
StoreType = GetStringOrDefault(RejectedCertificateStoreTypeKey, () => "Directory"),
};
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs
index 192e885233..a1fb2e2de0 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs
@@ -4,9 +4,11 @@
// ------------------------------------------------------------
namespace Microsoft.Azure.IIoT.OpcUa.Protocol {
+ using Opc.Ua;
using System;
+ using System.Linq;
+ using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
- using Opc.Ua;
///
/// Configuration extensions
@@ -20,8 +22,8 @@ public static class OpcConfigEx {
///
///
///
- public static ApplicationConfiguration ToApplicationConfiguration(
- this IClientServicesConfig2 opcConfig, bool createSelfSignedCertIfNone,
+ public static async Task ToApplicationConfigurationAsync(
+ this IClientServicesConfig opcConfig, bool createSelfSignedCertIfNone,
CertificateValidationEventHandler handler) {
if (string.IsNullOrWhiteSpace(opcConfig.ApplicationName)) {
throw new ArgumentNullException(nameof(opcConfig.ApplicationName));
@@ -40,20 +42,28 @@ public static ApplicationConfiguration ToApplicationConfiguration(
applicationConfiguration.CertificateValidator.CertificateValidation += handler;
- X509Certificate2 certificate = null;
+ var configuredSubject = applicationConfiguration.SecurityConfiguration
+ .ApplicationCertificate.SubjectName;
+ applicationConfiguration.SecurityConfiguration.ApplicationCertificate.SubjectName =
+ applicationConfiguration.ApplicationName;
+ await applicationConfiguration.CertificateValidator
+ .Update(applicationConfiguration.SecurityConfiguration);
- // use existing certificate, if it is there
- certificate = applicationConfiguration.SecurityConfiguration.ApplicationCertificate.Find(true).Result;
+ // use existing certificate, if present
+ var certificate = applicationConfiguration.SecurityConfiguration
+ .ApplicationCertificate.Certificate;
// create a self signed certificate if there is none
if (certificate == null && createSelfSignedCertIfNone) {
certificate = CertificateFactory.CreateCertificate(
- applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StoreType,
- applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StorePath,
+ applicationConfiguration.SecurityConfiguration
+ .ApplicationCertificate.StoreType,
+ applicationConfiguration.SecurityConfiguration
+ .ApplicationCertificate.StorePath,
null,
applicationConfiguration.ApplicationUri,
applicationConfiguration.ApplicationName,
- applicationConfiguration.ApplicationName,
+ configuredSubject,
null,
CertificateFactory.defaultKeySize,
DateTime.UtcNow - TimeSpan.FromDays(1),
@@ -61,17 +71,29 @@ public static ApplicationConfiguration ToApplicationConfiguration(
CertificateFactory.defaultHashSize
);
- // update security information
- applicationConfiguration.SecurityConfiguration.ApplicationCertificate.Certificate =
- certificate ??
+ if (certificate == null) {
throw new Exception(
"OPC UA application certificate can not be created! Cannot continue without it!");
- //await applicationConfiguration.CertificateValidator.UpdateCertificate(
- //applicationConfiguration.SecurityConfiguration).ConfigureAwait(false);
+ }
+
+ applicationConfiguration.SecurityConfiguration
+ .ApplicationCertificate.Certificate = certificate;
+ try {
+ // copy the certificate *public key only* into the trusted certificates list
+ using (ICertificateStore trustedStore = applicationConfiguration
+ .SecurityConfiguration.TrustedPeerCertificates.OpenStore()) {
+ using (var publicKey = new X509Certificate2(certificate.RawData)) {
+ trustedStore.Add(publicKey.YieldReturn());
+ }
+ }
+ }
+ catch { }
+ // update security information
+ await applicationConfiguration.CertificateValidator.UpdateCertificate(
+ applicationConfiguration.SecurityConfiguration);
}
applicationConfiguration.ApplicationUri = Utils.GetApplicationUriFromCertificate(certificate);
-
return applicationConfiguration;
}
}
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs
index a4a9ec44b5..6ca0a7e495 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs
@@ -50,7 +50,8 @@ public static SecurityConfiguration ToSecurityConfiguration(this ISecurityConfig
AutoAcceptUntrustedCertificates = securityConfig.AutoAcceptUntrustedCertificates,
RejectSHA1SignedCertificates = securityConfig.RejectSha1SignedCertificates,
MinimumCertificateKeySize = securityConfig.MinimumCertificateKeySize,
- ApplicationCertificate = securityConfig.ApplicationCertificate.ToCertificateIdentifier()
+ ApplicationCertificate = securityConfig.ApplicationCertificate.ToCertificateIdentifier(),
+ AddAppCertToTrustedStore = true
};
return securityConfiguration;
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig2.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig.cs
similarity index 93%
rename from components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig2.cs
rename to components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig.cs
index aa5b43b7ab..0a65e9b9a3 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig2.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol {
///
/// Client services configuration
///
- public interface IClientServicesConfig2 : ITransportQuotaConfig, ISecurityConfig {
+ public interface IClientServicesConfig : ITransportQuotaConfig, ISecurityConfig {
///
/// Application name
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs
index 29b7cc2a00..407174e5ef 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs
@@ -11,6 +11,11 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol {
///
public interface ISecurityConfig {
+ ///
+ /// PkiRootPath
+ ///
+ string PkiRootPath { get; }
+
///
/// Certificate
///
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs
index f8cf48bee5..7b7a921695 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs
@@ -5,7 +5,6 @@
namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Services {
using Microsoft.Azure.IIoT.OpcUa.Protocol.Models;
- using Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime;
using Microsoft.Azure.IIoT.OpcUa.Registry.Models;
using Microsoft.Azure.IIoT.OpcUa.Core.Models;
using Microsoft.Azure.IIoT.OpcUa.Registry;
@@ -20,10 +19,9 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Services {
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
- using System.Runtime.InteropServices;
+ using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
- using System.Security.Cryptography.X509Certificates;
///
/// Opc ua stack based service client
@@ -34,32 +32,19 @@ public class ClientServices : IClientHost, IEndpointServices, IEndpointDiscovery
///
/// Create client host services
///
+ ///
///
///
- public ClientServices(ILogger logger, TimeSpan? maxOpTimeout = null) :
- this(logger, new ClientServicesConfig(), maxOpTimeout) {
- }
-
- ///
- /// Create client host services
- ///
- ///
- ///
- ///
- public ClientServices(ILogger logger, IClientServicesConfig configuration,
+ public ClientServices(ILogger logger, IClientServicesConfig clientConfig,
TimeSpan? maxOpTimeout = null) {
_logger = logger ??
throw new ArgumentNullException(nameof(logger));
- _configuration = configuration ??
- throw new ArgumentNullException(nameof(configuration));
+ _clientConfig = clientConfig ??
+ throw new ArgumentNullException(nameof(clientConfig));
_maxOpTimeout = maxOpTimeout;
-
+ _appConfig = _clientConfig.ToApplicationConfigurationAsync(true, VerifyCertificate).Result;
// Create discovery config and client certificate
- _appConfig = CreateApplicationConfiguration(
- TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30));
- InitApplicationSecurityAsync().Wait();
-
_timer = new Timer(_ => OnTimer(), null, kEvictionCheck, Timeout.InfiniteTimeSpan);
}
@@ -423,222 +408,6 @@ private void EvictIfInactive(ConnectionIdentifier id) {
}
}
- ///
- /// Create application configuration for client
- ///
- ///
- private ApplicationConfiguration CreateApplicationConfiguration(
- TimeSpan operationTimeout, TimeSpan sessionTimeout) {
-
- // mitigation for bug in .NET Core 2.1
- var effectiveAppCertStoreType = _configuration.AppCertStoreType;
- var effectiveOwnCertPath = _configuration.OwnCertPath;
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
- effectiveAppCertStoreType = CertificateStoreType.X509Store;
- effectiveOwnCertPath = _configuration.OwnCertX509StorePathDefault;
- }
-
- var applicationConfiguration = new ApplicationConfiguration {
- ApplicationName = "Azure IIoT OPC Twin Client Services",
- ApplicationType = Opc.Ua.ApplicationType.Client,
- ApplicationUri = "urn:" + Utils.GetHostName() + ":Azure:IIoTOpcTwin",
- CertificateValidator = new CertificateValidator(),
- SecurityConfiguration = new SecurityConfiguration {
- ApplicationCertificate = new CertificateIdentifier {
- StoreType = effectiveAppCertStoreType,
- StorePath = effectiveOwnCertPath,
- SubjectName = "Azure IIoT OPC Twin"
- },
- TrustedPeerCertificates = new CertificateTrustList {
- StoreType = CertificateStoreType.Directory,
- StorePath = _configuration.TrustedCertPath
- },
- TrustedIssuerCertificates = new CertificateTrustList {
- StoreType = CertificateStoreType.Directory,
- StorePath = _configuration.IssuerCertPath
- },
- RejectedCertificateStore = new CertificateTrustList {
- StoreType = CertificateStoreType.Directory,
- StorePath = _configuration.RejectedCertPath
- },
- NonceLength = 32,
- AutoAcceptUntrustedCertificates = _configuration.AutoAcceptUntrustedCertificates,
- RejectSHA1SignedCertificates = false,
- AddAppCertToTrustedStore = false,
- MinimumCertificateKeySize = 1024
- },
- TransportConfigurations = new TransportConfigurationCollection(),
- TransportQuotas = TransportQuotaConfigEx.DefaultTransportQuotas(),
- ClientConfiguration = new ClientConfiguration {
- DefaultSessionTimeout = (int)sessionTimeout.TotalMilliseconds
- }
- };
- applicationConfiguration.TransportQuotas.OperationTimeout = (int)operationTimeout.TotalMilliseconds;
- return applicationConfiguration;
- }
-
- ///
- /// Initialize the OPC UA Application's security configuration
- ///
- ///
- private async Task InitApplicationSecurityAsync() {
-
- // update certificates validator
- _appConfig.CertificateValidator.CertificateValidation +=
- new CertificateValidationEventHandler(VerifyCertificate);
- await _appConfig.CertificateValidator
- .Update(_appConfig).ConfigureAwait(false);
-
- // lookup for an existing certificate in the configured store
- var ownCertificate = await _appConfig.SecurityConfiguration
- .ApplicationCertificate.Find(true).ConfigureAwait(false);
- if (ownCertificate == null) {
- //
- // Work around windows issue and lookup application certificate also on
- // directory if configured. This is needed for container persistence.
- //
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
- _configuration.AppCertStoreType == CertificateStoreType.Directory) {
-
- // Use x509 store instead of directory for private cert.
- var ownCertificateIdentifier = new CertificateIdentifier {
- StoreType = _configuration.AppCertStoreType,
- StorePath = _configuration.OwnCertPath,
- SubjectName = _appConfig.SecurityConfiguration
- .ApplicationCertificate.SubjectName
- };
- ownCertificate = await ownCertificateIdentifier.Find(true)
- .ConfigureAwait(false);
- if ((ownCertificate != null) && !ownCertificate.Verify()) {
- try {
- _logger.Warning("Found malformed own certificate {Thumbprint}, " +
- "{Subject} in the store - deleting it...",
- ownCertificate.Thumbprint, ownCertificate.Subject);
- ownCertificateIdentifier.RemoveFromStore(ownCertificate);
- }
- catch (Exception ex) {
- _logger.Information(ex,
- "Failed to remove malformed own certificate");
- }
- ownCertificate = null;
- }
- }
- }
-
- if (ownCertificate == null) {
-
- _logger.Information("Application own certificate not found. " +
- "Creating a new self-signed certificate with default settings...");
- ownCertificate = CertificateFactory.CreateCertificate(
- _appConfig.SecurityConfiguration.ApplicationCertificate.StoreType,
- _appConfig.SecurityConfiguration.ApplicationCertificate.StorePath,
- null,
- _appConfig.ApplicationUri, _appConfig.ApplicationName,
- _appConfig.SecurityConfiguration.ApplicationCertificate.SubjectName,
- null, CertificateFactory.defaultKeySize,
- DateTime.UtcNow - TimeSpan.FromDays(1),
- CertificateFactory.defaultLifeTime, CertificateFactory.defaultHashSize,
- false, null, null);
-
- _appConfig.SecurityConfiguration.ApplicationCertificate.Certificate =
- ownCertificate;
- _logger.Information(
- "New application certificate with {Thumbprint}, {Subject} created",
- ownCertificate.Thumbprint, ownCertificate.SubjectName.Name);
- }
- else {
- _logger.Information("Application certificate with {Thumbprint}, {Subject} " +
- "found in the certificate store",
- ownCertificate.Thumbprint, ownCertificate.SubjectName.Name);
- }
- // Set the Certificate as the newly created certificate
- await SetOwnCertificateAsync(ownCertificate);
- if (_appConfig.SecurityConfiguration.AutoAcceptUntrustedCertificates) {
- _logger.Warning(
- "WARNING: Automatically accepting certificates. This is a security risk.");
- }
- }
-
- ///
- /// set a new application instance certificate
- ///
- ///
- private async Task SetOwnCertificateAsync(X509Certificate2 newCertificate) {
-
- if (newCertificate == null || !newCertificate.HasPrivateKey) {
- throw new ArgumentException("Empty or invalid certificate");
- }
-
- // attempt to replace the old certificate from the various trust lists
- var oldCertificate = _appConfig.SecurityConfiguration
- .ApplicationCertificate.Certificate;
- if (oldCertificate?.Thumbprint != newCertificate.Thumbprint) {
- return;
- }
-
- _logger.Information(
- "Setting new application certificate {Thumbprint}, {Subject}...",
- newCertificate.Thumbprint, newCertificate.SubjectName.Name);
-
- // copy the certificate, public key only into the trusted certificates list
- using (var publicKey = new X509Certificate2(newCertificate.RawData)) {
- var trustList =
- _appConfig.SecurityConfiguration.TrustedPeerCertificates;
- if (oldCertificate != null) {
- trustList.Remove(oldCertificate.YieldReturn());
- }
- trustList.Add(newCertificate.YieldReturn());
- }
-
- // add the certificate to the own store
- try {
- var applicationCertificate = _appConfig.SecurityConfiguration
- .ApplicationCertificate;
- _logger.Information(
- "Adding own certificate to configured certificate store");
- // Remove old and add new
- if (oldCertificate != null) {
- applicationCertificate.RemoveFromStore(oldCertificate);
- }
- applicationCertificate.AddToStore(newCertificate, true);
- }
- catch (Exception ex) {
- _logger.Warning(ex,
- "Failed adding own certificate into configured certificate store.");
- }
-
- //
- // Work around windows issue and persist application certificate also on
- // directory if configured. This is needed for container persistence.
- //
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
- _configuration.AppCertStoreType == CertificateStoreType.Directory) {
- var applicationCertificate = new CertificateIdentifier {
- StoreType = CertificateStoreType.Directory,
- StorePath = _configuration.OwnCertPath,
- SubjectName = newCertificate.SubjectName.Name
- };
- try {
- _logger.Information(
- "Persisting own certificate into directory certificate store...");
- // Remove old and add new
- if (oldCertificate != null) {
- applicationCertificate.RemoveFromStore(oldCertificate);
- }
- applicationCertificate.AddToStore(newCertificate, true);
- }
- catch (Exception ex) {
- _logger.Warning(ex,
- "Failed adding own certificate to directory certificate store.");
- }
- }
-
- _appConfig.SecurityConfiguration.ApplicationCertificate
- .Certificate = newCertificate;
- await _appConfig.CertificateValidator.UpdateCertificate(
- _appConfig.SecurityConfiguration);
- }
-
///
/// Default event handler to validate certificates and handle auto accept.
///
@@ -751,7 +520,7 @@ public void Dispose() {
private const int kMaxDiscoveryAttempts = 3;
private readonly ILogger _logger;
private readonly TimeSpan? _maxOpTimeout;
- private readonly IClientServicesConfig _configuration;
+ private readonly IClientServicesConfig _clientConfig;
private readonly ApplicationConfiguration _appConfig;
private readonly Dictionary _clients =
new Dictionary();
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs
index 438213304c..523e11de04 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs
@@ -32,7 +32,7 @@ public class DefaultSessionManager : ISessionManager {
///
///
///
- public DefaultSessionManager(IClientServicesConfig2 clientConfig, ILogger logger) {
+ public DefaultSessionManager(IClientServicesConfig clientConfig, ILogger logger) {
_logger = logger;
_clientConfig = clientConfig;
_lock = new SemaphoreSlim(1, 1);
@@ -110,7 +110,7 @@ void OnValidate(CertificateValidator sender, CertificateValidationEventArgs e) {
}
};
- var applicationConfiguration = _clientConfig.ToApplicationConfiguration(
+ var applicationConfiguration = await _clientConfig.ToApplicationConfigurationAsync(
true, OnValidate);
var endpointConfiguration = _clientConfig.ToEndpointConfiguration();
@@ -403,7 +403,7 @@ public static EndpointIdentifier GetEndpointId(SessionClient session) {
}
private readonly ILogger _logger;
- private readonly IClientServicesConfig2 _clientConfig;
+ private readonly IClientServicesConfig _clientConfig;
private readonly Dictionary _sessions =
new Dictionary();
private readonly SemaphoreSlim _lock;
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs
index 14ef550c8b..c20d02acca 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs
@@ -12,7 +12,6 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Services {
using System.Threading;
using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
- using System.Runtime.InteropServices;
///
/// Console host for servers
@@ -21,7 +20,8 @@ public class ServerConsoleHost : IServerHost {
///
public X509Certificate2 Certificate { get; private set; }
-
+ ///
+ public string PkiRootPath { get; set; }
///
public bool AutoAccept { get; set; }
@@ -70,7 +70,7 @@ public async Task StartAsync(IEnumerable ports) {
await _lock.WaitAsync();
try {
if (_server == null) {
- await StartServerInternalAsync(ports);
+ await StartServerInternalAsync(ports, PkiRootPath);
return;
}
}
@@ -97,24 +97,19 @@ public void Dispose() {
/// Start server
///
///
+ ///
///
- private async Task StartServerInternalAsync(IEnumerable ports) {
+ private async Task StartServerInternalAsync(IEnumerable ports, string pkiRootPath) {
ApplicationInstance.MessageDlg = new DummyDialog();
- var config = _factory.CreateServer(ports, out _server);
+ var config = _factory.CreateServer(ports, pkiRootPath, out _server);
_logger.Information("Server created...");
config = ApplicationInstance.FixupAppConfig(config);
-
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
- config.SecurityConfiguration.ApplicationCertificate.StoreType =
- CertificateStoreType.X509Store;
- config.SecurityConfiguration.ApplicationCertificate.StorePath =
- "CurrentUser\\UA_MachineDefault";
- }
_logger.Information("Validate configuration...");
await config.Validate(ApplicationType.Server);
+ config.SecurityConfiguration.AutoAcceptUntrustedCertificates = AutoAccept;
config.CertificateValidator = new CertificateValidator();
config.CertificateValidator.CertificateValidation += (v, e) => {
if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted) {
@@ -126,10 +121,8 @@ private async Task StartServerInternalAsync(IEnumerable ports) {
_logger.Information("Initialize certificate validation...");
await config.CertificateValidator.Update(config.SecurityConfiguration);
+ var cert = config.SecurityConfiguration.ApplicationCertificate.Certificate;
- // Use existing certificate, if it is there.
- var cert = await config.SecurityConfiguration.ApplicationCertificate
- .Find(true);
if (cert == null) {
_logger.Information("Creating new certificate in {path}...",
config.SecurityConfiguration.ApplicationCertificate.StorePath);
@@ -143,15 +136,12 @@ private async Task StartServerInternalAsync(IEnumerable ports) {
null, CertificateFactory.defaultKeySize,
DateTime.UtcNow - TimeSpan.FromDays(1),
CertificateFactory.defaultLifeTime,
- CertificateFactory.defaultHashSize,
- false, null, null);
+ CertificateFactory.defaultHashSize);
#pragma warning restore IDE0067 // Dispose objects before losing scope
- }
-
- if (cert != null) {
config.SecurityConfiguration.ApplicationCertificate.Certificate = cert;
- config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert);
+ await config.CertificateValidator.UpdateCertificate(config.SecurityConfiguration);
}
+ config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert);
var application = new ApplicationInstance(config);
@@ -159,12 +149,18 @@ private async Task StartServerInternalAsync(IEnumerable ports) {
var haveAppCertificate =
await application.CheckApplicationInstanceCertificate(false, 0);
if (!haveAppCertificate) {
- _logger.Error("Failed validating certificate!");
+ _logger.Error("Failed validating own certificate!");
throw new Exception("Application instance certificate invalid!");
}
- // Set certificate
- Certificate = cert;
+ // Set Certificate
+ try {
+ // just take the public key
+ Certificate = new X509Certificate2(config.SecurityConfiguration.ApplicationCertificate.Certificate.RawData);
+ }
+ catch {
+ Certificate = config.SecurityConfiguration.ApplicationCertificate.Certificate;
+ }
_logger.Information("Starting server ...");
// start the server.
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj
index e6ee1323af..8eddaee437 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj
@@ -4,9 +4,9 @@
netcoreapp3.1
-
-
-
+
+
+
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs
index ec0de9f331..27f7fda913 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs
@@ -32,6 +32,7 @@ namespace Microsoft.Azure.IIoT.OpcUa.Cli {
using System.IO;
using System.IO.Compression;
using System.Linq;
+ using System.Net;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
@@ -62,7 +63,7 @@ public static void Main(string[] args) {
var op = Op.None;
var endpoint = new EndpointModel();
string fileName = null;
- var host = Utils.GetHostName();
+ var host = Dns.GetHostName();
var ports = new List();
try {
for (var i = 0; i < args.Length; i++) {
@@ -622,7 +623,7 @@ public ServerWrapper(EndpointModel endpoint, StackLogger logger) {
_cts = new CancellationTokenSource();
if (endpoint.Url == null) {
_server = RunSampleServerAsync(_cts.Token, logger.Logger);
- endpoint.Url = "opc.tcp://" + Utils.GetHostName() +
+ endpoint.Url = "opc.tcp://" + Dns.GetHostName() +
":51210/UA/SampleServer";
}
else {
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs
index 741027ec03..966dfd7c5a 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs
@@ -35,6 +35,11 @@ public abstract class BaseServerFixture : IDisposable {
///
public X509Certificate2 Certificate => _serverHost.Certificate;
+ ///
+ /// Cert folder
+ ///
+ public string PkiRootPath { get; private set; }
+
///
/// Logger
///
@@ -50,7 +55,7 @@ public abstract class BaseServerFixture : IDisposable {
///
public static int StartPort { set => _nextPort = value; }
- ///
+ ///
/// Create fixture
///
protected BaseServerFixture(IEnumerable nodes) {
@@ -62,15 +67,18 @@ protected BaseServerFixture(IEnumerable nodes) {
_client = new Lazy(() => {
return new ClientServices(Logger, _config);
}, false);
- _serverHost = new ServerConsoleHost(
- new ServerFactory(Logger, nodes) {
- LogStatus = false
- }, Logger) {
- AutoAccept = true
- };
+ PkiRootPath = Path.Combine(Directory.GetCurrentDirectory(), "pki",
+ Guid.NewGuid().ToByteArray().ToBase16String());
var port = Interlocked.Increment(ref _nextPort);
for (var i = 0; i < 200; i++) { // Retry 200 times
try {
+ _serverHost = new ServerConsoleHost(
+ new ServerFactory(Logger, nodes) {
+ LogStatus = false
+ }, Logger) {
+ PkiRootPath = PkiRootPath,
+ AutoAccept = true
+ };
Logger.Information("Starting server host on {port}...",
port);
_serverHost.StartAsync(new int[] { port }).Wait();
@@ -90,17 +98,16 @@ public void Dispose() {
Logger.Information("Disposing server and client fixture...");
_serverHost.Dispose();
// Clean up all created certificates
- var certFolder = Path.Combine(Directory.GetCurrentDirectory(), "OPC Foundation");
- if (Directory.Exists(certFolder)) {
+ if (Directory.Exists(PkiRootPath)) {
Logger.Information("Server disposed - cleaning up server certificates...");
- Try.Op(() => Directory.Delete(certFolder, true));
+ Try.Op(() => Directory.Delete(PkiRootPath, true));
}
if (_client.IsValueCreated) {
Logger.Information("Disposing client...");
Task.Run(() => _client.Value.Dispose()).Wait();
- Logger.Information("Client disposed - cleaning up client certificates...");
- _config?.Dispose();
}
+ Logger.Information("Client disposed - cleaning up client certificates...");
+ _config?.Dispose();
Logger.Information("Server and client fixture disposed.");
}
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs
index e653839892..bc5e1bb5bf 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs
@@ -5,50 +5,69 @@
namespace Microsoft.Azure.IIoT.OpcUa.Testing.Runtime {
using Microsoft.Azure.IIoT.OpcUa.Protocol;
+ using Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime;
using Microsoft.Azure.IIoT.Utils;
using System;
using System.IO;
- using System.Runtime.InteropServices;
///
/// Client's application configuration implementation
///
public class TestClientServicesConfig : IClientServicesConfig, IDisposable {
- ///
- /// Pki root
- ///
- public const string Pki = "pki";
-
///
- public string AppCertStoreType =>
- RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
- "X509Store" : "Directory";
-
+ public string PkiRootPath { get;}
+ ///
+ public string ApplicationName => _opc.ApplicationName;
+ ///
+ public string ApplicationUri => _opc.ApplicationUri;
+ ///
+ public string ProductUri => _opc.ProductUri;
+ ///
+ public uint DefaultSessionTimeout => _opc.DefaultSessionTimeout;
+ ///
+ public int KeepAliveInterval => _opc.KeepAliveInterval;
+ ///
+ public uint MaxKeepAliveCount => _opc.MaxKeepAliveCount;
///
- public string PkiRootPath { get; }
+ public int MinSubscriptionLifetime => _opc.MinSubscriptionLifetime;
///
- public string OwnCertPath => Path.Combine(PkiRootPath, "own");
+ public CertificateInfo ApplicationCertificate => _opc.ApplicationCertificate;
///
- public string TrustedCertPath => Path.Combine(PkiRootPath, "trusted");
+ public bool AutoAcceptUntrustedCertificates { get; private set; }
///
- public string IssuerCertPath => Path.Combine(PkiRootPath, "issuer");
+ public ushort MinimumCertificateKeySize => _opc.MinimumCertificateKeySize;
///
- public string RejectedCertPath => Path.Combine(PkiRootPath, "rejected");
+ public CertificateStore RejectedCertificateStore => _opc.RejectedCertificateStore;
///
- public string OwnCertX509StorePathDefault => "CurrentUser\\UA_MachineDefault";
+ public bool RejectSha1SignedCertificates => _opc.RejectSha1SignedCertificates;
///
- public bool AutoAcceptUntrustedCertificates { get; }
+ public CertificateStore TrustedIssuerCertificates => _opc.TrustedIssuerCertificates;
///
- public TimeSpan? DefaultSessionTimeout => null;
+ public CertificateStore TrustedPeerCertificates => _opc.TrustedPeerCertificates;
///
- public TimeSpan? OperationTimeout => null;
+ public int ChannelLifetime => _opc.ChannelLifetime;
+ ///
+ public int MaxArrayLength => _opc.MaxArrayLength;
+ ///
+ public int MaxBufferSize => _opc.MaxBufferSize;
+ ///
+ public int MaxByteStringLength => _opc.MaxByteStringLength;
+ ///
+ public int MaxMessageSize => _opc.MaxMessageSize;
+ ///
+ public int MaxStringLength => _opc.MaxStringLength;
+ ///
+ public int OperationTimeout => _opc.OperationTimeout;
+ ///
+ public int SecurityTokenLifetime => _opc.SecurityTokenLifetime;
///
public TestClientServicesConfig(bool autoAccept = false) {
AutoAcceptUntrustedCertificates = autoAccept;
- PkiRootPath = Path.Combine(Directory.GetCurrentDirectory(), Pki,
+ PkiRootPath = Path.Combine(Directory.GetCurrentDirectory(), "pki",
Guid.NewGuid().ToByteArray().ToBase16String());
+ _opc = new ClientServicesConfig();
}
///
@@ -57,5 +76,7 @@ public void Dispose() {
Try.Op(() => Directory.Delete(PkiRootPath, true));
}
}
+
+ private readonly ClientServicesConfig _opc;
}
}
diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs
index 394313ec97..4dceb3c381 100644
--- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs
+++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs
@@ -11,10 +11,12 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Sample {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.IdentityModel.Selectors;
+ using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
///
@@ -60,10 +62,10 @@ public ServerFactory(ILogger logger) :
}
///
- public ApplicationConfiguration CreateServer(IEnumerable ports,
+ public ApplicationConfiguration CreateServer(IEnumerable ports, string applicationName,
out ServerBase server) {
server = new Server(LogStatus, _nodes, _logger);
- return Server.CreateServerConfiguration(ports);
+ return Server.CreateServerConfiguration(ports, applicationName);
}
///
@@ -88,7 +90,7 @@ public Server(bool logStatus, IEnumerable nodes,
///
///
public static ApplicationConfiguration CreateServerConfiguration(
- IEnumerable ports) {
+ IEnumerable ports, string pkiRootPath) {
var extensions = new List