Skip to content

Commit 6667772

Browse files
simonrozsivaljonathanpeppers
authored andcommitted
Fix ServerCertificateCustomValidator on API 21-23 (#8637)
Follow-up to #8594 to fix dotnet/runtime#95506 on Android API 21-23
1 parent 940f059 commit 6667772

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

src/Mono.Android/Xamarin.Android.Net/ServerCertificateCustomValidator.cs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using System.Net.Security;
66
using System.Security.Cryptography.X509Certificates;
77

8+
using Android.OS;
9+
using Android.Runtime;
810
using Javax.Net.Ssl;
911

1012
using JavaCertificateException = Java.Security.Cert.CertificateException;
@@ -25,9 +27,9 @@ public ServerCertificateCustomValidator (Func<HttpRequestMessage, X509Certificat
2527

2628
public ITrustManager[] ReplaceX509TrustManager (ITrustManager[]? trustManagers, HttpRequestMessage requestMessage)
2729
{
28-
var originalX509TrustManager = FindX509TrustManager(trustManagers);
30+
var originalX509TrustManager = FindX509TrustManager(trustManagers, out int originalTrustManagerIndex);
2931
var trustManagerWithCallback = new TrustManager (originalX509TrustManager, requestMessage, Callback);
30-
return ModifyTrustManagersArray (trustManagers, original: originalX509TrustManager, replacement: trustManagerWithCallback);
32+
return ModifyTrustManagersArray (trustManagers, originalTrustManagerIndex, trustManagerWithCallback);
3133
}
3234

3335
private sealed class TrustManager : Java.Lang.Object, IX509TrustManager
@@ -161,27 +163,45 @@ private sealed class AlwaysAcceptingHostnameVerifier : Java.Lang.Object, IHostna
161163

162164
[DynamicDependency(nameof(IX509TrustManager.CheckServerTrusted), typeof(IX509TrustManagerInvoker))]
163165
[DynamicDependency(nameof(IX509TrustManager.CheckServerTrusted), typeof(X509ExtendedTrustManagerInvoker))]
164-
private static IX509TrustManager FindX509TrustManager(ITrustManager[] trustManagers)
166+
private static IX509TrustManager FindX509TrustManager(ITrustManager[] trustManagers, out int index)
165167
{
166-
foreach (var trustManager in trustManagers) {
167-
if (trustManager is IX509TrustManager tm)
168-
return tm;
168+
for (int i = 0; i < trustManagers.Length; i++) {
169+
var trustManager = trustManagers [i];
170+
if (trustManager is IX509TrustManager x509TrustManager) {
171+
index = i;
172+
return x509TrustManager;
173+
}
174+
175+
// On API 21-23, the default Java trust manager is TrustManagerImpl from Conscrypt. The class implements X509TrustManager
176+
// but the .NET pattern matching will fail in this case and we need to cast it explicitly.
177+
int apiLevel = (int)Build.VERSION.SdkInt;
178+
if (apiLevel <= 23) {
179+
if (IsTrustManagerImpl (trustManager)) {
180+
index = i;
181+
return trustManager.JavaCast<IX509TrustManager> ();
182+
}
183+
}
169184
}
170185

171186
throw new InvalidOperationException($"Could not find {nameof(IX509TrustManager)} in {nameof(ITrustManager)} array.");
187+
188+
static bool IsTrustManagerImpl (ITrustManager trustManager)
189+
{
190+
var javaClassName = JNIEnv.GetClassNameFromInstance (trustManager.Handle);
191+
return javaClassName.Equals ("com/android/org/conscrypt/TrustManagerImpl", StringComparison.Ordinal);
192+
}
172193
}
173194

174-
private static ITrustManager[] ModifyTrustManagersArray (ITrustManager[] trustManagers, IX509TrustManager original, IX509TrustManager replacement)
195+
private static ITrustManager[] ModifyTrustManagersArray (ITrustManager[] trustManagers, int originalTrustManagerIndex, IX509TrustManager replacement)
175196
{
176197
var modifiedTrustManagersArray = new ITrustManager [trustManagers.Length];
177198

178199
for (int i = 0; i < trustManagers.Length; i++) {
179-
if (trustManagers [i] == original) {
200+
if (i == originalTrustManagerIndex) {
180201
modifiedTrustManagersArray [i] = replacement;
181202
} else {
182203
modifiedTrustManagersArray [i] = trustManagers [i];
183204
}
184-
185205
}
186206

187207
return modifiedTrustManagersArray;

0 commit comments

Comments
 (0)