Esempio n. 1
0
        public static void SerialNumber_AlwaysPositive(string desiredSerial, string expectedSerial)
        {
            using (ECDsa ecdsa = ECDsa.Create(EccTestData.Secp521r1_DiminishedPublic_Data.KeyParameters))
            {
                var generator = X509SignatureGenerator.CreateForECDsa(ecdsa);

                CertificateRequest request = new CertificateRequest(
                    new X500DistinguishedName("CN=Test Cert"),
                    generator.PublicKey,
                    HashAlgorithmName.SHA512);

                DateTimeOffset now          = DateTimeOffset.UtcNow;
                byte[]         serialNumber = desiredSerial.HexToByteArray();

                // byte[] serialNumber
                X509Certificate2 cert = request.Create(
                    request.SubjectName,
                    generator,
                    now,
                    now.AddDays(1),
                    serialNumber);

                using (cert)
                {
                    Assert.Equal(expectedSerial, cert.SerialNumber);
                }

                // ReadOnlySpan<byte> serialNumber
                cert = request.Create(
                    request.SubjectName,
                    generator,
                    now,
                    now.AddDays(1),
                    serialNumber.AsSpan());

                using (cert)
                {
                    Assert.Equal(expectedSerial, cert.SerialNumber);
                }
            }
        }
        public static void ECDSA_Signing_RSAPublicKey()
        {
            using (RSA rsa = RSA.Create())
                using (ECDsa ecdsa = ECDsa.Create())
                {
                    var request = new CertificateRequest(
                        new X500DistinguishedName("CN=Test"),
                        ecdsa,
                        HashAlgorithmName.SHA256);

                    request.CertificateExtensions.Add(
                        new X509BasicConstraintsExtension(true, false, 0, true));

                    DateTimeOffset now = DateTimeOffset.UtcNow;

                    using (X509Certificate2 cert = request.CreateSelfSigned(now, now.AddDays(1)))
                    {
                        X509SignatureGenerator rsaGenerator =
                            X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1);

                        request = new CertificateRequest(
                            new X500DistinguishedName("CN=Leaf"),
                            rsaGenerator.PublicKey,
                            HashAlgorithmName.SHA256);

                        byte[] serialNumber = { 1, 1, 2, 3, 5, 8, 13 };

                        Assert.Throws <ArgumentException>(
                            () => request.Create(cert, now, now.AddHours(3), serialNumber));

                        X509SignatureGenerator ecdsaGenerator =
                            X509SignatureGenerator.CreateForECDsa(ecdsa);

                        // Passes with the generator
                        using (request.Create(cert.SubjectName, ecdsaGenerator, now, now.AddHours(3), serialNumber))
                        {
                        }
                    }
                }
        }
Esempio n. 3
0
        public static X509Certificate2 CreateSelfSignedCertificateAsync(
            string CA        = "MoHA Corp .Inc",
            int validForDays = 30)
        {
            using RSA rootRSA = RSA.Create(4096);
            using RSA certRSA = RSA.Create(2048);
            var certAuthorityReq = new CertificateRequest(
                $"CN={CA}",
                rootRSA,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);

            certAuthorityReq.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(true, false, 0, true));
            certAuthorityReq.CertificateExtensions.Add(
                new X509SubjectKeyIdentifierExtension(certAuthorityReq.PublicKey, false));
            using var rootCertificate = certAuthorityReq
                                        .CreateSelfSigned(
                      DateTimeOffset.UtcNow.AddDays(-30),
                      DateTimeOffset.UtcNow.AddDays(365));

            var csr = new CertificateRequest(
                $"CN={CA}",
                certRSA,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);

            csr.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(false, false, 0, false));
            csr.CertificateExtensions.Add(
                new X509KeyUsageExtension(
                    X509KeyUsageFlags.DigitalSignature
                    | X509KeyUsageFlags.NonRepudiation
                    | X509KeyUsageFlags.CrlSign
                    | X509KeyUsageFlags.DataEncipherment
                    | X509KeyUsageFlags.KeyAgreement
                    | X509KeyUsageFlags.KeyCertSign
                    | X509KeyUsageFlags.KeyEncipherment,
                    false));
            csr.CertificateExtensions.Add(
                new X509EnhancedKeyUsageExtension(new OidCollection {
                new Oid("1.3.6.1.5.5.7.3.8")
            }, true));
            csr.CertificateExtensions.Add(
                new X509SubjectKeyIdentifierExtension(csr.PublicKey, false));
            using var certificate = csr.Create(
                      rootCertificate,
                      DateTimeOffset.UtcNow.AddDays(-1),
                      DateTimeOffset.UtcNow.AddDays(validForDays),
                      new byte[] { 1, 2, 3, 4 });
            return(certificate.CopyWithPrivateKey(certRSA));
        }
        public static void DisplayCertificateTest()
        {
            using (ECDsa ecdsa = ECDsa.Create(EccTestData.Secp256r1Data.KeyParameters))
            {
                CertificateRequest request = new CertificateRequest("CN=Test", ecdsa, HashAlgorithmName.SHA256);
                DateTimeOffset     now     = DateTimeOffset.UtcNow;

                using (X509Certificate2 cert = request.Create(request.SubjectName, X509SignatureGenerator.CreateForECDsa(ecdsa), now, now.AddMinutes(10), new byte[1]))
                {
                    X509Certificate2UI.DisplayCertificate(cert);
                }
            }
        }
