Files
UA-.NETStandard/Stack
Marc Schier 5ca95abd0d [security] HttpsTransportChannel: refuse factory path when OPC UA cert validation is required
Security-review subagent finding (HIGH, confidence 9/10).

When consumers used the new DI flow services.AddOpcUa().AddClient(...),
the channel took the IHttpClientFactory branch and got back a named
HttpClient configured purely with AddStandardResilienceHandler() — and
the underlying HttpClientHandler was NOT exposed for HttpsTransportChannel
to attach:
  - ServerCertificateCustomValidationCallback wired against the OPC UA
    CertificateValidator (so the OPC UA trust list was dropped — falling
    back to the OS trust chain only)
  - The OPC UA application instance client certificate (so OPC UA mTLS
    was silently disabled)
  - AllowAutoRedirect = false (HTTPS redirects were now followed)
  - MaxConnectionsPerServer / MaxRequestContentBufferSize quotas (no
    longer enforced at the HTTP layer)

A server presenting a publicly-trusted CA-issued cert (CA misissuance,
domain takeover, compromised CA) would be accepted while the OPC UA
trust list — the proper authority for OPC UA — was ignored.

Fix:
- CanUseHttpClientFactory() now refuses the factory path whenever the
  channel quotas carry a CertificateValidator (i.e. whenever OPC UA
  server-cert validation is required), unconditionally routing to
  CreateDirectHttpClient() which wires the OPC UA server-cert callback
  and the OPC UA mTLS client cert.
- CreateHttpClient() emits a one-time LogWarning when a non-Shared
  factory was supplied but bypassed for security reasons, so operators
  see that the named HttpClient pipeline (e.g. Polly resilience handler)
  is NOT applied to this OPC UA HTTPS channel.
- DefaultOpcUaHttpClientFactory.Shared continues to take the direct
  path as before (no behavior change for non-DI consumers).

Verified locally:
- Stack/Opc.Ua.Core builds clean on net48 and net10.0 (0 W, 0 E)
- Libraries/Opc.Ua.Client builds clean on net10.0 (0 W, 0 E)
- OpcUaHttpClientFactoryTests on net8.0: 4/4 pass
- Https | Transport | ClientChannelManager filter on net8.0: 112/112 pass
2026-06-11 09:53:51 +02:00
..