¿Cómo conectar el cliente Grpc (NuGet> 2.33) (.NET Framework) con el servidor Grpc.Asp.NetCore (NuGet> 2.31) (.NET 5.0) usando HTTPS y mi propio certificado?

Nov 29 2020

Mensaje de excepción:

Grpc.Core.RpcException: 'Estado (StatusCode = "No disponible", Detail = "no se pudo conectar a todas las direcciones", DebugException = "Grpc.Core.Internal.CoreErrorDetailException: {" creado ":" @ 1606657072.668000000 "," descripción " : "No se pudo seleccionar el subcanal", "archivo": "T: \ src \ github \ grpc \ workspace_csharp_ext_windows_x86 \ src \ core \ ext \ filtros \ client_channel \ client_channel.cc", "file_line": 4166, "referenced_errors": [ {"created": "@ 1606657072.668000000", "description": "no se pudo conectar a todas las direcciones", "file": "T: \ src \ github \ grpc \ workspace_csharp_ext_windows_x86 \ src \ core \ ext \ filters \ client_channel \ lb_policy \ pick_first \ pick_first.cc "," file_line ": 398," grpc_status ": 14}]}") '

Creé un ejemplo en GitHub con el que puedes modificar, jugar y responder esta pregunta fácilmente si logras resolver el problema.

grpc_certifier_example

...

Descubrí que el problema está en mis propios certificados y no puedo crear los míos propios que funcionen, probé numerosas combinaciones.

He usado este ejemplo para generar mis certificados: ¿Cómo habilitar SSL del lado del servidor para gRPC?

y lo probé en este ejemplo: https://github.com/angelagyang/GRPCProtobufExample

Respuestas

1 HrvojeBatrnek Dec 01 2020 at 14:32

El problema está en el certificado y su CN =. CN =% COMPUTERNAME% debe ser servidor DNS o IP, en mi caso tenía que ser localhost y el servidor necesita tener un certificado con la clave (pfx). El principal problema es que lanza la excepción sin una explicación relevante.

Cliente:

                //THIS IS YOUR CLIENT'S CERTIFICATE AND IT'S KEY
                var keyCertPair = new KeyCertificatePair(File.ReadAllText($"{rootDir}/samplecert.pem.txt"), File.ReadAllText($"{rootDir}/samplecert.key.txt"));
                //GetRootCertificates() GETS THE CA CERTIFICATE, NOT THE CLIENT CERTIFICATE NOR SERVER CERTIFICATE
                var channelCreds = new SslCredentials(GetRootCertificates(), keyCertPair);
                //YOU DON'T EVEN NEED TO PROVIDE KeyCertificatePair, IT WORKS WITH JUST A CA ROOT
                var channelCreds = new SslCredentials(GetRootCertificates());

Servidor:

                //LoadSSLCertificate() GETS THE SERVER CERTIFICATE
                var sslCertificate = LoadSSLCertificate(); 
                o.ListenAnyIP(5001, listenOptions =>
                {
                    listenOptions.UseHttps(sslCertificate, httpsOptions =>
                    {
                        httpsOptions.SslProtocols = SslProtocols.Tls12;
                        httpsOptions.ClientCertificateMode = ClientCertificateMode.NoCertificate;
                        httpsOptions.ClientCertificateValidation = (certificate, chain, errors) =>
                        {
                            return true;
                            //return certificate.Thumbprint.Equals(_clientThumbprint, StringComparison.OrdinalIgnoreCase);
                        };
                    });
                });

Creación de certificados:

@echo off
REM set OPENSSL_CONF=c:\OpenSSL-Win64\bin\openssl.cfg   

echo Generate CA key:
openssl genrsa -passout pass:1111 -des3 -out ca.key 4096

echo Generate CA certificate:
openssl req -passin pass:1111 -new -x509 -days 365 -key ca.key -out ca.crt -subj  "/C=US/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=MyRootCA"

echo Generate server key:
openssl genrsa -passout pass:1111 -des3 -out server.key 4096

echo Generate server signing request:
openssl req -passin pass:1111 -new -key server.key -out server.csr -subj  "/C=US/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=%COMPUTERNAME%"

echo Self-sign server certificate:
openssl x509 -req -passin pass:1111 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

echo Remove passphrase from server key:
openssl rsa -passin pass:1111 -in server.key -out server.key

echo Generate client key
openssl genrsa -passout pass:1111 -des3 -out client.key 4096

echo Generate client signing request:
openssl req -passin pass:1111 -new -key client.key -out client.csr -subj  "/C=US/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=%CLIENT-COMPUTERNAME%"

echo Self-sign client certificate:
openssl x509 -passin pass:1111 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

echo Remove passphrase from client key:
openssl rsa -passin pass:1111 -in client.key -out client.key

echo Create server.pfx file:
openssl pkcs12 -export -passout pass:1111 -out server.pfx -inkey server.key -in server.crt