Archive

Archive for August, 2026

Fixing .NET SslException on Linux Container

.NET 8 / C# LINUX / OPENSSL GOOGLE CLOUD RUN
Fixing .NET SslException on Linux Container
Deployments: The ‘RequireEncryption’ Policy Pitfall
Author: DevOps & Software Architecture Engineering Category: Troubleshooting & Cloud Deployments

A common friction point when migrating .NET services from Windows development machines to Linux
container environments (such as Google Cloud Run, AWS Fargate, or Kubernetes) is subtle differences in
native TLS/SSL implementations. Code that executes perfectly on local Windows workstations can abruptly
fail in production container environments with mysterious cryptographic stack traces.
This technical note breaks down a classic Windows vs. Linux SSL interop failure in .NET and presents the
resolution.

  1. The Symptom
    Consider a standard scenario: A .NET application makes outbound HTTPS requests using HttpClient or
    SocketsHttpHandler . During local testing on Windows, all HTTP operations complete cleanly. However, as
    soon as the service is deployed to a Linux container environment, all outbound HTTPS calls fail with an
    HttpRequestException wrapping an underlying SslException .
    The application logs reveal an error trace similar to the following:

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner
exception.
—> System.Security.Authentication.AuthenticationException: Authentication failed, see inner
exception.
—> Interop+OpenSsl+SslException: The ‘RequireEncryption’ encryption policy is not supported
by this installation of OpenSSL.
at Interop.OpenSsl.CalculateEffectiveProtocols(SslAuthenticationOptions
sslAuthenticationOptions)
at Interop.OpenSsl.GetOrCreateSslContextHandle(SslAuthenticationOptions
sslAuthenticationOptions, Boolean allowCached)
at Interop.OpenSsl.AllocateSslHandle(SslAuthenticationOptions sslAuthenticationOptions)
at System.Net.Security.SslStreamPal.HandshakeInternal(SafeDeleteSslContext& context,
ReadOnlySpan`1 inputBuffer, Int32& consumed, SslAuthenticationOptions
sslAuthenticationOptions)

Despite the exception mentioning RequireEncryption , the connection attempt aborts before any HTTP
traffic or TLS handshaking can take place.
2. The Root Cause
.NET relies on operating system abstraction layers for network security:

DevOps & .NET Engineering Engineering Notes Page 1 of 3

Platform Underlying Security Layer Encryption Policy Handling
Windows SChannel (Schannel.dll)

Natively supports granular policy enforcement including
EncryptionPolicy.RequireEncryption via OS APIs.

Linux

OpenSSL ( libssl /
Interop.OpenSsl )

Relies on OpenSSL’s native cipher suite negotiation. Does
not support mapping .NET’s legacy OS-level policy flags
down to OpenSSL constructs.
In .NET, SslClientAuthenticationOptions.EncryptionPolicy defaults to
EncryptionPolicy.RequireEncryption . When running on Windows, SChannel handles this flag natively.
When executing on Linux, .NET routes TLS setup through Interop.OpenSsl . Upon inspecting the policy,
the Linux interop layer explicitly throws an exception because OpenSSL cannot bind .NET’s policy enum
directly to an OpenSSL context flag.
3. The Solution
To resolve this issue without altering container base images or lowering system-wide security configurations,
explicitly set the EncryptionPolicy property inside your SslClientAuthenticationOptions to
EncryptionPolicy.AllowNoEncryption .

Myth vs. Reality: Setting EncryptionPolicy.AllowNoEncryption does NOT disable TLS encryption or
allow unencrypted plain text. Instead, it instructs .NET’s interop layer to pass cipher negotiation directly to
OpenSSL’s internal engine rather than attempting Windows-style pre-flight policy validation.
Updated Code Example
Modify your SocketsHttpHandler or SslStream configuration as follows:

var handler = new SocketsHttpHandler
{
AutomaticDecompression = DecompressionMethods.All,
SslOptions = new SslClientAuthenticationOptions
{
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13,
// Bypasses .NET OpenSSL interop check on Linux while maintaining full TLS encryption
EncryptionPolicy = EncryptionPolicy.AllowNoEncryption
}
};
using var client = new HttpClient(handler);

  1. Deployment Notes for Serverless & Containers
    No Dockerfile modifications required: If you use Buildpack-based continuous deployment (e.g.,
    gcloud run deploy directly from source code), this code-level fix is sufficient. Rebuilding and
    redeploying the application source solves the problem immediately.

DevOps & .NET Engineering Engineering Notes Page 2 of 3

Cross-Platform Consistency: EncryptionPolicy.AllowNoEncryption works identically across both
Windows (SChannel) and Linux (OpenSSL) environments, making your codebase cross-platform
compliant.

Document generated for technical reference & troubleshooting archive.

Introducing Two-Way Plate ⇄ VIN Lookup for the Netherlands

We’re excited to announce a new addition to our Netherlands vehicle data coverage: two-way lookup between number plate and VIN.

The Problem with One-Directional Lookups

Until now, Dutch vehicle data access has been built around the number plate (kenteken) as the primary key. That works well when you already have a plate — but it falls short in situations where a VIN is the only identifier you have. Import/export workflows, insurance and claims processing, VIN decoding pipelines, and international vehicle history checks all commonly start from a VIN, not a plate.

What’s New

We’ve added lookup in both directions for the Netherlands:

  • Plate → VIN — resolve a Dutch kenteken to its VIN and full vehicle record
  • VIN → Plate — go straight from a 17-character VIN to the matching plate and full vehicle record, no plate required as a starting point

Whichever identifier you have on hand, you can resolve the other.

A successful lookup returns:

  • Plate number — the matching Dutch kenteken
  • Category — vehicle type classification (e.g. passenger car), including a reference image
  • Brand — manufacturer name and logo
  • Model — model name and photo
  • Type/variant detail — trim designation, production date range, engine/motor code, power output (kW and pk), and fuel type

In short: you can now resolve a bare VIN into a fully classified vehicle — make, model, trim, engine, and power output — in a single call.

Why This Matters

For platforms working with vehicle history, KYC-adjacent verification, parts lookup, or insurance underwriting, having lookup available in both directions closes a real gap — you’re no longer stuck if the identifier you’re given isn’t the one your existing pipeline expects. It also opens the door to richer downstream enrichment: once you have the plate, deeper RDW-equivalent detail becomes accessible too.

Access

This capability is currently being rolled out to strategic partners. If you’d like access, get in touch via kentekenapi.com and we’ll get you set up.