SSL/TSL - Issue in finding Certificates - c#

I am testing the example given in below link.
https://msdn.microsoft.com/en-us/library/system.net.security.sslstream.aspx
To generate certificates I am using the one with 40 userful answers SSLStream example - how do I get certificates that work?
To run the server I am using command
SslTcpServer.exe TempCert.cer
Below is the code from msdn where I am facing problem.
public static int Main(string[] args)
{
string serverCertificateName = null;
string machineName = null;
if (args == null ||args.Length <1 )
{
DisplayUsage();
}
// User can specify the machine name and server name.
// Server name must match the name on the server's certificate.
machineName = args[0];
if (args.Length <2 )
{
serverCertificateName = machineName;
}
else
{
serverCertificateName = args[1];
}
SslTcpClient.RunClient (machineName, serverCertificateName);
return 0;
}
I get below error when calling X509Certificate.CreateFromCertFile:
System.Security.Cryptography.CryptographicException: 'The system cannot find the file specified.
public static void RunServer(string certificate)
{
serverCertificate = X509Certificate.CreateFromCertFile(certificate);
// Create a TCP/IP (IPv4) socket and listen for incoming connections.
//serverCertificate = new X509Certificate2(certificate,"");
}
serverCertificateName is passed as argument and it should be just the name of the certificate or should i give the full path of the certificate?
If I give path of the certificate it is working fine.Then what is point in installing the certificates in the store? How can I get it from store and use it?

Here is some code that will return a list of the host names supported by installed certificates (that's a little more than you wanted, but should point you in the right direction):
System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
HashSet<string> certificateNames = new HashSet<string>();
foreach (System.Security.Cryptography.X509Certificates.X509Certificate2 mCert in store.Certificates)
{
// is this a UCC certificate?
System.Security.Cryptography.X509Certificates.X509Extension uccSan = mCert.Extensions["2.5.29.17"];
if (uccSan != null)
{
foreach (string nvp in uccSan.Format(true).Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
{
string[] parts = nvp.Split('=');
string name = parts[0];
string value = (parts.Length > 0) ? parts[1] : null;
if (String.Equals(name, "DNS Name", StringComparison.InvariantCultureIgnoreCase))
{
certificateNames.Add(value.ToLowerInvariant());
}
}
}
else // just a regular certificate--add the single name
{
string certificateHost = mCert.GetNameInfo(System.Security.Cryptography.X509Certificates.X509NameType.SimpleName, false);
certificateNames.Add(certificateHost.ToLowerInvariant());
}
}
return certificateNames;

Related

c# Cross-Platform device information from local network from lan scan

I have currently wrote a code which scans the local network with a function called "bool ping()". I want to add a capability to provide basic device information when the function returns 'true'. I've found 'ManagementObjectSearcher'.
At first it looked perfect but when It gets used for a non-windows device it crash. Therefore I suppose that this method cannot be used for non-windows devices.
As I want to add the below code ( or login , after enough polishing ), to an android app that scans the local network and returns the
A) IP address and
B) (one of the following )
the device type ( desktop , laptop , smartphone)
and/or
the OS type ( android , windows , linux , tvOS )
Is there a valid way I can do what I am looking for? I believe I have experienced apps that do stuff like that, though I don't know what language they were based on.
namespace LanConsole
{
class Program
{
static void Main(string[] args)
{
string host = "192.168.1.10"; // android smartphone IP
string temp = null;
// arguments I found
string[] _searchClass = { "Win32_ComputerSystem", "Win32_OperatingSystem", "Win32_BaseBoard", "Win32_BIOS" };
string[] param = { "UserName", "Caption", "Product", "Description" };
bool v = ping(host, 10, 900); // bool function send ping to host
if (v == true)
{
Console.WriteLine("true");
for (int i = 0; i <= _searchClass.Length - 1; i++)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\\\" + host + "\\root\\CIMV2", "SELECT *FROM " + _searchClass[i]);
foreach (ManagementObject obj in searcher.Get())
{
temp += obj.GetPropertyValue(param[i]).ToString() + "\n";
if (i == _searchClass.Length - 1)
{
Console.WriteLine(temp, "Hostinfo: " + host);
break;
}
}
Console.WriteLine("");
}
}
else
Console.WriteLine("false");
}
public static bool ping(string host, int attempts, int timeout)
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply pingReply;
for (int i = 0; i < attempts; i++)
{
try
{
pingReply = ping.Send(host, timeout);
// If there is a successful ping, return true.
if (pingReply != null &&
pingReply.Status == System.Net.NetworkInformation.IPStatus.Success)
{
return true;
}
}
catch
{
// supressing errors
}
}
// Return false if ping fales "attempts" times
return false;
}
}
}