Esempio n. 5
0
        public static void AssociatePersistedKey_CAPI_RSA(int provType, KeyNumber keyNumber)
        {
            const string KeyName = nameof(AssociatePersistedKey_CAPI_RSA);

            CspParameters cspParameters = new CspParameters(provType)
            {
                KeyNumber        = (int)keyNumber,
                KeyContainerName = KeyName,
                Flags            = CspProviderFlags.UseNonExportableKey,
            };

            using (RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(cspParameters))
            {
                rsaCsp.PersistKeyInCsp = false;

                // Use SHA-1 because the FULL and SCHANNEL providers can't handle SHA-2.
                HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1;
                var    generator = new RSASha1Pkcs1SignatureGenerator(rsaCsp);
                byte[] signature;

                CertificateRequest request = new CertificateRequest(
                    new X500DistinguishedName($"CN={KeyName}-{provType}-{keyNumber}"),
                    generator.PublicKey,
                    hashAlgorithm);

                DateTimeOffset now = DateTimeOffset.UtcNow;

                using (X509Certificate2 cert = request.Create(request.SubjectName, generator, now, now.AddDays(1), new byte[1]))
                    using (X509Certificate2 withPrivateKey = cert.CopyWithPrivateKey(rsaCsp))
                        using (RSA rsa = withPrivateKey.GetRSAPrivateKey())
                        {
                            signature = rsa.SignData(Array.Empty <byte>(), hashAlgorithm, RSASignaturePadding.Pkcs1);

                            Assert.True(
                                rsaCsp.VerifyData(Array.Empty <byte>(), signature, hashAlgorithm, RSASignaturePadding.Pkcs1));
                        }

                // Some certs have disposed, did they delete the key?
                cspParameters.Flags = CspProviderFlags.UseExistingKey;

                using (RSACryptoServiceProvider stillPersistedKey = new RSACryptoServiceProvider(cspParameters))
                {
                    byte[] signature2 = stillPersistedKey.SignData(
                        Array.Empty <byte>(),
                        hashAlgorithm,
                        RSASignaturePadding.Pkcs1);

                    Assert.Equal(signature, signature2);
                }
            }
        }
        public static void Sign_ArgumentValidation()
        {
            using (X509Certificate2 testRoot = new X509Certificate2(TestData.PfxData, TestData.PfxDataPassword))
            {
                CertificateRequest request = new CertificateRequest("CN=Test", testRoot.GetRSAPublicKey(), HashAlgorithmName.SHA256);

                Assert.Throws <ArgumentNullException>(
                    "generator",
                    () => request.Create(testRoot.SubjectName, null, DateTimeOffset.MinValue, DateTimeOffset.MinValue, null));

                Assert.Throws <ArgumentException>(
                    null,
                    () => request.Create(testRoot, DateTimeOffset.MaxValue, DateTimeOffset.MinValue, null));

                Assert.Throws <ArgumentException>(
                    "serialNumber",
                    () => request.Create(testRoot, DateTimeOffset.MinValue, DateTimeOffset.MaxValue, null));

                Assert.Throws <ArgumentException>(
                    "serialNumber",
                    () => request.Create(testRoot, DateTimeOffset.MinValue, DateTimeOffset.MaxValue, Array.Empty <byte>()));
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Create a self signed certificate, optionally providing a locally existente CA certificate
        /// </summary>
        /// <param name="subjectName"></param>
        /// <param name="organization"></param>
        /// <param name="country"></param>
        /// <param name="authority">Optional authority cert to sign this one against.</param>
        /// <param name="expirationDays"></param>
        /// <returns></returns>
        public static X509Certificate2 GenerateSelfSignedCertificate(
            string subjectName,
            string organization,
            string country,
            X509Certificate2 authority = null,
            int expirationDays         = 90)
        {
            // Have this certificate work with localhost, etc..
            SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();

            sanBuilder.AddIpAddress(IPAddress.Loopback);
            sanBuilder.AddIpAddress(IPAddress.IPv6Loopback);
            sanBuilder.AddDnsName("localhost");
            sanBuilder.AddDnsName(Environment.MachineName);

            X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN={subjectName}, O={organization}, C={country}");

            using (RSA rsa = RSA.Create(2048))
            {
                var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

                request.CertificateExtensions.Add(
                    new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));

                request.CertificateExtensions.Add(
                    new X509EnhancedKeyUsageExtension(
                        new OidCollection {
                    new Oid("1.3.6.1.5.5.7.3.1")
                }, false));

                request.CertificateExtensions.Add(sanBuilder.Build());

                DateTimeOffset notBefore = DateTimeOffset.UtcNow;
                DateTimeOffset notAfter  = notBefore.AddDays(expirationDays);

                X509Certificate2 certWithPrivateKey;

                if (authority == null)
                {
                    certWithPrivateKey = request.CreateSelfSigned(notBefore, notAfter);
                }
                else
                {
                    byte[] serialnumber = Encoding.ASCII.GetBytes(DateTime.UtcNow.ToString("MMMMddyyyyHHmmss"));
                    certWithPrivateKey = request.Create(authority, notBefore, notAfter, serialnumber);
                }

                return(certWithPrivateKey);
            }
        }
Esempio n. 8
0
        private static X509Certificate2 CreateIntermediate(string name, X509Certificate2 issuer)
        {
            using var key = RSA.Create();
            var request = new CertificateRequest(name, key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

            request.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));

            var serialNumber = new byte[8];

            using var rng = RandomNumberGenerator.Create();
            rng.GetBytes(serialNumber);

            return(request.Create(issuer, DateTimeOffset.UtcNow, issuer.NotAfter, serialNumber).CopyWithPrivateKey(key));
        }
        //public static X509Certificate2 CreateSelfSignedCertificateWithBouncyCastle(CertificateData certificateData, bool addPrivateKey)
        //{
        //    IDictionary attributes = GetNameParametersTable(certificateData);
        //    X509Name name = new X509Name(_orderedAttributes, attributes);

        //    var kpgen = new RsaKeyPairGenerator();
        //    var randomGenerator = new CryptoApiRandomGenerator();
        //    var random = new SecureRandom(randomGenerator);
        //    AsymmetricCipherKeyPair subjectKeyPair = default(AsymmetricCipherKeyPair);
        //    var keyGenerationParameters = new KeyGenerationParameters(random, 2048);
        //    kpgen.Init(keyGenerationParameters);
        //    subjectKeyPair = kpgen.GenerateKeyPair();
        //    AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
        //    ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", issuerKeyPair.Private, random);

        //    var cerKp = kpgen.GenerateKeyPair();

        //    X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();

        //    certGen.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random));
        //    certGen.SetIssuerDN(name);
        //    certGen.SetNotBefore(DateTime.Today.Subtract(new TimeSpan(1, 0, 0, 0)));
        //    certGen.SetNotAfter(DateTime.Today.AddDays(5000));
        //    certGen.SetSubjectDN(name);
        //    certGen.SetPublicKey(cerKp.Public);
        //    certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
        //    certGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, true,
        //        new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(cerKp.Public)));

        //    var certificate = certGen.Generate(signatureFactory);

        //    if (addPrivateKey)
        //    {
        //        return AddPrivateKey(certificate, subjectKeyPair, random);
        //    }

        //    System.Security.Cryptography.X509Certificates.X509Certificate initialCert = DotNetUtilities.ToX509Certificate(certificate);
        //    return new X509Certificate2(initialCert);
        //}

        //public static X509Certificate2 AddPrivateKey(Org.BouncyCastle.X509.X509Certificate certificate,
        //    AsymmetricCipherKeyPair subjectKeyPair, SecureRandom random)
        //{
        //    var store = new Pkcs12Store();
        //    string friendlyName = certificate.SubjectDN.ToString();
        //    X509Certificate2 cert = new X509Certificate2();
        //    var certificateEntry = new X509CertificateEntry(certificate);
        //    store.SetCertificateEntry(friendlyName, certificateEntry);
        //    store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry });
        //    var stream = new MemoryStream();
        //    store.Save(stream, "".ToCharArray(), random);
        //    var convertedCertificate = new X509Certificate2(stream.ToArray(), "",
        //        X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
        //    return convertedCertificate;
        //}

        //public static X509Certificate2 AddPrivateKey(Org.BouncyCastle.X509.X509Certificate certificate,
        //    AsymmetricCipherKeyPair subjectKeyPair)
        //{
        //    var randomGenerator = new CryptoApiRandomGenerator();
        //    var random = new SecureRandom(randomGenerator);
        //    return AddPrivateKey(certificate, subjectKeyPair, random);
        //}
        //public static Pkcs10CertificationRequest CreateCertificateSignRequest(CertificateData certificateData, out AsymmetricCipherKeyPair subjectKP)
        //{
        //    IDictionary attributes = GetNameParametersTable(certificateData);

        //    var kpgen = new RsaKeyPairGenerator();

        //    var randomGenerator = new CryptoApiRandomGenerator();
        //    var random = new SecureRandom(randomGenerator);
        //    var keyGenerationParameters = new KeyGenerationParameters(random, 2048);

        //    kpgen.Init(keyGenerationParameters);
        //    AsymmetricCipherKeyPair subjectKeyPair = default(AsymmetricCipherKeyPair);
        //    subjectKeyPair = kpgen.GenerateKeyPair();
        //    AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
        //    ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", issuerKeyPair.Private, random);

        //    X509Name subject = new X509Name(new ArrayList(attributes.Keys), attributes);

        //    Pkcs10CertificationRequest result = new Pkcs10CertificationRequest(signatureFactory, subject,
        //        subjectKeyPair.Public, null);

        //    subjectKP = subjectKeyPair;
        //    return result;
        //}

        public static X509Certificate2 CreateAndSignCertificate(string subject, RSA key, X509Certificate2 caCertificate)
        {
            CertificateRequest request = new CertificateRequest(subject, key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

            request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
            request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.NonRepudiation | X509KeyUsageFlags.DigitalSignature, false));
            request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
            byte[] serialNumber = BitConverter.GetBytes(DateTime.Now.ToBinary());

            DateTimeOffset expiration = DateTimeOffset.Now.AddYears(14);

            var clientCertificate = request.Create(caCertificate, DateTimeOffset.Now, expiration, serialNumber);

            return(clientCertificate.CopyWithPrivateKey(key));
        }
        public byte[] GenerateDeviceCertificate(string commonName, string password)
        {
            using RSA rsa = RSA.Create(2048);
            var certificateRequest = new CertificateRequest(new X500DistinguishedName($"CN={commonName}"), rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

            certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
            certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, false));
            certificateRequest.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection {
                new Oid("1.3.6.1.5.5.7.3.8")
            }, true));
            certificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));

            return(certificateRequest
                   .Create(_intermediateCertificate, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(360), new byte[] { 1, 2, 3, 4 })
                   .Export(X509ContentType.Pfx, password));
        }
        public async Task <X509Certificate2> IssueCertificateAsync(string subjectName, RSAPublicKeyParameters publicKey)
        {
            var certificateBundle = await _keyVaultClient.GetCertificateAsync(_rootCertificateId);

            using var issuerCertificate = new X509Certificate2(certificateBundle.Cer);

            using RSA certificateKey = CreateCertificateKey(publicKey);
            CertificateRequest request = CreateCertificateRequest(subjectName, certificateKey, issuerCertificate.Extensions[SubjectIdExtensionOid]);

            byte[] certificateSerialNumber = await _serialNumberGenerator.GenerateSerialAsync();

            using var rsaKeyVault = _keyVaultClient.ToRSA(certificateBundle.KeyIdentifier, issuerCertificate);
            var generator = X509SignatureGenerator.CreateForRSA(rsaKeyVault, RSASignaturePadding.Pkcs1);

            return(request.Create(issuerCertificate.SubjectName, generator, DateTime.Today.AddDays(-1), DateTime.Today.AddYears(1), certificateSerialNumber));
        }
