HttpWebRequest.GetResponse() gives SendFailure to EC2 behind ELB over https - c#

Our .NET code is posting using JSON to an HTTPS REST API. It works on machines from Vista up (I think they all have .NET 4.5), however, we need to support down to Win XP with .Net 4.0 and on that machine our code fails on the last line shown below.
If we change the URI to HTTP from HTTPS, it works fine. A number of the lines you see below (such those for CertificateValidationCallBack) were added in an attempt to fix this issue).
BIG FLAG: We have noticed that on this XP machine, IE 8 gives "Internet Explorer cannot display the webpage" over HTTPS, though HTTP is fine. We added the CertificateValidationCallBack handler hoping it would get around this issue. I'm not sure it does.
Some information about the server configuration. It is an EC2 instance behind an ELB. The ELB holds the SSL cert and sends data received from port 443 to port 80. Apache on the EC2 instance just deals with port 80.
ADDED: sslchecker.com shows a good certificate.
private static bool CertificateValidationCallBack(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true;
}
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.PreAuthenticate = true;
using (var client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
try
{
string responseString ;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
_webEx = null;
webRequest.ContentType = "application/json";
webRequest.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(credsString);
// webRequest.ContentLength = bytes.Length;
webRequest.KeepAlive = false;
webRequest.Timeout = -1;
System.IO.Stream os = webRequest.GetRequestStream();
os.Write(bytes, 0, bytes.Length); //Push it out there
os.Close();
System.Net.WebResponse resp = webRequest.GetResponse();
. . . . .
}
}

Related

Unable to make HttpWebRequest that is working on Postman

I have a token request that works on Postman on a server.
No body, just basic authentication with username and password:
However, I have this code below that returns the error:
The request was aborted: Could not create SSL/TLS secure channel.
Here is the code below:
string responsedata = string.Empty;
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlToken);
request.Method = "POST";
request.Headers.Add("Authorization", "Basic " + encoded);
request.PreAuthenticate = true;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
responsedata = reader.ReadToEnd();
}
What am I doing worng?
I suspect your problem is related to the SecurityProtocol your application runs on.
Try running this before your request.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
The endpoint your trying to connect probably requires a higher version of Tls than what your application is providing.
The default value of this is defined by the system it runs on see:
https://learn.microsoft.com/en-us/dotnet/api/system.net.securityprotocoltype?view=net-7.0#system-net-securityprotocoltype-systemdefault
So when running on an older OS this often is too low for modern API endpoints.
You can test this by enabling or disabling specific versions of TLS/SSL in Postman, look for "Protocols disabled during handshake" in the settings tab for your request.
Like Neil Moss already commented above...
Think you are in use of untrusted certificate on server side so try to ignore certificate validation...
request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

Zipwise.com Could not create SSL/TLS secure channel

I'm running into an issue with my application. When trying to use ZipWise.com's api to get some zip codes I get the error "The request was aborted: Could not create SSL/TLS secure channel." I did not make any changes to the program, and it all of a sudden stopped allowing me to use their API. I tried adding this to the beginning of my code before the request is created:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
I disabled TLS 1.0, TLS 1.1, SSL 2.0, and SSL 3.0 on the server (and rebooted). I'm able to open the url in a browser without issue. I verified on SSL Labs that they are using TLS 1.2.
When I run this on my development PC, it executes without issue and returns a bunch of zip codes. When I try to run it on the server, it fails and gives me that error.
Here is some sample code I used in a Windows forms application that produces the same error:
private void button1_Click(object sender, EventArgs e)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.Expect100Continue = true;
string url = "https://zipwise.com/webservices/radius.php?key=**********&zip=90210&radius=50";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));
request.Method = "POST";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();//exception occurs here
StreamReader input = null;
XDocument doc = null;
if (response.StatusCode.Equals(HttpStatusCode.OK))
{
input = new StreamReader(response.GetResponseStream());
doc = XDocument.Parse(input.ReadToEnd());
}
response.Close();
request.ServicePoint.CloseConnectionGroup(request.ConnectionGroupName);
if (input != null)
{
input.Close();
var tempZips = (from z in doc.Descendants("result") select z.Descendants("zip").Single().Value).ToList();
finalZips.AddRange(tempZips);
foreach(string s in finalZips)
{
listBox1.Items.Add(s);
}
}
}
Any help is appreciated!
EDIT: The application is running on .NET 4.6, The SSL Cert on the server is still valid.

Could not establish secure channel for SSL/TLS C# Web service Client