How to get certificate from specific binding C#

I found on the internet only way to got all the certificates from the iis and i do it like the following (c#):
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
store.Certificates;
Now I try to get a specific certificate of specific binding, how can I do it in C#?
The certificates themselves hold absolutely no information about the bindings used in IIS, so you cannot retrieve the certificates from the machine and expect them to have anything related to IIS. You would need to query that information from IIS.
To do this, you will need add a reference to the library that can be found under %windir%\system32\inetsrv\Microsoft.Web.Administration.dll (note: IIS 7 or newer must be installed). After this, you can do something like the following to get the certificate:
ServerManager manager = new ServerManager();
Site yourSite = manager.Sites["yourSiteName"];
X509Certificate2 yourCertificate = null;
foreach (Binding binding in yourSite.Bindings)
{
if (binding.Protocol == "https" && binding.EndPoint.ToString() == "127.0.0.1" /*your binding IP*/)
{
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
yourCertificate = store.Certificates.Find(X509FindType.FindByThumbprint, ToHex(binding.CertificateHash), true)[0];
break;
}
}
public static string ToHex(byte[] ba)
{
var hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
hex.AppendFormat("{0:x2}", b);
}
return hex.ToString();
}
I think Camilo's answer has a small problem. As far as I can see (tested it) the code to find the certificate does not work, because System.Convert.ToBase64String(binding.CertificateHash) does not return a valid certificate thumbprint.
My version:
/// <summary>
/// Returns the https certificate used for a given local IIS website.
/// </summary>
/// <param name="sWebsite">Website url, e.g., "https://myserver.company.com"</param>
/// <returns>certificate, null if not found</returns>
private X509Certificate2 FindIisHttpsCert(string sWebsite)
{
Uri uriWebsite = new Uri(sWebsite);
using (ServerManager sm = new ServerManager())
{
string sBindingPort = string.Format(":{0}:", uriWebsite.Port);
Binding bdBestMatch = null;
foreach (Site s in sm.Sites)
{
foreach (Binding bd in s.Bindings)
{
if (bd.BindingInformation.IndexOf(sBindingPort) >= 0)
{
string sBindingHostInfo = bd.BindingInformation.Substring(bd.BindingInformation.LastIndexOf(':') + 1);
if (uriWebsite.Host.IndexOf(sBindingHostInfo, StringComparison.InvariantCultureIgnoreCase) == 0)
{
if ((bd.Protocol == "https") && ((bdBestMatch == null) || (bdBestMatch.BindingInformation.Length < bd.BindingInformation.Length)))
bdBestMatch = bd;
}
}
}
}
if (bdBestMatch != null)
{
StringBuilder sbThumbPrint = new StringBuilder();
for (int i = 0; i < bdBestMatch.CertificateHash.Length; i++)
sbThumbPrint.AppendFormat("{0:X2}", bdBestMatch.CertificateHash[i]);
X509Store store = new X509Store(bdBestMatch.CertificateStoreName, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindByThumbprint, sbThumbPrint.ToString(), true);
if (coll.Count > 0)
return coll[0];
}
}
return null; // if no matching site was found
}
This function also works if multiple https sites are hosted on the same server (tested) and should work if the site uses a port other than 443 (not tested). To get Binding info, %windir%\system32\inetsrv\Microsoft.Web.Administration.dll is used, as in Camilo's answer.
I had tried the solution, but ran into problems NOT finding the certificate. Ended up being that the cert store needs to be properly specified based on the binding:
ServerManager manager = new ServerManager();
Site yourSite = manager.Sites["yourSiteName"];
X509Certificate2 yourCertificate = null;
foreach (Binding binding in yourSite.Bindings)
{
if (binding.Protocol == "https" && binding.EndPoint.ToString() == "127.0.0.1" /*your binding IP*/)
{
var store = new X509Store(binding.CertificateStoreName, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindByThumbprint, ToHex(binding.CertificateHash), true);
if (certs.Count > 0)
yourCertificate = certs[0];
break;
}
}
public static string ToHex(byte[] ba)
{
var hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
hex.AppendFormat("{0:x2}", b);
}
return hex.ToString();
}
The following link should help:
basically store.Certificates returns a collection of all certificates in the particular store, you can then search through for the one you want. The link shows how to do this if you know the subject name of the certificate you want.
How to get X509Certificate from certificate store and generate xml signature data?

