Why does SSL connection to grpc server fail if the client is not running as admin and using client certificates?

Stephen Richardson 41 Reputation points
2023-11-29T11:32:31.86+00:00

I have a grpc server hosted in a Windows Service based on the grpc sample Greeter.

Server Code:

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseWindowsService(options =>
{
    options.ServiceName = "WindowsGreeter8";
});

builder.WebHost.ConfigureKestrel(kestrel =>
{
    kestrel.Listen(IPAddress.Any, 7042, listenOptions =>
    {
        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        store.Open(OpenFlags.OpenExistingOnly);

        X509Certificate2Collection cers = store.Certificates.Find(X509FindType.FindByIssuerName, "acme.com", false);
        X509Certificate2Collection serverCers = store.Certificates.Find(X509FindType.FindByIssuerName, "localhost", false);
        
        if ((cers.Count > 0) && (serverCers.Count > 0))
        {
            listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;

            listenOptions.UseHttps(serverCers[0], options =>
            {
                options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
                options.ClientCertificateValidation = (certificate, chain, errors) => certificate.Issuer == cers[0].Issuer;

                options.SslProtocols = System.Security.Authentication.SslProtocols.Tls13 | System.Security.Authentication.SslProtocols.Tls12;
            });
        }
    });
});

// Add services to the container.
builder.Services.AddGrpc();

var app = builder.Build();

// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");

app.Run();

The server requires the client to have a specific certificate.

Client code:

var handler = new HttpClientHandler();

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly);

X509Certificate2Collection cers = store.Certificates.Find(X509FindType.FindByIssuerName, "acme.com", false);

if (cers.Count > 0)
{
    Console.WriteLine("Found Certificate");
    handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls13 | System.Security.Authentication.SslProtocols.Tls12;
    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
    handler.ClientCertificates.Add(cers[0]);
    handler.UseProxy = false;
}

using var channel = GrpcChannel.ForAddress("https://localhost:7042", new GrpcChannelOptions()
{
    HttpHandler = handler,
    DisposeHttpClient = true
});

var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(
                  new HelloRequest { Name = "GreeterClient" });
Console.WriteLine("Greeting: " + reply.Message);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();

If the client is run as admin the grpc call works correctly.

User's image

However, if it is not run with admin rights the SSL connection fails with the exception: System.ComponentModel.Win32Exception (0x8009030D): The credentials supplied to the package were not recognized

Why doesn't this work?

See runtime output below.User's image

.NET
.NET
Microsoft Technologies based on the .NET software framework.
4,103 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,558 questions
{count} votes

Accepted answer
  1. Anonymous
    2023-11-30T02:47:18.4966667+00:00

    Hi @Stephen Richardson , Welcome to Microsoft Q&A, You said If the client is run as admin the grpc call works correctly.

    Make sure that the user running the Windows service has read access to the certificate private key. When you run the service as administrator it may have the necessary permissions, but as a normal user it may not.

    You can adjust the permissions of a certificate by doing the following:

    • Open the Certificate MMC snap-in (certmgr.msc).
    • Find your certificate in personal storage.
    • Right click on the certificate, go to "All Tasks" -> "Manage Private Keys".
    • Add the user running the service to the list and grant them at least read permissions.

    You are opening the certificate store in the LocalMachine store. Make sure that the certificates are in the LocalMachine store and not the CurrentUser store if you want the service to access them when running as a non-administrator.

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.