diff --git a/src/AVEVA.Historian.Client/HistorianClientOptions.cs b/src/AVEVA.Historian.Client/HistorianClientOptions.cs
index e147305..21eed2f 100644
--- a/src/AVEVA.Historian.Client/HistorianClientOptions.cs
+++ b/src/AVEVA.Historian.Client/HistorianClientOptions.cs
@@ -27,4 +27,15 @@ public sealed class HistorianClientOptions
public HistorianTransport Transport { get; init; } = HistorianTransport.LocalPipe;
public string TargetSpn { get; init; } = @"NT SERVICE\aahClientAccessPoint";
+
+ ///
+ /// When true, the WCF channel factories used by the SDK accept the server's
+ /// X.509 certificate without chain validation. Useful when connecting to a
+ /// development / on-prem Historian whose /HistCert endpoint presents an
+ /// installer-generated self-signed cert that isn't in the local trust store
+ /// (notably .NET WCF on Linux ignores the system CA bundle for its own
+ /// X509Chain checks). Default false; do not enable in production where the
+ /// server's identity matters.
+ ///
+ public bool AllowUntrustedServerCertificate { get; init; }
}
diff --git a/src/AVEVA.Historian.Client/Wcf/HistorianWcfAuthChainHelper.cs b/src/AVEVA.Historian.Client/Wcf/HistorianWcfAuthChainHelper.cs
index 02a0e59..eaa3396 100644
--- a/src/AVEVA.Historian.Client/Wcf/HistorianWcfAuthChainHelper.cs
+++ b/src/AVEVA.Historian.Client/Wcf/HistorianWcfAuthChainHelper.cs
@@ -45,6 +45,7 @@ internal static class HistorianWcfAuthChainHelper
Action? additionalSetup = null)
{
ChannelFactory historyFactory = new(historyBinding, historyEndpoint);
+ HistorianWcfClientCredentialsHelper.Configure(historyFactory, options);
historyFactory.Endpoint.EndpointBehaviors.Add(new HistorianWcfHistAddressingBehavior());
if (HistorianWcfMessageCaptureBehavior.IsEnabled)
{
diff --git a/src/AVEVA.Historian.Client/Wcf/HistorianWcfClientCredentialsHelper.cs b/src/AVEVA.Historian.Client/Wcf/HistorianWcfClientCredentialsHelper.cs
new file mode 100644
index 0000000..8759671
--- /dev/null
+++ b/src/AVEVA.Historian.Client/Wcf/HistorianWcfClientCredentialsHelper.cs
@@ -0,0 +1,38 @@
+using System.IdentityModel.Selectors;
+using System.IdentityModel.Tokens;
+using System.Security.Cryptography.X509Certificates;
+using System.ServiceModel;
+using System.ServiceModel.Security;
+
+namespace AVEVA.Historian.Client.Wcf;
+
+///
+/// Centralizes per-channel-factory credentials configuration that's not bound to a
+/// single binding type. Today this covers ServerCertificateValidation for the
+/// cert-transport binding when callers opt into .
+/// Apply at every ChannelFactory<T> instantiation point in the WCF layer.
+///
+internal static class HistorianWcfClientCredentialsHelper
+{
+ public static void Configure(ChannelFactory factory, HistorianClientOptions options)
+ {
+ ArgumentNullException.ThrowIfNull(factory);
+ ArgumentNullException.ThrowIfNull(options);
+
+ if (options.AllowUntrustedServerCertificate)
+ {
+ factory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
+ {
+ CertificateValidationMode = X509CertificateValidationMode.Custom,
+ CustomCertificateValidator = AcceptAnyCertificateValidator.Instance,
+ RevocationMode = X509RevocationMode.NoCheck,
+ };
+ }
+ }
+
+ private sealed class AcceptAnyCertificateValidator : X509CertificateValidator
+ {
+ public static readonly AcceptAnyCertificateValidator Instance = new();
+ public override void Validate(X509Certificate2 certificate) { }
+ }
+}
diff --git a/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs b/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs
index e37d036..3d79a72 100644
--- a/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs
+++ b/src/AVEVA.Historian.Client/Wcf/HistorianWcfEventOrchestrator.cs
@@ -111,6 +111,7 @@ internal sealed class HistorianWcfEventOrchestrator
CancellationToken cancellationToken)
{
ChannelFactory factory = new(binding, retrievalEndpoint);
+ HistorianWcfClientCredentialsHelper.Configure(factory, _options);
try
{
diff --git a/src/AVEVA.Historian.Client/Wcf/HistorianWcfReadOrchestrator.cs b/src/AVEVA.Historian.Client/Wcf/HistorianWcfReadOrchestrator.cs
index aa147ed..d84da8e 100644
--- a/src/AVEVA.Historian.Client/Wcf/HistorianWcfReadOrchestrator.cs
+++ b/src/AVEVA.Historian.Client/Wcf/HistorianWcfReadOrchestrator.cs
@@ -179,6 +179,7 @@ internal sealed class HistorianWcfReadOrchestrator
CancellationToken cancellationToken)
{
ChannelFactory retrievalFactory = new(binding, retrievalEndpoint);
+ HistorianWcfClientCredentialsHelper.Configure(retrievalFactory, _options);
try
{
@@ -280,6 +281,7 @@ internal sealed class HistorianWcfReadOrchestrator
CancellationToken cancellationToken)
{
ChannelFactory retrievalFactory = new(binding, retrievalEndpoint);
+ HistorianWcfClientCredentialsHelper.Configure(retrievalFactory, _options);
try
{