diff --git a/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs b/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs
index 860756bb54..d2502edfba 100644
--- a/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs
+++ b/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs
@@ -80,7 +80,7 @@ ApplicationConfiguration configuration
ServerCertificateGroup defaultApplicationGroup = new ServerCertificateGroup {
NodeId = Opc.Ua.ObjectIds.ServerConfiguration_CertificateGroups_DefaultApplicationGroup,
BrowseName = Opc.Ua.BrowseNames.DefaultApplicationGroup,
- CertificateTypes = new NodeId[]{},
+ CertificateTypes = new NodeId[] { },
ApplicationCertificates = new CertificateIdentifierCollection(),
IssuerStore = new CertificateStoreIdentifier(configuration.SecurityConfiguration.TrustedIssuerCertificates.StorePath),
TrustedStore = new CertificateStoreIdentifier(configuration.SecurityConfiguration.TrustedPeerCertificates.StorePath)
@@ -397,7 +397,7 @@ private ServiceResult UpdateCertificate(
// identify the existing certificate to be updated
// it should be of the same type and same subject name as the new certificate
- CertificateIdentifier existingCertIdentifier = certificateGroup.ApplicationCertificates.FirstOrDefault(cert =>
+ CertificateIdentifier existingCertIdentifier = certificateGroup.ApplicationCertificates.FirstOrDefault(cert =>
X509Utils.CompareDistinguishedName(cert.Certificate.Subject, newCert.Subject) &&
cert.CertificateType == certificateTypeId);
@@ -451,8 +451,8 @@ private ServiceResult UpdateCertificate(
{
// verify cert with issuer chain
CertificateValidator certValidator = new CertificateValidator();
-// TODO: why?
-// certValidator.MinimumCertificateKeySize = 1024;
+ // TODO: why?
+ // certValidator.MinimumCertificateKeySize = 1024;
CertificateTrustList issuerStore = new CertificateTrustList();
CertificateIdentifierCollection issuerCollection = new CertificateIdentifierCollection();
foreach (var issuerCert in newIssuerCollection)
@@ -677,7 +677,15 @@ private ServiceResult ApplyChanges(
// give the client some time to receive the response
// before the certificate update may disconnect all sessions
await Task.Delay(1000).ConfigureAwait(false);
- await m_configuration.CertificateValidator.UpdateCertificateAsync(m_configuration.SecurityConfiguration).ConfigureAwait(false);
+ try
+ {
+ await m_configuration.CertificateValidator.UpdateCertificateAsync(m_configuration.SecurityConfiguration).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Utils.LogCritical(ex, "Failed to sucessfully Apply Changes: Error updating application instance certificates. Server could be in faulted state.");
+ throw ex;
+ }
}
);
}
diff --git a/Libraries/Opc.Ua.Server/Server/StandardServer.cs b/Libraries/Opc.Ua.Server/Server/StandardServer.cs
index 45dd363f88..1ee4c896ba 100644
--- a/Libraries/Opc.Ua.Server/Server/StandardServer.cs
+++ b/Libraries/Opc.Ua.Server/Server/StandardServer.cs
@@ -488,7 +488,7 @@ public override ResponseHeader CreateSession(
// check if complete chain should be sent.
if (InstanceCertificateTypesProvider.SendCertificateChain)
{
- serverCertificate = InstanceCertificateTypesProvider.LoadCertificateChainRaw(instanceCertificate);
+ serverCertificate = InstanceCertificateTypesProvider.LoadCertificateChainRawAsync(instanceCertificate).GetAwaiter().GetResult();
}
else
{
diff --git a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs
index 1ef99083af..3ed00e08ae 100644
--- a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs
+++ b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs
@@ -125,7 +125,7 @@ CertificateTypesProvider certificateTypesProvider
// check if complete chain should be sent.
if (certificateTypesProvider.SendCertificateChain)
{
- description.ServerCertificate = certificateTypesProvider.LoadCertificateChainRaw(instanceCertificate);
+ description.ServerCertificate = certificateTypesProvider.LoadCertificateChainRawAsync(instanceCertificate).GetAwaiter().GetResult();
}
}
diff --git a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs
index 0f46ebdbca..2da30e11a9 100644
--- a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs
+++ b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs
@@ -477,10 +477,9 @@ public void CertificateUpdate(
foreach (EndpointDescription description in m_descriptions)
{
- ServerBase.SetServerCertificateInEndpointDescription(description,
- m_serverCertProvider.SendCertificateChain,
+ ServerBase.SetServerCertificateInEndpointDescriptionAsync(description,
certificateTypeProvider,
- false);
+ false).GetAwaiter().GetResult();
}
Start();
diff --git a/Stack/Opc.Ua.Core/Security/Certificates/CertificateTypesProvider.cs b/Stack/Opc.Ua.Core/Security/Certificates/CertificateTypesProvider.cs
index 9e4c587569..9d472af10d 100644
--- a/Stack/Opc.Ua.Core/Security/Certificates/CertificateTypesProvider.cs
+++ b/Stack/Opc.Ua.Core/Security/Certificates/CertificateTypesProvider.cs
@@ -122,7 +122,7 @@ public X509Certificate2 GetInstanceCertificate(string securityPolicyUri)
/// Loads the cached certificate chain blob of a certificate for use in a secure channel as raw byte array.
///
/// The application certificate.
- public byte[] LoadCertificateChainRaw(X509Certificate2 certificate)
+ public async Task LoadCertificateChainRawAsync(X509Certificate2 certificate)
{
if (certificate == null)
{
@@ -134,7 +134,13 @@ public byte[] LoadCertificateChainRaw(X509Certificate2 certificate)
return result.Item2;
}
- return certificate.RawData;
+ // load certificate chain.
+ Tuple dictionaryValue = await LoadCertificateChainFromStoreAsync(certificate).ConfigureAwait(false);
+
+ // update cached values
+ m_certificateChain[certificate.Thumbprint] = dictionaryValue;
+
+ return dictionaryValue.Item2;
}
///
@@ -154,51 +160,44 @@ public async Task LoadCertificateChainAsync(X509Cert
}
// load certificate chain.
- var certificateChain = new X509Certificate2Collection(certificate);
- var issuers = new List();
- if (await m_certificateValidator.GetIssuers(certificate, issuers).ConfigureAwait(false))
- {
- for (int i = 0; i < issuers.Count; i++)
- {
- certificateChain.Add(issuers[i].Certificate);
- }
- }
-
- byte[] certificateChainRaw = Utils.CreateCertificateChainBlob(certificateChain);
- var dictionaryValue = new Tuple(certificateChain, certificateChainRaw);
+ Tuple dictionaryValue = await LoadCertificateChainFromStoreAsync(certificate).ConfigureAwait(false);
// update cached values
m_certificateChain[certificate.Thumbprint] = dictionaryValue;
- return certificateChain;
+ return dictionaryValue.Item1;
}
///
- /// Loads the certificate chain for an application certificate from cache.
+ /// Update the security configuration of the cert type provider.
///
- /// The application certificate.
- public X509Certificate2Collection LoadCertificateChain(X509Certificate2 certificate)
+ /// The new security configuration.
+ public async Task UpdateAsync(SecurityConfiguration securityConfiguration)
{
- if (certificate == null)
- {
- return null;
- }
-
- if (m_certificateChain.TryGetValue(certificate.Thumbprint, out var certificateChainTuple))
- {
- return certificateChainTuple.Item1;
- }
-
- return null;
+ m_securityConfiguration = securityConfiguration;
+ //ToDo intialize internal CertificateValidator after Certificate Update to clear cache of old application certificates
+ await Task.CompletedTask.ConfigureAwait(false);
}
///
- /// Update the security configuration of the cert type provider.
+ /// Builds the chain using the Issuer and Trusted Stores of the certificateValidator
///
- /// The new security configuration.
- public void Update(SecurityConfiguration securityConfiguration)
+ /// the certificate to load the chain for
+ ///
+ private async Task> LoadCertificateChainFromStoreAsync(X509Certificate2 certificate)
{
- m_securityConfiguration = securityConfiguration;
+ var certificateChain = new X509Certificate2Collection(certificate);
+ var issuers = new List();
+ if (await m_certificateValidator.GetIssuers(certificate, issuers).ConfigureAwait(false))
+ {
+ for (int i = 0; i < issuers.Count; i++)
+ {
+ certificateChain.Add(issuers[i].Certificate);
+ }
+ }
+
+ byte[] certificateChainRaw = Utils.CreateCertificateChainBlob(certificateChain);
+ return new Tuple(certificateChain, certificateChainRaw);
}
CertificateValidator m_certificateValidator;
diff --git a/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs b/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs
index eb4f7de894..ffcbf0a807 100644
--- a/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs
+++ b/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs
@@ -21,10 +21,10 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
-using Microsoft.Extensions.Logging;
using Opc.Ua.Bindings;
using System.Net.Sockets;
using Opc.Ua.Security.Certificates;
+using System.Threading.Tasks;
namespace Opc.Ua
{
@@ -604,12 +604,10 @@ public static bool RequireEncryption(EndpointDescription description)
/// Sets the Server Certificate in an Endpoint description if the description requires encryption.
///
/// the endpoint Description to set the server certificate
- /// true if the certificate chain shall be sent
/// The provider to get the server certificate per certificate type.
/// only set certificate if the endpoint does require Encryption
- public static void SetServerCertificateInEndpointDescription(
+ public static async Task SetServerCertificateInEndpointDescriptionAsync(
EndpointDescription description,
- bool sendCertificateChain,
CertificateTypesProvider certificateTypesProvider,
bool checkRequireEncryption = true)
{
@@ -617,9 +615,9 @@ public static void SetServerCertificateInEndpointDescription(
{
X509Certificate2 serverCertificate = certificateTypesProvider.GetInstanceCertificate(description.SecurityPolicyUri);
// check if complete chain should be sent.
- if (sendCertificateChain)
+ if (certificateTypesProvider.SendCertificateChain)
{
- description.ServerCertificate = certificateTypesProvider.LoadCertificateChainRaw(serverCertificate);
+ description.ServerCertificate = await certificateTypesProvider.LoadCertificateChainRawAsync(serverCertificate).ConfigureAwait(false);
}
else
{
@@ -796,7 +794,16 @@ protected virtual EndpointBase GetEndpointInstance(ServerBase server)
///
protected virtual void OnCertificateUpdate(object sender, CertificateUpdateEventArgs e)
{
- InstanceCertificateTypesProvider.Update(e.SecurityConfiguration);
+ InstanceCertificateTypesProvider.UpdateAsync(e.SecurityConfiguration).GetAwaiter().GetResult();
+
+ //update certificate in the endpoint descriptions
+ foreach (EndpointDescription endpointDescription in m_endpoints)
+ {
+ SetServerCertificateInEndpointDescriptionAsync(
+ endpointDescription,
+ InstanceCertificateTypesProvider).GetAwaiter().GetResult();
+ }
+
foreach (var listener in TransportListeners)
{
listener.CertificateUpdate(e.CertificateValidator, InstanceCertificateTypesProvider);
diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpServiceHost.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpServiceHost.cs
index fa12741ec1..fa671e1e5d 100644
--- a/Stack/Opc.Ua.Core/Stack/Tcp/TcpServiceHost.cs
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpServiceHost.cs
@@ -76,7 +76,6 @@ public List CreateServiceHost(
uri.Host = computerName;
}
- bool sendCertificateChain = instanceCertificateTypesProvider.SendCertificateChain;
ITransportListener listener = this.Create();
if (listener != null)
{
@@ -96,10 +95,9 @@ public List CreateServiceHost(
};
description.UserIdentityTokens = serverBase.GetUserTokenPolicies(configuration, description);
- ServerBase.SetServerCertificateInEndpointDescription(
+ ServerBase.SetServerCertificateInEndpointDescriptionAsync(
description,
- sendCertificateChain,
- instanceCertificateTypesProvider);
+ instanceCertificateTypesProvider).GetAwaiter().GetResult();
listenerEndpoints.Add(description);
}
diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs
index f651ab3d30..5469ff6875 100644
--- a/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs
@@ -490,7 +490,7 @@ CertificateTypesProvider certificateTypesProvider
X509Certificate2 serverCertificate = certificateTypesProvider.GetInstanceCertificate(description.SecurityPolicyUri);
if (certificateTypesProvider.SendCertificateChain)
{
- byte[] serverCertificateChainRaw = certificateTypesProvider.LoadCertificateChainRaw(serverCertificate);
+ byte[] serverCertificateChainRaw = certificateTypesProvider.LoadCertificateChainRawAsync(serverCertificate).GetAwaiter().GetResult();
description.ServerCertificate = serverCertificateChainRaw;
}
else
diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs
index a950d14cb1..4377c95734 100644
--- a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs
@@ -898,7 +898,7 @@ protected void ReadAsymmetricMessageHeader(
if (loadChain)
{
- m_serverCertificateChain = m_serverCertificateTypesProvider?.LoadCertificateChain(receiverCertificate);
+ m_serverCertificateChain = m_serverCertificateTypesProvider?.LoadCertificateChainAsync(receiverCertificate).GetAwaiter().GetResult();
}
}
else
@@ -930,7 +930,7 @@ protected void ReviseSecurityMode(bool firstCall, MessageSecurityMode requestedM
m_securityMode = endpoint.SecurityMode;
m_selectedEndpoint = endpoint;
m_serverCertificate = m_serverCertificateTypesProvider.GetInstanceCertificate(m_securityPolicyUri);
- m_serverCertificateChain = m_serverCertificateTypesProvider.LoadCertificateChain(m_serverCertificate);
+ m_serverCertificateChain = m_serverCertificateTypesProvider.LoadCertificateChainAsync(m_serverCertificate).GetAwaiter().GetResult();
supported = true;
break;
}