Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#, .Net Core Private key authentication httpClient

We are having a problem with a friend with loading a private certificate to httpHandler.
We are using .net core and need to host all aplication in the cloud.
Main goal is to get message from SQS and perform some specified API shots after with consumed data.
We have a problem with certificate with public / private key. We have tried I think all the possible ways of loading it.

    public async Task<HttpResponseMessage> VisitHttps()
    {
        // Proceed for an invalid cerficate
        ServicePointManager.ServerCertificateValidationCallback +=
        (sender, certificate, chain, sslPolicyErrors) => true;

        // Add the certificate
        var handler = new HttpClientHandler();
        var cert = GetMyCert();
        if (cert != null)
        {
            handler.ClientCertificates.Add(cert);
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
            //handler.PreAuthenticate = true;
        }
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;


        HttpClient cclient = new HttpClient(handler)
        {
            //BaseAddress = new Uri("https://someurl.com")

        };
        cclient.DefaultRequestHeaders.Accept.Clear();
        cclient.DefaultRequestHeaders.Accept.Add(new 

MediaTypeWithQualityHeaderValue("application/json"));
            return await cclient.GetAsync("https://some-url.com/ping"); }

And the method GetMyCert() looks like below:

string currentLocation = $"{AppDomain.CurrentDomain.BaseDirectory}key-public.crt";
                //var xcert = new X509Certificate2(currentLocation, "password");

                ////var currentLocationPriv = $"{AppDomain.CurrentDomain.BaseDirectory}key-private.crt";
                ////var privcert = new X509Certificate2(currentLocationPriv, "password", X509KeyStorageFlags.EphemeralKeySet);
                //var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                //certStore.Open(OpenFlags.ReadWrite);
                //certStore.Add(xcert);
                //certStore.Close();
            //return xcert;

            X509Store store = new X509Store("My", StoreLocation.CurrentUser);
            X509Certificate2 cert;
            cert = new X509Certificate2(File.ReadAllBytes(currentLocation), "password", X509KeyStorageFlags.MachineKeySet);
            bool result = cert.Verify();
            var r2 = result;
            return cert;

commented lines are variances of what we have tried to do.
We have no idea what else we should try to handle this issue.
Any guidelines would be more than welcome

EDIT:
I've tried registering this inside startup class but it seems not working anyway. I always got the private key field inside certificate empty. And hasPrivateKey marked as false.

 private void CreateCert(IServiceCollection services)
    {
        string currentLocation = $"{AppDomain.CurrentDomain.BaseDirectory}key-public.crt";
        var certificate = new X509Certificate2(currentLocation, "password");
        services.AddHttpClient("TestClient", client =>
        {
            client.BaseAddress = new Uri("https://someurl.com");
        })
        .ConfigurePrimaryHttpMessageHandler(() =>
            {
            var handler = new HttpClientHandler();
            handler.ClientCertificates.Add(certificate);
            return handler;
        });
    }  

My Test code:

        [Fact]
    public async Task ShouldPong()
    {
        var testClient = new TestClient()
        {
            BaseAddress = new Uri("https://someurl.com")
        };
        var result = await testClient.GetAsync("/ping");
        result.StatusCode.Should().Be(HttpStatusCode.OK);
    }

TestClient:

public class TestClient : HttpClient
{
    public TestClient()
        :base()
    {

    }

    public TestClient(HttpMessageHandler handler)
        : base(handler)
    {

    }
}  

EDIT:
The problem was solved when changing the .crt files into a .pfx file. Since the API we was hitting was hosted on nginx.

like image 382
Kacper Werema Avatar asked Jun 06 '19 14:06

Kacper Werema


1 Answers

The problem was resolved by creating a .PFX file. The server we were hitting was hosted on nginx that requires .pfx format. The .crt files are PEM certificate that was not valid for nginx.

like image 65
Kacper Werema Avatar answered Sep 27 '22 20:09

Kacper Werema