Find certificate by thumbprint - c#

System can't find certificate by string thumbprint
var thumbprint = "‎2E7F6E8A0124E6745C3999EE15770C0A4931F342";
X509Certificate2 certificate = new X509Certificate2();
X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly);
var c = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false).OfType<X509Certificate>().FirstOrDefault();
this core returns null. But I try this too
foreach (X509Certificate2 mCert in store.Certificates)
{
var c= store.Certificates.Find(X509FindType.FindByThumbprint, mCert.Thumbprint, false).Count;
}
c is always 1 , so some problem is in characters. I copied this thumbprint value.

The following works for me:
public async Task<X509Certificate2> GetCertificate(string certificateThumbprint)
{
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.OfType<X509Certificate2>()
.FirstOrDefault(x => x.Thumbprint == certificateThumbprint);
store.Close();
return cert;
}

Related

Trying to access Azure Keyvault from .Net Framework project is hanging

I'm currently working on a 256 bit AES encryption API project for my job. One of the aspects of these encryption APIs is they need to access our Azure Keyvault to retrieve a key (we have different keys for different projects).
For some reason the .Net Framework project hangs when trying to access the key vault after the first successful execution. It will hang on this line: var key = client.GetKeyAsync($"https://automationkeys.vault.azure.net/keys/{product}").GetAwaiter().GetResult();
I have the same encryption API made using .Net Core and I'm able to execute calls multiple times in a row without issue.
After doing some reading I have a feeling it has to do with async / await but I don't know enough about all that to see where the problem is.
Here is my full KeyVaultAccessor class:
public static class KeyVaultAccessor
{
public static string GetKey(string product)
{
var keyValue = string.Empty;
try
{
var client = GetKeyVaultClient(<my_app_id>, <keyvault_cert_thumbprint>);
var key = client.GetKeyAsync($"https://automationkeys.vault.azure.net/keys/{product}").GetAwaiter().GetResult();
keyValue = key?.KeyIdentifier.Version;
if (string.IsNullOrEmpty(keyValue))
{
Assert.Fail($"Key was null or empty for product: {product}");
}
}
catch (Exception e)
{
Assert.Fail($"Error occurred while attempting to retrieve key for product: {product}. {e.Message}");
}
return keyValue;
}
private static KeyVaultClient GetKeyVaultClient(string appId, string thumbprint)
{
var keyVault = new KeyVaultClient(async (authority, resource, scope) =>
{
var authenticationContext = new AuthenticationContext(authority, null);
X509Certificate2 certificate;
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
var certificateCollection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (certificateCollection.Count == 0)
{
throw new Exception("<certificate name> not installed in the store");
}
certificate = certificateCollection[0];
}
finally
{
store.Close();
}
var clientAssertionCertificate = new ClientAssertionCertificate(appId, certificate);
var result = await authenticationContext.AcquireTokenAsync(resource, clientAssertionCertificate);
return result.AccessToken;
});
return keyVault;
}
}
Not quite sure your root reason, but if you want to get a key in Azure keyVault by ClientCertificateCredential and local cert, try the code below which works perfectly for me:
using System;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Keys;
namespace key_vault_console_app
{
class Program
{
static void Main(string[] args)
{
var keyVaultName = "";
var tenantID = "";
var appID = "";
var certThumbprint = "";
var kvUri = $"https://{keyVaultName}.vault.azure.net";
var certCred = new ClientCertificateCredential(tenantID, appID, GetLocalCert(certThumbprint));
var client = new KeyClient(new Uri(kvUri), certCred);
Console.Write(client.GetKey("<your key name>").Value.Key.Id);
}
public static X509Certificate2 GetLocalCert(string thumbprint)
{
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
var certificateCollection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (certificateCollection.Count == 0)
{
throw new Exception("cert not installed in the store");
}
return certificateCollection[0];
}
finally
{
store.Close();
}
}
}
}
Result:

c# .net core certificate chain on linux fails, windows works