Esempio n. 12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="subjectName"></param>
        /// <param name="organization"></param>
        /// <param name="country"></param>
        /// <param name="authority"></param>
        /// <param name="expirationDays"></param>
        /// <returns></returns>
        public static X509Certificate2 GenerateSelfSignedCertificateBackup(
            string subjectName,
            string organization,
            string country,
            X509Certificate2 authority = null,
            int expirationDays         = 90)
        {
            var ecdsa = ECDsa.Create(); // generate asymmetric key pair

            CertificateRequest request = new CertificateRequest(
                $"CN={subjectName}, O={organization}, C={country}",
                ecdsa,
                HashAlgorithmName.SHA256);

            // Indicate this certificate is to be used as a TLS Server via the EKU extension
            request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection {
                new Oid("1.3.6.1.5.5.7.3.1")
            }, false));

            // Indicate the Subject Alternative Names requested

            // SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
            // sanBuilder.AddDnsName("www.adatum.com");
            // sanBuilder.AddDnsName("adatum.com");
            // request.CertificateExtensions.Add(sanBuilder.Build());

            // Produce a certificate good for a year

            DateTimeOffset notBefore = DateTimeOffset.UtcNow;
            DateTimeOffset notAfter  = notBefore.AddDays(expirationDays);

            X509Certificate2 certWithPrivateKey;

            if (authority == null)
            {
                certWithPrivateKey = request.CreateSelfSigned(notBefore, notAfter);
            }
            else
            {
                byte[] serialnumber = Encoding.ASCII.GetBytes(DateTime.UtcNow.ToString("MMMMddyyyyHHmmss"));
                certWithPrivateKey = request.Create(authority, notBefore, notAfter, serialnumber);
            }

            return(certWithPrivateKey);
        }
