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
Related
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.
I'm trying to set a Certificate for identityserver and it keeps failing with a "no access to private key error".
Taking it out of identityserver, the following code throws an access denied error
static X509Certificate2 GetCertificateFromDisk()
{
using (var stream = File.Open(#"patht-to-pfx", FileMode.Open))
{
var cert = new X509Certificate2(ReadStream(stream), "password", X509KeyStorageFlags.MachineKeySet);
return cert;
}
}
When running the code as administrator it works fine, not when running it under my own account. Eventually I want to run it as localsystem.
I even added 'Everyone' under the certificates private key permissions in my local computer certificate store,
screenprint here
... still I get the exception.
What is wrong here? Going Crazy about it
Update
Great tips from CryptoGuy in the answer below. Important note: Opening the file is not correct only Identityserver3 still failed when getting the certificate from the store. What made it work was to regenerate the certificate using Keith Sparkjoy's tool SerfCert. My previous certificate was generated using powershell. So keep in mind that powershell certificates have issues with accessibility of private key. Thanks to Keith for the tool!
There are few things to consider.
1) you are performing write access to Local Machine store. X509KeyStorageFlags.MachineKeySet attempts to save private key to Local Machine store. Therefore, you need administrator permissions to write there. You should remove this flag to perform read-only access
2)
Documentation says that adding permissions in MMC (manage private key-option on a certificate) should allow this, but it doesn't seem to work
it works on an already saved private keys.
What you really should do is to import certificate and private key to Local Machine store and then configure your application to reference installed certificate.
3) if your application runs under unpriveleged account and the key don't need to be shared, then you should use Current User store.
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")
I am Developing Asp.net application in Which I Want to Read Current user Certificate From x509Store...Its Working Fine For my Local Machine .. When I Deploy application on IIS...than I Can't Pick Current user Certificate which I will Use for application authentication...
This Is Following Code for Working Fine for Local System..
public X509Certificate2 selectCert(StoreName store, StoreLocation Location , string windowTitle, string windowMsg)
{
X509Certificate2 certSelected = null;
X509Store x509Store = new X509Store(store);
x509Store.Open(OpenFlags.ReadWrite);
X509Certificate2Collection col = x509Store.Certificates;
X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(col, windowTitle, windowMsg, X509SelectionFlag.SingleSelection);
if (sel.Count > 0)
{
X509Certificate2Enumerator en = sel.GetEnumerator();
en.MoveNext();
certSelected = en.Current;
}
x509Store.Close();
return certSelected;
}
Here x509Store.Certificates Return Some Collection of Current User Certificate..
But when I Run Deployed application In ISS. x509Store.Certificates Give Empty Collection at Sever...For Current User & I've checked my personal store (via certmgr.mmc) and I'm sure that I have the certificates...Crucial Problem Please Solve Out...I can't Understand .. What is happened...
Thanx
Your IIS app must be running under the ASP .net built in account in IIS, which does not have permission to access the certificate stores.
One way to solve it is to change the user to some other wihch has permissions, but it will lead to security issues.
A better approach but more complex is to have a service executed with elevated privileges which accepts incomming TCP/UDP/pipes connections from local machine, retrieves the certificates and pass them out, in this way you can call safely that service from your asp.net page without giving it elevated permissions
If you have installed the certificate as CurrentUser, only services running under your username will have access.
In order to access the certificate for all usernames in a machine, you will have to install the certificate as LocalMachine and retrieve the same using LocalMachine
for more info read
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.