I create a self sign certificate in debug with .net core and store it into the certificate store (my/root). When the app runs under windows the certificate cain is okay but under linux (ubuntu) the certificate chain check fails.
Certificate creation code is:
public static X509Certificate2 BuildSelfSignedServerCertificate()
{
using RSA rsa = RSA.Create(2048);
var request = new CertificateRequest("CN=My_Certificate",
rsa,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment |
X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));
request.CertificateExtensions
.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection {
new Oid("1.3.6.1.5.5.7.3.1"),
new Oid("1.3.6.1.5.5.7.3.2") }, false));
var certificate = request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)),
new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
LogFileLevelInformation("Created new self sign certificate.");
return certificate;
}
Then I add the certificate at my and root stores:
public static void CreateCert()
{
var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certificateStore.Open(OpenFlags.ReadWrite);
bool result = certificateStore.Certificates.OfType<X509Certificate2>()
.Any(cert => cert.Subject.Contains("My_Certificate"));
if (result)
return;
var cert = BuildSelfSignedServerCertificate();
certificateStore.Add(cert);
certificateStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser, OpenFlags.MaxAllowed);
certificateStore.Open(OpenFlags.MaxAllowed);
certificateStore.Add(cert);
LogFileLevelInformation("New certificate added to store.");
}
then later I verify the chain:
private X509Certificate2 VerifyCertificateChain(X509Certificate2 certificate)
{
var chain = new X509Chain();
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
var chainBuilt = chain.Build(certificate);
if (chainBuilt)
{
LogDebugLevelInformation("The certificate chain is validated.")
return certificate;
}
return null;
}
the certificate check under windows with
var chainBuilt = chain.Build(certificate);
returns with result true, but when the same code runs under linux it returns false.
the certificate is available on linux under:
/root/.dotnet/corefx/cryptography/x509stores/root
and
/root/.dotnet/corefx/cryptography/x509stores/my
chain.StatusCode = "unable to get local issuer certificate"
Any idea why it is failing under linux?

Adding an SSL Certificate programmatically to get working https

I have some code that is supposed to add an ssl certifacate to a port. It does say it has succesfully added a certificate, but when i host the website and then type in the localhost url (localhost:{port}) the page keeps loading. I don't understand why it doesn't work.
I already tried to host the website without ssl and that worked fine so that's not the problem.
public static class Certificate
{
public static void Standard(int port)
{
var certSubjectName = "HelloMyNameIsHank";
var expiresIn = TimeSpan.FromHours(1);
var cert = GenerateCert(certSubjectName, expiresIn);
Console.WriteLine("Generated certificate, {0}Thumbprint: {1}{0}", Environment.NewLine, cert.Thumbprint);
RegisterSslOnPort(port, cert.Thumbprint);
Console.WriteLine($"Registerd SSL on port: {port}");
}
private static void RegisterSslOnPort(int port, string certThumbprint)
{
var appId = Guid.NewGuid();
string arguments = $"http add sslcert ipport=0.0.0.0:{port} certhash={certThumbprint} appid={{{appId}}}";
ProcessStartInfo procStartInfo = new ProcessStartInfo("netsh", arguments);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
var process = Process.Start(procStartInfo);
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
Console.WriteLine(line);
}
process.WaitForExit();
}
public static X509Certificate2 GenerateCert(string certName, TimeSpan expiresIn)
{
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
var existingCert = store.Certificates.Find(X509FindType.FindBySubjectName, certName, false);
if (existingCert.Count > 0)
{
store.Close();
return existingCert[0];
}
else
{
var cert = CreateSelfSignedCertificate(certName, expiresIn);
store.Add(cert);
store.Close();
return cert;
}
}
public static X509Certificate2 CreateSelfSignedCertificate(string subjectName, TimeSpan expiresIn)
{
// create DN for subject and issuer
var dn = new CX500DistinguishedName();
dn.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_NONE);
// create a new private key for the certificate
CX509PrivateKey privateKey = new CX509PrivateKey();
privateKey.ProviderName = "Microsoft Base Cryptographic Provider v1.0";
privateKey.MachineContext = true;
privateKey.Length = 2048;
privateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE; // use is not limited
privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
privateKey.Create();
// Use the stronger SHA512 hashing algorithm
var hashobj = new CObjectId();
hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
AlgorithmFlags.AlgorithmFlagsNone, "SHA512");
// add extended key usage if you want - look at MSDN for a list of possible OIDs
var oid = new CObjectId();
oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server
var oidlist = new CObjectIds();
oidlist.Add(oid);
var eku = new CX509ExtensionEnhancedKeyUsage();
eku.InitializeEncode(oidlist);
// Create the self signing request
var cert = new CX509CertificateRequestCertificate();
cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, "");
cert.Subject = dn;
cert.Issuer = dn; // the issuer and the subject are the same
cert.NotBefore = DateTime.Now;
// this cert expires immediately. Change to whatever makes sense for you
cert.NotAfter = DateTime.Now.Add(expiresIn);
cert.X509Extensions.Add((CX509Extension)eku); // add the EKU
cert.HashAlgorithm = hashobj; // Specify the hashing algorithm
cert.Encode(); // encode the certificate
// Do the final enrollment process
var enroll = new CX509Enrollment();
enroll.InitializeFromRequest(cert); // load the certificate
enroll.CertificateFriendlyName = subjectName; // Optional: add a friendly name
string csr = enroll.CreateRequest(); // Output the request in base64
// and install it back as the response
enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); // no password
// output a base64 encoded PKCS#12 so we can import it back to the .Net security classes
var base64encoded = enroll.CreatePFX("", // no password, this is for internal consumption
PFXExportOptions.PFXExportChainWithRoot);
// instantiate the target class with the PKCS#12 data (and the empty password)
return new System.Security.Cryptography.X509Certificates.X509Certificate2(
System.Convert.FromBase64String(base64encoded), "",
// mark the private key as exportable (this is usually what you want to do)
System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable
);
}
}
I want to be able to host my website with https. If anyone knows why this doesn't work please tell me.
I'm using httplistener for hosting. I don't want to use ASP.NET and/or IIS.
I'm not to familiar with ssl certificates so I would also really appreciate some code snippets even if it's just pseudo-code.

