Using secured websocket in C# - c#

I'm using Fleck to implement websocket functionality in my MVC application. On the local setup I have https scheme with self signed certificate, whereas on production setup, I have paid certificate.
This is the syntax given in docs.
var server = new WebSocketServer("wss://0.0.0.0:8431");
server.Certificate = new X509Certificate2("MyCert.pfx");
server.Start(socket =>
{
//...use as normal
});
Here instead of MyCert.pfx, what should be given in case of self signed certificate / [aid certificate? Should it be a path? After providing only name, it gives error System.Security.Cryptography.CryptographicException: The system cannot find the file specified..

Yes, The parameter should be a file path, you can placed pfx file in AppData directory, And use Server.MapPath("~/App_Data/MyCert.pfx")

Related

OPC UA Certificate chain validation incomplete - OPC Foundation SDK

I've been struggling with this code for hours.
I need to connect to an OPC UA server (IP 192.168.7.118), it's a Siemens S7-1200 PLC.
I'm using the official OPC Foundation NuGet package and the following code:
static void Main(string[] args)
{
// Generate a client application
ApplicationInstance application = new ApplicationInstance();
application.ApplicationType = ApplicationType.Client;
// Load the configuration file
application.LoadApplicationConfiguration(#"./ConsoleReferenceClient.Config.xml", false).Wait();
ApplicationConfiguration m_configuration = application.ApplicationConfiguration;
m_configuration.SecurityConfiguration.AutoAcceptUntrustedCertificates = true;
// Connect to a server
// Get the endpoint by connecting to server's discovery endpoint.
// Try to find the first endopint without security.
EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint("opc.tcp://192.168.7.118", false);
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration) { };
// Create the session
Session session = Session.Create(m_configuration, endpoint, false, false, m_configuration.ApplicationName, (uint)m_configuration.ClientConfiguration.DefaultSessionTimeout, new UserIdentity(), null).Result;
}
I'm getting error Certificate chain validation incomplete on session.Create().
The config.xml file specifies:
<SecurityConfiguration>
<!-- Where the application instance certificate is stored (MachineDefault) -->
<ApplicationCertificate>
<StoreType>Directory</StoreType>
<StorePath>%CommonApplicationData%\OPC Foundation\pki\own</StorePath>
<SubjectName>CN=Quickstart Console Reference Client, C=US, S=Arizona, O=OPC Foundation, DC=localhost</SubjectName>
</ApplicationCertificate>
<!-- Where the issuer certificate are stored (certificate authorities) -->
<TrustedIssuerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%appdata%\opc foundation\pki\issuer</StorePath>
</TrustedIssuerCertificates>
<!-- Where the trust list is stored -->
<TrustedPeerCertificates>
<StoreType>Directory</StoreType>
<StorePath>%appdata%\opc foundation\pki\trusted</StorePath>
</TrustedPeerCertificates>
<!-- The directory used to store invalid certficates for later review by the administrator. -->
<RejectedCertificateStore>
<StoreType>Directory</StoreType>
<StorePath>%appdata%\opc foundation\pki\rejected</StorePath>
</RejectedCertificateStore>
<!-- WARNING: The following setting (to automatically accept untrusted certificates) should be used
for easy debugging purposes ONLY and turned off for production deployments! -->
<AutoAcceptUntrustedCertificates>false</AutoAcceptUntrustedCertificates>
</SecurityConfiguration>
From Siemens Tia Portal, I exported the device certificate under trusted directory, and the issuer certificate under issuer directory. The issuer is the Tia Portal project itself.
I also tried to install both certificates with default Windows Certificate Management, but nothing worked.
I've worked with other OPC UA library in the past, but this is the first time I'm using the official OPC Foundation SDK and honestly I found the documentation a bit challenging to fully understand.
Any help would be much appreciated.
I worked around the problem with the following code:
// Get server certificate
var rawCertificate = endpointDescription.ServerCertificate;
CertificateIdentifier serverCertificate = new(rawCertificate);
// Add server certificate to trusted peers and trusted issuers
configuration.SecurityConfiguration.TrustedPeerCertificates.TrustedCertificates.Add(serverCertificate);
configuration.SecurityConfiguration.TrustedIssuerCertificates.TrustedCertificates.Add(serverCertificate);
This manages to manually add (code-behind instead of configuration file) the server certificate to trusted certificate store.
I don't know why, but I could not get it working loading configuration from file.

Using C#, how to programmatically determine if a certificate in a Windows certificate store has been disabled

I'm currently working on refining communications between mutually authenticated client/server applications using HTTPS. I am currently building validation logic into a C# client to help identify configuration issues when a TLS connection fails. In verifying the connection, I validate that the root CA certificate presented by the server is installed on the client, in the appropriate store, and is valid. I'm using X509Store to pull the X509Certificate2, and validating it using X509Chain.
My issue is that the certificate will report as valid even if the certificate has been disabled via MMC. So the TLS connection will fail, despite the chain reporting as valid.
It's an unlikely case, but one I'd like to handle by reporting something like "Could not connect because root CA is disabled."
Could anyone point me in the direction of a .NET or Win32 call that could be made to determine the value of "Certificate Purposes" for a certificate? Or to read the "Certificate Status" for a cert?
I read through MSDN's listing of what's in the System.Security.Cryptography namespace, and started looking into CryptoAPI and CNG, but didn't find anything so far.
Thanks!
That dialog does not "disable" a certificate it disables it "for all purposes". What this means is it counts as having an empty Enhanced Key Usage extension for purposes of EKU validation.
Normally a root certificate (or an intermediate CA certificate) will not have an EKU extension, so if you do a chain build with any ApplicationPolicy value it will be a match. Once you set it to Disable for all purposes you'll get a chain error X509ChainStatusFlags.NotValidForUsage.
If you want to build something for validating TLS you'd check either the Server Authentication or Client Authentication EKUs (depending on what you're checking):
// Server EKU or Client EKU
Oid eku = forServer ? new Oid("1.3.6.1.5.5.7.3.1") : new Oid("1.3.6.1.5.5.7.3.2");
// Test if it's valid for that purpose
chain.ChainPolicy.ApplicationPolicy.Add(eku);
If you want to "Disable" a root CA altogether, add a copy of the certificate to the Disallowed store (called "Untrusted Certificates" in the UI). That will result in a chain build producing X509ChainStatusFlags.ExplicitDistrust.