Esempio n. 13
0
        public static X509Certificate2 CreateTlsCertificate(string commonName, X509Certificate2 caCertificate, int keySize, int days, params string[] subjectAltNames)
        {
            string subjectName = $"CN = {commonName}";

            var rsa = RSA.Create(keySize);

            var certificateRequest = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

            AddExtension(certificateRequest.CertificateExtensions, subjectAltNames);



            var dateTime = DateTime.UtcNow;

            X509Certificate2 tlsCertificate = certificateRequest.Create(caCertificate, new DateTimeOffset(dateTime), new DateTimeOffset(dateTime.AddDays(days)), Create20SerialNumber());

            return(new X509Certificate2(tlsCertificate.CopyWithPrivateKey(rsa).Export(X509ContentType.Pfx), string.Empty, X509KeyStorageFlags.Exportable));
        }
Esempio n. 14
0
        public static void AssociatePersistedKey_CAPI_DSA(int provType)
        {
            const string KeyName = nameof(AssociatePersistedKey_CAPI_DSA);

            CspParameters cspParameters = new CspParameters(provType)
            {
                KeyContainerName = KeyName,
                Flags            = CspProviderFlags.UseNonExportableKey,
            };

            using (DSACryptoServiceProvider dsaCsp = new DSACryptoServiceProvider(cspParameters))
            {
                dsaCsp.PersistKeyInCsp = false;

                X509SignatureGenerator dsaGen = new DSAX509SignatureGenerator(dsaCsp);

                // Use SHA-1 because that's all DSACryptoServiceProvider understands.
                HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1;

                CertificateRequest request = new CertificateRequest(
                    new X500DistinguishedName($"CN={KeyName}-{provType}"),
                    dsaGen.PublicKey,
                    hashAlgorithm);

                DateTimeOffset now = DateTimeOffset.UtcNow;

                using (X509Certificate2 cert = request.Create(request.SubjectName, dsaGen, now, now.AddDays(1), new byte[1]))
                    using (X509Certificate2 certWithPrivateKey = cert.CopyWithPrivateKey(dsaCsp))
                        using (DSA dsa = certWithPrivateKey.GetDSAPrivateKey())
                        {
                            byte[] signature = dsa.SignData(Array.Empty <byte>(), hashAlgorithm);

                            Assert.True(dsaCsp.VerifyData(Array.Empty <byte>(), signature, hashAlgorithm));
                        }

                // Some certs have disposed, did they delete the key?
                cspParameters.Flags = CspProviderFlags.UseExistingKey;

                using (var stillPersistedKey = new DSACryptoServiceProvider(cspParameters))
                {
                    stillPersistedKey.SignData(Array.Empty <byte>(), hashAlgorithm);
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Request a new certificate.
        /// </summary>
        /// <param name="subject">The complete subject list</param>
        /// <param name="certificatePassPhrase">The certificate request password</param>
        /// <param name="certificatePath">The certificate full path and file name.</param>
        public void RequestCertificateMultiDomain(Subject subject, string certificatePassPhrase, string certificatePath)
        {
            if (subject == null)
            {
                throw new ArgumentNullException("subject");
            }
            if (String.IsNullOrEmpty(certificatePath))
            {
                throw new ArgumentNullException("certificatePath");
            }

            // Create a new certificate request.
            CertificateRequest certificate = new CertificateRequest(
                Nequeo.Security.OpenSsl.Properties.Settings.Default.OpenSSLExecutable,
                Nequeo.Security.OpenSsl.Properties.Settings.Default.OpenSSLMultiDomainConfiguration);

            // Create the certificate.
            certificate.Create(subject, certificatePassPhrase, certificatePath, true);
        }
        public static void SelectCertificateSingleSelectionTest(int count)
        {
            using (ECDsa ecdsa = ECDsa.Create(EccTestData.Secp256r1Data.KeyParameters))
            {
                CertificateRequest request = new CertificateRequest("CN=Test", ecdsa, HashAlgorithmName.SHA256);
                DateTimeOffset     now     = DateTimeOffset.UtcNow;

                using (X509Certificate2 cert = request.Create(request.SubjectName, X509SignatureGenerator.CreateForECDsa(ecdsa), now, now.AddMinutes(10), new byte[1]))
                {
                    X509Certificate2Collection collection = new X509Certificate2Collection()
                    {
                        cert, cert
                    };
                    X509Certificate2Collection actual = X509Certificate2UI.SelectFromCollection(
                        collection, $"Choose {count} Certificate", string.Empty, count < 2 ? X509SelectionFlag.SingleSelection : X509SelectionFlag.MultiSelection, IntPtr.Zero);
                    Assert.Equal(count, actual.Count);
                }
            }
        }
        public void BasicRsaCertificateRequestTest()
        {
            // Load PKCS#11 based store
            using (var pkcs11Store = new Pkcs11X509Store(SoftHsm2Manager.LibraryPath, SoftHsm2Manager.PinProvider))
            {
                // Find signing certificate (CA certificate)
                Pkcs11X509Certificate pkcs11CertOfCertificateAuthority = Helpers.GetCertificate(pkcs11Store, SoftHsm2Manager.Token1Label, SoftHsm2Manager.Token1TestUserRsaLabel);

                // Generate new key pair for end entity
                RSA rsaKeyPairOfEndEntity = RSA.Create(2048);

                // Define certificate request
                CertificateRequest certificateRequest = new CertificateRequest(
                    new X500DistinguishedName("C=SK,L=Bratislava,CN=BasicRsaCertificateRequestTest"),
                    rsaKeyPairOfEndEntity,
                    HashAlgorithmName.SHA256,
                    RSASignaturePadding.Pkcs1);

                // Define certificate extensions
                certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
                certificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));
                certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, false));

                // Issue X.509 certificate for end entity
                X509Certificate2 certificateOfEndEntity = certificateRequest.Create(
                    pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.SubjectName,
                    X509SignatureGenerator.CreateForRSA(pkcs11CertOfCertificateAuthority.GetRSAPrivateKey(), RSASignaturePadding.Pkcs1),
                    DateTimeOffset.UtcNow,
                    DateTimeOffset.UtcNow.AddDays(365),
                    new BigInteger(1).ToByteArray());

                // Verify signature on X.509 certificate for end entity
                Assert.IsTrue(CaCertSignedEndEntityCert(pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.RawData, certificateOfEndEntity.RawData));

                // Asociate end entity certificate with its private key
                certificateOfEndEntity = certificateOfEndEntity.CopyWithPrivateKey(rsaKeyPairOfEndEntity);

                // Export end entity certificate to PKCS#12 file
                string basePath       = Helpers.GetBasePath();
                string pkcs12FilePath = Path.Combine(basePath, "BasicRsaCertificateRequestTest.p12");
                File.WriteAllBytes(pkcs12FilePath, certificateOfEndEntity.Export(X509ContentType.Pkcs12, "password"));
            }
        }
