Search code examples
c#sslhttpwebrequestx509certificatex509

How do I use SSL certificates with HttpWebRequest in C#?


Currently I'm writing a utility application that will connect to a given IP and port and check the information in the SSL certificate using HttpWebRequest. When I try to extract the certificate I get an error that an exception was thrown. The exception seems to be because the act of coping the SSL certificate seems to trigger yet another validation check.

Here is the code, and maybe someone can either show me a better way to do this or if I am missing something. I don't care if the SSL Certificate is expired or doesn't match the URL. None of that is relevant for what I'm doing.

When I assign the X509Certificate in the delegate to a new variable, and look at the variable in the debugger, all the properties show SSLCert.Issuer threw an exception of type 'System.Security.Cryptography.CyrptographicException'

When I try to access a property of SSLCert, I get the following Exception thrown: m_safeCertContext is an invalid handle

I'be searched for that exception, but everything points to an invalid certificate, which might be true if the certificate is expired, and might be true for the IP and port combination I am connecting to. But since I am connecting to the IP using the IP and not anything that would match the common name, I expect that and could care less as I still need the information.

The code is below, I put some comments in as well for what doesn't work and what does work.

 // To get around the SSL validation in the HttpWebRequest
        System.Net.ServicePointManager.ServerCertificateValidationCallback =
            delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                // The below works but isn't what I want. CertName and ExpireDate are both Strings
                this.CertName = ProcessSubject(certificate.Subject);
                this.ExpireDate = certificate.GetExpirationDateString();
                // The below works but the X509Certificate SSLCert shows exceptions in the debugger for most of the properties.
                this.SSLCert = certificate;

                return true; // **** Always accept
            };
        HttpWebRequest myRequest = (HttpWebRequest)System.Net.WebRequest.Create("https://" + this.IP + ":" + this.Port + "/SSLCheck.html");
        myRequest.KeepAlive = false;
        myRequest.Method = "GET";

        try
        {
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
        }
        catch (Exception e)
        {
            if (e.Message != "The remote server returned an error: (404) Not Found.")
            {
                throw Exception("Error");
            }

        }

        // THE BELOW FAILS
        this.CertName = this.SSLCert.Subject;

Solution

  • (Edit from our comments below)

    I suppose what you need to do is create a custom class and store the data you need in it inside the delegate code, rather than pass around the actual certificate reference.