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

14,930

Solution 1

(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.

Solution 2

This is just a guess on my part. WHat I think is happening is that the certificate info coming through in the SSL handshake is used by .NET to create a cert object that is passed to you in the delegate. The delegate is only to be used for the purpose of validation. After the call completes, .NET closes the safe handle of the certificate. THat is why the call fails when trying to access the certificate outside the callback.

TO get around this, you can serialize the certificate inside the delegate, and deserialize it outside the delegate.

Share:
14,930
omniplex
Author by

omniplex

Updated on June 04, 2022

Comments

  • omniplex
    omniplex almost 2 years

    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;
    
  • omniplex
    omniplex about 13 years
    Unfortunately the same problem. While the delegate takes in a type of X509Certificate, the type actually passed in is an X509Certificate2 so I'm just casting it to what it is. Though I did try it and recheck, same problem.
  • Mike Atlas
    Mike Atlas about 13 years
    Maybe try making a memberwise clone instead?
  • omniplex
    omniplex about 13 years
    That's a good attempt, but oddly, I see the method as being a protected method on the MSDN site, but yet, it doesn't appear to be available for some reason. VS is highlighting it as an error and it won't compile. Also intellisense doesn't show it as a valid method.
  • omniplex
    omniplex about 13 years
    Here is something interesting. When I am in the delegate and do the assignment, it shows fine for SSLCert, however, it doesn't seem to internally throw exceptions until after I exit from the delegate.
  • Mike Atlas
    Mike Atlas about 13 years
    Oversight on my part (that MemberwiseClone is protected). I guess what you need to do is create a custom class and store the data you need in it inside the delegate, rather than pass around the actual certificate reference.
  • omniplex
    omniplex about 13 years
    ok, well, at least that gives me some validation that the way I was doing it is the best way ( at least at the moment ).
  • Alex Filipovici
    Alex Filipovici about 8 years
    Thanks, this helped me (only needed a certificate property, so I assigned it to a class scoped variable from the delegate).