Esempio n. 18
0
        public X509Certificate2 CreateSignedCertificate(string certificateName, string dnsName, X509Certificate2 issuerCertificate)
        {
            var sanBuilder = new SubjectAlternativeNameBuilder();

            sanBuilder.AddIpAddress(IPAddress.Loopback);
            sanBuilder.AddIpAddress(IPAddress.IPv6Loopback);
            sanBuilder.AddDnsName(dnsName);
            sanBuilder.AddDnsName(Environment.MachineName);

            var distinguishedName = new X500DistinguishedName($"CN={certificateName}");

            using var rsa = RSA.Create(2048);
            var request = new CertificateRequest(
                distinguishedName,
                rsa,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);

            request.CertificateExtensions.Add(
                new X509KeyUsageExtension(
                    X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment |
                    X509KeyUsageFlags.DigitalSignature, false));

            request.CertificateExtensions.Add(
                new X509EnhancedKeyUsageExtension(
                    new OidCollection {
                new Oid("1.3.6.1.5.5.7.3.1")
            }, false));

            request.CertificateExtensions.Add(sanBuilder.Build());

            var notBefore = issuerCertificate.NotBefore;
            var notAfter  = issuerCertificate.NotAfter.AddDays(-1);

            // cert serial is the epoch/unix timestamp
            var epoch    = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var unixTime = Convert.ToInt64((DateTime.UtcNow - epoch).TotalSeconds);
            var serial   = BitConverter.GetBytes(unixTime);

            var certificate = request.Create(issuerCertificate, notBefore, notAfter, serial);

            return(certificate.CopyWithPrivateKey(rsa));
        }
Esempio n. 19
0
        static bool createChildCert(string subjectName, DateTimeOffset expirate)
        {
            try
            {
                Console.WriteLine($"Creating certificate for {subjectName}");
                var    clientKey     = RSA.Create(2048);
                string clientSubject = $"CN={subjectName}";
                var    clientReq     = new CertificateRequest(clientSubject, clientKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
                clientReq.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
                clientReq.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, false));
                clientReq.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(clientReq.PublicKey, false));
                byte[] serialNumber = BitConverter.GetBytes(DateTime.Now.ToBinary());
                //var clientCert = clientReq.Create(rootCert, DateTimeOffset.Now, expirate, serialNumber);
                var clientCert = clientReq.Create(rootCert, DateTimeOffset.Now, expirate, serialNumber);
                clientCert = clientCert.CopyWithPrivateKey(clientKey);



                File.WriteAllBytes($"{subjectName}.pfx", clientCert.Export(X509ContentType.Pfx));
                // Создание .crt и .key
                StringBuilder builder = new StringBuilder();
                builder.AppendLine("-----BEGIN CERTIFICATE-----");
                builder.AppendLine(Convert.ToBase64String(clientCert.RawData, Base64FormattingOptions.InsertLineBreaks));
                builder.AppendLine("-----END CERTIFICATE-----");
                File.WriteAllText($"{subjectName}.crt", builder.ToString());
                builder.Clear();

                /*
                 * string name = clientKey.SignatureAlgorithm.ToUpper();
                 * builder.AppendLine($"-----BEGIN {name} PRIVATE KEY-----");
                 * builder.AppendLine(Convert.ToBase64String(clientKey.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks));
                 * builder.AppendLine($"-----END {name} PRIVATE KEY-----");
                 * File.WriteAllText($"{subjectName}.key", builder.ToString());
                 */

                return(true);
            }
            catch (Exception e)
            {
                Console.WriteLine($"An error occurred during creating a cerificate for {subjectName}.\n + {e.Message}");
                return(false);
            }
        }
