Securing GRPC connections with server.key and server.crt using protobuf-net grpc

255 Views Asked by At

I'm trying to make secure grpc calls from the client side but I can't seem to get my code to work; here are the steps and implementations I've taken.

My specs: I'm running visual studio on mac m1 pro and I'm using Protobuf-net Grpc

Step 1 - Install OpenSSL

brew install openssl

Step 2 - Create a certificate and key

openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes

this asked a couple of questions. and then created the crt and key files.

I've also confirmed that certificate and key pair are created correctly by running the below commands.

openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5

Implementations

Server:

Program.cs file

var builder = WebApplication.CreateBuilder(args);

X509Certificate2 cert = new X509Certificate2("/Users/asimgunduz/server.crt", "/Users/asimgunduz/server.key");

builder.WebHost.ConfigureKestrel(opt =>
{
    opt.Listen(IPAddress.Any, 5010, listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http1;
        listenOptions.UseHttps(cert);
    });

});

Client Side

 public static void RegisterGrpcService<TService>(this IServiceCollection Services) where TService : class
    {
        X509Certificate2 certificate = new X509Certificate2("/Users/asimgunduz/server.crt", "/Users/asimgunduz/server.key");

        var socketsHandler = new SocketsHttpHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
            PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
            KeepAlivePingDelay = TimeSpan.FromSeconds(60),
            KeepAlivePingTimeout = TimeSpan.FromSeconds(30),
            EnableMultipleHttp2Connections = true,
        };

        socketsHandler.SslOptions.RemoteCertificateValidationCallback = (message, cert, chain, errors) =>
        {
            // Perform custom validation here and return a boolean indicating whether the certificate is valid
            return certificate.Equals(cert);
        };

        var hand = new GrpcWebHandler(GrpcWebMode.GrpcWeb, socketsHandler);
       
        //hand.HttpVersion = HttpVersion.Version11;

        Services.AddCodeFirstGrpcClient<TService>(x =>
        {
            x.ChannelOptionsActions.Add(x => new GrpcChannelOptions
            {
                HttpHandler = hand,

                MaxReceiveMessageSize = null, //30000000
                MaxSendMessageSize = null, //30000000
                Credentials = ChannelCredentials.Insecure,
                UnsafeUseInsecureChannelCallCredentials = true,
                ServiceConfig = new ServiceConfig { LoadBalancingConfigs = { new RoundRobinConfig() } }
            });

            x.Address = new Uri("http://localhost:5010");

        })
       .ConfigurePrimaryHttpMessageHandler(x => hand);
    }

    

    public static void RegisterGrpcServiceWithSsl2<TService>(this IServiceCollection services, string address) where TService : class
    {
        X509Certificate2 certificate = new X509Certificate2("/Users/asimgunduz/server.crt", "/Users/asimgunduz/server.key");

        var handler = new SocketsHttpHandler
        {
            SslOptions = new SslClientAuthenticationOptions
            {
                RemoteCertificateValidationCallback = (sender, cert, chain, errors) =>
                {
                    X509Chain x509Chain = new X509Chain();
                    x509Chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                    bool isChainValid = x509Chain.Build(new X509Certificate2(cert));
                    return isChainValid;
                },
                ClientCertificates = new X509Certificate2Collection { certificate }
            },
            PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
            KeepAlivePingDelay = TimeSpan.FromSeconds(60),
            KeepAlivePingTimeout = TimeSpan.FromSeconds(30),
            EnableMultipleHttp2Connections = true
        };

        var channel = GrpcChannel.ForAddress(address, new GrpcChannelOptions
        {
            HttpHandler = handler,
        });

        services.AddCodeFirstGrpcClient<TService>(x =>
        {
            x.Address = new Uri(address);
            x.ChannelOptionsActions.Add(options =>
            {
                options.HttpHandler = handler;
            });
        });
    }

When I run Server it throws the following exception

"The server mode SSL must use a certificate with the associated private key."

any help is much appreciated.

1

There are 1 best solutions below

0
On

Aright after an hour of hard work, I've managed to make my code work: just leaving here in case future me or someone else needs it..

Changes made in my code

(SERVER) program.cs I've changed port number from 5010 => 7178

//Created certificate with the below method
var certificate =
  X509Certificate2.CreateFromPemFile("/Users/asimgunduz/server.crt", Path.ChangeExtension("/Users/asimgunduz/server.crt", "key"));

//Verify is blueprints match
var verf = certificate.Verify();

//and finally add usehttps(with the created certificate)

builder.WebHost.ConfigureKestrel(opt =>
{
    opt.ListenLocalhost(7178, o =>
    {
        o.Protocols = HttpProtocols.Http1;
        o.UseHttps(certificate);
    });

});

and this is How I updated my extension methods in client side

        public static void RegisterGrpcServiceWithSsl2<TService>(this IServiceCollection services, string address) where TService : class
    {

        var certificate =
          X509Certificate2.CreateFromPemFile("/Users/asimgunduz/server.crt", Path.ChangeExtension("/Users/asimgunduz/server.crt", "key"));

        var socketsHandler = new SocketsHttpHandler
        {
            SslOptions = new SslClientAuthenticationOptions
            {
                RemoteCertificateValidationCallback = (sender, cert, chain, errors) =>
                {
                    X509Chain x509Chain = new X509Chain();
                    x509Chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                    bool isChainValid = x509Chain.Build(new X509Certificate2(cert));
                    return isChainValid;
                },
                ClientCertificates = new X509Certificate2Collection { certificate }
            },
            PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
            KeepAlivePingDelay = TimeSpan.FromSeconds(60),
            KeepAlivePingTimeout = TimeSpan.FromSeconds(30),
            EnableMultipleHttp2Connections = true
        };


        var hand = new GrpcWebHandler(GrpcWebMode.GrpcWeb, socketsHandler);

        hand.HttpVersion = HttpVersion.Version11;

        services.AddCodeFirstGrpcClient<TService>(x =>
        {
            x.ChannelOptionsActions.Add(x => new GrpcChannelOptions
            {
                HttpHandler = hand,

                MaxReceiveMessageSize = null, 
                MaxSendMessageSize = null, 
                Credentials = ChannelCredentials.Insecure,
                UnsafeUseInsecureChannelCallCredentials = true,
                ServiceConfig = new ServiceConfig { LoadBalancingConfigs = { new RoundRobinConfig() } }
            });

            x.Address = new Uri(address);

        })
       .ConfigurePrimaryHttpMessageHandler(x => hand);

        
    }