How do I access X.509 certificates stored in a service account?

I'm trying to digitally sign a PDF document using Syncfusion PDF 10.4, like so:
PdfLoadedDocument document = new PdfLoadedDocument(inputStream);
PdfCertificate certificate = PdfCertificate.FindBySubject(certificateStoreType, certificateSubjectName);
PdfSignature signature = new PdfSignature(document, document.Pages[0], certificate, "Signatur");
signature.Bounds = new RectangleF(new PointF(5, 5), new SizeF(100, 100));
This works great for my local user account after installing a suitable certificate using MMC (adding the Certificates snap-in for My user account and storing it in Personal), but not for a service (choosing Service account this time, and picking my service). Running the same code results in no suitable certificate being found, i.e. certificate is null. Furthermore, PdfCertificate.GetCertificates() throws an AccessViolationException, which I assume is a bug on Syncfusion's end.
I can, however, reproduce the same problem without Syncfusion code:
var store = new System.Security.Cryptography.X509Certificates.X509Store("My");
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
foreach (var item in store.Certificates)
{
…
}
Run as my own user, the certificate shows up (as do all the others shown in MMC under Personal), but if I debug the service (by running it, then invoking System.Diagnostics.Debugger.Launch()), I only get a "CN=LOCAL SERVICE" certificate, which doesn't show up in MMC at all.
I'm assuming that I need to A) tell it to open the correct certificate store, or B) change something about the way the service is installed or run, such as giving it a different identity, enabling UserInteraction, etc. Currently, it runs using LocalService and with UserInteraction disabled.
From what I remember, Windows machine accounts (like LocalService) use the machine certificate store. This means that in your code, you have to access the store with StoreLocation.LocalMachine.
var store =
new System.Security.Cryptography.X509Certificates.X509Store(StoreLocation.LocalMachine);
Note that if you decide to run the service under specific identity, you should rather first login as the identity, then import the certificate to the Personal store and then, use StoreLocation.CurrentUser.
The answer appears to be that .NET doesn't support accessing service account certificate stores without P/Invoke or the like:
I don't think that any of the .NET APIs allow access to the Services Certificate store.
However, you can install the certificate into the CurrentUser store of the account that the service runs under.
I've changed the service to run under its own user (which doesn't need admin rights), ran mmc.exe as that user using runas, and imported the certificate to that user's personal store.
I ran into this problem, and to solve it had to allow the "Local Service" account to access the "Local Computer" certificate store using the tool "WinHttpCertCfg"
It is described in detail here:
https://support.microsoft.com/en-us/help/901183/how-to-call-a-web-service-by-using-a-client-certificate-for-authentication-in-an-asp-net-web-application