Esempio n. 20
0
        public static void TestInvalidAia()
        {
            using (RSA key = RSA.Create())
            {
                CertificateRequest rootReq = new CertificateRequest(
                    "CN=Root",
                    key,
                    HashAlgorithmName.SHA256,
                    RSASignaturePadding.Pkcs1);

                rootReq.CertificateExtensions.Add(
                    new X509BasicConstraintsExtension(true, false, 0, true));

                CertificateRequest certReq = new CertificateRequest(
                    "CN=test",
                    key,
                    HashAlgorithmName.SHA256,
                    RSASignaturePadding.Pkcs1);

                certReq.CertificateExtensions.Add(
                    new X509BasicConstraintsExtension(false, false, 0, false));

                certReq.CertificateExtensions.Add(
                    new X509Extension(
                        "1.3.6.1.5.5.7.1.1",
                        new byte[] { 5 },
                        critical: false));

                DateTimeOffset notBefore = DateTimeOffset.UtcNow.AddDays(-1);
                DateTimeOffset notAfter  = notBefore.AddDays(30);

                using (X509Certificate2 root = rootReq.CreateSelfSigned(notBefore, notAfter))
                    using (X509Certificate2 ee = certReq.Create(root, notBefore, notAfter, root.GetSerialNumber()))
                    {
                        X509Chain chain = new X509Chain();
                        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                        Assert.False(chain.Build(ee));
                        Assert.Equal(1, chain.ChainElements.Count);
                        Assert.Equal(X509ChainStatusFlags.PartialChain, chain.AllStatusFlags());
                    }
            }
        }
Esempio n. 21
0
        public X509Certificate2 CreateFakeCertificate(string fakeCN, string rootCertSerialNumber)
        {
            using (var userStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
                using (var rsa = RSA.Create(4096))
                    using (var random = new RNGCryptoServiceProvider())
                    {
                        var parsedParams = JsonConvert.DeserializeObject <RSAParameters>(RsaParams);
                        rsa.ImportParameters(parsedParams);
                        userStore.Open(OpenFlags.MaxAllowed);
                        using (var rootCert = userStore.Certificates.Cast <X509Certificate2>().Single(c => c.SerialNumber.Equals(rootCertSerialNumber, StringComparison.InvariantCultureIgnoreCase)))
                        {
                            var req = new CertificateRequest($"CN={fakeCN}", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

                            req.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
                            req.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));
                            req.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection {
                                new Oid("1.3.6.1.5.5.7.3.1"), // server auth
                                new Oid("1.3.6.1.5.5.7.3.2")  // client auth
                            }, true));
                            req.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(req.PublicKey, false));

                            var sanBuilder = new SubjectAlternativeNameBuilder();
                            sanBuilder.AddDnsName(fakeCN);
                            var sanExtension = sanBuilder.Build();
                            req.CertificateExtensions.Add(sanExtension);

                            var serialNumber = new byte[16];
                            //random.GetBytes(serialNumber);

                            var notBefore = new DateTime(2018, 07, 10);
                            var notAfter  = new DateTime(2019, 01, 01);
                            // https://github.com/dotnet/corefx/issues/24454#issuecomment-388231655
                            using (var corruptFakeCert = req.Create(rootCert, notBefore, notAfter, serialNumber).CopyWithPrivateKey(rsa))
                            {
                                var fixedFakeCert = new X509Certificate2(corruptFakeCert.Export(X509ContentType.Pkcs12));
                                return(fixedFakeCert);
                            }
                        }
                    }
        }
Esempio n. 22
0
        public static X509Certificate2 GenerateCertificate(
            string issuerName,
            string subjectName,
            RSA issuerAlgorithm,
            RSA algorithm)
        {
            var subjectDN = $"CN={subjectName}";
            var issuerDN  = new X500DistinguishedName($"CN={issuerName}");

            var notAfter  = DateTime.UtcNow.Add(TimeSpan.FromHours(1));
            var notBefore = DateTime.UtcNow.Subtract(TimeSpan.FromHours(1));

            var random       = new Random();
            var serial       = random.Next();
            var serialNumber = BitConverter.GetBytes(serial);

            Array.Reverse(serialNumber);

            var hashAlgorithm = System.Security.Cryptography.HashAlgorithmName.SHA256;
            var request       = new CertificateRequest(subjectDN, algorithm, hashAlgorithm, RSASignaturePadding.Pkcs1);

            request.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(certificateAuthority: true, hasPathLengthConstraint: false, pathLengthConstraint: 0, critical: true));
            request.CertificateExtensions.Add(
                new X509SubjectKeyIdentifierExtension(request.PublicKey, critical: false));
            request.CertificateExtensions.Add(
                new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign, critical: true));
            request.CertificateExtensions.Add(
                new X509EnhancedKeyUsageExtension(new OidCollection {
                new Oid(Oids.CodeSigningEku)
            }, critical: true));

            var generator = X509SignatureGenerator.CreateForRSA(issuerAlgorithm, RSASignaturePadding.Pkcs1);

            using (var temp = request.Create(issuerDN, generator, notBefore, notAfter, serialNumber))
            {
                var certResult = temp.CopyWithPrivateKey(algorithm);
                return(new X509Certificate2(certResult.Export(X509ContentType.Pkcs12), password: (string)null, keyStorageFlags: X509KeyStorageFlags.Exportable));
            }
        }
