Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Security.AccessControl;
- using System.Security.Cryptography;
- using System.Security.Principal;
- using Org.BouncyCastle.Asn1;
- using Org.BouncyCastle.Asn1.Pkcs;
- using Org.BouncyCastle.Asn1.X509;
- using Org.BouncyCastle.Crypto;
- using Org.BouncyCastle.Crypto.Generators;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Crypto.Prng;
- using Org.BouncyCastle.Math;
- using Org.BouncyCastle.OpenSsl;
- using Org.BouncyCastle.Pkcs;
- using Org.BouncyCastle.Security;
- using Org.BouncyCastle.Utilities;
- using Org.BouncyCastle.X509;
- namespace EndpointManager.SSL
- {
- // From https://granadacoder.wordpress.com/2016/11/04/service-bus-and-custom-self-signed-certificates-with-a-high-availabilitymultiple-computing-nodes-in-the-farm/
- /*
- <?xml version=”1.0″ encoding=”utf-8″?>
- <packages>
- <package id=”BouncyCastle” version=”1.8.1″ targetFramework=”net45″ />
- </packages>
- */
- /* Notes, because this code actually places certificates IN YOUR CERTIFICATE STORE, it needs to be run “As Administrator” */
- public class BouncyCastleMaker
- {
- public const string DefaultIssuer = "UniversalSearchServerLocalCA";
- public void SetupCertificates(string domain, string siteName, out System.Security.Cryptography.X509Certificates.X509Certificate2 cert2, out string storeName)
- {
- string issuerCnName = string.Format("CN={0}", DefaultIssuer);
- string certName = "(Universal Search) " + siteName.Trim();
- List<string> subjectAlternateNames = new List<string>();
- subjectAlternateNames.Add(domain);
- string password = Guid.NewGuid().ToString();
- AsymmetricKeyParameter caPrivKey = GenerateCACertificate(issuerCnName, password);
- System.Security.Cryptography.X509Certificates.X509Certificate2 cert = GenerateSelfSignedCertificate(certName, subjectAlternateNames, password, issuerCnName, caPrivKey);
- var store = System.Security.Cryptography.X509Certificates.StoreName.My;
- storeName = "MY";
- AddAccessToCertificate(cert);
- AddCertToStore(cert, store, System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);
- cert2 = cert;
- }
- public System.Security.Cryptography.X509Certificates.X509Certificate2 GenerateSelfSignedCertificate(string certificateName, List<string> subjectAlternateNames, string privateKeyFilePassword, string issuerName, AsymmetricKeyParameter issuerPrivKey)
- {
- return GenerateSelfSignedCertificate(certificateName, subjectAlternateNames, privateKeyFilePassword, issuerName, issuerPrivKey, 2048);
- }
- public System.Security.Cryptography.X509Certificates.X509Certificate2 GenerateSelfSignedCertificate(string certificateName, List<string> subjectAlternateNames, string privateKeyFilePassword, string issuerName, AsymmetricKeyParameter issuerPrivKey, int keyStrength)
- {
- string subjectName = string.Format("CN={0}", certificateName);
- // Generating Random Numbers
- var randomGenerator = new CryptoApiRandomGenerator();
- var random = new SecureRandom(randomGenerator);
- // The Certificate Generator
- X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
- // Serial Number
- var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
- certificateGenerator.SetSerialNumber(serialNumber);
- // Signature Algorithm
- const string SignatureAlgorithm = "SHA256WithRSA";
- certificateGenerator.SetSignatureAlgorithm(SignatureAlgorithm);
- // Issuer and Subject Name
- var subjectDN = new X509Name(subjectName);
- // original code var issuerDN = issuerName;
- var issuerDN = new X509Name(issuerName);
- certificateGenerator.SetIssuerDN(issuerDN);
- certificateGenerator.SetSubjectDN(subjectDN);
- // Valid For
- var notBefore = DateTime.UtcNow.Date;
- var notAfter = notBefore.AddYears(2);
- certificateGenerator.SetNotBefore(notBefore);
- certificateGenerator.SetNotAfter(notAfter);
- KeyUsage keyUsage = new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment);
- certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, keyUsage);
- // Add the “Extended Key Usage” attribute, specifying “server authentication”.
- var usages = new[] { KeyPurposeID.IdKPServerAuth };
- certificateGenerator.AddExtension(
- X509Extensions.ExtendedKeyUsage.Id,
- false,
- new ExtendedKeyUsage(usages));
- /* DNS Name=*.fullyqualified.domainname.com */
- if (subjectAlternateNames.Count <= 1)
- {
- /* the <=1 is for the simple reason of showing an alternate syntax .. */
- foreach (string subjectAlternateName in subjectAlternateNames)
- {
- GeneralName altName = new GeneralName(GeneralName.DnsName, subjectAlternateName);
- GeneralNames subjectAltName = new GeneralNames(altName);
- certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, subjectAltName);
- }
- }
- else
- {
- //Asn1Encodable[] ansiEncodeSubjectAlternativeNames = new Asn1Encodable[]
- // {
- // //new GeneralName(GeneralName.DnsName, “*.fullyqualified.domainname.com”),
- // new GeneralName(GeneralName.DnsName, “*.fullyqualified.domainname.com”)
- // };
- List<Asn1Encodable> asn1EncodableList = new List<Asn1Encodable>();
- foreach (string subjectAlternateName in subjectAlternateNames)
- {
- asn1EncodableList.Add(new GeneralName(GeneralName.DnsName, subjectAlternateName));
- }
- DerSequence subjectAlternativeNamesExtension = new DerSequence(asn1EncodableList.ToArray());
- certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
- }
- // Subject Public Key
- AsymmetricCipherKeyPair subjectKeyPair;
- var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
- var keyPairGenerator = new RsaKeyPairGenerator();
- keyPairGenerator.Init(keyGenerationParameters);
- subjectKeyPair = keyPairGenerator.GenerateKeyPair();
- certificateGenerator.SetPublicKey(subjectKeyPair.Public);
- // Generating the Certificate
- var issuerKeyPair = subjectKeyPair;
- // selfsign certificate
- var certificate = certificateGenerator.Generate(issuerPrivKey, random);
- // correcponding private key
- PrivateKeyInfo pinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
- // merge into X509Certificate2
- // As per
- // - https://stackoverflow.com/questions/4198493/x509certificate2-has-private-key-not-exportable
- // - https://docs.microsoft.com/en-us/archive/blogs/webapps/a-fatal-error-occurred-when-attempting-to-access-the-ssl-server-credential-private-key-0x8009030d
- // must set exportable flag
- var x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded(),privateKeyFilePassword, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.PersistKeySet | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.UserKeySet);
- var seq = (Asn1Sequence)Asn1Object.FromByteArray(pinfo.ParsePrivateKey().GetDerEncoded());
- if (seq.Count != 9)
- {
- throw new PemException("malformed sequence in RSA private key");
- }
- var rsa = new RsaPrivateKeyStructure(seq);
- RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
- rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);
- x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
- return x509;
- }
- public AsymmetricKeyParameter GenerateCACertificate(string subjectName, string privateKeyFilePassword, int keyStrength = 2048)
- {
- // Generating Random Numbers
- var randomGenerator = new CryptoApiRandomGenerator();
- var random = new SecureRandom(randomGenerator);
- // The Certificate Generator
- var certificateGenerator = new X509V3CertificateGenerator();
- // Serial Number
- var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
- certificateGenerator.SetSerialNumber(serialNumber);
- // Signature Algorithm
- const string SignatureAlgorithm = "SHA256WithRSA";
- certificateGenerator.SetSignatureAlgorithm(SignatureAlgorithm);
- // Issuer and Subject Name
- var subjectDN = new X509Name(subjectName);
- var issuerDN = subjectDN;
- certificateGenerator.SetIssuerDN(issuerDN);
- certificateGenerator.SetSubjectDN(subjectDN);
- // Valid For
- var notBefore = DateTime.UtcNow.Date;
- var notAfter = notBefore.AddYears(2);
- certificateGenerator.SetNotBefore(notBefore);
- certificateGenerator.SetNotAfter(notAfter);
- KeyUsage keyUsage = new KeyUsage(KeyUsage.KeyCertSign | KeyUsage.CrlSign);
- certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, keyUsage);
- // Subject Public Key
- AsymmetricCipherKeyPair subjectKeyPair;
- var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
- var keyPairGenerator = new RsaKeyPairGenerator();
- keyPairGenerator.Init(keyGenerationParameters);
- subjectKeyPair = keyPairGenerator.GenerateKeyPair();
- certificateGenerator.SetPublicKey(subjectKeyPair.Public);
- // Generating the Certificate
- var issuerKeyPair = subjectKeyPair;
- // selfsign certificate
- Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);
- System.Security.Cryptography.X509Certificates.X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded(), privateKeyFilePassword, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.PersistKeySet | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.UserKeySet);
- #region Private Key
- // correcponding private key
- PrivateKeyInfo pinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
- var seq = (Asn1Sequence)Asn1Object.FromByteArray(pinfo.ParsePrivateKey().GetDerEncoded());
- if (seq.Count != 9)
- {
- throw new PemException("malformed sequence in RSA private key");
- }
- var rsa = new RsaPrivateKeyStructure(seq);
- RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
- rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);
- x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
- #endregion
- // Add CA certificate to Root store
- AddAccessToCertificate(x509);
- AddCertToStore(x509, System.Security.Cryptography.X509Certificates.StoreName.Root, System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);
- return issuerKeyPair.Private;
- }
- public void AddCertToStore(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
- {
- System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl);
- store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite);
- store.Add(cert);
- store.Close();
- }
- private static void AddAccessToCertificate(System.Security.Cryptography.X509Certificates.X509Certificate2 cert)
- {
- RSACryptoServiceProvider rsa = cert.PrivateKey as RSACryptoServiceProvider;
- if (rsa != null)
- {
- if (TryFindKeyLocation(rsa.CspKeyContainerInfo.UniqueKeyContainerName, out string keyfilepath))
- {
- FileInfo file = new FileInfo(keyfilepath + "\\" +
- rsa.CspKeyContainerInfo.UniqueKeyContainerName);
- FileSecurity fs = file.GetAccessControl();
- var sid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
- fs.AddAccessRule(new FileSystemAccessRule(sid,
- FileSystemRights.FullControl, AccessControlType.Allow));
- file.SetAccessControl(fs);
- } else
- {
- throw new Exception(keyfilepath);
- }
- }
- }
- private static bool TryFindKeyLocation(string keyFileName, out string location)
- {
- string text1 =
- Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
- string text2 = text1 + @"\Microsoft\Crypto\RSA\MachineKeys";
- string[] textArray1 = Directory.GetFiles(text2, keyFileName);
- if (textArray1.Length > 0)
- {
- location = text2;
- return true;
- }
- string text3 =
- Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
- string text4 = text3 + @"\Microsoft\Crypto\RSA\";
- textArray1 = Directory.GetDirectories(text4);
- if (textArray1.Length > 0)
- {
- foreach (string text5 in textArray1)
- {
- textArray1 = Directory.GetFiles(text5, keyFileName);
- if (textArray1.Length != 0)
- {
- location = text5;
- return true;
- }
- }
- }
- location = "Private key exists but is not accessible";
- return false;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement