alexrainman / ModernHttpClient

ModernHttpClient
MIT License
126 stars 27 forks source link

Android "No Peer Certificate" Crash #83

Open orwo1 opened 1 year ago

orwo1 commented 1 year ago

We got a couple of crashes from users in production over this: Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod(Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method) in <d7f9dfbcb6c04d738e1dd7808896c4c4> Android.Runtime.JNIEnv.CallObjectMethod(System.IntPtr jobject, System.IntPtr jmethod) in <0cf0053216ec42658b97ca5f8f06cb4f> Javax.Net.Ssl.ISSLSessionInvoker.GetPeerCertificateChain() in <0cf0053216ec42658b97ca5f8f06cb4f> ModernHttpClient.HostnameVerifier.Verify(System.String hostname, Javax.Net.Ssl.ISSLSession session) in <94c8f607f91b4ba1bc884851faba684e> Javax.Net.Ssl.IHostnameVerifierInvoker.n_Verify_Ljava_lang_String_Ljavax_net_ssl_SSLSession_(System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_hostname, System.IntPtr native_session) in <0cf0053216ec42658b97ca5f8f06cb4f> (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.122(intptr,intptr,intptr,intptr) --- End of managed Java.IO.IOException stack trace --- javax.net.ssl.SSLPeerUnverifiedException: No peer certificate com.android.org.conscrypt.SSLNullSession.getPeerCertificateChain in SSLNullSession.java:120 com.android.org.conscrypt.ExternalSession.getPeerCertificateChain in ExternalSession.java:121 com.android.org.conscrypt.Java7ExtendedSSLSession.getPeerCertificateChain in Java7ExtendedSSLSession.java:143 crc646acbd0515738a876.HostnameVerifier.n_verify(Native Method) crc646acbd0515738a876.HostnameVerifier.verify in HostnameVerifier.java:30 okhttp3.internal.connection.RealConnection.connectTls in RealConnection.java:326 okhttp3.internal.connection.RealConnection.establishProtocol in RealConnection.java:284 okhttp3.internal.connection.RealConnection.connect in RealConnection.java:169 okhttp3.internal.connection.StreamAllocation.findConnection in StreamAllocation.java:258 okhttp3.internal.connection.StreamAllocation.findHealthyConnection in StreamAllocation.java:135 okhttp3.internal.connection.StreamAllocation.newStream in StreamAllocation.java:114 okhttp3.internal.connection.ConnectInterceptor.intercept in ConnectInterceptor.java:42 okhttp3.internal.http.RealInterceptorChain.proceed in RealInterceptorChain.java:147 okhttp3.internal.http.RealInterceptorChain.proceed in RealInterceptorChain.java:121 okhttp3.internal.cache.CacheInterceptor.intercept in CacheInterceptor.java:93 okhttp3.internal.http.RealInterceptorChain.proceed in RealInterceptorChain.java:147 okhttp3.internal.http.RealInterceptorChain.proceed in RealInterceptorChain.java:121 okhttp3.internal.http.BridgeInterceptor.intercept in BridgeInterceptor.java:93 okhttp3.internal.http.RealInterceptorChain.proceed in RealInterceptorChain.java:147 okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept in RetryAndFollowUpInterceptor.java:127 okhttp3.internal.http.RealInterceptorChain.proceed in RealInterceptorChain.java:147 okhttp3.internal.http.RealInterceptorChain.proceed in RealInterceptorChain.java:121 okhttp3.RealCall.getResponseWithInterceptorChain in RealCall.java:257 okhttp3.RealCall$AsyncCall.execute in RealCall.java:201 okhttp3.internal.NamedRunnable.run in NamedRunnable.java:32 java.util.concurrent.ThreadPoolExecutor.processTask in ThreadPoolExecutor.java:1187 java.util.concurrent.ThreadPoolExecutor.runWorker in ThreadPoolExecutor.java:1152 java.util.concurrent.ThreadPoolExecutor$Worker.run in ThreadPoolExecutor.java:641 java.lang.Thread.run in Thread.java:784 Across several version of Android OS, starting with 9 upwards. We cannot identify when this crash is happening exactly as we have no logs from that time that could point to specific in our code. We use Polly for several of our methods in order to reauthenticate against our servers. This for example is our Get method:

    `public async Task<WebResult<TResult>> GetAsync<TResult>(string url, Dictionary<string, string> args, string path, bool 
       reportError, bool logResult = true, CancellationToken token = default(CancellationToken))
    {
        var result = new WebResult<TResult>();
        string correlationId = string.Empty;

        try
        {
            if (args != null)
            {
                url += ArgsToString(args);
            }

            var httpResponse = await AuthenticationOnUnauthorizePolicy.ExecuteAsync(async () =>
            {
                correlationId = Guid.NewGuid().ToString();
                _logger.Info(log...);

                using (var client = new HttpClient(new NativeMessageHandler()) { Timeout = new TimeSpan(0, 0, TimeOutSec) })
                {
                    UpdateClientHeader(client, correlationId);
                    WriteNetworkAccessStatusToLog();
                    return await client.GetAsync(url, token);
                }
            });

            var sReader = await httpResponse.Content.ReadAsStringAsync();
            await HandleRequest(result, sReader, httpResponse, correlationId, url, path, logResult);
        }
        catch (Exception ex)
        {
            if (token.IsCancellationRequested)
            {
                return null;
            }

            _logger.Error(InfraLogTags.HttpTag, $"Error, correlationId: {correlationId}");
            HandleRequestException(result, ex, url, correlationId);
        }

        return result;
    }`

Could you please investigate this issue?

AlonRom commented 1 year ago

@alexrainman will this be fixed in the new version as well?

AlonRom commented 1 year ago

@alexrainman ?