Esempio n. 23
0
        public static void InvalidPublicKeyEncoding(string caseName, string parametersHex)
        {
            var generator = new InvalidSignatureGenerator(
                Array.Empty <byte>(),
                parametersHex.HexToByteArray(),
                new byte[] { 0x05, 0x00 });

            CertificateRequest request = new CertificateRequest(
                new X500DistinguishedName("CN=Test"),
                generator.PublicKey,
                HashAlgorithmName.SHA256);

            DateTimeOffset now = DateTimeOffset.UtcNow;

            Exception exception = Assert.Throws <CryptographicException>(
                () => request.Create(request.SubjectName, generator, now, now.AddDays(1), new byte[1]));

            if (CultureInfo.CurrentCulture.Name == "en-US")
            {
                Assert.Contains("ASN1", exception.Message);
            }
        }
Esempio n. 24
0
        /// <inheritdoc/>
        public override X509Certificate2 CreateForRSA(X509SignatureGenerator generator)
        {
            CreateDefaults();

            if (m_rsaPublicKey == null && IssuerCAKeyCert == null)
            {
                throw new NotSupportedException("Need an issuer certificate or a public key for a signature generator.");
            }

            var issuerSubjectName = SubjectName;

            if (IssuerCAKeyCert != null)
            {
                issuerSubjectName = IssuerCAKeyCert.SubjectName;
            }

            RSA rsaKeyPair   = null;
            RSA rsaPublicKey = m_rsaPublicKey;

            if (rsaPublicKey == null)
            {
                rsaKeyPair   = RSA.Create(m_keySize == 0 ? X509Defaults.RSAKeySize : m_keySize);
                rsaPublicKey = rsaKeyPair;
            }

            var request = new CertificateRequest(SubjectName, rsaPublicKey, HashAlgorithmName, RSASignaturePadding.Pkcs1);

            CreateX509Extensions(request, false);

            X509Certificate2 signedCert = request.Create(
                issuerSubjectName,
                generator,
                NotBefore,
                NotAfter,
                m_serialNumber.Reverse().ToArray()
                );

            return((rsaKeyPair == null) ? signedCert : signedCert.CopyWithPrivateKey(rsaKeyPair));
        }
Esempio n. 25
0
        /// <inheritdoc/>
        public override X509Certificate2 CreateForECDsa(X509SignatureGenerator generator)
        {
            if (IssuerCAKeyCert == null)
            {
                throw new NotSupportedException("X509 Signature generator requires an issuer certificate.");
            }

            if (m_ecdsaPublicKey == null && m_curve == null)
            {
                throw new NotSupportedException("Need a public key or a ECCurve to create the certificate.");
            }

            CreateDefaults();

            ECDsa key       = null;
            ECDsa publicKey = m_ecdsaPublicKey;

            if (publicKey == null)
            {
                key       = ECDsa.Create((ECCurve)m_curve);
                publicKey = key;
            }

            var request = new CertificateRequest(SubjectName, publicKey, HashAlgorithmName);

            CreateX509Extensions(request, true);

            X509Certificate2 signedCert = request.Create(
                IssuerCAKeyCert.SubjectName,
                generator,
                NotBefore,
                NotAfter,
                m_serialNumber.Reverse().ToArray()
                );

            // return a X509Certificate2
            return((key == null) ? signedCert : signedCert.CopyWithPrivateKey(key));
        }
        public static void ECDSA_Signing_UnknownPublicKeyAlgorithm()
        {
            using ECDsa ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
            PublicKey gostRPublicKey = PublicKey.CreateFromSubjectPublicKeyInfo(
                TestData.GostR3410SubjectPublicKeyInfo,
                out _);

            CertificateRequest issuerRequest = new CertificateRequest(
                new X500DistinguishedName("CN=root"),
                ecdsa,
                HashAlgorithmName.SHA256);

            issuerRequest.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(true, false, 0, true));

            CertificateRequest request = new CertificateRequest(
                new X500DistinguishedName("CN=test"),
                gostRPublicKey,
                HashAlgorithmName.SHA256);

            request.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(false, false, 0, true));

            DateTimeOffset notBefore = DateTimeOffset.UtcNow;
            DateTimeOffset notAfter  = notBefore.AddDays(30);

            byte[] serial = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using X509Certificate2 issuer = issuerRequest.CreateSelfSigned(notBefore, notAfter);

            X509SignatureGenerator ecdsaGenerator = X509SignatureGenerator.CreateForECDsa(ecdsa);

            using X509Certificate2 cert = request.Create(issuer.SubjectName, ecdsaGenerator, notBefore, notAfter, serial);

            Assert.Null(cert.GetECDsaPublicKey());
            Assert.Null(cert.GetECDiffieHellmanPublicKey());
            Assert.Equal("1.2.643.2.2.19", cert.PublicKey.Oid.Value);
        }
