I am trying to add a certificate to a web request to connect to Azure services.
My code looks like this:
string certThumbprint = "thumbprint";
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint, certThumbprint, false);
Now I can confirm that the certificate does exist and the thumbprint is correct. However certCollection comes back empty.
Any ideas?
Update: here is how I open the cert store
certStore.Open(OpenFlags.ReadOnly);
You probably have a hidden character or two at the very beginning of your thumbprint. I've made this mistake many times before when copying the thumbprint from the certificate manager in MMC. Here is a link for more information on this issue.
http://support.microsoft.com/kb/2023835
A safe way to get the certificate thumbprints of the Personal Certificates store is to use an elevated instance of PowerShell.
PS C:\> dir cert:LocalMachine\My | select Thumbprint, FriendlyName, Subject
I encountered the same issue today, while it's possible that there are hidden characters before and after the thumbprint it's also possible that if your debugging runs under a different user, the StoreLocation.CurrentUser isn't the same Store as the one you open in Windows.
I had this issue running in Service Fabric on localhost
Related
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
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.
I hope I can explain this correctly. I inherited a couple of windows applications that need a certificate installed to the local cert store in order to access an Azure Key Vault's Secret to do what the applications do. Currently everything is working correctly. The cert in Azure is set to expire on 10/31/2019.
A new certificate has been created with an expiration in September of 2020.
When I had these applications dumped on me I was give the cert to use but it has a .p12 extension. I can only export the new Azure certificate as .cer or .pfx.
When I install the newly exported cert as either .pfx or .cer the applications fail. If I install the old cert with .p12 extension they work.
Both apps use the code below to get (I think) the local cert that is current via the "Issuer" which is CN = Value. I've checked both the old and new values of "Issuer/CN =" and they are identical.
Does the cert exported in Azure need to have a .p12 extension? If so how do I do that.
If the cert in Azure exported is okay as a .pfx where might my problem(s) be?
C# code in apps that get local cert to in turn gets the necessary Azure secret to do the work:
private static X509Certificate2 ReadCertificateFromStore(string certName)
{
X509Certificate2 cert = null;
try
{
using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates;
// Find unexpired certificates.
X509Certificate2Collection currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
// From the collection of unexpired certificates, find the ones with the correct name.
X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, false);
// Return the first certificate in the collection, has the right name and is current.
cert = signingCert.OfType<X509Certificate2>().OrderByDescending(c => c.NotBefore).FirstOrDefault();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return cert;
}
First .p12 as well as .pfx are extension for the PKCS#12 format.
Both apps use the code below to get (I think) the local cert that is current via the "Issuer" which is CN = Value. I've checked both the old and new values of "Issuer/CN =" and they are identical.
Based on your code that is not true
// From the collection of unexpired certificates, find the ones with the correct name.
X509Certificate2Collection signingCert =
currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, false);
It says FindBySubjectDistinguishedName which means that the subject of both certificates need to be exactly the same. Here is an example:
And another one with multiple elements in the subject:
You could also install both certificates and play around to figure the parameters to get the right certificate. I converted parts of your code to PowerShell:
$store =
new-object System.Security.Cryptography.X509Certificates.X509Store( `
[System.Security.Cryptography.X509Certificates.StoreName]::My, `
[System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser);
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly);
$signingCert =
$store.Certificates.Find(
[System.Security.Cryptography.X509Certificates.X509FindType]::FindBySubjectDistinguishedName,
"CN=...", `
$false);
$signingCert
Mystery solved. In addition to installing the certificate on the machines in question you also need to register the cert (.cer portion) in Azure's App Registrations.
I have written some lines of code which will delete certificates from Certificate Store before installing a new one if that certificate already exists, as below:
X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite | OpenFlags.IncludeArchived);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectName, "CertName", false);
if (certs.Count > 0)
{
foreach (var cert in certs)
{
store.Remove(cert);
}
}
But, each time a certificate will be detected before it is deleted it promts the user to press yes so the cert is deleted. Is it possible to delete the certs without asking the user?
Is it possible to delete the certs without asking the user?
the short answer is NO. Certificate management (add/remove certs) in the Current User\Trusted Root CAs requires explicit user consent. This behavior is hardcoded in the crypt32.dll library.
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/