Skip to content

Commit 6667772

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

1 file changed

Lines changed: 29 additions & 9 deletions

File tree

‎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
usingSystem.Net.Security;
66
usingSystem.Security.Cryptography.X509Certificates;
77

8+
usingAndroid.OS;
9+
usingAndroid.Runtime;
810
usingJavax.Net.Ssl;
911

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

2628
publicITrustManager[]ReplaceX509TrustManager(ITrustManager[]?trustManagers,HttpRequestMessagerequestMessage)
2729
{
28-
varoriginalX509TrustManager=FindX509TrustManager(trustManagers);
30+
varoriginalX509TrustManager=FindX509TrustManager(trustManagers,outintoriginalTrustManagerIndex);
2931
vartrustManagerWithCallback=newTrustManager(originalX509TrustManager,requestMessage,Callback);
30-
returnModifyTrustManagersArray(trustManagers,original:originalX509TrustManager,replacement:trustManagerWithCallback);
32+
returnModifyTrustManagersArray(trustManagers,originalTrustManagerIndex,trustManagerWithCallback);
3133
}
3234

3335
privatesealedclassTrustManager: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-
privatestaticIX509TrustManagerFindX509TrustManager(ITrustManager[]trustManagers)
166+
privatestaticIX509TrustManagerFindX509TrustManager(ITrustManager[]trustManagers,outintindex)
165167
{
166-
foreach(vartrustManagerintrustManagers){
167-
if(trustManagerisIX509TrustManagertm)
168-
returntm;
168+
for(inti=0;i<trustManagers.Length;i++){
169+
vartrustManager=trustManagers[i];
170+
if(trustManagerisIX509TrustManagerx509TrustManager){
171+
index=i;
172+
returnx509TrustManager;
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+
intapiLevel=(int)Build.VERSION.SdkInt;
178+
if(apiLevel<=23){
179+
if(IsTrustManagerImpl(trustManager)){
180+
index=i;
181+
returntrustManager.JavaCast<IX509TrustManager>();
182+
}
183+
}
169184
}
170185

171186
thrownewInvalidOperationException($"Could not find {nameof(IX509TrustManager)} in {nameof(ITrustManager)} array.");
187+
188+
staticboolIsTrustManagerImpl(ITrustManagertrustManager)
189+
{
190+
varjavaClassName=JNIEnv.GetClassNameFromInstance(trustManager.Handle);
191+
returnjavaClassName.Equals("com/android/org/conscrypt/TrustManagerImpl",StringComparison.Ordinal);
192+
}
172193
}
173194

174-
privatestaticITrustManager[]ModifyTrustManagersArray(ITrustManager[]trustManagers,IX509TrustManageroriginal,IX509TrustManagerreplacement)
195+
privatestaticITrustManager[]ModifyTrustManagersArray(ITrustManager[]trustManagers,intoriginalTrustManagerIndex,IX509TrustManagerreplacement)
175196
{
176197
varmodifiedTrustManagersArray=newITrustManager[trustManagers.Length];
177198

178199
for(inti=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
returnmodifiedTrustManagersArray;

0 commit comments

Comments
 (0)