31

i am looking to get the data from any given domain names SSL certificate. For example I want to put in any website address e.g. "http://stackoverflow.com" and my code would firstly check if an SSL certificate exists. If it does then I want it to pull out the expiry date of the certificate. [ i am reading Domainnames from DB ] Example :http://www.digicert.com/help/

i need to create a web service to check expiry date. how can i implement it?? - I have looked up loads of different things such as RequestCertificateValidationCallback and ClientCertificates etc.

I could be completely wrong (hence why I need help) but would I create a HTTPWebRequest and then somehow request the client certificate and specific elements that way?

i tried the example provided @SSL certificate pre-fetch .NET , but i am getting forbitten 403 error.

johnnyRose
  • 7,310
  • 17
  • 40
  • 61
user166013
  • 1,411
  • 4
  • 21
  • 37
  • please use details in this links as you want http://stackoverflow.com/questions/1534908/transfer-files-over-ftps-ssl-tls-using-c-net?answertab=active#tab-top http://www.codeproject.com/Articles/31624/An-FTP-secure-client-library-for-C these links deals with ftp... but I got use them to as I want to get details about certificates. Try to use them to httprequest. – cdev Mar 07 '13 at 12:19
  • i tried using httprequest but i am getting 403 forbidden error – user166013 Mar 11 '13 at 09:38
  • I have added an answer. Please check it and let me know its helpful to you. – cdev Mar 11 '13 at 16:42

4 Answers4

42

For this to work your project will need a reference to System.Security:

using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

// Do webrequest to get info on secure site
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://mail.google.com");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();

// retrieve the ssl cert and assign it to an X509Certificate object
X509Certificate cert = request.ServicePoint.Certificate;

// convert the X509Certificate to an X509Certificate2 object by passing it into the constructor
X509Certificate2 cert2 = new X509Certificate2(cert);

string cn = cert2.GetIssuerName();
string cedate = cert2.GetExpirationDateString();
string cpub = cert2.GetPublicKeyString();

// display the cert dialog box
X509Certificate2UI.DisplayCertificate(cert2);

.NET Core 2.1 - .NET 5

You can use HttpClientHandler and ServerCertificateCustomValidationCallback Property. (This class is available in .net 4.7.1 and above also).

var handler = new HttpClientHandler
{
     UseDefaultCredentials = true,

     ServerCertificateCustomValidationCallback = (sender, cert, chain, error) =>
     {

          // Access cert object.

          return true;
     }
 };

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

          }
      }
 }
Aage
  • 5,932
  • 2
  • 32
  • 57
cdev
  • 5,043
  • 2
  • 33
  • 32
16

@cdev's solution didn't work for me on .NET Core 2.1. It seems HttpWebRequest is not completely supported on .NET Core.

Here is the function I'm using on .NET Core to get any server's X509 certificate:

// using System;
// using System.Net.Http;
// using System.Security.Cryptography.X509Certificates;
// using System.Threading.Tasks;

static async Task<X509Certificate2> GetServerCertificateAsync(string url)
{
    X509Certificate2 certificate = null;
    var httpClientHandler = new HttpClientHandler
    {
        ServerCertificateCustomValidationCallback = (_, cert, __, ___) =>
        {
            certificate = new X509Certificate2(cert.GetRawCertData());
            return true;
        }
    };

    var httpClient = new HttpClient(httpClientHandler);
    await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));

    return certificate ?? throw new NullReferenceException();
}
Hafiz
  • 4,921
  • 3
  • 19
  • 28
Poulad
  • 1,149
  • 1
  • 12
  • 22
  • 4
    For .NET 3.1, this did not work for me to grab the cert at the end; I had to change `certificate = cert` into `certificate = new X509Certificate2(cert.GetRawCertData())` – codeMonkey Apr 10 '20 at 17:28
  • @codeMonkey you are amazing. This was the solution I wanted and it didn't work initially and then you posted this! thanks, I would prefer this as the accepted solution – Hafiz Apr 10 '20 at 17:33
  • No, YOU'RE amazing @Hafiz! ❤ – codeMonkey Apr 10 '20 at 18:27
  • 1
    this was also the solution that worked for me in .net core 5 – WtFudgE Dec 18 '20 at 07:55
  • Some websites do not accept HttpMethod.Head. You could use HttpMethod.Get instead, but it will be slightly slower. – r3verse Aug 09 '21 at 11:13
  • When you provide the URL make sure it is an https:// address (NOTICE the S). – FlyingV Aug 16 '21 at 18:53
6

One thing to note is that you might need to set request.AllowAutoRedirect = False. Otherwise, if the server redirects HTTPS to HTTP, you won't be able to get the certificate from the HttpWebRequest object.

user60177
  • 61
  • 1
  • 2
1

Recreating the HttpClient each time you want to make a request is very ineffective and may cause performance issues. Better to create a single readonly client for all the methods. More informations can be found here.

private readonly HttpClientHandler _handler;
private readonly HttpClient _client;

And this is my solution to getting certificate info:

Code inside constructor:

 _handler = new HttpClientHandler {
    ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
    {
        sender.Properties.Add("Valid", sslPolicyErrors == System.Net.Security.SslPolicyErrors.None);
        sender.Properties.Add("Errors", sslPolicyErrors);
        return true;
    }
 };
 _client = new HttpClient(_handler);

Then you can read all the variables by:

using var request = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com/");
var response = await _client.SendAsync(request);
var isCertificateValid = (bool)request.Properties["Valid"];
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77