2

I am having issues with makecert not able to generate a self-signed SSL certificate with Subject Alternative Name (SAN) in place. Latest versions of Google Chrome gives a security error when the website is accessed over HTTPS. I have read through several articles to try and understand the context and have come to the conclusion that makecert is old enough and won't be able to support X509 v3 certificate generation with SAN. Is there an alternative means for generating a self signed root certificate and intermediate certificates based on that root CA using something else that can run in Windows 7 and above please?

Root certificate is generated as follows:

makecert.exe -pe -ss Root -sr LocalMachine -n "CN=DIGITALMARKETRESEARCHAPPS PTY LTD, O=DIGITALMARKETRESEARCHAPPS PTY LTD, OU=DIGITALMARKETRESEARCHAPPS PTY LTD" -eku 1.3.6.1.5.5.7.3.1 -r -cy authority -a sha256

Intermediate certificate with the above Root CA is created as follows:

makecert.exe -pe -ss my -n "CN=www.myawesomesite.com.au, O=DIGITALMARKETRESEARCHAPPS PTY LTD, OU=DIGITALMARKETRESEARCHAPPS PTY LTD" -sky exchange -in "DIGITALMARKETRESEARCHAPPS PTY LTD"

I cannot seem to find a way to use either New-SelfsignedCertificateEx or New-SelfSignedCertificate to map exactly to the parameter above and create a certificate with the given root CA.

I will be really thankful for any help in the correct direction please.

At the moment, there is this old application that our clients use which makes use of makecert.exe to generate SSL certificates on the fly. Unfortunately this was done a long time ago and is hard to go back and tell them to change the whole architecture at this point. Google Xhrome in particular has been complaining about these certificates generated by makecert as explained in this article below:

http://news.thewindowsclub.com/deprecation-coming-to-google-chrome-heres-how-it-could-affect-your-workflow-88723/

http://www.telerik.com/blogs/understanding-fiddler-certificate-generators

user207421
  • 305,947
  • 44
  • 307
  • 483
Lone Wolf
  • 21
  • 4
  • 1
    You can do it all with `openssl.exe`. Off topic. – user207421 Jul 19 '17 at 11:17
  • You can do all with New-SelfSignedCertificate PowerShell cmdlet. – Crypt32 Jul 19 '17 at 13:19
  • Thanks EJP and Crypt32 for your valuable time. I have read posts about openssl however in this context I need to replace the packaged makecert.exe with another executable or so that I can distribute along. Basically, what happens is as follows: Application -> Uses fiddler core to inspect HTTPS requests -> there is a call to makecert.exe using processinfo to launch the external process and create root certificate and end entity certificates. I tried New-SelfSignedCertificate however I am not able to create a chain of trust in place and not all parameters work in Windows 7 and 8, 8.1 – Lone Wolf Jul 24 '17 at 01:00

1 Answers1

1

The upcoming release of .NET Core 2.0 has added new classes to help here. While I know that either "powershell can" or "there's a version of powershell that does" work with .NET Core I don't know how, so there may be an adapter required for this answer.

Given signingCert, an X509Certificate2 instance which HasPrivateKey==true:

private static X509Certificate2 CreateNewCertificate(
    X509Certificate2 signingCert,
    int newRsaKeySize,
    IEnumerable<string> sanDnsEntries)
{
    var sanBuilder = new SubjectAlternativeNameBuilder();
    string primaryDnsName = null;

    foreach (string dnsEntry in sanDnsEntries)
    {
        // Let's just use the first one as the subject.
        primaryDnsName = primaryDnsName ?? dnsEntry;

        sanBuilder.AddDnsName(dnsEntry);
    }

    // New .NET Core Create(int) method.  Or use
    // rsa = RSA.Create(), rsa.KeySize = newRsaKeySize,
    // or (on .NET Framework) new RSACng(newRsaKeySize)
    using (RSA rsa = RSA.Create(newRsaKeySize))
    {
        var certRequest = new CertificateRequest(
            $"CN={primaryDnsName}, O=Et OU=Cetera",
            rsa,
            HashAlgorithmName.SHA256,
            RSASignaturePadding.Pkcs1);

        // Explicitly not a CA.
        certRequest.CertificateExtensions.Add(
            new X509BasicConstraintsExtension(false, false, 0, false));

        certRequest.CertificateExtensions.Add(
            new X509KeyUsageExtension(
                X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment,
                true));

        // TLS Server EKU
        certRequest.CertificateExtensions.Add(
            new X509EnhancedKeyUsageExtension(
                new OidCollection
                {
                    new Oid("1.3.6.1.5.5.7.3.1"),
                },
                false));

        // Add the SubjectAlternativeName extension
        certRequest.CertificateExtensions.Add(sanBuilder.Build());

        // Serial number.
        // It needs to be unique per issuer.
        // CA/Browser forum rules say 64 or more bits must come from a CSPRNG.
        // RFC 3280 says not to use more than 20 bytes.
        // Let's use 16 (two C# `long`s)
        byte[] serialNumber = new byte[16];

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

        // If you care about monotonicity (and believe your clock is monotonic enough):
        {
            long ticks = DateTime.UtcNow.Ticks;
            byte[] tickBytes = BitConverter.GetBytes(ticks);

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(tickBytes);
            }

            Buffer.BlockCopy(tickBytes, 0, serialNumber, 0, tickBytes.Length);
        }

        DateTimeOffset now = DateTimeOffset.UtcNow;

        return certRequest.Create(
            signingCert,
            now,
            now.AddDays(90),
            serialNumber);
    }
}

API Documentation

bartonjs
  • 30,352
  • 2
  • 71
  • 111