Reputation: 20761
I need to build a self-signed x509 certificate that is recognized valid on my computer through C# code.
If required, this can be ran with admin privileges.
My current code is the following
public static X509Certificate2 GenerateCertificate(string name)
{
string subjectName = $"CN={name}";
using (RSA rsa = RSA.Create(2048))
{
CertificateRequest req = new CertificateRequest(
subjectName,
rsa,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
req.CertificateExtensions.Add(
new X509BasicConstraintsExtension(false, false, 0, false));
req.CertificateExtensions.Add(
new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation,
false));
req.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.8")
},
true));
req.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(req.PublicKey, false));
return req.CreateSelfSigned(
DateTimeOffset.UtcNow.AddDays(-1),
DateTimeOffset.UtcNow.AddYears(50));
}
}
public static X509Certificate2 GetOrCreateCertificate(string serverName)
{
using (X509Store store = new X509Store(StoreLocation.LocalMachine))
{
X509Certificate2 certificate;
store.Open(OpenFlags.ReadWrite);
X509Certificate2Collection certificateCollection = store.Certificates.Find(X509FindType.FindBySubjectName, serverName, true);//With true, my certificates are not returned
if (certificateCollection.Count > 0)
{
certificate = certificateCollection[0];
return certificate;
}
certificate = GenerateCertificate(serverName);
store.Add(certificate);
return certificate;
}
}
Currently, if I go in the windows MMC, certificate snap-in, I see the certificate, but it is considered as invalid.
What did I miss?
EDIT
Upvotes: 0
Views: 815
Reputation: 33266
The problem that you're having seems to be that the system doesn't trust the new certificate.
In order to be trusted, the root of a certificate chain must be represented in one of the following stores:
(there are also some other stores involved, for domain-managed root authorities)
So after you do
certificate = GenerateCertificate(serverName);
store.Add(certificate);
You will also want to do
using (X509Store rootStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
using (X509Certificate2 withoutPrivateKey = new X509Certificate2(certificate.RawData))
{
rootStore.Open(OpenFlags.ReadWrite);
rootStore.Add(withoutPrivateKey);
}
Now the system will be able to verify the (single-node) chain up to a trusted certificate, and the validOnly: true
constraint on Find will consider the certificate to be "valid" (which, for that method, means chain-trusted and not expired).
Upvotes: 1