Search code examples
c#.net-corecertificateasp.net-core-webapiclient-certificates

Fail to send/receive Client Certificate from Console App to web api


I created a Web Api to accept a client certificate.
I am calling the web api from a console app using the following code.

var uri = new Uri("https://myservice.azurewebsites.net/api/values");

var handler = new WebRequestHandler();

handler.ClientCertificateOptions = ClientCertificateOption.Manual;
var certResults = new X509Store(StoreLocation.LocalMachine);
var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);

try
{
    certStore.Open(OpenFlags.ReadOnly);
}
catch (Exception)
{
    Console.WriteLine("Unable to access Certificate store");
}

var thumbprint = "<<self signed cert thumbprint>>";
var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
certStore.Close();

HttpClient client = new HttpClient(handler);
if (certCollection.Count > 0)
{
    handler.ClientCertificates.Add(certCollection[0]);
    client.DefaultRequestHeaders.Add("Thumbprint", certCollection[0].Thumbprint);
}

var result = client.GetAsync(uri).GetAwaiter().GetResult();

Console.WriteLine($"status: {result.StatusCode}");    
Console.WriteLine($"content: {result.Content.ReadAsStringAsync().GetAwaiter().GetResult()}");    
Console.ReadLine();
}

On the server side, I added a middleware to get the certificate details.

{
    //var certHeader = context.Request.Headers["X-ARR-ClientCert"];

    var certificate = context.Connection.ClientCertificate;
    if (certificate != null)
    {
        try
        {
            //var clientCertBytes = Convert.FromBase64String(certHeader);
            //var certificate = new X509Certificate2(clientCertBytes);

            bool isValidCert = IsValidClientCertificate(certificate);
            if (isValidCert)
            {
                await _next.Invoke(context);
            }
            else
            {
                _logger.LogError("Certificate is not valid");
                context.Response.StatusCode = 403;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message, ex);
            await context.Response.WriteAsync(ex.Message);
            context.Response.StatusCode = 403;
        }
    }
    else
    {
        _logger.LogError("X-ARR-ClientCert header is missing");
        context.Response.StatusCode = 403;
    }
}

I tried running it on the local machine and on Azure App Services. I set the flag clientCertEnabled to true in resources.azure.com. Web Api is SSL enabled.

But the certificate is always coming as null in both
var certHeader = context.Request.Headers["X-ARR-ClientCert"]; and var certificate = context.Connection.ClientCertificate;.

What am I doing wrong here?

Thanks in advance.


Solution

  • Was reasearching some of this stuff myself and seeing your question, I wonder if you are having one of the issues described in the link Securing ASP.NET WebAPI using Client Certificates

    Specifically:

    4 Add MyPersonalCA.cer to Local Machine -> Truted Root Certificate Authorities. This is key, espcially while you are developing and want to try things. If you don’t do it, Request.ClientCertificate won’t be populated because the cert chain is untrusted.