C# Download all https certificates from a website

2019-08-08 16:30发布

I want to save all certificates from a URL to disk. So for example https://www.google.de

If I browse this page with Firefox, I can see three certificates. enter image description here

With Firefox I can export them all, and save them to disk.

So I want to do that in C#. I started getting the certificates with the following code..

    /// <summary>
    /// Get and write certificate from URL into file in path
    /// </summary>
    /// <param name="_URL">URL of website with certficate</param>
    /// <param name="_path">Path where you want to store certificate</param>
    private static void SaveCertificate(String _URL, String _path)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_URL);
            request.AllowAutoRedirect = false;

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

            X509Certificate2 cert = new X509Certificate2(request.ServicePoint.Certificate);

            File.WriteAllText(_path, ExportToPEM(cert));
        }
        catch (Exception)
        {
        }
    }

    /// <summary>
    /// Export a certificate to a PEM format string
    /// </summary>
    /// <param name="_cert">The certificate to export</param>
    /// <returns>A PEM encoded string</returns>
    public static string ExportToPEM(X509Certificate2 _cert)
    {
        StringBuilder builder = new StringBuilder();

        try
        {
            builder.AppendLine("-----BEGIN CERTIFICATE-----");
            builder.AppendLine(Convert.ToBase64String(_cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
            builder.AppendLine("-----END CERTIFICATE-----");

        }
        catch (Exception)
        {
        }

        return builder.ToString();
    }

The problem with this code is, I just get one certificate exept three. (the certificate I get is the marked certificate in the screenshot from firefox)

I also tryed the solution from here SO Question but it didnt work for me.

My question is, how can I get all certificates from a URL?

1条回答
唯我独甜
2楼-- · 2019-08-08 17:10

One way you can get the certificate chain is by implementing a ServerCertificateValidationCallback on your request.

It's a function that accepts the parameters:

(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)

This is normally used to validate the certificate and chain, but in this case we're just using it to get access to the certificate chain. It does feel a lot like a hack but it should work. I've implemented an proof of concept based on your posted code. The code outputs the certs to the console window.

   public static void Main(string[] args)
    {
        SaveCertificate("https://www.google.de", "");
    }
    /// <summary>
    /// Get and write certificate from URL into file in path
    /// </summary>
    /// <param name="_URL">URL of website with certficate</param>
    /// <param name="_path">Path where you want to store certificate</param>
    private static void SaveCertificate(string url, string path)
    {

            var request = (HttpWebRequest)WebRequest.Create(url);
            request.AllowAutoRedirect = false;
            request.ServerCertificateValidationCallback = ServerCertificateValidationCallback;

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            response.Close();
            Console.ReadLine();

    }

    private static bool ServerCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        foreach (var cer in chain.ChainElements)
        {
            Console.WriteLine(cer.Certificate.FriendlyName);
            Console.WriteLine(ExportToPem(cer.Certificate));
        }

        return true;
    }

    /// <summary>
    /// Export a certificate to a PEM format string
    /// </summary>
    /// <param name="_cert">The certificate to export</param>
    /// <returns>A PEM encoded string</returns>
    public static string ExportToPem(X509Certificate2 cert)
    {
        StringBuilder builder = new StringBuilder();

        try
        {
            builder.AppendLine("-----BEGIN CERTIFICATE-----");
            builder.AppendLine(Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
            builder.AppendLine("-----END CERTIFICATE-----");

        }
        catch (Exception)
        {
        }

        return builder.ToString();
    }
查看更多
登录 后发表回答