0

Hi I want to generate a certificate chain using c#. Something like this:

certificate chain

I create this code for generation:

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace CC.CertificateCore
{
    public class CertBuilder
    {
        public static CertResult BuildChain()
        {
            CertResult result = new CertResult();

            using ECDsa rootKey = ECDsa.Create(ECCurve.NamedCurves.brainpoolP256t1);

            result.Root = CreateCert(rootKey, "CN=Root CA", "Root");

            using ECDsa aKey = result.Root.GetECDsaPublicKey();

            result.A = CreateCert(aKey, "CN=Root CA", "A");

            using ECDsa bKey = result.A.GetECDsaPublicKey();

            result.B = CreateCert(bKey, "CN=A CA", "B", selfSigned: true);

            return result;
        }

        private static X509Certificate2 CreateCert(ECDsa key, string issuer, string friendlyName, bool selfSigned = false)
        {
            var distinguishedName = new X500DistinguishedName(issuer);

            var request = new CertificateRequest(distinguishedName, key, HashAlgorithmName.MD5);
            request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, false));

            var certificate = selfSigned 
                ? request.CreateSelfSigned(NotBefore(), NotAfter()) 
                : request.Create(distinguishedName, X509SignatureGenerator.CreateForECDsa(key), NotBefore(), NotAfter(), Serial());
            
            certificate.FriendlyName = friendlyName;
            
            return certificate;
        }

        public static byte[] Serial()
        {
            byte[] serial = new byte[12];

            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(serial);
            }

            return serial;
        }

        public static DateTimeOffset NotBefore()
        {
            return new DateTimeOffset(DateTime.UtcNow.AddDays(-1));
        }

        public static DateTimeOffset NotAfter()
        {
            return new DateTimeOffset(DateTime.UtcNow.AddDays(3650));
        }
    }

    public class CertResult
    {
        public X509Certificate2 Root { get; set; }
        public X509Certificate2 A { get; set; }
        public X509Certificate2 B { get; set; }
    }
}

And I getting this error (WindowsCryptographicException: 'Key does not exist.'): error

What Im doing wrong? Is this chain even possible?. The chain is a requirement and I'm implementing a probe of concept to validate if it can be done. The project is a console project netcore 3.1

Thanks in advance,

Regards

Omar Amalfi
  • 379
  • 1
  • 2
  • 14
  • You should use CA software instead. Don't try to roll your own CA code. As PoC it is ok, but not for any real production environment. – Crypt32 Sep 23 '20 at 13:01
  • Hi Crypt32, yes is like you said. Some IT guy at some point is going to do that and give me a Self Signed Cert (the B in the sample) and with this certificate Im going to used to trust establishment. But the bureaucracy is making them delay, so I decide to move forward and do it myself meanwhile. – Omar Amalfi Sep 23 '20 at 13:28
  • 1
    Conceptual problem with your picture: signing is done with the **private key**, not the public key. The public key is used to verify the signature. – President James K. Polk Sep 23 '20 at 21:54

1 Answers1

1
using ECDsa aKey = result.Root.GetECDsaPublicKey();

result.A = CreateCert(aKey, "CN=Root CA", "A");

...

 : request.Create(distinguishedName, X509SignatureGenerator.CreateForECDsa(key), NotBefore(), NotAfter(), Serial());

You're trying to sign with a public key. Public keys can't sign. The exception is saying that the private portion of the key is missing.

Since your code ultimately is using the same key as the subject public key and the signing key, you're trying to create all of your certificates as self-signed. This is reinforced by you using the same distinguished name for the issuer and the subject in each certificate. So there's no chaining happening at all.

bartonjs
  • 30,352
  • 2
  • 71
  • 111