How can I access the "certificate enrollment requests" store in C#? - c#

How do I access via C# the keys stored in the Certificate Enrollment Requests store?
I tried using:
var requestCertStore = new X509Store("Certificate Enrollment Requests",
StoreLocation.LocalMachine);
requestCertStore.Open(OpenFlags.MaxAllowed);
var certs = requestCertStore.Certificates;
but the certs collection does not contain the certificate I'm looking to access in the "Certificate Enrollment Requests" store. I also don't see any StoreName enum that corresponds to this store, so using the new X509Store(StoreName storeName, StoreLocation storeLocation) constructor isn't an option.
Is it not possible to retrieve these certs via C#/.NET?

The solution is to use "REQUEST" instead of "Certificate Enrollment Requests":
var requestCertStore = new X509Store("REQUEST", StoreLocation.LocalMachine);
requestCertStore.Open(OpenFlags.MaxAllowed);
var certs = requestCertStore.Certificates;
I found the hint here: Delete a pending certificate request.

Related

how to get X509Certificate using Friendly Name rather than Thumbprint?

I have a certificate which having Friendly Name as well and I want to get the certificate using Friendly Name rather than Thumbprint. I don't see any method like FindByFriendlyName..., how to do this?
var thumbprint ="f454......"
var friendlyName = "ASP.NET Core...."
X509Certificate2Collection signingCerts = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
X509Certificate2Enumerator enumerator = signingCerts.GetEnumerator();
Built-in search can be done only against static fields, that never change for any given certificate. Friendly name is not static, it can be changed for any single certificate unlimited times. Thus, I would STRONGLY recommend to not rely on cert friendly name. EVER.
you can do manual filtering, by enumerating all certificates and checking for matching certificate, but it is very poor and fragile way.
If you want something that's a stable search value across cert renewals and is easy to read, you might try the subject name (if the cert has a decent subject name, other than localhost or something):
var subject ="org name signing cert......"
var friendlyName = "ASP.NET Core...."
X509Certificate2Collection signingCerts = store.Certificates.Find(X509FindType.FindBySubjectName, subject, true);
X509Certificate2Enumerator enumerator = signingCerts.GetEnumerator();
(You probably only want valid/non-expired certs, too, so use true for the last param.)
I have a use case to look up by FriendlyName. The code is below
//store variable
X509Store store;
//certificate variable
X509Certificate2 cert;
//init store using root and local machine
store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
//open store for read only
store.Open(OpenFlags.ReadOnly);
//find cert using linq
cert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(x => x.FriendlyName == "cert-friendlyname-here");
//close store
store.Close();

Loading Azure certificate when NOT using custom domain names

