Reputation: 1961
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
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
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