How to install a certificate to personal store without password? - c#

I am kind of new to certificates and all that stuff.
I have a web application that sends a https request by iframe (it has to be https due to the application itself is also https) to a .NET application running on the client which has an HttpListener listening on https://localhost:[port] so the client app can receive a "do something now" from a browser click.
When I install the client app, I install the *.crt file to the Root-Store and bind it to our port:
X509Certificate2 certificateFromCrtFile = new X509Certificate2(X509Certificate2.CreateFromCertFile(crtPath));
X509Store rootStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
rootStore.Open(OpenFlags.ReadWrite);
rootStore.Add(certificateFromCrtFile);
rootStore.Close();
string crtThumbprint = certificateFromCrtFile.Thumbprint;
string netshParams = string.Format("http add sslcert ipport=0.0.0.0:[port] certhash={0} appid={{{1}}}", crtThumbprint, Guid.NewGuid());
Utilities.StartProcess("netsh.exe", Environment.SystemDirectory, netshParams, true, true);
Now, before that, I have to install the certificate also in the personal store because my "server" in that case is the HttpListener on the same client.
Okay, so I could do it the following way:
X509Certificate2 certificateFromPfxFile = new X509Certificate2(pfxPath, "pwd");
X509Store personalStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
personalStore.Open(OpenFlags.ReadWrite);
personalStore.Add(certificateFromPfxFile);
personalStore.Close();
In this case I have to write the *.pfx password in clear text in code.
And if I understood correctly, with this password you can easily get the private key, right?

When storing in PFX the private key is encrypted with your password. So when you attempt to install it to a personal store to indicate your ownership of this certificate, you have to present the password. That's mandate.
The trusted root authority is different, as you don't own the certificates. You just install the crt files to say that you trust whoever owns them.

Related

C# X509Store Access Web Hosting

I have an SSL cert stored in the Web Hosting Folder of the Certificate Store. I cannot seem to be able to access this store from C#. Does anyone know how to do this?
X509Store store = new X509Store("Web Hosting");
store.Open(OpenFlags.ReadOnly);
var t = store.Certificates.GetEnumerator();
while (t.MoveNext())
{
//this is always empty
}
Additional Detail
I need this cert for a gRPC service that I am writing. gRPC requires a certificate for the SSL connection. In the mean time aka development I am using Let's Encrypt to generate the certificate. When the cert was generated the cert was put into the Web Hosting folder of the cert store.
It turns out you can drag and drop the certs to a different location in the cert manager. I relocated the cert to the Personal folder and I was able to access it by:
X509Store store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
Try removing the space; e.g., try the name as webhosting (no space)
In PowerShell, to display certs in this store location:
dir cert:\localmachine\webhosting

Pair Certificate Enrollment Request key and X509Certificate2

I'm migrating a tool that creates Certificate Enrollment Request (certmgr.msc) that prompts a security dialog to assign it a password, then send that request to the CA and later the CA sends back a Base 64 encoded certificate. Everything is fine.
Now, that i have that b64string, i can convert it to a certificate using
var bytes = Encoding.UTF8.GetBytes(b64string);
var certificate = new X509Certificate2(bytes);
the thing is that i need to install that certificate in CurrentUser/Personal store to sign transactions, but i can't because the private key is not within the installed certificate.
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();
I think i must set the password withing the X509Certificate2 constructor, but how could i get that password? Or how could i pair the certificate request and the installed certificate?
I have some old C code that uses XEnroll i think, that does what i want in 1 line:
hr = m_pXEnroll->raw_acceptPKCS7( PKCS7 );
What i'm doing wrong? Maybe my focus is incorrect
I made this up using CertEnrollLib.
As #Crypt32 pointed, it is just as easy as IX509Enrollment.InstallResponse(...)
This is my code:
CX509Enrollment objEnroll = new CX509EnrollmentClass();
objEnroll.Initialize(X509CertificateEnrollmentContext.ContextUser);
objEnroll.InstallResponse(InstallResponseRestrictionFlags.AllowNone, pkcs7, EncodingType.XCN_CRYPT_STRING_BASE64, null);
In my case, for this code to work i have to have a Certificate Enrollment Request, that i generated using the same lib. I'll post the link only cause it's not directly related to this topic.
https://www.sysadmins.lv/retired-msft-blogs/alejacma/how-to-create-a-certificate-request-with-certenroll-and-net-csharp.aspx
I don't know if there is a more pure C# way of doing this in the framework version i'm using (4.0), but this worked for me.

C#: How to invoke a SOAP service requiring client-side authentication with certificates installed at runtime

