runtime: Exception of type 'Interop+AndroidCrypto+SslException' was thrown.

I want to connect to a gRPC service that is hosted in ASP Core application. All my projects are .NET 6.

In the client side, I have a a library that is the gRPC client, that receive the certificates of the client in a string format and then it creates the channel and the connection to the service. In this way, I can use this library in many clients, WPF, MAUI and so on.

When I use the WPF client, it works, I can connect with the remote server, but when I use the MAUI project, I get an error. Is this error:

Exception of type 'Interop+AndroidCrypto+SslException' was thrown.

{Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException: Authentication failed, see inner exception. SslException: Exception of type 'Interop+AndroidCrypto+SslException' was thrown.", DebugException="System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
 ---> Interop+AndroidCrypto+SslException: Exception of type 'Interop+AndroidCrypto+SslException' was thrown.
   --- End of inner exception stack trace ---
   at System.Net.Security.SslStream.<ForceAuthenticationAsync>d__175`1[[System.Net.Security.AsyncReadWriteAdapter, System.Net.Security, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]].MoveNext()
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.AddHttp2ConnectionAsync(HttpRequestMessage request)
   at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.<WaitWithCancellationAsync>d__1[[System.Net.Http.Http2Connection, System.Net.Http, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]].MoveNext()
   at System.Net.Http.HttpConnectionPool.GetHttp2ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   at Grpc.Net.Client.Internal.GrpcCall`2.<RunCall>d__73[[GestorOrdenadores.Service.Client.Grpc.HelloRequest, GestorOrdenadores.Service.Client.Grpc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[GestorOrdenadores.Service.Client.Grpc.HelloReply, GestorOrdenadores.Service.Client.Grpc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() in /_/src/Grpc.Net.Client/Internal/GrpcCall.cs:line 493")
   at GestorOrdenadores.Service.Client.Grpc.ServiceClientGrpc.SayHelloAsync(String paramNombre) in D:\desarrollo\proyectos\GestorOrdenadores\GestorOrdenadores.Service.Client.Grpc\ServiceClientGrpc.cs:line 71
   at GestorOrdenadores.Client.Maui.MainPage.OnBtnPingClicked(Object sender, EventArgs e) in D:\desarrollo\proyectos\GestorOrdenadores\GestorOrdenadores.Client.Maui\MainPage.xaml.cs:line 49}

The code of the library is this:

public class ServiceClientGrpc
    {
        #region constructores
        public ServiceClientGrpc(string paramDireccion, int paramPuerto, string paramCertificado, string paramKey)
        {
            var cert = X509Certificate2.CreateFromPem(paramCertificado, paramKey);

            paramDireccion = @"https://192.168.1.200";
            paramPuerto = 5001;


            HttpClientHandler miHttpHandler = new HttpClientHandler();
            miHttpHandler.ClientCertificates.Add(cert);
            HttpClient httpClient = new(miHttpHandler);

            miHttpHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

            var channel = GrpcChannel.ForAddress(paramDireccion + ":" + paramPuerto, new GrpcChannelOptions
            {
                HttpClient = httpClient
            });





            _client = new Greeter.GreeterClient(channel);
        }
        #endregion constructores


        private readonly Greeter.GreeterClient _client;



        public async Task<string> SayHelloAsync(string paramNombre)
        {
            HelloRequest miRequest = new HelloRequest()
            {
                Name = paramNombre
            };

            return (await _client.SayHelloAsync(miRequest)).Message;
        }
    }

The WPF client:

private async void BtnSaludar_Click(object sender, RoutedEventArgs e)
{
    try
    {
        string miStrCertificado = System.IO.File.ReadAllText(@"Certificados\Client.crt");
        string miStrClave = System.IO.File.ReadAllText(@"Certificados\Client.key");

        ServiceClientGrpc miService = new ServiceClientGrpc("https://192.168.1.200", 5001, miStrCertificado, miStrClave);


        MessageBox.Show(await miService.SayHelloAsync("Álvaro"));
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

The MAUI client:

private async void OnBtnSaludarClicked(object sender, EventArgs e)
{
    try
    {
        //Get address and port from XML file.
        string miStrDireccion = Configuracion.GestorConfiguracion.GetDireccionServicio();
        int miStrPuerto = Configuracion.GestorConfiguracion.GetPuertoServicio();

        //Get the certificates from Asserts files
        using Stream miStmCertificado = await FileSystem.OpenAppPackageFileAsync("certificados/client.crt");
        using StreamReader miSrCertificado = new StreamReader(miStmCertificado);
        string miStrCertificado = await miSrCertificado.ReadToEndAsync();

        using Stream miStmKey = await FileSystem.OpenAppPackageFileAsync("certificados/client.key");
        using StreamReader miSrKey = new StreamReader(miStmKey);
        string miStrKey = await miSrKey.ReadToEndAsync();


        ServiceClientGrpc miServicio = new ServiceClientGrpc(miStrDireccion, miStrPuerto, miStrCertificado, miStrKey);

        EtrRespuestaPing.Text = await miServicio.SayHelloAsync("Álvaro"); //Excetion in this line
    }
    catch(Exception ex)
    {
        await DisplayAlert("Alert", ex.Message, "OK");
    }
}

From the android device in which I am debugging the MAUI project, I can ping the server with an application that pings.

Really the code is the same in WPF and MAUI, just I instantiate an object of type ServiceClientGrpc, passing the same data. Is ServiceClientGrpc who creates the channel and call the service.

In the past, when I tried this with Xamarin, I read that there was limitations in Xamarin, but I though that now MAUI can use Net 6, I had hope that I could use the same library for all the clients.

Is it not possible to use the same library for windows clients and android clients?

Thanks.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 21 (14 by maintainers)

Most upvoted comments

Grpc.Core isn’t supported by Microsoft. It was created by the gRPC team. @ComptonAlvaro if you are using Grpc.Core then please ask questions for using it at grpc/grpc. No one at dotnet/runtime knows how it works.

Grpc.Net.Client currently doesn’t officially support MAUI+Android. Waiting on work in https://github.com/dotnet/runtime/issues/69095 before committing to supporting gRPC on Android.

In saying that, I’m pretty sure Grpc.Net.Client requires SocketsHttpHandler. That means either:

  • Creating SocketsHttpHandler directly
  • Or using HttpClientHandler + configuration to ensure it creates SocketsHttpHandler internally (I don’t know the config name off the top of my head).

When Android is supported, then I agree that gRPC+Android docs are required. There might also be the opportunity to detect at runtime that the current platform is Android and check that a valid handler is configured.