download two files from SFTP site [duplicate]

This question already has answers here:
SFTP Libraries for .NET [closed]
(8 answers)
Closed 4 years ago.
I'am using .NET 4.5 and I need to connect to an SFTP site and download two files to my local pc. From my reading on the internet there are no in built libraries I can use in .NET.
Are there any reliable 3rd parties that I can use that also have simple examples?
I have the following
username: myusername
password: mypassword
hostname: fts-sftp.myhost.com
protocol: SFTP
Port: 6621
Update
I have the code below however I am getting the following error message on the "sftp.Connect()" line.
An unhandled exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
Additional information: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Have checked the creditenals that have been supplied to me to make sure I have no typo's.
using Renci.SshNet;
using Renci.SshNet.Common;
using Renci.SshNet.Sftp;
namespace SftpExample2
{
class Program
{
static void Main(string[] args)
{
string host = "fts-sftp.myaddress.com";
string password = "mypassword";
string username = "myusername";
string remoteDirectory = ".";
int port = 6671;
using (SftpClient sftp = new SftpClient(host, port, username, password))
{
sftp.Connect();
var files = sftp.ListDirectory(remoteDirectory);
foreach (var file in files)
Console.WriteLine(file.FullName);
sftp.Disconnect();
};
}
}
}
I generaly use Renci.SshNet
below is an example of download, it should be trivial to change it for download.
I ripped it out of an old project, it might need some tuning to get it to compile/run
static public void UploadFiles(string [] files)
{
string host = " fts-sftp.myhost.com";
string userName = "user";
string password = "pass";
var keyboardAuthMethod = new KeyboardInteractiveAuthenticationMethod(userName);
keyboardAuthMethod.AuthenticationPrompt += delegate(Object senderObject, AuthenticationPromptEventArgs eventArgs)
{
foreach (var prompt in eventArgs.Prompts)
{
if (prompt.Request.Equals("Password: ", StringComparison.InvariantCultureIgnoreCase))
{
prompt.Response = password;
}
}
};
var passwordAuthMethod = new PasswordAuthenticationMethod(userName, password);
var connectInfo = new ConnectionInfo(host, userName, passwordAuthMethod, keyboardAuthMethod);
using (SftpClient serverConnection = new SftpClient(connectInfo))
{
try
{
foreach (var file in files)
{
if (!file.Name.StartsWith("."))
{
string remoteFileName = file.Name;
if (file.LastWriteTime.Date == DateTime.Today)
Console.WriteLine(file.FullName);
File.OpenWrite(localFileName);
string sDir = #"localpath";
Stream file1 = File.OpenRead(remoteDirectory + file.Name);
sftp.DownloadFile(remoteDirectory, file1);
}
serverConnection.Disconnect();
}
catch (Exception e)
{
throw e;
}
}
}
using Tamir.SharpSsh;
public void DownloadSFTP_Files()
{
string _ftpURL = "URLHERE";
string _SftpUserName = "USERNAMEHERE";
string _SftpPassword = "PASSWORDHERE";
int _port = 22;
Sftp oSftp = new Sftp(_ftpURL, _SftpUserName, _SftpPassword);
oSftp.Connect(_port);
string path = "";
// Get List of Files in the SFTP Directory
System.Collections.ArrayList GetFiles_List = oSftp.GetFileList(path);
// Download the Files Form SFTP Server to you Local system
string ServerPath= "SERVERDiRECTORYPATHHERE";
string LocalPath= "LOCALDiRECTORYPATHHERE";
oSftp.Get(ServerPath, LocalPath);
oSftp.Close();
}

Converting IPAddress[] to string

I've got a server application which I'm trying to automatically set the IP address to, taken from the machine's dynamically allocated IP address. So far I've got this to get the IPv4 but it's returned as type IPAddress[] which I have some trouble converting to a string[] so my HttpListener can use it. Any hint to how I can convert it? Or am I going about this the wrong way?
This is what I'm using to get the IP address:
class Program
{
static void Main(string[] args)
{
string name = (args.Length < 1) ? Dns.GetHostName() : args[0];
try
{
IPAddress[] addrs = Array.FindAll(Dns.GetHostEntry(string.Empty).AddressList,
a => a.AddressFamily == AddressFamily.InterNetwork);
Console.WriteLine("Your IP address is: ");
foreach (IPAddress addr in addrs)
Console.WriteLine("{0} {1}", name, addr);
//Here I'm trying to convert the IPAddress[] into a string[] to use in my listener
string str = addrs.ToString();
string[] ipString = { str };
Response.Listener(ipString);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
//current way of setting the IP address - not optimal
string[] ipstring = new string[1] {"10.10.180.11:8080"};
Response.Listener(ipstring);
}
}
And the listener for good times sake:
public static void Listener(string[] prefixes)
{
if (!HttpListener.IsSupported)
{
Console.WriteLine("Windows XP SP2 or Server 2003 is required to use the HttpListener class.");
return;
}
// URI prefixes are required,
// for example "http://contoso.com:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// Create a listener.
HttpListener listener = new HttpListener();
// Add the prefixes.
foreach (string s in prefixes)
{
listener.Prefixes.Add("http://" + s + "/");
}
listener.Start();
This should do the trick.
string[] ips = addresses.Select(ip => ip.ToString()).ToArray();
Make sure you have a using statement for System.Linq
You are trying to convert an IPAdress's array like one IPAdress.
You can use LINQ to convert each IPAdress, then you can make the String's array :
String[] strAddrs = (from cad in addrs select cad.ToString()).ToArray();
Don't forget : using System.Linq;
If you have an IPAddress object, you can get the string representation like this:
v4:
validIP4.MapToIPv4().ToString();
v6:
validIP4.MapToIPv6().ToString();

C# RunAs /Smartcard

My application used to accept username/password to authenticate to a remote share (on Windows server) and then get the file listings etc.
public int ConnectNetResource(string server, string user, string password, ref string driveLeter) {
NETRESOURCE net = new NETRESOURCE();
net.dwScope = 0;
net.dwType = 0;
net.dwDisplayType = 0;
net.dwUsage = 0;
net.lpRemoteName = server;
net.lpLocalName = driveLeter;
net.lpProvider = null;
return WNetAddConnection2(ref net, password, user, 0);
}
Now, we need to authenticate using SmartCard. I have code to GetSmartCards, but I do not know how to make use of the certificate to authenticate.
public static X509Certificate2 GetClientCertificate()
{
X509Certificate2 certificate = null;
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
// Nothing to do if no cert found.
if (store.Certificates != null && store.Certificates.Count > 0)
{
if (store.Certificates.Count == 1)
{
// Return the certificate present.
certificate = store.Certificates[0];
}
else
{
// Request the user to select a certificate
var certificates = X509Certificate2UI.SelectFromCollection(store.Certificates, "Digital Certificates", "Select a certificate from the following list:", X509SelectionFlag.SingleSelection);
// Check if one has been returned
if (certificates != null && certificates.Count > 0)
certificate = certificates[0];
}
}
}
finally
{
store.Close();
}
return certificate;
}
GetClientCertificate function will return a user selected certificate, now HOW do I use this certificate to connect to a remote share. What API's or .dll can i use.
Btw, I am a windows engineer who can google code and make it work somehow. Will greatly appreciate a working code. Thank you.

Categories