I have an application deployed to IIS that needs to invoke a SOAP service. It's using WCF from .NET Framework. That SOAP service requires that requests made be authenticated with a client-side certificate which is given at runtime. Admin users of the application can update the used certificate in a back-office. The goal is for autonomy and the certificate lifecycle management be independent from IIS or the underlying system so using the machine certificate store is not an option.
Here's the initial code:
var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
var client = new ServiceReference1.myClient(binding, new EndpointAddress(serviceUrl));
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var certificate = new X509Certificate2(certificateBinary, certificatePassword);
client.ClientCredentials.ClientCertificate.Certificate = certificate;
//use the client
var result = client.myMethod(new ServiceReference1.MethodRequest());
certificateBinary is the result of loading a PFX file containing the full certificate chain (client certificate, intermediate and root CAs) and certificatePassword the password used to create that file.
But the request is rejected by the server. From looking at Wireshark, it seems only the client-certificate is sent. This is different from what happens if we install the PFX on the machine store which works fine.
So the next step I tried was to install the certificates at runtime. First load them:
X509Certificate2Collection collection = new X509Certificate2Collection();
try {
collection.Import(ssCertificateFile, ssPassword, X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet);
}
Then identify what kind of certificates they are and finally installing them on the current user store:
private static void InstallCertificates(X509Certificate2Collection clientCerts, X509Certificate2Collection intermediateCAs, X509Certificate2Collection RootCAs) {
using (X509Store personalStore = new X509Store(StoreName.My, StoreLocation.CurrentUser)) {
personalStore.Open(OpenFlags.ReadWrite);
personalStore.AddRange(clientCerts);
}
using (X509Store intermediateStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser)) {
intermediateStore.Open(OpenFlags.ReadWrite);
intermediateStore.AddRange(intermediateCAs);
}
using (X509Store trustedCAsStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser)) {
trustedCAsStore.Open(OpenFlags.ReadWrite);
trustedCAsStore.AddRange(rootCAs);
}
}
This fails when installing the root CAs in trusted root certificate authorities (StoreName.Root) with:
System.Security.Cryptography.CryptographicException: The request is not supported.
at System.Security.Cryptography.X509Certificates.X509Store.Add(X509Certificate2 certificate)
at System.Security.Cryptography.X509Certificates.X509Store.AddRange(X509Certificate2Collection certificates)
at OutSystems.NssCertificationExtremeXP.CssCertificationExtremeXP.InstallCertificates(CertificatesClassifier certificates)
so only the client certificate and the intermediate CAs get installed and at runtime apparently this is not enough.
But if I take the exact same code as it is and run it with in a separate C# project, when installing the root CAs there's a confirmation dialog
and if I click OK the certificate is installed.
From here and here, it looks like every time we want to install something in the user Trusted Root Certificate Authorities, that prompt happens and it probably is not supported on the context of a non-GUI usage.
The problem is that even if I don't install the root CA in the store, I can successfully call the SOAP service when running this stand-alone app, only when running under IIS this fails.
Does anyone know why this happens and how to solve it?

How I can get an azure management certificate?

I have a console application running on an Azure cloud service VM that need getting a management certificate.
My certificate is loaded on SETTINGS/CERTIFICATE but what should I do next?
I tried something like this:
X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
certStore.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates
.Find(X509FindType.FindByThumbprint, certificateThumb, false);
X509Certificate2 certificate = certCollection[0];
Maybe I don't understand how works SETTINGS/CERTIFICATE but I only get an error message saying there are no certificate having this thumbprint.
EDIT: I complete my question.
Is this enough to make a declaration in SETTINGS/CERTIFICATE?
I answer my question.
In fact we have 2 way to use management certificate.
create a publishsetting file with the powershell command get-AzurePublishsettingsFile. The command adds a .cer certificate in management store as well. We just have to deserialize the base 64 certificate found into the file and add it in the credentials
create a certificate with makecert. Load the .cer in the azure management store and the .pfx in the local store from where the client application is installed
some links:
http://www.wadewegner.com/2011/11/programmatically-installing-and-using-your-management-certificate-with-the-new-publishsettings-file/

Can't make BITS upload work with client certificate authentication

I have an IIS extension for BITS with upload enabled on the server (Win2008) and a C# .NET4 client running as a windows service on the client machine (Win8.1)
The BITS upload without the certificate auth is working fine.
I have generated a self-signed root cert, added it to TrustedCA storage on both machines, generated child client and server certs, added them to the respective storages. Both are displayed as valid and trusted in the MMC console.
However, when I try to use client cert authentication (setting "Require client certificate" in the IIS and adding the certificate to the BITS job on the client), the client certificate does not seem to be received by IIS.
The code I'm using to set the cert on client is:
var httpOptions = (IBackgroundCopyJobHttpOptions) job2;
httpOptions.SetClientCertificateByName(certificate.certLocation, certificate.certStoreName, certificate.certSubjectName);
The certLocation is
BG_CERT_STORE_LOCATION.BG_CERT_STORE_LOCATION_LOCAL_MACHINE
since the client certificate is installed into LocalMachine and the service is running as LocalSystem.
Additionally, right after I have called SetClientCertificateByName, I try to get it back:
string stName, stLocation;
var hash = new IntPtr();
httpOptions.GetClientCertificate(out loc, out stName, hash, out stLocation)
But it returns empty values.
I have tried to check the certificate presence via:
var store = new X509Store(certificate.certStoreName, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindBySubjectName, certificate.certSubjectName, true)
and the certificate is indeed there.
I have also tried using WinHttpCertCfg.exe (no errors, but nothing changed) and FindPrivateKey.exe (says "Unable to obtain private key file name") to grant the access to the cert's private key to the LocalSystem account.
I'm out of ideas on this one. Any insight would be very appreciated.

Categories