Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inspect server certificate using HttpClient

I'm rewriting some web handling code in WinForms and switching from HttpWebRequest to HttpClient. There's one last thing I require that I cannot seem to find out how to accomplish.

In HttpWebRequest, I can capture the certificate from the web server I'm connecting to and display it:

...
HttpWebRequest request = CreateHttpRequest(destUri);

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

cert = request.ServicePoint.Certificate;

if (cert != null) 
{ 
  cert2 = new X509Certificate2(cert); 
  X509Certificate2UI.DisplayCertificate(cert2);
}
...

I cannot find the equivalent way capture the certificate using HttpClient:

//... Use HttpClient.
using (HttpClient client = new HttpClient())
{
  using (HttpResponseMessage response = await client.GetAsync(destUri))
  {
    using (HttpContent content = response.Content)
    {
      string result = await content.ReadAsStringAsync();
    }
  }
}

How/where can I do this here? I don't know how to get to the ServicePoint.Certificate.

like image 549
LordChariot Avatar asked Jul 14 '17 06:07

LordChariot


3 Answers

Apparently, you don't need to get the certificate from the ServicePointManager.ServerCertificateValidationCallback. You can find it from ServicepointManager itself, like so:

//... Use HttpClient.
using (HttpClient client = new HttpClient())
{
  using (HttpResponseMessage response = await client.GetAsync(destUri))
  {
    // Get Certificate Here
    var cert = ServicePointManager.FindServicePoint(destUri).Certificate;
    //
    using (HttpContent content = response.Content)
    {
      string result = await content.ReadAsStringAsync();
    }
  }
}
like image 161
LordChariot Avatar answered Oct 14 '22 22:10

LordChariot


Bulding on Remus answer - here is something I've cobbled up in LinqPad, which does give you access to your certificate:

var handler = new WebRequestHandler();
handler.UseDefaultCredentials = true;
handler.AllowPipelining = true;
handler.ServerCertificateValidationCallback =  (sender, cert, chain, error) => {
    //do something with cert here
    cert.Subject.Dump();
    //useless validation on my part
    return true;
};


using (HttpClient client = new HttpClient(handler))
{
  using (HttpResponseMessage response = await client.GetAsync("https://google.com"))
  {
    using (HttpContent content = response.Content)
    {
        //foo
    }
  }
}

Dump() the outputs the following:

CN=*.google.com, O=Google Inc, L=Mountain View, S=California, C=US

CN=www.google.de, O=Google Inc, L=Mountain View, S=California, C=US

CN=www.google.com, O=Google Inc, L=Mountain View, S=California, C=US

like image 44
Marco Avatar answered Oct 14 '22 23:10

Marco


Use a WebRequestHandler with a proper certificate validation callback. see HttpClient, HttpClientHandler, and WebRequestHandler Explained for example.

like image 37
Remus Rusanu Avatar answered Oct 14 '22 22:10

Remus Rusanu