Esempio n. 27
0
        private static X509Certificate2 Generate()
        {
            // Taken from https://github.com/dotnet/corefx/blob/5012dfe0813bf9f3eaf7a6460671e07ea048fd52/src/System.Security.Cryptography.X509Certificates/tests/CertificateCreation/CertificateRequestUsageTests.cs#L190
            using var rsa = RSA.Create();
            var request = new CertificateRequest(
                "CN=localhost, OU=.NET Framework (CoreFX), O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
                rsa,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);

            var caFakeIssuer = GenerateCA("CN=Fake Name CA, OU=Fake, O=Fake Org, L=FakeVille, S=Fake State, C=US");

            var serialNumber = new byte[8];

            RandomNumberGenerator.Fill(serialNumber);
            var now  = DateTimeOffset.UtcNow;
            var cert = request.Create(caFakeIssuer, now.AddDays(-1), now.AddDays(90), serialNumber);

            var temp = cert.CopyWithPrivateKey(rsa);

            // Work around described in https://github.com/dotnet/corefx/issues/35120
            return(new X509Certificate2(temp.Export(X509ContentType.Pfx)));
        }
Esempio n. 28
0
        public static void ThirdPartyProvider_DSA()
        {
            using (DSA dsaOther = new DSAOther())
            {
                dsaOther.ImportParameters(TestData.GetDSA1024Params());

                X509SignatureGenerator dsaGen = new DSAX509SignatureGenerator(dsaOther);

                // macOS DSA is limited to FIPS 186-3.
                HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1;

                CertificateRequest request = new CertificateRequest(
                    new X500DistinguishedName($"CN={nameof(ThirdPartyProvider_DSA)}"),
                    dsaGen.PublicKey,
                    hashAlgorithm);

                byte[] signature;
                byte[] data = request.SubjectName.RawData;

                DateTimeOffset now = DateTimeOffset.UtcNow;

                using (X509Certificate2 cert = request.Create(request.SubjectName, dsaGen, now, now.AddDays(1), new byte[1]))
                    using (X509Certificate2 certWithPrivateKey = cert.CopyWithPrivateKey(dsaOther))
                    {
                        using (DSA dsa = certWithPrivateKey.GetDSAPrivateKey())
                        {
                            signature = dsa.SignData(data, hashAlgorithm);
                        }

                        // DSAOther is exportable, so ensure PFX export succeeds
                        byte[] pfxBytes = certWithPrivateKey.Export(X509ContentType.Pkcs12, request.SubjectName.Name);
                        Assert.InRange(pfxBytes.Length, 100, int.MaxValue);
                    }

                Assert.True(dsaOther.VerifyData(data, signature, hashAlgorithm));
            }
        }
        public static void ECDSA_Signing_ECDSA_NoKeyUsageValidForECDSAAndECDH()
        {
            using ECDsa ecdsa     = ECDsa.Create(ECCurve.NamedCurves.nistP256);
            using ECDsa ecdsaLeaf = ECDsa.Create(ECCurve.NamedCurves.nistP256);

            CertificateRequest issuerRequest = new CertificateRequest(
                new X500DistinguishedName("CN=root"),
                ecdsa,
                HashAlgorithmName.SHA256);

            issuerRequest.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(true, false, 0, true));

            CertificateRequest request = new CertificateRequest(
                new X500DistinguishedName("CN=test"),
                ecdsaLeaf,
                HashAlgorithmName.SHA256);

            request.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(false, false, 0, true));

            DateTimeOffset notBefore = DateTimeOffset.UtcNow;
            DateTimeOffset notAfter  = notBefore.AddDays(30);

            byte[] serial = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using X509Certificate2 issuer           = issuerRequest.CreateSelfSigned(notBefore, notAfter);
            using X509Certificate2 cert             = request.Create(issuer, notBefore, notAfter, serial);
            using ECDiffieHellman publicCertEcDhKey = cert.GetECDiffieHellmanPublicKey();
            using ECDsa publicCertEcDsaKey          = cert.GetECDsaPublicKey();
            byte[] expectedSubjectPublicKeyInfo = ecdsaLeaf.ExportSubjectPublicKeyInfo();

            Assert.NotNull(publicCertEcDhKey);
            Assert.NotNull(publicCertEcDsaKey);
            Assert.Equal(expectedSubjectPublicKeyInfo, publicCertEcDhKey.ExportSubjectPublicKeyInfo());
            Assert.Equal(expectedSubjectPublicKeyInfo, publicCertEcDsaKey.ExportSubjectPublicKeyInfo());
        }
Esempio n. 30
0
        public static X509Certificate2 CreateCertificateFromCA(X509Certificate2 caCert, string commonName, IEnumerable <string> subjectAlternativeNames = null)
        {
            using (var privateKey = RSA.Create(4096))
            {
                subjectAlternativeNames = subjectAlternativeNames ?? Enumerable.Empty <string>();
                var req = new CertificateRequest($"CN={commonName}", privateKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

                // Set SAN names if any
                var sanBuilder = new SubjectAlternativeNameBuilder();
                foreach (var san in subjectAlternativeNames)
                {
                    sanBuilder.AddDnsName(san);
                }
                req.CertificateExtensions.Add(sanBuilder.Build());

                // not a CA cert
                req.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));

                // allow the cert to be used for TLS
                req.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection
                {
                    new Oid("1.3.6.1.5.5.7.3.2"), // client
                    new Oid("1.3.6.1.5.5.7.3.1")  // server
                },
                                                                                false));

                req.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(req.PublicKey, false));

                // https://blog.rassie.dk/2018/04/creating-an-x-509-certificate-chain-in-c/
                // This is a self-signed cert. The serial number doesn't really matter.
                // Use Unix epoch for a random-enough serial number.
                var epoch        = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                var unixTime     = Convert.ToInt64((DateTime.UtcNow - epoch).TotalSeconds);
                var serialNumber = BitConverter.GetBytes(unixTime);
                return(req.Create(caCert, caCert.NotBefore, caCert.NotAfter, serialNumber).CopyWithPrivateKey(privateKey));
            }
        }