Why I don`t see a PIN prompt for SmartCard when I publish the webservice? C#, IIS

I want to sign an XML with X509 Certificate in C# Webservice.
Get the cert by thubmprint from x509Store
private static bool GetCert(string thumbprint)
{
GlobalCert = new X509Certificate2();
X509Store x509Store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
x509Store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certCollection = x509Store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
x509Store.Close();
if (certCollection.Count == 0) {
return false;
}
foreach (X509Certificate2 cert in certCollection)
{
GlobalCert = cert;
}
return true;
}
Signing the xml (user has to enter his PIN for the certificate)
private static void SignXml(XmlDocument xmlDoc)
{
SignedXml signedXml = new SignedXml(xmlDoc);
Reference reference = new Reference();
reference.Uri = "#signedContent";
signedXml.AddReference(reference);
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigC14NWithCommentsTransformUrl;
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(GlobalCert));
signedXml.KeyInfo = keyInfo;
if (GlobalCert.HasPrivateKey)
{
signedXml.SigningKey = GlobalCert.PrivateKey;
}
else
{
signedXml.SigningKey = GlobalCert.GetRSAPrivateKey();
}
signedXml.ComputeSignature();//Here the prompt for PIN pops up
XmlElement xmlDigitalSignature = signedXml.GetXml();
xmlDoc.FirstChild.FirstChild.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
}
POST the xml
Great... It works but only in DEBUG (localhost:2626).
When I publish the webservice (localhost:8080) the prompt for pin request dont pop up.
My AppPool Identity is set to LocalService.
Any help will be appreciated!

How to change issuer Name while creating X509Certificate2 in C#

I am working with creating X509Certificate2 certificate in my C#.net application. While creating certificate, how to set the issuer name? currently issuer name shows same as subject name.
Please help.
Hmm.
Finally I have used Bouncy Castle dll to create certificates.Using this, there is a method to set issuer name.
This is the fully code to generate x509Certificate and to store into Trusted People store:
private X509Certificate2 GeneratePFXFile(string certificate,string company,string email,string state,string locality,string username,string country)
{
X509Certificate2 cert = null;
try
{
var kpgen = new RsaKeyPairGenerator();
kpgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048));
var kp = kpgen.GenerateKeyPair();
var gen = new X509V3CertificateGenerator();
var certName = new X509Name("CN=" + certificate);
var issuer = new X509Name("C="+country+",O="+company+",OU=LBC Mundial Corp.USA,E="+email+",L="+locality+",ST="+state);
var serialNo = BigInteger.ProbablePrime(120, new Random());
gen.SetSerialNumber(serialNo);
gen.SetSubjectDN(certName);
gen.SetIssuerDN(issuer);
gen.SetNotAfter(DateTime.Now.AddYears(50));
gen.SetNotBefore(DateTime.Now);
gen.SetSignatureAlgorithm("MD5WithRSA");
gen.SetPublicKey(kp.Public);
gen.AddExtension(
X509Extensions.AuthorityKeyIdentifier.Id,
false,
new AuthorityKeyIdentifier(
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(kp.Public),
new GeneralNames(new GeneralName(certName)),
serialNo));
gen.AddExtension(
X509Extensions.ExtendedKeyUsage.Id,
false,
new ExtendedKeyUsage(new ArrayList() { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1") }));
var newCert = gen.Generate(kp.Private);
byte[] pfx = DotNetUtilities.ToX509Certificate(newCert).Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pfx, (string)null);
X509Store store = new X509Store((StoreName)StoreName.TrustedPeople, (StoreLocation)StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
cert = new X509Certificate2(pfx,(string)null, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
store.Add(cert);
store.Close();
}
catch (Exception ex)
{
ShowError(ex.Message);
return null;
}
return cert;
}

Categories

Resources