Cheshire Cat
Cheshire Cat

Reputation: 1961

Check if HTTPS Web Service is available with HttpWebRequest and X509 SSL certificate

I need to implement a method that checks if a web service is available. The main problem is that the URL is HTTPS and requires a certificate. So I need to get the certificate from the machine and then create a HttpWebRequest to get a HttpWebResponse.

With my actual implementation I can retrieve the certificate but when I call request.GetResponse() method it throws this Exception:

[System.Net.WebException] = {"The underlying connection was closed: An unexpected error occurred on a send"}

InnerException:

[System.IO.IOException] = {"Received an unexpected EOF or 0 bytes from the transport stream"}

I read many possible solutions around but none seems to work for me. I'm on .NET 3.5.

This is my code

using (WebClient client = new WebClient())
{
    X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, CertificateThumbprint, false);

    if (certificates.Count == 0)
        throw new Exception("No corresponding certificate found.");

    X509Certificate2 certificate = certificates[0];

    // Not compiling on .NET 3.5
    // Error: cannot apply '+=' operator to 
    //'System.Net.Security.RemoteCertificateValidationCallback' 
    //and 'anonymous method'
    //ServicePointManager.ServerCertificateValidationCallback +=
    //    delegate(
    //        object sender,
    //        X509Certificate certificate,
    //        X509Chain chain,
    //        SslPolicyErrors sslPolicyErrors)
    //    {
    //        return true;
    //    };

    // Not compiling on .NET 3.5
    // Error: cannot apply '+=' operator to 'System.Net.Security.RemoteCertificateValidationCallback' and 'lambda expression'
    // ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

    // Not working
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

    // Not working
    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(UrlWSInvioComunicazioni);
    request.ClientCertificates.Add(certificate);
    request.Method = "HEAD";

    // throws Exception...
    HttpWebResponse webResponse = request.GetResponse() as HttpWebResponse;
    webResponse.Close();

    response.ResultCode = ResultCode.Success;
    response.ResultMessage = "Service available.";
}

Update 2017/05/10

Since I'm on .NET 3.5 that didn't support TLS 1.2, I'm using a patch from Microsoft (see KB3154519) that makes possible to use TLS 1.2 by using SecurityProtocolTypeExtensions and SslProtocolsExtensions extension classes.

I already used that method with some other web services since January 2017 (when Microsoft released the patch) and it works without any problem.

I think that the problem that I have now:

[System.Net.WebException] = {"The request was aborted: Could not create SSL/TLS secure channel."}

has to do with something in my PC.

Update 2017/05/12

I finally found that the problem was related to IIS. The Application Pool of the web application on my PC was running with Identity set to ApplicationPoolIdentity. When set to LocalSystem or my current user (administrator), it worked.

So I think that something with the access to certificates is not correct while the Application Pool runs as ApplicationPoolIdentity.

Upvotes: 1

Views: 1728

Answers (1)

migabriel
migabriel

Reputation: 58

scan the URL to see what SSL providers the server is using. You can do that here -> https://www.ssllabs.com/ssltest/analyze.html

protocols

some server have the ssl3 disabled for security reasons. So you have to use this setting instead:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;

or use Tls 1.2 if is available on the client.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls12;

Update Check if this code is working for you

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | (SecurityProtocolType)3072;
var httpRequest = (HttpWebRequest)WebRequest.Create("https://google.com");
httpRequest.Method = "GET";
httpRequest.ContentType = "text/html";

httpRequest.KeepAlive = false;
httpRequest.MaximumAutomaticRedirections = 30;

var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
var responseStream = new StreamReader(httpResponse.GetResponseStream());

var strResponse = responseStream.ReadToEnd();

httpResponse.Close();
responseStream.Close();

Upvotes: 1

Related Questions