I have a WPF application and that calling 4 web services (Written with Java) on the same base URL and it was working perfectly until I install google chrome. I installed chrome and I've got this error:
Could not establish secure channel for SSL/TLS C# Web service
I didn't write another code. That happened for just I installed chrome then I remove chrome but didn't work and I tried system restore, uninstall eset smart security and I cleaned all windows(8.1 single languages) certificate. So how can I figure it out? Here is my web service caller
public string call(string url, string json)
{
try
{
var webrequest = (HttpWebRequest)WebRequest.Create(url);
var key = JsonConvert.SerializeObject(LoginService.SessionData.SessionKey);
UTF8Encoding uTF8Encoding = new UTF8Encoding();
byte[] requestBytes = uTF8Encoding.GetBytes(json);
WebClient client = new WebClient();
webrequest.Method = "POST";
webrequest.Headers.Add("SESSION_KEY", LoginService.SessionData.SessionKey);
webrequest.ContentType = "application/json";
webrequest.ContentLength = requestBytes.LongLength;
Stream requestStream = webrequest.GetRequestStream();//here the exception
requestStream.Write(requestBytes, 0, requestBytes.Length);
using (var response = webrequest.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
var responseBuf = reader.ReadToEnd();
String responseJson = Convert.ToString(responseBuf);
return responseJson;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return null;
}
By my observation there are a large number of services over the last several months that are turning off SSL and/or older TLS versions to mitigate security problems inherent in them.
Anywhere within the AppDomain you can just force the connection to use TLS 1.2 like this:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
You can also OR together multiple versions if you need to support older ones as well:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12

How to: C# WebClient to hit service endpoint (Oauth 2.0 like protocol) with Mutual TLS

I need to hit a service to obtain the app ticket to authenticate against another service. The solution is hosted on a endpoint.
I tried using the POSTMAN app in google chrome and it succeeds and returns me the AppID. When I submit the (POST)request in POSTMAN app, it prompts for a certificate. When I select the correct certificate the call succeeds.
I need to implement the same in C# (in a web application)
I tried using the RestSharp.RestClient library and am constantly getting the following error:
"Client certificate not found in site certificates".
Attaching the code for reference.
var client = new RestSharp.RestClient("MyUrl");
var request = new RestSharp.RestRequest("pksecure/oauth20_clientcredentials.srf", RestSharp.Method.POST);
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("param2", "value2");
request.AddParameter("scope", "machinename");
client.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
client.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate(
#"E:\MyCertificate.pfx"
, "MyPassword"
));
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslError)
{
bool validationResult = true;
return validationResult;
};
var response = client.Execute(request);
var content = response.Content; // raw content as string
Pls. help to make this call using the mutual TLS.
TIA,
Sam.
I am not sure why I was not able to get it done using RestSharp.
But I could get it working by using HttpWebRequest Instead.
Also, earlier I was using the Certficate.Pfx file which caused the error. Using the Certificate.Cer file solved the issue.
Posting the code for reference:
var request = (HttpWebRequest)WebRequest.Create("MyURL/oauth20_clientcredentials.srf");
var postData = "grant_type=client_credentials";
postData += "&param2=value2";
postData += "&scope=" + HttpUtility.UrlEncode("machinename");
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
request.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate(#"E:\MyCertificate.cer"));
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
return appToken;
Thanks,
Sam Jayander Thiagarajan.

Accessing a web service and a HTTP interface using certificate authentication

It is the first time I have to use certificate authentication.
A commercial partner expose two services, a XML Web Service and a HTTP service. I have to access both of them with .NET clients.
What I have tried
0. Setting up the environment
I have installed the SSLCACertificates (on root and two intermediate) and the client certificate in my local machine (win 7 professional) using certmgr.exe.
1. For the web service
I have the client certificate (der).
The service will be consumed via a .NET proxy.
Here's the code:
OrderWSService proxy = new OrderWSService();
string CertFile = "ClientCert_DER.cer";
proxy.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate(CertFile));
orderTrackingTO ot = new orderTrackingTO() { order_id = "80", tracking_id = "82", status = stateOrderType.IN_PREPARATION };
resultResponseTO res = proxy.insertOrderTracking(ot);
Exception reported at last statement: The request failed with an empty response.
2. For the HTTP interface
it is a HTTPS interface I have to call through POST method.
The HTTPS request will be send from a .NET client using HTTPWebRequest.
Here's the code:
string PostData = "MyPostData";
//setting the request
HttpWebRequest req;
req = (HttpWebRequest)HttpWebRequest.Create(url);
req.UserAgent = "MyUserAgent";
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate(CertFile, "MyPassword"));
//setting the request content
byte[] byteArray = Encoding.UTF8.GetBytes(PostData);
Stream dataStream = req.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
//obtaining the response
WebResponse res = req.GetResponse();
r = new StreamReader(res.GetResponseStream());
Exception reported at last statement: The request was aborted: Could not create SSL/TLS secure channel.
3. Last try: using the browser
In Chrome, after installing the certificates, if I try to access both urls I get a 107 error:
Error 107 (net::ERR_SSL_PROTOCOL_ERROR)
I am stuck.
The following should help you identify the issue, here are two methods to test SSL connectivity one tests the site whilst the other is a callback method to identify why SSL failed. If nothing else it should give you a better idea why it is failing.
When the method is called it will pop up with the select certificate dialog box, obviously when you do this for real you'll want to read from the cert store automatically. The reason I have put this in is because if no valid certificate is found then you will know your problem is with the way the certificate is installed.
The best thing to do is put this code in a simple console app:
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Net;
private static void CheckSite(string url, string method)
{
X509Certificate2 cert = null;
ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
X509Store store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certcollection = (X509Certificate2Collection)store.Certificates;
// pick a certificate from the store
cert = X509Certificate2UI.SelectFromCollection(certcollection,
"Caption",
"Message", X509SelectionFlag.SingleSelection)[0];
store.Close();
HttpWebRequest ws = (HttpWebRequest)WebRequest.Create(url);
ws.Credentials = CredentialCache.DefaultCredentials;
ws.Method = method;
if (cert != null)
ws.ClientCertificates.Add(cert);
using (HttpWebResponse webResponse = (HttpWebResponse)ws.GetResponse())
{
using (Stream responseStream = webResponse.GetResponseStream())
{
using (StreamReader responseStreamReader = new StreamReader(responseStream, true))
{
string response = responseStreamReader.ReadToEnd();
Console.WriteLine(response);
responseStreamReader.Close();
}
responseStream.Close();
}
webResponse.Close();
}
}
/// <summary>
/// Certificate validation callback.
/// </summary>
private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
{
// If the certificate is a valid, signed certificate, return true.
if (error == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
Console.WriteLine("X509Certificate [{0}] Policy Error: '{1}'",
cert.Subject,
error.ToString());
return false;
}

Categories