obtain ssl certificate information - .net - c#

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/

Related

Cannot use client certificate from certificate store, only by loading from file

I am using WebRequest to connect to a webpage that uses https.
If I try to use a client certificate that is in the personal store in LocalMachine by using
var myStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
myStore.Open(OpenFlags.ReadOnly);
var clientCertificates = myStore.Certificates.Find(X509FindType.FindBySubjectName, "foobar",
validOnly: false);
and then I create a connection with
var req = (HttpWebRequest)WebRequest.Create("https://theserver.com/the/url");
req.Method = "POST";
req.ContentType = "application/json";
req.ProtocolVersion = HttpVersion.Version11;
req.ClientCertificates = clientCertificates;
req.ServerCertificateValidationCallback += (o, certificate, chain, errors) =>
{
return true;
};
using (var stream = req.GetRequestStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
}
var response = req.GetResponse();
I fail on the req.GetResponse line with
System.Net.WebException: 'The request was aborted: Could not create
SSL/TLS secure channel.'
But if I instead load the client certificate from file, (the same file that I had previously installed in the store) with
var certificatePath = #"C:\temp\file.p12";
var clientCertificate = new X509Certificate2(certificatePath, "pwd",
X509KeyStorageFlags.Exportable);
and
req.ClientCertificates.Add(clientCertificate);
I will be able to run the https query successfully.
This requires both that I keep a file in the file system and that I put a password in the source code.
How do I use the store instead of the file system?
Why do I have to use validOnly: false to get the client certificates?
edit
The preferrable way of getting access to those certificates (client and server certificate) would be to have them in web.config as endpoints, but I have not succeeded doing that.
To solve the symptoms of the problem/many problems, I had to add the user Everyone to the ACL of the private key of the certificate.
Instead of changing the ACL of the private key, I found that the ClientCertificates property worked perfectly well if I only gave it public keys. Yes, the authentication won't work if you don't have the private key in the store, but converting to a public-key-only certificate appears to work for me every time.
var publicKeyOnly = new X509Certificate2(authenticationCert.Export((X509ContentType.Cert));

Could not create SSL/TLS secure channel - HttpWebRequest

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.

Appharbor JustOneDB https request from C# getting 400 errors

I am trying to do a https GET to JustOneDB it works if I do it from the curl utility. But its NOT working from C#.
I get (400) Bad Request
I searched around and disabled security and all that but its still not working. Any ideas?
Has anyone done this w/ rest and JustOneDB?
This works along w/ all the other rest examples:
curl -k -XGET 'https://username:password#77.92.68.105:31415/justonedb/database/database name'
This DON'T work: I Dummied the string to remove my passcode.
public ActionResult JustOneDb()
{
///////////
HttpWebRequest request = null;
HttpWebResponse response = null;
try
{
String Xml;
//curl -k -XGET 'https://zn0lvkpdhdxb70l2_DUMMY_urshn5e7i41lb3fiwuh#77.92.68.105:31415/justonedb/database/n10lvkpdhdxei0l2uja'
string url = #"https://zn0lvkpdhdxb70_DUMMY_urshn5e7i41lb3fiwuh#77.92.68.105:31415/justonedb/database/n10lvkpdhdxei0l2uja";
request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Credentials = CredentialCache.DefaultCredentials;
// Ignore Certificate validation failures (aka untrusted certificate + certificate chains)
ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
// Get response
using (response = (HttpWebResponse)request.GetResponse())
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
Xml = reader.ReadToEnd();
}
return Content(Xml);
}
catch (Exception ee)
{
return Content(ee.ToString());
}
//////////////
ViewBag.fn = "*.xml";
return View();
}
Results:
System.Net.WebException: The remote server returned an error: (400) Bad Request. at System.Net.HttpWebRequest.GetResponse()
at Mvc3Razor.Controllers.MyXmlController.JustOneDb() ...
TIA
FxM :{
Instead of passing the username password in the url, you should create the correct credentials with "username" and "password". You might also want to consider using something like RestSharp instead of the raw WebRequest.
There was a mismatch with the certificate, which has been fixed. It is still self-signed, but now the hostname matches. We will be changing to use a fully signed certificate soon, but in the mean time please let me know if it works with just the self-signed override.
Ok, I copied the code, and the problem is that the HttpWebRequest library is not adding the authentication header in the original request. The solution is to insert the header manually, so if you add the following two lines after the 'request.Method = "GET" line (and remove the username/password from the URL string):
string authInfo = "zn0lvkpdhdxb70l2_DUMMY_urshn5e7i41lb3fiwuh";
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
It should work correctly.

Login to HTTPS captive portal

I actually connect in my univ to the network through a captive portal at this url https://secure.arubanetworks.com/cgi-bin/login, time ago I made a program to connect to it which worked perfect (C++ & libCurl), sending an HTTP POST with the needed "query string" such as username and password, but i think it was because there wasn't still the SSL, a X.509 Cert, that now seems to work with a GET instead of the POST that used before.
Pasting on Firefox the full url with the query string worked to me perfect, as it should, so i just tried to achieve that in a little C# program, but since i don't know what to do about the certificate (i asume there must be smth to do with it.. :P) it throws me a ProtocolError, and now i thought i should understand a bit about it first, so i'm interested in the code to achieve it, but also the way it works. :)
PS: Also would love if there's a way to set the account or the program (exe) as a callback, on the connection properties (my OS is Win7) so that once connected to the network im inmediatelly authenticated. :D
Thanks in advance for your time and help mates! ;)
Uri uri = new Uri(url + "?" + postData);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.Method = this.method;
// ToDo: Something doesn't work with the cert auth I guess
req.Proxy = null;
req.Credentials = CredentialCache.DefaultCredentials;
ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
};
try
{
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream responseStream = resp.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string responseFromServer = reader.ReadToEnd();
}
catch (WebException e)
{
if (e.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = e.Response as HttpWebResponse;
if (response != null)
{
Console.WriteLine(e.ToString());
}
}
}
Try this for an https GET. For reference, it's related to but simpler than doing an https POST.
There's a difference if you need an asynch approach, but I don't think that's what you need. So, you still use HttpWebRequest object, but there's a difference after you get to the .method -- all you should need is to stuff your uri into the request, and grab the response. I don't think you should manually need to mess with the proxy or credentials.

Calling a php webservice from .net with a cert

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.

Categories

Resources