TLS handshake failure on Android API < 21 with Xamarin.Android HttpClient
0 reputation · 20 May 2023, 03:25 UTC
0 reputation · 20 May 2023, 03:25 UTC
When a Xamarin.Android app uses HttpClient to connect to a TLS‑1.2‑only endpoint on devices running API 19 or 20, the request frequently fails with an SSL handshake exception. The failure occurs even though the OS kernel supports TLS 1.2, because the default AndroidClientHandler (wrapping java.net.HttpURLConnection) does not enable the protocol by default. The managed handler, which relies on ServicePointManager, also cannot guarantee TLS 1.2 usage on these API levels.
The goal is to determine a reliable configuration that guarantees a TLS 1.2 handshake without duplicating writes or relying on server‑side idempotency. Constraints include the handler selection logic, the version of Xamarin.Android, and the fact that ServicePointManager.SecurityProtocol only affects the managed handler.
Unresolved questions:
To reliably enforce TLS 1.2 on Android API 19 and 20, you must use the managed HttpClientHandler and explicitly set the security protocol before instantiating the client.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; before any HttpClient is created.HttpClient using a new HttpClientHandler (the managed implementation) rather than the AndroidClientHandler.The AndroidClientHandler wraps java.net.HttpURLConnection. While the Android OS kernel on API 19/20 supports TLS 1.2, the native Java implementation does not enable it by default. Because Xamarin.Android does not provide a supported API to inject a custom SSLContext into this handler, there is no official way to force TLS 1.2 while using the native handler.
The managed handler is a .NET implementation that respects the ServicePointManager.SecurityProtocol setting. On API 19/20, the .NET runtime utilizes the underlying OpenSSL library to negotiate TLS 1.2. This approach is reliable provided you are using Xamarin.Android SDK 9.0 or later.
using System.Net;
using System.Net.Http;
// Must be called before HttpClient is instantiated
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Explicitly use the managed handler
var handler = new HttpClientHandler();
var client = new HttpClient(handler);
// Request will now negotiate TLS 1.2
var response = await client.GetAsync("https://your-tls12-endpoint.com");
This solution assumes the use of Xamarin.Android SDK 9.0+. On older SDKs, SecurityProtocol settings may be ignored. To verify the fix:
Client Hello specifies TLS 1.2.If the handshake still fails after implementing the above, please confirm your Xamarin.Android SDK version. If you are on a version prior to 9.0, the managed handler may not correctly honor the SecurityProtocol setting on these specific API levels.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.