As I understand if someone doesn't want to use a custom domain name and instead plans on using *.azurewebsite.net domain assigned to the website by Azure, then HTTPS is already enabled with a certificate from Microsoft(I know this is not as secure as using a custom domain name). How would be I able to load this certificate programmatically. Currently I use the following method to load a certificate from local machine or Azure :
public static X509Certificate2 LoadFromStore(string certificateThumbprint,bool hostedOnAzure)
{
var s = certificateThumbprint;
var thumbprint = Regex.Replace(s, #"[^\da-zA-z]", string.Empty).ToUpper();
var store = hostedOnAzure ? new X509Store(StoreName.My, StoreLocation.CurrentUser) : new X509Store(StoreName.Root, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates;
var signingCert = certCollection.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (signingCert.Count == 0)
{
throw new FileNotFoundException(string.Format("Cert with thumbprint: '{0}' not found in certificate store. Also number of certificates in the sotre was {1}", thumbprint, store.Certificates.Count));
}
return signingCert[0];
}
finally
{
store.Close();
}
}
I assume the culprit is the following line of code :
new X509Store(StoreName.My, StoreLocation.CurrentUser)
because when I get an exception it tells me there is no certificate in the store although I pass the correct certificate Thumbprint(I grab the thumbprint from Chrome manually).
You will not be able to access this certificate programmatically in your WebApp as this certificate is not really installed on the Azure WebApp. Azure WebApps have a front-end server which does a "kind of" SSL Offloading so the WebApp actually never has access to this particular certificate. Why exactly you want to read this certificate though ?
Typically if there is a need for certificates in WebApps, you would install client certificates and pass them to services for Authentication as mentioned in https://azure.microsoft.com/en-us/blog/using-certificates-in-azure-websites-applications/ and those certificates you can access programmatically (code snippet mentioned in the same article)
But I am not sure what exactly you want to achieve by reading the server certificate

c# X509Certificate2 add certificate how mark as exportable

I have a .NET 4.0 program which is running localhost on port 9000.
I want to support SSL and have a .pfx certificate to import.
Because the program is running at multiple computers the programm itself is responsible
to store the certificate and register the its port.
When imported and registered by the program, everything works.
But when I reboot the computer the https connection does not work any.. more..
The event viewer gives the following error:
A fatal error occurred when attempting to access the SSL server
credential private key. The error code returned from the
cryptographic module is 0x8009030D. The internal error state is 10001.
and
An error occurred while using SSL configuration for endpoint
0.0.0.0:9000. The error status code is contained within the returned data.
I found some solutions which state that you need to mark the certificate as 'exportable' while importing
but I can't find how I do that in code.
Website 1 and Website 2
Storing the certificate:
String path = String.Concat(IOHelper.AssemblyPath, #"\certificate.pfx");
X509Certificate2 cert = new X509Certificate2(path, "password");
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
if(!store.Certificates.Contains(cert))
{
store.Add(cert);
}
Registering the host:
netsh http add sslcert ipport=0.0.0.0:9000 certhash=<cert hash> appid=<app id>
To mark a X509Certificate2 as exportable is actually quite simple. You add a third parameter (X509KeyStorageFlags.Exportable) which indicates that the certificate is exportable.
var cert = new X509Certificate2(path, "password", X509KeyStorageFlags.Exportable);
Further to Madeillei's answer, you can pass the following flags:
var cert = new X509Certificate2(path, "password", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable| X509KeyStorageFlags.MachineKeySet);
If you are storing the cert in the CurrentUser store rather than in the LocalMachine store, do the following:
var cert = new X509Certificate2(path, "password", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable| X509KeyStorageFlags.UserKeySet);
The Key set flags indicate the following:
//
// Summary:
// Private keys are stored in the current user store rather than the local computer
// store. This occurs even if the certificate specifies that the keys should go
// in the local computer store.
UserKeySet = 1,
//
// Summary:
// Private keys are stored in the local computer store rather than the current user
// store.
MachineKeySet = 2,
The private key needs to be in the same place as the rest of the certificate for it to work.

How to Find Certificates by Issuer

I'm trying to loop through the Certificate store and identify if a certificate has a specific issuer. I located this article which provides the example of calling the certificates issuer:
Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine, x509.Issuer);
But their example appears to require an input certificate. Is it possible to loop through the Certificates to identify if there are any on a machine that have the specific issuer?
Something like:
ForEach(cert in x509certificate2.store)
{
if (cert.issuer == SpecificIssuer)
{
console.writeline(cert.ToString());
}
}
The certificates I'm trying to isolate will belong to specific stores (?) such as [Console Root\Certificates (Local Computer)\Personal\Certificates] if it is possible to further filter the loops scope to just these specific stores.
You can use the Certificates.Find(), use the StoreName to specify your own store.
X509Store Store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
Store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection CertColl = Store.Certificates.Find(X509FindType.FindByIssuerName, "Microsoft",true);
foreach (X509Certificate2 Cert in CertColl)
Console.WriteLine("Cert: " + Cert.IssuerName.Name);

Check if end user certificate installed in windows keystore?

Is there any way to check in C# if the PKI end user certificate is installed in the user windows keystore (Personal)? (An exception would do?) I would be passing some attribute like Name.
You can use the X509Store class to search for certificates on the system. Below code sample finds a certificate by subject name of "XYZ" in the Current User's Personal Store.
System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly); // Dont forget. otherwise u will get an exception.
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectName,"XYZ",true);
if(certs.Count > 0)
{
// Certificate is found.
}
else
{
// No Certificate found by that subject name.
}

Categories

Resources