diff --git a/clients/dotnet/ZB.MOM.WW.MxGateway.Client.Tests/MxGatewayClientTlsHandlerTests.cs b/clients/dotnet/ZB.MOM.WW.MxGateway.Client.Tests/MxGatewayClientTlsHandlerTests.cs
new file mode 100644
index 0000000..3ba09f5
--- /dev/null
+++ b/clients/dotnet/ZB.MOM.WW.MxGateway.Client.Tests/MxGatewayClientTlsHandlerTests.cs
@@ -0,0 +1,42 @@
+using System.Net.Http;
+using ZB.MOM.WW.MxGateway.Client;
+
+namespace ZB.MOM.WW.MxGateway.Client.Tests;
+
+public sealed class MxGatewayClientTlsHandlerTests
+{
+ ///
+ /// Verifies that when TLS is used with no pinned CA and RequireCertificateValidation is false (default),
+ /// the handler installs an accept-all callback so the gateway's self-signed cert is trusted.
+ ///
+ [Fact]
+ public void Handler_SkipsVerification_WhenTlsAndNoCaPinned()
+ {
+ MxGatewayClientOptions options = new()
+ {
+ Endpoint = new Uri("https://localhost:5120"),
+ ApiKey = "k",
+ UseTls = true,
+ };
+ using SocketsHttpHandler handler = MxGatewayClient.CreateHttpHandlerForTests(options);
+ Assert.NotNull(handler.SslOptions.RemoteCertificateValidationCallback);
+ }
+
+ ///
+ /// Verifies that when RequireCertificateValidation is true, the callback is left null
+ /// so the OS trust store performs validation.
+ ///
+ [Fact]
+ public void Handler_KeepsDefaultVerification_WhenRequireCertificateValidation()
+ {
+ MxGatewayClientOptions options = new()
+ {
+ Endpoint = new Uri("https://localhost:5120"),
+ ApiKey = "k",
+ UseTls = true,
+ RequireCertificateValidation = true,
+ };
+ using SocketsHttpHandler handler = MxGatewayClient.CreateHttpHandlerForTests(options);
+ Assert.Null(handler.SslOptions.RemoteCertificateValidationCallback);
+ }
+}
diff --git a/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClient.cs b/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClient.cs
index 2ae95ff..20c35a4 100644
--- a/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClient.cs
+++ b/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClient.cs
@@ -315,7 +315,10 @@ public sealed class MxGatewayClient : IAsyncDisposable
.ConfigureAwait(false);
}
- private static HttpMessageHandler CreateHttpHandler(MxGatewayClientOptions options)
+ private static HttpMessageHandler CreateHttpHandler(MxGatewayClientOptions options) =>
+ CreateHttpHandlerForTests(options);
+
+ internal static SocketsHttpHandler CreateHttpHandlerForTests(MxGatewayClientOptions options)
{
SocketsHttpHandler handler = new()
{
@@ -350,6 +353,10 @@ public sealed class MxGatewayClient : IAsyncDisposable
return customChain.Build(certificateToValidate);
};
}
+ else if (!options.RequireCertificateValidation)
+ {
+ handler.SslOptions.RemoteCertificateValidationCallback = (_, _, _, _) => true;
+ }
}
return handler;
diff --git a/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClientOptions.cs b/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClientOptions.cs
index f66b56e..df93c3b 100644
--- a/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClientOptions.cs
+++ b/clients/dotnet/ZB.MOM.WW.MxGateway.Client/MxGatewayClientOptions.cs
@@ -27,6 +27,14 @@ public sealed class MxGatewayClientOptions
///
public string? CaCertificatePath { get; init; }
+ ///
+ /// When true, TLS connections without a pinned
+ /// use the OS trust store. When false (default), the gateway certificate is
+ /// accepted without verification — appropriate for this internal tool's
+ /// auto-generated self-signed certificate. Pinning a CA always verifies.
+ ///
+ public bool RequireCertificateValidation { get; init; }
+
///
/// Gets the server name override for SNI during TLS handshake.
///
diff --git a/clients/dotnet/ZB.MOM.WW.MxGateway.Client/ZB.MOM.WW.MxGateway.Client.csproj b/clients/dotnet/ZB.MOM.WW.MxGateway.Client/ZB.MOM.WW.MxGateway.Client.csproj
index 590435d..bf34ef7 100644
--- a/clients/dotnet/ZB.MOM.WW.MxGateway.Client/ZB.MOM.WW.MxGateway.Client.csproj
+++ b/clients/dotnet/ZB.MOM.WW.MxGateway.Client/ZB.MOM.WW.MxGateway.Client.csproj
@@ -27,4 +27,10 @@
+
+
+ <_Parameter1>ZB.MOM.WW.MxGateway.Client.Tests
+
+
+