Installing client certificates in Windows Store XAML apps

I would like to use client certificate authentication in Windows Store XAML app. Using makecert i have created a self-signed CA and client certificates, the authentication works in IIS/ASP.NET + browser (IE10,Chrome, etc.) fine.
Now I wanted to use it in Windows Store app, but am unsure on how to actually install the certificate. I have a cert.pfx file that i imported to IE10.
Here is the code I use to consume HTTP service over SSL.
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
HttpClient client = new HttpClient(handler);
Not sure whats the difference between ClientCertificateOption.Automatic and ClientCertificateOption.Manual.
When I try to connect the certificate is not being presented to the server and i get 401 error I am guessing that the certificate is not present in app cert store and thus nothing is being sent to the server. How do I install the cert then?
Should I use CertificateEnrollmentManager.ImportPfxDataAsync() method? if so how can i convert .pfx to 'Base64-encoded PFX message'
Should pfx contain private key?
Or maybe I should use Certificates extension as described here: http://msdn.microsoft.com/en-us/library/windows/apps/hh464981.aspx#certificates_extension_content
The following code will load a pfx file and create a base64 encoded string that can be used by ImportPfxDataAsync method:
StorageFolder packageLocation = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFolder certificateFolder = await packageLocation.GetFolderAsync("Certificates");
StorageFile certificate = await certificateFolder.GetFileAsync("YourCert.pfx");
IBuffer buffer = await Windows.Storage.FileIO.ReadBufferAsync(certificate);
string encodedString = Windows.Security.Cryptography.CryptographicBuffer.EncodeToBase64String(buffer);
This assumes that you put your certificate in 'Certificates' folder.
You may want to have a look at http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/ this walks through end-to-end scenario of using client certificates in windows 8 app to communicate with asp.net web api.

How to load another's certificate to my local certificate store?

I have a certificate (.pem file) that is distributed by another service vendor. I downloaded the certificate from the vendor and saved it to my local drive. In my WCF client, I am trying to load this certificate from the local drive and it is giving me an error “The private key is not present in the X.509 certificate” when communicating with the service. I was told that I need to load this certificate to my local certificate store to resolve this error. Can anyone provide some directions? Thanks!
I have the below function to load certificate from the path specified in the file parameter.
public static X509Certificate LoadCertificate(string file)
{
try
{
return X509Certificate.CreateFromCertFile(file);
}
catch (System.Security.Cryptography.CryptographicException)
{
string filestr = File.ReadAllText(file);
StringBuilder sb = new StringBuilder(filestr.Remove(0, filestr.IndexOf("-----BEGIN CERTIFICATE-----")));
sb.Replace("-----BEGIN CERTIFICATE-----", "");
sb.Replace("-----END CERTIFICATE-----", "");
//Decode
try
{ //see if the file is a valid Base64 encoded cert
byte[] certBytes = Convert.FromBase64String(sb.ToString());
return new X509Certificate(certBytes);
}
catch (System.FormatException)
{
throw;
}
}
}
In my WCF client, it is loading the certificate that was created from LoadCertificate() function.
public X509Certificate Certificate { get; set; }
ClientCredentials loginCredentials = new ClientCredentials();
loginCredentials.UserName.UserName = this.UserId;
loginCredentials.UserName.Password = this.Password;
loginCredentials.ClientCertificate.Certificate = new X509Certificate2(this.Certificate);
Your code says you are trying to use the certificate to authenticate the client to the server, in addition to providing a username and a password. That's pretty bizarre but I guess possible. You will need the private keys associated with that certificate for that purpose, as the client will need them to encrypt the communication so the server can use the certificate to decrypt and verify that the client is legit. A .pem file can contain both public and private keys but maybe the one that was sent to you does not?
My guess is that really you only wanted the client to connect to a server that is using this certificate to identity itself and encrypt the communication. If so, all the client needs to do is import the certificate locally so it can compare against this local version when the server sends it when the client first connects to it.
Do to that, Microsoft made double clicking on a .pem file in a file browser start the certificate import wizard. But in case that does not work for you, here is the hard way:
Start - run - mmc
File - Add/Remove snap-in
Select "certificates" - click Add - choose Computer Account - Local computer
Close snap-in window with OK
Now browse to Certificates (Local computer) - Personal - Certificates
Right click - All Tasks - Import

Categories

Resources