I'm using this code from c# to call a php web service that is secured by user/password and certificate:
string wsurl = ConfigurationManager.AppSettings["Url"];
string wsuser = ConfigurationManager.AppSettings["User"];
string wspass = ConfigurationManager.AppSettings["Pass"];
string url = string.Format(wsurl, param1, param2);
System.Net.CredentialCache oCredentialCache = new System.Net.CredentialCache();
oCredentialCache.Add(new System.Uri(url), "Basic",
new System.Net.NetworkCredential(wsuser, wspass));
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Timeout = TIMEOUT;
req.Credentials = oCredentialCache;
req.Method = "GET";
AttachCert(req);
//Get the data as an HttpWebResponse object
WebResponse resp = req.GetResponse();
This works as expected when run from my devel machine but when we upload this to the server I get a Timeout error on the call to GetResponse().
The AttachCert() call is where I attach the certificate to the request, and if I comment this line I don't get the timeout but a correct error saying the call could not be completed because of the missing certificate.
This is the AttachCert code:
public static void AttachCert(HttpWebRequest Request)
{
// Obtain the certificate.
string certpath = ConfigurationManager.AppSettings["CertPath"];
X509Certificate Cert = X509Certificate.CreateFromCertFile(certpath);
ServicePointManager.CertificatePolicy = new CertPolicy();
Request.ClientCertificates.Add(Cert);
}
Any idea why this would work on my machine but not on the server? We tried to remove the certificate on the webservice and the it worked as expected. So there's clearly something strange on that call but I cannot figure what.
Thanks
Vicenç
Try registering this callback and watch for any errors.
public static bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors) {
// check for errors
// just return true to accept any certificate (self signed etc)
}
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(MyClass.ValidateRemoteCertificate);
I hope it helps.
Related
I am client side developer (Unity/C#) and I have API that require SSL certificate at connection. I have this certificate (.pfx).
When I try to make request by HttpWebRequest class (code listen below) I have error (code 400: Bad request, No required SSL certificate was sent). Any idea how to make it works?
When I put my URL in browser I have popup which asks for certificate and I can provide certificate there and then I have result!
Maybe I need to use Stream from request?
Here is how request looks in Inspector:
void Connect() {
// I think it is not necessary
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate);
// certificate creation
certificate = new X509Certificate2(path, pass);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// adding certificate to request
request.ClientCertificates.Add(certificate);
request.Method = "GET";
request.AuthenticationLevel = AuthenticationLevel.MutualAuthRequested;
request.Accept = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
}
public static bool ValidateServerCertificate(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true;
}
I am trying to make a connection to my kubernetes api and cant seem to get SSL to work from C#.
When i run the following via curl, everything seems to work as expected:
And I have this for c# to do the same:
try
{
// use the TLS protocol
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
// create HTTP web request with proper content type
HttpWebRequest request = WebRequest.Create(Constants.K8_API_RC_URI) as HttpWebRequest;
request.ContentType = "application/json;charset=UTF8";
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + Constants.K8_TOKEN);
// load the X.509 certificate and add to the web request
X509Certificate cert = new X509Certificate(Constants.K8_CRT);
request.ClientCertificates.Add(cert);
// call the web service and get response
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
string jsonContents = new StreamReader(responseStream).ReadToEnd();
}
catch (Exception exc)
{
// log and print out error
log.Info(exc.Message);
}
Where
Constants.K8_CRT is the Path to ca.crt
and ca.crt contains the following:
-----BEGIN CERTIFICATE-----
MIIDMDCCAhigAwIBAgIIcwd9rrnaPcowDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwIYWNzazhz
and more letters.......
cwSfuIp7e49KC3HSqcU3Mz4oFNm5bw==
-----END CERTIFICATE-----
I get the following error:
Could not create SSL/TLS secure channel.
P.S. I know there are Kubernetes clients for .Net out there and I have tried just about all of them but since I am integrating this with Azure Functions most of the third party libraries do not work for various reasons.
The CA cert should be used to validate server cert chain, not passed as an ClientCertificate.
Here is an example.
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => {
if (errors == SslPolicyErrors.None) return true;
X509Certificate2 serverCert = new X509Certificate2(certificate);
X509Certificate2 caCert = new X509Certificate2(#"./ca.cert");
chain.ChainPolicy.ExtraStore.Add(caCert);
chain.Build(serverCert);
foreach (var chainStatus in chain.ChainStatus) {
if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot) continue;
if (chainStatus.Status != X509ChainStatusFlags.NoError) return false;
}
return true;
};
HttpWebRequest request = WebRequest.CreateHttp("https://master:6443/api/v1");
request.Headers[HttpRequestHeader.Authorization] = "Bearer " + "SOME_TOKEN";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
var content = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine(content);
Thanks for #Jimi's comments i was able to get this to work with adding the following:
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true; // **** Always accept
};
NOTE: Im certain this just ignores the SSL validation and continues without it. In our case this may be acceptable.
im doing a WebRequest on webservice.domain.com in an console application:
WebRequest webRequest = HttpWebRequest.Create(url_web);
WebResponse webResp = webRequest.GetResponse();
and i get an exeption every time the WebRequest is called:
The request was aborted: Could not create SSL/TLS secure channel.
The Destinationserver is secured by a certificate, bound to mail.domain.com, alternative names are webservice.domain.com and some other subdomains.
Already tried
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(delegate { return true; });
WebRequest webRequest = HttpWebRequest.Create(url_web);
WebResponse webResp = webRequest.GetResponse();
without success.
"Normal" certificates, wildcard or standard work without any problems.
Try this
webRequest.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; };
I am trying to do a HTTPS POST in C# to a server which does not have a proper SSL certificate installed (my test development server). The request is timing out using WebClient, as well as HttpWebRequest. I've set up my own ServerCertificateValidationCallback to bypass the cert check, but that hasn't helped. If I make the exact same call in a webpage, that call succeeds.
So:
Call to URL https://testServer/myAction?myData in webpage - succeeds.
POST to https://testServer/myAction with myData using WebClient - timeout.
My code for the WebClient post is as follows:
private static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
//solve the problem of invalid certificates - accept all as valid
return true;
}
public void callPost(object o)
{
string myData = (string)o;
try
{
Uri uri = new Uri("https://testServer/myAction");
WebClient client = new WebClient();
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
byte[] uploadBytes = Encoding.UTF8.GetBytes(myData);
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
byte[] responseBytes = client.UploadData(uri, "POST", Encoding.UTF8.GetBytes(urlData));
Console.WriteLine("WebRequest:{0}\n", Encoding.ASCII.GetString(responseBytes));
}
catch (Exception e)
{
Console.WriteLine("WebRequest Error:{0}\n", e.ToString());
}
}
Any ideas how to get the POST to work in C#? Thanks!
After more searching, I found someone who was having a similar problem and who had found a solution.
To debug this and similar situations, enable SSL tracing/logging as described here. http://blogs.msdn.com/b/dgorti/archive/2005/09/18/471003.aspx
My problem was that I needed to declare an SSL3 connection as follows
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
Adding this to my code before calling client.UploadData fixed the problem.
i am looking to get the data from any given domain names SSL certificate. For example I want to put in any website address e.g. "http://stackoverflow.com" and my code would firstly check if an SSL certificate exists. If it does then I want it to pull out the expiry date of the certificate. [ i am reading Domainnames from DB ] Example :http://www.digicert.com/help/
i need to create a web service to check expiry date. how can i implement it?? - I have looked up loads of different things such as RequestCertificateValidationCallback and ClientCertificates etc. Since i am new to this, i am not sure what has to be done.
I could be completely wrong (hence why I need help) but would I create a HTTPWebRequest and then somehow request the client certificate and specific elements that way?
i tried the example provided #SSL certificate pre-fetch .NET , but i am getting forbitten 403 error.
Any help would be much appreciated - Thank you.
This is the code i have written which is throwing 403 forbidden error.
Uri u = new Uri("http://services.efi.com/");
ServicePoint sp = ServicePointManager.FindServicePoint(u);
string groupName = Guid.NewGuid().ToString();
HttpWebRequest req = HttpWebRequest.Create(u) as HttpWebRequest;
req.Accept = "*/*";
req.ConnectionGroupName = groupName;
using (WebResponse resp = req.GetResponse())
{
// Ignore response, and close the response.
}
sp.CloseConnectionGroup(groupName);
// Implement favourite null check pattern here on sp.Certificate
string expiryDate = sp.Certificate.GetExpirationDateString();
string str = expiryDate;
This works fine:
namespace ConsoleApplication1
{
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
class Program
{
static void Main()
{
ServicePointManager.ServerCertificateValidationCallback += ServerCertificateValidationCallback;
var request = WebRequest.Create("https://www.google.com");
var response = request.GetResponse();
Console.WriteLine("Done.");
Console.ReadLine();
}
private static bool ServerCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
Console.WriteLine("Certificate expires on " + certificate.GetExpirationDateString());
return true;
}
}
}
You are getting a "403 forbidden" status because that's what the server returns when you access that page. I see the same thing when I browse to that Uri using IE. This status indicates that you don't have permission to access the Url, so perhaps you should try your code on a page that you have access to.
Also, you're unlikely to see a certificate on a http connection - you might want to try https instead.
If you need to download the certificate:
//Do webrequest to get info on secure site
var certName = "FileName";
var url = "https://mail.google.com";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();
//retrieve the ssl cert and assign it to an X509Certificate object
X509Certificate cert = request.ServicePoint.Certificate;
//convert the X509Certificate to an X509Certificate2 object by passing it into the constructor
X509Certificate2 cert2 = new X509Certificate2(cert);
string cn = cert2.GetIssuerName();
string cedate = cert2.GetExpirationDateString();
string cpub = cert2.GetPublicKeyString();
var path = Directory.GetCurrentDirectory() + string.Concat("\\", certName, ".der");
byte[] certData = cert2.Export(X509ContentType.Cert);
File.WriteAllBytes(path, certData);
Console.WriteLine("cert2.GetIssuerName :{0}", cert2.GetIssuerName());
Console.WriteLine("cert2.GetExpirationDateString :{0}", cert2.GetExpirationDateString());
Console.WriteLine("cert2.GetPublicKeyString :{0}", cert2.GetPublicKeyString());
.cs Sample File :https://gist.github.com/thedom85/6db200104c075310527aaef63b172253
I also recommend this site : https://www.simple-talk.com/dotnet/.net-framework/tlsssl-and-.net-framework-4.0/